]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.boringcrypto] all: merge master into dev.boringcrypto
authorRoland Shoemaker <roland@golang.org>
Fri, 5 Nov 2021 18:08:36 +0000 (11:08 -0700)
committerRoland Shoemaker <roland@golang.org>
Fri, 5 Nov 2021 20:13:16 +0000 (13:13 -0700)
Change-Id: I1aa33cabd0c55fe64994b08f8a3f7b6bbfb3282c

2814 files changed:
.github/SUPPORT.md
AUTHORS
CONTRIBUTORS
README.md
api/except.txt
api/go1.1.txt
api/go1.17.txt
api/go1.9.txt
api/next.txt
doc/asm.html
doc/go1.17.html [deleted file]
doc/go1.18.html [new file with mode: 0644]
doc/go_spec.html
misc/cgo/errors/errors_test.go
misc/cgo/test/cgo_test.go
misc/cgo/test/issue42018.go [new file with mode: 0644]
misc/cgo/test/issue42018_windows.go [new file with mode: 0644]
misc/cgo/test/testdata/issue43639.go [new file with mode: 0644]
misc/cgo/test/testdata/issue43639/a.go [new file with mode: 0644]
misc/cgo/test/typeparam.go [new file with mode: 0644]
misc/cgo/testcarchive/carchive_test.go
misc/cgo/testcarchive/testdata/libgo8/a.go [new file with mode: 0644]
misc/cgo/testcarchive/testdata/main8.c [new file with mode: 0644]
misc/cgo/testcshared/cshared_test.go
misc/cgo/testcshared/testdata/libgo2/dup2.go
misc/cgo/testcshared/testdata/libgo2/dup3.go
misc/cgo/testgodefs/testdata/issue48396.go [new file with mode: 0644]
misc/cgo/testgodefs/testdata/main.go
misc/cgo/testgodefs/testgodefs_test.go
misc/cgo/testsanitizers/asan_test.go [new file with mode: 0644]
misc/cgo/testsanitizers/cc_test.go
misc/cgo/testsanitizers/testdata/asan1_fail.go [new file with mode: 0644]
misc/cgo/testsanitizers/testdata/asan2_fail.go [new file with mode: 0644]
misc/cgo/testsanitizers/testdata/asan3_fail.go [new file with mode: 0644]
misc/cgo/testsanitizers/testdata/asan4_fail.go [new file with mode: 0644]
misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go [new file with mode: 0644]
misc/cgo/testshared/shared_test.go
misc/cgo/testshared/testdata/issue47837/a/a.go [new file with mode: 0644]
misc/cgo/testshared/testdata/issue47837/main/main.go [new file with mode: 0644]
misc/go.mod
misc/ios/go_ios_exec.go
misc/linkcheck/linkcheck.go
misc/wasm/go_js_wasm_exec
misc/wasm/wasm_exec.js
misc/wasm/wasm_exec_node.js [new file with mode: 0644]
src/archive/tar/common.go
src/archive/tar/format.go
src/archive/tar/reader.go
src/archive/tar/reader_test.go
src/archive/tar/stat_actime1.go
src/archive/tar/stat_actime2.go
src/archive/tar/stat_unix.go
src/archive/tar/strconv.go
src/archive/tar/writer.go
src/archive/tar/writer_test.go
src/archive/zip/reader.go
src/archive/zip/reader_test.go
src/archive/zip/writer_test.go
src/bufio/bufio.go
src/bufio/bufio_test.go
src/bufio/example_test.go
src/bytes/boundary_test.go
src/bytes/bytes.go
src/bytes/bytes_test.go
src/bytes/example_test.go
src/cmd/api/goapi.go
src/cmd/api/run.go
src/cmd/api/testdata/src/pkg/p4/golden.txt [new file with mode: 0644]
src/cmd/api/testdata/src/pkg/p4/p4.go [new file with mode: 0644]
src/cmd/asm/internal/arch/arch.go
src/cmd/asm/internal/arch/arm64.go
src/cmd/asm/internal/asm/asm.go
src/cmd/asm/internal/asm/operand_test.go
src/cmd/asm/internal/asm/testdata/amd64enc.s
src/cmd/asm/internal/asm/testdata/arm64.s
src/cmd/asm/internal/asm/testdata/arm64error.s
src/cmd/asm/internal/asm/testdata/ppc64.s
src/cmd/asm/internal/asm/testdata/riscv64.s
src/cmd/asm/internal/asm/testdata/riscv64error.s
src/cmd/asm/internal/flags/flags.go
src/cmd/asm/main.go
src/cmd/cgo/ast.go
src/cmd/cgo/ast_go1.go [new file with mode: 0644]
src/cmd/cgo/ast_go118.go [new file with mode: 0644]
src/cmd/cgo/gcc.go
src/cmd/cgo/main.go
src/cmd/cgo/out.go
src/cmd/compile/abi-internal.md
src/cmd/compile/doc.go
src/cmd/compile/internal/abi/abiutils.go
src/cmd/compile/internal/amd64/ssa.go
src/cmd/compile/internal/amd64/versions_test.go [new file with mode: 0644]
src/cmd/compile/internal/arm/ssa.go
src/cmd/compile/internal/arm64/ssa.go
src/cmd/compile/internal/base/base.go
src/cmd/compile/internal/base/debug.go
src/cmd/compile/internal/base/flag.go
src/cmd/compile/internal/bitvec/bv.go
src/cmd/compile/internal/deadcode/deadcode.go
src/cmd/compile/internal/dwarfgen/dwarf.go
src/cmd/compile/internal/dwarfgen/dwinl.go
src/cmd/compile/internal/escape/call.go
src/cmd/compile/internal/escape/expr.go
src/cmd/compile/internal/escape/graph.go
src/cmd/compile/internal/escape/stmt.go
src/cmd/compile/internal/escape/utils.go
src/cmd/compile/internal/gc/export.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/gc/util.go
src/cmd/compile/internal/importer/iimport.go
src/cmd/compile/internal/importer/testdata/a.go
src/cmd/compile/internal/importer/testdata/b.go
src/cmd/compile/internal/importer/testdata/exports.go
src/cmd/compile/internal/importer/testdata/issue15920.go
src/cmd/compile/internal/importer/testdata/issue20046.go
src/cmd/compile/internal/importer/testdata/issue25301.go
src/cmd/compile/internal/importer/testdata/issue25596.go
src/cmd/compile/internal/importer/testdata/p.go
src/cmd/compile/internal/importer/testdata/versions/test.go
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/ir/func.go
src/cmd/compile/internal/ir/mini.go
src/cmd/compile/internal/ir/name.go
src/cmd/compile/internal/ir/node.go
src/cmd/compile/internal/ir/node_gen.go
src/cmd/compile/internal/ir/scc.go
src/cmd/compile/internal/ir/stmt.go
src/cmd/compile/internal/ir/symtab.go
src/cmd/compile/internal/liveness/arg.go [new file with mode: 0644]
src/cmd/compile/internal/liveness/bvset.go
src/cmd/compile/internal/liveness/plive.go
src/cmd/compile/internal/mips/ssa.go
src/cmd/compile/internal/mips64/ssa.go
src/cmd/compile/internal/noder/decl.go
src/cmd/compile/internal/noder/decoder.go
src/cmd/compile/internal/noder/encoder.go
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/func.go
src/cmd/compile/internal/noder/helpers.go
src/cmd/compile/internal/noder/import.go
src/cmd/compile/internal/noder/irgen.go
src/cmd/compile/internal/noder/noder.go
src/cmd/compile/internal/noder/object.go
src/cmd/compile/internal/noder/posmap.go
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/reader2.go
src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/noder/stmt.go
src/cmd/compile/internal/noder/syncmarker_string.go
src/cmd/compile/internal/noder/transform.go
src/cmd/compile/internal/noder/types.go
src/cmd/compile/internal/noder/unified.go
src/cmd/compile/internal/noder/unified_test.go
src/cmd/compile/internal/noder/validate.go
src/cmd/compile/internal/noder/writer.go
src/cmd/compile/internal/pkginit/init.go
src/cmd/compile/internal/pkginit/initorder.go
src/cmd/compile/internal/ppc64/galign.go
src/cmd/compile/internal/ppc64/ssa.go
src/cmd/compile/internal/reflectdata/alg.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/riscv64/ssa.go
src/cmd/compile/internal/s390x/ssa.go
src/cmd/compile/internal/ssa/block.go
src/cmd/compile/internal/ssa/branchelim.go
src/cmd/compile/internal/ssa/check.go
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/config.go
src/cmd/compile/internal/ssa/critical.go
src/cmd/compile/internal/ssa/deadcode.go
src/cmd/compile/internal/ssa/debug.go
src/cmd/compile/internal/ssa/debug_lines_test.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/debug_test.go
src/cmd/compile/internal/ssa/expand_calls.go
src/cmd/compile/internal/ssa/export_test.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/fuse_branchredirect.go
src/cmd/compile/internal/ssa/gen/386.rules
src/cmd/compile/internal/ssa/gen/386Ops.go
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/gen/AMD64Ops.go
src/cmd/compile/internal/ssa/gen/ARM.rules
src/cmd/compile/internal/ssa/gen/ARM64.rules
src/cmd/compile/internal/ssa/gen/ARM64Ops.go
src/cmd/compile/internal/ssa/gen/ARMOps.go
src/cmd/compile/internal/ssa/gen/MIPS.rules
src/cmd/compile/internal/ssa/gen/MIPS64.rules
src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
src/cmd/compile/internal/ssa/gen/MIPSOps.go
src/cmd/compile/internal/ssa/gen/PPC64.rules
src/cmd/compile/internal/ssa/gen/PPC64Ops.go
src/cmd/compile/internal/ssa/gen/RISCV64.rules
src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
src/cmd/compile/internal/ssa/gen/S390X.rules
src/cmd/compile/internal/ssa/gen/S390XOps.go
src/cmd/compile/internal/ssa/gen/Wasm.rules
src/cmd/compile/internal/ssa/gen/WasmOps.go
src/cmd/compile/internal/ssa/gen/generic.rules
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/gen/main.go
src/cmd/compile/internal/ssa/html.go
src/cmd/compile/internal/ssa/location.go
src/cmd/compile/internal/ssa/op.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/print.go
src/cmd/compile/internal/ssa/regalloc.go
src/cmd/compile/internal/ssa/rewrite.go
src/cmd/compile/internal/ssa/rewrite386.go
src/cmd/compile/internal/ssa/rewriteAMD64.go
src/cmd/compile/internal/ssa/rewriteARM.go
src/cmd/compile/internal/ssa/rewriteARM64.go
src/cmd/compile/internal/ssa/rewriteMIPS.go
src/cmd/compile/internal/ssa/rewriteMIPS64.go
src/cmd/compile/internal/ssa/rewritePPC64.go
src/cmd/compile/internal/ssa/rewriteRISCV64.go
src/cmd/compile/internal/ssa/rewriteS390X.go
src/cmd/compile/internal/ssa/rewriteWasm.go
src/cmd/compile/internal/ssa/rewritegeneric.go
src/cmd/compile/internal/ssa/shortcircuit.go
src/cmd/compile/internal/ssa/stmtlines_test.go
src/cmd/compile/internal/ssa/testdata/inline-dump.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/testdata/sayhi.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/value.go
src/cmd/compile/internal/ssa/writebarrier.go
src/cmd/compile/internal/ssagen/abi.go
src/cmd/compile/internal/ssagen/pgen.go
src/cmd/compile/internal/ssagen/pgen_test.go [deleted file]
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/staticdata/data.go
src/cmd/compile/internal/staticdata/embed.go
src/cmd/compile/internal/staticinit/sched.go
src/cmd/compile/internal/syntax/dumper_test.go
src/cmd/compile/internal/syntax/error_test.go
src/cmd/compile/internal/syntax/nodes.go
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/parser_test.go
src/cmd/compile/internal/syntax/pos.go
src/cmd/compile/internal/syntax/printer.go
src/cmd/compile/internal/syntax/printer_test.go
src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2
src/cmd/compile/internal/syntax/testdata/interface.go2
src/cmd/compile/internal/syntax/testdata/issue43527.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/issue48382.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/tparams.go2
src/cmd/compile/internal/syntax/testdata/typeset.go2 [new file with mode: 0644]
src/cmd/compile/internal/test/abiutils_test.go
src/cmd/compile/internal/test/inl_test.go
src/cmd/compile/internal/test/inst_test.go [new file with mode: 0644]
src/cmd/compile/internal/test/ssa_test.go
src/cmd/compile/internal/test/testdata/mysort/mysort.go [new file with mode: 0644]
src/cmd/compile/internal/test/testdata/ptrsort.go [new file with mode: 0644]
src/cmd/compile/internal/test/testdata/ptrsort.out [new file with mode: 0644]
src/cmd/compile/internal/typebits/typebits.go
src/cmd/compile/internal/typecheck/bexport.go
src/cmd/compile/internal/typecheck/builtin.go
src/cmd/compile/internal/typecheck/builtin/runtime.go
src/cmd/compile/internal/typecheck/const.go
src/cmd/compile/internal/typecheck/crawler.go
src/cmd/compile/internal/typecheck/dcl.go
src/cmd/compile/internal/typecheck/expr.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
src/cmd/compile/internal/typecheck/stmt.go
src/cmd/compile/internal/typecheck/subr.go
src/cmd/compile/internal/typecheck/type.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/typecheck/universe.go
src/cmd/compile/internal/types/alg.go
src/cmd/compile/internal/types/fmt.go
src/cmd/compile/internal/types/identity.go
src/cmd/compile/internal/types/pkg.go
src/cmd/compile/internal/types/size.go
src/cmd/compile/internal/types/sizeof_test.go
src/cmd/compile/internal/types/type.go
src/cmd/compile/internal/types/type_test.go
src/cmd/compile/internal/types/universe.go [new file with mode: 0644]
src/cmd/compile/internal/types2/api.go
src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/builtins_test.go
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/check_test.go
src/cmd/compile/internal/types2/context.go [new file with mode: 0644]
src/cmd/compile/internal/types2/conversions.go
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/errors.go
src/cmd/compile/internal/types2/errors_test.go
src/cmd/compile/internal/types2/example_test.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/hilbert_test.go
src/cmd/compile/internal/types2/index.go
src/cmd/compile/internal/types2/infer.go
src/cmd/compile/internal/types2/instantiate.go
src/cmd/compile/internal/types2/instantiate_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/interface.go
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/mono.go [new file with mode: 0644]
src/cmd/compile/internal/types2/mono_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/named.go
src/cmd/compile/internal/types2/object.go
src/cmd/compile/internal/types2/object_test.go
src/cmd/compile/internal/types2/operand.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/resolver.go
src/cmd/compile/internal/types2/return.go
src/cmd/compile/internal/types2/self_test.go
src/cmd/compile/internal/types2/signature.go
src/cmd/compile/internal/types2/sizeof_test.go
src/cmd/compile/internal/types2/stdlib_test.go
src/cmd/compile/internal/types2/stmt.go
src/cmd/compile/internal/types2/struct.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/termlist.go
src/cmd/compile/internal/types2/termlist_test.go
src/cmd/compile/internal/types2/testdata/check/builtins.go2
src/cmd/compile/internal/types2/testdata/check/compliterals.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/check/decls0.src
src/cmd/compile/internal/types2/testdata/check/expr2.src
src/cmd/compile/internal/types2/testdata/check/expr3.src
src/cmd/compile/internal/types2/testdata/check/funcinference.go2 [moved from src/cmd/compile/internal/types2/testdata/check/tinference.go2 with 75% similarity]
src/cmd/compile/internal/types2/testdata/check/issues.go2
src/cmd/compile/internal/types2/testdata/check/issues.src
src/cmd/compile/internal/types2/testdata/check/linalg.go2
src/cmd/compile/internal/types2/testdata/check/main.go2
src/cmd/compile/internal/types2/testdata/check/stmt0.src
src/cmd/compile/internal/types2/testdata/check/typeinference.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/check/typeinst.go2
src/cmd/compile/internal/types2/testdata/check/typeinst2.go2
src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/check/typeparams.go2
src/cmd/compile/internal/types2/testdata/examples/constraints.go2
src/cmd/compile/internal/types2/testdata/examples/inference.go2
src/cmd/compile/internal/types2/testdata/examples/methods.go2
src/cmd/compile/internal/types2/testdata/examples/types.go2
src/cmd/compile/internal/types2/testdata/examples/typesets.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue39768.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49003.go [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49005.go [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/spec/assignability.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/spec/conversions.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/tuple.go
src/cmd/compile/internal/types2/type.go
src/cmd/compile/internal/types2/typelists.go [new file with mode: 0644]
src/cmd/compile/internal/types2/typeparam.go
src/cmd/compile/internal/types2/typeset.go
src/cmd/compile/internal/types2/typeset_test.go
src/cmd/compile/internal/types2/typestring.go
src/cmd/compile/internal/types2/typexpr.go
src/cmd/compile/internal/types2/unify.go
src/cmd/compile/internal/types2/union.go
src/cmd/compile/internal/types2/universe.go
src/cmd/compile/internal/walk/assign.go
src/cmd/compile/internal/walk/builtin.go
src/cmd/compile/internal/walk/closure.go
src/cmd/compile/internal/walk/compare.go
src/cmd/compile/internal/walk/complit.go
src/cmd/compile/internal/walk/convert.go
src/cmd/compile/internal/walk/expr.go
src/cmd/compile/internal/walk/order.go
src/cmd/compile/internal/walk/range.go
src/cmd/compile/internal/walk/select.go
src/cmd/compile/internal/walk/stmt.go
src/cmd/compile/internal/walk/walk.go
src/cmd/compile/internal/wasm/ssa.go
src/cmd/compile/internal/x86/ssa.go
src/cmd/cover/cover.go
src/cmd/cover/testdata/test.go
src/cmd/dist/build.go
src/cmd/dist/buildruntime.go
src/cmd/dist/buildtag.go [new file with mode: 0644]
src/cmd/dist/buildtool.go
src/cmd/dist/exec.go [new file with mode: 0644]
src/cmd/dist/test.go
src/cmd/dist/util.go
src/cmd/doc/dirs.go
src/cmd/doc/pkg.go
src/cmd/fix/buildtag.go [new file with mode: 0644]
src/cmd/fix/buildtag_test.go [new file with mode: 0644]
src/cmd/fix/cftype.go
src/cmd/fix/fix.go
src/cmd/fix/main.go
src/cmd/fix/main_test.go
src/cmd/fix/typecheck.go
src/cmd/go.mod
src/cmd/go.sum
src/cmd/go/alldocs.go
src/cmd/go/go11.go
src/cmd/go/go_test.go
src/cmd/go/go_unix_test.go
src/cmd/go/internal/base/base.go
src/cmd/go/internal/base/flag.go
src/cmd/go/internal/base/signal_notunix.go
src/cmd/go/internal/base/signal_unix.go
src/cmd/go/internal/base/tool.go
src/cmd/go/internal/bug/bug.go
src/cmd/go/internal/cache/cache.go
src/cmd/go/internal/cfg/cfg.go
src/cmd/go/internal/clean/clean.go
src/cmd/go/internal/envcmd/env.go
src/cmd/go/internal/fix/fix.go
src/cmd/go/internal/fmtcmd/fmt.go
src/cmd/go/internal/fsys/fsys_test.go
src/cmd/go/internal/generate/generate.go
src/cmd/go/internal/get/get.go
src/cmd/go/internal/help/helpdoc.go
src/cmd/go/internal/imports/build.go
src/cmd/go/internal/imports/scan_test.go
src/cmd/go/internal/list/list.go
src/cmd/go/internal/load/flag.go
src/cmd/go/internal/load/pkg.go
src/cmd/go/internal/load/test.go
src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go
src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go
src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go
src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go
src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go
src/cmd/go/internal/lockedfile/lockedfile_filelock.go
src/cmd/go/internal/lockedfile/lockedfile_plan9.go
src/cmd/go/internal/lockedfile/lockedfile_test.go
src/cmd/go/internal/lockedfile/transform_test.go
src/cmd/go/internal/modcmd/download.go
src/cmd/go/internal/modcmd/edit.go
src/cmd/go/internal/modcmd/editwork.go [new file with mode: 0644]
src/cmd/go/internal/modcmd/graph.go
src/cmd/go/internal/modcmd/init.go
src/cmd/go/internal/modcmd/initwork.go [new file with mode: 0644]
src/cmd/go/internal/modcmd/mod.go
src/cmd/go/internal/modcmd/tidy.go
src/cmd/go/internal/modcmd/vendor.go
src/cmd/go/internal/modcmd/verify.go
src/cmd/go/internal/modcmd/why.go
src/cmd/go/internal/modfetch/bootstrap.go
src/cmd/go/internal/modfetch/cache.go
src/cmd/go/internal/modfetch/codehost/codehost.go
src/cmd/go/internal/modfetch/codehost/git.go
src/cmd/go/internal/modfetch/codehost/shell.go
src/cmd/go/internal/modfetch/codehost/vcs.go
src/cmd/go/internal/modfetch/coderepo.go
src/cmd/go/internal/modfetch/fetch.go
src/cmd/go/internal/modfetch/sumdb.go
src/cmd/go/internal/modget/get.go
src/cmd/go/internal/modget/query.go
src/cmd/go/internal/modload/build.go
src/cmd/go/internal/modload/buildlist.go
src/cmd/go/internal/modload/edit.go
src/cmd/go/internal/modload/import.go
src/cmd/go/internal/modload/import_test.go
src/cmd/go/internal/modload/init.go
src/cmd/go/internal/modload/list.go
src/cmd/go/internal/modload/load.go
src/cmd/go/internal/modload/modfile.go
src/cmd/go/internal/modload/mvs.go
src/cmd/go/internal/modload/query.go
src/cmd/go/internal/modload/search.go
src/cmd/go/internal/modload/stat_openfile.go
src/cmd/go/internal/modload/stat_unix.go
src/cmd/go/internal/modload/stat_windows.go
src/cmd/go/internal/modload/vendor.go
src/cmd/go/internal/mvs/mvs.go
src/cmd/go/internal/mvs/mvs_test.go
src/cmd/go/internal/robustio/robustio_flaky.go
src/cmd/go/internal/robustio/robustio_other.go
src/cmd/go/internal/run/run.go
src/cmd/go/internal/search/search.go
src/cmd/go/internal/str/path.go [moved from src/cmd/internal/str/path.go with 74% similarity]
src/cmd/go/internal/str/str.go [moved from src/cmd/internal/str/str.go with 72% similarity]
src/cmd/go/internal/str/str_test.go [moved from src/cmd/internal/str/str_test.go with 97% similarity]
src/cmd/go/internal/test/flagdefs.go
src/cmd/go/internal/test/flagdefs_test.go
src/cmd/go/internal/test/genflags.go
src/cmd/go/internal/test/internal/genflags/vetflag.go [new file with mode: 0644]
src/cmd/go/internal/test/test.go
src/cmd/go/internal/test/testflag.go
src/cmd/go/internal/tool/tool.go
src/cmd/go/internal/txtar/archive_test.go [deleted file]
src/cmd/go/internal/vcs/vcs.go
src/cmd/go/internal/vcs/vcs_test.go
src/cmd/go/internal/version/exe.go [deleted file]
src/cmd/go/internal/version/version.go
src/cmd/go/internal/vet/vet.go
src/cmd/go/internal/vet/vetflag.go
src/cmd/go/internal/web/bootstrap.go
src/cmd/go/internal/web/http.go
src/cmd/go/internal/web/url_other.go
src/cmd/go/internal/web/url_other_test.go
src/cmd/go/internal/work/action.go
src/cmd/go/internal/work/build.go
src/cmd/go/internal/work/buildid.go
src/cmd/go/internal/work/exec.go
src/cmd/go/internal/work/exec_test.go
src/cmd/go/internal/work/gc.go
src/cmd/go/internal/work/gccgo.go
src/cmd/go/internal/work/init.go
src/cmd/go/internal/work/testgo.go
src/cmd/go/proxy_test.go
src/cmd/go/script_test.go
src/cmd/go/stop_other_test.go
src/cmd/go/stop_unix_test.go
src/cmd/go/testdata/addmod.go
src/cmd/go/testdata/mod/example.com_fuzzfail_v0.1.0.txt [new file with mode: 0644]
src/cmd/go/testdata/mod/example.com_fuzzfail_v0.2.0.txt [new file with mode: 0644]
src/cmd/go/testdata/mod/example.com_split-incompatible_v2.0.0+incompatible.txt
src/cmd/go/testdata/mod/example.com_split-incompatible_v2.1.0-pre+incompatible.txt
src/cmd/go/testdata/savedir.go
src/cmd/go/testdata/script/README
src/cmd/go/testdata/script/build_cache_disabled.txt
src/cmd/go/testdata/script/build_cache_trimpath.txt
src/cmd/go/testdata/script/build_concurrent_backend.txt [new file with mode: 0644]
src/cmd/go/testdata/script/build_gcflags_order.txt [new file with mode: 0644]
src/cmd/go/testdata/script/build_i_deprecate.txt
src/cmd/go/testdata/script/build_issue48319.txt [new file with mode: 0644]
src/cmd/go/testdata/script/build_negative_p.txt [new file with mode: 0644]
src/cmd/go/testdata/script/build_runtime_gcflags.txt
src/cmd/go/testdata/script/build_trimpath.txt
src/cmd/go/testdata/script/cgo_path_space_quote.txt [new file with mode: 0644]
src/cmd/go/testdata/script/env_unset.txt
src/cmd/go/testdata/script/env_write.txt
src/cmd/go/testdata/script/gcflags_patterns.txt
src/cmd/go/testdata/script/get_404_meta.txt
src/cmd/go/testdata/script/get_go_file.txt
src/cmd/go/testdata/script/get_insecure_no_longer_supported.txt
src/cmd/go/testdata/script/goflags.txt
src/cmd/go/testdata/script/gopath_install.txt
src/cmd/go/testdata/script/gopath_local.txt
src/cmd/go/testdata/script/govcs.txt
src/cmd/go/testdata/script/install_msan_and_race_require_cgo.txt
src/cmd/go/testdata/script/link_external_undef.txt [new file with mode: 0644]
src/cmd/go/testdata/script/list_all_gobuild.txt [new file with mode: 0644]
src/cmd/go/testdata/script/list_reserved.txt [new file with mode: 0644]
src/cmd/go/testdata/script/list_shadow.txt
src/cmd/go/testdata/script/list_test_err.txt
src/cmd/go/testdata/script/mod_all.txt
src/cmd/go/testdata/script/mod_bad_domain.txt
src/cmd/go/testdata/script/mod_build_info_err.txt
src/cmd/go/testdata/script/mod_build_trimpath_issue48557.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_build_versioned.txt
src/cmd/go/testdata/script/mod_cache_dir.txt
src/cmd/go/testdata/script/mod_cache_rw.txt
src/cmd/go/testdata/script/mod_case.txt
src/cmd/go/testdata/script/mod_case_cgo.txt
src/cmd/go/testdata/script/mod_concurrent.txt
src/cmd/go/testdata/script/mod_deprecate_message.txt
src/cmd/go/testdata/script/mod_domain_root.txt
src/cmd/go/testdata/script/mod_dot.txt
src/cmd/go/testdata/script/mod_download.txt
src/cmd/go/testdata/script/mod_download_insecure_redirect.txt [moved from src/cmd/go/testdata/script/mod_get_insecure_redirect.txt with 65% similarity]
src/cmd/go/testdata/script/mod_download_partial.txt
src/cmd/go/testdata/script/mod_download_private_vcs.txt [moved from src/cmd/go/testdata/script/mod_get_private_vcs.txt with 79% similarity]
src/cmd/go/testdata/script/mod_download_svn.txt [moved from src/cmd/go/testdata/script/mod_get_svn.txt with 61% similarity]
src/cmd/go/testdata/script/mod_download_too_many_redirects.txt [moved from src/cmd/go/testdata/script/mod_get_too_many_redirects.txt with 69% similarity]
src/cmd/go/testdata/script/mod_edit.txt
src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt
src/cmd/go/testdata/script/mod_get_ambiguous_import.txt
src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt
src/cmd/go/testdata/script/mod_get_changes.txt
src/cmd/go/testdata/script/mod_get_cmd.txt [deleted file]
src/cmd/go/testdata/script/mod_get_commit.txt
src/cmd/go/testdata/script/mod_get_deprecate_install.txt
src/cmd/go/testdata/script/mod_get_deprecated.txt
src/cmd/go/testdata/script/mod_get_downadd_indirect.txt
src/cmd/go/testdata/script/mod_get_downgrade.txt
src/cmd/go/testdata/script/mod_get_downgrade_missing.txt
src/cmd/go/testdata/script/mod_get_downup_artifact.txt
src/cmd/go/testdata/script/mod_get_downup_indirect.txt
src/cmd/go/testdata/script/mod_get_downup_pseudo_artifact.txt
src/cmd/go/testdata/script/mod_get_errors.txt
src/cmd/go/testdata/script/mod_get_extra.txt
src/cmd/go/testdata/script/mod_get_fallback.txt
src/cmd/go/testdata/script/mod_get_fossil.txt
src/cmd/go/testdata/script/mod_get_go_file.txt
src/cmd/go/testdata/script/mod_get_incompatible.txt
src/cmd/go/testdata/script/mod_get_indirect.txt
src/cmd/go/testdata/script/mod_get_issue37438.txt
src/cmd/go/testdata/script/mod_get_issue47979.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_get_latest_pseudo.txt
src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_get_local.txt
src/cmd/go/testdata/script/mod_get_main.txt
src/cmd/go/testdata/script/mod_get_major.txt
src/cmd/go/testdata/script/mod_get_missing_ziphash.txt
src/cmd/go/testdata/script/mod_get_moved.txt
src/cmd/go/testdata/script/mod_get_newcycle.txt
src/cmd/go/testdata/script/mod_get_none.txt
src/cmd/go/testdata/script/mod_get_nopkgs.txt
src/cmd/go/testdata/script/mod_get_patch.txt
src/cmd/go/testdata/script/mod_get_patchbound.txt
src/cmd/go/testdata/script/mod_get_patchcycle.txt
src/cmd/go/testdata/script/mod_get_patchmod.txt
src/cmd/go/testdata/script/mod_get_patterns.txt
src/cmd/go/testdata/script/mod_get_pkgtags.txt
src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt
src/cmd/go/testdata/script/mod_get_promote_implicit.txt
src/cmd/go/testdata/script/mod_get_pseudo.txt
src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt
src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt
src/cmd/go/testdata/script/mod_get_replaced.txt
src/cmd/go/testdata/script/mod_get_retract.txt
src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt
src/cmd/go/testdata/script/mod_get_split.txt
src/cmd/go/testdata/script/mod_get_sum_noroot.txt
src/cmd/go/testdata/script/mod_get_tags.txt
src/cmd/go/testdata/script/mod_get_test.txt
src/cmd/go/testdata/script/mod_get_trailing_slash.txt
src/cmd/go/testdata/script/mod_get_update_unrelated_sum.txt
src/cmd/go/testdata/script/mod_get_upgrade.txt
src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt
src/cmd/go/testdata/script/mod_get_wild.txt
src/cmd/go/testdata/script/mod_getmode_vendor.txt
src/cmd/go/testdata/script/mod_getx.txt
src/cmd/go/testdata/script/mod_gomodcache.txt
src/cmd/go/testdata/script/mod_gonoproxy.txt
src/cmd/go/testdata/script/mod_gopkg_unstable.txt
src/cmd/go/testdata/script/mod_import.txt
src/cmd/go/testdata/script/mod_import_v1suffix.txt
src/cmd/go/testdata/script/mod_in_testdata_dir.txt
src/cmd/go/testdata/script/mod_init_invalid_major.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_install_pkg_version.txt
src/cmd/go/testdata/script/mod_install_versioned.txt
src/cmd/go/testdata/script/mod_internal.txt
src/cmd/go/testdata/script/mod_invalid_path.txt
src/cmd/go/testdata/script/mod_invalid_path_dotname.txt
src/cmd/go/testdata/script/mod_invalid_path_plus.txt
src/cmd/go/testdata/script/mod_invalid_version.txt
src/cmd/go/testdata/script/mod_issue35317.txt
src/cmd/go/testdata/script/mod_lazy_downgrade.txt
src/cmd/go/testdata/script/mod_lazy_import_allmod.txt
src/cmd/go/testdata/script/mod_list.txt
src/cmd/go/testdata/script/mod_list_command_line_arguments.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_list_deprecated.txt
src/cmd/go/testdata/script/mod_list_dir.txt
src/cmd/go/testdata/script/mod_list_direct.txt
src/cmd/go/testdata/script/mod_list_replace_dir.txt
src/cmd/go/testdata/script/mod_list_sums.txt
src/cmd/go/testdata/script/mod_list_update_nolatest.txt
src/cmd/go/testdata/script/mod_list_upgrade_pseudo.txt
src/cmd/go/testdata/script/mod_load_badchain.txt
src/cmd/go/testdata/script/mod_load_badzip.txt
src/cmd/go/testdata/script/mod_missing_repo.txt
src/cmd/go/testdata/script/mod_multirepo.txt
src/cmd/go/testdata/script/mod_no_gopath.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_outside.txt
src/cmd/go/testdata/script/mod_overlay.txt
src/cmd/go/testdata/script/mod_permissions.txt
src/cmd/go/testdata/script/mod_prefer_compatible.txt
src/cmd/go/testdata/script/mod_proxy_invalid.txt
src/cmd/go/testdata/script/mod_proxy_list.txt
src/cmd/go/testdata/script/mod_query.txt
src/cmd/go/testdata/script/mod_query_empty.txt
src/cmd/go/testdata/script/mod_query_exclude.txt
src/cmd/go/testdata/script/mod_query_main.txt
src/cmd/go/testdata/script/mod_readonly.txt
src/cmd/go/testdata/script/mod_replace.txt
src/cmd/go/testdata/script/mod_replace_gopkgin.txt
src/cmd/go/testdata/script/mod_replace_import.txt
src/cmd/go/testdata/script/mod_replace_readonly.txt
src/cmd/go/testdata/script/mod_retention.txt
src/cmd/go/testdata/script/mod_retract.txt
src/cmd/go/testdata/script/mod_retract_fix_version.txt
src/cmd/go/testdata/script/mod_retract_incompatible.txt
src/cmd/go/testdata/script/mod_retract_pseudo_base.txt
src/cmd/go/testdata/script/mod_retract_rationale.txt
src/cmd/go/testdata/script/mod_retract_rename.txt
src/cmd/go/testdata/script/mod_retract_replace.txt
src/cmd/go/testdata/script/mod_run_nonmain.txt
src/cmd/go/testdata/script/mod_run_pkg_version.txt
src/cmd/go/testdata/script/mod_skip_write.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_sum_lookup.txt
src/cmd/go/testdata/script/mod_sum_readonly.txt
src/cmd/go/testdata/script/mod_sum_replaced.txt
src/cmd/go/testdata/script/mod_sumdb.txt
src/cmd/go/testdata/script/mod_sumdb_cache.txt
src/cmd/go/testdata/script/mod_sumdb_file_path.txt
src/cmd/go/testdata/script/mod_sumdb_golang.txt
src/cmd/go/testdata/script/mod_sumdb_proxy.txt
src/cmd/go/testdata/script/mod_symlink.txt
src/cmd/go/testdata/script/mod_tidy_compat.txt
src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt
src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt
src/cmd/go/testdata/script/mod_tidy_convergence.txt
src/cmd/go/testdata/script/mod_tidy_convergence_loop.txt
src/cmd/go/testdata/script/mod_tidy_downgrade_ambiguous.txt [new file with mode: 0644]
src/cmd/go/testdata/script/mod_tidy_replace.txt
src/cmd/go/testdata/script/mod_tidy_sum.txt
src/cmd/go/testdata/script/mod_tidy_too_new.txt
src/cmd/go/testdata/script/mod_upgrade_patch.txt
src/cmd/go/testdata/script/mod_vcs_missing.txt
src/cmd/go/testdata/script/mod_vendor.txt
src/cmd/go/testdata/script/mod_vendor_auto.txt
src/cmd/go/testdata/script/mod_vendor_build.txt
src/cmd/go/testdata/script/mod_vendor_embed.txt
src/cmd/go/testdata/script/mod_vendor_goversion.txt
src/cmd/go/testdata/script/mod_verify.txt
src/cmd/go/testdata/script/modfile_flag.txt
src/cmd/go/testdata/script/run_dirs.txt
src/cmd/go/testdata/script/run_wildcard.txt
src/cmd/go/testdata/script/test_benchmark_1x.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_cache_inputs.txt
src/cmd/go/testdata/script/test_fail_newline.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_flag.txt
src/cmd/go/testdata/script/test_fuzz.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_cache.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_chatty.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_cleanup.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_deadline.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_fuzztime.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_io_error.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_match.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_minimize.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_modcache.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_multiple.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_mutate_fail.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_mutator.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_mutator_repeat.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_non_crash_signal.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_parallel.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_profile_flags.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_run.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_seed_corpus.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_setenv.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_fuzz_unsupported.txt [new file with mode: 0644]
src/cmd/go/testdata/script/test_race_install.txt
src/cmd/go/testdata/script/test_vet.txt
src/cmd/go/testdata/script/vendor_list_issue11977.txt
src/cmd/go/testdata/script/version.txt
src/cmd/go/testdata/script/version_build_settings.txt [new file with mode: 0644]
src/cmd/go/testdata/script/version_buildvcs_bzr.txt [new file with mode: 0644]
src/cmd/go/testdata/script/version_buildvcs_fossil.txt [new file with mode: 0644]
src/cmd/go/testdata/script/version_buildvcs_git.txt [new file with mode: 0644]
src/cmd/go/testdata/script/version_buildvcs_hg.txt [new file with mode: 0644]
src/cmd/go/testdata/script/version_buildvcs_nested.txt [new file with mode: 0644]
src/cmd/go/testdata/script/version_replace.txt
src/cmd/go/testdata/script/work.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_edit.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_env.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_prune.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_replace.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_replace_conflict.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_replace_conflict_override.txt [new file with mode: 0644]
src/cmd/go/testdata/script/work_sum.txt [new file with mode: 0644]
src/cmd/gofmt/gofmt.go
src/cmd/gofmt/gofmt_test.go
src/cmd/gofmt/rewrite.go
src/cmd/gofmt/testdata/typeparams.golden
src/cmd/gofmt/testdata/typeparams.input
src/cmd/internal/buildid/buildid_test.go
src/cmd/internal/buildid/rewrite.go
src/cmd/internal/dwarf/dwarf.go
src/cmd/internal/goobj/builtin.go
src/cmd/internal/goobj/funcinfo.go
src/cmd/internal/goobj/objfile.go
src/cmd/internal/obj/arm/obj5.go
src/cmd/internal/obj/arm64/a.out.go
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/arm64/doc.go
src/cmd/internal/obj/arm64/obj7.go
src/cmd/internal/obj/dwarf.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/mips/obj0.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/obj/pcln.go
src/cmd/internal/obj/plist.go
src/cmd/internal/obj/ppc64/a.out.go
src/cmd/internal/obj/ppc64/anames.go
src/cmd/internal/obj/ppc64/anames9.go
src/cmd/internal/obj/ppc64/asm9.go
src/cmd/internal/obj/ppc64/asm_test.go
src/cmd/internal/obj/ppc64/doc.go
src/cmd/internal/obj/ppc64/list9.go
src/cmd/internal/obj/ppc64/obj9.go
src/cmd/internal/obj/riscv/anames.go
src/cmd/internal/obj/riscv/asm_test.go
src/cmd/internal/obj/riscv/cpu.go
src/cmd/internal/obj/riscv/obj.go
src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
src/cmd/internal/obj/s390x/objz.go
src/cmd/internal/obj/sym.go
src/cmd/internal/obj/util.go
src/cmd/internal/obj/wasm/wasmobj.go
src/cmd/internal/obj/x86/aenum.go
src/cmd/internal/obj/x86/anames.go
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/internal/objabi/flag.go
src/cmd/internal/objabi/funcdata.go
src/cmd/internal/objabi/funcid.go
src/cmd/internal/objabi/reloctype.go
src/cmd/internal/objabi/reloctype_string.go
src/cmd/internal/objabi/symkind.go
src/cmd/internal/objabi/symkind_string.go
src/cmd/internal/objabi/util.go
src/cmd/internal/objfile/goobj.go
src/cmd/internal/quoted/quoted.go [new file with mode: 0644]
src/cmd/internal/quoted/quoted_test.go [new file with mode: 0644]
src/cmd/internal/sys/arch.go
src/cmd/internal/sys/args.go [new file with mode: 0644]
src/cmd/internal/sys/supported.go
src/cmd/link/doc.go
src/cmd/link/dwarf_test.go
src/cmd/link/internal/arm/asm.go
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/ld/config.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/deadcode.go
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/dwarf_test.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/ld_test.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/link.go
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/ld/outbuf_darwin.go
src/cmd/link/internal/ld/outbuf_nofallocate.go
src/cmd/link/internal/ld/outbuf_notdarwin.go
src/cmd/link/internal/ld/pcln.go
src/cmd/link/internal/ld/pe.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/ld/xcoff.go
src/cmd/link/internal/loader/loader.go
src/cmd/link/internal/loader/symbolbuilder.go
src/cmd/link/internal/mips/asm.go
src/cmd/link/internal/mips64/asm.go
src/cmd/link/internal/ppc64/asm.go
src/cmd/link/internal/riscv64/asm.go
src/cmd/link/internal/riscv64/obj.go
src/cmd/link/internal/sym/symbol.go
src/cmd/link/internal/sym/symkind.go
src/cmd/link/internal/sym/symkind_string.go
src/cmd/link/internal/wasm/asm.go
src/cmd/link/link_test.go
src/cmd/nm/nm_cgo_test.go
src/cmd/objdump/objdump_test.go
src/cmd/pprof/readlineui.go
src/cmd/trace/annotations.go
src/cmd/trace/annotations_test.go
src/cmd/trace/main.go
src/cmd/trace/trace_test.go
src/cmd/trace/trace_unix_test.go
src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go
src/cmd/vendor/github.com/google/pprof/internal/driver/config.go
src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
src/cmd/vendor/github.com/google/pprof/internal/driver/tagroot.go [new file with mode: 0644]
src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
src/cmd/vendor/github.com/google/pprof/internal/report/report.go
src/cmd/vendor/github.com/google/pprof/internal/report/source.go
src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
src/cmd/vendor/github.com/ianlancetaylor/demangle/README.md
src/cmd/vendor/github.com/ianlancetaylor/demangle/ast.go
src/cmd/vendor/github.com/ianlancetaylor/demangle/demangle.go
src/cmd/vendor/github.com/ianlancetaylor/demangle/rust.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/arch/arm64/arm64asm/plan9x.go
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
src/cmd/vendor/golang.org/x/mod/modfile/work.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/mod/module/module.go
src/cmd/vendor/golang.org/x/mod/zip/zip.go
src/cmd/vendor/golang.org/x/sync/AUTHORS [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sync/CONTRIBUTORS [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sync/LICENSE [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sync/PATENTS [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/README.md
src/cmd/vendor/golang.org/x/sys/unix/asm_bsd_386.s
src/cmd/vendor/golang.org/x/sys/unix/asm_bsd_arm.s
src/cmd/vendor/golang.org/x/sys/unix/ifreq_linux.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/ioctl_linux.go
src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh
src/cmd/vendor/golang.org/x/sys/unix/syscall_darwin.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_illumos.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_unix.go
src/cmd/vendor/golang.org/x/sys/unix/sysvshm_linux.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/sysvshm_unix.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/sysvshm_unix_other.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go
src/cmd/vendor/golang.org/x/sys/windows/exec_windows.go
src/cmd/vendor/golang.org/x/sys/windows/memory_windows.go
src/cmd/vendor/golang.org/x/sys/windows/security_windows.go
src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
src/cmd/vendor/golang.org/x/tools/cover/profile.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
src/cmd/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go
src/cmd/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/typeof.go
src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
src/cmd/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go [deleted file]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/termlist.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go [deleted file]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeterm.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/txtar/archive.go [moved from src/cmd/go/internal/txtar/archive.go with 96% similarity]
src/cmd/vendor/modules.txt
src/cmd/vet/vet_test.go
src/compress/gzip/issue14937_test.go
src/compress/lzw/writer.go
src/compress/lzw/writer_test.go
src/constraints/constraints.go [new file with mode: 0644]
src/constraints/constraints_test.go [new file with mode: 0644]
src/container/list/list.go
src/container/list/list_test.go
src/context/benchmark_test.go
src/context/context.go
src/crypto/aes/aes_gcm.go
src/crypto/aes/cipher_asm.go
src/crypto/aes/cipher_generic.go
src/crypto/aes/gcm_ppc64le.go
src/crypto/cipher/xor_generic.go
src/crypto/cipher/xor_ppc64x.go
src/crypto/crypto.go
src/crypto/ecdsa/ecdsa.go
src/crypto/ecdsa/ecdsa_noasm.go
src/crypto/ecdsa/ecdsa_s390x_test.go
src/crypto/ecdsa/ecdsa_test.go
src/crypto/ed25519/internal/edwards25519/field/fe_amd64.go
src/crypto/ed25519/internal/edwards25519/field/fe_amd64_noasm.go
src/crypto/ed25519/internal/edwards25519/field/fe_arm64.go
src/crypto/ed25519/internal/edwards25519/field/fe_arm64_noasm.go
src/crypto/ed25519/internal/edwards25519/tables.go
src/crypto/elliptic/elliptic.go
src/crypto/elliptic/elliptic_test.go
src/crypto/elliptic/export_generate.go [new file with mode: 0644]
src/crypto/elliptic/fuzz_test.go
src/crypto/elliptic/gen_p256_table.go [new file with mode: 0644]
src/crypto/elliptic/internal/fiat/p521.go
src/crypto/elliptic/internal/fiat/p521_test.go
src/crypto/elliptic/internal/nistec/p521.go [new file with mode: 0644]
src/crypto/elliptic/internal/nistec/p521_test.go [new file with mode: 0644]
src/crypto/elliptic/p224.go
src/crypto/elliptic/p224_test.go
src/crypto/elliptic/p256.go
src/crypto/elliptic/p256_asm.go
src/crypto/elliptic/p256_asm_amd64.s
src/crypto/elliptic/p256_asm_arm64.s
src/crypto/elliptic/p256_asm_table.go
src/crypto/elliptic/p256_asm_table_test.go
src/crypto/elliptic/p256_generic.go
src/crypto/elliptic/p256_ppc64le.go
src/crypto/elliptic/p256_s390x.go
src/crypto/elliptic/p521.go
src/crypto/internal/subtle/aliasing.go
src/crypto/internal/subtle/aliasing_appengine.go
src/crypto/md5/gen.go
src/crypto/md5/md5_test.go
src/crypto/md5/md5block_decl.go
src/crypto/md5/md5block_generic.go
src/crypto/rand/eagain.go
src/crypto/rand/rand.go
src/crypto/rand/rand_batched.go
src/crypto/rand/rand_batched_test.go
src/crypto/rand/rand_getentropy.go
src/crypto/rand/rand_js.go
src/crypto/rand/rand_unix.go
src/crypto/sha1/fallback_test.go
src/crypto/sha1/issue15617_test.go
src/crypto/sha1/sha1_test.go
src/crypto/sha1/sha1block_decl.go
src/crypto/sha1/sha1block_generic.go
src/crypto/sha256/fallback_test.go
src/crypto/sha256/sha256_test.go
src/crypto/sha256/sha256block_decl.go
src/crypto/sha256/sha256block_generic.go
src/crypto/sha512/fallback_test.go
src/crypto/sha512/sha512_test.go
src/crypto/sha512/sha512block_amd64.go
src/crypto/sha512/sha512block_decl.go
src/crypto/sha512/sha512block_generic.go
src/crypto/tls/common.go
src/crypto/tls/conn.go
src/crypto/tls/generate_cert.go
src/crypto/tls/handshake_client_test.go
src/crypto/tls/handshake_messages.go
src/crypto/tls/handshake_test.go
src/crypto/tls/handshake_unix_test.go
src/crypto/x509/internal/macos/corefoundation.go
src/crypto/x509/internal/macos/security.go
src/crypto/x509/name_constraints_test.go
src/crypto/x509/parser.go
src/crypto/x509/pem_decrypt.go
src/crypto/x509/root_bsd.go
src/crypto/x509/root_darwin.go
src/crypto/x509/root_ios.go
src/crypto/x509/root_ios_gen.go
src/crypto/x509/root_js.go
src/crypto/x509/root_omit.go
src/crypto/x509/root_omit_test.go
src/crypto/x509/root_plan9.go
src/crypto/x509/root_unix.go
src/crypto/x509/root_unix_test.go
src/crypto/x509/root_windows.go
src/crypto/x509/verify.go
src/crypto/x509/verify_test.go
src/crypto/x509/x509_test_import.go
src/database/sql/convert.go
src/database/sql/convert_test.go
src/database/sql/driver/driver.go
src/database/sql/driver/types.go
src/database/sql/fakedb_test.go
src/database/sql/sql.go
src/database/sql/sql_test.go
src/debug/buildinfo/buildinfo.go [new file with mode: 0644]
src/debug/buildinfo/buildinfo_test.go [new file with mode: 0644]
src/debug/dwarf/testdata/typedef.c
src/debug/dwarf/testdata/typedef.macho4 [new file with mode: 0644]
src/debug/dwarf/type.go
src/debug/dwarf/type_test.go
src/debug/elf/file.go
src/debug/gosym/pclntab.go
src/debug/gosym/pclntab_test.go
src/debug/gosym/symtab.go
src/debug/gosym/symtab_test.go
src/debug/macho/file.go
src/debug/macho/file_test.go
src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 [new file with mode: 0644]
src/embed/embed.go
src/embed/example_test.go [new file with mode: 0644]
src/embed/internal/embedtest/embed_test.go
src/encoding/ascii85/ascii85.go
src/encoding/asn1/asn1.go
src/encoding/asn1/common.go
src/encoding/base32/base32.go
src/encoding/base32/example_test.go
src/encoding/base64/base64.go
src/encoding/base64/example_test.go
src/encoding/binary/binary.go
src/encoding/csv/fuzz.go
src/encoding/gob/debug.go
src/encoding/gob/decgen.go
src/encoding/gob/decode.go
src/encoding/gob/decoder.go
src/encoding/gob/dump.go
src/encoding/gob/encgen.go
src/encoding/gob/encode.go
src/encoding/gob/encoder.go
src/encoding/gob/encoder_test.go
src/encoding/gob/timing_test.go
src/encoding/gob/type.go
src/encoding/gob/type_test.go
src/encoding/json/decode.go
src/encoding/json/decode_test.go
src/encoding/json/encode.go
src/encoding/json/fuzz.go
src/encoding/json/tags.go
src/encoding/pem/pem.go
src/encoding/xml/marshal.go
src/encoding/xml/read.go
src/encoding/xml/typeinfo.go
src/encoding/xml/xml.go
src/errors/wrap.go
src/flag/flag.go
src/fmt/print.go
src/fmt/scan.go
src/fmt/scan_test.go
src/go.mod
src/go.sum
src/go/ast/ast.go
src/go/ast/print.go
src/go/ast/walk.go
src/go/build/build.go
src/go/build/build_test.go
src/go/build/deps_test.go
src/go/build/gc.go
src/go/build/gccgo.go
src/go/build/read.go
src/go/build/read_test.go
src/go/build/syslist.go
src/go/constant/value_test.go
src/go/doc/comment.go
src/go/doc/example.go
src/go/doc/example_test.go
src/go/doc/exports.go
src/go/doc/filter.go
src/go/doc/headscan.go
src/go/doc/reader.go
src/go/doc/testdata/generics.0.golden [new file with mode: 0644]
src/go/doc/testdata/generics.1.golden [new file with mode: 0644]
src/go/doc/testdata/generics.2.golden [new file with mode: 0644]
src/go/doc/testdata/generics.go [new file with mode: 0644]
src/go/importer/importer_test.go
src/go/internal/gccgoimporter/parser.go
src/go/internal/gccgoimporter/testdata/escapeinfo.gox
src/go/internal/gccgoimporter/testdata/time.gox
src/go/internal/gccgoimporter/testdata/unicode.gox
src/go/internal/gccgoimporter/testdata/v1reflect.gox
src/go/internal/gcimporter/gcimporter_test.go
src/go/internal/gcimporter/iimport.go
src/go/internal/gcimporter/support.go
src/go/internal/typeparams/common.go
src/go/internal/typeparams/typeparams.go
src/go/parser/error_test.go
src/go/parser/parser.go
src/go/parser/resolver.go
src/go/parser/short_test.go
src/go/parser/testdata/interface.go2
src/go/parser/testdata/issue49174.go2 [new file with mode: 0644]
src/go/parser/testdata/issue49175.go2 [new file with mode: 0644]
src/go/parser/testdata/linalg.go2
src/go/parser/testdata/resolution/typeparams.go2
src/go/parser/testdata/typeset.go2 [new file with mode: 0644]
src/go/printer/nodes.go
src/go/printer/printer.go
src/go/printer/testdata/generics.golden
src/go/printer/testdata/generics.input
src/go/token/position.go
src/go/types/api.go
src/go/types/api_test.go
src/go/types/assignments.go
src/go/types/builtins.go
src/go/types/builtins_test.go
src/go/types/call.go
src/go/types/check.go
src/go/types/check_test.go
src/go/types/context.go [new file with mode: 0644]
src/go/types/conversions.go
src/go/types/decl.go
src/go/types/errorcodes.go
src/go/types/errors.go
src/go/types/errors_test.go
src/go/types/eval.go
src/go/types/eval_test.go
src/go/types/example_test.go
src/go/types/expr.go
src/go/types/exprstring.go
src/go/types/exprstring_test.go
src/go/types/gotype.go
src/go/types/index.go
src/go/types/infer.go
src/go/types/instantiate.go
src/go/types/instantiate_test.go [new file with mode: 0644]
src/go/types/interface.go
src/go/types/lookup.go
src/go/types/methodset.go
src/go/types/mono.go [new file with mode: 0644]
src/go/types/mono_test.go [new file with mode: 0644]
src/go/types/named.go
src/go/types/object.go
src/go/types/object_test.go
src/go/types/operand.go
src/go/types/predicates.go
src/go/types/resolver.go
src/go/types/self_test.go
src/go/types/signature.go
src/go/types/sizeof_test.go
src/go/types/stdlib_test.go
src/go/types/stmt.go
src/go/types/struct.go
src/go/types/subst.go
src/go/types/termlist.go [new file with mode: 0644]
src/go/types/termlist_test.go [new file with mode: 0644]
src/go/types/testdata/check/builtins.go2
src/go/types/testdata/check/compliterals.go2 [new file with mode: 0644]
src/go/types/testdata/check/decls0.src
src/go/types/testdata/check/expr2.src
src/go/types/testdata/check/funcinference.go2 [moved from src/go/types/testdata/check/tinference.go2 with 63% similarity]
src/go/types/testdata/check/issues.go2
src/go/types/testdata/check/issues.src
src/go/types/testdata/check/linalg.go2
src/go/types/testdata/check/main.go2
src/go/types/testdata/check/map2.go2
src/go/types/testdata/check/typeinference.go2 [new file with mode: 0644]
src/go/types/testdata/check/typeinst.go2
src/go/types/testdata/check/typeinst2.go2
src/go/types/testdata/check/typeinstcycles.go2 [new file with mode: 0644]
src/go/types/testdata/check/typeparams.go2
src/go/types/testdata/check/unions.go2 [new file with mode: 0644]
src/go/types/testdata/examples/constraints.go2
src/go/types/testdata/examples/functions.go2
src/go/types/testdata/examples/inference.go2
src/go/types/testdata/examples/methods.go2
src/go/types/testdata/examples/types.go2
src/go/types/testdata/examples/typesets.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue39634.go2
src/go/types/testdata/fixedbugs/issue39711.go2
src/go/types/testdata/fixedbugs/issue39723.go2
src/go/types/testdata/fixedbugs/issue39725.go2
src/go/types/testdata/fixedbugs/issue39768.go2
src/go/types/testdata/fixedbugs/issue39938.go2
src/go/types/testdata/fixedbugs/issue39976.go2
src/go/types/testdata/fixedbugs/issue40038.go2
src/go/types/testdata/fixedbugs/issue40056.go2
src/go/types/testdata/fixedbugs/issue40684.go2
src/go/types/testdata/fixedbugs/issue41124.go2
src/go/types/testdata/fixedbugs/issue42758.go2
src/go/types/testdata/fixedbugs/issue43527.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue45550.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue45639.go2
src/go/types/testdata/fixedbugs/issue45985.go2
src/go/types/testdata/fixedbugs/issue46461.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue47127.go2
src/go/types/testdata/fixedbugs/issue47411.go2
src/go/types/testdata/fixedbugs/issue47747.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue47796.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue47818.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue47887.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue47968.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48008.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48018.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48048.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48082.src [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48083.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48136.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48234.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48472.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48529.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48582.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48619.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48656.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48695.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48703.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48819.src [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48951.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue48974.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue49003.go [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue49043.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue49242.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue49247.go2 [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue49296.go2 [new file with mode: 0644]
src/go/types/testdata/spec/assignability.go2 [new file with mode: 0644]
src/go/types/testdata/spec/conversions.go2 [new file with mode: 0644]
src/go/types/tuple.go
src/go/types/type.go
src/go/types/typelists.go [new file with mode: 0644]
src/go/types/typeparam.go
src/go/types/typeset.go
src/go/types/typeset_test.go [new file with mode: 0644]
src/go/types/typestring.go
src/go/types/typestring_test.go
src/go/types/typeterm.go
src/go/types/typeterm_test.go
src/go/types/typexpr.go
src/go/types/unify.go
src/go/types/union.go
src/go/types/universe.go
src/hash/crc32/crc32_otherarch.go
src/hash/crc32/crc32_ppc64le.s
src/hash/crc32/gen_const_ppc64le.go
src/html/fuzz.go
src/html/template/attr.go
src/html/template/content.go
src/html/template/context.go
src/html/template/escape.go
src/html/template/escape_test.go
src/html/template/exec_test.go
src/html/template/js.go
src/html/template/url.go
src/image/color/palette/gen.go
src/image/draw/bench_test.go
src/image/draw/draw.go
src/image/draw/draw_test.go
src/image/internal/imageutil/gen.go
src/image/png/fuzz.go
src/image/png/reader.go
src/index/suffixarray/gen.go
src/internal/abi/abi.go
src/internal/abi/abi_arm64.go
src/internal/abi/abi_generic.go
src/internal/abi/abi_ppc64x.go [new file with mode: 0644]
src/internal/buildcfg/cfg.go
src/internal/buildcfg/cfg_test.go [new file with mode: 0644]
src/internal/buildcfg/exp.go
src/internal/bytealg/bytealg.go
src/internal/bytealg/compare_386.s
src/internal/bytealg/compare_generic.go
src/internal/bytealg/compare_native.go
src/internal/bytealg/compare_ppc64x.s
src/internal/bytealg/count_generic.go
src/internal/bytealg/count_native.go
src/internal/bytealg/count_ppc64x.s
src/internal/bytealg/equal_386.s
src/internal/bytealg/equal_ppc64x.s
src/internal/bytealg/index_generic.go
src/internal/bytealg/index_native.go
src/internal/bytealg/index_ppc64x.go
src/internal/bytealg/index_ppc64x.s
src/internal/bytealg/indexbyte_generic.go
src/internal/bytealg/indexbyte_native.go
src/internal/bytealg/indexbyte_ppc64x.s
src/internal/cfg/cfg.go
src/internal/cpu/cpu.go
src/internal/cpu/cpu_arm64_android.go
src/internal/cpu/cpu_arm64_darwin.go
src/internal/cpu/cpu_arm64_freebsd.go
src/internal/cpu/cpu_arm64_hwcap.go
src/internal/cpu/cpu_arm64_linux.go
src/internal/cpu/cpu_arm64_other.go
src/internal/cpu/cpu_mips64x.go
src/internal/cpu/cpu_no_name.go
src/internal/cpu/cpu_ppc64x.go
src/internal/cpu/cpu_ppc64x_aix.go
src/internal/cpu/cpu_ppc64x_linux.go
src/internal/cpu/cpu_test.go
src/internal/cpu/cpu_x86.go
src/internal/cpu/cpu_x86_test.go
src/internal/fmtsort/sort.go
src/internal/fuzz/counters_supported.go [new file with mode: 0644]
src/internal/fuzz/counters_unsupported.go [new file with mode: 0644]
src/internal/fuzz/coverage.go [new file with mode: 0644]
src/internal/fuzz/encoding.go [new file with mode: 0644]
src/internal/fuzz/encoding_test.go [new file with mode: 0644]
src/internal/fuzz/fuzz.go [new file with mode: 0644]
src/internal/fuzz/mem.go [new file with mode: 0644]
src/internal/fuzz/minimize.go [new file with mode: 0644]
src/internal/fuzz/minimize_test.go [new file with mode: 0644]
src/internal/fuzz/mutator.go [new file with mode: 0644]
src/internal/fuzz/mutator_test.go [new file with mode: 0644]
src/internal/fuzz/mutators_byteslice.go [new file with mode: 0644]
src/internal/fuzz/mutators_byteslice_test.go [new file with mode: 0644]
src/internal/fuzz/pcg.go [new file with mode: 0644]
src/internal/fuzz/queue.go [new file with mode: 0644]
src/internal/fuzz/queue_test.go [new file with mode: 0644]
src/internal/fuzz/sys_posix.go [new file with mode: 0644]
src/internal/fuzz/sys_unimplemented.go [new file with mode: 0644]
src/internal/fuzz/sys_windows.go [new file with mode: 0644]
src/internal/fuzz/trace.go [new file with mode: 0644]
src/internal/fuzz/worker.go [new file with mode: 0644]
src/internal/fuzz/worker_test.go [new file with mode: 0644]
src/internal/goarch/gengoarch.go
src/internal/goarch/zgoarch_386.go
src/internal/goarch/zgoarch_amd64.go
src/internal/goarch/zgoarch_arm.go
src/internal/goarch/zgoarch_arm64.go
src/internal/goarch/zgoarch_arm64be.go
src/internal/goarch/zgoarch_armbe.go
src/internal/goarch/zgoarch_loong64.go
src/internal/goarch/zgoarch_mips.go
src/internal/goarch/zgoarch_mips64.go
src/internal/goarch/zgoarch_mips64le.go
src/internal/goarch/zgoarch_mips64p32.go
src/internal/goarch/zgoarch_mips64p32le.go
src/internal/goarch/zgoarch_mipsle.go
src/internal/goarch/zgoarch_ppc.go
src/internal/goarch/zgoarch_ppc64.go
src/internal/goarch/zgoarch_ppc64le.go
src/internal/goarch/zgoarch_riscv.go
src/internal/goarch/zgoarch_riscv64.go
src/internal/goarch/zgoarch_s390.go
src/internal/goarch/zgoarch_s390x.go
src/internal/goarch/zgoarch_sparc.go
src/internal/goarch/zgoarch_sparc64.go
src/internal/goarch/zgoarch_wasm.go
src/internal/godebug/godebug.go [new file with mode: 0644]
src/internal/godebug/godebug_test.go [new file with mode: 0644]
src/internal/goexperiment/exp_pacerredesign_off.go [new file with mode: 0644]
src/internal/goexperiment/exp_pacerredesign_on.go [new file with mode: 0644]
src/internal/goexperiment/flags.go
src/internal/goos/gengoos.go
src/internal/goos/zgoos_aix.go
src/internal/goos/zgoos_android.go
src/internal/goos/zgoos_darwin.go
src/internal/goos/zgoos_dragonfly.go
src/internal/goos/zgoos_freebsd.go
src/internal/goos/zgoos_hurd.go
src/internal/goos/zgoos_illumos.go
src/internal/goos/zgoos_ios.go
src/internal/goos/zgoos_js.go
src/internal/goos/zgoos_linux.go
src/internal/goos/zgoos_netbsd.go
src/internal/goos/zgoos_openbsd.go
src/internal/goos/zgoos_plan9.go
src/internal/goos/zgoos_solaris.go
src/internal/goos/zgoos_windows.go
src/internal/goos/zgoos_zos.go
src/internal/goroot/gc.go
src/internal/goroot/gccgo.go
src/internal/intern/intern.go [new file with mode: 0644]
src/internal/intern/intern_test.go [new file with mode: 0644]
src/internal/poll/errno_unix.go
src/internal/poll/errno_windows.go
src/internal/poll/error_stub_test.go
src/internal/poll/export_posix_test.go
src/internal/poll/fcntl_js.go
src/internal/poll/fcntl_libc.go
src/internal/poll/fcntl_syscall.go
src/internal/poll/fd_fsync_posix.go
src/internal/poll/fd_poll_js.go
src/internal/poll/fd_poll_runtime.go
src/internal/poll/fd_posix.go
src/internal/poll/fd_posix_test.go
src/internal/poll/fd_unix.go
src/internal/poll/fd_windows.go
src/internal/poll/fd_writev_darwin.go
src/internal/poll/fd_writev_illumos.go
src/internal/poll/fd_writev_unix.go
src/internal/poll/hook_cloexec.go
src/internal/poll/hook_unix.go
src/internal/poll/iovec_illumos.go
src/internal/poll/iovec_unix.go
src/internal/poll/sendfile_bsd.go
src/internal/poll/sock_cloexec.go
src/internal/poll/sockopt.go
src/internal/poll/sockopt_unix.go
src/internal/poll/sockoptip.go
src/internal/poll/splice_linux.go
src/internal/poll/splice_linux_test.go
src/internal/poll/strconv.go
src/internal/poll/sys_cloexec.go
src/internal/poll/writev.go
src/internal/profile/legacy_profile.go
src/internal/reflectlite/tostring_test.go
src/internal/reflectlite/type.go
src/internal/reflectlite/value.go
src/internal/syscall/execenv/execenv_default.go
src/internal/syscall/execenv/execenv_windows.go
src/internal/syscall/unix/at.go
src/internal/syscall/unix/at_libc.go
src/internal/syscall/unix/at_sysnum_fstatat64_linux.go
src/internal/syscall/unix/at_sysnum_fstatat_linux.go
src/internal/syscall/unix/at_sysnum_newfstatat_linux.go
src/internal/syscall/unix/fcntl_linux_32bit.go
src/internal/syscall/unix/getentropy_darwin.go
src/internal/syscall/unix/getrandom.go
src/internal/syscall/unix/ioctl_aix.go
src/internal/syscall/unix/net.go [new file with mode: 0644]
src/internal/syscall/unix/net_js.go [new file with mode: 0644]
src/internal/syscall/unix/nonblocking.go
src/internal/syscall/unix/nonblocking_js.go
src/internal/syscall/unix/nonblocking_libc.go
src/internal/syscall/unix/pipe2_illumos.go
src/internal/syscall/unix/sysnum_linux_generic.go
src/internal/syscall/unix/sysnum_linux_mips64x.go
src/internal/syscall/unix/sysnum_linux_mipsx.go
src/internal/syscall/unix/sysnum_linux_ppc64x.go
src/internal/syscall/unix/writev_illumos.go
src/internal/syscall/windows/exec_windows_test.go
src/internal/syscall/windows/mksyscall.go
src/internal/syscall/windows/net_windows.go [new file with mode: 0644]
src/internal/syscall/windows/registry/export_test.go
src/internal/syscall/windows/registry/key.go
src/internal/syscall/windows/registry/mksyscall.go
src/internal/syscall/windows/registry/registry_test.go
src/internal/syscall/windows/registry/syscall.go
src/internal/syscall/windows/registry/value.go
src/internal/syscall/windows/sysdll/sysdll.go
src/internal/testenv/testenv_cgo.go
src/internal/testenv/testenv_notwin.go
src/io/example_test.go
src/io/io.go
src/io/io_test.go
src/io/multi_test.go
src/io/pipe.go
src/log/log.go
src/log/log_test.go
src/log/syslog/example_test.go
src/log/syslog/syslog.go
src/log/syslog/syslog_test.go
src/log/syslog/syslog_unix.go
src/make.bash
src/make.rc
src/math/big/arith_amd64.s
src/math/big/float.go
src/math/cmplx/huge_test.go
src/math/dim_asm.go
src/math/dim_noasm.go
src/math/example_test.go
src/math/exp2_asm.go
src/math/exp2_noasm.go
src/math/exp_amd64.go
src/math/exp_asm.go
src/math/exp_noasm.go
src/math/floor_asm.go
src/math/floor_noasm.go
src/math/huge_test.go
src/math/hypot_asm.go
src/math/hypot_noasm.go
src/math/log_asm.go
src/math/log_stub.go
src/math/modf_asm.go
src/math/modf_noasm.go
src/math/rand/gen_cooked.go
src/math/sinh_s390x.s
src/math/sqrt_asm.go
src/math/sqrt_noasm.go
src/math/stubs.go
src/math/tan_s390x.s
src/mime/encodedword.go
src/mime/mediatype.go
src/mime/type_unix.go
src/mime/type_unix_test.go
src/net/addrselect.go
src/net/addrselect_test.go
src/net/cgo_aix.go
src/net/cgo_android.go
src/net/cgo_bsd.go
src/net/cgo_linux.go
src/net/cgo_netbsd.go
src/net/cgo_openbsd.go
src/net/cgo_resnew.go
src/net/cgo_resold.go
src/net/cgo_socknew.go
src/net/cgo_sockold.go
src/net/cgo_solaris.go
src/net/cgo_stub.go
src/net/cgo_unix.go
src/net/cgo_unix_test.go
src/net/cgo_windows.go
src/net/conf.go
src/net/conf_netcgo.go
src/net/conf_test.go
src/net/conn_test.go
src/net/dial_test.go
src/net/dial_unix_test.go
src/net/dnsclient.go
src/net/dnsclient_unix.go
src/net/dnsclient_unix_test.go
src/net/dnsconfig_unix.go
src/net/dnsconfig_unix_test.go
src/net/dnsname_test.go
src/net/error_posix.go
src/net/error_posix_test.go
src/net/error_test.go
src/net/error_unix.go
src/net/error_unix_test.go
src/net/example_test.go
src/net/external_test.go
src/net/fcntl_libc_test.go
src/net/fcntl_syscall_test.go
src/net/fd_posix.go
src/net/fd_unix.go
src/net/file_stub.go
src/net/file_test.go
src/net/file_unix.go
src/net/hook_unix.go
src/net/hosts.go
src/net/hosts_test.go
src/net/http/cgi/child.go
src/net/http/cgi/host.go
src/net/http/cgi/host_test.go
src/net/http/cgi/plan9_test.go
src/net/http/cgi/posix_test.go
src/net/http/client_test.go
src/net/http/cookie.go
src/net/http/cookie_test.go
src/net/http/fs.go
src/net/http/h2_bundle.go
src/net/http/header.go
src/net/http/header_test.go
src/net/http/httputil/reverseproxy.go
src/net/http/httputil/reverseproxy_test.go
src/net/http/internal/chunked.go
src/net/http/internal/chunked_test.go
src/net/http/main_test.go
src/net/http/omithttp2.go
src/net/http/pprof/pprof.go
src/net/http/request.go
src/net/http/request_test.go
src/net/http/response.go
src/net/http/roundtrip.go
src/net/http/roundtrip_js.go
src/net/http/serve_test.go
src/net/http/server.go
src/net/http/server_test.go
src/net/http/transfer.go
src/net/http/transport.go
src/net/http/transport_default_js.go [new file with mode: 0644]
src/net/http/transport_default_other.go [new file with mode: 0644]
src/net/http/transport_test.go
src/net/http/triv.go
src/net/interface_aix.go
src/net/interface_bsd.go
src/net/interface_bsd_test.go
src/net/interface_bsdvar.go
src/net/interface_freebsd.go
src/net/interface_stub.go
src/net/interface_test.go
src/net/interface_unix_test.go
src/net/internal/socktest/main_test.go
src/net/internal/socktest/main_unix_test.go
src/net/internal/socktest/switch_posix.go
src/net/internal/socktest/switch_stub.go
src/net/internal/socktest/switch_unix.go
src/net/internal/socktest/sys_cloexec.go
src/net/internal/socktest/sys_unix.go
src/net/ip_test.go
src/net/iprawsock_posix.go
src/net/iprawsock_test.go
src/net/ipsock_posix.go
src/net/listen_test.go
src/net/lookup.go
src/net/lookup_fake.go
src/net/lookup_plan9.go
src/net/lookup_test.go
src/net/lookup_unix.go
src/net/lookup_windows.go
src/net/lookup_windows_test.go
src/net/mail/message.go
src/net/main_cloexec_test.go
src/net/main_conf_test.go
src/net/main_noconf_test.go
src/net/main_posix_test.go
src/net/main_test.go
src/net/main_unix_test.go
src/net/mockserver_test.go
src/net/net.go
src/net/net_fake.go
src/net/net_test.go
src/net/netgo_unix_test.go
src/net/netip/export_test.go [new file with mode: 0644]
src/net/netip/inlining_test.go [new file with mode: 0644]
src/net/netip/leaf_alts.go [new file with mode: 0644]
src/net/netip/netip.go [new file with mode: 0644]
src/net/netip/netip_pkg_test.go [new file with mode: 0644]
src/net/netip/netip_test.go [new file with mode: 0644]
src/net/netip/slow_test.go [new file with mode: 0644]
src/net/netip/uint128.go [new file with mode: 0644]
src/net/netip/uint128_test.go [new file with mode: 0644]
src/net/nss.go
src/net/nss_test.go
src/net/packetconn_test.go
src/net/parse.go
src/net/parse_test.go
src/net/platform_test.go
src/net/port_unix.go
src/net/protoconn_test.go
src/net/rawconn_stub_test.go
src/net/rawconn_test.go
src/net/rawconn_unix_test.go
src/net/rpc/client_test.go
src/net/rpc/server.go
src/net/sendfile_stub.go
src/net/sendfile_test.go
src/net/sendfile_unix_alt.go
src/net/server_test.go
src/net/smtp/smtp.go
src/net/sock_bsd.go
src/net/sock_cloexec.go
src/net/sock_posix.go
src/net/sock_stub.go
src/net/sockaddr_posix.go
src/net/sockopt_bsd.go
src/net/sockopt_posix.go
src/net/sockopt_stub.go
src/net/sockoptip_bsdvar.go
src/net/sockoptip_posix.go
src/net/sockoptip_stub.go
src/net/splice_stub.go
src/net/splice_test.go
src/net/sys_cloexec.go
src/net/tcpsock.go
src/net/tcpsock_posix.go
src/net/tcpsock_test.go
src/net/tcpsock_unix_test.go
src/net/tcpsockopt_posix.go
src/net/tcpsockopt_stub.go
src/net/tcpsockopt_unix.go
src/net/textproto/reader.go
src/net/timeout_test.go
src/net/udpsock.go
src/net/udpsock_plan9.go
src/net/udpsock_posix.go
src/net/udpsock_test.go
src/net/unixsock_posix.go
src/net/unixsock_readmsg_cloexec.go
src/net/unixsock_readmsg_cmsg_cloexec.go
src/net/unixsock_readmsg_other.go
src/net/unixsock_readmsg_test.go
src/net/unixsock_test.go
src/net/unixsock_windows_test.go
src/net/url/example_test.go
src/net/url/url.go
src/net/url/url_test.go
src/net/write_unix_test.go
src/net/writev_test.go
src/net/writev_unix.go
src/os/dir_unix.go
src/os/endian_big.go
src/os/endian_little.go
src/os/env_unix_test.go
src/os/error_errno.go
src/os/error_posix.go
src/os/error_unix_test.go
src/os/error_windows_test.go
src/os/exec.go
src/os/exec/exec.go
src/os/exec/exec_linux_test.go
src/os/exec/exec_posix_test.go
src/os/exec/exec_test.go
src/os/exec/exec_unix.go
src/os/exec/exec_windows_test.go
src/os/exec/lp_js.go
src/os/exec/lp_unix.go
src/os/exec/lp_unix_test.go
src/os/exec/read3.go
src/os/exec_posix.go
src/os/exec_unix.go
src/os/exec_unix_test.go
src/os/executable_path.go
src/os/executable_plan9.go
src/os/executable_procfs.go
src/os/executable_sysctl.go
src/os/export_unix_test.go
src/os/fifo_test.go
src/os/file_posix.go
src/os/file_unix.go
src/os/os_test.go
src/os/os_unix_test.go
src/os/path_unix.go
src/os/pipe2_bsd.go
src/os/pipe2_illumos.go
src/os/pipe_bsd.go
src/os/pipe_linux.go
src/os/pipe_test.go
src/os/rawconn.go
src/os/rawconn_test.go
src/os/readfrom_stub.go
src/os/removeall_at.go
src/os/removeall_noat.go
src/os/signal/example_unix_test.go
src/os/signal/internal/pty/pty.go
src/os/signal/signal_cgo_test.go
src/os/signal/signal_linux_test.go
src/os/signal/signal_test.go
src/os/signal/signal_unix.go
src/os/stat_js.go
src/os/stat_unix.go
src/os/sticky_bsd.go
src/os/sticky_notbsd.go
src/os/sys_bsd.go
src/os/sys_js.go
src/os/sys_unix.go
src/os/timeout_test.go
src/os/types_unix.go
src/os/user/cgo_listgroups_unix.go [new file with mode: 0644]
src/os/user/cgo_lookup_unix.go
src/os/user/cgo_unix_test.go
src/os/user/getgrouplist_darwin.go
src/os/user/getgrouplist_unix.go
src/os/user/listgroups_aix.go [deleted file]
src/os/user/listgroups_illumos.go [deleted file]
src/os/user/listgroups_stub.go [new file with mode: 0644]
src/os/user/listgroups_unix.go
src/os/user/listgroups_unix_test.go [new file with mode: 0644]
src/os/user/lookup_android.go
src/os/user/lookup_plan9.go
src/os/user/lookup_stubs.go
src/os/user/lookup_unix.go
src/os/user/lookup_unix_test.go
src/os/user/user.go
src/os/user/user_test.go
src/os/wait_unimp.go
src/os/wait_wait6.go
src/os/wait_waitid.go
src/path/filepath/example_unix_test.go
src/path/filepath/example_unix_walk_test.go
src/path/filepath/path_test.go
src/path/filepath/path_unix.go
src/path/filepath/path_windows.go
src/path/filepath/symlink_unix.go
src/plugin/plugin_dlopen.go
src/plugin/plugin_stubs.go
src/plugin/plugin_test.go
src/race.bash
src/reflect/abi.go
src/reflect/abi_test.go
src/reflect/all_test.go
src/reflect/asm_ppc64x.s
src/reflect/deepequal.go
src/reflect/example_test.go
src/reflect/export_test.go
src/reflect/float32reg_generic.go [new file with mode: 0644]
src/reflect/float32reg_ppc64x.s [new file with mode: 0644]
src/reflect/makefunc.go
src/reflect/set_test.go
src/reflect/stubs_ppc64x.go [new file with mode: 0644]
src/reflect/tostring_test.go
src/reflect/type.go
src/reflect/value.go
src/reflect/visiblefields.go
src/reflect/visiblefields_test.go
src/regexp/all_test.go
src/regexp/exec2_test.go
src/regexp/exec_test.go
src/regexp/find_test.go
src/regexp/onepass.go
src/regexp/regexp.go
src/regexp/syntax/parse.go
src/regexp/syntax/prog.go
src/runtime/abi_test.go
src/runtime/asan.go [new file with mode: 0644]
src/runtime/asan/asan.go [new file with mode: 0644]
src/runtime/asan0.go [new file with mode: 0644]
src/runtime/asan_amd64.s [new file with mode: 0644]
src/runtime/asan_arm64.s [new file with mode: 0644]
src/runtime/asm.s
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_arm.s
src/runtime/asm_arm64.s
src/runtime/asm_mips64x.s
src/runtime/asm_mipsx.s
src/runtime/asm_ppc64x.s
src/runtime/asm_riscv64.s
src/runtime/asm_s390x.s
src/runtime/auxv_none.go
src/runtime/cgo/asm_riscv64.s
src/runtime/cgo/callbacks_traceback.go
src/runtime/cgo/dragonfly.go
src/runtime/cgo/freebsd.go
src/runtime/cgo/gcc_sigaction.c
src/runtime/cgo/linux.go
src/runtime/cgo/mmap.go
src/runtime/cgo/netbsd.go
src/runtime/cgo/openbsd.go
src/runtime/cgo/setenv.go
src/runtime/cgo/sigaction.go
src/runtime/cgo_mmap.go
src/runtime/cgo_ppc64x.go
src/runtime/cgo_sigaction.go
src/runtime/cgocall.go
src/runtime/checkptr_test.go
src/runtime/cpuflags.go
src/runtime/cputicks.go
src/runtime/crash_cgo_test.go
src/runtime/crash_nonunix_test.go
src/runtime/crash_unix_test.go
src/runtime/debug.go
src/runtime/debug/mod.go
src/runtime/debug/panic_test.go
src/runtime/debug_test.go
src/runtime/debugcall.go
src/runtime/debuglog.go
src/runtime/debuglog_off.go
src/runtime/debuglog_on.go
src/runtime/defer_test.go
src/runtime/defs1_linux.go
src/runtime/defs2_linux.go
src/runtime/defs3_linux.go
src/runtime/defs_aix.go
src/runtime/defs_aix_ppc64.go
src/runtime/defs_arm_linux.go
src/runtime/defs_darwin.go
src/runtime/defs_dragonfly.go
src/runtime/defs_freebsd.go
src/runtime/defs_linux.go
src/runtime/defs_linux_386.go
src/runtime/defs_linux_amd64.go
src/runtime/defs_linux_arm.go
src/runtime/defs_linux_arm64.go
src/runtime/defs_linux_mips64x.go
src/runtime/defs_linux_mipsx.go
src/runtime/defs_linux_ppc64.go
src/runtime/defs_linux_ppc64le.go
src/runtime/defs_linux_riscv64.go
src/runtime/defs_linux_s390x.go
src/runtime/defs_netbsd.go
src/runtime/defs_netbsd_386.go
src/runtime/defs_netbsd_amd64.go
src/runtime/defs_netbsd_arm.go
src/runtime/defs_openbsd.go
src/runtime/defs_solaris.go
src/runtime/defs_solaris_amd64.go
src/runtime/duff_ppc64x.s
src/runtime/env_posix.go
src/runtime/export_debug_regabiargs_off_test.go
src/runtime/export_debug_regabiargs_on_test.go
src/runtime/export_debug_test.go
src/runtime/export_futex_test.go
src/runtime/export_linux_test.go
src/runtime/export_mmap_test.go
src/runtime/export_pipe2_test.go
src/runtime/export_pipe_test.go
src/runtime/export_test.go
src/runtime/export_unix_test.go
src/runtime/export_windows_test.go
src/runtime/extern.go
src/runtime/float_test.go [new file with mode: 0644]
src/runtime/funcdata.h
src/runtime/futex_test.go
src/runtime/gc_test.go
src/runtime/hash32.go
src/runtime/hash64.go
src/runtime/heapdump.go
src/runtime/iface.go
src/runtime/internal/atomic/atomic_386.go
src/runtime/internal/atomic/atomic_arm.go
src/runtime/internal/atomic/atomic_arm64.go
src/runtime/internal/atomic/atomic_mips64x.go
src/runtime/internal/atomic/atomic_mipsx.go
src/runtime/internal/atomic/atomic_ppc64x.go
src/runtime/internal/atomic/doc.go [new file with mode: 0644]
src/runtime/internal/atomic/stubs.go
src/runtime/internal/atomic/types.go [new file with mode: 0644]
src/runtime/internal/atomic/types_64bit.go [new file with mode: 0644]
src/runtime/internal/sys/intrinsics.go
src/runtime/internal/sys/intrinsics_common.go
src/runtime/internal/sys/intrinsics_stubs.go
src/runtime/lfstack_32bit.go
src/runtime/lfstack_64bit.go
src/runtime/libfuzzer.go
src/runtime/lock_futex.go
src/runtime/lock_js.go
src/runtime/lock_sema.go
src/runtime/lockrank_off.go
src/runtime/lockrank_on.go
src/runtime/malloc.go
src/runtime/map.go
src/runtime/map_test.go
src/runtime/mbarrier.go
src/runtime/mbitmap.go
src/runtime/mcache.go
src/runtime/mcentral.go
src/runtime/mem_bsd.go
src/runtime/mem_js.go
src/runtime/memclr_386.s
src/runtime/memclr_ppc64x.s
src/runtime/memmove_386.s
src/runtime/memmove_ppc64x.s
src/runtime/mfixalloc.go
src/runtime/mgc.go
src/runtime/mgcmark.go
src/runtime/mgcpacer.go
src/runtime/mgcpacer_test.go [new file with mode: 0644]
src/runtime/mgcscavenge.go
src/runtime/mgcsweep.go
src/runtime/mgcwork.go
src/runtime/mheap.go
src/runtime/mkduff.go
src/runtime/mkfastlog2table.go
src/runtime/mkpreempt.go
src/runtime/mksizeclasses.go
src/runtime/mmap.go
src/runtime/mpagealloc.go
src/runtime/mpagealloc_32bit.go
src/runtime/mpagealloc_64bit.go
src/runtime/mpagecache.go
src/runtime/mpagecache_test.go
src/runtime/mpallocbits.go
src/runtime/mprof.go
src/runtime/msan.go
src/runtime/msan/msan.go
src/runtime/msan0.go
src/runtime/nbpipe_fcntl_libc_test.go
src/runtime/nbpipe_fcntl_unix_test.go
src/runtime/nbpipe_pipe.go
src/runtime/nbpipe_pipe2.go
src/runtime/nbpipe_test.go
src/runtime/netpoll.go
src/runtime/netpoll_epoll.go
src/runtime/netpoll_fake.go
src/runtime/netpoll_kqueue.go
src/runtime/netpoll_stub.go
src/runtime/norace_linux_test.go
src/runtime/norace_test.go
src/runtime/os3_solaris.go
src/runtime/os_aix.go
src/runtime/os_darwin.go
src/runtime/os_dragonfly.go
src/runtime/os_freebsd.go
src/runtime/os_freebsd2.go
src/runtime/os_freebsd_noauxv.go
src/runtime/os_js.go
src/runtime/os_linux.go
src/runtime/os_linux_arm64.go
src/runtime/os_linux_be64.go
src/runtime/os_linux_generic.go
src/runtime/os_linux_mips64x.go
src/runtime/os_linux_mipsx.go
src/runtime/os_linux_noauxv.go
src/runtime/os_linux_novdso.go
src/runtime/os_linux_ppc64x.go
src/runtime/os_linux_x86.go
src/runtime/os_netbsd.go
src/runtime/os_nonopenbsd.go
src/runtime/os_only_solaris.go
src/runtime/os_openbsd.go
src/runtime/os_openbsd_libc.go
src/runtime/os_openbsd_syscall.go
src/runtime/os_openbsd_syscall1.go
src/runtime/os_openbsd_syscall2.go
src/runtime/os_windows.go
src/runtime/panic.go
src/runtime/panic32.go
src/runtime/plugin.go
src/runtime/pprof/mprof_test.go
src/runtime/pprof/pprof_norusage.go
src/runtime/pprof/pprof_rusage.go
src/runtime/pprof/pprof_test.go
src/runtime/pprof/proto.go
src/runtime/pprof/proto_test.go
src/runtime/pprof/rusage_test.go [new file with mode: 0644]
src/runtime/preempt.go
src/runtime/preempt_386.s
src/runtime/preempt_nonwindows.go
src/runtime/preempt_riscv64.s
src/runtime/print.go
src/runtime/proc.go
src/runtime/race.go
src/runtime/race/output_test.go
src/runtime/race/race.go
src/runtime/race/race_linux_test.go
src/runtime/race/race_test.go
src/runtime/race/race_unix_test.go
src/runtime/race/race_windows_test.go
src/runtime/race/sched_test.go
src/runtime/race/syso_test.go
src/runtime/race/timer_test.go
src/runtime/race0.go
src/runtime/race_ppc64le.s
src/runtime/relax_stub.go
src/runtime/rt0_linux_riscv64.s
src/runtime/runtime-gdb.py
src/runtime/runtime-gdb_test.go
src/runtime/runtime2.go
src/runtime/runtime_linux_test.go
src/runtime/runtime_mmap_test.go
src/runtime/runtime_unix_test.go
src/runtime/select.go
src/runtime/semasleep_test.go
src/runtime/sigaction.go
src/runtime/signal_386.go
src/runtime/signal_aix_ppc64.go
src/runtime/signal_amd64.go
src/runtime/signal_arm.go
src/runtime/signal_arm64.go
src/runtime/signal_linux_mips64x.go
src/runtime/signal_linux_mipsx.go
src/runtime/signal_linux_ppc64x.go
src/runtime/signal_mips64x.go
src/runtime/signal_mipsx.go
src/runtime/signal_ppc64x.go
src/runtime/signal_riscv64.go
src/runtime/signal_unix.go
src/runtime/signal_windows.go
src/runtime/signal_windows_test.go
src/runtime/sigqueue.go
src/runtime/sigqueue_note.go
src/runtime/sigtab_linux_generic.go
src/runtime/sigtab_linux_mipsx.go
src/runtime/slice.go
src/runtime/softfloat64.go
src/runtime/stack.go
src/runtime/stack_test.go
src/runtime/string.go
src/runtime/stubs.go
src/runtime/stubs2.go
src/runtime/stubs3.go
src/runtime/stubs_linux.go
src/runtime/stubs_mips64x.go
src/runtime/stubs_mipsx.go
src/runtime/stubs_nonlinux.go
src/runtime/stubs_ppc64.go
src/runtime/stubs_ppc64x.go [moved from src/runtime/stubs_ppc64le.go with 59% similarity]
src/runtime/symtab.go
src/runtime/symtab_test.go
src/runtime/sys_darwin_amd64.s
src/runtime/sys_freebsd_amd64.s
src/runtime/sys_libc.go
src/runtime/sys_linux_386.s
src/runtime/sys_linux_amd64.s
src/runtime/sys_linux_arm.s
src/runtime/sys_linux_arm64.s
src/runtime/sys_linux_mips64x.s
src/runtime/sys_linux_mipsx.s
src/runtime/sys_linux_ppc64x.s
src/runtime/sys_linux_riscv64.s
src/runtime/sys_linux_s390x.s
src/runtime/sys_mips64x.go
src/runtime/sys_mipsx.go
src/runtime/sys_nonppc64x.go
src/runtime/sys_openbsd.go
src/runtime/sys_openbsd1.go
src/runtime/sys_openbsd2.go
src/runtime/sys_openbsd3.go
src/runtime/sys_plan9_amd64.s
src/runtime/sys_ppc64x.go
src/runtime/sys_windows_amd64.s
src/runtime/sys_windows_arm.s
src/runtime/sys_windows_arm64.s
src/runtime/sys_x86.go
src/runtime/syscall_windows.go
src/runtime/syscall_windows_test.go
src/runtime/testdata/testprog/checkptr.go
src/runtime/testdata/testprog/numcpu_freebsd.go
src/runtime/testdata/testprog/traceback_ancestors.go
src/runtime/testdata/testprogcgo/panic.c [new file with mode: 0644]
src/runtime/testdata/testprogcgo/panic.go [new file with mode: 0644]
src/runtime/testdata/testprogcgo/sigthrow.go [new file with mode: 0644]
src/runtime/time.go
src/runtime/time_fake.go
src/runtime/time_linux_amd64.s
src/runtime/time_nofake.go
src/runtime/time_windows.h
src/runtime/time_windows_amd64.s
src/runtime/time_windows_arm.s
src/runtime/time_windows_arm64.s
src/runtime/timeasm.go
src/runtime/timestub.go
src/runtime/timestub2.go
src/runtime/tls_riscv64.s
src/runtime/tls_stub.go
src/runtime/trace.go
src/runtime/traceback.go
src/runtime/traceback_test.go
src/runtime/type.go
src/runtime/vdso_elf32.go
src/runtime/vdso_elf64.go
src/runtime/vdso_freebsd.go
src/runtime/vdso_freebsd_x86.go
src/runtime/vdso_in_none.go
src/runtime/vdso_linux.go
src/runtime/vdso_linux_mips64x.go
src/runtime/vdso_linux_ppc64x.go
src/runtime/vdso_linux_riscv64.go [new file with mode: 0644]
src/runtime/vlrt.go
src/runtime/wincallback.go
src/runtime/write_err.go
src/strconv/fp_test.go
src/strconv/ftoaryu.go
src/strconv/quote.go
src/strconv/quote_test.go
src/strings/clone.go [new file with mode: 0644]
src/strings/clone_test.go [new file with mode: 0644]
src/strings/compare.go
src/strings/example_test.go
src/strings/replace.go
src/strings/strings.go
src/strings/strings_test.go
src/sync/atomic/atomic_test.go
src/sync/atomic/value.go
src/sync/example_test.go
src/sync/mutex.go
src/sync/mutex_test.go
src/sync/pool.go
src/sync/pool_test.go
src/sync/runtime2.go
src/sync/runtime2_lockrank.go
src/sync/rwmutex.go
src/sync/rwmutex_test.go
src/sync/waitgroup.go
src/sync/waitgroup_test.go
src/syscall/asan.go [new file with mode: 0644]
src/syscall/asan0.go [new file with mode: 0644]
src/syscall/bpf_bsd.go
src/syscall/creds_test.go
src/syscall/dirent.go
src/syscall/dirent_test.go
src/syscall/dll_windows.go
src/syscall/endian_big.go
src/syscall/endian_little.go
src/syscall/env_unix.go
src/syscall/exec_aix_test.go
src/syscall/exec_bsd.go
src/syscall/exec_freebsd.go [new file with mode: 0644]
src/syscall/exec_libc.go
src/syscall/exec_libc2.go
src/syscall/exec_linux.go
src/syscall/exec_linux_test.go
src/syscall/exec_pdeathsig_test.go [new file with mode: 0644]
src/syscall/exec_solaris_test.go
src/syscall/exec_unix.go
src/syscall/exec_unix_test.go
src/syscall/exec_windows.go
src/syscall/export_unix_test.go
src/syscall/flock.go
src/syscall/flock_linux_32bit.go
src/syscall/forkpipe.go
src/syscall/forkpipe2.go
src/syscall/fs_js.go
src/syscall/getdirentries_test.go
src/syscall/js/export_test.go
src/syscall/js/func.go
src/syscall/js/js.go
src/syscall/js/js_test.go
src/syscall/mkasm.go
src/syscall/mkpost.go
src/syscall/mksyscall_windows.go
src/syscall/mmap_unix_test.go
src/syscall/msan.go
src/syscall/msan0.go
src/syscall/net_js.go
src/syscall/netlink_linux.go
src/syscall/ptrace_darwin.go
src/syscall/ptrace_ios.go
src/syscall/route_bsd.go
src/syscall/route_freebsd_32bit.go
src/syscall/route_freebsd_64bit.go
src/syscall/setuidgid_32_linux.go
src/syscall/setuidgid_linux.go
src/syscall/sockcmsg_unix.go
src/syscall/sockcmsg_unix_other.go
src/syscall/syscall_aix.go
src/syscall/syscall_bsd.go
src/syscall/syscall_bsd_test.go
src/syscall/syscall_darwin.go
src/syscall/syscall_dragonfly.go
src/syscall/syscall_dup2_linux.go [deleted file]
src/syscall/syscall_dup3_linux.go [deleted file]
src/syscall/syscall_freebsd.go
src/syscall/syscall_freebsd_test.go
src/syscall/syscall_illumos.go
src/syscall/syscall_js.go
src/syscall/syscall_linux.go
src/syscall/syscall_linux_386.go
src/syscall/syscall_linux_amd64.go
src/syscall/syscall_linux_arm.go
src/syscall/syscall_linux_arm64.go
src/syscall/syscall_linux_mips64x.go
src/syscall/syscall_linux_mipsx.go
src/syscall/syscall_linux_ppc64x.go
src/syscall/syscall_linux_riscv64.go
src/syscall/syscall_linux_s390x.go
src/syscall/syscall_linux_test.go
src/syscall/syscall_netbsd.go
src/syscall/syscall_openbsd.go
src/syscall/syscall_openbsd1.go
src/syscall/syscall_openbsd_libc.go
src/syscall/syscall_openbsd_mips64.go
src/syscall/syscall_ptrace_test.go
src/syscall/syscall_solaris.go
src/syscall/syscall_unix.go
src/syscall/syscall_unix_test.go
src/syscall/syscall_windows.go
src/syscall/tables_js.go
src/syscall/time_fake.go
src/syscall/time_nofake.go
src/syscall/timestruct.go
src/syscall/types_aix.go
src/syscall/types_darwin.go
src/syscall/types_dragonfly.go
src/syscall/types_freebsd.go
src/syscall/types_illumos_amd64.go
src/syscall/types_linux.go
src/syscall/types_netbsd.go
src/syscall/types_openbsd.go
src/syscall/types_solaris.go
src/syscall/zerrors_darwin_amd64.go
src/syscall/zerrors_darwin_arm64.go
src/syscall/zerrors_dragonfly_amd64.go
src/syscall/zerrors_freebsd_386.go
src/syscall/zerrors_freebsd_amd64.go
src/syscall/zerrors_freebsd_arm.go
src/syscall/zerrors_freebsd_arm64.go
src/syscall/zerrors_linux_386.go
src/syscall/zerrors_linux_amd64.go
src/syscall/zerrors_linux_arm.go
src/syscall/zerrors_linux_arm64.go
src/syscall/zerrors_linux_ppc64.go
src/syscall/zerrors_linux_ppc64le.go
src/syscall/zerrors_netbsd_386.go
src/syscall/zerrors_netbsd_amd64.go
src/syscall/zerrors_netbsd_arm.go
src/syscall/zerrors_netbsd_arm64.go
src/syscall/zerrors_openbsd_386.go
src/syscall/zerrors_openbsd_amd64.go
src/syscall/zerrors_openbsd_arm.go
src/syscall/zerrors_solaris_amd64.go
src/syscall/zsyscall_aix_ppc64.go
src/syscall/zsyscall_darwin_amd64.go
src/syscall/zsyscall_darwin_amd64.s
src/syscall/zsyscall_darwin_arm64.go
src/syscall/zsyscall_darwin_arm64.s
src/syscall/zsyscall_dragonfly_amd64.go
src/syscall/zsyscall_freebsd_386.go
src/syscall/zsyscall_freebsd_amd64.go
src/syscall/zsyscall_freebsd_arm.go
src/syscall/zsyscall_freebsd_arm64.go
src/syscall/zsyscall_linux_386.go
src/syscall/zsyscall_linux_amd64.go
src/syscall/zsyscall_linux_arm.go
src/syscall/zsyscall_linux_arm64.go
src/syscall/zsyscall_linux_mips.go
src/syscall/zsyscall_linux_mips64.go
src/syscall/zsyscall_linux_mips64le.go
src/syscall/zsyscall_linux_mipsle.go
src/syscall/zsyscall_linux_ppc64.go
src/syscall/zsyscall_linux_ppc64le.go
src/syscall/zsyscall_linux_riscv64.go
src/syscall/zsyscall_linux_s390x.go
src/syscall/zsyscall_netbsd_386.go
src/syscall/zsyscall_netbsd_amd64.go
src/syscall/zsyscall_netbsd_arm.go
src/syscall/zsyscall_netbsd_arm64.go
src/syscall/zsyscall_openbsd_386.go
src/syscall/zsyscall_openbsd_amd64.go
src/syscall/zsyscall_openbsd_arm.go
src/syscall/zsyscall_openbsd_arm64.go
src/syscall/zsyscall_openbsd_mips64.go
src/syscall/zsyscall_plan9_386.go
src/syscall/zsyscall_plan9_amd64.go
src/syscall/zsyscall_plan9_arm.go
src/syscall/zsyscall_solaris_amd64.go
src/syscall/zsyscall_windows.go
src/syscall/zsysnum_darwin_amd64.go
src/syscall/zsysnum_darwin_arm64.go
src/syscall/zsysnum_dragonfly_amd64.go
src/syscall/zsysnum_freebsd_386.go
src/syscall/zsysnum_freebsd_amd64.go
src/syscall/zsysnum_freebsd_arm.go
src/syscall/zsysnum_freebsd_arm64.go
src/syscall/zsysnum_linux_386.go
src/syscall/zsysnum_linux_amd64.go
src/syscall/zsysnum_linux_arm.go
src/syscall/zsysnum_linux_arm64.go
src/syscall/zsysnum_linux_ppc64.go
src/syscall/zsysnum_linux_ppc64le.go
src/syscall/zsysnum_netbsd_386.go
src/syscall/zsysnum_netbsd_amd64.go
src/syscall/zsysnum_netbsd_arm.go
src/syscall/zsysnum_netbsd_arm64.go
src/syscall/zsysnum_openbsd_386.go
src/syscall/zsysnum_openbsd_amd64.go
src/syscall/zsysnum_openbsd_arm.go
src/syscall/zsysnum_solaris_amd64.go
src/syscall/ztypes_darwin_amd64.go
src/syscall/ztypes_darwin_arm64.go
src/syscall/ztypes_dragonfly_amd64.go
src/syscall/ztypes_freebsd_386.go
src/syscall/ztypes_freebsd_amd64.go
src/syscall/ztypes_freebsd_arm.go
src/syscall/ztypes_freebsd_arm64.go
src/syscall/ztypes_linux_386.go
src/syscall/ztypes_linux_amd64.go
src/syscall/ztypes_linux_arm.go
src/syscall/ztypes_linux_arm64.go
src/syscall/ztypes_linux_ppc64.go
src/syscall/ztypes_linux_ppc64le.go
src/syscall/ztypes_netbsd_386.go
src/syscall/ztypes_netbsd_amd64.go
src/syscall/ztypes_netbsd_arm.go
src/syscall/ztypes_netbsd_arm64.go
src/syscall/ztypes_openbsd_386.go
src/syscall/ztypes_openbsd_amd64.go
src/syscall/ztypes_solaris_amd64.go
src/testing/benchmark.go
src/testing/fstest/mapfs.go
src/testing/fstest/mapfs_test.go
src/testing/fuzz.go [new file with mode: 0644]
src/testing/helper_test.go
src/testing/helperfuncs_test.go
src/testing/internal/testdeps/deps.go
src/testing/match.go
src/testing/match_test.go
src/testing/quick/quick.go
src/testing/run_example.go
src/testing/run_example_js.go
src/testing/sub_test.go
src/testing/testing.go
src/text/template/doc.go
src/text/template/exec.go
src/text/template/exec_test.go
src/text/template/funcs.go
src/text/template/multi_test.go
src/text/template/option.go
src/text/template/parse/lex.go
src/text/template/parse/lex_test.go
src/text/template/parse/node.go
src/text/template/parse/parse.go
src/text/template/parse/parse_test.go
src/text/template/template.go
src/time/embed.go
src/time/format.go
src/time/format_test.go
src/time/genzabbrs.go
src/time/internal_test.go
src/time/sleep.go
src/time/sleep_test.go
src/time/sys_plan9.go
src/time/sys_unix.go
src/time/tick.go
src/time/tick_test.go
src/time/time.go
src/time/time_test.go
src/time/tzdata/generate_zipdata.go
src/time/zoneinfo.go
src/time/zoneinfo_ios.go
src/time/zoneinfo_js.go
src/time/zoneinfo_unix.go
src/time/zoneinfo_unix_test.go
src/unicode/example_test.go
src/unicode/utf8/utf8.go
src/unicode/utf8/utf8_test.go
src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s
src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s
src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
src/vendor/golang.org/x/crypto/curve25519/curve25519.go
src/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go [deleted file]
src/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s [deleted file]
src/vendor/golang.org/x/crypto/curve25519/curve25519_generic.go [deleted file]
src/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go [deleted file]
src/vendor/golang.org/x/crypto/curve25519/internal/field/README [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint [new file with mode: 0644]
src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh [new file with mode: 0644]
src/vendor/golang.org/x/crypto/poly1305/sum_amd64.s
src/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s
src/vendor/golang.org/x/crypto/poly1305/sum_s390x.s
src/vendor/golang.org/x/net/route/address.go
src/vendor/golang.org/x/net/route/message.go
src/vendor/golang.org/x/net/route/sys_freebsd.go
src/vendor/golang.org/x/sys/cpu/cpu.go
src/vendor/golang.org/x/sys/cpu/cpu_x86.go
src/vendor/modules.txt
test/abi/method_wrapper.go [new file with mode: 0644]
test/asmhdr.dir/main.go [new file with mode: 0644]
test/asmhdr.dir/main.s [new file with mode: 0644]
test/asmhdr.go [new file with mode: 0644]
test/codegen/arithmetic.go
test/codegen/bitfield.go
test/codegen/bits.go
test/codegen/bmi.go [new file with mode: 0644]
test/codegen/bool.go
test/codegen/comparisons.go
test/codegen/copy.go
test/codegen/issue48054.go [new file with mode: 0644]
test/codegen/math.go
test/codegen/mathbits.go
test/codegen/memcombine.go
test/codegen/noextend.go
test/codegen/rotate.go
test/codegen/shift.go
test/fixedbugs/bug062.go
test/fixedbugs/bug131.go
test/fixedbugs/bug175.go
test/fixedbugs/bug289.go
test/fixedbugs/gcc101994.go [new file with mode: 0644]
test/fixedbugs/issue10975.go
test/fixedbugs/issue14652.go
test/fixedbugs/issue19323.go
test/fixedbugs/issue26616.go
test/fixedbugs/issue27595.go
test/fixedbugs/issue32901.dir/main.go
test/fixedbugs/issue46938.go [new file with mode: 0644]
test/fixedbugs/issue47068.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue47068.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue47068.dir/main.go [new file with mode: 0644]
test/fixedbugs/issue47068.go [moved from src/internal/cpu/cpu_386.go with 54% similarity]
test/fixedbugs/issue47712.go [new file with mode: 0644]
test/fixedbugs/issue47771.go [new file with mode: 0644]
test/fixedbugs/issue47928.go [new file with mode: 0644]
test/fixedbugs/issue48026.go [new file with mode: 0644]
test/fixedbugs/issue48033.go [new file with mode: 0644]
test/fixedbugs/issue48088.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue48088.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue48088.go [moved from src/internal/cpu/cpu_amd64.go with 54% similarity]
test/fixedbugs/issue48092.go [new file with mode: 0644]
test/fixedbugs/issue48097.go [new file with mode: 0644]
test/fixedbugs/issue48230.go [new file with mode: 0644]
test/fixedbugs/issue48289.go [new file with mode: 0644]
test/fixedbugs/issue48301.go [new file with mode: 0644]
test/fixedbugs/issue48357.go [new file with mode: 0644]
test/fixedbugs/issue48459.go [new file with mode: 0644]
test/fixedbugs/issue48473.go [new file with mode: 0644]
test/fixedbugs/issue48476.go [new file with mode: 0644]
test/fixedbugs/issue48536.go [new file with mode: 0644]
test/fixedbugs/issue48558.go [new file with mode: 0644]
test/fixedbugs/issue48784.go [new file with mode: 0644]
test/fixedbugs/issue48898.go [new file with mode: 0644]
test/fixedbugs/issue48898.out [new file with mode: 0644]
test/fixedbugs/issue48916.go [new file with mode: 0644]
test/fixedbugs/issue49003.go [new file with mode: 0644]
test/fixedbugs/issue49005a.go [new file with mode: 0644]
test/fixedbugs/issue49005b.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/c.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/d.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/e.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/f.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/g.go [new file with mode: 0644]
test/fixedbugs/issue49016.go [new file with mode: 0644]
test/fixedbugs/issue49029.go [new file with mode: 0644]
test/fixedbugs/issue49094.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue49094.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue49094.dir/p.go [new file with mode: 0644]
test/fixedbugs/issue49094.go [new file with mode: 0644]
test/fixedbugs/issue49100.go [new file with mode: 0644]
test/fixedbugs/issue49100.out [new file with mode: 0644]
test/fixedbugs/issue49100b.go [new file with mode: 0644]
test/fixedbugs/issue49100b.out [new file with mode: 0644]
test/fixedbugs/issue49110.go [new file with mode: 0644]
test/fixedbugs/issue49122.go [new file with mode: 0644]
test/fixedbugs/issue49143.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue49143.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue49143.dir/c.go [new file with mode: 0644]
test/fixedbugs/issue49143.dir/p.go [new file with mode: 0644]
test/fixedbugs/issue49143.go [new file with mode: 0644]
test/fixedbugs/issue49145.go [new file with mode: 0644]
test/fixedbugs/issue49145.out [new file with mode: 0644]
test/fixedbugs/issue49240.go [new file with mode: 0644]
test/fixedbugs/issue49249.go [new file with mode: 0644]
test/fixedbugs/issue9083.go
test/inline.go
test/inline_endian.go [new file with mode: 0644]
test/interface/pointer.go
test/linkname.dir/linkname1.go
test/linkname2.go
test/live_regabi.go
test/maymorestack.go [new file with mode: 0644]
test/reflectmethod7.go
test/run.go
test/switch6.go
test/typeparam/absdiff.go
test/typeparam/absdiffimp.dir/a.go
test/typeparam/absdiffimp.dir/main.go
test/typeparam/aliasimp.dir/main.go
test/typeparam/append.go
test/typeparam/boundmethod.go
test/typeparam/double.go
test/typeparam/eface.go [new file with mode: 0644]
test/typeparam/genembed.go [new file with mode: 0644]
test/typeparam/genembed2.go [new file with mode: 0644]
test/typeparam/geninline.dir/a.go [new file with mode: 0644]
test/typeparam/geninline.dir/main.go [new file with mode: 0644]
test/typeparam/geninline.go [new file with mode: 0644]
test/typeparam/index2.go [new file with mode: 0644]
test/typeparam/issue44688.go
test/typeparam/issue46461.go [new file with mode: 0644]
test/typeparam/issue46461b.dir/a.go [new file with mode: 0644]
test/typeparam/issue46461b.dir/b.go [new file with mode: 0644]
test/typeparam/issue46461b.go [new file with mode: 0644]
test/typeparam/issue46591.go [new file with mode: 0644]
test/typeparam/issue47272.go [new file with mode: 0644]
test/typeparam/issue47272.out [new file with mode: 0644]
test/typeparam/issue47514c.dir/a.go [new file with mode: 0644]
test/typeparam/issue47514c.dir/main.go [new file with mode: 0644]
test/typeparam/issue47514c.go [new file with mode: 0644]
test/typeparam/issue47676.go [new file with mode: 0644]
test/typeparam/issue47684.go [new file with mode: 0644]
test/typeparam/issue47684b.go [new file with mode: 0644]
test/typeparam/issue47684c.go [new file with mode: 0644]
test/typeparam/issue47708.go [new file with mode: 0644]
test/typeparam/issue47710.go [new file with mode: 0644]
test/typeparam/issue47713.go [new file with mode: 0644]
test/typeparam/issue47713.out [new file with mode: 0644]
test/typeparam/issue47716.go [new file with mode: 0644]
test/typeparam/issue47723.go [new file with mode: 0644]
test/typeparam/issue47740.go [new file with mode: 0644]
test/typeparam/issue47740.out [new file with mode: 0644]
test/typeparam/issue47740b.go [new file with mode: 0644]
test/typeparam/issue47775.dir/b.go [new file with mode: 0644]
test/typeparam/issue47775.dir/main.go [new file with mode: 0644]
test/typeparam/issue47775.go [new file with mode: 0644]
test/typeparam/issue47775b.go [new file with mode: 0644]
test/typeparam/issue47797.go [new file with mode: 0644]
test/typeparam/issue47877.go [new file with mode: 0644]
test/typeparam/issue47878.go [new file with mode: 0644]
test/typeparam/issue47892.dir/a.go [new file with mode: 0644]
test/typeparam/issue47892.dir/main.go [new file with mode: 0644]
test/typeparam/issue47892.go [new file with mode: 0644]
test/typeparam/issue47892b.dir/a.go [new file with mode: 0644]
test/typeparam/issue47892b.dir/main.go [new file with mode: 0644]
test/typeparam/issue47892b.go [new file with mode: 0644]
test/typeparam/issue47896.go [new file with mode: 0644]
test/typeparam/issue47901.go [new file with mode: 0644]
test/typeparam/issue47924.go [new file with mode: 0644]
test/typeparam/issue47925.go [new file with mode: 0644]
test/typeparam/issue47925b.go [new file with mode: 0644]
test/typeparam/issue47925c.go [new file with mode: 0644]
test/typeparam/issue47925d.go [new file with mode: 0644]
test/typeparam/issue47929.go [new file with mode: 0644]
test/typeparam/issue47948.go [new file with mode: 0644]
test/typeparam/issue47966.go [new file with mode: 0644]
test/typeparam/issue48013.go [new file with mode: 0644]
test/typeparam/issue48016.go [new file with mode: 0644]
test/typeparam/issue48030.go [new file with mode: 0644]
test/typeparam/issue48042.go [new file with mode: 0644]
test/typeparam/issue48047.go [new file with mode: 0644]
test/typeparam/issue48049.go [new file with mode: 0644]
test/typeparam/issue48056.go [new file with mode: 0644]
test/typeparam/issue48094.dir/a.go [new file with mode: 0644]
test/typeparam/issue48094.dir/main.go [new file with mode: 0644]
test/typeparam/issue48094.go [new file with mode: 0644]
test/typeparam/issue48094b.dir/a.go [new file with mode: 0644]
test/typeparam/issue48094b.dir/b.go [new file with mode: 0644]
test/typeparam/issue48094b.go [new file with mode: 0644]
test/typeparam/issue48137.go [new file with mode: 0644]
test/typeparam/issue48185a.dir/p.go [new file with mode: 0644]
test/typeparam/issue48185a.dir/p_test.go [new file with mode: 0644]
test/typeparam/issue48185a.go [new file with mode: 0644]
test/typeparam/issue48185b.dir/a.go [new file with mode: 0644]
test/typeparam/issue48185b.dir/main.go [new file with mode: 0644]
test/typeparam/issue48185b.go [new file with mode: 0644]
test/typeparam/issue48191.go [new file with mode: 0644]
test/typeparam/issue48198.go [new file with mode: 0644]
test/typeparam/issue48225.go [new file with mode: 0644]
test/typeparam/issue48253.go [new file with mode: 0644]
test/typeparam/issue48276a.go [new file with mode: 0644]
test/typeparam/issue48276a.out [new file with mode: 0644]
test/typeparam/issue48276b.go [new file with mode: 0644]
test/typeparam/issue48280.dir/a.go [new file with mode: 0644]
test/typeparam/issue48280.dir/main.go [new file with mode: 0644]
test/typeparam/issue48280.go [new file with mode: 0644]
test/typeparam/issue48306.dir/a.go [new file with mode: 0644]
test/typeparam/issue48306.dir/main.go [new file with mode: 0644]
test/typeparam/issue48306.go [new file with mode: 0644]
test/typeparam/issue48317.go [new file with mode: 0644]
test/typeparam/issue48318.go [new file with mode: 0644]
test/typeparam/issue48337a.dir/a.go [new file with mode: 0644]
test/typeparam/issue48337a.dir/main.go [new file with mode: 0644]
test/typeparam/issue48337a.go [new file with mode: 0644]
test/typeparam/issue48337a.out [new file with mode: 0644]
test/typeparam/issue48337b.dir/a.go [new file with mode: 0644]
test/typeparam/issue48337b.dir/main.go [new file with mode: 0644]
test/typeparam/issue48337b.go [new file with mode: 0644]
test/typeparam/issue48344.go [new file with mode: 0644]
test/typeparam/issue48424.go [new file with mode: 0644]
test/typeparam/issue48453.go [new file with mode: 0644]
test/typeparam/issue48454.dir/a.go [new file with mode: 0644]
test/typeparam/issue48454.dir/b.go [new file with mode: 0644]
test/typeparam/issue48454.dir/main.go [new file with mode: 0644]
test/typeparam/issue48454.go [new file with mode: 0644]
test/typeparam/issue48462.dir/a.go [new file with mode: 0644]
test/typeparam/issue48462.dir/main.go [new file with mode: 0644]
test/typeparam/issue48462.go [new file with mode: 0644]
test/typeparam/issue48537.go [new file with mode: 0644]
test/typeparam/issue48538.go [new file with mode: 0644]
test/typeparam/issue48598.go [new file with mode: 0644]
test/typeparam/issue48602.go [new file with mode: 0644]
test/typeparam/issue48604.go [new file with mode: 0644]
test/typeparam/issue48609.go [new file with mode: 0644]
test/typeparam/issue48617.go [new file with mode: 0644]
test/typeparam/issue48645a.go [new file with mode: 0644]
test/typeparam/issue48645a.out [new file with mode: 0644]
test/typeparam/issue48645b.go [new file with mode: 0644]
test/typeparam/issue48716.dir/a.go [new file with mode: 0644]
test/typeparam/issue48716.dir/main.go [new file with mode: 0644]
test/typeparam/issue48716.go [new file with mode: 0644]
test/typeparam/issue48838.go [new file with mode: 0644]
test/typeparam/issue48962.go [new file with mode: 0644]
test/typeparam/issue49027.dir/a.go [new file with mode: 0644]
test/typeparam/issue49027.dir/main.go [new file with mode: 0644]
test/typeparam/issue49027.go [new file with mode: 0644]
test/typeparam/issue49049.go [new file with mode: 0644]
test/typeparam/issue49241.dir/a.go [new file with mode: 0644]
test/typeparam/issue49241.dir/b.go [new file with mode: 0644]
test/typeparam/issue49241.dir/c.go [new file with mode: 0644]
test/typeparam/issue49241.dir/main.go [new file with mode: 0644]
test/typeparam/issue49241.go [new file with mode: 0644]
test/typeparam/issue49246.dir/a.go [new file with mode: 0644]
test/typeparam/issue49246.dir/b.go [new file with mode: 0644]
test/typeparam/issue49246.go [new file with mode: 0644]
test/typeparam/issue49295.go [new file with mode: 0644]
test/typeparam/issue49309.go [new file with mode: 0644]
test/typeparam/recoverimp.dir/a.go [new file with mode: 0644]
test/typeparam/recoverimp.dir/main.go [new file with mode: 0644]
test/typeparam/recoverimp.go [new file with mode: 0644]
test/typeparam/recoverimp.out [new file with mode: 0644]
test/typeparam/settable.go
test/typeparam/sliceimp.dir/a.go
test/typeparam/slices.go
test/typeparam/smoketest.go
test/typeparam/subdict.go
test/typeparam/tparam1.go
test/typeparam/typelist.go
test/typeparam/typeswitch2.go
test/unsafebuiltins.go
test/writebarrier.go
test/zerodivide.go

index 23fec84fb65e3b19b6bc650b6e862744c1cd6099..2ec957a52b4e1f37aa5beb3f4f57a14edeac45a5 100644 (file)
@@ -11,4 +11,4 @@ For asking questions, see:
 
 * [Stack Overflow](https://stackoverflow.com/questions/tagged/go) with questions tagged "go"
 
-* **IRC** channel #go-nuts on Freenode
+* **IRC** channel #go-nuts on Libera
diff --git a/AUTHORS b/AUTHORS
index 95d3158d204ff0cc73238867aeba27e0d70b0e34..8d7e19673210c37c80bf3b346db326af394aee09 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -817,6 +817,7 @@ Lehner Florian <dev@der-flo.net>
 Leigh McCulloch <leighmcc@gmail.com>
 Leo Antunes <leo@costela.net>
 Leon Klingele <git@leonklingele.de>
+Leonard Wang <wangdeyu0907@gmail.com> <wangdeyu@golangcn.org>
 Leonel Quinteros <leonel.quinteros@gmail.com>
 Lev Shamardin <shamardin@gmail.com>
 Lewin Bormann <lewin.bormann@gmail.com>
@@ -1015,6 +1016,7 @@ Nathan Youngman <git@nathany.com>
 Nathaniel Cook <nvcook42@gmail.com>
 Naveen Kumar Sangi <naveenkumarsangi@protonmail.com>
 Neelesh Chandola <neelesh.c98@gmail.com>
+Neil Alexander <neilalexander@neilalexander.dev>
 Neil Lyons <nwjlyons@googlemail.com>
 Netflix, Inc.
 Neuman Vong <neuman.vong@gmail.com>
@@ -1479,6 +1481,7 @@ Zheng Dayu <davidzheng23@gmail.com>
 Zhongtao Chen <chenzhongtao@126.com>
 Zhou Peng <p@ctriple.cn>
 Ziad Hatahet <hatahet@gmail.com>
+Zizhao Zhang <btw515wolf2@gmail.com>
 Zorion Arrizabalaga <zorionk@gmail.com>
 Максим Федосеев <max.faceless.frei@gmail.com>
 Роман Хавроненко <hagen1778@gmail.com>
index 1984d44c53773624a686c0af48bc1055d4fb0e5a..a548cb0e2fee5430ce7ddf332e7e28e940a24824 100644 (file)
@@ -1109,7 +1109,6 @@ Ian Lance Taylor <iant@golang.org>
 Ian Leue <ian@appboy.com>
 Ian Mckay <iann0036@gmail.com>
 Ian Tay <iantay@google.com>
-Ian Woolf <btw515wolf2@gmail.com>
 Ian Zapolsky <ianzapolsky@gmail.com>
 Ibrahim AshShohail <ibra.sho@gmail.com>
 Icarus Sparry <golang@icarus.freeuk.com>
@@ -1570,7 +1569,7 @@ Leigh McCulloch <leighmcc@gmail.com>
 Leo Antunes <leo@costela.net>
 Leo Rudberg <ljr@google.com>
 Leon Klingele <git@leonklingele.de>
-Leonard Wang <wangdeyu0907@gmail.com>
+Leonard Wang <wangdeyu0907@gmail.com> <wangdeyu@golangcn.org>
 Leonardo Comelli <leonardo.comelli@gmail.com>
 Leonel Quinteros <leonel.quinteros@gmail.com>
 Lev Shamardin <shamardin@gmail.com>
@@ -1902,6 +1901,7 @@ Naveen Kumar Sangi <naveenkumarsangi@protonmail.com>
 Neeilan Selvalingam <neeilan96@gmail.com>
 Neelesh Chandola <neelesh.c98@gmail.com>
 Nehal J Wani <nehaljw.kkd1@gmail.com>
+Neil Alexander <neilalexander@neilalexander.dev>
 Neil Lyons <nwjlyons@googlemail.com>
 Neuman Vong <neuman.vong@gmail.com>
 Neven Sajko <nsajko@gmail.com>
@@ -2749,6 +2749,7 @@ Zhongwei Yao <zhongwei.yao@arm.com>
 Zhou Peng <p@ctriple.cn>
 Ziad Hatahet <hatahet@gmail.com>
 Ziheng Liu <lzhfromustc@gmail.com>
+Zizhao Zhang <btw515wolf2@gmail.com>
 Zorion Arrizabalaga <zorionk@gmail.com>
 Zvonimir Pavlinovic <zpavlinovic@google.com>
 Zyad A. Ali <zyad.ali.me@gmail.com>
index 837734b6e574bfd1f3c99d2a8a4845e58534dbb8..5aca9587fa47e81c13207d036f8b1864f9a65db4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ for source installation instructions.
 
 Go is the work of thousands of contributors. We appreciate your help!
 
-To contribute, please read the contribution guidelines at https://golang.org/doc/contribute.html.
+To contribute, please read the contribution guidelines at https://golang.org/doc/contribute.
 
 Note that the Go project uses the issue tracker for bug reports and
 proposals only. See https://golang.org/wiki/Questions for a list of
index 14fe7785fa54d3bc2a484c992113edf1d13c2d1f..b9972c121cfa4addbfdbfe82644b567745da846e 100644 (file)
@@ -492,6 +492,7 @@ pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uin
 pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
 pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
 pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
+pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalExample) *M
 pkg testing, func RegisterCover(Cover)
 pkg text/scanner, const GoTokens = 1012
 pkg text/template/parse, type DotNode bool
index 81d095704a4c9c58625d72376e4c77724dd8c957..bb00b3b02cc8ad8fffcd32f4df04df67c30cbce8 100644 (file)
@@ -2603,7 +2603,34 @@ pkg runtime/debug, type GCStats struct, Pause []time.Duration
 pkg runtime/debug, type GCStats struct, PauseQuantiles []time.Duration
 pkg runtime/debug, type GCStats struct, PauseTotal time.Duration
 pkg sort, func Reverse(Interface) Interface
-pkg strconv, const IntSize = 64
+pkg strconv (darwin-amd64), const IntSize = 64
+pkg strconv (darwin-amd64-cgo), const IntSize = 64
+pkg strconv (freebsd-386), const IntSize = 32
+pkg strconv (freebsd-386-cgo), const IntSize = 32
+pkg strconv (freebsd-amd64), const IntSize = 64
+pkg strconv (freebsd-amd64-cgo), const IntSize = 64
+pkg strconv (freebsd-arm), const IntSize = 32
+pkg strconv (freebsd-arm-cgo), const IntSize = 32
+pkg strconv (linux-386), const IntSize = 32
+pkg strconv (linux-386-cgo), const IntSize = 32
+pkg strconv (linux-amd64), const IntSize = 64
+pkg strconv (linux-amd64-cgo), const IntSize = 64
+pkg strconv (linux-arm), const IntSize = 32
+pkg strconv (linux-arm-cgo), const IntSize = 32
+pkg strconv (netbsd-386), const IntSize = 32
+pkg strconv (netbsd-386-cgo), const IntSize = 32
+pkg strconv (netbsd-amd64), const IntSize = 64
+pkg strconv (netbsd-amd64-cgo), const IntSize = 64
+pkg strconv (netbsd-arm), const IntSize = 32
+pkg strconv (netbsd-arm-cgo), const IntSize = 32
+pkg strconv (netbsd-arm64), const IntSize = 64
+pkg strconv (netbsd-arm64-cgo), const IntSize = 64
+pkg strconv (openbsd-386), const IntSize = 32
+pkg strconv (openbsd-386-cgo), const IntSize = 32
+pkg strconv (openbsd-amd64), const IntSize = 64
+pkg strconv (openbsd-amd64-cgo), const IntSize = 64
+pkg strconv (windows-386), const IntSize = 32
+pkg strconv (windows-amd64), const IntSize = 64
 pkg strings, func TrimPrefix(string, string) string
 pkg strings, func TrimSuffix(string, string) string
 pkg strings, method (*Reader) WriteTo(io.Writer) (int64, error)
@@ -49366,7 +49393,7 @@ pkg syscall (windows-386), const IP_MULTICAST_TTL = 10
 pkg syscall (windows-386), const IP_TOS = 3
 pkg syscall (windows-386), const IP_TTL = 4
 pkg syscall (windows-386), const ImplementsGetwd = true
-pkg syscall (windows-386), const InvalidHandle = 18446744073709551615
+pkg syscall (windows-386), const InvalidHandle = 4294967295
 pkg syscall (windows-386), const KEY_ALL_ACCESS = 983103
 pkg syscall (windows-386), const KEY_CREATE_LINK = 32
 pkg syscall (windows-386), const KEY_CREATE_SUB_KEY = 4
index 48505381f1e41f961684e0df5f68b74b7766d902..ca2cd162f8bc8e9359bf8e886dfb42c6dc9c052d 100644 (file)
@@ -63,12 +63,93 @@ pkg image/draw, type RGBA64Image interface, RGBA64At(int, int) color.RGBA64
 pkg image/draw, type RGBA64Image interface, Set(int, int, color.Color)
 pkg image/draw, type RGBA64Image interface, SetRGBA64(int, int, color.RGBA64)
 pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry
+pkg math (darwin-amd64), const MaxInt = 9223372036854775807
+pkg math (darwin-amd64), const MaxUint = 18446744073709551615
+pkg math (darwin-amd64), const MinInt = -9223372036854775808
+pkg math (darwin-amd64-cgo), const MaxInt = 9223372036854775807
+pkg math (darwin-amd64-cgo), const MaxUint = 18446744073709551615
+pkg math (darwin-amd64-cgo), const MinInt = -9223372036854775808
+pkg math (freebsd-386), const MaxInt = 2147483647
+pkg math (freebsd-386), const MaxUint = 4294967295
+pkg math (freebsd-386), const MinInt = -2147483648
+pkg math (freebsd-386-cgo), const MaxInt = 2147483647
+pkg math (freebsd-386-cgo), const MaxUint = 4294967295
+pkg math (freebsd-386-cgo), const MinInt = -2147483648
+pkg math (freebsd-amd64), const MaxInt = 9223372036854775807
+pkg math (freebsd-amd64), const MaxUint = 18446744073709551615
+pkg math (freebsd-amd64), const MinInt = -9223372036854775808
+pkg math (freebsd-amd64-cgo), const MaxInt = 9223372036854775807
+pkg math (freebsd-amd64-cgo), const MaxUint = 18446744073709551615
+pkg math (freebsd-amd64-cgo), const MinInt = -9223372036854775808
+pkg math (freebsd-arm), const MaxInt = 2147483647
+pkg math (freebsd-arm), const MaxUint = 4294967295
+pkg math (freebsd-arm), const MinInt = -2147483648
+pkg math (freebsd-arm-cgo), const MaxInt = 2147483647
+pkg math (freebsd-arm-cgo), const MaxUint = 4294967295
+pkg math (freebsd-arm-cgo), const MinInt = -2147483648
+pkg math (linux-386), const MaxInt = 2147483647
+pkg math (linux-386), const MaxUint = 4294967295
+pkg math (linux-386), const MinInt = -2147483648
+pkg math (linux-386-cgo), const MaxInt = 2147483647
+pkg math (linux-386-cgo), const MaxUint = 4294967295
+pkg math (linux-386-cgo), const MinInt = -2147483648
+pkg math (linux-amd64), const MaxInt = 9223372036854775807
+pkg math (linux-amd64), const MaxUint = 18446744073709551615
+pkg math (linux-amd64), const MinInt = -9223372036854775808
+pkg math (linux-amd64-cgo), const MaxInt = 9223372036854775807
+pkg math (linux-amd64-cgo), const MaxUint = 18446744073709551615
+pkg math (linux-amd64-cgo), const MinInt = -9223372036854775808
+pkg math (linux-arm), const MaxInt = 2147483647
+pkg math (linux-arm), const MaxUint = 4294967295
+pkg math (linux-arm), const MinInt = -2147483648
+pkg math (linux-arm-cgo), const MaxInt = 2147483647
+pkg math (linux-arm-cgo), const MaxUint = 4294967295
+pkg math (linux-arm-cgo), const MinInt = -2147483648
+pkg math (netbsd-386), const MaxInt = 2147483647
+pkg math (netbsd-386), const MaxUint = 4294967295
+pkg math (netbsd-386), const MinInt = -2147483648
+pkg math (netbsd-386-cgo), const MaxInt = 2147483647
+pkg math (netbsd-386-cgo), const MaxUint = 4294967295
+pkg math (netbsd-386-cgo), const MinInt = -2147483648
+pkg math (netbsd-amd64), const MaxInt = 9223372036854775807
+pkg math (netbsd-amd64), const MaxUint = 18446744073709551615
+pkg math (netbsd-amd64), const MinInt = -9223372036854775808
+pkg math (netbsd-amd64-cgo), const MaxInt = 9223372036854775807
+pkg math (netbsd-amd64-cgo), const MaxUint = 18446744073709551615
+pkg math (netbsd-amd64-cgo), const MinInt = -9223372036854775808
+pkg math (netbsd-arm), const MaxInt = 2147483647
+pkg math (netbsd-arm), const MaxUint = 4294967295
+pkg math (netbsd-arm), const MinInt = -2147483648
+pkg math (netbsd-arm-cgo), const MaxInt = 2147483647
+pkg math (netbsd-arm-cgo), const MaxUint = 4294967295
+pkg math (netbsd-arm-cgo), const MinInt = -2147483648
+pkg math (netbsd-arm64), const MaxInt = 9223372036854775807
+pkg math (netbsd-arm64), const MaxUint = 18446744073709551615
+pkg math (netbsd-arm64), const MinInt = -9223372036854775808
+pkg math (netbsd-arm64-cgo), const MaxInt = 9223372036854775807
+pkg math (netbsd-arm64-cgo), const MaxUint = 18446744073709551615
+pkg math (netbsd-arm64-cgo), const MinInt = -9223372036854775808
+pkg math (openbsd-386), const MaxInt = 2147483647
+pkg math (openbsd-386), const MaxUint = 4294967295
+pkg math (openbsd-386), const MinInt = -2147483648
+pkg math (openbsd-386-cgo), const MaxInt = 2147483647
+pkg math (openbsd-386-cgo), const MaxUint = 4294967295
+pkg math (openbsd-386-cgo), const MinInt = -2147483648
+pkg math (openbsd-amd64), const MaxInt = 9223372036854775807
+pkg math (openbsd-amd64), const MaxUint = 18446744073709551615
+pkg math (openbsd-amd64), const MinInt = -9223372036854775808
+pkg math (openbsd-amd64-cgo), const MaxInt = 9223372036854775807
+pkg math (openbsd-amd64-cgo), const MaxUint = 18446744073709551615
+pkg math (openbsd-amd64-cgo), const MinInt = -9223372036854775808
+pkg math (windows-386), const MaxInt = 2147483647
+pkg math (windows-386), const MaxUint = 4294967295
+pkg math (windows-386), const MinInt = -2147483648
+pkg math (windows-amd64), const MaxInt = 9223372036854775807
+pkg math (windows-amd64), const MaxUint = 18446744073709551615
+pkg math (windows-amd64), const MinInt = -9223372036854775808
 pkg math, const MaxFloat64 = 1.79769e+308  // 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
-pkg math, const MaxInt = 9223372036854775807
 pkg math, const MaxInt ideal-int
-pkg math, const MaxUint = 18446744073709551615
 pkg math, const MaxUint ideal-int
-pkg math, const MinInt = -9223372036854775808
 pkg math, const MinInt ideal-int
 pkg math, const SmallestNonzeroFloat32 = 1.4013e-45  // 1/713623846352979940529142984724747568191373312
 pkg math, const SmallestNonzeroFloat64 = 4.94066e-324  // 1/202402253307310618352495346718917307049556649764142118356901358027430339567995346891960383701437124495187077864316811911389808737385793476867013399940738509921517424276566361364466907742093216341239767678472745068562007483424692698618103355649159556340810056512358769552333414615230502532186327508646006263307707741093494784
index c7a4968aaf701db13a4ed7809a3dde22c8e741fd..bde9db1c609ece706bf397f2243f6d1ce90bd61f 100644 (file)
@@ -50,7 +50,34 @@ pkg image/png, type EncoderBufferPool interface, Put(*EncoderBuffer)
 pkg math/big, method (*Int) IsInt64() bool
 pkg math/big, method (*Int) IsUint64() bool
 pkg math/big, type Word uint
-pkg math/bits, const UintSize = 64
+pkg math/bits (darwin-amd64), const UintSize = 64
+pkg math/bits (darwin-amd64-cgo), const UintSize = 64
+pkg math/bits (freebsd-386), const UintSize = 32
+pkg math/bits (freebsd-386-cgo), const UintSize = 32
+pkg math/bits (freebsd-amd64), const UintSize = 64
+pkg math/bits (freebsd-amd64-cgo), const UintSize = 64
+pkg math/bits (freebsd-arm), const UintSize = 32
+pkg math/bits (freebsd-arm-cgo), const UintSize = 32
+pkg math/bits (linux-386), const UintSize = 32
+pkg math/bits (linux-386-cgo), const UintSize = 32
+pkg math/bits (linux-amd64), const UintSize = 64
+pkg math/bits (linux-amd64-cgo), const UintSize = 64
+pkg math/bits (linux-arm), const UintSize = 32
+pkg math/bits (linux-arm-cgo), const UintSize = 32
+pkg math/bits (netbsd-386), const UintSize = 32
+pkg math/bits (netbsd-386-cgo), const UintSize = 32
+pkg math/bits (netbsd-amd64), const UintSize = 64
+pkg math/bits (netbsd-amd64-cgo), const UintSize = 64
+pkg math/bits (netbsd-arm), const UintSize = 32
+pkg math/bits (netbsd-arm-cgo), const UintSize = 32
+pkg math/bits (netbsd-arm64), const UintSize = 64
+pkg math/bits (netbsd-arm64-cgo), const UintSize = 64
+pkg math/bits (openbsd-386), const UintSize = 32
+pkg math/bits (openbsd-386-cgo), const UintSize = 32
+pkg math/bits (openbsd-amd64), const UintSize = 64
+pkg math/bits (openbsd-amd64-cgo), const UintSize = 64
+pkg math/bits (windows-386), const UintSize = 32
+pkg math/bits (windows-amd64), const UintSize = 64
 pkg math/bits, const UintSize ideal-int
 pkg math/bits, func LeadingZeros(uint) int
 pkg math/bits, func LeadingZeros16(uint16) int
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cc4120b7aba0a0ae0896bf7e85461d8f60eda21f 100644 (file)
@@ -0,0 +1,47 @@
+pkg debug/buildinfo, func Read(io.ReaderAt) (*debug.BuildInfo, error)
+pkg debug/buildinfo, func ReadFile(string) (*debug.BuildInfo, error)
+pkg debug/buildinfo, type BuildInfo = debug.BuildInfo
+pkg runtime/debug, method (*BuildInfo) MarshalText() ([]byte, error)
+pkg runtime/debug, method (*BuildInfo) UnmarshalText() ([]byte, error)
+pkg runtime/debug, type BuildInfo struct, GoVersion string
+pkg runtime/debug, type BuildInfo struct, Settings []BuildSetting
+pkg runtime/debug, type BuildSetting struct
+pkg runtime/debug, type BuildSetting struct, Key string
+pkg runtime/debug, type BuildSetting struct, Value string
+pkg testing, func Fuzz(func(*F)) FuzzResult
+pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalFuzzTarget, []InternalExample) *M
+pkg testing, func RunFuzzTargets(func(string, string) (bool, error), []InternalFuzzTarget) bool
+pkg testing, func RunFuzzing(func(string, string) (bool, error), []InternalFuzzTarget) bool
+pkg testing, method (*B) Setenv(string, string)
+pkg testing, method (*F) Add(...interface{})
+pkg testing, method (*F) Cleanup(func())
+pkg testing, method (*F) Error(...interface{})
+pkg testing, method (*F) Errorf(string, ...interface{})
+pkg testing, method (*F) Fail()
+pkg testing, method (*F) FailNow()
+pkg testing, method (*F) Failed() bool
+pkg testing, method (*F) Fatal(...interface{})
+pkg testing, method (*F) Fatalf(string, ...interface{})
+pkg testing, method (*F) Fuzz(interface{})
+pkg testing, method (*F) Helper()
+pkg testing, method (*F) Log(...interface{})
+pkg testing, method (*F) Logf(string, ...interface{})
+pkg testing, method (*F) Name() string
+pkg testing, method (*F) Setenv(string, string)
+pkg testing, method (*F) Skip(...interface{})
+pkg testing, method (*F) SkipNow()
+pkg testing, method (*F) Skipf(string, ...interface{})
+pkg testing, method (*F) Skipped() bool
+pkg testing, method (*F) TempDir() string
+pkg testing, method (*T) Setenv(string, string)
+pkg testing, method (FuzzResult) String() string
+pkg testing, type F struct
+pkg testing, type FuzzResult struct
+pkg testing, type FuzzResult struct, Crasher entry
+pkg testing, type FuzzResult struct, Error error
+pkg testing, type FuzzResult struct, N int
+pkg testing, type FuzzResult struct, T time.Duration
+pkg testing, type InternalFuzzTarget struct
+pkg testing, type InternalFuzzTarget struct, Fn func(*F)
+pkg testing, type InternalFuzzTarget struct, Name string
+pkg net/http, method (*Cookie) Valid() error
index 51f85eb94822a4a900bfbb205f5cbcc709e5a2f8..f7787a4076ce600dbce55eef8b1dbdccdf2898c5 100644 (file)
@@ -125,8 +125,8 @@ it is a distinct program, so there are some differences.
 One is in constant evaluation.
 Constant expressions in the assembler are parsed using Go's operator
 precedence, not the C-like precedence of the original.
-Thus <code>3&amp;1<<2</code> is 4, not 0—it parses as <code>(3&amp;1)<<2</code>
-not <code>3&amp;(1<<2)</code>.
+Thus <code>3&amp;1&lt;&lt;2</code> is 4, not 0—it parses as <code>(3&amp;1)&lt;&lt;2</code>
+not <code>3&amp;(1&lt;&lt;2)</code>.
 Also, constants are always evaluated as 64-bit unsigned integers.
 Thus <code>-2</code> is not the integer value minus two,
 but the unsigned 64-bit integer with the same bit pattern.
@@ -914,8 +914,6 @@ This assembler is used by GOARCH values ppc64 and ppc64le.
 Reference: <a href="/pkg/cmd/internal/obj/ppc64">Go PPC64 Assembly Instructions Reference Manual</a>
 </p>
 
-</ul>
-
 <h3 id="s390x">IBM z/Architecture, a.k.a. s390x</h3>
 
 <p>
diff --git a/doc/go1.17.html b/doc/go1.17.html
deleted file mode 100644 (file)
index c1b5ab3..0000000
+++ /dev/null
@@ -1,1240 +0,0 @@
-<!--{
-       "Title": "Go 1.17 Release Notes",
-       "Path":  "/doc/go1.17"
-}-->
-
-<!--
-NOTE: In this document and others in this directory, the convention is to
-set fixed-width phrases with non-fixed-width spaces, as in
-<code>hello</code> <code>world</code>.
-Do not send CLs removing the interior tags from such phrases.
--->
-
-<style>
-  main ul li { margin: 0.5em 0; }
-</style>
-
-<h2 id="introduction">Introduction to Go 1.17</h2>
-
-<p>
-  The latest Go release, version 1.17, arrives six months after <a href="/doc/go1.16">Go 1.16</a>.
-  Most of its changes are in the implementation of the toolchain, runtime, and libraries.
-  As always, the release maintains the Go 1 <a href="/doc/go1compat">promise of compatibility</a>.
-  We expect almost all Go programs to continue to compile and run as before.
-</p>
-
-<h2 id="language">Changes to the language</h2>
-
-<p>
-  Go 1.17 includes three small enhancements to the language.
-</p>
-
-<ul>
-  <li><!-- CL 216424; issue 395 -->
-    <a href="/ref/spec#Conversions_from_slice_to_array_pointer">Conversions
-    from slice to array pointer</a>: An expression <code>s</code> of
-    type <code>[]T</code> may now be converted to array pointer type
-    <code>*[N]T</code>. If <code>a</code> is the result of such a
-    conversion, then corresponding indices that are in range refer to
-    the same underlying elements: <code>&amp;a[i] == &amp;s[i]</code>
-    for <code>0 &lt;= i &lt; N</code>. The conversion panics if
-    <code>len(s)</code> is less than <code>N</code>.
-  </li>
-
-  <li><!-- CL 312212; issue 40481 -->
-    <a href="/pkg/unsafe#Add"><code>unsafe.Add</code></a>:
-    <code>unsafe.Add(ptr, len)</code> adds <code>len</code>
-    to <code>ptr</code> and returns the updated pointer
-    <code>unsafe.Pointer(uintptr(ptr) + uintptr(len))</code>.
-  </li>
-
-  <li><!-- CL 312212; issue 19367 -->
-    <a href="/pkg/unsafe#Slice"><code>unsafe.Slice</code></a>:
-    For expression <code>ptr</code> of type <code>*T</code>,
-    <code>unsafe.Slice(ptr, len)</code> returns a slice of
-    type <code>[]T</code> whose underlying array starts
-    at <code>ptr</code> and whose length and capacity
-    are <code>len</code>.
-  </li>
-</ul>
-
-<p>
-  The package unsafe enhancements were added to simplify writing code that conforms
-  to <code>unsafe.Pointer</code>'s <a href="/pkg/unsafe/#Pointer">safety
-  rules</a>, but the rules remain unchanged. In particular, existing
-  programs that correctly use <code>unsafe.Pointer</code> remain
-  valid, and new programs must still follow the rules when
-  using <code>unsafe.Add</code> or <code>unsafe.Slice</code>.
-</p>
-
-
-<p>
-  Note that the new conversion from slice to array pointer is the
-  first case in which a type conversion can panic at run time.
-  Analysis tools that assume type conversions can never panic
-  should be updated to consider this possibility.
-</p>
-
-<h2 id="ports">Ports</h2>
-
-<h3 id="darwin">Darwin</h3>
-
-<p><!-- golang.org/issue/23011 -->
-  As <a href="go1.16#darwin">announced</a> in the Go 1.16 release
-  notes, Go 1.17 requires macOS 10.13 High Sierra or later; support
-  for previous versions has been discontinued.
-</p>
-
-<h3 id="windows">Windows</h3>
-
-<p><!-- golang.org/issue/36439 -->
-  Go 1.17 adds support of 64-bit ARM architecture on Windows (the
-  <code>windows/arm64</code> port). This port supports cgo.
-</p>
-
-<h3 id="openbsd">OpenBSD</h3>
-
-<p><!-- golang.org/issue/43005 -->
-  The 64-bit MIPS architecture on OpenBSD (the <code>openbsd/mips64</code>
-  port) now supports cgo.
-</p>
-
-<p><!-- golang.org/issue/36435 -->
-  In Go 1.16, on the 64-bit x86 and 64-bit ARM architectures on
-  OpenBSD (the <code>openbsd/amd64</code> and <code>openbsd/arm64</code>
-  ports) system calls are made through <code>libc</code>, instead
-  of directly using machine instructions. In Go 1.17, this is also
-  done on the 32-bit x86 and 32-bit ARM architectures on OpenBSD
-  (the <code>openbsd/386</code> and <code>openbsd/arm</code> ports).
-  This ensures compatibility with OpenBSD 6.9 onwards, which require
-  system calls to be made through <code>libc</code> for non-static
-  Go binaries.
-</p>
-
-<h3 id="arm64">ARM64</h3>
-
-<p><!-- CL 288814 -->
-  Go programs now maintain stack frame pointers on the 64-bit ARM
-  architecture on all operating systems. Previously it maintained
-  stack frame pointers only on Linux, macOS, and iOS.
-</p>
-
-<h3 id="loong64">loong64 GOARCH value reserved</h3>
-
-<p><!-- CL 333909 -->
-  The main Go compiler does not yet support the LoongArch
-  architecture, but we've reserved the <code>GOARCH</code> value
-  "<code>loong64</code>".
-  This means that Go files named <code>*_loong64.go</code> will now
-  be <a href="/pkg/go/build/#hdr-Build_Constraints">ignored by Go
-  tools</a> except when that GOARCH value is being used.
-</p>
-
-<h2 id="tools">Tools</h2>
-
-<h3 id="go-command">Go command</h3>
-
-<a id="lazy-loading"><!-- for existing links only --></a>
-<h4 id="graph-pruning">Pruned module graphs in <code>go 1.17</code> modules</h4>
-
-<p><!-- golang.org/issue/36460 -->
-  If a module specifies <code>go</code> <code>1.17</code> or higher, the module
-  graph includes only the <em>immediate</em> dependencies of
-  other <code>go</code> <code>1.17</code> modules, not their full transitive
-  dependencies. (See <a href="/ref/mod#graph-pruning">Module graph pruning</a>
-  for more detail.)
-</p>
-
-<p>
-  For the <code>go</code> command to correctly resolve transitive imports using
-  the pruned module graph, the <code>go.mod</code> file for each module needs to
-  include more detail about the transitive dependencies relevant to that module.
-  If a module specifies <code>go</code> <code>1.17</code> or higher in its
-  <code>go.mod</code> file, its <code>go.mod</code> file now contains an
-  explicit <a href="/ref/mod#go-mod-file-require"><code>require</code>
-  directive</a> for every module that provides a transitively-imported package.
-  (In previous versions, the <code>go.mod</code> file typically only included
-  explicit requirements for <em>directly</em>-imported packages.)
-<p>
-
-<p>
-  Since the expanded <code>go.mod</code> file needed for module graph pruning
-  includes all of the dependencies needed to load the imports of any package in
-  the main module, if the main module specifies
-  <code>go</code> <code>1.17</code> or higher the <code>go</code> tool no longer
-  reads (or even downloads) <code>go.mod</code> files for dependencies if they
-  are not needed in order to complete the requested command.
-  (See <a href="/ref/mod#lazy-loading">Lazy loading</a>.)
-</p>
-
-<p><!-- golang.org/issue/45965 -->
-  Because the number of explicit requirements may be substantially larger in an
-  expanded Go 1.17 <code>go.mod</code> file, the newly-added requirements
-  on <em>indirect</em> dependencies in a <code>go</code> <code>1.17</code>
-  module are maintained in a separate <code>require</code> block from the block
-  containing direct dependencies.
-</p>
-
-<p><!-- golang.org/issue/45094 -->
-  To facilitate the upgrade to Go 1.17 pruned module graphs, the
-  <a href="/ref/mod#go-mod-tidy"><code>go</code> <code>mod</code> <code>tidy</code></a>
-  subcommand now supports a <code>-go</code> flag to set or change
-  the <code>go</code> version in the <code>go.mod</code> file. To convert
-  the <code>go.mod</code> file for an existing module to Go 1.17 without
-  changing the selected versions of its dependencies, run:
-</p>
-
-<pre>
-  go mod tidy -go=1.17
-</pre>
-
-<p><!-- golang.org/issue/46141 -->
-  By default, <code>go</code> <code>mod</code> <code>tidy</code> verifies that
-  the selected versions of dependencies relevant to the main module are the same
-  versions that would be used by the prior Go release (Go 1.16 for a module that
-  specifies <code>go</code> <code>1.17</code>), and preserves
-  the <code>go.sum</code> entries needed by that release even for dependencies
-  that are not normally needed by other commands.
-</p>
-
-<p>
-  The <code>-compat</code> flag allows that version to be overridden to support
-  older (or only newer) versions, up to the version specified by
-  the <code>go</code> directive in the <code>go.mod</code> file. To tidy
-  a <code>go</code> <code>1.17</code> module for Go 1.17 only, without saving
-  checksums for (or checking for consistency with) Go 1.16:
-</p>
-
-<pre>
-  go mod tidy -compat=1.17
-</pre>
-
-<p>
-  Note that even if the main module is tidied with <code>-compat=1.17</code>,
-  users who <code>require</code> the module from a
-  <code>go</code> <code>1.16</code> or earlier module will still be able to
-  use it, provided that the packages use only compatible language and library
-  features.
-</p>
-
-<p><!-- golang.org/issue/46366 -->
-  The <a href="/ref/mod#go-mod-graph"><code>go</code> <code>mod</code> <code>graph</code></a>
-  subcommand also supports the <code>-go</code> flag, which causes it to report
-  the graph as seen by the indicated Go version, showing dependencies that may
-  otherwise be pruned out.
-</p>
-
-<h4 id="module-deprecation-comments">Module deprecation comments</h4>
-
-<p><!-- golang.org/issue/40357 -->
-  Module authors may deprecate a module by adding a
-  <a href="/ref/mod#go-mod-file-module-deprecation"><code>// Deprecated:</code>
-  comment</a> to <code>go.mod</code>, then tagging a new version.
-  <code>go</code> <code>get</code> now prints a warning if a module needed to
-  build packages named on the command line is deprecated. <code>go</code>
-  <code>list</code> <code>-m</code> <code>-u</code> prints deprecations for all
-  dependencies (use <code>-f</code> or <code>-json</code> to show the full
-  message). The <code>go</code> command considers different major versions to
-  be distinct modules, so this mechanism may be used, for example, to provide
-  users with migration instructions for a new major version.
-</p>
-
-<h4 id="go-get"><code>go</code> <code>get</code></h4>
-
-<p><!-- golang.org/issue/37519 -->
-  The <code>go</code> <code>get</code> <code>-insecure</code> flag is
-  deprecated and has been removed. To permit the use of insecure schemes
-  when fetching dependencies, please use the <code>GOINSECURE</code>
-  environment variable. The <code>-insecure</code> flag also bypassed module
-  sum validation, use <code>GOPRIVATE</code> or <code>GONOSUMDB</code> if
-  you need that functionality. See <code>go</code> <code>help</code>
-  <code>environment</code> for details.
-</p>
-
-<p><!-- golang.org/issue/43684 -->
-  <code>go</code> <code>get</code> prints a deprecation warning when installing
-  commands outside the main module (without the <code>-d</code> flag).
-  <code>go</code> <code>install</code> <code>cmd@version</code> should be used
-  instead to install a command at a specific version, using a suffix like
-  <code>@latest</code> or <code>@v1.2.3</code>. In Go 1.18, the <code>-d</code>
-  flag will always be enabled, and <code>go</code> <code>get</code> will only
-  be used to change dependencies in <code>go.mod</code>.
-</p>
-
-<h4 id="missing-go-directive"><code>go.mod</code> files missing <code>go</code> directives</h4>
-
-<p><!-- golang.org/issue/44976 -->
-  If the main module's <code>go.mod</code> file does not contain
-  a <a href="/doc/modules/gomod-ref#go"><code>go</code> directive</a> and
-  the <code>go</code> command cannot update the <code>go.mod</code> file, the
-  <code>go</code> command now assumes <code>go 1.11</code> instead of the
-  current release. (<code>go</code> <code>mod</code> <code>init</code> has added
-  <code>go</code> directives automatically <a href="/doc/go1.12#modules">since
-  Go 1.12</a>.)
-</p>
-
-<p><!-- golang.org/issue/44976 -->
-  If a module dependency lacks an explicit <code>go.mod</code> file, or
-  its <code>go.mod</code> file does not contain
-  a <a href="/doc/modules/gomod-ref#go"><code>go</code> directive</a>,
-  the <code>go</code> command now assumes <code>go 1.16</code> for that
-  dependency instead of the current release. (Dependencies developed in GOPATH
-  mode may lack a <code>go.mod</code> file, and
-  the <code>vendor/modules.txt</code> has to date never recorded
-  the <code>go</code> versions indicated by dependencies' <code>go.mod</code>
-  files.)
-</p>
-
-<h4 id="vendor"><code>vendor</code> contents</h4>
-
-<p><!-- golang.org/issue/36876 -->
-  If the main module specifies <code>go</code> <code>1.17</code> or higher,
-  <a href="/ref/mod#go-mod-vendor"><code>go</code> <code>mod</code> <code>vendor</code></a>
-  now annotates
-  <code>vendor/modules.txt</code> with the <code>go</code> version indicated by
-  each vendored module in its own <code>go.mod</code> file. The annotated
-  version is used when building the module's packages from vendored source code.
-</p>
-
-<p><!-- golang.org/issue/42970 -->
-  If the main module specifies <code>go</code> <code>1.17</code> or higher,
-  <code>go</code> <code>mod</code> <code>vendor</code> now omits <code>go.mod</code>
-  and <code>go.sum</code> files for vendored dependencies, which can otherwise
-  interfere with the ability of the <code>go</code> command to identify the correct
-  module root when invoked within the <code>vendor</code> tree.
-</p>
-
-<h4 id="password-prompts">Password prompts</h4>
-
-<p><!-- golang.org/issue/44904 -->
-  The <code>go</code> command by default now suppresses SSH password prompts and
-  Git Credential Manager prompts when fetching Git repositories using SSH, as it
-  already did previously for other Git password prompts. Users authenticating to
-  private Git repos with password-protected SSH may configure
-  an <code>ssh-agent</code> to enable the <code>go</code> command to use
-  password-protected SSH keys.
-</p>
-
-<h4 id="go-mod-download"><code>go</code> <code>mod</code> <code>download</code></h4>
-
-<p><!-- golang.org/issue/45332 -->
-  When <code>go</code> <code>mod</code> <code>download</code> is invoked without
-  arguments, it will no longer save sums for downloaded module content to
-  <code>go.sum</code>. It may still make changes to <code>go.mod</code> and
-  <code>go.sum</code> needed to load the build list. This is the same as the
-  behavior in Go 1.15. To save sums for all modules, use <code>go</code>
-  <code>mod</code> <code>download</code> <code>all</code>.
-</p>
-
-<h4 id="build-lines"><code>//go:build</code> lines</h4>
-
-<p>
-  The <code>go</code> command now understands <code>//go:build</code> lines
-  and prefers them over <code>// +build</code> lines. The new syntax uses
-  boolean expressions, just like Go, and should be less error-prone.
-  As of this release, the new syntax is fully supported, and all Go files
-  should be updated to have both forms with the same meaning. To aid in
-  migration, <a href="#gofmt"><code>gofmt</code></a> now automatically
-  synchronizes the two forms. For more details on the syntax and migration plan,
-  see
-  <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
-</p>
-
-<h4 id="go run"><code>go</code> <code>run</code></h4>
-
-<p><!-- golang.org/issue/42088 -->
-  <code>go</code> <code>run</code> now accepts arguments with version suffixes
-  (for example, <code>go</code> <code>run</code>
-  <code>example.com/cmd@v1.0.0</code>).  This causes <code>go</code>
-  <code>run</code> to build and run packages in module-aware mode, ignoring the
-  <code>go.mod</code> file in the current directory or any parent directory, if
-  there is one. This is useful for running executables without installing them or
-  without changing dependencies of the current module.
-</p>
-
-<h3 id="gofmt">Gofmt</h3>
-
-<p>
-  <code>gofmt</code> (and <code>go</code> <code>fmt</code>) now synchronizes
-  <code>//go:build</code> lines with <code>// +build</code> lines. If a file
-  only has <code>// +build</code> lines, they will be moved to the appropriate
-  location in the file, and matching <code>//go:build</code> lines will be
-  added. Otherwise, <code>// +build</code> lines will be overwritten based on
-  any existing <code>//go:build</code> lines. For more information, see
-  <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
-</p>
-
-<h3 id="vet">Vet</h3>
-
-<h4 id="vet-buildtags">New warning for mismatched <code>//go:build</code> and <code>// +build</code> lines</h4>
-
-<p><!-- CL 240609 -->
-  The <code>vet</code> tool now verifies that <code>//go:build</code> and
-  <code>// +build</code> lines are in the correct part of the file and
-  synchronized with each other. If they aren't,
-  <a href="#gofmt"><code>gofmt</code></a> can be used to fix them. For more
-  information, see
-  <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
-</p>
-
-<h4 id="vet-sigchanyzer">New warning for calling <code>signal.Notify</code> on unbuffered channels</h4>
-
-<p><!-- CL 299532 -->
-  The vet tool now warns about calls to <a href="/pkg/os/signal/#Notify">signal.Notify</a>
-  with incoming signals being sent to an unbuffered channel. Using an unbuffered channel
-  risks missing signals sent on them as <code>signal.Notify</code> does not block when
-  sending to a channel. For example:
-</p>
-
-<pre>
-c := make(chan os.Signal)
-// signals are sent on c before the channel is read from.
-// This signal may be dropped as c is unbuffered.
-signal.Notify(c, os.Interrupt)
-</pre>
-
-<p>
-  Users of <code>signal.Notify</code> should use channels with sufficient buffer space to keep up with the
-  expected signal rate.
-</p>
-
-<h4 id="vet-error-stdmethods">New warnings for Is, As and Unwrap methods</h4>
-
-<p><!-- CL 321389 -->
-  The vet tool now warns about methods named <code>As</code>, <code>Is</code> or <code>Unwrap</code>
-  on types implementing the <code>error</code> interface that have a different signature than the
-  one expected by the <code>errors</code> package. The <code>errors.{As,Is,Unwrap}</code> functions
-  expect such methods to implement either <code>Is(error)</code> <code>bool</code>,
-  <code>As(interface{})</code> <code>bool</code>, or <code>Unwrap()</code> <code>error</code>
-  respectively. The functions <code>errors.{As,Is,Unwrap}</code> will ignore methods with the same
-  names but a different signature. For example:
-</p>
-
-<pre>
-type MyError struct { hint string }
-func (m MyError) Error() string { ... } // MyError implements error.
-func (MyError) Is(target interface{}) bool { ... } // target is interface{} instead of error.
-func Foo() bool {
-       x, y := MyError{"A"}, MyError{"B"}
-       return errors.Is(x, y) // returns false as x != y and MyError does not have an `Is(error) bool` function.
-}
-</pre>
-
-<h3 id="cover">Cover</h3>
-
-<p><!-- CL 249759 -->
-  The <code>cover</code> tool now uses an optimized parser
-  from <code>golang.org/x/tools/cover</code>, which may be noticeably faster
-  when parsing large coverage profiles.
-</p>
-
-<h2 id="compiler">Compiler</h2>
-
-<p><!-- golang.org/issue/40724 -->
-  Go 1.17 implements a new way of passing function arguments and results using
-  registers instead of the stack.
-  Benchmarks for a representative set of Go packages and programs show
-  performance improvements of about 5%, and a typical reduction in
-  binary size of about 2%.
-  This is currently enabled for Linux, macOS, and Windows on the
-  64-bit x86 architecture (the <code>linux/amd64</code>,
-  <code>darwin/amd64</code>, and <code>windows/amd64</code> ports).
-</p>
-
-<p>
-  This change does not affect the functionality of any safe Go code
-  and is designed to have no impact on most assembly code.
-  It may affect code that violates
-  the <a href="/pkg/unsafe#Pointer"><code>unsafe.Pointer</code></a>
-  rules when accessing function arguments, or that depends on
-  undocumented behavior involving comparing function code pointers.
-  To maintain compatibility with existing assembly functions, the
-  compiler generates adapter functions that convert between the new
-  register-based calling convention and the previous stack-based
-  calling convention.
-  These adapters are typically invisible to users, except that taking
-  the address of a Go function in assembly code or taking the address
-  of an assembly function in Go code
-  using <code>reflect.ValueOf(fn).Pointer()</code>
-  or <code>unsafe.Pointer</code> will now return the address of the
-  adapter.
-  Code that depends on the value of these code pointers may no longer
-  behave as expected.
-  Adapters also may cause a very small performance overhead in two
-  cases: calling an assembly function indirectly from Go via
-  a <code>func</code> value, and calling Go functions from assembly.
-</p>
-
-<p><!-- CL 304470 -->
-  The format of stack traces from the runtime (printed when an uncaught panic
-  occurs, or when <code>runtime.Stack</code> is called) is improved. Previously,
-  the function arguments were printed as hexadecimal words based on the memory
-  layout. Now each argument in the source code is printed separately, separated
-  by commas. Aggregate-typed (struct, array, string, slice, interface, and complex)
-  arguments are delimited by curly braces. A caveat is that the value of an
-  argument that only lives in a register and is not stored to memory may be
-  inaccurate. Function return values (which were usually inaccurate) are no longer
-  printed.
-</p>
-
-<p><!-- CL 283112, golang.org/issue/28727 -->
-  Functions containing closures can now be inlined.
-  One effect of this change is that a function with a closure may
-  produce a distinct closure code pointer for each place that the
-  function is inlined.
-  Go function values are not directly comparable, but this change
-  could reveal bugs in code that uses <code>reflect</code>
-  or <code>unsafe.Pointer</code> to bypass this language restriction
-  and compare functions by code pointer.
-</p>
-
-<h3 id="link">Linker</h3>
-
-<p><!-- CL 310349 -->
-  When the linker uses external linking mode, which is the default
-  when linking a program that uses cgo, and the linker is invoked
-  with a <code>-I</code> option, the option will now be passed to the
-  external linker as a <code>-Wl,--dynamic-linker</code> option.
-</p>
-
-<h2 id="library">Core library</h2>
-
-<h3 id="runtime/cgo"><a href="/pkg/runtime/cgo">Cgo</a></h3>
-
-<p>
-  The <a href="/pkg/runtime/cgo">runtime/cgo</a> package now provides a
-  new facility that allows to turn any Go values to a safe representation
-  that can be used to pass values between C and Go safely. See
-  <a href="/pkg/runtime/cgo#Handle">runtime/cgo.Handle</a> for more information.
-</p>
-
-<h3 id="semicolons">URL query parsing</h3>
-<!-- CL 325697, CL 326309 -->
-
-<p>
-  The <code>net/url</code> and <code>net/http</code> packages used to accept
-  <code>";"</code> (semicolon) as a setting separator in URL queries, in
-  addition to <code>"&"</code> (ampersand). Now, settings with non-percent-encoded
-  semicolons are rejected and <code>net/http</code> servers will log a warning to
-  <a href="/pkg/net/http#Server.ErrorLog"><code>Server.ErrorLog</code></a>
-  when encountering one in a request URL.
-</p>
-
-<p>
-  For example, before Go 1.17 the <a href="/pkg/net/url#URL.Query"><code>Query</code></a>
-  method of the URL <code>example?a=1;b=2&c=3</code> would have returned
-  <code>map[a:[1] b:[2] c:[3]]</code>, while now it returns <code>map[c:[3]]</code>.
-</p>
-
-<p>
-  When encountering such a query string,
-  <a href="/pkg/net/url#URL.Query"><code>URL.Query</code></a>
-  and
-  <a href="/pkg/net/http#Request.FormValue"><code>Request.FormValue</code></a>
-  ignore any settings that contain a semicolon,
-  <a href="/pkg/net/url#ParseQuery"><code>ParseQuery</code></a>
-  returns the remaining settings and an error, and
-  <a href="/pkg/net/http#Request.ParseForm"><code>Request.ParseForm</code></a>
-  and
-  <a href="/pkg/net/http#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>
-  return an error but still set <code>Request</code> fields based on the
-  remaining settings.
-</p>
-
-<p>
-  <code>net/http</code> users can restore the original behavior by using the new
-  <a href="/pkg/net/http#AllowQuerySemicolons"><code>AllowQuerySemicolons</code></a>
-  handler wrapper. This will also suppress the <code>ErrorLog</code> warning.
-  Note that accepting semicolons as query separators can lead to security issues
-  if different systems interpret cache keys differently.
-  See <a href="https://golang.org/issue/25192">issue 25192</a> for more information.
-</p>
-
-<h3 id="ALPN">TLS strict ALPN</h3>
-<!-- CL 289209, CL 325432 -->
-
-<p>
-  When <a href="/pkg/crypto/tls#Config.NextProtos"><code>Config.NextProtos</code></a>
-  is set, servers now enforce that there is an overlap between the configured
-  protocols and the ALPN protocols advertised by the client, if any. If there is
-  no mutually supported protocol, the connection is closed with the
-  <code>no_application_protocol</code> alert, as required by RFC 7301. This
-  helps mitigate <a href="https://alpaca-attack.com/">the ALPACA cross-protocol attack</a>.
-</p>
-
-<p>
-  As an exception, when the value <code>"h2"</code> is included in the server's
-  <code>Config.NextProtos</code>, HTTP/1.1 clients will be allowed to connect as
-  if they didn't support ALPN.
-  See <a href="https://golang.org/issue/46310">issue 46310</a> for more information.
-</p>
-
-<h3 id="minor_library_changes">Minor changes to the library</h3>
-
-<p>
-  As always, there are various minor changes and updates to the library,
-  made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
-  in mind.
-</p>
-
-<dl id="archive/zip"><dt><a href="/pkg/archive/zip/">archive/zip</a></dt>
-  <dd>
-    <p><!-- CL 312310 -->
-      The new methods <a href="/pkg/archive/zip#File.OpenRaw"><code>File.OpenRaw</code></a>, <a href="/pkg/archive/zip#Writer.CreateRaw"><code>Writer.CreateRaw</code></a>, <a href="/pkg/archive/zip#Writer.Copy"><code>Writer.Copy</code></a> provide support for cases where performance is a primary concern.
-    </p>
-  </dd>
-</dl><!-- archive/zip -->
-
-<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
-  <dd>
-    <p><!-- CL 280492 -->
-      The <a href="/pkg/bufio/#Writer.WriteRune"><code>Writer.WriteRune</code></a> method
-      now writes the replacement character U+FFFD for negative rune values,
-      as it does for other invalid runes.
-    </p>
-  </dd>
-</dl><!-- bufio -->
-
-<dl id="bytes"><dt><a href="/pkg/bytes/">bytes</a></dt>
-  <dd>
-    <p><!-- CL 280492 -->
-      The <a href="/pkg/bytes/#Buffer.WriteRune"><code>Buffer.WriteRune</code></a> method
-      now writes the replacement character U+FFFD for negative rune values,
-      as it does for other invalid runes.
-    </p>
-  </dd>
-</dl><!-- bytes -->
-
-<dl id="compress/lzw"><dt><a href="/pkg/compress/lzw/">compress/lzw</a></dt>
-  <dd>
-    <p><!-- CL 273667 -->
-      The <a href="/pkg/compress/lzw/#NewReader"><code>NewReader</code></a>
-      function is guaranteed to return a value of the new
-      type <a href="/pkg/compress/lzw/#Reader"><code>Reader</code></a>,
-      and similarly <a href="/pkg/compress/lzw/#NewWriter"><code>NewWriter</code></a>
-      is guaranteed to return a value of the new
-      type <a href="/pkg/compress/lzw/#Writer"><code>Writer</code></a>.
-      These new types both implement a <code>Reset</code> method
-      (<a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>,
-      <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>)
-      that allows reuse of the <code>Reader</code> or <code>Writer</code>.
-    </p>
-  </dd>
-</dl><!-- compress/lzw -->
-
-<dl id="crypto/ed25519"><dt><a href="/pkg/crypto/ed25519/">crypto/ed25519</a></dt>
-  <dd>
-    <p><!-- CL 276272 -->
-      The <code>crypto/ed25519</code> package has been rewritten, and all
-      operations are now approximately twice as fast on amd64 and arm64.
-      The observable behavior has not otherwise changed.
-    </p>
-  </dd>
-</dl><!-- crypto/ed25519 -->
-
-<dl id="crypto/elliptic"><dt><a href="/pkg/crypto/elliptic/">crypto/elliptic</a></dt>
-  <dd>
-    <p><!-- CL 233939 -->
-      <a href="/pkg/crypto/elliptic#CurveParams"><code>CurveParams</code></a>
-      methods now automatically invoke faster and safer dedicated
-      implementations for known curves (P-224, P-256, and P-521) when
-      available. Note that this is a best-effort approach and applications
-      should avoid using the generic, not constant-time <code>CurveParams</code>
-      methods and instead use dedicated
-      <a href="/pkg/crypto/elliptic#Curve"><code>Curve</code></a> implementations
-      such as <a href="/pkg/crypto/elliptic#P256"><code>P256</code></a>.
-    </p>
-
-    <p><!-- CL 315271, CL 315274 -->
-      The <a href="/pkg/crypto/elliptic#P521"><code>P521</code></a> curve
-      implementation has been rewritten using code generated by the
-      <a href="https://github.com/mit-plv/fiat-crypto">fiat-crypto project</a>,
-      which is based on a formally-verified model of the arithmetic
-      operations. It is now constant-time and three times faster on amd64 and
-      arm64. The observable behavior has not otherwise changed.
-    </p>
-  </dd>
-</dl><!-- crypto/elliptic -->
-
-<dl id="crypto/rand"><dt><a href="/pkg/crypto/rand/">crypto/rand</a></dt>
-  <dd>
-    <p><!-- CL 302489, CL 299134, CL 269999 -->
-      The <code>crypto/rand</code> package now uses the <code>getentropy</code>
-      syscall on macOS and the <code>getrandom</code> syscall on Solaris,
-      Illumos, and DragonFlyBSD.
-    </p>
-  </dd>
-</dl><!-- crypto/rand -->
-
-<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
-  <dd>
-    <p><!-- CL 295370 -->
-      The new <a href="/pkg/crypto/tls#Conn.HandshakeContext"><code>Conn.HandshakeContext</code></a>
-      method allows the user to control cancellation of an in-progress TLS
-      handshake. The provided context is accessible from various callbacks through the new
-      <a href="/pkg/crypto/tls#ClientHelloInfo.Context"><code>ClientHelloInfo.Context</code></a> and
-      <a href="/pkg/crypto/tls#CertificateRequestInfo.Context"><code>CertificateRequestInfo.Context</code></a>
-      methods. Canceling the context after the handshake has finished has no effect.
-    </p>
-
-    <p><!-- CL 314609 -->
-      Cipher suite ordering is now handled entirely by the
-      <code>crypto/tls</code> package. Currently, cipher suites are sorted based
-      on their security, performance, and hardware support taking into account
-      both the local and peer's hardware. The order of the
-      <a href="/pkg/crypto/tls#Config.CipherSuites"><code>Config.CipherSuites</code></a>
-      field is now ignored, as well as the
-      <a href="/pkg/crypto/tls#Config.PreferServerCipherSuites"><code>Config.PreferServerCipherSuites</code></a>
-      field. Note that <code>Config.CipherSuites</code> still allows
-      applications to choose what TLS 1.0–1.2 cipher suites to enable.
-    </p>
-
-    <p>
-      The 3DES cipher suites have been moved to
-      <a href="/pkg/crypto/tls#InsecureCipherSuites"><code>InsecureCipherSuites</code></a>
-      due to <a href="https://sweet32.info/">fundamental block size-related
-      weakness</a>. They are still enabled by default but only as a last resort,
-      thanks to the cipher suite ordering change above.
-    </p>
-
-    <p><!-- golang.org/issue/45428 -->
-      Beginning in the next release, Go 1.18, the
-      <a href="/pkg/crypto/tls/#Config.MinVersion"><code>Config.MinVersion</code></a>
-      for <code>crypto/tls</code> clients will default to TLS 1.2, disabling TLS 1.0
-      and TLS 1.1 by default. Applications will be able to override the change by
-      explicitly setting <code>Config.MinVersion</code>.
-      This will not affect <code>crypto/tls</code> servers.
-    </p>
-  </dd>
-</dl><!-- crypto/tls -->
-
-<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
-  <dd>
-    <p><!-- CL 224157 -->
-      <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
-      now returns an error if the provided private key doesn't match the
-      parent's public key, if any. The resulting certificate would have failed
-      to verify.
-    </p>
-
-    <p><!-- CL 315209 -->
-      The temporary <code>GODEBUG=x509ignoreCN=0</code> flag has been removed.
-    </p>
-
-    <p><!-- CL 274234 -->
-      <a href="/pkg/crypto/x509/#ParseCertificate"><code>ParseCertificate</code></a>
-      has been rewritten, and now consumes ~70% fewer resources. The observable
-      behavior has not otherwise changed, except for error messages.
-    </p>
-
-    <p><!-- CL 321190 -->
-      On BSD systems, <code>/etc/ssl/certs</code> is now searched for trusted
-      roots. This adds support for the new system trusted certificate store in
-      FreeBSD 12.2+.
-    </p>
-
-    <p><!-- golang.org/issue/41682 -->
-      Beginning in the next release, Go 1.18, <code>crypto/x509</code> will
-      reject certificates signed with the SHA-1 hash function. This doesn't
-      apply to self-signed root certificates. Practical attacks against SHA-1
-      <a href="https://shattered.io/">have been demonstrated in 2017</a> and publicly
-      trusted Certificate Authorities have not issued SHA-1 certificates since 2015.
-    </p>
-  </dd>
-</dl><!-- crypto/x509 -->
-
-<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
-  <dd>
-    <p><!-- CL 258360 -->
-      The <a href="/pkg/database/sql/#DB.Close"><code>DB.Close</code></a> method now closes
-      the <code>connector</code> field if the type in this field implements the
-      <a href="/pkg/io/#Closer"><code>io.Closer</code></a> interface.
-    </p>
-
-    <p><!-- CL 311572 -->
-      The new
-      <a href="/pkg/database/sql/#NullInt16"><code>NullInt16</code></a>
-      and
-      <a href="/pkg/database/sql/#NullByte"><code>NullByte</code></a>
-      structs represent the int16 and byte values that may be null. These can be used as
-      destinations of the <a href="/pkg/database/sql/#Scan"><code>Scan</code></a> method,
-      similar to NullString.
-    </p>
-  </dd>
-</dl><!-- database/sql -->
-
-<dl id="debug/elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
-  <dd>
-    <p><!-- CL 239217 -->
-      The <a href="/pkg/debug/elf/#SHT_MIPS_ABIFLAGS"><code>SHT_MIPS_ABIFLAGS</code></a>
-      constant has been added.
-    </p>
-  </dd>
-</dl><!-- debug/elf -->
-
-<dl id="encoding/binary"><dt><a href="/pkg/encoding/binary/">encoding/binary</a></dt>
-  <dd>
-    <p><!-- CL 299531 -->
-      <code>binary.Uvarint</code> will stop reading after <code>10 bytes</code> to avoid
-      wasted computations. If more than <code>10 bytes</code> are needed, the byte count returned is <code>-11</code>.
-      <br />
-      Previous Go versions could return larger negative counts when reading incorrectly encoded varints.
-    </p>
-  </dd>
-</dl><!-- encoding/binary -->
-
-<dl id="encoding/csv"><dt><a href="/pkg/encoding/csv/">encoding/csv</a></dt>
-  <dd>
-    <p><!-- CL 291290 -->
-      The new
-      <a href="/pkg/encoding/csv/#Reader.FieldPos"><code>Reader.FieldPos</code></a>
-      method returns the line and column corresponding to the start of
-      a given field in the record most recently returned by
-      <a href="/pkg/encoding/csv/#Reader.Read"><code>Read</code></a>.
-    </p>
-  </dd>
-</dl><!-- encoding/csv -->
-
-<dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
-  <dd>
-    <p><!-- CL 277893 -->
-      When a comment appears within a
-      <a href="/pkg/encoding/xml/#Directive"><code>Directive</code></a>, it is now replaced
-      with a single space instead of being completely elided.
-    </p>
-
-    <p>
-      Invalid element or attribute names with leading, trailing, or multiple
-      colons are now stored unmodified into the
-      <a href="/pkg/encoding/xml/#Name"><code>Name.Local</code></a> field.
-    </p>
-  </dd>
-</dl><!-- encoding/xml -->
-
-<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
-  <dd>
-    <p><!-- CL 271788 -->
-      Flag declarations now panic if an invalid name is specified.
-    </p>
-  </dd>
-</dl><!-- flag -->
-
-<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
-  <dd>
-    <p><!-- CL 310732 -->
-      The new
-      <a href="/pkg/go/build/#Context.ToolTags"><code>Context.ToolTags</code></a>
-      field holds the build tags appropriate to the current Go
-      toolchain configuration.
-    </p>
-  </dd>
-</dl><!-- go/build -->
-
-<dl id="go/format"><dt><a href="/pkg/go/format/">go/format</a></dt>
-  <dd>
-    <p>
-      The <a href="/pkg/go/format/#Source"><code>Source</code></a> and
-      <a href="/pkg/go/format/#Node"><code>Node</code></a> functions now
-      synchronize <code>//go:build</code> lines with <code>// +build</code>
-      lines. If a file only has <code>// +build</code> lines, they will be
-      moved to the appropriate location in the file, and matching
-      <code>//go:build</code> lines will be added. Otherwise,
-      <code>// +build</code> lines will be overwritten based on any existing
-      <code>//go:build</code> lines. For more information, see
-      <a href="https://golang.org/design/draft-gobuild">https://golang.org/design/draft-gobuild</a>.
-    </p>
-  </dd>
-</dl><!-- go/format -->
-
-<dl id="go/parser"><dt><a href="/pkg/go/parser/">go/parser</a></dt>
-  <dd>
-    <p><!-- CL 306149 -->
-      The new <a href="/pkg/go/parser/#SkipObjectResolution"><code>SkipObjectResolution</code></a>
-      <code>Mode</code> value instructs the parser not to resolve identifiers to
-      their declaration. This may improve parsing speed.
-    </p>
-  </dd>
-</dl><!-- go/parser -->
-
-<dl id="image"><dt><a href="/pkg/image/">image</a></dt>
-  <dd>
-    <p><!-- CL 311129 -->
-      The concrete image types (<code>RGBA</code>, <code>Gray16</code> and so on)
-      now implement a new <a href="/pkg/image/#RGBA64Image"><code>RGBA64Image</code></a>
-      interface. The concrete types that previously implemented
-      <a href="/pkg/image/draw/#Image"><code>draw.Image</code></a> now also implement
-      <a href="/pkg/image/draw/#RGBA64Image"><code>draw.RGBA64Image</code></a>, a
-      new interface in the <code>image/draw</code> package.
-    </p>
-  </dd>
-</dl><!-- image -->
-
-<dl id="io/fs"><dt><a href="/pkg/io/fs/">io/fs</a></dt>
-  <dd>
-    <p><!-- CL 293649 -->
-      The new <a href="/pkg/io/fs/#FileInfoToDirEntry"><code>FileInfoToDirEntry</code></a> function converts a <code>FileInfo</code> to a <code>DirEntry</code>.
-    </p>
-  </dd>
-</dl><!-- io/fs -->
-
-<dl id="math"><dt><a href="/pkg/math/">math</a></dt>
-  <dd>
-    <p><!-- CL 247058 -->
-      The math package now defines three more constants: <code>MaxUint</code>, <code>MaxInt</code> and <code>MinInt</code>.
-      For 32-bit systems their values are <code>2^32 - 1</code>, <code>2^31 - 1</code> and <code>-2^31</code>, respectively.
-      For 64-bit systems their values are <code>2^64 - 1</code>, <code>2^63 - 1</code> and <code>-2^63</code>, respectively.
-    </p>
-  </dd>
-</dl><!-- math -->
-
-<dl id="mime"><dt><a href="/pkg/mime/">mime</a></dt>
-  <dd>
-    <p><!-- CL 305230 -->
-      On Unix systems, the table of MIME types is now read from the local system's
-      <a href="https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.21.html">Shared MIME-info Database</a>
-      when available.
-    </p>
-  </dd>
-</dl><!-- mime -->
-
-<dl id="mime/multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
-  <dd>
-    <p><!-- CL 313809 -->
-      <a href="/pkg/mime/multipart/#Part.FileName"><code>Part.FileName</code></a>
-      now applies
-      <a href="/pkg/path/filepath/#Base"><code>filepath.Base</code></a> to the
-      return value. This mitigates potential path traversal vulnerabilities in
-      applications that accept multipart messages, such as <code>net/http</code>
-      servers that call
-      <a href="/pkg/net/http/#Request.FormFile"><code>Request.FormFile</code></a>.
-    </p>
-  </dd>
-</dl><!-- mime/multipart -->
-
-<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
-  <dd>
-    <p><!-- CL 272668 -->
-      The new method <a href="/pkg/net/#IP.IsPrivate"><code>IP.IsPrivate</code></a> reports whether an address is
-      a private IPv4 address according to <a href="https://datatracker.ietf.org/doc/rfc1918">RFC 1918</a>
-      or a local IPv6 address according <a href="https://datatracker.ietf.org/doc/rfc4193">RFC 4193</a>.
-    </p>
-
-    <p><!-- CL 301709 -->
-      The Go DNS resolver now only sends one DNS query when resolving an address for an IPv4-only or IPv6-only network,
-      rather than querying for both address families.
-    </p>
-
-    <p><!-- CL 307030 -->
-      The <a href="/pkg/net/#ErrClosed"><code>ErrClosed</code></a> sentinel error and
-      <a href="/pkg/net/#ParseError"><code>ParseError</code></a> error type now implement
-      the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface.
-    </p>
-
-    <p><!-- CL 325829 -->
-      The <a href="/pkg/net/#ParseIP"><code>ParseIP</code></a> and <a href="/pkg/net/#ParseCIDR"><code>ParseCIDR</code></a>
-      functions now reject IPv4 addresses which contain decimal components with leading zeros.
-
-      These components were always interpreted as decimal, but some operating systems treat them as octal.
-      This mismatch could hypothetically lead to security issues if a Go application was used to validate IP addresses
-      which were then used in their original form with non-Go applications which interpreted components as octal. Generally,
-      it is advisable to always re-encode values after validation, which avoids this class of parser misalignment issues.
-    </p>
-  </dd>
-</dl><!-- net -->
-
-<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
-  <dd>
-    <p><!-- CL 295370 -->
-      The <a href="/pkg/net/http/"><code>net/http</code></a> package now uses the new
-      <a href="/pkg/crypto/tls#Conn.HandshakeContext"><code>(*tls.Conn).HandshakeContext</code></a>
-      with the <a href="/pkg/net/http/#Request"><code>Request</code></a> context
-      when performing TLS handshakes in the client or server.
-    </p>
-
-    <p><!-- CL 235437 -->
-      Setting the <a href="/pkg/net/http/#Server"><code>Server</code></a>
-      <code>ReadTimeout</code> or <code>WriteTimeout</code> fields to a negative value now indicates no timeout
-      rather than an immediate timeout.
-    </p>
-
-    <p><!-- CL 308952 -->
-      The <a href="/pkg/net/http/#ReadRequest"><code>ReadRequest</code></a> function
-      now returns an error when the request has multiple Host headers.
-    </p>
-
-    <p><!-- CL 313950 -->
-      When producing a redirect to the cleaned version of a URL,
-      <a href="/pkg/net/http/#ServeMux"><code>ServeMux</code></a> now always
-      uses relative URLs in the <code>Location</code> header. Previously it
-      would echo the full URL of the request, which could lead to unintended
-      redirects if the client could be made to send an absolute request URL.
-    </p>
-
-    <p><!-- CL 308009, CL 313489 -->
-      When interpreting certain HTTP headers handled by <code>net/http</code>,
-      non-ASCII characters are now ignored or rejected.
-    </p>
-
-    <p><!-- CL 325697 -->
-      If
-      <a href="/pkg/net/http/#Request.ParseForm"><code>Request.ParseForm</code></a>
-      returns an error when called by
-      <a href="/pkg/net/http/#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>,
-      the latter now continues populating
-      <a href="/pkg/net/http/#Request.MultipartForm"><code>Request.MultipartForm</code></a>
-      before returning it.
-    </p>
-  </dd>
-</dl><!-- net/http -->
-
-<dl id="net/http/httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
-  <dd>
-    <p><!-- CL 308950 -->
-      <a href="/pkg/net/http/httptest/#ResponseRecorder.WriteHeader"><code>ResponseRecorder.WriteHeader</code></a>
-      now panics when the provided code is not a valid three-digit HTTP status code.
-      This matches the behavior of <a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>
-      implementations in the <a href="/pkg/net/http/"><code>net/http</code></a> package.
-    </p>
-  </dd>
-</dl><!-- net/http/httptest -->
-
-<dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
-  <dd>
-    <p><!-- CL 314850 -->
-      The new method <a href="/pkg/net/url/#Values.Has"><code>Values.Has</code></a>
-      reports whether a query parameter is set.
-    </p>
-  </dd>
-</dl><!-- net/url -->
-
-<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
-  <dd>
-    <p><!-- CL 268020 -->
-      The <a href="/pkg/os/#File.WriteString"><code>File.WriteString</code></a> method
-      has been optimized to not make a copy of the input string.
-    </p>
-  </dd>
-</dl><!-- os -->
-
-<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
-  <dd>
-    <p><!-- CL 334669 -->
-      The new
-      <a href="/pkg/reflect/#Value.CanConvert"><code>Value.CanConvert</code></a>
-      method reports whether a value can be converted to a type.
-      This may be used to avoid a panic when converting a slice to an
-      array pointer type if the slice is too short.
-      Previously it was sufficient to use
-      <a href="/pkg/reflect/#Type.ConvertibleTo"><code>Type.ConvertibleTo</code></a>
-      for this, but the newly permitted conversion from slice to array
-      pointer type can panic even if the types are convertible.
-    </p>
-
-    <p><!-- CL 266197 -->
-      The new
-      <a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a>
-      and
-      <a href="/pkg/reflect/#Method.IsExported"><code>Method.IsExported</code></a>
-      methods report whether a struct field or type method is exported.
-      They provide a more readable alternative to checking whether <code>PkgPath</code>
-      is empty.
-    </p>
-
-    <p><!-- CL 281233 -->
-      The new <a href="/pkg/reflect/#VisibleFields"><code>VisibleFields</code></a> function
-      returns all the visible fields in a struct type, including fields inside anonymous struct members.
-    </p>
-
-    <p><!-- CL 284136 -->
-      The <a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a> function now panics when
-      called with a negative length.
-    </p>
-
-    <p><!-- CL 301652 -->
-      Checking the <a href="/pkg/reflect/#Type"><code>Type.ConvertibleTo</code></a> method
-      is no longer sufficient to guarantee that a call to
-      <a href="/pkg/reflect/#Value.Convert"><code>Value.Convert</code></a> will not panic.
-      It may panic when converting `[]T` to `*[N]T` if the slice's length is less than N.
-      See the <a href="#language">language changes</a> section above.
-    </p>
-  </dd>
-</dl><!-- reflect -->
-
-<dl id="runtime/metrics"><dt><a href="/pkg/runtime/metrics">runtime/metrics</a></dt>
-  <dd>
-    <p><!-- CL 308933, CL 312431, CL 312909 -->
-      New metrics were added that track total bytes and objects allocated and freed.
-      A new metric tracking the distribution of goroutine scheduling latencies was
-      also added.
-    </p>
-  </dd>
-</dl><!-- runtime/metrics -->
-
-<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof">runtime/pprof</a></dt>
-  <dd>
-    <p><!-- CL 299991 -->
-      Block profiles are no longer biased to favor infrequent long events over
-      frequent short events.
-    </p>
-  </dd>
-</dl><!-- runtime/pprof -->
-
-<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
-  <dd>
-    <p><!-- CL 170079, CL 170080 -->
-      The <code>strconv</code> package now uses Ulf Adams's Ryū algorithm for formatting floating-point numbers.
-      This algorithm improves performance on most inputs and is more than 99% faster on worst-case inputs.
-    </p>
-
-    <p><!-- CL 314775 -->
-      The new <a href="/pkg/strconv/#QuotedPrefix"><code>QuotedPrefix</code></a> function
-      returns the quoted string (as understood by
-      <a href="/pkg/strconv/#Unquote"><code>Unquote</code></a>)
-      at the start of input.
-    </p>
-  </dd>
-</dl><!-- strconv -->
-
-<dl id="strings"><dt><a href="/pkg/strings/">strings</a></dt>
-  <dd>
-    <p><!-- CL 280492 -->
-      The <a href="/pkg/strings/#Builder.WriteRune"><code>Builder.WriteRune</code></a> method
-      now writes the replacement character U+FFFD for negative rune values,
-      as it does for other invalid runes.
-    </p>
-  </dd>
-</dl><!-- strings -->
-
-<dl id="sync/atomic"><dt><a href="/pkg/sync/atomic/">sync/atomic</a></dt>
-  <dd>
-    <p><!-- CL 241678 -->
-      <code>atomic.Value</code> now has <a href="/pkg/sync/atomic/#Value.Swap"><code>Swap</code></a> and
-      <a href="/pkg/sync/atomic/#Value.CompareAndSwap"><code>CompareAndSwap</code></a> methods that provide
-      additional atomic operations.
-    </p>
-  </dd>
-</dl><!-- sync/atomic -->
-
-<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
-  <dd>
-    <p><!-- CL 295371 -->
-    <p>
-      The <a href="/pkg/syscall/#GetQueuedCompletionStatus"><code>GetQueuedCompletionStatus</code></a> and
-      <a href="/pkg/syscall/#PostQueuedCompletionStatus"><code>PostQueuedCompletionStatus</code></a>
-      functions are now deprecated. These functions have incorrect signatures and are superseded by
-      equivalents in the <a href="https://godoc.org/golang.org/x/sys/windows"><code>golang.org/x/sys/windows</code></a> package.
-    </p>
-
-    <p><!-- CL 313653 -->
-      On Unix-like systems, the process group of a child process is now set with signals blocked.
-      This avoids sending a <code>SIGTTOU</code> to the child when the parent is in a background process group.
-    </p>
-
-    <p><!-- CL 288298, CL 288300 -->
-      The Windows version of
-      <a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a>
-      has two new fields. <code>AdditionalInheritedHandles</code> is
-      a list of additional handles to be inherited by the new child
-      process. <code>ParentProcess</code> permits specifying the
-      parent process of the new process.
-
-    <p><!-- CL 311570 -->
-      The constant <code>MSG_CMSG_CLOEXEC</code> is now defined on
-      DragonFly and all OpenBSD systems (it was already defined on
-      some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).
-    </p>
-
-    <p><!-- CL 315281 -->
-      The constants <code>SYS_WAIT6</code> and <code>WEXITED</code>
-      are now defined on NetBSD systems (<code>SYS_WAIT6</code> was
-      already defined on DragonFly and FreeBSD systems;
-      <code>WEXITED</code> was already defined on Darwin, DragonFly,
-      FreeBSD, Linux, and Solaris systems).
-    </p>
-  </dd>
-</dl><!-- syscall -->
-
-<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
-  <dd>
-    <p><!-- CL 310033 -->
-      Added a new <a href="/cmd/go/#hdr-Testing_flags">testing flag</a> <code>-shuffle</code> which controls the execution order of tests and benchmarks.
-    </p>
-    <p><!-- CL 260577 -->
-      The new
-      <a href="/pkg/testing/#T.Setenv"><code>T.Setenv</code></a>
-      and <a href="/pkg/testing/#B.Setenv"><code>B.Setenv</code></a>
-      methods support setting an environment variable for the duration
-      of the test or benchmark.
-    </p>
-  </dd>
-</dl><!-- testing -->
-
-<dl id="text/template/parse"><dt><a href="/pkg/text/template/parse/">text/template/parse</a></dt>
-  <dd>
-    <p><!-- CL 301493 -->
-      The new <a href="/pkg/text/template/parse/#Mode"><code>SkipFuncCheck</code></a> <a href=><code>Mode</code></a>
-      value changes the template parser to not verify that functions are defined.
-    </p>
-  </dd>
-</dl><!-- text/template/parse -->
-
-<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
-  <dd>
-    <p><!-- CL 260858 -->
-      The <a href="/pkg/time/#Time"><code>Time</code></a> type now has a
-      <a href="/pkg/time/#Time.GoString"><code>GoString</code></a> method that
-      will return a more useful value for times when printed with the
-      <code>%#v</code> format specifier in the <code>fmt</code> package.
-    </p>
-
-    <p><!-- CL 264077 -->
-      The new <a href="/pkg/time/#Time.IsDST"><code>Time.IsDST</code></a> method can be used to check whether the time
-      is in Daylight Savings Time in its configured location.
-    </p>
-
-    <p><!-- CL 293349 -->
-      The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and
-      <a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a>
-      methods return the number of milliseconds and microseconds elapsed since
-      January 1, 1970 UTC respectively.
-      <br />
-      The new <a href="/pkg/time/#UnixMilli"><code>UnixMilli</code></a> and
-      <a href="/pkg/time/#UnixMicro"><code>UnixMicro</code></a> functions
-      return the local <code>Time</code> corresponding to the given Unix time.
-    </p>
-
-    <p><!-- CL 300996 -->
-      The package now accepts comma "," as a separator for fractional seconds when parsing and formatting time.
-      For example, the following time layouts are now accepted:
-      <ul>
-        <li>2006-01-02 15:04:05,999999999 -0700 MST</li>
-        <li>Mon Jan _2 15:04:05,000000 2006</li>
-        <li>Monday, January 2 15:04:05,000 2006</li>
-      </ul>
-    </p>
-
-    <p><!-- CL 320252 -->
-      The new constant <a href="/pkg/time/#Layout"><code>Layout</code></a>
-      defines the reference time.
-    </p>
-  </dd>
-</dl><!-- time -->
-
-<dl id="unicode"><dt><a href="/pkg/unicode/">unicode</a></dt>
-  <dd>
-    <p><!-- CL 280493 -->
-      The <a href="/pkg/unicode/#Is"><code>Is</code></a>,
-      <a href="/pkg/unicode/#IsGraphic"><code>IsGraphic</code></a>,
-      <a href="/pkg/unicode/#IsLetter"><code>IsLetter</code></a>,
-      <a href="/pkg/unicode/#IsLower"><code>IsLower</code></a>,
-      <a href="/pkg/unicode/#IsMark"><code>IsMark</code></a>,
-      <a href="/pkg/unicode/#IsNumber"><code>IsNumber</code></a>,
-      <a href="/pkg/unicode/#IsPrint"><code>IsPrint</code></a>,
-      <a href="/pkg/unicode/#IsPunct"><code>IsPunct</code></a>,
-      <a href="/pkg/unicode/#IsSpace"><code>IsSpace</code></a>,
-      <a href="/pkg/unicode/#IsSymbol"><code>IsSymbol</code></a>, and
-      <a href="/pkg/unicode/#IsUpper"><code>IsUpper</code></a> functions
-      now return <code>false</code> on negative rune values, as they do for other invalid runes.
-    </p>
-  </dd>
-</dl><!-- unicode -->
diff --git a/doc/go1.18.html b/doc/go1.18.html
new file mode 100644 (file)
index 0000000..385a1ae
--- /dev/null
@@ -0,0 +1,242 @@
+<!--{
+       "Title": "Go 1.18 Release Notes",
+       "Path":  "/doc/go1.18"
+}-->
+
+<!--
+NOTE: In this document and others in this directory, the convention is to
+set fixed-width phrases with non-fixed-width spaces, as in
+<code>hello</code> <code>world</code>.
+Do not send CLs removing the interior tags from such phrases.
+-->
+
+<style>
+  main ul li { margin: 0.5em 0; }
+</style>
+
+<h2 id="introduction">DRAFT RELEASE NOTES — Introduction to Go 1.18</h2>
+
+<p>
+  <strong>
+    Go 1.18 is not yet released. These are work-in-progress
+    release notes. Go 1.18 is expected to be released in February 2022.
+  </strong>
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+  TODO: complete this section
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p id="freebsd">
+  Go 1.18 is the last release that is supported on FreeBSD 11.x, which has
+  already reached end-of-life. Go 1.19 will require FreeBSD 12.2+ or FreeBSD
+  13.0+.
+  FreeBSD 13.0+ will require a kernel with the COMPAT_FREEBSD12 option set (this is the default).
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<p>
+  TODO: complete this section, or delete if not needed
+</p>
+
+<h3 id="go-command">Go command</h3>
+
+<p><!-- golang.org/issue/43684 -->
+  <code>go</code> <code>get</code> no longer builds or installs packages in
+  module-aware mode. <code>go</code> <code>get</code> is now dedicated to
+  adjusting dependencies in <code>go.mod</code>. Effectively, the
+  <code>-d</code> flag is always enabled. To install the latest version
+  of an executable outside the context of the current module, use
+  <a href="https://golang.org/ref/mod#go-install"><code>go</code>
+  <code>install</code> <code>example.com/cmd@latest</code></a>. Any
+  <a href="https://golang.org/ref/mod#version-queries">version query</a>
+  may be used instead of <code>latest</code>. This form of <code>go</code>
+  <code>install</code> was added in Go 1.16, so projects supporting older
+  versions may need to provide install instructions for both <code>go</code>
+  <code>install</code> and <code>go</code> <code>get</code>. <code>go</code>
+  <code>get</code> now reports an error when used outside a module, since there
+  is no <code>go.mod</code> file to update. In GOPATH mode (with
+  <code>GO111MODULE=off</code>), <code>go</code> <code>get</code> still builds
+  and installs packages, as before.
+</p>
+
+<p><!-- golang.org/issue/37475 -->
+  The <code>go</code> command now embeds version control information in
+  binaries including the currently checked-out revision, commit time, and a
+  flag indicating whether edited or untracked files are present. Version
+  control information is embedded if the <code>go</code> command is invoked in
+  a directory within a Git, Mercurial, Fossil, or Bazaar repository, and the
+  <code>main</code> package and its containing main module are in the same
+  repository. This information may be omitted using the flag
+  <code>-buildvcs=false</code>.
+</p>
+
+<p><!-- golang.org/issue/37475 -->
+  Additionally, the <code>go</code> command embeds information about the build
+  including build and tool tags (set with <code>-tags</code>), compiler,
+  assembler, and linker flags (like <code>-gcflags</code>), whether cgo was
+  enabled, and if it was, the values of the cgo environment variables
+  (like <code>CGO_CFLAGS</code>). This information may be omitted using the
+  flag <code>-buildinfo=false</code>. Both VCS and build information may be
+  read together with module information using <code>go</code>
+  <code>version</code> <code>-m</code> <code>file</code> or
+  <code>runtime/debug.ReadBuildInfo</code> (for the currently running binary)
+  or the new <a href="#debug/buildinfo"><code>debug/buildinfo</code></a>
+  package.
+</p>
+
+<p><!-- https://golang.org/issue/44435 -->
+  If the main module's <code>go.mod</code> file
+  specifies <a href="/ref/mod#go-mod-file-go"><code>go</code> <code>1.17</code></a>
+  or higher, <code>go</code> <code>mod</code> <code>download</code> without
+  arguments now downloads source code for only the modules
+  explicitly <a href="/ref/mod#go-mod-file-require">required</a> in the main
+  module's <code>go.mod</code> file. (In a <code>go</code> <code>1.17</code> or
+  higher module, that set already includes all dependencies needed to build the
+  packages and tests in the main module.)
+  To also download source code for transitive dependencies, use
+  <code>go</code> <code>mod</code> <code>download</code> <code>all</code>.
+</p>
+
+<p>
+  TODO: complete this section, or delete if not needed
+</p>
+
+<h3 id="gofmt"><code>gofmt</code></h3>
+
+<p><!-- https://golang.org/issue/43566 -->
+  <code>gofmt</code> now reads and formats input files concurrently, with a
+  memory limit proportional to <code>GOMAXPROCS</code>. On a machine with
+  multiple CPUs, <code>gofmt</code> should now be significantly faster.
+</p>
+
+
+<h2 id="runtime">Runtime</h2>
+
+<p>
+  TODO: complete this section, or delete if not needed
+</p>
+
+<h2 id="compiler">Compiler</h2>
+
+<p>
+  TODO: complete this section, or delete if not needed
+</p>
+
+<h2 id="linker">Linker</h2>
+
+<p>
+  TODO: complete this section, or delete if not needed
+</p>
+
+<h2 id="library">Core library</h2>
+
+<h3>TODO</h3>
+<p>
+  TODO: complete this section
+</p>
+
+<h3 id="netip">New <code>net/netip</code> package</h3>
+<p>
+  The new <a href="/pkg/net/netip/"><code>net/netip</code></a>
+  package defines a new IP address type, <a href="/pkg/net/netip/#Addr"><code>Addr</code></a>.
+  Compared to the existing
+  <a href="/pkg/net/#IP"><code>net.IP</code></a> type, the <code>netip.Addr</code> type takes less
+  memory, is immutable, and is comparable so it supports <code>==</code>
+  and can be used as a map key.
+</p>
+<p>
+  In addition to <code>Addr</code>, the package defines
+  <a href="/pkg/net/netip/#AddrPort"><code>AddrPort</code></a>, representing
+  an IP and port, and
+  <a href="/pkg/net/netip/#Prefix"><code>Prefix</code></a>, representing
+  a network CIDR prefix.
+</p>
+<p>
+  The <code>net</code> package now has methods to send and receive UDP packets
+  using <code>netip.Addr</code> values instead of the relatively heavy
+  <code>*net.UDPAddr</code> values.
+</p>
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+  As always, there are various minor changes and updates to the library,
+  made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
+  in mind.
+</p>
+
+<p>
+  TODO: complete this section
+</p>
+
+<dl id="debug/buildinfo"><dt><a href="/pkg/debug/buildinfo">debug/buildinfo</a></dt>
+  <dd>
+    <p><!-- golang.org/issue/39301 -->
+      This new package provides access to module versions, version control
+      information, and build flags embedded in executable files built by
+      the <code>go</code> command. The same information is also available via
+      <a href="/pkg/runtime/debug#ReadBuildInfo"><code>runtime/debug.ReadBuildInfo</code></a>
+      for the currently running binary and via <code>go</code>
+      <code>version</code> <code>-m</code> on the command line.
+    </p>
+  </dd>
+</dl>
+
+<dl id="image/draw"><dt><a href="/pkg/image/draw/">image/draw</a></dt>
+  <dd>
+    <p><!-- CL 340049 -->
+      The <code>Draw</code> and <code>DrawMask</code> fallback implementations
+      (used when the arguments are not the most common image types) are now
+      faster when those arguments implement the optional
+      <a href="/pkg/image/draw/#RGBA64Image"><code>draw.RGBA64Image</code></a>
+      and <a href="/pkg/image/#RGBA64Image"><code>image.RGBA64Image</code></a>
+      interfaces that were added in Go 1.17.
+    </p>
+  </dd>
+</dl><!-- image/draw -->
+
+<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
+  <dd>
+    <p><!-- CL 356049, 320929 -->
+      The new
+      <a href="/pkg/reflect/#Value.SetIterKey"><code>Value.SetIterKey</code></a>
+      and <a href="/pkg/reflect/#Value.SetIterValue"><code>Value.SetIterValue</code></a>
+      methods set a Value using a map iterator as the source. They are equivalent to
+      <code>Value.Set(iter.Key())</code> and <code>Value.Set(iter.Value())</code> but
+      do fewer allocations.
+    </p>
+  </dd>
+  <dd>
+    <p><!-- CL 350691 -->
+      The new
+      <a href="/pkg/reflect/#Value.UnsafePointer"><code>Value.UnsafePointer</code></a>
+      method returns the Value's value as an <a href="/pkg/unsafe/#Pointer"><code>unsafe.Pointer</code></a>.
+      This allows callers to migrate from <a href="/pkg/reflect/#Value.UnsafeAddr"><code>Value.UnsafeAddr</code></a>
+      and <a href="/pkg/reflect/#Value.Pointer"><code>Value.Pointer</code></a>
+      to eliminate the need to perform uintptr to unsafe.Pointer conversions at the callsite (as unsafe.Pointer rules require).
+    </p>
+  </dd>
+</dl><!-- reflect -->
+
+<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
+  <dd>
+    <p><!-- CL 336550 -->
+      The new function <a href="/pkg/syscall/?GOOS=windows#SyscallN"><code>SyscallN</code></a>
+      has been introduced for Windows, allowing for calls with arbitrary number
+      of arguments. As a result,
+      <a href="/pkg/syscall/?GOOS=windows#Syscall"><code>Syscall</code></a>,
+      <a href="/pkg/syscall/?GOOS=windows#Syscall6"><code>Syscall6</code></a>,
+      <a href="/pkg/syscall/?GOOS=windows#Syscall9"><code>Syscall9</code></a>,
+      <a href="/pkg/syscall/?GOOS=windows#Syscall12"><code>Syscall12</code></a>,
+      <a href="/pkg/syscall/?GOOS=windows#Syscall15"><code>Syscall15</code></a>, and
+      <a href="/pkg/syscall/?GOOS=windows#Syscall18"><code>Syscall18</code></a> are
+      deprecated in favor of <a href="/pkg/syscall/?GOOS=windows#SyscallN"><code>SyscallN</code></a>.
+    </p>
+  </dd>
+</dl><!-- syscall -->
index fd5fee46eb220c1111d8aa33853037f751d4bdbb..46eebb57136d0bcb56566c6a46cf3f72c54965ec 100644 (file)
@@ -1,6 +1,6 @@
 <!--{
        "Title": "The Go Programming Language Specification",
-       "Subtitle": "Version of Jul 26, 2021",
+       "Subtitle": "Version of Oct 15, 2021",
        "Path": "/ref/spec"
 }-->
 
@@ -3000,6 +3000,18 @@ method value; the saved copy is then used as the receiver in any calls,
 which may be executed later.
 </p>
 
+<pre>
+type S struct { *T }
+type T int
+func (t T) M() { print(t) }
+
+t := new(T)
+s := S{T: t}
+f := t.M                    // receiver *t is evaluated and stored in f
+g := s.M                    // receiver *(s.T) is evaluated and stored in g
+*t = 42                     // does not affect stored receivers in f and g
+</pre>
+
 <p>
 The type <code>T</code> may be an interface or non-interface type.
 </p>
@@ -3602,7 +3614,7 @@ var i = 1&lt;&lt;s                   // 1 has type int
 var j int32 = 1&lt;&lt;s             // 1 has type int32; j == 0
 var k = uint64(1&lt;&lt;s)           // 1 has type uint64; k == 1&lt;&lt;33
 var m int = 1.0&lt;&lt;s             // 1.0 has type int; m == 1&lt;&lt;33
-var n = 1.0&lt;&lt;s == j            // 1.0 has type int; n == true
+var n = 1.0&lt;&lt;s == j            // 1.0 has type int32; n == true
 var o = 1&lt;&lt;s == 2&lt;&lt;s           // 1 and 2 have type int; o == false
 var p = 1&lt;&lt;s == 1&lt;&lt;33          // 1 has type int; p == true
 var u = 1.0&lt;&lt;s                 // illegal: 1.0 has type float64, cannot shift
@@ -4338,7 +4350,7 @@ t0 := (*[0]string)(t)    // t0 == nil
 t1 := (*[1]string)(t)    // panics: len([1]string) > len(t)
 
 u := make([]byte, 0)
-u0 = (*[0]byte)(u)       // u0 != nil
+u0 := (*[0]byte)(u)      // u0 != nil
 </pre>
 
 <h3 id="Constant_expressions">Constant expressions</h3>
@@ -4549,9 +4561,8 @@ SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | S
 <h3 id="Terminating_statements">Terminating statements</h3>
 
 <p>
-A <i>terminating statement</i> prevents execution of all statements that lexically
-appear after it in the same <a href="#Blocks">block</a>. The following statements
-are terminating:
+A <i>terminating statement</i> interrupts the regular flow of control in
+a <a href="#Blocks">block</a>. The following statements are terminating:
 </p>
 
 <ol>
@@ -4587,7 +4598,8 @@ are terminating:
        A <a href="#For_statements">"for" statement</a> in which:
        <ul>
        <li>there are no "break" statements referring to the "for" statement, and</li>
-       <li>the loop condition is absent.</li>
+       <li>the loop condition is absent, and</li>
+       <li>the "for" statement does not use a range clause.</li>
        </ul>
 </li>
 
index 68a30a44fe427d434df9dc634f702fc38552aa5e..e90ed1e058d83d7318b3ebaadf2c81f5dfaef7ce 100644 (file)
@@ -36,14 +36,13 @@ func check(t *testing.T, file string) {
                                continue
                        }
 
-                       frags := bytes.SplitAfterN(line, []byte("ERROR HERE: "), 2)
-                       if len(frags) == 1 {
+                       _, frag, ok := bytes.Cut(line, []byte("ERROR HERE: "))
+                       if !ok {
                                continue
                        }
-                       frag := fmt.Sprintf(":%d:.*%s", i+1, frags[1])
-                       re, err := regexp.Compile(frag)
+                       re, err := regexp.Compile(fmt.Sprintf(":%d:.*%s", i+1, frag))
                        if err != nil {
-                               t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
+                               t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frag)
                                continue
                        }
                        errors = append(errors, re)
index 143f23f0e0cc36983ad44595469b5b7f55ff0d56..fe99e251e96bb40c59af980a298a126e03cb811b 100644 (file)
@@ -59,6 +59,7 @@ func Test28896(t *testing.T)                 { test28896(t) }
 func Test30065(t *testing.T)                 { test30065(t) }
 func Test32579(t *testing.T)                 { test32579(t) }
 func Test31891(t *testing.T)                 { test31891(t) }
+func Test42018(t *testing.T)                 { test42018(t) }
 func Test45451(t *testing.T)                 { test45451(t) }
 func TestAlign(t *testing.T)                 { testAlign(t) }
 func TestAtol(t *testing.T)                  { testAtol(t) }
diff --git a/misc/cgo/test/issue42018.go b/misc/cgo/test/issue42018.go
new file mode 100644 (file)
index 0000000..fab686a
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2021 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:build !windows
+// +build !windows
+
+package cgotest
+
+import "testing"
+
+func test42018(t *testing.T) {
+       t.Skip("skipping Windows-only test")
+}
diff --git a/misc/cgo/test/issue42018_windows.go b/misc/cgo/test/issue42018_windows.go
new file mode 100644 (file)
index 0000000..8f4570a
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+typedef void *HANDLE;
+
+struct HWND__{int unused;}; typedef struct HWND__ *HWND;
+*/
+import "C"
+
+import (
+       "testing"
+       "unsafe"
+)
+
+func test42018(t *testing.T) {
+       // Test that Windows handles are marked go:notinheap, by growing the
+       // stack and checking for pointer adjustments. Trick from
+       // test/fixedbugs/issue40954.go.
+       var i int
+       handle := C.HANDLE(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
+       recurseHANDLE(100, handle, uintptr(unsafe.Pointer(&i)))
+       hwnd := C.HWND(unsafe.Pointer(uintptr(unsafe.Pointer(&i))))
+       recurseHWND(400, hwnd, uintptr(unsafe.Pointer(&i)))
+}
+
+func recurseHANDLE(n int, p C.HANDLE, v uintptr) {
+       if n > 0 {
+               recurseHANDLE(n-1, p, v)
+       }
+       if uintptr(unsafe.Pointer(p)) != v {
+               panic("adjusted notinheap pointer")
+       }
+}
+
+func recurseHWND(n int, p C.HWND, v uintptr) {
+       if n > 0 {
+               recurseHWND(n-1, p, v)
+       }
+       if uintptr(unsafe.Pointer(p)) != v {
+               panic("adjusted notinheap pointer")
+       }
+}
diff --git a/misc/cgo/test/testdata/issue43639.go b/misc/cgo/test/testdata/issue43639.go
new file mode 100644 (file)
index 0000000..e755fbd
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+// Issue 43639: No runtime test needed, make sure package cgotest/issue43639 compiles well.
+
+import _ "cgotest/issue43639"
diff --git a/misc/cgo/test/testdata/issue43639/a.go b/misc/cgo/test/testdata/issue43639/a.go
new file mode 100644 (file)
index 0000000..fe37d5e
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2021 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 issue43639
+
+// #cgo CFLAGS: -W -Wall -Werror
+import "C"
diff --git a/misc/cgo/test/typeparam.go b/misc/cgo/test/typeparam.go
new file mode 100644 (file)
index 0000000..5f766c2
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+// #include <stddef.h>
+import "C"
+
+func generic[T, U any](t T, u U) {}
+
+func useGeneric() {
+       const zero C.size_t = 0
+
+       generic(zero, zero)
+       generic[C.size_t, C.size_t](0, 0)
+}
index 55be3c5f70710ffe3f1847ac9a545790cdf0d501..a2b43bb72d8d3a351d9c86f715d736d390f42bc5 100644 (file)
@@ -931,3 +931,55 @@ func TestManyCalls(t *testing.T) {
                t.Error(err)
        }
 }
+
+// Issue 49288.
+func TestPreemption(t *testing.T) {
+       if runtime.Compiler == "gccgo" {
+               t.Skip("skipping asynchronous preemption test with gccgo")
+       }
+
+       t.Parallel()
+
+       if !testWork {
+               defer func() {
+                       os.Remove("testp8" + exeSuffix)
+                       os.Remove("libgo8.a")
+                       os.Remove("libgo8.h")
+               }()
+       }
+
+       cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo8.a", "./libgo8")
+       if out, err := cmd.CombinedOutput(); err != nil {
+               t.Logf("%s", out)
+               t.Fatal(err)
+       }
+       checkLineComments(t, "libgo8.h")
+
+       ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
+       if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+               t.Logf("%s", out)
+               t.Fatal(err)
+       }
+
+       argv := cmdToRun("./testp8")
+       cmd = exec.Command(argv[0], argv[1:]...)
+       var sb strings.Builder
+       cmd.Stdout = &sb
+       cmd.Stderr = &sb
+       if err := cmd.Start(); err != nil {
+               t.Fatal(err)
+       }
+
+       timer := time.AfterFunc(time.Minute,
+               func() {
+                       t.Error("test program timed out")
+                       cmd.Process.Kill()
+               },
+       )
+       defer timer.Stop()
+
+       if err := cmd.Wait(); err != nil {
+               t.Log(sb.String())
+               t.Error(err)
+       }
+}
diff --git a/misc/cgo/testcarchive/testdata/libgo8/a.go b/misc/cgo/testcarchive/testdata/libgo8/a.go
new file mode 100644 (file)
index 0000000..718418e
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2021 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 "C"
+
+import (
+       "os"
+       "runtime"
+       "sync/atomic"
+)
+
+var started int32
+
+// Start a goroutine that loops forever.
+func init() {
+       runtime.GOMAXPROCS(1)
+       go func() {
+               for {
+                       atomic.StoreInt32(&started, 1)
+               }
+       }()
+}
+
+//export GoFunction8
+func GoFunction8() {
+       for atomic.LoadInt32(&started) == 0 {
+               runtime.Gosched()
+       }
+       os.Exit(0)
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcarchive/testdata/main8.c b/misc/cgo/testcarchive/testdata/main8.c
new file mode 100644 (file)
index 0000000..95fb7a3
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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 preemption.
+
+#include <stdlib.h>
+
+#include "libgo8.h"
+
+int main() {
+       GoFunction8();
+
+       // That should have exited the program.
+       abort();
+}
index 19ad8c76a838b54bad64c35635216088ff40db80..84b92d502fdb5e6b17448e1f015833af7f10e555 100644 (file)
@@ -200,7 +200,7 @@ func adbRun(t *testing.T, env []string, adbargs ...string) string {
        args := append(adbCmd(), "exec-out")
        // Propagate LD_LIBRARY_PATH to the adb shell invocation.
        for _, e := range env {
-               if strings.Index(e, "LD_LIBRARY_PATH=") != -1 {
+               if strings.Contains(e, "LD_LIBRARY_PATH=") {
                        adbargs = append([]string{e}, adbargs...)
                        break
                }
@@ -326,7 +326,7 @@ func createHeaders() error {
                        base, name := filepath.Split(args[0])
                        args[0] = filepath.Join(base, "llvm-dlltool")
                        var machine string
-                       switch strings.SplitN(name, "-", 2)[0] {
+                       switch prefix, _, _ := strings.Cut(name, "-"); prefix {
                        case "i686":
                                machine = "i386"
                        case "x86_64":
index d18f0b130d3f767671e4030fd34056c85c4bd132..d343aa54d9a8779450092461213c8d748d26fb84 100644 (file)
@@ -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 darwin dragonfly freebsd linux,!arm64 netbsd openbsd
+// +build darwin dragonfly freebsd linux,!arm64,!riscv64 netbsd openbsd
 
 package main
 
index c9c65a6e3c1f62be51add7bc6c129cb92dabe2b3..459f0dc196874fbf53db87bf2d976f21d18c4043 100644 (file)
@@ -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 linux,arm64
+// +build linux,arm64 linux,riscv64
 
 package main
 
diff --git a/misc/cgo/testgodefs/testdata/issue48396.go b/misc/cgo/testgodefs/testdata/issue48396.go
new file mode 100644 (file)
index 0000000..d4c1924
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2021 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
+
+/*
+// from <linux/kcm.h>
+struct issue48396 {
+       int fd;
+       int bpf_fd;
+};
+*/
+import "C"
+
+type Issue48396 C.struct_issue48396
index 4a3f6a701cc0e7e1a6a348afdbf72407b64a8ca1..5c670f3d329c1acc2e2788c8024cd2233ec0aa62 100644 (file)
@@ -28,6 +28,9 @@ var v7 = S{}
 // Test that #define'd type is fully defined
 var _ = issue38649{X: 0}
 
+// Test that prefixes do not cause duplicate field names.
+var _ = Issue48396{Fd: 1, Bpf_fd: 2}
+
 func main() {
        pass := true
 
index aae34043605d340a64c6ede42b79ce1ca4575a6e..7628ffc595b7e261ad24e502d8257f1d7494f1f1 100644 (file)
@@ -25,6 +25,7 @@ var filePrefixes = []string{
        "issue37621",
        "issue38649",
        "issue39534",
+       "issue48396",
 }
 
 func TestGoDefs(t *testing.T) {
diff --git a/misc/cgo/testsanitizers/asan_test.go b/misc/cgo/testsanitizers/asan_test.go
new file mode 100644 (file)
index 0000000..dbcce2f
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2021 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 sanitizers_test
+
+import (
+       "strings"
+       "testing"
+)
+
+func TestASAN(t *testing.T) {
+       goos, err := goEnv("GOOS")
+       if err != nil {
+               t.Fatal(err)
+       }
+       goarch, err := goEnv("GOARCH")
+       if err != nil {
+               t.Fatal(err)
+       }
+       // The asan tests require support for the -asan option.
+       if !aSanSupported(goos, goarch) {
+               t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
+       }
+
+       t.Parallel()
+       requireOvercommit(t)
+       config := configure("address")
+       config.skipIfCSanitizerBroken(t)
+
+       mustRun(t, config.goCmd("build", "std"))
+
+       cases := []struct {
+               src               string
+               memoryAccessError string
+       }{
+               {src: "asan1_fail.go", memoryAccessError: "heap-use-after-free"},
+               {src: "asan2_fail.go", memoryAccessError: "heap-buffer-overflow"},
+               {src: "asan3_fail.go", memoryAccessError: "use-after-poison"},
+               {src: "asan4_fail.go", memoryAccessError: "use-after-poison"},
+               {src: "asan_useAfterReturn.go"},
+       }
+       for _, tc := range cases {
+               tc := tc
+               name := strings.TrimSuffix(tc.src, ".go")
+               t.Run(name, func(t *testing.T) {
+                       t.Parallel()
+
+                       dir := newTempDir(t)
+                       defer dir.RemoveAll(t)
+
+                       outPath := dir.Join(name)
+                       mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
+
+                       cmd := hangProneCmd(outPath)
+                       if tc.memoryAccessError != "" {
+                               out, err := cmd.CombinedOutput()
+                               if err != nil && strings.Contains(string(out), tc.memoryAccessError) {
+                                       return
+                               }
+                               t.Fatalf("%#q exited without expected memory access error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.memoryAccessError, out)
+                       }
+                       mustRun(t, cmd)
+               })
+       }
+}
index 384b6250e1ef168ae130f6d77a5e302341d1cd99..b776afa3e63b319c0452e7ff307960b999690fc3 100644 (file)
@@ -267,6 +267,9 @@ func configure(sanitizer string) *config {
                        c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan")
                }
 
+       case "address":
+               c.goFlags = append(c.goFlags, "-asan")
+
        default:
                panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
        }
@@ -344,7 +347,7 @@ func (c *config) checkCSanitizer() (skip bool, err error) {
                if os.IsNotExist(err) {
                        return true, fmt.Errorf("%#q failed to produce executable: %v", strings.Join(cmd.Args, " "), err)
                }
-               snippet := bytes.SplitN(out, []byte{'\n'}, 2)[0]
+               snippet, _, _ := bytes.Cut(out, []byte("\n"))
                return true, fmt.Errorf("%#q generated broken executable: %v\n%s", strings.Join(cmd.Args, " "), err, snippet)
        }
 
@@ -450,3 +453,14 @@ func mSanSupported(goos, goarch string) bool {
                return false
        }
 }
+
+// aSanSupported is a copy of the function cmd/internal/sys.ASanSupported,
+// because the internal pacakage can't be used here.
+func aSanSupported(goos, goarch string) bool {
+       switch goos {
+       case "linux":
+               return goarch == "amd64" || goarch == "arm64"
+       default:
+               return false
+       }
+}
diff --git a/misc/cgo/testsanitizers/testdata/asan1_fail.go b/misc/cgo/testsanitizers/testdata/asan1_fail.go
new file mode 100644 (file)
index 0000000..e60db76
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+int* test() {
+ p = (int *)malloc(2 * sizeof(int));
+ free(p);
+ return p;
+}
+*/
+import "C"
+import "fmt"
+
+func main() {
+       // C passes Go an invalid pointer.
+       a := C.test()
+       // Use after free
+       *a = 2
+       // We shouldn't get here; asan should stop us first.
+       fmt.Println(*a)
+}
diff --git a/misc/cgo/testsanitizers/testdata/asan2_fail.go b/misc/cgo/testsanitizers/testdata/asan2_fail.go
new file mode 100644 (file)
index 0000000..e35670c
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+int* f() {
+  int i;
+  p = (int *)malloc(5*sizeof(int));
+  for (i = 0; i < 5; i++) {
+    p[i] = i+10;
+  }
+  return p;
+}
+*/
+import "C"
+import (
+       "fmt"
+       "unsafe"
+)
+
+func main() {
+       a := C.f()
+       q5 := (*C.int)(unsafe.Add(unsafe.Pointer(a), 4*5))
+       // Access to C pointer out of bounds.
+       *q5 = 100
+       // We shouldn't get here; asan should stop us first.
+       fmt.Printf("q5: %d, %x\n", *q5, q5)
+}
diff --git a/misc/cgo/testsanitizers/testdata/asan3_fail.go b/misc/cgo/testsanitizers/testdata/asan3_fail.go
new file mode 100644 (file)
index 0000000..9f6d26d
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+void test(int *a) {
+       // Access Go pointer out of bounds.
+       int c = a[5];        // BOOM
+       // We shouldn't get here; asan should stop us first.
+       printf("a[5]=%d\n", c);
+}
+*/
+import "C"
+
+func main() {
+       cIntSlice := []C.int{200, 201, 203, 203, 204}
+       C.test(&cIntSlice[0])
+}
diff --git a/misc/cgo/testsanitizers/testdata/asan4_fail.go b/misc/cgo/testsanitizers/testdata/asan4_fail.go
new file mode 100644 (file)
index 0000000..1209845
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+#include <stdlib.h>
+#include <stdio.h>
+
+void test(int* a) {
+       // Access Go pointer out of bounds.
+       a[3] = 300;          // BOOM
+       // We shouldn't get here; asan should stop us first.
+       printf("a[3]=%d\n", a[3]);
+}*/
+import "C"
+
+func main() {
+       var cIntArray [2]C.int
+       C.test(&cIntArray[0]) // cIntArray is moved to heap.
+}
diff --git a/misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go b/misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go
new file mode 100644 (file)
index 0000000..3d3d5a6
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2021 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
+
+// The -fsanitize=address option of C compier can detect stack-use-after-return bugs.
+// In the following program, the local variable 'local' was moved to heap by the Go
+// compiler because foo() is returning the reference to 'local', and return stack of
+// foo() will be invalid. Thus for main() to use the reference to 'local', the 'local'
+// must be available even after foo() has finished. Therefore, Go has no such issue.
+
+import "fmt"
+
+var ptr *int
+
+func main() {
+       foo()
+       fmt.Printf("ptr=%x, %v", *ptr, ptr)
+}
+
+func foo() {
+       var local int
+       local = 1
+       ptr = &local // local is moved to heap.
+}
index e77f84891543f584ccb5bd2aa538f0e6237e9d17..672811fe0e333b7031b7fcd41c6e4b206c882cad 100644 (file)
@@ -1033,7 +1033,7 @@ func TestGlobal(t *testing.T) {
 // Run a test using -linkshared of an installed shared package.
 // Issue 26400.
 func TestTestInstalledShared(t *testing.T) {
-       goCmd(nil, "test", "-linkshared", "-test.short", "sync/atomic")
+       goCmd(t, "test", "-linkshared", "-test.short", "sync/atomic")
 }
 
 // Test generated pointer method with -linkshared.
@@ -1045,8 +1045,8 @@ func TestGeneratedMethod(t *testing.T) {
 // Test use of shared library struct with generated hash function.
 // Issue 30768.
 func TestGeneratedHash(t *testing.T) {
-       goCmd(nil, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
-       goCmd(nil, "test", "-linkshared", "./issue30768")
+       goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
+       goCmd(t, "test", "-linkshared", "./issue30768")
 }
 
 // Test that packages can be added not in dependency order (here a depends on b, and a adds
@@ -1070,3 +1070,11 @@ func TestIssue44031(t *testing.T) {
        goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b")
        goCmd(t, "run", "-linkshared", "./issue44031/main")
 }
+
+// Test that we use a variable from shared libraries (which implement an
+// interface in shared libraries.). A weak reference is used in the itab
+// in main process. It can cause unreacheble panic. See issue 47873.
+func TestIssue47873(t *testing.T) {
+       goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue47837/a")
+       goCmd(t, "run", "-linkshared", "./issue47837/main")
+}
diff --git a/misc/cgo/testshared/testdata/issue47837/a/a.go b/misc/cgo/testshared/testdata/issue47837/a/a.go
new file mode 100644 (file)
index 0000000..68588ed
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2021 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
+
+type A interface {
+       M()
+}
+
+//go:noinline
+func TheFuncWithArgA(a A) {
+       a.M()
+}
+
+type ImplA struct{}
+
+//go:noinline
+func (A *ImplA) M() {}
diff --git a/misc/cgo/testshared/testdata/issue47837/main/main.go b/misc/cgo/testshared/testdata/issue47837/main/main.go
new file mode 100644 (file)
index 0000000..77c6f34
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2021 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 (
+       "testshared/issue47837/a"
+)
+
+func main() {
+       var vara a.ImplA
+       a.TheFuncWithArgA(&vara)
+}
index fc9f1133a4608ae4ca0143f4a8fc4414866d9400..712a051f4573c1fb521d67cb8e96be0008eb7c89 100644 (file)
@@ -8,4 +8,4 @@
 // directory.)
 module misc
 
-go 1.12
+go 1.18
index 9e63717d9214d6eb98726bb21d9f2c993fded2ac..34a734cda780e3112fd4a15c4befca692a3ec0a2 100644 (file)
@@ -148,9 +148,8 @@ func runOnDevice(appdir string) error {
        // Device IDs as listed with ios-deploy -c.
        deviceID = os.Getenv("GOIOS_DEVICE_ID")
 
-       parts := strings.SplitN(appID, ".", 2)
-       if len(parts) == 2 {
-               bundleID = parts[1]
+       if _, id, ok := strings.Cut(appID, "."); ok {
+               bundleID = id
        }
 
        if err := signApp(appdir); err != nil {
@@ -291,11 +290,10 @@ func findDevImage() (string, error) {
        var iosVer, buildVer string
        lines := bytes.Split(out, []byte("\n"))
        for _, line := range lines {
-               spl := bytes.SplitN(line, []byte(": "), 2)
-               if len(spl) != 2 {
+               key, val, ok := strings.Cut(string(line), ": ")
+               if !ok {
                        continue
                }
-               key, val := string(spl[0]), string(spl[1])
                switch key {
                case "ProductVersion":
                        iosVer = val
index 570b430da4f1cbc76f14250822406e5449978757..efe400965b2e06c7bdb9a02b5fd7d38d72cf07e6 100644 (file)
@@ -81,10 +81,8 @@ func crawl(url string, sourceURL string) {
        }
        mu.Lock()
        defer mu.Unlock()
-       var frag string
-       if i := strings.Index(url, "#"); i >= 0 {
-               frag = url[i+1:]
-               url = url[:i]
+       if u, frag, ok := strings.Cut(url, "#"); ok {
+               url = u
                if frag != "" {
                        uf := urlFrag{url, frag}
                        neededFrags[uf] = append(neededFrags[uf], sourceURL)
index b700722dfe97e57e423e1d51f50c24d778d5fc5f..fcbd0e4fc8ce0e4eb3a753289b0a8283327b3bdd 100755 (executable)
@@ -11,4 +11,4 @@ while [ -h "$SOURCE" ]; do
 done
 DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
 
-exec node "$DIR/wasm_exec.js" "$@"
+exec node "$DIR/wasm_exec_node.js" "$@"
index 231185a123ed12f8bc6b2ad7a56a00e3615a656a..9ce6a20c3ffa82debd6853a72f02c316ccfb642d 100644 (file)
@@ -2,47 +2,18 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-(() => {
-       // Map multiple JavaScript environments to a single common API,
-       // preferring web standards over Node.js API.
-       //
-       // Environments considered:
-       // - Browsers
-       // - Node.js
-       // - Electron
-       // - Parcel
-       // - Webpack
-
-       if (typeof global !== "undefined") {
-               // global already exists
-       } else if (typeof window !== "undefined") {
-               window.global = window;
-       } else if (typeof self !== "undefined") {
-               self.global = self;
-       } else {
-               throw new Error("cannot export Go (neither global, window nor self is defined)");
-       }
-
-       if (!global.require && typeof require !== "undefined") {
-               global.require = require;
-       }
-
-       if (!global.fs && global.require) {
-               const fs = require("fs");
-               if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
-                       global.fs = fs;
-               }
-       }
+"use strict";
 
+(() => {
        const enosys = () => {
                const err = new Error("not implemented");
                err.code = "ENOSYS";
                return err;
        };
 
-       if (!global.fs) {
+       if (!globalThis.fs) {
                let outputBuf = "";
-               global.fs = {
+               globalThis.fs = {
                        constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
                        writeSync(fd, buf) {
                                outputBuf += decoder.decode(buf);
@@ -87,8 +58,8 @@
                };
        }
 
-       if (!global.process) {
-               global.process = {
+       if (!globalThis.process) {
+               globalThis.process = {
                        getuid() { return -1; },
                        getgid() { return -1; },
                        geteuid() { return -1; },
                }
        }
 
-       if (!global.crypto && global.require) {
-               const nodeCrypto = require("crypto");
-               global.crypto = {
-                       getRandomValues(b) {
-                               nodeCrypto.randomFillSync(b);
-                       },
-               };
-       }
-       if (!global.crypto) {
-               throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
+       if (!globalThis.crypto) {
+               throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
        }
 
-       if (!global.performance) {
-               global.performance = {
-                       now() {
-                               const [sec, nsec] = process.hrtime();
-                               return sec * 1000 + nsec / 1000000;
-                       },
-               };
+       if (!globalThis.performance) {
+               throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
        }
 
-       if (!global.TextEncoder && global.require) {
-               global.TextEncoder = require("util").TextEncoder;
-       }
-       if (!global.TextEncoder) {
-               throw new Error("global.TextEncoder is not available, polyfill required");
+       if (!globalThis.TextEncoder) {
+               throw new Error("globalThis.TextEncoder is not available, polyfill required");
        }
 
-       if (!global.TextDecoder && global.require) {
-               global.TextDecoder = require("util").TextDecoder;
-       }
-       if (!global.TextDecoder) {
-               throw new Error("global.TextDecoder is not available, polyfill required");
+       if (!globalThis.TextDecoder) {
+               throw new Error("globalThis.TextDecoder is not available, polyfill required");
        }
 
-       // End of polyfills for common API.
-
        const encoder = new TextEncoder("utf-8");
        const decoder = new TextDecoder("utf-8");
 
-       global.Go = class {
+       globalThis.Go = class {
                constructor() {
                        this.argv = ["js"];
                        this.env = {};
                                null,
                                true,
                                false,
-                               global,
+                               globalThis,
                                this,
                        ];
                        this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
                                [null, 2],
                                [true, 3],
                                [false, 4],
-                               [global, 5],
+                               [globalThis, 5],
                                [this, 6],
                        ]);
                        this._idPool = [];   // unused ids that have been garbage collected
                                offset += 8;
                        });
 
+                       // The linker guarantees global data starts from at least wasmMinDataAddr.
+                       // Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
+                       const wasmMinDataAddr = 4096 + 8192;
+                       if (offset >= wasmMinDataAddr) {
+                               throw new Error("total length of command line and environment variables exceeds limit");
+                       }
+
                        this._inst.exports.run(argc, argv);
                        if (this.exited) {
                                this._resolveExitPromise();
                        };
                }
        }
-
-       if (
-               typeof module !== "undefined" &&
-               global.require &&
-               global.require.main === module &&
-               global.process &&
-               global.process.versions &&
-               !global.process.versions.electron
-       ) {
-               if (process.argv.length < 3) {
-                       console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
-                       process.exit(1);
-               }
-
-               const go = new Go();
-               go.argv = process.argv.slice(2);
-               go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
-               go.exit = process.exit;
-               WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
-                       process.on("exit", (code) => { // Node.js exits if no event handler is pending
-                               if (code === 0 && !go.exited) {
-                                       // deadlock, make Go print error and stack traces
-                                       go._pendingEvent = { id: 0 };
-                                       go._resume();
-                               }
-                       });
-                       return go.run(result.instance);
-               }).catch((err) => {
-                       console.error(err);
-                       process.exit(1);
-               });
-       }
 })();
diff --git a/misc/wasm/wasm_exec_node.js b/misc/wasm/wasm_exec_node.js
new file mode 100644 (file)
index 0000000..f9200ca
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2021 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.
+
+"use strict";
+
+if (process.argv.length < 3) {
+       console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
+       process.exit(1);
+}
+
+globalThis.require = require;
+globalThis.fs = require("fs");
+globalThis.TextEncoder = require("util").TextEncoder;
+globalThis.TextDecoder = require("util").TextDecoder;
+
+globalThis.performance = {
+       now() {
+               const [sec, nsec] = process.hrtime();
+               return sec * 1000 + nsec / 1000000;
+       },
+};
+
+const crypto = require("crypto");
+globalThis.crypto = {
+       getRandomValues(b) {
+               crypto.randomFillSync(b);
+       },
+};
+
+require("./wasm_exec");
+
+const go = new Go();
+go.argv = process.argv.slice(2);
+go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
+go.exit = process.exit;
+WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
+       process.on("exit", (code) => { // Node.js exits if no event handler is pending
+               if (code === 0 && !go.exited) {
+                       // deadlock, make Go print error and stack traces
+                       go._pendingEvent = { id: 0 };
+                       go._resume();
+               }
+       });
+       return go.run(result.instance);
+}).catch((err) => {
+       console.error(err);
+       process.exit(1);
+});
index c667cfc8720b5b9db1a72184bd9fb42461916ec0..595de64725ae6ba09eef3c301d048544b37a9734 100644 (file)
@@ -316,10 +316,10 @@ func invertSparseEntries(src []sparseEntry, size int64) []sparseEntry {
 // fileState tracks the number of logical (includes sparse holes) and physical
 // (actual in tar archive) bytes remaining for the current file.
 //
-// Invariant: LogicalRemaining >= PhysicalRemaining
+// Invariant: logicalRemaining >= physicalRemaining
 type fileState interface {
-       LogicalRemaining() int64
-       PhysicalRemaining() int64
+       logicalRemaining() int64
+       physicalRemaining() int64
 }
 
 // allowedFormats determines which formats can be used.
@@ -413,22 +413,22 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
 
        // Check basic fields.
        var blk block
-       v7 := blk.V7()
-       ustar := blk.USTAR()
-       gnu := blk.GNU()
-       verifyString(h.Name, len(v7.Name()), "Name", paxPath)
-       verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath)
-       verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname)
-       verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname)
-       verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone)
-       verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid)
-       verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid)
-       verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize)
-       verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone)
-       verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone)
-       verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime)
-       verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime)
-       verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime)
+       v7 := blk.toV7()
+       ustar := blk.toUSTAR()
+       gnu := blk.toGNU()
+       verifyString(h.Name, len(v7.name()), "Name", paxPath)
+       verifyString(h.Linkname, len(v7.linkName()), "Linkname", paxLinkpath)
+       verifyString(h.Uname, len(ustar.userName()), "Uname", paxUname)
+       verifyString(h.Gname, len(ustar.groupName()), "Gname", paxGname)
+       verifyNumeric(h.Mode, len(v7.mode()), "Mode", paxNone)
+       verifyNumeric(int64(h.Uid), len(v7.uid()), "Uid", paxUid)
+       verifyNumeric(int64(h.Gid), len(v7.gid()), "Gid", paxGid)
+       verifyNumeric(h.Size, len(v7.size()), "Size", paxSize)
+       verifyNumeric(h.Devmajor, len(ustar.devMajor()), "Devmajor", paxNone)
+       verifyNumeric(h.Devminor, len(ustar.devMinor()), "Devminor", paxNone)
+       verifyTime(h.ModTime, len(v7.modTime()), "ModTime", paxMtime)
+       verifyTime(h.AccessTime, len(gnu.accessTime()), "AccessTime", paxAtime)
+       verifyTime(h.ChangeTime, len(gnu.changeTime()), "ChangeTime", paxCtime)
 
        // Check for header-only types.
        var whyOnlyPAX, whyOnlyGNU string
index cfe24a5e1d339540c26feb898bfa6ce09d1813d8..21b9d9d4dbc628f7f18a370d7bb10f597b0efc70 100644 (file)
@@ -156,28 +156,28 @@ var zeroBlock block
 type block [blockSize]byte
 
 // Convert block to any number of formats.
-func (b *block) V7() *headerV7       { return (*headerV7)(b) }
-func (b *block) GNU() *headerGNU     { return (*headerGNU)(b) }
-func (b *block) STAR() *headerSTAR   { return (*headerSTAR)(b) }
-func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
-func (b *block) Sparse() sparseArray { return sparseArray(b[:]) }
+func (b *block) toV7() *headerV7       { return (*headerV7)(b) }
+func (b *block) toGNU() *headerGNU     { return (*headerGNU)(b) }
+func (b *block) toSTAR() *headerSTAR   { return (*headerSTAR)(b) }
+func (b *block) toUSTAR() *headerUSTAR { return (*headerUSTAR)(b) }
+func (b *block) toSparse() sparseArray { return sparseArray(b[:]) }
 
 // GetFormat checks that the block is a valid tar header based on the checksum.
 // It then attempts to guess the specific format based on magic values.
 // If the checksum fails, then FormatUnknown is returned.
-func (b *block) GetFormat() Format {
+func (b *block) getFormat() Format {
        // Verify checksum.
        var p parser
-       value := p.parseOctal(b.V7().Chksum())
-       chksum1, chksum2 := b.ComputeChecksum()
+       value := p.parseOctal(b.toV7().chksum())
+       chksum1, chksum2 := b.computeChecksum()
        if p.err != nil || (value != chksum1 && value != chksum2) {
                return FormatUnknown
        }
 
        // Guess the magic values.
-       magic := string(b.USTAR().Magic())
-       version := string(b.USTAR().Version())
-       trailer := string(b.STAR().Trailer())
+       magic := string(b.toUSTAR().magic())
+       version := string(b.toUSTAR().version())
+       trailer := string(b.toSTAR().trailer())
        switch {
        case magic == magicUSTAR && trailer == trailerSTAR:
                return formatSTAR
@@ -190,23 +190,23 @@ func (b *block) GetFormat() Format {
        }
 }
 
-// SetFormat writes the magic values necessary for specified format
+// setFormat writes the magic values necessary for specified format
 // and then updates the checksum accordingly.
-func (b *block) SetFormat(format Format) {
+func (b *block) setFormat(format Format) {
        // Set the magic values.
        switch {
        case format.has(formatV7):
                // Do nothing.
        case format.has(FormatGNU):
-               copy(b.GNU().Magic(), magicGNU)
-               copy(b.GNU().Version(), versionGNU)
+               copy(b.toGNU().magic(), magicGNU)
+               copy(b.toGNU().version(), versionGNU)
        case format.has(formatSTAR):
-               copy(b.STAR().Magic(), magicUSTAR)
-               copy(b.STAR().Version(), versionUSTAR)
-               copy(b.STAR().Trailer(), trailerSTAR)
+               copy(b.toSTAR().magic(), magicUSTAR)
+               copy(b.toSTAR().version(), versionUSTAR)
+               copy(b.toSTAR().trailer(), trailerSTAR)
        case format.has(FormatUSTAR | FormatPAX):
-               copy(b.USTAR().Magic(), magicUSTAR)
-               copy(b.USTAR().Version(), versionUSTAR)
+               copy(b.toUSTAR().magic(), magicUSTAR)
+               copy(b.toUSTAR().version(), versionUSTAR)
        default:
                panic("invalid format")
        }
@@ -214,17 +214,17 @@ func (b *block) SetFormat(format Format) {
        // Update checksum.
        // This field is special in that it is terminated by a NULL then space.
        var f formatter
-       field := b.V7().Chksum()
-       chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
+       field := b.toV7().chksum()
+       chksum, _ := b.computeChecksum() // Possible values are 256..128776
        f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
        field[7] = ' '
 }
 
-// ComputeChecksum computes the checksum for the header block.
+// computeChecksum computes the checksum for the header block.
 // POSIX specifies a sum of the unsigned byte values, but the Sun tar used
 // signed byte values.
 // We compute and return both.
-func (b *block) ComputeChecksum() (unsigned, signed int64) {
+func (b *block) computeChecksum() (unsigned, signed int64) {
        for i, c := range b {
                if 148 <= i && i < 156 {
                        c = ' ' // Treat the checksum field itself as all spaces.
@@ -236,68 +236,68 @@ func (b *block) ComputeChecksum() (unsigned, signed int64) {
 }
 
 // Reset clears the block with all zeros.
-func (b *block) Reset() {
+func (b *block) reset() {
        *b = block{}
 }
 
 type headerV7 [blockSize]byte
 
-func (h *headerV7) Name() []byte     { return h[000:][:100] }
-func (h *headerV7) Mode() []byte     { return h[100:][:8] }
-func (h *headerV7) UID() []byte      { return h[108:][:8] }
-func (h *headerV7) GID() []byte      { return h[116:][:8] }
-func (h *headerV7) Size() []byte     { return h[124:][:12] }
-func (h *headerV7) ModTime() []byte  { return h[136:][:12] }
-func (h *headerV7) Chksum() []byte   { return h[148:][:8] }
-func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
-func (h *headerV7) LinkName() []byte { return h[157:][:100] }
+func (h *headerV7) name() []byte     { return h[000:][:100] }
+func (h *headerV7) mode() []byte     { return h[100:][:8] }
+func (h *headerV7) uid() []byte      { return h[108:][:8] }
+func (h *headerV7) gid() []byte      { return h[116:][:8] }
+func (h *headerV7) size() []byte     { return h[124:][:12] }
+func (h *headerV7) modTime() []byte  { return h[136:][:12] }
+func (h *headerV7) chksum() []byte   { return h[148:][:8] }
+func (h *headerV7) typeFlag() []byte { return h[156:][:1] }
+func (h *headerV7) linkName() []byte { return h[157:][:100] }
 
 type headerGNU [blockSize]byte
 
-func (h *headerGNU) V7() *headerV7       { return (*headerV7)(h) }
-func (h *headerGNU) Magic() []byte       { return h[257:][:6] }
-func (h *headerGNU) Version() []byte     { return h[263:][:2] }
-func (h *headerGNU) UserName() []byte    { return h[265:][:32] }
-func (h *headerGNU) GroupName() []byte   { return h[297:][:32] }
-func (h *headerGNU) DevMajor() []byte    { return h[329:][:8] }
-func (h *headerGNU) DevMinor() []byte    { return h[337:][:8] }
-func (h *headerGNU) AccessTime() []byte  { return h[345:][:12] }
-func (h *headerGNU) ChangeTime() []byte  { return h[357:][:12] }
-func (h *headerGNU) Sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
-func (h *headerGNU) RealSize() []byte    { return h[483:][:12] }
+func (h *headerGNU) v7() *headerV7       { return (*headerV7)(h) }
+func (h *headerGNU) magic() []byte       { return h[257:][:6] }
+func (h *headerGNU) version() []byte     { return h[263:][:2] }
+func (h *headerGNU) userName() []byte    { return h[265:][:32] }
+func (h *headerGNU) groupName() []byte   { return h[297:][:32] }
+func (h *headerGNU) devMajor() []byte    { return h[329:][:8] }
+func (h *headerGNU) devMinor() []byte    { return h[337:][:8] }
+func (h *headerGNU) accessTime() []byte  { return h[345:][:12] }
+func (h *headerGNU) changeTime() []byte  { return h[357:][:12] }
+func (h *headerGNU) sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
+func (h *headerGNU) realSize() []byte    { return h[483:][:12] }
 
 type headerSTAR [blockSize]byte
 
-func (h *headerSTAR) V7() *headerV7      { return (*headerV7)(h) }
-func (h *headerSTAR) Magic() []byte      { return h[257:][:6] }
-func (h *headerSTAR) Version() []byte    { return h[263:][:2] }
-func (h *headerSTAR) UserName() []byte   { return h[265:][:32] }
-func (h *headerSTAR) GroupName() []byte  { return h[297:][:32] }
-func (h *headerSTAR) DevMajor() []byte   { return h[329:][:8] }
-func (h *headerSTAR) DevMinor() []byte   { return h[337:][:8] }
-func (h *headerSTAR) Prefix() []byte     { return h[345:][:131] }
-func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
-func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
-func (h *headerSTAR) Trailer() []byte    { return h[508:][:4] }
+func (h *headerSTAR) v7() *headerV7      { return (*headerV7)(h) }
+func (h *headerSTAR) magic() []byte      { return h[257:][:6] }
+func (h *headerSTAR) version() []byte    { return h[263:][:2] }
+func (h *headerSTAR) userName() []byte   { return h[265:][:32] }
+func (h *headerSTAR) groupName() []byte  { return h[297:][:32] }
+func (h *headerSTAR) devMajor() []byte   { return h[329:][:8] }
+func (h *headerSTAR) devMinor() []byte   { return h[337:][:8] }
+func (h *headerSTAR) prefix() []byte     { return h[345:][:131] }
+func (h *headerSTAR) accessTime() []byte { return h[476:][:12] }
+func (h *headerSTAR) changeTime() []byte { return h[488:][:12] }
+func (h *headerSTAR) trailer() []byte    { return h[508:][:4] }
 
 type headerUSTAR [blockSize]byte
 
-func (h *headerUSTAR) V7() *headerV7     { return (*headerV7)(h) }
-func (h *headerUSTAR) Magic() []byte     { return h[257:][:6] }
-func (h *headerUSTAR) Version() []byte   { return h[263:][:2] }
-func (h *headerUSTAR) UserName() []byte  { return h[265:][:32] }
-func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
-func (h *headerUSTAR) DevMajor() []byte  { return h[329:][:8] }
-func (h *headerUSTAR) DevMinor() []byte  { return h[337:][:8] }
-func (h *headerUSTAR) Prefix() []byte    { return h[345:][:155] }
+func (h *headerUSTAR) v7() *headerV7     { return (*headerV7)(h) }
+func (h *headerUSTAR) magic() []byte     { return h[257:][:6] }
+func (h *headerUSTAR) version() []byte   { return h[263:][:2] }
+func (h *headerUSTAR) userName() []byte  { return h[265:][:32] }
+func (h *headerUSTAR) groupName() []byte { return h[297:][:32] }
+func (h *headerUSTAR) devMajor() []byte  { return h[329:][:8] }
+func (h *headerUSTAR) devMinor() []byte  { return h[337:][:8] }
+func (h *headerUSTAR) prefix() []byte    { return h[345:][:155] }
 
 type sparseArray []byte
 
-func (s sparseArray) Entry(i int) sparseElem { return sparseElem(s[i*24:]) }
-func (s sparseArray) IsExtended() []byte     { return s[24*s.MaxEntries():][:1] }
-func (s sparseArray) MaxEntries() int        { return len(s) / 24 }
+func (s sparseArray) entry(i int) sparseElem { return sparseElem(s[i*24:]) }
+func (s sparseArray) isExtended() []byte     { return s[24*s.maxEntries():][:1] }
+func (s sparseArray) maxEntries() int        { return len(s) / 24 }
 
 type sparseElem []byte
 
-func (s sparseElem) Offset() []byte { return s[00:][:12] }
-func (s sparseElem) Length() []byte { return s[12:][:12] }
+func (s sparseElem) offset() []byte { return s[00:][:12] }
+func (s sparseElem) length() []byte { return s[12:][:12] }
index 1b1d5b46891b6bc972ed6bd9bfb1efc63eef1433..4b11909bc9527d37af905cba8c33f495b83893ca 100644 (file)
@@ -65,7 +65,7 @@ func (tr *Reader) next() (*Header, error) {
        format := FormatUSTAR | FormatPAX | FormatGNU
        for {
                // Discard the remainder of the file and any padding.
-               if err := discard(tr.r, tr.curr.PhysicalRemaining()); err != nil {
+               if err := discard(tr.r, tr.curr.physicalRemaining()); err != nil {
                        return nil, err
                }
                if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil {
@@ -355,7 +355,7 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
        }
 
        // Verify the header matches a known format.
-       format := tr.blk.GetFormat()
+       format := tr.blk.getFormat()
        if format == FormatUnknown {
                return nil, nil, ErrHeader
        }
@@ -364,30 +364,30 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
        hdr := new(Header)
 
        // Unpack the V7 header.
-       v7 := tr.blk.V7()
-       hdr.Typeflag = v7.TypeFlag()[0]
-       hdr.Name = p.parseString(v7.Name())
-       hdr.Linkname = p.parseString(v7.LinkName())
-       hdr.Size = p.parseNumeric(v7.Size())
-       hdr.Mode = p.parseNumeric(v7.Mode())
-       hdr.Uid = int(p.parseNumeric(v7.UID()))
-       hdr.Gid = int(p.parseNumeric(v7.GID()))
-       hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
+       v7 := tr.blk.toV7()
+       hdr.Typeflag = v7.typeFlag()[0]
+       hdr.Name = p.parseString(v7.name())
+       hdr.Linkname = p.parseString(v7.linkName())
+       hdr.Size = p.parseNumeric(v7.size())
+       hdr.Mode = p.parseNumeric(v7.mode())
+       hdr.Uid = int(p.parseNumeric(v7.uid()))
+       hdr.Gid = int(p.parseNumeric(v7.gid()))
+       hdr.ModTime = time.Unix(p.parseNumeric(v7.modTime()), 0)
 
        // Unpack format specific fields.
        if format > formatV7 {
-               ustar := tr.blk.USTAR()
-               hdr.Uname = p.parseString(ustar.UserName())
-               hdr.Gname = p.parseString(ustar.GroupName())
-               hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
-               hdr.Devminor = p.parseNumeric(ustar.DevMinor())
+               ustar := tr.blk.toUSTAR()
+               hdr.Uname = p.parseString(ustar.userName())
+               hdr.Gname = p.parseString(ustar.groupName())
+               hdr.Devmajor = p.parseNumeric(ustar.devMajor())
+               hdr.Devminor = p.parseNumeric(ustar.devMinor())
 
                var prefix string
                switch {
                case format.has(FormatUSTAR | FormatPAX):
                        hdr.Format = format
-                       ustar := tr.blk.USTAR()
-                       prefix = p.parseString(ustar.Prefix())
+                       ustar := tr.blk.toUSTAR()
+                       prefix = p.parseString(ustar.prefix())
 
                        // For Format detection, check if block is properly formatted since
                        // the parser is more liberal than what USTAR actually permits.
@@ -396,23 +396,23 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
                                hdr.Format = FormatUnknown // Non-ASCII characters in block.
                        }
                        nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
-                       if !(nul(v7.Size()) && nul(v7.Mode()) && nul(v7.UID()) && nul(v7.GID()) &&
-                               nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) {
+                       if !(nul(v7.size()) && nul(v7.mode()) && nul(v7.uid()) && nul(v7.gid()) &&
+                               nul(v7.modTime()) && nul(ustar.devMajor()) && nul(ustar.devMinor())) {
                                hdr.Format = FormatUnknown // Numeric fields must end in NUL
                        }
                case format.has(formatSTAR):
-                       star := tr.blk.STAR()
-                       prefix = p.parseString(star.Prefix())
-                       hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
-                       hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
+                       star := tr.blk.toSTAR()
+                       prefix = p.parseString(star.prefix())
+                       hdr.AccessTime = time.Unix(p.parseNumeric(star.accessTime()), 0)
+                       hdr.ChangeTime = time.Unix(p.parseNumeric(star.changeTime()), 0)
                case format.has(FormatGNU):
                        hdr.Format = format
                        var p2 parser
-                       gnu := tr.blk.GNU()
-                       if b := gnu.AccessTime(); b[0] != 0 {
+                       gnu := tr.blk.toGNU()
+                       if b := gnu.accessTime(); b[0] != 0 {
                                hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
                        }
-                       if b := gnu.ChangeTime(); b[0] != 0 {
+                       if b := gnu.changeTime(); b[0] != 0 {
                                hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
                        }
 
@@ -439,8 +439,8 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
                        // See https://golang.org/issues/21005
                        if p2.err != nil {
                                hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
-                               ustar := tr.blk.USTAR()
-                               if s := p.parseString(ustar.Prefix()); isASCII(s) {
+                               ustar := tr.blk.toUSTAR()
+                               if s := p.parseString(ustar.prefix()); isASCII(s) {
                                        prefix = s
                                }
                                hdr.Format = FormatUnknown // Buggy file is not GNU
@@ -465,38 +465,38 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
        // Make sure that the input format is GNU.
        // Unfortunately, the STAR format also has a sparse header format that uses
        // the same type flag but has a completely different layout.
-       if blk.GetFormat() != FormatGNU {
+       if blk.getFormat() != FormatGNU {
                return nil, ErrHeader
        }
        hdr.Format.mayOnlyBe(FormatGNU)
 
        var p parser
-       hdr.Size = p.parseNumeric(blk.GNU().RealSize())
+       hdr.Size = p.parseNumeric(blk.toGNU().realSize())
        if p.err != nil {
                return nil, p.err
        }
-       s := blk.GNU().Sparse()
-       spd := make(sparseDatas, 0, s.MaxEntries())
+       s := blk.toGNU().sparse()
+       spd := make(sparseDatas, 0, s.maxEntries())
        for {
-               for i := 0; i < s.MaxEntries(); i++ {
+               for i := 0; i < s.maxEntries(); i++ {
                        // This termination condition is identical to GNU and BSD tar.
-                       if s.Entry(i).Offset()[0] == 0x00 {
+                       if s.entry(i).offset()[0] == 0x00 {
                                break // Don't return, need to process extended headers (even if empty)
                        }
-                       offset := p.parseNumeric(s.Entry(i).Offset())
-                       length := p.parseNumeric(s.Entry(i).Length())
+                       offset := p.parseNumeric(s.entry(i).offset())
+                       length := p.parseNumeric(s.entry(i).length())
                        if p.err != nil {
                                return nil, p.err
                        }
                        spd = append(spd, sparseEntry{Offset: offset, Length: length})
                }
 
-               if s.IsExtended()[0] > 0 {
+               if s.isExtended()[0] > 0 {
                        // There are more entries. Read an extension header and parse its entries.
                        if _, err := mustReadFull(tr.r, blk[:]); err != nil {
                                return nil, err
                        }
-                       s = blk.Sparse()
+                       s = blk.toSparse()
                        continue
                }
                return spd, nil // Done
@@ -678,11 +678,13 @@ func (fr *regFileReader) WriteTo(w io.Writer) (int64, error) {
        return io.Copy(w, struct{ io.Reader }{fr})
 }
 
-func (fr regFileReader) LogicalRemaining() int64 {
+// logicalRemaining implements fileState.logicalRemaining.
+func (fr regFileReader) logicalRemaining() int64 {
        return fr.nb
 }
 
-func (fr regFileReader) PhysicalRemaining() int64 {
+// logicalRemaining implements fileState.physicalRemaining.
+func (fr regFileReader) physicalRemaining() int64 {
        return fr.nb
 }
 
@@ -694,9 +696,9 @@ type sparseFileReader struct {
 }
 
 func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
-       finished := int64(len(b)) >= sr.LogicalRemaining()
+       finished := int64(len(b)) >= sr.logicalRemaining()
        if finished {
-               b = b[:sr.LogicalRemaining()]
+               b = b[:sr.logicalRemaining()]
        }
 
        b0 := b
@@ -724,7 +726,7 @@ func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
                return n, errMissData // Less data in dense file than sparse file
        case err != nil:
                return n, err
-       case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
+       case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
                return n, errUnrefData // More data in dense file than sparse file
        case finished:
                return n, io.EOF
@@ -746,7 +748,7 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
 
        var writeLastByte bool
        pos0 := sr.pos
-       for sr.LogicalRemaining() > 0 && !writeLastByte && err == nil {
+       for sr.logicalRemaining() > 0 && !writeLastByte && err == nil {
                var nf int64 // Size of fragment
                holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
                if sr.pos < holeStart { // In a data fragment
@@ -754,7 +756,7 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
                        nf, err = io.CopyN(ws, sr.fr, nf)
                } else { // In a hole fragment
                        nf = holeEnd - sr.pos
-                       if sr.PhysicalRemaining() == 0 {
+                       if sr.physicalRemaining() == 0 {
                                writeLastByte = true
                                nf--
                        }
@@ -779,18 +781,18 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
                return n, errMissData // Less data in dense file than sparse file
        case err != nil:
                return n, err
-       case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
+       case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
                return n, errUnrefData // More data in dense file than sparse file
        default:
                return n, nil
        }
 }
 
-func (sr sparseFileReader) LogicalRemaining() int64 {
+func (sr sparseFileReader) logicalRemaining() int64 {
        return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
 }
-func (sr sparseFileReader) PhysicalRemaining() int64 {
-       return sr.fr.PhysicalRemaining()
+func (sr sparseFileReader) physicalRemaining() int64 {
+       return sr.fr.physicalRemaining()
 }
 
 type zeroReader struct{}
index 789ddc1bc0345ae95058f6fafa7311b54c5f6c25..c31a847ec3e9db714ff59b6029f70930dac90e78 100644 (file)
@@ -1021,12 +1021,12 @@ func TestParsePAX(t *testing.T) {
 
 func TestReadOldGNUSparseMap(t *testing.T) {
        populateSparseMap := func(sa sparseArray, sps []string) []string {
-               for i := 0; len(sps) > 0 && i < sa.MaxEntries(); i++ {
-                       copy(sa.Entry(i), sps[0])
+               for i := 0; len(sps) > 0 && i < sa.maxEntries(); i++ {
+                       copy(sa.entry(i), sps[0])
                        sps = sps[1:]
                }
                if len(sps) > 0 {
-                       copy(sa.IsExtended(), "\x80")
+                       copy(sa.isExtended(), "\x80")
                }
                return sps
        }
@@ -1034,19 +1034,19 @@ func TestReadOldGNUSparseMap(t *testing.T) {
        makeInput := func(format Format, size string, sps ...string) (out []byte) {
                // Write the initial GNU header.
                var blk block
-               gnu := blk.GNU()
-               sparse := gnu.Sparse()
-               copy(gnu.RealSize(), size)
+               gnu := blk.toGNU()
+               sparse := gnu.sparse()
+               copy(gnu.realSize(), size)
                sps = populateSparseMap(sparse, sps)
                if format != FormatUnknown {
-                       blk.SetFormat(format)
+                       blk.setFormat(format)
                }
                out = append(out, blk[:]...)
 
                // Write extended sparse blocks.
                for len(sps) > 0 {
                        var blk block
-                       sps = populateSparseMap(blk.Sparse(), sps)
+                       sps = populateSparseMap(blk.toSparse(), sps)
                        out = append(out, blk[:]...)
                }
                return out
@@ -1359,7 +1359,7 @@ func TestFileReader(t *testing.T) {
                        wantCnt int64
                        wantErr error
                }
-               testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
+               testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
                        wantLCnt int64
                        wantPCnt int64
                }
@@ -1596,11 +1596,11 @@ func TestFileReader(t *testing.T) {
                                        t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
                                }
                        case testRemaining:
-                               if got := fr.LogicalRemaining(); got != tf.wantLCnt {
-                                       t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
+                               if got := fr.logicalRemaining(); got != tf.wantLCnt {
+                                       t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
                                }
-                               if got := fr.PhysicalRemaining(); got != tf.wantPCnt {
-                                       t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
+                               if got := fr.physicalRemaining(); got != tf.wantPCnt {
+                                       t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
                                }
                        default:
                                t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
index 4fdf2a04b3df40d6f1d59c119faa9acb5029f317..c4c2480feeb0c4db635a9b48d56bf2ef9cb910b7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || linux || dragonfly || openbsd || solaris
-// +build aix linux dragonfly openbsd solaris
 
 package tar
 
index 5a9a35cbb4e22d9df42f307843730032d7e0b392..f76d6be220f87f89c55e553e88b5e4737484001f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || freebsd || netbsd
-// +build darwin freebsd netbsd
 
 package tar
 
index 3957349d6ef0aa4461062c3203c7bd852d6328ed..717a0b3abc7246a50207378bbba81424ce155dcc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris
-// +build aix linux darwin dragonfly freebsd openbsd netbsd solaris
 
 package tar
 
index f0b61e6dba69a4fb393c8c92c694713c9defd4d6..275db6f0263f2ce8f165c265bba65a272f951bad 100644 (file)
@@ -14,7 +14,7 @@ import (
 
 // hasNUL reports whether the NUL character exists within s.
 func hasNUL(s string) bool {
-       return strings.IndexByte(s, 0) >= 0
+       return strings.Contains(s, "\x00")
 }
 
 // isASCII reports whether the input is an ASCII C-style string.
@@ -201,10 +201,7 @@ func parsePAXTime(s string) (time.Time, error) {
        const maxNanoSecondDigits = 9
 
        // Split string into seconds and sub-seconds parts.
-       ss, sn := s, ""
-       if pos := strings.IndexByte(s, '.'); pos >= 0 {
-               ss, sn = s[:pos], s[pos+1:]
-       }
+       ss, sn, _ := strings.Cut(s, ".")
 
        // Parse the seconds.
        secs, err := strconv.ParseInt(ss, 10, 64)
@@ -254,48 +251,32 @@ func formatPAXTime(ts time.Time) (s string) {
 // return the remainder as r.
 func parsePAXRecord(s string) (k, v, r string, err error) {
        // The size field ends at the first space.
-       sp := strings.IndexByte(s, ' ')
-       if sp == -1 {
+       nStr, rest, ok := strings.Cut(s, " ")
+       if !ok {
                return "", "", s, ErrHeader
        }
 
        // Parse the first token as a decimal integer.
-       n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
-       if perr != nil || n < 5 || int64(len(s)) < n {
+       n, perr := strconv.ParseInt(nStr, 10, 0) // Intentionally parse as native int
+       if perr != nil || n < 5 || n > int64(len(s)) {
                return "", "", s, ErrHeader
        }
-
-       afterSpace := int64(sp + 1)
-       beforeLastNewLine := n - 1
-       // In some cases, "length" was perhaps padded/malformed, and
-       // trying to index past where the space supposedly is goes past
-       // the end of the actual record.
-       // For example:
-       //    "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319"
-       //                                  ^     ^
-       //                                  |     |
-       //                                  |  afterSpace=35
-       //                                  |
-       //                          beforeLastNewLine=29
-       // yet indexOf(firstSpace) MUST BE before endOfRecord.
-       //
-       // See https://golang.org/issues/40196.
-       if afterSpace >= beforeLastNewLine {
+       n -= int64(len(nStr) + 1) // convert from index in s to index in rest
+       if n <= 0 {
                return "", "", s, ErrHeader
        }
 
        // Extract everything between the space and the final newline.
-       rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:]
+       rec, nl, rem := rest[:n-1], rest[n-1:n], rest[n:]
        if nl != "\n" {
                return "", "", s, ErrHeader
        }
 
        // The first equals separates the key from the value.
-       eq := strings.IndexByte(rec, '=')
-       if eq == -1 {
+       k, v, ok = strings.Cut(rec, "=")
+       if !ok {
                return "", "", s, ErrHeader
        }
-       k, v = rec[:eq], rec[eq+1:]
 
        if !validPAXRecord(k, v) {
                return "", "", s, ErrHeader
@@ -333,7 +314,7 @@ func formatPAXRecord(k, v string) (string, error) {
 // for the PAX version of the USTAR string fields.
 // The key must not contain an '=' character.
 func validPAXRecord(k, v string) bool {
-       if k == "" || strings.IndexByte(k, '=') >= 0 {
+       if k == "" || strings.Contains(k, "=") {
                return false
        }
        switch k {
index e80498d03e39c0699a4f6d51c91fd4dda471ffa4..3729f7e82c192f685e43398a88d2777bde5c17e0 100644 (file)
@@ -50,7 +50,7 @@ func (tw *Writer) Flush() error {
        if tw.err != nil {
                return tw.err
        }
-       if nb := tw.curr.LogicalRemaining(); nb > 0 {
+       if nb := tw.curr.logicalRemaining(); nb > 0 {
                return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
        }
        if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
@@ -117,8 +117,8 @@ func (tw *Writer) writeUSTARHeader(hdr *Header) error {
        // Pack the main header.
        var f formatter
        blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
-       f.formatString(blk.USTAR().Prefix(), namePrefix)
-       blk.SetFormat(FormatUSTAR)
+       f.formatString(blk.toUSTAR().prefix(), namePrefix)
+       blk.setFormat(FormatUSTAR)
        if f.err != nil {
                return f.err // Should never happen since header is validated
        }
@@ -208,7 +208,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
        var f formatter // Ignore errors since they are expected
        fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
        blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
-       blk.SetFormat(FormatPAX)
+       blk.setFormat(FormatPAX)
        if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
                return err
        }
@@ -250,10 +250,10 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
        var spb []byte
        blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
        if !hdr.AccessTime.IsZero() {
-               f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
+               f.formatNumeric(blk.toGNU().accessTime(), hdr.AccessTime.Unix())
        }
        if !hdr.ChangeTime.IsZero() {
-               f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
+               f.formatNumeric(blk.toGNU().changeTime(), hdr.ChangeTime.Unix())
        }
        // TODO(dsnet): Re-enable this when adding sparse support.
        // See https://golang.org/issue/22735
@@ -293,7 +293,7 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
                        f.formatNumeric(blk.GNU().RealSize(), realSize)
                }
        */
-       blk.SetFormat(FormatGNU)
+       blk.setFormat(FormatGNU)
        if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
                return err
        }
@@ -321,28 +321,28 @@ type (
 // The block returned is only valid until the next call to
 // templateV7Plus or writeRawFile.
 func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
-       tw.blk.Reset()
+       tw.blk.reset()
 
        modTime := hdr.ModTime
        if modTime.IsZero() {
                modTime = time.Unix(0, 0)
        }
 
-       v7 := tw.blk.V7()
-       v7.TypeFlag()[0] = hdr.Typeflag
-       fmtStr(v7.Name(), hdr.Name)
-       fmtStr(v7.LinkName(), hdr.Linkname)
-       fmtNum(v7.Mode(), hdr.Mode)
-       fmtNum(v7.UID(), int64(hdr.Uid))
-       fmtNum(v7.GID(), int64(hdr.Gid))
-       fmtNum(v7.Size(), hdr.Size)
-       fmtNum(v7.ModTime(), modTime.Unix())
+       v7 := tw.blk.toV7()
+       v7.typeFlag()[0] = hdr.Typeflag
+       fmtStr(v7.name(), hdr.Name)
+       fmtStr(v7.linkName(), hdr.Linkname)
+       fmtNum(v7.mode(), hdr.Mode)
+       fmtNum(v7.uid(), int64(hdr.Uid))
+       fmtNum(v7.gid(), int64(hdr.Gid))
+       fmtNum(v7.size(), hdr.Size)
+       fmtNum(v7.modTime(), modTime.Unix())
 
-       ustar := tw.blk.USTAR()
-       fmtStr(ustar.UserName(), hdr.Uname)
-       fmtStr(ustar.GroupName(), hdr.Gname)
-       fmtNum(ustar.DevMajor(), hdr.Devmajor)
-       fmtNum(ustar.DevMinor(), hdr.Devminor)
+       ustar := tw.blk.toUSTAR()
+       fmtStr(ustar.userName(), hdr.Uname)
+       fmtStr(ustar.groupName(), hdr.Gname)
+       fmtNum(ustar.devMajor(), hdr.Devmajor)
+       fmtNum(ustar.devMinor(), hdr.Devminor)
 
        return &tw.blk
 }
@@ -351,7 +351,7 @@ func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum num
 // It uses format to encode the header format and will write data as the body.
 // It uses default values for all of the other fields (as BSD and GNU tar does).
 func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
-       tw.blk.Reset()
+       tw.blk.reset()
 
        // Best effort for the filename.
        name = toASCII(name)
@@ -361,15 +361,15 @@ func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) erro
        name = strings.TrimRight(name, "/")
 
        var f formatter
-       v7 := tw.blk.V7()
-       v7.TypeFlag()[0] = flag
-       f.formatString(v7.Name(), name)
-       f.formatOctal(v7.Mode(), 0)
-       f.formatOctal(v7.UID(), 0)
-       f.formatOctal(v7.GID(), 0)
-       f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB
-       f.formatOctal(v7.ModTime(), 0)
-       tw.blk.SetFormat(format)
+       v7 := tw.blk.toV7()
+       v7.typeFlag()[0] = flag
+       f.formatString(v7.name(), name)
+       f.formatOctal(v7.mode(), 0)
+       f.formatOctal(v7.uid(), 0)
+       f.formatOctal(v7.gid(), 0)
+       f.formatOctal(v7.size(), int64(len(data))) // Must be < 8GiB
+       f.formatOctal(v7.modTime(), 0)
+       tw.blk.setFormat(format)
        if f.err != nil {
                return f.err // Only occurs if size condition is violated
        }
@@ -511,10 +511,13 @@ func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
        return io.Copy(struct{ io.Writer }{fw}, r)
 }
 
-func (fw regFileWriter) LogicalRemaining() int64 {
+// logicalRemaining implements fileState.logicalRemaining.
+func (fw regFileWriter) logicalRemaining() int64 {
        return fw.nb
 }
-func (fw regFileWriter) PhysicalRemaining() int64 {
+
+// logicalRemaining implements fileState.physicalRemaining.
+func (fw regFileWriter) physicalRemaining() int64 {
        return fw.nb
 }
 
@@ -526,9 +529,9 @@ type sparseFileWriter struct {
 }
 
 func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
-       overwrite := int64(len(b)) > sw.LogicalRemaining()
+       overwrite := int64(len(b)) > sw.logicalRemaining()
        if overwrite {
-               b = b[:sw.LogicalRemaining()]
+               b = b[:sw.logicalRemaining()]
        }
 
        b0 := b
@@ -556,7 +559,7 @@ func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
                return n, errMissData // Not possible; implies bug in validation logic
        case err != nil:
                return n, err
-       case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
+       case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
                return n, errUnrefData // Not possible; implies bug in validation logic
        case overwrite:
                return n, ErrWriteTooLong
@@ -578,12 +581,12 @@ func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
 
        var readLastByte bool
        pos0 := sw.pos
-       for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
+       for sw.logicalRemaining() > 0 && !readLastByte && err == nil {
                var nf int64 // Size of fragment
                dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
                if sw.pos < dataStart { // In a hole fragment
                        nf = dataStart - sw.pos
-                       if sw.PhysicalRemaining() == 0 {
+                       if sw.physicalRemaining() == 0 {
                                readLastByte = true
                                nf--
                        }
@@ -613,18 +616,18 @@ func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
                return n, errMissData // Not possible; implies bug in validation logic
        case err != nil:
                return n, err
-       case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
+       case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
                return n, errUnrefData // Not possible; implies bug in validation logic
        default:
                return n, ensureEOF(rs)
        }
 }
 
-func (sw sparseFileWriter) LogicalRemaining() int64 {
+func (sw sparseFileWriter) logicalRemaining() int64 {
        return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
 }
-func (sw sparseFileWriter) PhysicalRemaining() int64 {
-       return sw.fw.PhysicalRemaining()
+func (sw sparseFileWriter) physicalRemaining() int64 {
+       return sw.fw.physicalRemaining()
 }
 
 // zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
index a00f02d8fab698a588872ade0e5693b0d0dc0660..95ce99a3ed7d1276a6093f7d6a4ee26ab77310e2 100644 (file)
@@ -987,11 +987,9 @@ func TestIssue12594(t *testing.T) {
                // The prefix field should never appear in the GNU format.
                var blk block
                copy(blk[:], b.Bytes())
-               prefix := string(blk.USTAR().Prefix())
-               if i := strings.IndexByte(prefix, 0); i >= 0 {
-                       prefix = prefix[:i] // Truncate at the NUL terminator
-               }
-               if blk.GetFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
+               prefix := string(blk.toUSTAR().prefix())
+               prefix, _, _ = strings.Cut(prefix, "\x00") // Truncate at the NUL terminator
+               if blk.getFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
                        t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
                }
 
@@ -1029,7 +1027,7 @@ func TestFileWriter(t *testing.T) {
                        wantCnt int64
                        wantErr error
                }
-               testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
+               testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
                        wantLCnt int64
                        wantPCnt int64
                }
@@ -1292,11 +1290,11 @@ func TestFileWriter(t *testing.T) {
                                        t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
                                }
                        case testRemaining:
-                               if got := fw.LogicalRemaining(); got != tf.wantLCnt {
-                                       t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
+                               if got := fw.logicalRemaining(); got != tf.wantLCnt {
+                                       t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
                                }
-                               if got := fw.PhysicalRemaining(); got != tf.wantPCnt {
-                                       t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
+                               if got := fw.physicalRemaining(); got != tf.wantPCnt {
+                                       t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
                                }
                        default:
                                t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
index 2d53f4c7231653d651b4f3b5bb1a15325b4a33ac..e40a2c656b9c711c5266d9e0a5f439c930d95a37 100644 (file)
@@ -102,7 +102,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
        // indicate it contains up to 1 << 128 - 1 files. Since each file has a
        // header which will be _at least_ 30 bytes we can safely preallocate
        // if (data size / 30) >= end.directoryRecords.
-       if (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
+       if end.directorySize < uint64(size) && (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
                z.File = make([]*File, 0, end.directoryRecords)
        }
        z.Comment = end.comment
@@ -741,6 +741,9 @@ func (r *Reader) initFileList() {
                for _, file := range r.File {
                        isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
                        name := toValidName(file.Name)
+                       if name == "" {
+                               continue
+                       }
                        for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
                                dirs[dir] = true
                        }
@@ -782,8 +785,11 @@ func fileEntryLess(x, y string) bool {
 func (r *Reader) Open(name string) (fs.File, error) {
        r.initFileList()
 
+       if !fs.ValidPath(name) {
+               return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
+       }
        e := r.openLookup(name)
-       if e == nil || !fs.ValidPath(name) {
+       if e == nil {
                return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
        }
        if e.isDir {
@@ -797,7 +803,7 @@ func (r *Reader) Open(name string) (fs.File, error) {
 }
 
 func split(name string) (dir, elem string, isDir bool) {
-       if name[len(name)-1] == '/' {
+       if len(name) > 0 && name[len(name)-1] == '/' {
                isDir = true
                name = name[:len(name)-1]
        }
index 37dafe6c8e7c448c8fa28359e07fc2cdbb73560f..a54915316c18be57fde724184db02b6945ff0f73 100644 (file)
@@ -13,6 +13,7 @@ import (
        "io/fs"
        "os"
        "path/filepath"
+       "reflect"
        "regexp"
        "strings"
        "testing"
@@ -1202,6 +1203,15 @@ func TestCVE202127919(t *testing.T) {
        if err != nil {
                t.Errorf("Error reading file: %v", err)
        }
+       if len(r.File) != 1 {
+               t.Fatalf("No entries in the file list")
+       }
+       if r.File[0].Name != "../test.txt" {
+               t.Errorf("Unexpected entry name: %s", r.File[0].Name)
+       }
+       if _, err := r.File[0].Open(); err != nil {
+               t.Errorf("Error opening file: %v", err)
+       }
 }
 
 func TestReadDataDescriptor(t *testing.T) {
@@ -1384,3 +1394,139 @@ func TestCVE202133196(t *testing.T) {
                t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
        }
 }
+
+func TestCVE202139293(t *testing.T) {
+       // directory size is so large, that the check in Reader.init
+       // overflows when subtracting from the archive size, causing
+       // the pre-allocation check to be bypassed.
+       data := []byte{
+               0x50, 0x4b, 0x06, 0x06, 0x05, 0x06, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
+               0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+               0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
+               0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+               0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+               0xff, 0x50, 0xfe, 0x00, 0xff, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff,
+       }
+       _, err := NewReader(bytes.NewReader(data), int64(len(data)))
+       if err != ErrFormat {
+               t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
+       }
+}
+
+func TestCVE202141772(t *testing.T) {
+       // Archive contains a file whose name is exclusively made up of '/', '\'
+       // characters, or "../", "..\" paths, which would previously cause a panic.
+       //
+       //  Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
+       // --------  ------  ------- ---- ---------- ----- --------  ----
+       //        0  Stored        0   0% 08-05-2021 18:32 00000000  /
+       //        0  Stored        0   0% 09-14-2021 12:59 00000000  //
+       //        0  Stored        0   0% 09-14-2021 12:59 00000000  \
+       //       11  Stored       11   0% 09-14-2021 13:04 0d4a1185  /test.txt
+       // --------          -------  ---                            -------
+       //       11               11   0%                            4 files
+       data := []byte{
+               0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08,
+               0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50,
+               0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50,
+               0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b,
+               0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d,
+               0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+               0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
+               0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c,
+               0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+               0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00,
+               0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+               0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50,
+               0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+               0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a,
+               0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+               0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25,
+               0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
+               0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
+               0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f,
+               0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+               0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+               0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
+               0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98,
+               0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
+               0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
+               0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b,
+               0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11,
+               0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00,
+               0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+               0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
+               0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
+               0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7,
+               0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7,
+               0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7,
+               0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
+               0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00,
+               0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
+       }
+       r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
+       if err != nil {
+               t.Fatalf("Error reading the archive: %v", err)
+       }
+       entryNames := []string{`/`, `//`, `\`, `/test.txt`}
+       var names []string
+       for _, f := range r.File {
+               names = append(names, f.Name)
+               if _, err := f.Open(); err != nil {
+                       t.Errorf("Error opening %q: %v", f.Name, err)
+               }
+               if _, err := r.Open(f.Name); err == nil {
+                       t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
+               }
+       }
+       if !reflect.DeepEqual(names, entryNames) {
+               t.Errorf("Unexpected file entries: %q", names)
+       }
+       if _, err := r.Open(""); err == nil {
+               t.Errorf("Opening %q with fs.FS API succeeded", "")
+       }
+       if _, err := r.Open("test.txt"); err != nil {
+               t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err)
+       }
+       dirEntries, err := fs.ReadDir(r, ".")
+       if err != nil {
+               t.Fatalf("Error reading the root directory: %v", err)
+       }
+       if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" {
+               t.Errorf("Unexpected directory entries")
+               for _, dirEntry := range dirEntries {
+                       _, err := r.Open(dirEntry.Name())
+                       t.Logf("%q (Open error: %v)", dirEntry.Name(), err)
+               }
+               t.FailNow()
+       }
+       info, err := dirEntries[0].Info()
+       if err != nil {
+               t.Fatalf("Error reading info entry: %v", err)
+       }
+       if name := info.Name(); name != "test.txt" {
+               t.Errorf("Inconsistent name in info entry: %v", name)
+       }
+}
index 97c6c5297994684ca7fcfc5ccc492025709d795c..2b73eca814f621a9a0289f24cf0b6bbe8df35c6c 100644 (file)
@@ -362,7 +362,7 @@ func TestWriterDirAttributes(t *testing.T) {
        }
 
        binary.LittleEndian.PutUint32(sig[:], uint32(dataDescriptorSignature))
-       if bytes.Index(b, sig[:]) != -1 {
+       if bytes.Contains(b, sig[:]) {
                t.Error("there should be no data descriptor")
        }
 }
index ec928e7ad69ed54d213d3a38d9efb011ff32eb82..063a7785f3637aa59c6ef8b8f62ed8a49e3e41a1 100644 (file)
@@ -68,7 +68,12 @@ func (b *Reader) Size() int { return len(b.buf) }
 
 // Reset discards any buffered data, resets all state, and switches
 // the buffered reader to read from r.
+// Calling Reset on the zero value of Reader initializes the internal buffer
+// to the default size.
 func (b *Reader) Reset(r io.Reader) {
+       if b.buf == nil {
+               b.buf = make([]byte, defaultBufSize)
+       }
        b.reset(b.buf, r)
 }
 
@@ -168,6 +173,10 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
        if n == 0 {
                return
        }
+
+       b.lastByte = -1
+       b.lastRuneSize = -1
+
        remain := n
        for {
                skip := b.Buffered()
@@ -261,8 +270,8 @@ func (b *Reader) ReadByte() (byte, error) {
 // UnreadByte unreads the last byte. Only the most recently read byte can be unread.
 //
 // UnreadByte returns an error if the most recent method called on the
-// Reader was not a read operation. Notably, Peek is not considered a
-// read operation.
+// Reader was not a read operation. Notably, Peek, Discard, and WriteTo are not
+// considered read operations.
 func (b *Reader) UnreadByte() error {
        if b.lastByte < 0 || b.r == 0 && b.w > 0 {
                return ErrInvalidUnreadByte
@@ -497,6 +506,9 @@ func (b *Reader) ReadString(delim byte) (string, error) {
 // If the underlying reader supports the WriteTo method,
 // this calls the underlying WriteTo without buffering.
 func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
+       b.lastByte = -1
+       b.lastRuneSize = -1
+
        n, err = b.writeBuf(w)
        if err != nil {
                return
@@ -590,7 +602,12 @@ func (b *Writer) Size() int { return len(b.buf) }
 
 // Reset discards any unflushed buffered data, clears any error, and
 // resets b to write its output to w.
+// Calling Reset on the zero value of Writer initializes the internal buffer
+// to the default size.
 func (b *Writer) Reset(w io.Writer) {
+       if b.buf == nil {
+               b.buf = make([]byte, defaultBufSize)
+       }
        b.err = nil
        b.n = 0
        b.wr = w
@@ -623,6 +640,14 @@ func (b *Writer) Flush() error {
 // Available returns how many bytes are unused in the buffer.
 func (b *Writer) Available() int { return len(b.buf) - b.n }
 
+// AvailableBuffer returns an empty buffer with b.Available() capacity.
+// This buffer is intended to be appended to and
+// passed to an immediately succeeding Write call.
+// The buffer is only valid until the next write operation on b.
+func (b *Writer) AvailableBuffer() []byte {
+       return b.buf[b.n:][:0]
+}
+
 // Buffered returns the number of bytes that have been written into the current buffer.
 func (b *Writer) Buffered() int { return b.n }
 
@@ -720,19 +745,14 @@ func (b *Writer) WriteString(s string) (int, error) {
 }
 
 // ReadFrom implements io.ReaderFrom. If the underlying writer
-// supports the ReadFrom method, and b has no buffered data yet,
-// this calls the underlying ReadFrom without buffering.
+// supports the ReadFrom method, this calls the underlying ReadFrom.
+// If there is buffered data and an underlying ReadFrom, this fills
+// the buffer and writes it before calling ReadFrom.
 func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
        if b.err != nil {
                return 0, b.err
        }
-       if b.Buffered() == 0 {
-               if w, ok := b.wr.(io.ReaderFrom); ok {
-                       n, err = w.ReadFrom(r)
-                       b.err = err
-                       return n, err
-               }
-       }
+       readerFrom, readerFromOK := b.wr.(io.ReaderFrom)
        var m int
        for {
                if b.Available() == 0 {
@@ -740,6 +760,12 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
                                return n, err1
                        }
                }
+               if readerFromOK && b.Buffered() == 0 {
+                       nn, err := readerFrom.ReadFrom(r)
+                       b.err = err
+                       n += nn
+                       return n, err
+               }
                nr := 0
                for nr < maxConsecutiveEmptyReads {
                        m, err = r.Read(b.buf[b.n:])
index ebcc711db9d48cdefa44d6ec9bddd2406c13b59d..66b3e700531a98a8c876013ba951039ea434c721 100644 (file)
@@ -10,6 +10,8 @@ import (
        "errors"
        "fmt"
        "io"
+       "math/rand"
+       "strconv"
        "strings"
        "testing"
        "testing/iotest"
@@ -302,6 +304,40 @@ func TestNoUnreadByteAfterPeek(t *testing.T) {
        }
 }
 
+func TestNoUnreadRuneAfterDiscard(t *testing.T) {
+       br := NewReader(strings.NewReader("example"))
+       br.ReadRune()
+       br.Discard(1)
+       if err := br.UnreadRune(); err == nil {
+               t.Error("UnreadRune didn't fail after Discard")
+       }
+}
+
+func TestNoUnreadByteAfterDiscard(t *testing.T) {
+       br := NewReader(strings.NewReader("example"))
+       br.ReadByte()
+       br.Discard(1)
+       if err := br.UnreadByte(); err == nil {
+               t.Error("UnreadByte didn't fail after Discard")
+       }
+}
+
+func TestNoUnreadRuneAfterWriteTo(t *testing.T) {
+       br := NewReader(strings.NewReader("example"))
+       br.WriteTo(io.Discard)
+       if err := br.UnreadRune(); err == nil {
+               t.Error("UnreadRune didn't fail after WriteTo")
+       }
+}
+
+func TestNoUnreadByteAfterWriteTo(t *testing.T) {
+       br := NewReader(strings.NewReader("example"))
+       br.WriteTo(io.Discard)
+       if err := br.UnreadByte(); err == nil {
+               t.Error("UnreadByte didn't fail after WriteTo")
+       }
+}
+
 func TestUnreadByte(t *testing.T) {
        segments := []string{"Hello, ", "world"}
        r := NewReader(&StringReader{data: segments})
@@ -608,6 +644,37 @@ func TestWriter(t *testing.T) {
        }
 }
 
+func TestWriterAppend(t *testing.T) {
+       got := new(bytes.Buffer)
+       var want []byte
+       rn := rand.New(rand.NewSource(0))
+       w := NewWriterSize(got, 64)
+       for i := 0; i < 100; i++ {
+               // Obtain a buffer to append to.
+               b := w.AvailableBuffer()
+               if w.Available() != cap(b) {
+                       t.Fatalf("Available() = %v, want %v", w.Available(), cap(b))
+               }
+
+               // While not recommended, it is valid to append to a shifted buffer.
+               // This forces Write to copy the the input.
+               if rn.Intn(8) == 0 && cap(b) > 0 {
+                       b = b[1:1:cap(b)]
+               }
+
+               // Append a random integer of varying width.
+               n := int64(rn.Intn(1 << rn.Intn(30)))
+               want = append(strconv.AppendInt(want, n, 10), ' ')
+               b = append(strconv.AppendInt(b, n, 10), ' ')
+               w.Write(b)
+       }
+       w.Flush()
+
+       if !bytes.Equal(got.Bytes(), want) {
+               t.Errorf("output mismatch:\ngot  %s\nwant %s", got.Bytes(), want)
+       }
+}
+
 // Check that write errors are returned properly.
 
 type errorWriterTest struct {
@@ -1284,6 +1351,54 @@ func TestWriterReadFromErrNoProgress(t *testing.T) {
        }
 }
 
+type readFromWriter struct {
+       buf           []byte
+       writeBytes    int
+       readFromBytes int
+}
+
+func (w *readFromWriter) Write(p []byte) (int, error) {
+       w.buf = append(w.buf, p...)
+       w.writeBytes += len(p)
+       return len(p), nil
+}
+
+func (w *readFromWriter) ReadFrom(r io.Reader) (int64, error) {
+       b, err := io.ReadAll(r)
+       w.buf = append(w.buf, b...)
+       w.readFromBytes += len(b)
+       return int64(len(b)), err
+}
+
+// Test that calling (*Writer).ReadFrom with a partially-filled buffer
+// fills the buffer before switching over to ReadFrom.
+func TestWriterReadFromWithBufferedData(t *testing.T) {
+       const bufsize = 16
+
+       input := createTestInput(64)
+       rfw := &readFromWriter{}
+       w := NewWriterSize(rfw, bufsize)
+
+       const writeSize = 8
+       if n, err := w.Write(input[:writeSize]); n != writeSize || err != nil {
+               t.Errorf("w.Write(%v bytes) = %v, %v; want %v, nil", writeSize, n, err, writeSize)
+       }
+       n, err := w.ReadFrom(bytes.NewReader(input[writeSize:]))
+       if wantn := len(input[writeSize:]); int(n) != wantn || err != nil {
+               t.Errorf("io.Copy(w, %v bytes) = %v, %v; want %v, nil", wantn, n, err, wantn)
+       }
+       if err := w.Flush(); err != nil {
+               t.Errorf("w.Flush() = %v, want nil", err)
+       }
+
+       if got, want := rfw.writeBytes, bufsize; got != want {
+               t.Errorf("wrote %v bytes with Write, want %v", got, want)
+       }
+       if got, want := rfw.readFromBytes, len(input)-bufsize; got != want {
+               t.Errorf("wrote %v bytes with ReadFrom, want %v", got, want)
+       }
+}
+
 func TestReadZero(t *testing.T) {
        for _, size := range []int{100, 2} {
                t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
@@ -1312,6 +1427,7 @@ func TestReaderReset(t *testing.T) {
        if string(buf) != "foo" {
                t.Errorf("buf = %q; want foo", buf)
        }
+
        r.Reset(strings.NewReader("bar bar"))
        all, err := io.ReadAll(r)
        if err != nil {
@@ -1320,12 +1436,23 @@ func TestReaderReset(t *testing.T) {
        if string(all) != "bar bar" {
                t.Errorf("ReadAll = %q; want bar bar", all)
        }
+
+       *r = Reader{} // zero out the Reader
+       r.Reset(strings.NewReader("bar bar"))
+       all, err = io.ReadAll(r)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if string(all) != "bar bar" {
+               t.Errorf("ReadAll = %q; want bar bar", all)
+       }
 }
 
 func TestWriterReset(t *testing.T) {
-       var buf1, buf2 bytes.Buffer
+       var buf1, buf2, buf3 bytes.Buffer
        w := NewWriter(&buf1)
        w.WriteString("foo")
+
        w.Reset(&buf2) // and not flushed
        w.WriteString("bar")
        w.Flush()
@@ -1335,6 +1462,17 @@ func TestWriterReset(t *testing.T) {
        if buf2.String() != "bar" {
                t.Errorf("buf2 = %q; want bar", buf2.String())
        }
+
+       *w = Writer{}  // zero out the Writer
+       w.Reset(&buf3) // and not flushed
+       w.WriteString("bar")
+       w.Flush()
+       if buf1.String() != "" {
+               t.Errorf("buf1 = %q; want empty", buf1.String())
+       }
+       if buf3.String() != "bar" {
+               t.Errorf("buf3 = %q; want bar", buf3.String())
+       }
 }
 
 func TestReaderDiscard(t *testing.T) {
index 8885d40549f1532010a320d00964f19bffbb5846..a864d11012e77f96bc2a24dc692ce967c73270e3 100644 (file)
@@ -20,6 +20,18 @@ func ExampleWriter() {
        // Output: Hello, world!
 }
 
+func ExampleWriter_AvailableBuffer() {
+       w := bufio.NewWriter(os.Stdout)
+       for _, i := range []int64{1, 2, 3, 4} {
+               b := w.AvailableBuffer()
+               b = strconv.AppendInt(b, i, 10)
+               b = append(b, ' ')
+               w.Write(b)
+       }
+       w.Flush()
+       // Output: 1 2 3 4
+}
+
 // The simplest use of a Scanner, to read standard input as a set of lines.
 func ExampleScanner_lines() {
        scanner := bufio.NewScanner(os.Stdin)
index 5a47526593b093678b85e0c45c2dfbd5a42d16ed..f9855fcb0520f3bdf9082f71ddf794c923c3d0b5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 //
 //go:build linux
-// +build linux
 
 package bytes_test
 
@@ -66,7 +65,11 @@ func TestIndexByteNearPageBoundary(t *testing.T) {
 
 func TestIndexNearPageBoundary(t *testing.T) {
        t.Parallel()
-       var q [64]byte
+       q := dangerousSlice(t)
+       if len(q) > 64 {
+               // Only worry about when we're near the end of a page.
+               q = q[len(q)-64:]
+       }
        b := dangerousSlice(t)
        if len(b) > 256 {
                // Only worry about when we're near the end of a page.
@@ -82,4 +85,16 @@ func TestIndexNearPageBoundary(t *testing.T) {
                }
                q[j-1] = 0
        }
+
+       // Test differing alignments and sizes of q which always end on a page boundary.
+       q[len(q)-1] = 1 // difference is only found on the last byte
+       for j := 0; j < len(q); j++ {
+               for i := range b {
+                       idx := Index(b[i:], q[j:])
+                       if idx != -1 {
+                               t.Fatalf("Index(b[%d:], q[%d:])=%d, want -1\n", i, j, idx)
+                       }
+               }
+       }
+       q[len(q)-1] = 0
 }
index ce52649f132bb9575beacdca5af912f97478bb32..9e6b68eaf4ea3e8145a350647dd1bc7e0f14b720 100644 (file)
@@ -21,7 +21,7 @@ func Equal(a, b []byte) bool {
 }
 
 // Compare returns an integer comparing two byte slices lexicographically.
-// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
+// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
 // A nil argument is equivalent to an empty slice.
 func Compare(a, b []byte) int {
        return bytealg.Compare(a, b)
@@ -699,7 +699,7 @@ func ToValidUTF8(s, replacement []byte) []byte {
                if c < utf8.RuneSelf {
                        i++
                        invalid = false
-                       b = append(b, byte(c))
+                       b = append(b, c)
                        continue
                }
                _, wid := utf8.DecodeRune(s[i:])
@@ -867,6 +867,8 @@ func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
 // most-significant bit of the highest word, map to the full range of all
 // 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
 // ensuring that any non-ASCII character will be reported as not in the set.
+// This allocates a total of 32 bytes even though the upper half
+// is unused to avoid bounds checks in asciiSet.contains.
 type asciiSet [8]uint32
 
 // makeASCIISet creates a set of ASCII characters and reports whether all
@@ -877,53 +879,133 @@ func makeASCIISet(chars string) (as asciiSet, ok bool) {
                if c >= utf8.RuneSelf {
                        return as, false
                }
-               as[c>>5] |= 1 << uint(c&31)
+               as[c/32] |= 1 << (c % 32)
        }
        return as, true
 }
 
 // contains reports whether c is inside the set.
 func (as *asciiSet) contains(c byte) bool {
-       return (as[c>>5] & (1 << uint(c&31))) != 0
+       return (as[c/32] & (1 << (c % 32))) != 0
 }
 
-func makeCutsetFunc(cutset string) func(r rune) bool {
-       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
-               return func(r rune) bool {
-                       return r == rune(cutset[0])
-               }
-       }
-       if as, isASCII := makeASCIISet(cutset); isASCII {
-               return func(r rune) bool {
-                       return r < utf8.RuneSelf && as.contains(byte(r))
-               }
-       }
-       return func(r rune) bool {
-               for _, c := range cutset {
-                       if c == r {
-                               return true
-                       }
+// containsRune is a simplified version of strings.ContainsRune
+// to avoid importing the strings package.
+// We avoid bytes.ContainsRune to avoid allocating a temporary copy of s.
+func containsRune(s string, r rune) bool {
+       for _, c := range s {
+               if c == r {
+                       return true
                }
-               return false
        }
+       return false
 }
 
 // Trim returns a subslice of s by slicing off all leading and
 // trailing UTF-8-encoded code points contained in cutset.
 func Trim(s []byte, cutset string) []byte {
-       return TrimFunc(s, makeCutsetFunc(cutset))
+       if len(s) == 0 || cutset == "" {
+               return s
+       }
+       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+               return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
+       }
+       if as, ok := makeASCIISet(cutset); ok {
+               return trimLeftASCII(trimRightASCII(s, &as), &as)
+       }
+       return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)
 }
 
 // TrimLeft returns a subslice of s by slicing off all leading
 // UTF-8-encoded code points contained in cutset.
 func TrimLeft(s []byte, cutset string) []byte {
-       return TrimLeftFunc(s, makeCutsetFunc(cutset))
+       if len(s) == 0 || cutset == "" {
+               return s
+       }
+       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+               return trimLeftByte(s, cutset[0])
+       }
+       if as, ok := makeASCIISet(cutset); ok {
+               return trimLeftASCII(s, &as)
+       }
+       return trimLeftUnicode(s, cutset)
+}
+
+func trimLeftByte(s []byte, c byte) []byte {
+       for len(s) > 0 && s[0] == c {
+               s = s[1:]
+       }
+       return s
+}
+
+func trimLeftASCII(s []byte, as *asciiSet) []byte {
+       for len(s) > 0 {
+               if !as.contains(s[0]) {
+                       break
+               }
+               s = s[1:]
+       }
+       return s
+}
+
+func trimLeftUnicode(s []byte, cutset string) []byte {
+       for len(s) > 0 {
+               r, n := rune(s[0]), 1
+               if r >= utf8.RuneSelf {
+                       r, n = utf8.DecodeRune(s)
+               }
+               if !containsRune(cutset, r) {
+                       break
+               }
+               s = s[n:]
+       }
+       return s
 }
 
 // TrimRight returns a subslice of s by slicing off all trailing
 // UTF-8-encoded code points that are contained in cutset.
 func TrimRight(s []byte, cutset string) []byte {
-       return TrimRightFunc(s, makeCutsetFunc(cutset))
+       if len(s) == 0 || cutset == "" {
+               return s
+       }
+       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+               return trimRightByte(s, cutset[0])
+       }
+       if as, ok := makeASCIISet(cutset); ok {
+               return trimRightASCII(s, &as)
+       }
+       return trimRightUnicode(s, cutset)
+}
+
+func trimRightByte(s []byte, c byte) []byte {
+       for len(s) > 0 && s[len(s)-1] == c {
+               s = s[:len(s)-1]
+       }
+       return s
+}
+
+func trimRightASCII(s []byte, as *asciiSet) []byte {
+       for len(s) > 0 {
+               if !as.contains(s[len(s)-1]) {
+                       break
+               }
+               s = s[:len(s)-1]
+       }
+       return s
+}
+
+func trimRightUnicode(s []byte, cutset string) []byte {
+       for len(s) > 0 {
+               r, n := rune(s[len(s)-1]), 1
+               if r >= utf8.RuneSelf {
+                       r, n = utf8.DecodeLastRune(s)
+               }
+               if !containsRune(cutset, r) {
+                       break
+               }
+               s = s[:len(s)-n]
+       }
+       return s
 }
 
 // TrimSpace returns a subslice of s by slicing off all leading and
@@ -1174,3 +1256,16 @@ func Index(s, sep []byte) int {
        }
        return -1
 }
+
+// Cut slices s around the first instance of sep,
+// returning the text before and after sep.
+// The found result reports whether sep appears in s.
+// If sep does not appear in s, cut returns s, nil, false.
+//
+// Cut returns slices of the original slice s, not copies.
+func Cut(s, sep []byte) (before, after []byte, found bool) {
+       if i := Index(s, sep); i >= 0 {
+               return s[:i], s[i+len(sep):], true
+       }
+       return s, nil, false
+}
index 544ee46f908860dc969170c26d8f3ad472394eee..3bece6adf0b905b63f580db349c5ee0cf007b89b 100644 (file)
@@ -1251,7 +1251,9 @@ var trimTests = []TrimTest{
        {"TrimLeft", "abba", "ab", ""},
        {"TrimRight", "abba", "ab", ""},
        {"TrimLeft", "abba", "a", "bba"},
+       {"TrimLeft", "abba", "b", "abba"},
        {"TrimRight", "abba", "a", "abb"},
+       {"TrimRight", "abba", "b", "abba"},
        {"Trim", "<tag>", "<>", "tag"},
        {"Trim", "* listitem", " *", "listitem"},
        {"Trim", `"quote"`, `"`, "quote"},
@@ -1565,6 +1567,29 @@ func TestEqualFold(t *testing.T) {
        }
 }
 
+var cutTests = []struct {
+       s, sep        string
+       before, after string
+       found         bool
+}{
+       {"abc", "b", "a", "c", true},
+       {"abc", "a", "", "bc", true},
+       {"abc", "c", "ab", "", true},
+       {"abc", "abc", "", "", true},
+       {"abc", "", "", "abc", true},
+       {"abc", "d", "abc", "", false},
+       {"", "d", "", "", false},
+       {"", "", "", "", true},
+}
+
+func TestCut(t *testing.T) {
+       for _, tt := range cutTests {
+               if before, after, found := Cut([]byte(tt.s), []byte(tt.sep)); string(before) != tt.before || string(after) != tt.after || found != tt.found {
+                       t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found)
+               }
+       }
+}
+
 func TestBufferGrowNegative(t *testing.T) {
        defer func() {
                if err := recover(); err == nil {
@@ -1963,6 +1988,13 @@ func BenchmarkTrimASCII(b *testing.B) {
        }
 }
 
+func BenchmarkTrimByte(b *testing.B) {
+       x := []byte("  the quick brown fox   ")
+       for i := 0; i < b.N; i++ {
+               Trim(x, " ")
+       }
+}
+
 func BenchmarkIndexPeriodic(b *testing.B) {
        key := []byte{1, 1}
        for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
index ae93202b5706e12da11cb8866af8f6a9d75b5745..d04b088fabbc4b683dd372d0acac9f3bacdf796d 100644 (file)
@@ -54,6 +54,19 @@ func ExampleBuffer_Len() {
        // Output: 5
 }
 
+func ExampleBuffer_Next() {
+       var b bytes.Buffer
+       b.Grow(64)
+       b.Write([]byte("abcde"))
+       fmt.Printf("%s\n", string(b.Next(2)))
+       fmt.Printf("%s\n", string(b.Next(2)))
+       fmt.Printf("%s", string(b.Next(2)))
+       // Output:
+       // ab
+       // cd
+       // e
+}
+
 func ExampleCompare() {
        // Interpret Compare's result by comparing it to zero.
        var a, b []byte
@@ -92,36 +105,6 @@ func ExampleCompare_search() {
        }
 }
 
-func ExampleTrimSuffix() {
-       var b = []byte("Hello, goodbye, etc!")
-       b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
-       b = bytes.TrimSuffix(b, []byte("gopher"))
-       b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
-       os.Stdout.Write(b)
-       // Output: Hello, world!
-}
-
-func ExampleTrimPrefix() {
-       var b = []byte("Goodbye,, world!")
-       b = bytes.TrimPrefix(b, []byte("Goodbye,"))
-       b = bytes.TrimPrefix(b, []byte("See ya,"))
-       fmt.Printf("Hello%s", b)
-       // Output: Hello, world!
-}
-
-func ExampleFields() {
-       fmt.Printf("Fields are: %q", bytes.Fields([]byte("  foo bar  baz   ")))
-       // Output: Fields are: ["foo" "bar" "baz"]
-}
-
-func ExampleFieldsFunc() {
-       f := func(c rune) bool {
-               return !unicode.IsLetter(c) && !unicode.IsNumber(c)
-       }
-       fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte("  foo1;bar2,baz3..."), f))
-       // Output: Fields are: ["foo1" "bar2" "baz3"]
-}
-
 func ExampleContains() {
        fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
        fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
@@ -168,6 +151,22 @@ func ExampleCount() {
        // 5
 }
 
+func ExampleCut() {
+       show := func(s, sep string) {
+               before, after, found := bytes.Cut([]byte(s), []byte(sep))
+               fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
+       }
+       show("Gopher", "Go")
+       show("Gopher", "ph")
+       show("Gopher", "er")
+       show("Gopher", "Badger")
+       // Output:
+       // Cut("Gopher", "Go") = "", "pher", true
+       // Cut("Gopher", "ph") = "Go", "er", true
+       // Cut("Gopher", "er") = "Goph", "", true
+       // Cut("Gopher", "Badger") = "Gopher", "", false
+}
+
 func ExampleEqual() {
        fmt.Println(bytes.Equal([]byte("Go"), []byte("Go")))
        fmt.Println(bytes.Equal([]byte("Go"), []byte("C++")))
@@ -181,6 +180,19 @@ func ExampleEqualFold() {
        // Output: true
 }
 
+func ExampleFields() {
+       fmt.Printf("Fields are: %q", bytes.Fields([]byte("  foo bar  baz   ")))
+       // Output: Fields are: ["foo" "bar" "baz"]
+}
+
+func ExampleFieldsFunc() {
+       f := func(c rune) bool {
+               return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+       }
+       fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte("  foo1;bar2,baz3..."), f))
+       // Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
 func ExampleHasPrefix() {
        fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
        fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
@@ -246,6 +258,12 @@ func ExampleIndexRune() {
        // -1
 }
 
+func ExampleJoin() {
+       s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
+       fmt.Printf("%s", bytes.Join(s, []byte(", ")))
+       // Output: foo, bar, baz
+}
+
 func ExampleLastIndex() {
        fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
        fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
@@ -286,10 +304,12 @@ func ExampleLastIndexFunc() {
        // -1
 }
 
-func ExampleJoin() {
-       s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
-       fmt.Printf("%s", bytes.Join(s, []byte(", ")))
-       // Output: foo, bar, baz
+func ExampleReader_Len() {
+       fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
+       fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())
+       // Output:
+       // 3
+       // 16
 }
 
 func ExampleRepeat() {
@@ -399,20 +419,6 @@ func ExampleTrimFunc() {
        // go-gopher!
 }
 
-func ExampleMap() {
-       rot13 := func(r rune) rune {
-               switch {
-               case r >= 'A' && r <= 'Z':
-                       return 'A' + (r-'A'+13)%26
-               case r >= 'a' && r <= 'z':
-                       return 'a' + (r-'a'+13)%26
-               }
-               return r
-       }
-       fmt.Printf("%s", bytes.Map(rot13, []byte("'Twas brillig and the slithy gopher...")))
-       // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
-}
-
 func ExampleTrimLeft() {
        fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789")))
        // Output:
@@ -429,11 +435,28 @@ func ExampleTrimLeftFunc() {
        // go-gopher!567
 }
 
+func ExampleTrimPrefix() {
+       var b = []byte("Goodbye,, world!")
+       b = bytes.TrimPrefix(b, []byte("Goodbye,"))
+       b = bytes.TrimPrefix(b, []byte("See ya,"))
+       fmt.Printf("Hello%s", b)
+       // Output: Hello, world!
+}
+
 func ExampleTrimSpace() {
        fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))
        // Output: a lone gopher
 }
 
+func ExampleTrimSuffix() {
+       var b = []byte("Hello, goodbye, etc!")
+       b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
+       b = bytes.TrimSuffix(b, []byte("gopher"))
+       b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
+       os.Stdout.Write(b)
+       // Output: Hello, world!
+}
+
 func ExampleTrimRight() {
        fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789")))
        // Output:
@@ -450,21 +473,6 @@ func ExampleTrimRightFunc() {
        // 1234go-gopher!
 }
 
-func ExampleToUpper() {
-       fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
-       // Output: GOPHER
-}
-
-func ExampleToUpperSpecial() {
-       str := []byte("ahoj vývojári golang")
-       totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str)
-       fmt.Println("Original : " + string(str))
-       fmt.Println("ToUpper : " + string(totitle))
-       // Output:
-       // Original : ahoj vývojári golang
-       // ToUpper : AHOJ VÝVOJÁRİ GOLANG
-}
-
 func ExampleToLower() {
        fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
        // Output: gopher
@@ -480,10 +488,17 @@ func ExampleToLowerSpecial() {
        // ToLower : ahoj vývojári golang
 }
 
-func ExampleReader_Len() {
-       fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
-       fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())
+func ExampleToUpper() {
+       fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
+       // Output: GOPHER
+}
+
+func ExampleToUpperSpecial() {
+       str := []byte("ahoj vývojári golang")
+       totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str)
+       fmt.Println("Original : " + string(str))
+       fmt.Println("ToUpper : " + string(totitle))
        // Output:
-       // 3
-       // 16
+       // Original : ahoj vývojári golang
+       // ToUpper : AHOJ VÝVOJÁRİ GOLANG
 }
index b07a238d679a1636657fb7618b8c0d7e7ea34a72..0c61b1b489747e70e630f787f64cf5d90aca0723 100644 (file)
@@ -653,10 +653,15 @@ func (w *Walker) ImportFrom(fromPath, fromDir string, mode types.ImportMode) (*t
        }
 
        // Type-check package files.
+       var sizes types.Sizes
+       if w.context != nil {
+               sizes = types.SizesFor(w.context.Compiler, w.context.GOARCH)
+       }
        conf := types.Config{
                IgnoreFuncBodies: true,
                FakeImportC:      true,
                Importer:         w,
+               Sizes:            sizes,
        }
        pkg, err = conf.Check(name, fset, files, nil)
        if err != nil {
@@ -701,6 +706,36 @@ func sortedMethodNames(typ *types.Interface) []string {
        return list
 }
 
+// sortedEmbeddeds returns constraint types embedded in an
+// interface. It does not include embedded interface types or methods.
+func (w *Walker) sortedEmbeddeds(typ *types.Interface) []string {
+       n := typ.NumEmbeddeds()
+       list := make([]string, 0, n)
+       for i := 0; i < n; i++ {
+               emb := typ.EmbeddedType(i)
+               switch emb := emb.(type) {
+               case *types.Interface:
+                       list = append(list, w.sortedEmbeddeds(emb)...)
+               case *types.Union:
+                       var buf bytes.Buffer
+                       nu := emb.Len()
+                       for i := 0; i < nu; i++ {
+                               if i > 0 {
+                                       buf.WriteString(" | ")
+                               }
+                               term := emb.Term(i)
+                               if term.Tilde() {
+                                       buf.WriteByte('~')
+                               }
+                               w.writeType(&buf, term.Type())
+                       }
+                       list = append(list, buf.String())
+               }
+       }
+       sort.Strings(list)
+       return list
+}
+
 func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
        switch typ := typ.(type) {
        case *types.Basic:
@@ -758,9 +793,16 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
 
        case *types.Interface:
                buf.WriteString("interface{")
-               if typ.NumMethods() > 0 {
+               if typ.NumMethods() > 0 || typ.NumEmbeddeds() > 0 {
                        buf.WriteByte(' ')
+               }
+               if typ.NumMethods() > 0 {
                        buf.WriteString(strings.Join(sortedMethodNames(typ), ", "))
+               }
+               if typ.NumEmbeddeds() > 0 {
+                       buf.WriteString(strings.Join(w.sortedEmbeddeds(typ), ", "))
+               }
+               if typ.NumMethods() > 0 || typ.NumEmbeddeds() > 0 {
                        buf.WriteByte(' ')
                }
                buf.WriteString("}")
@@ -795,12 +837,19 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
                }
                buf.WriteString(typ.Obj().Name())
 
+       case *types.TypeParam:
+               // Type parameter names may change, so use a placeholder instead.
+               fmt.Fprintf(buf, "$%d", typ.Index())
+
        default:
                panic(fmt.Sprintf("unknown type %T", typ))
        }
 }
 
 func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
+       if tparams := sig.TypeParams(); tparams != nil {
+               w.writeTypeParams(buf, tparams, true)
+       }
        w.writeParams(buf, sig.Params(), sig.Variadic())
        switch res := sig.Results(); res.Len() {
        case 0:
@@ -814,6 +863,23 @@ func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
        }
 }
 
+func (w *Walker) writeTypeParams(buf *bytes.Buffer, tparams *types.TypeParamList, withConstraints bool) {
+       buf.WriteByte('[')
+       c := tparams.Len()
+       for i := 0; i < c; i++ {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               tp := tparams.At(i)
+               w.writeType(buf, tp)
+               if withConstraints {
+                       buf.WriteByte(' ')
+                       w.writeType(buf, tp.Constraint())
+               }
+       }
+       buf.WriteByte(']')
+}
+
 func (w *Walker) writeParams(buf *bytes.Buffer, t *types.Tuple, variadic bool) {
        buf.WriteByte('(')
        for i, n := 0, t.Len(); i < n; i++ {
@@ -867,6 +933,12 @@ func (w *Walker) emitObj(obj types.Object) {
 
 func (w *Walker) emitType(obj *types.TypeName) {
        name := obj.Name()
+       if tparams := obj.Type().(*types.Named).TypeParams(); tparams != nil {
+               var buf bytes.Buffer
+               buf.WriteString(name)
+               w.writeTypeParams(&buf, tparams, true)
+               name = buf.String()
+       }
        typ := obj.Type()
        if obj.IsAlias() {
                w.emitf("type %s = %s", name, w.typeString(typ))
@@ -990,7 +1062,13 @@ func (w *Walker) emitMethod(m *types.Selection) {
                        log.Fatalf("exported method with unexported receiver base type: %s", m)
                }
        }
-       w.emitf("method (%s) %s%s", w.typeString(recv), m.Obj().Name(), w.signatureString(sig))
+       tps := ""
+       if rtp := sig.RecvTypeParams(); rtp != nil {
+               var buf bytes.Buffer
+               w.writeTypeParams(&buf, rtp, false)
+               tps = buf.String()
+       }
+       w.emitf("method (%s%s) %s%s", w.typeString(recv), tps, m.Obj().Name(), w.signatureString(sig))
 }
 
 func (w *Walker) emitf(format string, args ...interface{}) {
index 81979de191abc2f13263a467fc7e34aab31b8026..1b94a1b883f4747e6d37e17e99de6fdb5e0f7b39 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // The run program is invoked via the dist tool.
 // To invoke manually: go tool dist test -run api --no-rebuild
diff --git a/src/cmd/api/testdata/src/pkg/p4/golden.txt b/src/cmd/api/testdata/src/pkg/p4/golden.txt
new file mode 100644 (file)
index 0000000..7997ab4
--- /dev/null
@@ -0,0 +1,5 @@
+pkg p4, func NewPair[$0 interface{ M }, $1 interface{ ~int }]($0, $1) Pair
+pkg p4, method (Pair[$0, $1]) Second() $1
+pkg p4, method (Pair[$0, $1]) First() $0
+pkg p4, type Pair[$0 interface{ M }, $1 interface{ ~int }] struct
+pkg p4, func Clone[$0 interface{ ~[]$1 }, $1 interface{}]($0) $0
diff --git a/src/cmd/api/testdata/src/pkg/p4/p4.go b/src/cmd/api/testdata/src/pkg/p4/p4.go
new file mode 100644 (file)
index 0000000..462a75b
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2021 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 p4
+
+type Pair[T1 interface { M() }, T2 ~int] struct {
+       f1 T1
+       f2 T2
+}
+
+func NewPair[T1 interface { M() }, T2 ~int](v1 T1, v2 T2) Pair[T1, T2] {
+       return Pair[T1, T2]{f1: v1, f2: v2}
+}
+
+func (p Pair[X1, _]) First() X1 {
+       return p.f1
+}
+
+func (p Pair[_, X2]) Second() X2 {
+       return p.f2
+}
+
+func Clone[S ~[]T, T any](s S) S {
+       return append(S(nil), s...)
+}
index 026d8abf81305f51d953b500c35d3bd2d7c7a087..4d374cb828eadb595727a5f4e2552570a7f39d70 100644 (file)
@@ -50,7 +50,7 @@ func nilRegisterNumber(name string, n int16) (int16, bool) {
 
 // Set configures the architecture specified by GOARCH and returns its representation.
 // It returns nil if GOARCH is not recognized.
-func Set(GOARCH string) *Arch {
+func Set(GOARCH string, shared bool) *Arch {
        switch GOARCH {
        case "386":
                return archX86(&x86.Link386)
@@ -73,7 +73,7 @@ func Set(GOARCH string) *Arch {
        case "ppc64le":
                return archPPC64(&ppc64.Linkppc64le)
        case "riscv64":
-               return archRISCV64()
+               return archRISCV64(shared)
        case "s390x":
                return archS390x()
        case "wasm":
@@ -178,6 +178,10 @@ func archX86(linkArch *obj.LinkArch) *Arch {
        instructions["PSLLDQ"] = x86.APSLLO
        instructions["PSRLDQ"] = x86.APSRLO
        instructions["PADDD"] = x86.APADDL
+       // Spellings originally used in CL 97235.
+       instructions["MOVBELL"] = x86.AMOVBEL
+       instructions["MOVBEQQ"] = x86.AMOVBEQ
+       instructions["MOVBEWW"] = x86.AMOVBEW
 
        return &Arch{
                LinkArch:       linkArch,
@@ -374,6 +378,9 @@ func archPPC64(linkArch *obj.LinkArch) *Arch {
        for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ {
                register[obj.Rconv(i)] = int16(i)
        }
+       for i := ppc64.REG_CR0LT; i <= ppc64.REG_CR7SO; i++ {
+               register[obj.Rconv(i)] = int16(i)
+       }
        register["CR"] = ppc64.REG_CR
        register["XER"] = ppc64.REG_XER
        register["LR"] = ppc64.REG_LR
@@ -534,12 +541,18 @@ func archMips64(linkArch *obj.LinkArch) *Arch {
        }
 }
 
-func archRISCV64() *Arch {
+func archRISCV64(shared bool) *Arch {
        register := make(map[string]int16)
 
        // Standard register names.
        for i := riscv.REG_X0; i <= riscv.REG_X31; i++ {
-               if i == riscv.REG_G {
+               // Disallow X3 in shared mode, as this will likely be used as the
+               // GP register, which could result in problems in non-Go code,
+               // including signal handlers.
+               if shared && i == riscv.REG_GP {
+                       continue
+               }
+               if i == riscv.REG_TP || i == riscv.REG_G {
                        continue
                }
                name := fmt.Sprintf("X%d", i-riscv.REG_X0)
index 40d828a1fea7485d3389c529f16180ecdd140bc7..24689c5ab17657816a67e7fe0b69a498e40d4c99 100644 (file)
@@ -165,27 +165,21 @@ func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, i
                }
        }
        if reg <= arm64.REG_R31 && reg >= arm64.REG_R0 {
+               if !isAmount {
+                       return errors.New("invalid register extension")
+               }
                switch ext {
                case "UXTB":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        if a.Type == obj.TYPE_MEM {
                                return errors.New("invalid shift for the register offset addressing mode")
                        }
                        a.Reg = arm64.REG_UXTB + Rnum
                case "UXTH":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        if a.Type == obj.TYPE_MEM {
                                return errors.New("invalid shift for the register offset addressing mode")
                        }
                        a.Reg = arm64.REG_UXTH + Rnum
                case "UXTW":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        // effective address of memory is a base register value and an offset register value.
                        if a.Type == obj.TYPE_MEM {
                                a.Index = arm64.REG_UXTW + Rnum
@@ -193,48 +187,33 @@ func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, i
                                a.Reg = arm64.REG_UXTW + Rnum
                        }
                case "UXTX":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        if a.Type == obj.TYPE_MEM {
                                return errors.New("invalid shift for the register offset addressing mode")
                        }
                        a.Reg = arm64.REG_UXTX + Rnum
                case "SXTB":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
+                       if a.Type == obj.TYPE_MEM {
+                               return errors.New("invalid shift for the register offset addressing mode")
                        }
                        a.Reg = arm64.REG_SXTB + Rnum
                case "SXTH":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        if a.Type == obj.TYPE_MEM {
                                return errors.New("invalid shift for the register offset addressing mode")
                        }
                        a.Reg = arm64.REG_SXTH + Rnum
                case "SXTW":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        if a.Type == obj.TYPE_MEM {
                                a.Index = arm64.REG_SXTW + Rnum
                        } else {
                                a.Reg = arm64.REG_SXTW + Rnum
                        }
                case "SXTX":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        if a.Type == obj.TYPE_MEM {
                                a.Index = arm64.REG_SXTX + Rnum
                        } else {
                                a.Reg = arm64.REG_SXTX + Rnum
                        }
                case "LSL":
-                       if !isAmount {
-                               return errors.New("invalid register extension")
-                       }
                        a.Index = arm64.REG_LSL + Rnum
                default:
                        return errors.New("unsupported general register extension type: " + ext)
index cf0d1550f99f0e3d6f014b1b4782553692348bb2..d0cb6328f16b6e6936b826a7e11e09b914549b76 100644 (file)
@@ -793,6 +793,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                                return
                        }
                }
+               if p.arch.Family == sys.RISCV64 {
+                       prog.From = a[0]
+                       prog.Reg = p.getRegister(prog, op, &a[1])
+                       prog.SetRestArgs([]obj.Addr{a[2]})
+                       prog.To = a[3]
+                       break
+               }
                if p.arch.Family == sys.S390X {
                        if a[1].Type != obj.TYPE_REG {
                                p.errorf("second operand must be a register in %s instruction", op)
index 8ef02b1a0e8acacafb379d12030e1c522de984f0..c1295a0c4267d577e5302c493518aed7c69f47fb 100644 (file)
@@ -19,7 +19,7 @@ import (
 func setArch(goarch string) (*arch.Arch, *obj.Link) {
        buildcfg.GOOS = "linux" // obj can handle this OS for all architectures.
        buildcfg.GOARCH = goarch
-       architecture := arch.Set(goarch)
+       architecture := arch.Set(goarch, false)
        if architecture == nil {
                panic("asm: unrecognized architecture " + goarch)
        }
index c02f51d125916b84687fc8aba07428a37950ccd8..5bba292dee43f6659b457c8de9177682b0fa5d82 100644 (file)
@@ -2495,30 +2495,30 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        MOVAPS X11, (BX)                        // 440f291b
        MOVAPS X2, (R11)                        // 410f2913
        MOVAPS X11, (R11)                       // 450f291b
-       MOVBEWW DX, (BX)                        // 660f38f113
-       MOVBEWW R11, (BX)                       // 66440f38f11b
-       MOVBEWW DX, (R11)                       // 66410f38f113
-       MOVBEWW R11, (R11)                      // 66450f38f11b
-       MOVBEWW (BX), DX                        // 660f38f013
-       MOVBEWW (R11), DX                       // 66410f38f013
-       MOVBEWW (BX), R11                       // 66440f38f01b
-       MOVBEWW (R11), R11                      // 66450f38f01b
-       MOVBELL DX, (BX)                        // 0f38f113
-       MOVBELL R11, (BX)                       // 440f38f11b
-       MOVBELL DX, (R11)                       // 410f38f113
-       MOVBELL R11, (R11)                      // 450f38f11b
-       MOVBELL (BX), DX                        // 0f38f013
-       MOVBELL (R11), DX                       // 410f38f013
-       MOVBELL (BX), R11                       // 440f38f01b
-       MOVBELL (R11), R11                      // 450f38f01b
-       MOVBEQQ DX, (BX)                        // 480f38f113
-       MOVBEQQ R11, (BX)                       // 4c0f38f11b
-       MOVBEQQ DX, (R11)                       // 490f38f113
-       MOVBEQQ R11, (R11)                      // 4d0f38f11b
-       MOVBEQQ (BX), DX                        // 480f38f013
-       MOVBEQQ (R11), DX                       // 490f38f013
-       MOVBEQQ (BX), R11                       // 4c0f38f01b
-       MOVBEQQ (R11), R11                      // 4d0f38f01b
+       MOVBEW DX, (BX)                         // 660f38f113
+       MOVBEW R11, (BX)                        // 66440f38f11b
+       MOVBEW DX, (R11)                        // 66410f38f113
+       MOVBEW R11, (R11)                       // 66450f38f11b
+       MOVBEW (BX), DX                         // 660f38f013
+       MOVBEW (R11), DX                        // 66410f38f013
+       MOVBEW (BX), R11                        // 66440f38f01b
+       MOVBEW (R11), R11                       // 66450f38f01b
+       MOVBEL DX, (BX)                         // 0f38f113
+       MOVBEL R11, (BX)                        // 440f38f11b
+       MOVBEL DX, (R11)                        // 410f38f113
+       MOVBEL R11, (R11)                       // 450f38f11b
+       MOVBEL (BX), DX                         // 0f38f013
+       MOVBEL (R11), DX                        // 410f38f013
+       MOVBEL (BX), R11                        // 440f38f01b
+       MOVBEL (R11), R11                       // 450f38f01b
+       MOVBEQ DX, (BX)                         // 480f38f113
+       MOVBEQ R11, (BX)                        // 4c0f38f11b
+       MOVBEQ DX, (R11)                        // 490f38f113
+       MOVBEQ R11, (R11)                       // 4d0f38f11b
+       MOVBEQ (BX), DX                         // 480f38f013
+       MOVBEQ (R11), DX                        // 490f38f013
+       MOVBEQ (BX), R11                        // 4c0f38f01b
+       MOVBEQ (R11), R11                       // 4d0f38f01b
        MOVQ (BX), M2                           // 0f6e13 or 0f6f13 or 480f6e13
        MOVQ (R11), M2                          // 410f6e13 or 410f6f13 or 490f6e13
        MOVQ DX, M2                             // 0f6ed2 or 480f6ed2
index d8a20edfc13039d205c10a0579ab9414a54daa54..a4b56b0696b33a8524243df796ac9c7fee0ea4be 100644 (file)
@@ -334,6 +334,8 @@ TEXT        foo(SB), DUPOK|NOSPLIT, $-8
        EONW    $0x6006000060060, R5                // EONW     $1689262177517664, R5           // 1b0c8052db00a072a5003b4a
        ORNW    $0x6006000060060, R5                // ORNW     $1689262177517664, R5           // 1b0c8052db00a072a5003b2a
        BICSW   $0x6006000060060, R5                // BICSW    $1689262177517664, R5           // 1b0c8052db00a072a5003b6a
+       AND     $1, ZR                              // fb0340b2ff031b8a
+       ANDW    $1, ZR                              // fb030032ff031b0a
        // TODO: this could have better encoding
        ANDW    $-1, R10                            // 1b0080124a011b0a
        AND     $8, R0, RSP                         // 1f007d92
@@ -369,9 +371,9 @@ TEXT        foo(SB), DUPOK|NOSPLIT, $-8
        MOVD    $-1, R1                       // 01008092
        MOVD    $0x210000, R0                 // MOVD   $2162688, R0                // 2004a0d2
        MOVD    $0xffffffffffffaaaa, R1       // MOVD   $-21846, R1                 // a1aa8a92
-       MOVW    $1, ZR
+       MOVW    $1, ZR                        // 3f008052
        MOVW    $1, R1
-       MOVD    $1, ZR
+       MOVD    $1, ZR                        // 3f0080d2
        MOVD    $1, R1
        MOVK    $1, R1
        MOVD    $0x1000100010001000, RSP      // MOVD   $1152939097061330944, RSP   // ff8304b2
@@ -386,10 +388,10 @@ TEXT      foo(SB), DUPOK|NOSPLIT, $-8
        VMOVQ   $0x8040201008040202, $0x7040201008040201, V20         // VMOVQ  $-9205322385119247870, $8088500183983456769, V20
 
 // mov(to/from sp)
-       MOVD    $0x1002(RSP), R1              // MOVD   $4098(RSP), R1              // fb074091610b0091
-       MOVD    $0x1708(RSP), RSP             // MOVD   $5896(RSP), RSP             // fb0740917f231c91
-       MOVD    $0x2001(R7), R1               // MOVD   $8193(R7), R1               // fb08409161070091
-       MOVD    $0xffffff(R7), R1             // MOVD   $16777215(R7), R1           // fbfc7f9161ff3f91
+       MOVD    $0x1002(RSP), R1              // MOVD   $4098(RSP), R1              // e107409121080091
+       MOVD    $0x1708(RSP), RSP             // MOVD   $5896(RSP), RSP             // ff074091ff231c91
+       MOVD    $0x2001(R7), R1               // MOVD   $8193(R7), R1               // e108409121040091
+       MOVD    $0xffffff(R7), R1             // MOVD   $16777215(R7), R1           // e1fc7f9121fc3f91
        MOVD    $-0x1(R7), R1                 // MOVD   $-1(R7), R1                 // e10400d1
        MOVD    $-0x30(R7), R1                // MOVD   $-48(R7), R1                // e1c000d1
        MOVD    $-0x708(R7), R1               // MOVD   $-1800(R7), R1              // e1201cd1
index cf57179e43016156cf148dcbd001c54d5620b00e..3d3de1d9b13770ba9efbd403359a7b0a1abac0d6 100644 (file)
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 TEXT errors(SB),$0
-       AND     $1, RSP                                          // ERROR "illegal combination"
+       AND     $1, RSP                                          // ERROR "illegal source register"
        ANDS    $1, R0, RSP                                      // ERROR "illegal combination"
        ADDSW   R7->32, R14, R13                                 // ERROR "shift amount out of range 0 to 31"
        ADD     R1.UXTB<<5, R2, R3                               // ERROR "shift amount out of range 0 to 4"
@@ -406,12 +406,12 @@ TEXT errors(SB),$0
        VBIF    V0.D2, V1.D2, V2.D2                              // ERROR "invalid arrangement"
        VUADDW  V9.B8, V12.H8, V14.B8                            // ERROR "invalid arrangement"
        VUADDW2 V9.B8, V12.S4, V14.S4                            // ERROR "operand mismatch"
-       VUMAX   V1.D2, V2.D2, V3.D2                              // ERROR "invalid arrangement"
-       VUMIN   V1.D2, V2.D2, V3.D2                              // ERROR "invalid arrangement"
+       VUMAX   V1.D2, V2.D2, V3.D2                              // ERROR "invalid arrangement"
+       VUMIN   V1.D2, V2.D2, V3.D2                              // ERROR "invalid arrangement"
        VUMAX   V1.B8, V2.B8, V3.B16                             // ERROR "operand mismatch"
        VUMIN   V1.H4, V2.S4, V3.H4                              // ERROR "operand mismatch"
        VSLI    $64, V7.D2, V8.D2                                // ERROR "shift out of range"
-       VUSRA   $0, V7.D2, V8.D2                                 // ERROR "shift out of range"
+       VUSRA   $0, V7.D2, V8.D2                                 // ERROR "shift out of range"
        CASPD   (R3, R4), (R2), (R8, R9)                         // ERROR "source register pair must start from even register"
        CASPD   (R2, R3), (R2), (R9, R10)                        // ERROR "destination register pair must start from even register"
        CASPD   (R2, R4), (R2), (R8, R9)                         // ERROR "source register pair must be contiguous"
@@ -419,4 +419,17 @@ TEXT errors(SB),$0
        ADD     R1>>2, RSP, R3                                   // ERROR "illegal combination"
        ADDS    R2<<3, R3, RSP                                   // ERROR "unexpected SP reference"
        CMP     R1<<5, RSP                                       // ERROR "the left shift amount out of range 0 to 4"
+       MOVD.P  y+8(FP), R1                                      // ERROR "illegal combination"
+       MOVD.W  x-8(SP), R1                                      // ERROR "illegal combination"
+       LDP.P   x+8(FP), (R0, R1)                                // ERROR "illegal combination"
+       LDP.W   x+8(SP), (R0, R1)                                // ERROR "illegal combination"
+       ADD     $0x1234567, R27, R3                              // ERROR "cannot use REGTMP as source"
+       ADD     $0x3fffffffc000, R27, R5                         // ERROR "cannot use REGTMP as source"
+       AND     $0x22220000, R27, R4                             // ERROR "cannot use REGTMP as source"
+       ANDW    $0x6006000060060, R27, R5                        // ERROR "cannot use REGTMP as source"
+       STP     (R3, R4), 0x1234567(R27)                         // ERROR "REGTMP used in large offset store"
+       LDP     0x1234567(R27), (R3, R4)                         // ERROR "REGTMP used in large offset load"
+       STP     (R26, R27), 700(R2)                              // ERROR "cannot use REGTMP as source"
+       MOVK    $0, R10                                          // ERROR "zero shifts cannot be handled correctly"
+       MOVK    $(0<<32), R10                                    // ERROR "zero shifts cannot be handled correctly"
        RET
index b6c0aa5035c013652dcd7df91505d78cfd9ac6a7..c140fd025a64e8117754db20842bffe3e714b3ff 100644 (file)
@@ -342,14 +342,14 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        NOP F2
        NOP $4
 
-       CRAND CR1, CR2, CR3             // 4c620a02
-       CRANDN CR1, CR2, CR3            // 4c620902
-       CREQV CR1, CR2, CR3             // 4c620a42
-       CRNAND CR1, CR2, CR3            // 4c6209c2
-       CRNOR CR1, CR2, CR3             // 4c620842
-       CROR CR1, CR2, CR3              // 4c620b82
-       CRORN CR1, CR2, CR3             // 4c620b42
-       CRXOR CR1, CR2, CR3             // 4c620982
+       CRAND CR0GT, CR0EQ, CR0SO       // 4c620a02
+       CRANDN CR0GT, CR0EQ, CR0SO      // 4c620902
+       CREQV CR0GT, CR0EQ, CR0SO       // 4c620a42
+       CRNAND CR0GT, CR0EQ, CR0SO      // 4c6209c2
+       CRNOR CR0GT, CR0EQ, CR0SO       // 4c620842
+       CROR CR0GT, CR0EQ, CR0SO        // 4c620b82
+       CRORN CR0GT, CR0EQ, CR0SO       // 4c620b42
+       CRXOR CR0GT, CR0EQ, CR0SO       // 4c620982
 
        ISEL $1, R3, R4, R5             // 7ca3205e
        ISEL $0, R3, R4, R5             // 7ca3201e
@@ -649,6 +649,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        LXVB16X (R3)(R4), VS1           // 7c241ed8
        LXVW4X (R3)(R4), VS1            // 7c241e18
        LXV 16(R3), VS1                 // f4230011
+       LXV 16(R3), VS33                // f4230019
+       LXV 16(R3), V1                  // f4230019
        LXVL R3, R4, VS1                // 7c23221a
        LXVLL R3, R4, VS1               // 7c23225a
        LXVX R3, R4, VS1                // 7c232218
@@ -668,8 +670,13 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        MTFPRD R3, F0                   // 7c030166
        MFVRD V0, R3                    // 7c030067
        MFVSRLD VS63,R4                 // 7fe40267
+       MFVSRLD V31,R4                  // 7fe40267
        MFVSRWZ VS33,R4                 // 7c2400e7
+       MFVSRWZ V1,R4                   // 7c2400e7
        MTVSRD R3, VS1                  // 7c230166
+       MTVSRDD R3, R4, VS1             // 7c232366
+       MTVSRDD R3, R4, VS33            // 7c232367
+       MTVSRDD R3, R4, V1              // 7c232367
        MTVRD R3, V13                   // 7da30167
        MTVSRWA R4, VS31                // 7fe401a6
        MTVSRWS R4, VS32                // 7c040327
@@ -678,6 +685,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        XXBRW VS1, VS2                  // f04f0f6c
        XXBRH VS2, VS3                  // f067176c
        XXLAND VS1, VS2, VS3            // f0611410
+       XXLAND V1, V2, V3               // f0611417
+       XXLAND VS33, VS34, VS35         // f0611417
        XXLANDC VS1, VS2, VS3           // f0611450
        XXLEQV VS0, VS1, VS2            // f0400dd0
        XXLNAND VS0, VS1, VS2           // f0400d90
@@ -687,11 +696,17 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        XXLORQ VS1, VS2, VS3            // f0611490
        XXLXOR VS1, VS2, VS3            // f06114d0
        XXSEL VS1, VS2, VS3, VS4        // f08110f0
+       XXSEL VS33, VS34, VS35, VS36    // f08110ff
+       XXSEL V1, V2, V3, V4            // f08110ff
        XXMRGHW VS1, VS2, VS3           // f0611090
        XXMRGLW VS1, VS2, VS3           // f0611190
        XXSPLTW VS1, $1, VS2            // f0410a90
+       XXSPLTW VS33, $1, VS34          // f0410a93
+       XXSPLTW V1, $1, V2              // f0410a93
        XXPERM VS1, VS2, VS3            // f06110d0
        XXSLDWI VS1, VS2, $1, VS3       // f0611110
+       XXSLDWI V1, V2, $1, V3          // f0611117
+       XXSLDWI VS33, VS34, $1, VS35    // f0611117
        XSCVDPSP VS1, VS2               // f0400c24
        XVCVDPSP VS1, VS2               // f0400e24
        XSCVSXDDP VS1, VS2              // f0400de0
@@ -736,4 +751,17 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
        MOVD XER, R3                    // 7c6102a6
        MOVFL CR3, CR1                  // 4c8c0000
 
+       MOVW CR0, R1                    // 7c380026
+       MOVW CR7, R1                    // 7c301026
+       MOVW CR, R1                     // 7c200026
+
+       MOVW R1, CR                     // 7c2ff120
+       MOVFL R1, CR                    // 7c2ff120
+       MOVW R1, CR2                    // 7c320120
+       MOVFL R1, CR2                   // 7c320120
+       MOVFL R1, $255                  // 7c2ff120
+       MOVFL R1, $1                    // 7c301120
+       MOVFL R1, $128                  // 7c380120
+       MOVFL R1, $3                    // 7c203120
+
        RET
index 77c0764c48117a78132e0407837c45dc7194b208..fe911a74f5da6d85c1bf95a7c50678c3ca9cdf37 100644 (file)
@@ -10,20 +10,35 @@ start:
 
        // 2.4: Integer Computational Instructions
 
-       ADDI    $2047, X5, X6                           // 1383f27f
-       ADDI    $-2048, X5, X6                          // 13830280
        ADDI    $2047, X5                               // 9382f27f
        ADDI    $-2048, X5                              // 93820280
+       ADDI    $2048, X5                               // 9382024093820240
+       ADDI    $-2049, X5                              // 938202c09382f2bf
+       ADDI    $4094, X5                               // 9382f27f9382f27f
+       ADDI    $-4096, X5                              // 9382028093820280
+       ADDI    $4095, X5                               // b71f00009b8fffffb382f201
+       ADDI    $-4097, X5                              // b7ffffff9b8fffffb382f201
+       ADDI    $2047, X5, X6                           // 1383f27f
+       ADDI    $-2048, X5, X6                          // 13830280
+       ADDI    $2048, X5, X6                           // 1383024013030340
+       ADDI    $-2049, X5, X6                          // 138302c01303f3bf
+       ADDI    $4094, X5, X6                           // 1383f27f1303f37f
+       ADDI    $-4096, X5, X6                          // 1383028013030380
+       ADDI    $4095, X5, X6                           // b71f00009b8fffff3383f201
+       ADDI    $-4097, X5, X6                          // b7ffffff9b8fffff3383f201
 
        SLTI    $55, X5, X7                             // 93a37203
        SLTIU   $55, X5, X7                             // 93b37203
 
        ANDI    $1, X5, X6                              // 13f31200
        ANDI    $1, X5                                  // 93f21200
+       ANDI    $2048, X5                               // b71f00009b8f0f80b3f2f201
        ORI     $1, X5, X6                              // 13e31200
        ORI     $1, X5                                  // 93e21200
+       ORI     $2048, X5                               // b71f00009b8f0f80b3e2f201
        XORI    $1, X5, X6                              // 13c31200
        XORI    $1, X5                                  // 93c21200
+       XORI    $2048, X5                               // b71f00009b8f0f80b3c2f201
 
        SLLI    $1, X5, X6                              // 13931200
        SLLI    $1, X5                                  // 93921200
@@ -86,20 +101,15 @@ start:
        SRA     $1, X5                                  // 93d21240
 
        // 2.5: Control Transfer Instructions
-
-       // These jumps and branches get printed as a jump or branch
-       // to 2 because they transfer control to the second instruction
-       // in the function (the first instruction being an invisible
-       // stack pointer adjustment).
-       JAL     X5, start       // JAL  X5, 2           // eff25ff0
+       JAL     X5, 2(PC)                               // ef028000
        JALR    X6, (X5)                                // 67830200
        JALR    X6, 4(X5)                               // 67834200
-       BEQ     X5, X6, start   // BEQ  X5, X6, 2       // e38c62ee
-       BNE     X5, X6, start   // BNE  X5, X6, 2       // e39a62ee
-       BLT     X5, X6, start   // BLT  X5, X6, 2       // e3c862ee
-       BLTU    X5, X6, start   // BLTU X5, X6, 2       // e3e662ee
-       BGE     X5, X6, start   // BGE  X5, X6, 2       // e3d462ee
-       BGEU    X5, X6, start   // BGEU X5, X6, 2       // e3f262ee
+       BEQ     X5, X6, 2(PC)                           // 63846200
+       BNE     X5, X6, 2(PC)                           // 63946200
+       BLT     X5, X6, 2(PC)                           // 63c46200
+       BLTU    X5, X6, 2(PC)                           // 63e46200
+       BGE     X5, X6, 2(PC)                           // 63d46200
+       BGEU    X5, X6, 2(PC)                           // 63f46200
 
        // 2.6: Load and Store Instructions
        LW      (X5), X6                                // 03a30200
@@ -219,6 +229,10 @@ start:
        FMVSX   X5, F0                                  // 538002f0
        FMVXW   F0, X5                                  // d30200e0
        FMVWX   X5, F0                                  // 538002f0
+       FMADDS  F1, F2, F3, F4                          // 43822018
+       FMSUBS  F1, F2, F3, F4                          // 47822018
+       FNMSUBS F1, F2, F3, F4                          // 4b822018
+       FNMADDS F1, F2, F3, F4                          // 4f822018
 
        // 11.8: Single-Precision Floating-Point Compare Instructions
        FEQS    F0, F1, X7                              // d3a300a0
@@ -259,6 +273,10 @@ start:
        FSGNJXD F1, F0, F2                              // 53211022
        FMVXD   F0, X5                                  // d30200e2
        FMVDX   X5, F0                                  // 538002f2
+       FMADDD  F1, F2, F3, F4                          // 4382201a
+       FMSUBD  F1, F2, F3, F4                          // 4782201a
+       FNMSUBD F1, F2, F3, F4                          // 4b82201a
+       FNMADDD F1, F2, F3, F4                          // 4f82201a
 
        // 12.6: Double-Precision Floating-Point Classify Instruction
        FCLASSD F0, X5                                  // d31200e2
@@ -277,11 +295,17 @@ start:
 
        // MOV pseudo-instructions
        MOV     X5, X6                                  // 13830200
-       MOV     $2047, X5                               // 9b02f07f
-       MOV     $-2048, X5                              // 9b020080
-
-       // Converted to load of symbol.
-       MOV     $4294967296, X5                         // 97020000
+       MOV     $2047, X5                               // 9302f07f
+       MOV     $-2048, X5                              // 93020080
+       MOV     $2048, X5                               // b71200009b820280
+       MOV     $-2049, X5                              // b7f2ffff9b82f27f
+       MOV     $4096, X5                               // b7120000
+       MOV     $2147479552, X5                         // b7f2ff7f
+       MOV     $2147483647, X5                         // b70200809b82f2ff
+       MOV     $-2147483647, X5                        // b70200809b821200
+
+       // Converted to load of symbol (AUIPC + LD)
+       MOV     $4294967296, X5                         // 9702000083b20200
 
        MOV     (X5), X6                                // 03b30200
        MOV     4(X5), X6                               // 03b34200
@@ -325,42 +349,44 @@ start:
        NEGW    X5                                      // bb025040
        NEGW    X5, X6                                  // 3b035040
 
-       // These jumps can get printed as jumps to 2 because they go to the
-       // second instruction in the function (the first instruction is an
-       // invisible stack pointer adjustment).
-       JMP     start           // JMP  2               // 6ff01fc2
+       // This jumps to the second instruction in the function (the
+       // first instruction is an invisible stack pointer adjustment).
+       JMP     start                                   // JMP  2
+
+       JMP     2(PC)                                   // 6f008000
        JMP     (X5)                                    // 67800200
        JMP     4(X5)                                   // 67804200
 
-       // JMP and CALL to symbol are encoded as:
-       //      AUIPC $0, TMP
-       //      JALR $0, TMP
-       // with a R_RISCV_PCREL_ITYPE relocation - the linker resolves the
-       // real address and updates the immediates for both instructions.
-       CALL    asmtest(SB)                             // 970f0000
-       JMP     asmtest(SB)                             // 970f0000
+       // CALL and JMP to symbol are encoded as JAL (using LR or ZERO
+       // respectively), with a R_RISCV_CALL relocation. The linker resolves
+       // the real address and updates the immediate, using a trampoline in
+       // the case where the address is not directly reachable.
+       CALL    asmtest(SB)                             // ef000000
+       JMP     asmtest(SB)                             // 6f000000
 
        // Branch pseudo-instructions
-       BEQZ    X5, start       // BEQZ X5, 2           // e38202c0
-       BGEZ    X5, start       // BGEZ X5, 2           // e3d002c0
-       BGT     X5, X6, start   // BGT  X5, X6, 2       // e34e53be
-       BGTU    X5, X6, start   // BGTU X5, X6, 2       // e36c53be
-       BGTZ    X5, start       // BGTZ X5, 2           // e34a50be
-       BLE     X5, X6, start   // BLE  X5, X6, 2       // e35853be
-       BLEU    X5, X6, start   // BLEU X5, X6, 2       // e37653be
-       BLEZ    X5, start       // BLEZ X5, 2           // e35450be
-       BLTZ    X5, start       // BLTZ X5, 2           // e3c202be
-       BNEZ    X5, start       // BNEZ X5, 2           // e39002be
+       BEQZ    X5, 2(PC)                               // 63840200
+       BGEZ    X5, 2(PC)                               // 63d40200
+       BGT     X5, X6, 2(PC)                           // 63445300
+       BGTU    X5, X6, 2(PC)                           // 63645300
+       BGTZ    X5, 2(PC)                               // 63445000
+       BLE     X5, X6, 2(PC)                           // 63545300
+       BLEU    X5, X6, 2(PC)                           // 63745300
+       BLEZ    X5, 2(PC)                               // 63545000
+       BLTZ    X5, 2(PC)                               // 63c40200
+       BNEZ    X5, 2(PC)                               // 63940200
 
        // Set pseudo-instructions
        SEQZ    X15, X15                                // 93b71700
        SNEZ    X15, X15                                // b337f000
 
        // F extension
+       FABSS   F0, F1                                  // d3200020
        FNEGS   F0, F1                                  // d3100020
        FNES    F0, F1, X7                              // d3a300a093c31300
 
        // D extension
+       FABSD   F0, F1                                  // d3200022
        FNEGD   F0, F1                                  // d3100022
        FNED    F0, F1, X5                              // d3a200a293c21200
        FLTD    F0, F1, X5                              // d39200a2
index fb43e68fc1740b131328778f0612ccf99455674f..238552565bdd2f6fe1fe1f9769f7020403a6a5a7 100644 (file)
@@ -3,6 +3,14 @@
 // license that can be found in the LICENSE file.
 
 TEXT errors(SB),$0
+       MOV     $errors(SB), (X5)               // ERROR "address load must target register"
+       MOV     $8(SP), (X5)                    // ERROR "address load must target register"
+       MOVB    $8(SP), X5                      // ERROR "unsupported address load"
+       MOVH    $8(SP), X5                      // ERROR "unsupported address load"
+       MOVW    $8(SP), X5                      // ERROR "unsupported address load"
+       MOVF    $8(SP), X5                      // ERROR "unsupported address load"
+       MOV     $1234, 0(SP)                    // ERROR "constant load must target register"
+       MOV     $1234, 8(SP)                    // ERROR "constant load must target register"
        MOV     $0, 0(SP)                       // ERROR "constant load must target register"
        MOV     $0, 8(SP)                       // ERROR "constant load must target register"
        MOV     $1234, 0(SP)                    // ERROR "constant load must target register"
@@ -11,4 +19,8 @@ TEXT errors(SB),$0
        MOVH    $1, X5                          // ERROR "unsupported constant load"
        MOVW    $1, X5                          // ERROR "unsupported constant load"
        MOVF    $1, X5                          // ERROR "unsupported constant load"
+       MOVBU   X5, (X6)                        // ERROR "unsupported unsigned store"
+       MOVHU   X5, (X6)                        // ERROR "unsupported unsigned store"
+       MOVWU   X5, (X6)                        // ERROR "unsupported unsigned store"
+
        RET
index dd947c7b5ba5b805d4319d78fe432cafdbf1faad..607166e664d90fef67494671f45038e80e9fb6ed 100644 (file)
@@ -28,6 +28,10 @@ var (
        CompilingRuntime = flag.Bool("compiling-runtime", false, "source to be compiled is part of the Go runtime")
 )
 
+var DebugFlags struct {
+       MayMoreStack string `help:"call named function before all stack growth checks"`
+}
+
 var (
        D        MultiFlag
        I        MultiFlag
@@ -39,6 +43,7 @@ func init() {
        flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifier=value; can be set multiple times")
        flag.Var(&I, "I", "include directory; can be set multiple times")
        flag.BoolVar(&DebugV, "v", false, "print debug output")
+       flag.Var(objabi.NewDebugFlag(&DebugFlags, nil), "d", "enable debugging settings; try -d help")
        objabi.AddVersionFlag() // -V
        objabi.Flagcount("S", "print assembly and machine code", &PrintOut)
 }
index 043bc696e58ae2fb0fdd74bcc0e5cdcfe9bb7a39..3683527f5b8e582fdecac1fb1dbfa315de5956e9 100644 (file)
@@ -29,19 +29,20 @@ func main() {
        buildcfg.Check()
        GOARCH := buildcfg.GOARCH
 
-       architecture := arch.Set(GOARCH)
+       flags.Parse()
+
+       architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink)
        if architecture == nil {
                log.Fatalf("unrecognized architecture %s", GOARCH)
        }
 
-       flags.Parse()
-
        ctxt := obj.Linknew(architecture.LinkArch)
        ctxt.Debugasm = flags.PrintOut
        ctxt.Debugvlog = flags.DebugV
        ctxt.Flag_dynlink = *flags.Dynlink
        ctxt.Flag_linkshared = *flags.Linkshared
        ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
+       ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack
        ctxt.IsAsm = true
        ctxt.Pkgpath = *flags.Importpath
        switch *flags.Spectre {
index a073407a961e15af2a7b4cbe92afd925712e82b3..28879e349c49cf371b40a7fb0d09f2e4b285f549 100644 (file)
@@ -338,8 +338,7 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
 
        // everything else just recurs
        default:
-               error_(token.NoPos, "unexpected type %T in walk", x)
-               panic("unexpected type")
+               f.walkUnexpected(x, context, visit)
 
        case nil:
 
diff --git a/src/cmd/cgo/ast_go1.go b/src/cmd/cgo/ast_go1.go
new file mode 100644 (file)
index 0000000..f52bf00
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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:build compiler_bootstrap
+// +build compiler_bootstrap
+
+package main
+
+import (
+       "go/token"
+)
+
+func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
+       error_(token.NoPos, "unexpected type %T in walk", x)
+       panic("unexpected type")
+}
diff --git a/src/cmd/cgo/ast_go118.go b/src/cmd/cgo/ast_go118.go
new file mode 100644 (file)
index 0000000..db0108e
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2021 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:build !compiler_bootstrap
+// +build !compiler_bootstrap
+
+package main
+
+import (
+       "go/ast"
+       "go/token"
+)
+
+func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
+       switch n := x.(type) {
+       default:
+               error_(token.NoPos, "unexpected type %T in walk", x)
+               panic("unexpected type")
+
+       case *ast.IndexListExpr:
+               f.walk(&n.X, ctxExpr, visit)
+               f.walk(n.Indices, ctxExpr, visit)
+       }
+}
index a73e998877af812762afcc4716c17b78adf7f065..997a830994f09bdd6118299e31e20125cadff3ff 100644 (file)
@@ -23,10 +23,13 @@ import (
        "internal/xcoff"
        "math"
        "os"
+       "os/exec"
        "strconv"
        "strings"
        "unicode"
        "unicode/utf8"
+
+       "cmd/internal/quoted"
 )
 
 var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
@@ -382,7 +385,7 @@ func (p *Package) guessKinds(f *File) []*Name {
                stderr = p.gccErrors(b.Bytes())
        }
        if stderr == "" {
-               fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
+               fatalf("%s produced no output\non input:\n%s", gccBaseCmd[0], b.Bytes())
        }
 
        completed := false
@@ -457,7 +460,7 @@ func (p *Package) guessKinds(f *File) []*Name {
        }
 
        if !completed {
-               fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
+               fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", gccBaseCmd[0], b.Bytes(), stderr)
        }
 
        for i, n := range names {
@@ -488,7 +491,7 @@ func (p *Package) guessKinds(f *File) []*Name {
                // to users debugging preamble mistakes. See issue 8442.
                preambleErrors := p.gccErrors([]byte(f.Preamble))
                if len(preambleErrors) > 0 {
-                       error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
+                       error_(token.NoPos, "\n%s errors for preamble:\n%s", gccBaseCmd[0], preambleErrors)
                }
 
                fatalf("unresolved names")
@@ -1503,7 +1506,7 @@ func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
                                Args: []ast.Expr{getNewIdent(name.Mangle)},
                        }
                case "type":
-                       // Okay - might be new(T)
+                       // Okay - might be new(T), T(x), Generic[T], etc.
                        if r.Name.Type == nil {
                                error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
                        }
@@ -1545,20 +1548,37 @@ func gofmtPos(n ast.Expr, pos token.Pos) string {
        return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
 }
 
-// gccBaseCmd returns the start of the compiler command line.
+// checkGCCBaseCmd returns the start of the compiler command line.
 // It uses $CC if set, or else $GCC, or else the compiler recorded
 // during the initial build as defaultCC.
 // defaultCC is defined in zdefaultcc.go, written by cmd/dist.
-func (p *Package) gccBaseCmd() []string {
+//
+// The compiler command line is split into arguments on whitespace. Quotes
+// are understood, so arguments may contain whitespace.
+//
+// checkGCCBaseCmd confirms that the compiler exists in PATH, returning
+// an error if it does not.
+func checkGCCBaseCmd() ([]string, error) {
        // Use $CC if set, since that's what the build uses.
-       if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
-               return ret
+       value := os.Getenv("CC")
+       if value == "" {
+               // Try $GCC if set, since that's what we used to use.
+               value = os.Getenv("GCC")
+       }
+       if value == "" {
+               value = defaultCC(goos, goarch)
        }
-       // Try $GCC if set, since that's what we used to use.
-       if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
-               return ret
+       args, err := quoted.Split(value)
+       if err != nil {
+               return nil, err
        }
-       return strings.Fields(defaultCC(goos, goarch))
+       if len(args) == 0 {
+               return nil, errors.New("CC not set and no default found")
+       }
+       if _, err := exec.LookPath(args[0]); err != nil {
+               return nil, fmt.Errorf("C compiler %q not found: %v", args[0], err)
+       }
+       return args[:len(args):len(args)], nil
 }
 
 // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
@@ -1604,7 +1624,7 @@ func gccTmp() string {
 // gccCmd returns the gcc command line to use for compiling
 // the input.
 func (p *Package) gccCmd() []string {
-       c := append(p.gccBaseCmd(),
+       c := append(gccBaseCmd,
                "-w",          // no warnings
                "-Wno-error",  // warnings are not errors
                "-o"+gccTmp(), // write object to tmp
@@ -2005,7 +2025,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
 // #defines that gcc encountered while processing the input
 // and its included files.
 func (p *Package) gccDefines(stdin []byte) string {
-       base := append(p.gccBaseCmd(), "-E", "-dM", "-xc")
+       base := append(gccBaseCmd, "-E", "-dM", "-xc")
        base = append(base, p.gccMachine()...)
        stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
        return stdout
@@ -2086,6 +2106,9 @@ type typeConv struct {
        // Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
        getTypeIDs map[string]bool
 
+       // badStructs contains C structs that should be marked NotInHeap.
+       notInHeapStructs map[string]bool
+
        // Predeclared types.
        bool                                   ast.Expr
        byte                                   ast.Expr // denotes padding
@@ -2097,6 +2120,7 @@ type typeConv struct {
        string                                 ast.Expr
        goVoid                                 ast.Expr // _Ctype_void, denotes C's void
        goVoidPtr                              ast.Expr // unsafe.Pointer or *byte
+       goVoidPtrNoHeap                        ast.Expr // *_Ctype_void_notinheap, like goVoidPtr but marked NotInHeap
 
        ptrSize int64
        intSize int64
@@ -2120,6 +2144,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
        c.m = make(map[string]*Type)
        c.ptrs = make(map[string][]*Type)
        c.getTypeIDs = make(map[string]bool)
+       c.notInHeapStructs = make(map[string]bool)
        c.bool = c.Ident("bool")
        c.byte = c.Ident("byte")
        c.int8 = c.Ident("int8")
@@ -2138,6 +2163,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
        c.void = c.Ident("void")
        c.string = c.Ident("string")
        c.goVoid = c.Ident("_Ctype_void")
+       c.goVoidPtrNoHeap = c.Ident("*_Ctype_void_notinheap")
 
        // Normally cgo translates void* to unsafe.Pointer,
        // but for historical reasons -godefs uses *byte instead.
@@ -2518,6 +2544,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
                                tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
                        }
                        tt.Go = g
+                       tt.NotInHeap = c.notInHeapStructs[tag]
                        typedef[name.Name] = &tt
                }
 
@@ -2561,6 +2588,30 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
                                oldType.BadPointer = true
                        }
                }
+               if c.badVoidPointerTypedef(dt) {
+                       // Treat this typedef as a pointer to a NotInHeap void.
+                       s := *sub
+                       s.Go = c.goVoidPtrNoHeap
+                       sub = &s
+                       // Make sure we update any previously computed type.
+                       if oldType := typedef[name.Name]; oldType != nil {
+                               oldType.Go = sub.Go
+                       }
+               }
+               // Check for non-pointer "struct <tag>{...}; typedef struct <tag> *<name>"
+               // typedefs that should be marked NotInHeap.
+               if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
+                       if strct, ok := ptr.Type.(*dwarf.StructType); ok {
+                               if c.badStructPointerTypedef(dt.Name, strct) {
+                                       c.notInHeapStructs[strct.StructName] = true
+                                       // Make sure we update any previously computed type.
+                                       name := "_Ctype_struct_" + strct.StructName
+                                       if oldType := typedef[name]; oldType != nil {
+                                               oldType.NotInHeap = true
+                                       }
+                               }
+                       }
+               }
                t.Go = name
                t.BadPointer = sub.BadPointer
                t.NotInHeap = sub.NotInHeap
@@ -3010,6 +3061,31 @@ func upper(s string) string {
 // so that all fields are exported.
 func godefsFields(fld []*ast.Field) {
        prefix := fieldPrefix(fld)
+
+       // Issue 48396: check for duplicate field names.
+       if prefix != "" {
+               names := make(map[string]bool)
+       fldLoop:
+               for _, f := range fld {
+                       for _, n := range f.Names {
+                               name := n.Name
+                               if name == "_" {
+                                       continue
+                               }
+                               if name != prefix {
+                                       name = strings.TrimPrefix(n.Name, prefix)
+                               }
+                               name = upper(name)
+                               if names[name] {
+                                       // Field name conflict: don't remove prefix.
+                                       prefix = ""
+                                       break fldLoop
+                               }
+                               names[name] = true
+                       }
+               }
+       }
+
        npad := 0
        for _, f := range fld {
                for _, n := range f.Names {
@@ -3087,6 +3163,48 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
        return false
 }
 
+// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be NotInHeap.
+func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
+       // Match the Windows HANDLE type (#42018).
+       if goos != "windows" || dt.Name != "HANDLE" {
+               return false
+       }
+       // 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
+               }
+       }
+       return false
+}
+
+// badStructPointerTypedef is like badVoidPointerTypedefs but for structs.
+func (c *typeConv) badStructPointerTypedef(name string, dt *dwarf.StructType) bool {
+       // Windows handle types can all potentially contain non-pointers.
+       // badVoidPointerTypedef handles the "void *" HANDLE type, but other
+       // handles are defined as
+       //
+       // struct <name>__{int unused;}; typedef struct <name>__ *name;
+       //
+       // by the DECLARE_HANDLE macro in STRICT mode. The macro is declared in
+       // the Windows ntdef.h header,
+       //
+       // https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/ntdef.h#L779
+       if goos != "windows" {
+               return false
+       }
+       if len(dt.Field) != 1 {
+               return false
+       }
+       if dt.StructName != name+"__" {
+               return false
+       }
+       if f := dt.Field[0]; f.Name != "unused" || f.Type.Common().Name != "int" {
+               return false
+       }
+       return true
+}
+
 // baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
 // as badPointerTypedef reports.
 func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
index c6a0c525e64f212bd51bb7a5eb317e46a085ffbc..14642b7576b0122e0252960c498fe9ed11a21826 100644 (file)
@@ -21,7 +21,6 @@ import (
        "io"
        "io/ioutil"
        "os"
-       "os/exec"
        "path/filepath"
        "reflect"
        "runtime"
@@ -248,6 +247,7 @@ var importSyscall = flag.Bool("import_syscall", true, "import syscall in generat
 var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
 
 var goarch, goos, gomips, gomips64 string
+var gccBaseCmd []string
 
 func main() {
        objabi.AddVersionFlag() // -V
@@ -305,10 +305,10 @@ func main() {
        p := newPackage(args[:i])
 
        // We need a C compiler to be available. Check this.
-       gccName := p.gccBaseCmd()[0]
-       _, err := exec.LookPath(gccName)
+       var err error
+       gccBaseCmd, err = checkGCCBaseCmd()
        if err != nil {
-               fatalf("C compiler %q not found: %v", gccName, err)
+               fatalf("%v", err)
                os.Exit(2)
        }
 
index 94152f4278cb04b44325a936c50d8d11887f4b3d..4968f7059d9bd6e13789d84798f7b38d7deb4d71 100644 (file)
@@ -59,9 +59,9 @@ func (p *Package) writeDefs() {
        // Write C main file for using gcc to resolve imports.
        fmt.Fprintf(fm, "int main() { return 0; }\n")
        if *importRuntimeCgo {
-               fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
+               fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), __SIZE_TYPE__ ctxt __attribute__((unused))) { }\n")
                fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
-               fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
+               fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt __attribute__((unused))) { }\n")
                fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
        } else {
                // If we're not importing runtime/cgo, we *are* runtime/cgo,
@@ -70,8 +70,8 @@ func (p *Package) writeDefs() {
                fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
                fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
        }
-       fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
-       fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
+       fmt.Fprintf(fm, "void _cgo_allocate(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
+       fmt.Fprintf(fm, "void _cgo_panic(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
        fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
 
        // Write second Go output: definitions of _C_xxx.
@@ -135,6 +135,7 @@ func (p *Package) writeDefs() {
                fmt.Fprintf(fgo2, "%s", buf.Bytes())
                fmt.Fprintf(fgo2, "\n\n")
        }
+       fmt.Fprintf(fgo2, "//go:notinheap\ntype _Ctype_void_notinheap struct{}\n\n")
        if *gccgo {
                fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
        } else {
@@ -1054,9 +1055,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 
                fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
 
+               fmt.Fprintf(fgo2, "\t")
+
                if gccResult != "void" {
                        // Write results back to frame.
-                       fmt.Fprintf(fgo2, "\t")
                        forFieldList(fntype.Results,
                                func(i int, aname string, atype ast.Expr) {
                                        if i > 0 {
@@ -1458,10 +1460,10 @@ const gccProlog = `
   (have a negative array count) and an inscrutable error will come
   out of the compiler and hopefully mention "name".
 */
-#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
+#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2UL+1UL];
 
 /* Check at compile time that the sizes we use match our expectations. */
-#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
+#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), (size_t)n, _cgo_sizeof_##t##_is_not_##n)
 
 __cgo_size_assert(char, 1)
 __cgo_size_assert(short, 2)
index 3619aea4aa261e622633ab426c3ccaaa6b0e791d..50d8ed9159460d510d448cacc23a6ea502c8f012 100644 (file)
@@ -627,6 +627,105 @@ modifying or saving the FPCR.
 Functions are allowed to modify it between calls (as long as they
 restore it), but as of this writing Go code never does.
 
+### ppc64 architecture
+
+The ppc64 architecture uses R3 – R10 and R14 – R17 for integer arguments
+and results.
+
+It uses F1 – F12 for floating-point arguments and results.
+
+Register R31 is a permanent scratch register in Go.
+
+Special-purpose registers used within Go generated code and Go
+assembly code are as follows:
+
+| Register | Call meaning | Return meaning | Body meaning |
+| --- | --- | --- | --- |
+| R0  | Zero value | Same | Same |
+| R1  | Stack pointer | Same | Same |
+| R2  | TOC register | Same | Same |
+| R11 | Closure context pointer | Scratch | Scratch |
+| R12 | Function address on indirect calls | Scratch | Scratch |
+| R13 | TLS pointer | Same | Same |
+| R20,R21 | Scratch | Scratch | Used by duffcopy, duffzero |
+| R30 | Current goroutine | Same | Same |
+| R31 | Scratch | Scratch | Scratch |
+| LR  | Link register | Link register | Scratch |
+*Rationale*: These register meanings are compatible with Go’s
+stack-based calling convention.
+
+The link register, LR, holds the function return
+address at the function entry and is set to the correct return
+address before exiting the function. It is also used
+in some cases as the function address when doing an indirect call.
+
+The register R2 contains the address of the TOC (table of contents) which
+contains data or code addresses used when generating position independent
+code. Non-Go code generated when using cgo contains TOC-relative addresses
+which depend on R2 holding a valid TOC. Go code compiled with -shared or
+-dynlink initializes and maintains R2 and uses it in some cases for
+function calls; Go code compiled without these options does not modify R2.
+
+When making a function call R12 contains the function address for use by the
+code to generate R2 at the beginning of the function. R12 can be used for
+other purposes within the body of the function, such as trampoline generation.
+
+R20 and R21 are used in duffcopy and duffzero which could be generated
+before arguments are saved so should not be used for register arguments.
+
+The Count register CTR can be used as the call target for some branch instructions.
+It holds the return address when preemption has occurred.
+
+On PPC64 when a float32 is loaded it becomes a float64 in the register, which is
+different from other platforms and that needs to be recognized by the internal
+implementation of reflection so that float32 arguments are passed correctly.
+
+Registers R18 - R29 and F13 - F31 are considered scratch registers.
+
+#### Stack layout
+
+The stack pointer, R1, grows down and is aligned to 8 bytes in Go, but changed
+to 16 bytes when calling cgo.
+
+A function's stack frame, after the frame is created, is laid out as
+follows:
+
+    +------------------------------+
+    | ... locals ...               |
+    | ... outgoing arguments ...   |
+    | 24  TOC register R2 save     | When compiled with -shared/-dynlink
+    | 16  Unused in Go             | Not used in Go
+    |  8  CR save                  | nonvolatile CR fields
+    |  0  return PC                | ← R1 points to
+    +------------------------------+ ↓ lower addresses
+
+The "return PC" is loaded to the link register, LR, as part of the
+ppc64 `BL` operations.
+
+On entry to a non-leaf function, the stack frame size is subtracted from R1 to
+create its stack frame, and saves the value of LR at the bottom of the frame.
+
+A leaf function that does not require any stack space does not modify R1 and
+does not save LR.
+
+*NOTE*: We might need to save the frame pointer on the stack as
+in the PPC64 ELF v2 ABI so Go can inter-operate with platform debuggers
+and profilers.
+
+This stack layout is used by both register-based (ABIInternal) and
+stack-based (ABI0) calling conventions.
+
+#### Flags
+
+The condition register consists of 8 condition code register fields
+CR0-CR7. Go generated code only sets and uses CR0, commonly set by
+compare functions and use to determine the target of a conditional
+branch. The generated code does not set or use CR1-CR7.
+
+The floating point status and control register (FPSCR) is initialized
+to 0 by the kernel at startup of the Go program and not changed by
+the Go generated code.
+
 ## Future directions
 
 ### Spill path improvements
index b68ef274f379e0fa932b54307afafb0b8db1cfdf..ef7fa86749f0137d03c949a08dcf504cb58bb56f 100644 (file)
@@ -44,6 +44,8 @@ Flags:
                Print compiler version and exit.
        -asmhdr file
                Write assembly header to file.
+       -asan
+               Insert calls to C/C++ address sanitizer.
        -buildid id
                Record id as the build id in the export metadata.
        -blockprofile file
index d657ddc867bad00f44a00a3e9af54b7507b99683..74c8707b298aa2fdbf6254cb2f599d7f15833525 100644 (file)
@@ -144,7 +144,7 @@ func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64)
 }
 
 func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type {
-       w := t.Width
+       w := t.Size()
        if w == 0 {
                return rts
        }
@@ -193,12 +193,12 @@ func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type {
 // to input offsets, and returns the longer slice and the next unused offset.
 func appendParamOffsets(offsets []int64, at int64, t *types.Type) ([]int64, int64) {
        at = align(at, t)
-       w := t.Width
+       w := t.Size()
        if w == 0 {
                return offsets, at
        }
        if t.IsScalar() || t.IsPtrShaped() {
-               if t.IsComplex() || int(t.Width) > types.RegSize { // complex and *int64 on 32-bit
+               if t.IsComplex() || int(t.Size()) > types.RegSize { // complex and *int64 on 32-bit
                        s := w / 2
                        return append(offsets, at, at+s), at + w
                } else {
@@ -214,7 +214,7 @@ func appendParamOffsets(offsets []int64, at int64, t *types.Type) ([]int64, int6
                case types.TSTRUCT:
                        for i, f := range t.FieldSlice() {
                                offsets, at = appendParamOffsets(offsets, at, f.Type)
-                               if f.Type.Width == 0 && i == t.NumFields()-1 {
+                               if f.Type.Size() == 0 && i == t.NumFields()-1 {
                                        at++ // last field has zero width
                                }
                        }
@@ -531,7 +531,7 @@ type assignState struct {
 
 // align returns a rounded up to t's alignment
 func align(a int64, t *types.Type) int64 {
-       return alignTo(a, int(t.Align))
+       return alignTo(a, int(uint8(t.Alignment())))
 }
 
 // alignTo returns a rounded up to t, where t must be 0 or a power of 2.
@@ -546,7 +546,7 @@ func alignTo(a int64, t int) int64 {
 // specified type.
 func (state *assignState) stackSlot(t *types.Type) int64 {
        rv := align(state.stackOffset, t)
-       state.stackOffset = rv + t.Width
+       state.stackOffset = rv + t.Size()
        return rv
 }
 
@@ -554,7 +554,7 @@ func (state *assignState) stackSlot(t *types.Type) int64 {
 // that we've just determined to be register-assignable. The number of registers
 // needed is assumed to be stored in state.pUsed.
 func (state *assignState) allocateRegs(regs []RegIndex, t *types.Type) []RegIndex {
-       if t.Width == 0 {
+       if t.Size() == 0 {
                return regs
        }
        ri := state.rUsed.intRegs
@@ -647,7 +647,7 @@ func (state *assignState) floatUsed() int {
 // can register allocate, FALSE otherwise (and updates state
 // accordingly).
 func (state *assignState) regassignIntegral(t *types.Type) bool {
-       regsNeeded := int(types.Rnd(t.Width, int64(types.PtrSize)) / int64(types.PtrSize))
+       regsNeeded := int(types.Rnd(t.Size(), int64(types.PtrSize)) / int64(types.PtrSize))
        if t.IsComplex() {
                regsNeeded = 2
        }
@@ -722,14 +722,17 @@ func setup() {
                        types.NewField(nxp, fname("len"), ui),
                        types.NewField(nxp, fname("cap"), ui),
                })
+               types.CalcStructSize(synthSlice)
                synthString = types.NewStruct(types.NoPkg, []*types.Field{
                        types.NewField(nxp, fname("data"), unsp),
                        types.NewField(nxp, fname("len"), ui),
                })
+               types.CalcStructSize(synthString)
                synthIface = types.NewStruct(types.NoPkg, []*types.Field{
                        types.NewField(nxp, fname("f1"), unsp),
                        types.NewField(nxp, fname("f2"), unsp),
                })
+               types.CalcStructSize(synthIface)
        })
 }
 
@@ -764,10 +767,10 @@ func (state *assignState) regassign(pt *types.Type) bool {
 // ABIParamResultInfo held in 'state'.
 func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, isReturn bool) ABIParamAssignment {
        state.pUsed = RegAmounts{}
-       if pt.Width == types.BADWIDTH {
+       if pt.Size() == types.BADWIDTH {
                base.Fatalf("should never happen")
                panic("unreachable")
-       } else if pt.Width == 0 {
+       } else if pt.Size() == 0 {
                return state.stackAllocate(pt, n)
        } else if state.regassign(pt) {
                return state.regAllocate(pt, n, isReturn)
@@ -777,11 +780,11 @@ func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, is
 }
 
 // ComputePadding returns a list of "post element" padding values in
-// the case where we have a structure being passed in registers. Give
-// a param assignment corresponding to a struct, it returns a list of
-// contaning padding values for each field, e.g. the Kth element in
+// the case where we have a structure being passed in registers. Given
+// a param assignment corresponding to a struct, it returns a list
+// containing padding values for each field, e.g. the Kth element in
 // the list is the amount of padding between field K and the following
-// field. For things that are not struct (or structs without padding)
+// field. For things that are not structs (or structs without padding)
 // it returns a list of zeros. Example:
 //
 // type small struct {
@@ -793,8 +796,8 @@ func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, is
 //
 // For this struct we would return a list [0, 1, 0, 0], meaning that
 // we have one byte of padding after the second field, and no bytes of
-// padding after any of the other fields. Input parameter "storage"
-// is with enough capacity to accommodate padding elements for
+// padding after any of the other fields. Input parameter "storage" is
+// a slice with enough capacity to accommodate padding elements for
 // the architected register set in question.
 func (pa *ABIParamAssignment) ComputePadding(storage []uint64) []uint64 {
        nr := len(pa.Registers)
index 30dba057d011a142bf3014a33a098c2773d8a1dc..b0e5c34030f32b9d6b62159a7fef03e4dc3a5e80 100644 (file)
@@ -263,6 +263,24 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Reg = lo
                p.SetFrom3Reg(hi)
 
+       case ssa.OpAMD64BLSIQ, ssa.OpAMD64BLSIL,
+               ssa.OpAMD64BLSMSKQ, ssa.OpAMD64BLSMSKL,
+               ssa.OpAMD64BLSRQ, ssa.OpAMD64BLSRL,
+               ssa.OpAMD64TZCNTQ, ssa.OpAMD64TZCNTL:
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = v.Args[0].Reg()
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = v.Reg()
+
+       case ssa.OpAMD64ANDNQ, ssa.OpAMD64ANDNL:
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = v.Args[0].Reg()
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = v.Reg()
+               p.SetFrom3Reg(v.Args[1].Reg())
+
        case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU:
                // Arg[0] (the dividend) is in AX.
                // Arg[1] (the divisor) can be in any other register.
@@ -600,8 +618,21 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Reg = r
                p.SetFrom3Reg(v.Args[0].Reg())
 
+       case ssa.OpAMD64ANDQconst:
+               asm := v.Op.Asm()
+               // If the constant is positive and fits into 32 bits, use ANDL.
+               // This saves a few bytes of encoding.
+               if 0 <= v.AuxInt && v.AuxInt <= (1<<32-1) {
+                       asm = x86.AANDL
+               }
+               p := s.Prog(asm)
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = v.AuxInt
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = v.Reg()
+
        case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst,
-               ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst,
+               ssa.OpAMD64ANDLconst,
                ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst,
                ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst,
                ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst,
@@ -741,7 +772,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Val = math.Float64frombits(uint64(v.AuxInt))
                p.To.Type = obj.TYPE_REG
                p.To.Reg = x
-       case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVOload:
+       case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVOload,
+               ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVLQSXload,
+               ssa.OpAMD64MOVBEQload, ssa.OpAMD64MOVBELload:
                p := s.Prog(v.Op.Asm())
                p.From.Type = obj.TYPE_MEM
                p.From.Reg = v.Args[0].Reg()
@@ -757,7 +790,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Reg = v.Reg()
        case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore,
                ssa.OpAMD64ADDQmodify, ssa.OpAMD64SUBQmodify, ssa.OpAMD64ANDQmodify, ssa.OpAMD64ORQmodify, ssa.OpAMD64XORQmodify,
-               ssa.OpAMD64ADDLmodify, ssa.OpAMD64SUBLmodify, ssa.OpAMD64ANDLmodify, ssa.OpAMD64ORLmodify, ssa.OpAMD64XORLmodify:
+               ssa.OpAMD64ADDLmodify, ssa.OpAMD64SUBLmodify, ssa.OpAMD64ANDLmodify, ssa.OpAMD64ORLmodify, ssa.OpAMD64XORLmodify,
+               ssa.OpAMD64MOVBEQstore, ssa.OpAMD64MOVBELstore:
                p := s.Prog(v.Op.Asm())
                p.From.Type = obj.TYPE_REG
                p.From.Reg = v.Args[1].Reg()
@@ -822,7 +856,12 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Type = obj.TYPE_MEM
                p.To.Reg = v.Args[0].Reg()
                ssagen.AddAux2(&p.To, v, sc.Off64())
-       case ssa.OpAMD64MOVOstorezero:
+       case ssa.OpAMD64MOVOstoreconst:
+               sc := v.AuxValAndOff()
+               if sc.Val() != 0 {
+                       v.Fatalf("MOVO for non zero constants not implemented: %s", v.LongString())
+               }
+
                if s.ABI != obj.ABIInternal {
                        // zero X15 manually
                        opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
@@ -832,7 +871,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Reg = x86.REG_X15
                p.To.Type = obj.TYPE_MEM
                p.To.Reg = v.Args[0].Reg()
-               ssagen.AddAux(&p.To, v)
+               ssagen.AddAux2(&p.To, v, sc.Off64())
+
        case ssa.OpAMD64MOVQstoreconstidx1, ssa.OpAMD64MOVQstoreconstidx8, ssa.OpAMD64MOVLstoreconstidx1, ssa.OpAMD64MOVLstoreconstidx4, ssa.OpAMD64MOVWstoreconstidx1, ssa.OpAMD64MOVWstoreconstidx2, ssa.OpAMD64MOVBstoreconstidx1,
                ssa.OpAMD64ADDLconstmodifyidx1, ssa.OpAMD64ADDLconstmodifyidx4, ssa.OpAMD64ADDLconstmodifyidx8, ssa.OpAMD64ADDQconstmodifyidx1, ssa.OpAMD64ADDQconstmodifyidx8,
                ssa.OpAMD64ANDLconstmodifyidx1, ssa.OpAMD64ANDLconstmodifyidx4, ssa.OpAMD64ANDLconstmodifyidx8, ssa.OpAMD64ANDQconstmodifyidx1, ssa.OpAMD64ANDQconstmodifyidx8,
@@ -1002,7 +1042,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                }
                r := v.Reg()
                getgFromTLS(s, r)
-       case ssa.OpAMD64CALLstatic:
+       case ssa.OpAMD64CALLstatic, ssa.OpAMD64CALLtail:
                if s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal {
                        // zeroing X15 when entering ABIInternal from ABI0
                        if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9
@@ -1011,6 +1051,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                        // set G register from TLS
                        getgFromTLS(s, x86.REG_R14)
                }
+               if v.Op == ssa.OpAMD64CALLtail {
+                       s.TailCall(v)
+                       break
+               }
                s.Call(v)
                if s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 {
                        // zeroing X15 when entering ABIInternal from ABI0
@@ -1097,7 +1141,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                if v.Args[0].Reg() != v.Reg() {
                        // POPCNT on Intel has a false dependency on the destination register.
                        // Xor register with itself to break the dependency.
-                       p := s.Prog(x86.AXORQ)
+                       p := s.Prog(x86.AXORL)
                        p.From.Type = obj.TYPE_REG
                        p.From.Reg = v.Reg()
                        p.To.Type = obj.TYPE_REG
@@ -1225,6 +1269,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Type = obj.TYPE_MEM
                p.To.Reg = v.Args[0].Reg()
                ssagen.AddAux(&p.To, v)
+       case ssa.OpAMD64PrefetchT0, ssa.OpAMD64PrefetchNTA:
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_MEM
+               p.From.Reg = v.Args[0].Reg()
        case ssa.OpClobber:
                p := s.Prog(x86.AMOVL)
                p.From.Type = obj.TYPE_CONST
@@ -1304,22 +1352,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        p.To.Type = obj.TYPE_BRANCH
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
        case ssa.BlockRet:
                s.Prog(obj.ARET)
-       case ssa.BlockRetJmp:
-               if s.ABI == obj.ABI0 && b.Aux.(*obj.LSym).ABI() == obj.ABIInternal {
-                       // zeroing X15 when entering ABIInternal from ABI0
-                       if buildcfg.GOOS != "plan9" { // do not use SSE on Plan 9
-                               opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
-                       }
-                       // set G register from TLS
-                       getgFromTLS(s, x86.REG_R14)
-               }
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
 
        case ssa.BlockAMD64EQF:
                s.CombJump(b, next, &eqfJumps)
diff --git a/src/cmd/compile/internal/amd64/versions_test.go b/src/cmd/compile/internal/amd64/versions_test.go
new file mode 100644 (file)
index 0000000..ee1a8ca
--- /dev/null
@@ -0,0 +1,383 @@
+// Copyright 2021 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 amd64_test
+
+import (
+       "bufio"
+       "debug/elf"
+       "debug/macho"
+       "fmt"
+       "internal/testenv"
+       "io"
+       "math"
+       "math/bits"
+       "os"
+       "os/exec"
+       "regexp"
+       "runtime"
+       "strconv"
+       "strings"
+       "testing"
+)
+
+// Test to make sure that when building for GOAMD64=v1, we don't
+// use any >v1 instructions.
+func TestGoAMD64v1(t *testing.T) {
+       if runtime.GOARCH != "amd64" {
+               t.Skip("amd64-only test")
+       }
+       if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
+               t.Skip("test only works on elf or macho platforms")
+       }
+       if v := os.Getenv("GOAMD64"); v != "" && v != "v1" {
+               // Test runs only on v1 (which is the default).
+               // TODO: use build tags from #45454 instead.
+               t.Skip("GOAMD64 already set")
+       }
+       if os.Getenv("TESTGOAMD64V1") != "" {
+               t.Skip("recursive call")
+       }
+
+       // Make a binary which will be a modified version of the
+       // currently running binary.
+       dst, err := os.CreateTemp("", "TestGoAMD64v1")
+       if err != nil {
+               t.Fatalf("failed to create temp file: %v", err)
+       }
+       defer os.Remove(dst.Name())
+       dst.Chmod(0500) // make executable
+
+       // Clobber all the non-v1 opcodes.
+       opcodes := map[string]bool{}
+       var features []string
+       for feature, opcodeList := range featureToOpcodes {
+               if runtimeFeatures[feature] {
+                       features = append(features, fmt.Sprintf("cpu.%s=off", feature))
+               }
+               for _, op := range opcodeList {
+                       opcodes[op] = true
+               }
+       }
+       clobber(t, os.Args[0], dst, opcodes)
+       if err = dst.Close(); err != nil {
+               t.Fatalf("can't close binary: %v", err)
+       }
+
+       // Run the resulting binary.
+       cmd := exec.Command(dst.Name())
+       testenv.CleanCmdEnv(cmd)
+       cmd.Env = append(cmd.Env, "TESTGOAMD64V1=yes")
+       cmd.Env = append(cmd.Env, fmt.Sprintf("GODEBUG=%s", strings.Join(features, ",")))
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Fatalf("couldn't execute test: %s", err)
+       }
+       if string(out) != "PASS\n" {
+               t.Fatalf("test reported error: %s", string(out))
+       }
+}
+
+// Clobber copies the binary src to dst, replacing all the instructions in opcodes with
+// faulting instructions.
+func clobber(t *testing.T, src string, dst *os.File, opcodes map[string]bool) {
+       // Run objdump to get disassembly.
+       var re *regexp.Regexp
+       var disasm io.Reader
+       if false {
+               // TODO: go tool objdump doesn't disassemble the bmi1 instructions
+               // in question correctly. See issue 48584.
+               cmd := exec.Command("go", "tool", "objdump", src)
+               var err error
+               disasm, err = cmd.StdoutPipe()
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if err := cmd.Start(); err != nil {
+                       t.Fatal(err)
+               }
+               re = regexp.MustCompile(`^[^:]*:[-0-9]+\s+0x([0-9a-f]+)\s+([0-9a-f]+)\s+([A-Z]+)`)
+       } else {
+               // TODO: we're depending on platform-native objdump here. Hence the Skipf
+               // below if it doesn't run for some reason.
+               cmd := exec.Command("objdump", "-d", src)
+               var err error
+               disasm, err = cmd.StdoutPipe()
+               if err != nil {
+                       t.Skipf("can't run test due to missing objdump: %s", err)
+               }
+               if err := cmd.Start(); err != nil {
+                       t.Fatal(err)
+               }
+               re = regexp.MustCompile(`^\s*([0-9a-f]+):\s*((?:[0-9a-f][0-9a-f] )+)\s*([a-z0-9]+)`)
+       }
+
+       // Find all the instruction addresses we need to edit.
+       virtualEdits := map[uint64]bool{}
+       scanner := bufio.NewScanner(disasm)
+       for scanner.Scan() {
+               line := scanner.Text()
+               parts := re.FindStringSubmatch(line)
+               if len(parts) == 0 {
+                       continue
+               }
+               addr, err := strconv.ParseUint(parts[1], 16, 64)
+               if err != nil {
+                       continue // not a hex address
+               }
+               opcode := strings.ToLower(parts[3])
+               if !opcodes[opcode] {
+                       continue
+               }
+               t.Logf("clobbering instruction %s", line)
+               n := (len(parts[2]) - strings.Count(parts[2], " ")) / 2 // number of bytes in instruction encoding
+               for i := 0; i < n; i++ {
+                       // Only really need to make the first byte faulting, but might
+                       // as well make all the bytes faulting.
+                       virtualEdits[addr+uint64(i)] = true
+               }
+       }
+
+       // Figure out where in the binary the edits must be done.
+       physicalEdits := map[uint64]bool{}
+       if e, err := elf.Open(src); err == nil {
+               for _, sec := range e.Sections {
+                       vaddr := sec.Addr
+                       paddr := sec.Offset
+                       size := sec.Size
+                       for a := range virtualEdits {
+                               if a >= vaddr && a < vaddr+size {
+                                       physicalEdits[paddr+(a-vaddr)] = true
+                               }
+                       }
+               }
+       } else if m, err2 := macho.Open(src); err2 == nil {
+               for _, sec := range m.Sections {
+                       vaddr := sec.Addr
+                       paddr := uint64(sec.Offset)
+                       size := sec.Size
+                       for a := range virtualEdits {
+                               if a >= vaddr && a < vaddr+size {
+                                       physicalEdits[paddr+(a-vaddr)] = true
+                               }
+                       }
+               }
+       } else {
+               t.Log(err)
+               t.Log(err2)
+               t.Fatal("executable format not elf or macho")
+       }
+       if len(virtualEdits) != len(physicalEdits) {
+               t.Fatal("couldn't find an instruction in text sections")
+       }
+
+       // Copy source to destination, making edits along the way.
+       f, err := os.Open(src)
+       if err != nil {
+               t.Fatal(err)
+       }
+       r := bufio.NewReader(f)
+       w := bufio.NewWriter(dst)
+       a := uint64(0)
+       done := 0
+       for {
+               b, err := r.ReadByte()
+               if err == io.EOF {
+                       break
+               }
+               if err != nil {
+                       t.Fatal("can't read")
+               }
+               if physicalEdits[a] {
+                       b = 0xcc // INT3 opcode
+                       done++
+               }
+               err = w.WriteByte(b)
+               if err != nil {
+                       t.Fatal("can't write")
+               }
+               a++
+       }
+       if done != len(physicalEdits) {
+               t.Fatal("physical edits remaining")
+       }
+       w.Flush()
+       f.Close()
+}
+
+func setOf(keys ...string) map[string]bool {
+       m := make(map[string]bool, len(keys))
+       for _, key := range keys {
+               m[key] = true
+       }
+       return m
+}
+
+var runtimeFeatures = setOf(
+       "adx", "aes", "avx", "avx2", "bmi1", "bmi2", "erms", "fma",
+       "pclmulqdq", "popcnt", "rdtscp", "sse3", "sse41", "sse42", "ssse3",
+)
+
+var featureToOpcodes = map[string][]string{
+       // Note: we include *q, *l, and plain opcodes here.
+       // go tool objdump doesn't include a [QL] on popcnt instructions, until CL 351889
+       // native objdump doesn't include [QL] on linux.
+       "popcnt": {"popcntq", "popcntl", "popcnt"},
+       "bmi1":   {"andnq", "andnl", "andn", "blsiq", "blsil", "blsi", "blsmskq", "blsmskl", "blsmsk", "blsrq", "blsrl", "blsr", "tzcntq", "tzcntl", "tzcnt"},
+       "sse41":  {"roundsd"},
+       "fma":    {"vfmadd231sd"},
+       "movbe":  {"movbeqq", "movbeq", "movbell", "movbel", "movbe"},
+}
+
+// Test to use POPCNT instruction, if available
+func TestPopCnt(t *testing.T) {
+       for _, tt := range []struct {
+               x    uint64
+               want int
+       }{
+               {0b00001111, 4},
+               {0b00001110, 3},
+               {0b00001100, 2},
+               {0b00000000, 0},
+       } {
+               if got := bits.OnesCount64(tt.x); got != tt.want {
+                       t.Errorf("OnesCount64(%#x) = %d, want %d", tt.x, got, tt.want)
+               }
+               if got := bits.OnesCount32(uint32(tt.x)); got != tt.want {
+                       t.Errorf("OnesCount32(%#x) = %d, want %d", tt.x, got, tt.want)
+               }
+       }
+}
+
+// Test to use ANDN, if available
+func TestAndNot(t *testing.T) {
+       for _, tt := range []struct {
+               x, y, want uint64
+       }{
+               {0b00001111, 0b00000011, 0b1100},
+               {0b00001111, 0b00001100, 0b0011},
+               {0b00000000, 0b00000000, 0b0000},
+       } {
+               if got := tt.x &^ tt.y; got != tt.want {
+                       t.Errorf("%#x &^ %#x = %#x, want %#x", tt.x, tt.y, got, tt.want)
+               }
+               if got := uint32(tt.x) &^ uint32(tt.y); got != uint32(tt.want) {
+                       t.Errorf("%#x &^ %#x = %#x, want %#x", tt.x, tt.y, got, tt.want)
+               }
+       }
+}
+
+// Test to use BLSI, if available
+func TestBLSI(t *testing.T) {
+       for _, tt := range []struct {
+               x, want uint64
+       }{
+               {0b00001111, 0b001},
+               {0b00001110, 0b010},
+               {0b00001100, 0b100},
+               {0b11000110, 0b010},
+               {0b00000000, 0b000},
+       } {
+               if got := tt.x & -tt.x; got != tt.want {
+                       t.Errorf("%#x & (-%#x) = %#x, want %#x", tt.x, tt.x, got, tt.want)
+               }
+               if got := uint32(tt.x) & -uint32(tt.x); got != uint32(tt.want) {
+                       t.Errorf("%#x & (-%#x) = %#x, want %#x", tt.x, tt.x, got, tt.want)
+               }
+       }
+}
+
+// Test to use BLSMSK, if available
+func TestBLSMSK(t *testing.T) {
+       for _, tt := range []struct {
+               x, want uint64
+       }{
+               {0b00001111, 0b001},
+               {0b00001110, 0b011},
+               {0b00001100, 0b111},
+               {0b11000110, 0b011},
+               {0b00000000, 1<<64 - 1},
+       } {
+               if got := tt.x ^ (tt.x - 1); got != tt.want {
+                       t.Errorf("%#x ^ (%#x-1) = %#x, want %#x", tt.x, tt.x, got, tt.want)
+               }
+               if got := uint32(tt.x) ^ (uint32(tt.x) - 1); got != uint32(tt.want) {
+                       t.Errorf("%#x ^ (%#x-1) = %#x, want %#x", tt.x, tt.x, got, uint32(tt.want))
+               }
+       }
+}
+
+// Test to use BLSR, if available
+func TestBLSR(t *testing.T) {
+       for _, tt := range []struct {
+               x, want uint64
+       }{
+               {0b00001111, 0b00001110},
+               {0b00001110, 0b00001100},
+               {0b00001100, 0b00001000},
+               {0b11000110, 0b11000100},
+               {0b00000000, 0b00000000},
+       } {
+               if got := tt.x & (tt.x - 1); got != tt.want {
+                       t.Errorf("%#x & (%#x-1) = %#x, want %#x", tt.x, tt.x, got, tt.want)
+               }
+               if got := uint32(tt.x) & (uint32(tt.x) - 1); got != uint32(tt.want) {
+                       t.Errorf("%#x & (%#x-1) = %#x, want %#x", tt.x, tt.x, got, tt.want)
+               }
+       }
+}
+
+func TestTrailingZeros(t *testing.T) {
+       for _, tt := range []struct {
+               x    uint64
+               want int
+       }{
+               {0b00001111, 0},
+               {0b00001110, 1},
+               {0b00001100, 2},
+               {0b00001000, 3},
+               {0b00000000, 64},
+       } {
+               if got := bits.TrailingZeros64(tt.x); got != tt.want {
+                       t.Errorf("TrailingZeros64(%#x) = %d, want %d", tt.x, got, tt.want)
+               }
+               want := tt.want
+               if want == 64 {
+                       want = 32
+               }
+               if got := bits.TrailingZeros32(uint32(tt.x)); got != want {
+                       t.Errorf("TrailingZeros64(%#x) = %d, want %d", tt.x, got, want)
+               }
+       }
+}
+
+func TestRound(t *testing.T) {
+       for _, tt := range []struct {
+               x, want float64
+       }{
+               {1.4, 1},
+               {1.5, 2},
+               {1.6, 2},
+               {2.4, 2},
+               {2.5, 2},
+               {2.6, 3},
+       } {
+               if got := math.RoundToEven(tt.x); got != tt.want {
+                       t.Errorf("RoundToEven(%f) = %f, want %f", tt.x, got, tt.want)
+               }
+       }
+}
+
+func TestFMA(t *testing.T) {
+       for _, tt := range []struct {
+               x, y, z, want float64
+       }{
+               {2, 3, 4, 10},
+               {3, 4, 5, 17},
+       } {
+               if got := math.FMA(tt.x, tt.y, tt.z); got != tt.want {
+                       t.Errorf("FMA(%f,%f,%f) = %f, want %f", tt.x, tt.y, tt.z, got, tt.want)
+               }
+       }
+}
index 4b083cec46b4a5cff59981de626a75f62fc0e1b7..063fb65b33ab90bf7e56f5f681a1a32ec959487e 100644 (file)
@@ -88,15 +88,18 @@ func (v shift) String() string {
 }
 
 // makeshift encodes a register shifted by a constant
-func makeshift(reg int16, typ int64, s int64) shift {
+func makeshift(v *ssa.Value, reg int16, typ int64, s int64) shift {
+       if s < 0 || s >= 32 {
+               v.Fatalf("shift out of range: %d", s)
+       }
        return shift(int64(reg&0xf) | typ | (s&31)<<7)
 }
 
 // genshift generates a Prog for r = r0 op (r1 shifted by n)
-func genshift(s *ssagen.State, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
+func genshift(s *ssagen.State, v *ssa.Value, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
        p := s.Prog(as)
        p.From.Type = obj.TYPE_SHIFT
-       p.From.Offset = int64(makeshift(r1, typ, n))
+       p.From.Offset = int64(makeshift(v, r1, typ, n))
        p.Reg = r0
        if r != 0 {
                p.To.Type = obj.TYPE_REG
@@ -335,7 +338,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg0()
        case ssa.OpARMSRRconst:
-               genshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
+               genshift(s, v, arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
        case ssa.OpARMADDshiftLL,
                ssa.OpARMADCshiftLL,
                ssa.OpARMSUBshiftLL,
@@ -346,11 +349,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARMORshiftLL,
                ssa.OpARMXORshiftLL,
                ssa.OpARMBICshiftLL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
        case ssa.OpARMADDSshiftLL,
                ssa.OpARMSUBSshiftLL,
                ssa.OpARMRSBSshiftLL:
-               p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt)
+               p := genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt)
                p.Scond = arm.C_SBIT
        case ssa.OpARMADDshiftRL,
                ssa.OpARMADCshiftRL,
@@ -362,11 +365,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARMORshiftRL,
                ssa.OpARMXORshiftRL,
                ssa.OpARMBICshiftRL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
        case ssa.OpARMADDSshiftRL,
                ssa.OpARMSUBSshiftRL,
                ssa.OpARMRSBSshiftRL:
-               p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt)
+               p := genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt)
                p.Scond = arm.C_SBIT
        case ssa.OpARMADDshiftRA,
                ssa.OpARMADCshiftRA,
@@ -378,20 +381,20 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARMORshiftRA,
                ssa.OpARMXORshiftRA,
                ssa.OpARMBICshiftRA:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
        case ssa.OpARMADDSshiftRA,
                ssa.OpARMSUBSshiftRA,
                ssa.OpARMRSBSshiftRA:
-               p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt)
+               p := genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt)
                p.Scond = arm.C_SBIT
        case ssa.OpARMXORshiftRR:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
        case ssa.OpARMMVNshiftLL:
-               genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
        case ssa.OpARMMVNshiftRL:
-               genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
        case ssa.OpARMMVNshiftRA:
-               genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
        case ssa.OpARMMVNshiftLLreg:
                genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL)
        case ssa.OpARMMVNshiftRLreg:
@@ -513,11 +516,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Type = obj.TYPE_REG
                p.From.Reg = v.Args[0].Reg()
        case ssa.OpARMCMPshiftLL, ssa.OpARMCMNshiftLL, ssa.OpARMTSTshiftLL, ssa.OpARMTEQshiftLL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt)
        case ssa.OpARMCMPshiftRL, ssa.OpARMCMNshiftRL, ssa.OpARMTSTshiftRL, ssa.OpARMTEQshiftRL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt)
        case ssa.OpARMCMPshiftRA, ssa.OpARMCMNshiftRA, ssa.OpARMTSTshiftRA, ssa.OpARMTEQshiftRA:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt)
        case ssa.OpARMCMPshiftLLreg, ssa.OpARMCMNshiftLLreg, ssa.OpARMTSTshiftLLreg, ssa.OpARMTEQshiftLLreg:
                genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LL)
        case ssa.OpARMCMPshiftRLreg, ssa.OpARMCMNshiftRLreg, ssa.OpARMTSTshiftRLreg, ssa.OpARMTEQshiftRLreg:
@@ -583,13 +586,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                // this is just shift 0 bits
                fallthrough
        case ssa.OpARMMOVWloadshiftLL:
-               p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
+               p := genshift(s, v, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
                p.From.Reg = v.Args[0].Reg()
        case ssa.OpARMMOVWloadshiftRL:
-               p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
+               p := genshift(s, v, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
                p.From.Reg = v.Args[0].Reg()
        case ssa.OpARMMOVWloadshiftRA:
-               p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
+               p := genshift(s, v, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
                p.From.Reg = v.Args[0].Reg()
        case ssa.OpARMMOVWstoreidx, ssa.OpARMMOVBstoreidx, ssa.OpARMMOVHstoreidx:
                // this is just shift 0 bits
@@ -600,21 +603,21 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Reg = v.Args[2].Reg()
                p.To.Type = obj.TYPE_SHIFT
                p.To.Reg = v.Args[0].Reg()
-               p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LL, v.AuxInt))
+               p.To.Offset = int64(makeshift(v, v.Args[1].Reg(), arm.SHIFT_LL, v.AuxInt))
        case ssa.OpARMMOVWstoreshiftRL:
                p := s.Prog(v.Op.Asm())
                p.From.Type = obj.TYPE_REG
                p.From.Reg = v.Args[2].Reg()
                p.To.Type = obj.TYPE_SHIFT
                p.To.Reg = v.Args[0].Reg()
-               p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LR, v.AuxInt))
+               p.To.Offset = int64(makeshift(v, v.Args[1].Reg(), arm.SHIFT_LR, v.AuxInt))
        case ssa.OpARMMOVWstoreshiftRA:
                p := s.Prog(v.Op.Asm())
                p.From.Type = obj.TYPE_REG
                p.From.Reg = v.Args[2].Reg()
                p.To.Type = obj.TYPE_SHIFT
                p.To.Reg = v.Args[0].Reg()
-               p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_AR, v.AuxInt))
+               p.To.Offset = int64(makeshift(v, v.Args[1].Reg(), arm.SHIFT_AR, v.AuxInt))
        case ssa.OpARMMOVBreg,
                ssa.OpARMMOVBUreg,
                ssa.OpARMMOVHreg,
@@ -645,7 +648,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                }
                if buildcfg.GOARM >= 6 {
                        // generate more efficient "MOVB/MOVBU/MOVH/MOVHU Reg@>0, Reg" on ARMv6 & ARMv7
-                       genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, 0)
+                       genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, 0)
                        return
                }
                fallthrough
@@ -696,6 +699,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Reg = v.Reg()
        case ssa.OpARMCALLstatic, ssa.OpARMCALLclosure, ssa.OpARMCALLinter:
                s.Call(v)
+       case ssa.OpARMCALLtail:
+               s.TailCall(v)
        case ssa.OpARMCALLudiv:
                p := s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
@@ -936,17 +941,11 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
 
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
 
        case ssa.BlockRet:
                s.Prog(obj.ARET)
 
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
-
        case ssa.BlockARMEQ, ssa.BlockARMNE,
                ssa.BlockARMLT, ssa.BlockARMGE,
                ssa.BlockARMLE, ssa.BlockARMGT,
index c3319f949122bd14faf95c5317f39b62f2ffa5d1..96a29224bf71d50b0201457ae965f54a55381eb6 100644 (file)
@@ -79,15 +79,18 @@ func storeByType(t *types.Type) obj.As {
 }
 
 // makeshift encodes a register shifted by a constant, used as an Offset in Prog
-func makeshift(reg int16, typ int64, s int64) int64 {
+func makeshift(v *ssa.Value, reg int16, typ int64, s int64) int64 {
+       if s < 0 || s >= 64 {
+               v.Fatalf("shift out of range: %d", s)
+       }
        return int64(reg&31)<<16 | typ | (s&63)<<10
 }
 
 // genshift generates a Prog for r = r0 op (r1 shifted by n)
-func genshift(s *ssagen.State, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
+func genshift(s *ssagen.State, v *ssa.Value, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
        p := s.Prog(as)
        p.From.Type = obj.TYPE_SHIFT
-       p.From.Offset = makeshift(r1, typ, n)
+       p.From.Offset = makeshift(v, r1, typ, n)
        p.Reg = r0
        if r != 0 {
                p.To.Type = obj.TYPE_REG
@@ -310,11 +313,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg()
        case ssa.OpARM64MVNshiftLL, ssa.OpARM64NEGshiftLL:
-               genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
        case ssa.OpARM64MVNshiftRL, ssa.OpARM64NEGshiftRL:
-               genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
        case ssa.OpARM64MVNshiftRA, ssa.OpARM64NEGshiftRA:
-               genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
+       case ssa.OpARM64MVNshiftRO:
+               genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_ROR, v.AuxInt)
        case ssa.OpARM64ADDshiftLL,
                ssa.OpARM64SUBshiftLL,
                ssa.OpARM64ANDshiftLL,
@@ -323,7 +328,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARM64EONshiftLL,
                ssa.OpARM64ORNshiftLL,
                ssa.OpARM64BICshiftLL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
        case ssa.OpARM64ADDshiftRL,
                ssa.OpARM64SUBshiftRL,
                ssa.OpARM64ANDshiftRL,
@@ -332,7 +337,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARM64EONshiftRL,
                ssa.OpARM64ORNshiftRL,
                ssa.OpARM64BICshiftRL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
        case ssa.OpARM64ADDshiftRA,
                ssa.OpARM64SUBshiftRA,
                ssa.OpARM64ANDshiftRA,
@@ -341,7 +346,14 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARM64EONshiftRA,
                ssa.OpARM64ORNshiftRA,
                ssa.OpARM64BICshiftRA:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
+       case ssa.OpARM64ANDshiftRO,
+               ssa.OpARM64ORshiftRO,
+               ssa.OpARM64XORshiftRO,
+               ssa.OpARM64EONshiftRO,
+               ssa.OpARM64ORNshiftRO,
+               ssa.OpARM64BICshiftRO:
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_ROR, v.AuxInt)
        case ssa.OpARM64MOVDconst:
                p := s.Prog(v.Op.Asm())
                p.From.Type = obj.TYPE_CONST
@@ -384,11 +396,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Offset = v.AuxInt
                p.Reg = v.Args[0].Reg()
        case ssa.OpARM64CMPshiftLL, ssa.OpARM64CMNshiftLL, ssa.OpARM64TSTshiftLL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
        case ssa.OpARM64CMPshiftRL, ssa.OpARM64CMNshiftRL, ssa.OpARM64TSTshiftRL:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
        case ssa.OpARM64CMPshiftRA, ssa.OpARM64CMNshiftRA, ssa.OpARM64TSTshiftRA:
-               genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
+       case ssa.OpARM64TSTshiftRO:
+               genshift(s, v, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_ROR, v.AuxInt)
        case ssa.OpARM64MOVDaddr:
                p := s.Prog(arm64.AMOVD)
                p.From.Type = obj.TYPE_ADDR
@@ -1046,6 +1060,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p4.To.SetTarget(p)
        case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
                s.Call(v)
+       case ssa.OpARM64CALLtail:
+               s.TailCall(v)
        case ssa.OpARM64LoweredWB:
                p := s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
@@ -1095,6 +1111,12 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Reg = condBits[v.Op]
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg()
+       case ssa.OpARM64PRFM:
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_MEM
+               p.From.Reg = v.Args[0].Reg()
+               p.To.Type = obj.TYPE_CONST
+               p.To.Offset = v.AuxInt
        case ssa.OpARM64LoweredGetClosurePtr:
                // Closure pointer is R26 (arm64.REGCTXT).
                ssagen.CheckLoweredGetClosurePtr(v)
@@ -1110,6 +1132,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p := s.Prog(obj.AGETCALLERPC)
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg()
+       case ssa.OpARM64DMB:
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = v.AuxInt
        case ssa.OpARM64FlagConstant:
                v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
        case ssa.OpARM64InvertFlags:
@@ -1235,17 +1261,11 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
 
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
 
        case ssa.BlockRet:
                s.Prog(obj.ARET)
 
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
-
        case ssa.BlockARM64EQ, ssa.BlockARM64NE,
                ssa.BlockARM64LT, ssa.BlockARM64GE,
                ssa.BlockARM64LE, ssa.BlockARM64GT,
index 4c2516f60e364b5d177707daaa8584c0e1920777..be6d49fac766db1d846ad5a376e4e0d8297ece0e 100644 (file)
@@ -67,6 +67,7 @@ var NoInstrumentPkgs = []string{
        "runtime",
        "runtime/race",
        "runtime/msan",
+       "runtime/asan",
        "internal/cpu",
 }
 
index e2245e1c26ea64cb01cd4a63315f68fe70c5f949..b105e46e353cb4767b610e6dfe6f1293f2c2a526 100644 (file)
@@ -6,15 +6,6 @@
 
 package base
 
-import (
-       "fmt"
-       "log"
-       "os"
-       "reflect"
-       "strconv"
-       "strings"
-)
-
 // Debug holds the parsed debugging configuration values.
 var Debug DebugFlags
 
@@ -26,7 +17,7 @@ var Debug DebugFlags
 // Each setting is name=value; for ints, name is short for name=1.
 type DebugFlags struct {
        Append               int    `help:"print information about append compilation"`
-       Checkptr             int    `help:"instrument unsafe pointer conversions"`
+       Checkptr             int    `help:"instrument unsafe pointer conversions\n0: instrumentation disabled\n1: conversions involving unsafe.Pointer are instrumented\n2: conversions to unsafe.Pointer force heap allocation"`
        Closure              int    `help:"print information about closure compilation"`
        DclStack             int    `help:"run internal dclstack check"`
        Defer                int    `help:"print information about defer compilation"`
@@ -40,7 +31,7 @@ type DebugFlags struct {
        LocationLists        int    `help:"print information about DWARF location list creation"`
        Nil                  int    `help:"print information about nil checks"`
        NoOpenDefer          int    `help:"disable open-coded defers"`
-       PCTab                string `help:"print named pc-value table"`
+       PCTab                string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
        Panic                int    `help:"show all compiler panics"`
        Slice                int    `help:"print information about slice compilation"`
        SoftFloat            int    `help:"force compiler to emit soft-float code"`
@@ -51,142 +42,12 @@ type DebugFlags struct {
        UnifiedQuirks        int    `help:"enable unified IR construction's quirks mode"`
        WB                   int    `help:"print information about write barriers"`
        ABIWrap              int    `help:"print information about ABI wrapper generation"`
+       MayMoreStack         string `help:"call named function before all stack growth checks"`
 
-       any bool // set when any of the values have been set
-}
-
-// Any reports whether any of the debug flags have been set.
-func (d *DebugFlags) Any() bool { return d.any }
-
-type debugField struct {
-       name string
-       help string
-       val  interface{} // *int or *string
-}
-
-var debugTab []debugField
-
-func init() {
-       v := reflect.ValueOf(&Debug).Elem()
-       t := v.Type()
-       for i := 0; i < t.NumField(); i++ {
-               f := t.Field(i)
-               if f.Name == "any" {
-                       continue
-               }
-               name := strings.ToLower(f.Name)
-               help := f.Tag.Get("help")
-               if help == "" {
-                       panic(fmt.Sprintf("base.Debug.%s is missing help text", f.Name))
-               }
-               ptr := v.Field(i).Addr().Interface()
-               switch ptr.(type) {
-               default:
-                       panic(fmt.Sprintf("base.Debug.%s has invalid type %v (must be int or string)", f.Name, f.Type))
-               case *int, *string:
-                       // ok
-               }
-               debugTab = append(debugTab, debugField{name, help, ptr})
-       }
+       Any bool // set when any of the debug flags have been set
 }
 
 // DebugSSA is called to set a -d ssa/... option.
 // If nil, those options are reported as invalid options.
 // If DebugSSA returns a non-empty string, that text is reported as a compiler error.
 var DebugSSA func(phase, flag string, val int, valString string) string
-
-// parseDebug parses the -d debug string argument.
-func parseDebug(debugstr string) {
-       // parse -d argument
-       if debugstr == "" {
-               return
-       }
-       Debug.any = true
-Split:
-       for _, name := range strings.Split(debugstr, ",") {
-               if name == "" {
-                       continue
-               }
-               // display help about the -d option itself and quit
-               if name == "help" {
-                       fmt.Print(debugHelpHeader)
-                       maxLen := len("ssa/help")
-                       for _, t := range debugTab {
-                               if len(t.name) > maxLen {
-                                       maxLen = len(t.name)
-                               }
-                       }
-                       for _, t := range debugTab {
-                               fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
-                       }
-                       // ssa options have their own help
-                       fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
-                       fmt.Print(debugHelpFooter)
-                       os.Exit(0)
-               }
-               val, valstring, haveInt := 1, "", true
-               if i := strings.IndexAny(name, "=:"); i >= 0 {
-                       var err error
-                       name, valstring = name[:i], name[i+1:]
-                       val, err = strconv.Atoi(valstring)
-                       if err != nil {
-                               val, haveInt = 1, false
-                       }
-               }
-               for _, t := range debugTab {
-                       if t.name != name {
-                               continue
-                       }
-                       switch vp := t.val.(type) {
-                       case nil:
-                               // Ignore
-                       case *string:
-                               *vp = valstring
-                       case *int:
-                               if !haveInt {
-                                       log.Fatalf("invalid debug value %v", name)
-                               }
-                               *vp = val
-                       default:
-                               panic("bad debugtab type")
-                       }
-                       continue Split
-               }
-               // special case for ssa for now
-               if DebugSSA != nil && strings.HasPrefix(name, "ssa/") {
-                       // expect form ssa/phase/flag
-                       // e.g. -d=ssa/generic_cse/time
-                       // _ in phase name also matches space
-                       phase := name[4:]
-                       flag := "debug" // default flag is debug
-                       if i := strings.Index(phase, "/"); i >= 0 {
-                               flag = phase[i+1:]
-                               phase = phase[:i]
-                       }
-                       err := DebugSSA(phase, flag, val, valstring)
-                       if err != "" {
-                               log.Fatalf(err)
-                       }
-                       continue Split
-               }
-               log.Fatalf("unknown debug key -d %s\n", name)
-       }
-}
-
-const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
-
-<key> is one of:
-
-`
-
-const debugHelpFooter = `
-<value> is key-specific.
-
-Key "checkptr" supports values:
-       "0": instrumentation disabled
-       "1": conversions involving unsafe.Pointer are instrumented
-       "2": conversions to unsafe.Pointer force heap allocation
-
-Key "pctab" supports values:
-       "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
-`
index b8b205f4127032f14abb8d1f3df39e5044ebe775..d78f93b343fa118670f5703cefddd2f700f1d94e 100644 (file)
@@ -64,19 +64,19 @@ type CmdFlags struct {
        // V is added by objabi.AddVersionFlag
        W CountFlag "help:\"debug parse tree after type checking\""
 
-       LowerC int          "help:\"concurrency during compilation (1 means no concurrency)\""
-       LowerD func(string) "help:\"enable debugging settings; try -d help\""
-       LowerE CountFlag    "help:\"no limit on number of errors reported\""
-       LowerH CountFlag    "help:\"halt on error\""
-       LowerJ CountFlag    "help:\"debug runtime-initialized variables\""
-       LowerL CountFlag    "help:\"disable inlining\""
-       LowerM CountFlag    "help:\"print optimization decisions\""
-       LowerO string       "help:\"write output to `file`\""
-       LowerP *string      "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
-       LowerR CountFlag    "help:\"debug generated wrappers\""
-       LowerT bool         "help:\"enable tracing for debugging the compiler\""
-       LowerW CountFlag    "help:\"debug type checking\""
-       LowerV *bool        "help:\"increase debug verbosity\""
+       LowerC int        "help:\"concurrency during compilation (1 means no concurrency)\""
+       LowerD flag.Value "help:\"enable debugging settings; try -d help\""
+       LowerE CountFlag  "help:\"no limit on number of errors reported\""
+       LowerH CountFlag  "help:\"halt on error\""
+       LowerJ CountFlag  "help:\"debug runtime-initialized variables\""
+       LowerL CountFlag  "help:\"disable inlining\""
+       LowerM CountFlag  "help:\"print optimization decisions\""
+       LowerO string     "help:\"write output to `file`\""
+       LowerP *string    "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
+       LowerR CountFlag  "help:\"debug generated wrappers\""
+       LowerT bool       "help:\"enable tracing for debugging the compiler\""
+       LowerW CountFlag  "help:\"debug type checking\""
+       LowerV *bool      "help:\"increase debug verbosity\""
 
        // Special characters
        Percent          int  "flag:\"%\" help:\"debug non-static initializers\""
@@ -84,6 +84,7 @@ type CmdFlags struct {
 
        // Longer names
        AsmHdr             string       "help:\"write assembly header to `file`\""
+       ASan               bool         "help:\"build code compatible with C/C++ address sanitizer\""
        Bench              string       "help:\"append benchmark times to `file`\""
        BlockProfile       string       "help:\"write block profile to `file`\""
        BuildID            string       "help:\"record `id` as the build id in the export metadata\""
@@ -108,7 +109,7 @@ type CmdFlags struct {
        Live               CountFlag    "help:\"debug liveness analysis\""
        MSan               bool         "help:\"build code compatible with C/C++ memory sanitizer\""
        MemProfile         string       "help:\"write memory profile to `file`\""
-       MemProfileRate     int64        "help:\"set runtime.MemProfileRate to `rate`\""
+       MemProfileRate     int          "help:\"set runtime.MemProfileRate to `rate`\""
        MutexProfile       string       "help:\"write mutex profile to `file`\""
        NoLocalImports     bool         "help:\"reject local (relative) imports\""
        Pack               bool         "help:\"write to file.a instead of file.o\""
@@ -140,10 +141,11 @@ type CmdFlags struct {
 
 // ParseFlags parses the command-line flags into Flag.
 func ParseFlags() {
+       Flag.G = 3
        Flag.I = addImportDir
 
        Flag.LowerC = 1
-       Flag.LowerD = parseDebug
+       Flag.LowerD = objabi.NewDebugFlag(&Debug, DebugSSA)
        Flag.LowerP = &Ctxt.Pkgpath
        Flag.LowerV = &Ctxt.Debugvlog
 
@@ -176,6 +178,9 @@ func ParseFlags() {
        if Flag.MSan && !sys.MSanSupported(buildcfg.GOOS, buildcfg.GOARCH) {
                log.Fatalf("%s/%s does not support -msan", buildcfg.GOOS, buildcfg.GOARCH)
        }
+       if Flag.ASan && !sys.ASanSupported(buildcfg.GOOS, buildcfg.GOARCH) {
+               log.Fatalf("%s/%s does not support -asan", buildcfg.GOOS, buildcfg.GOARCH)
+       }
        if Flag.Race && !sys.RaceDetectorSupported(buildcfg.GOOS, buildcfg.GOARCH) {
                log.Fatalf("%s/%s does not support -race", buildcfg.GOOS, buildcfg.GOARCH)
        }
@@ -187,6 +192,7 @@ func ParseFlags() {
        Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
        Ctxt.Flag_optimize = Flag.N == 0
        Ctxt.Debugasm = int(Flag.S)
+       Ctxt.Flag_maymorestack = Debug.MayMoreStack
 
        if flag.NArg() < 1 {
                usage()
@@ -216,12 +222,16 @@ func ParseFlags() {
                }
                Flag.LowerO = p + suffix
        }
-
-       if Flag.Race && Flag.MSan {
+       switch {
+       case Flag.Race && Flag.MSan:
                log.Fatal("cannot use both -race and -msan")
+       case Flag.Race && Flag.ASan:
+               log.Fatal("cannot use both -race and -asan")
+       case Flag.MSan && Flag.ASan:
+               log.Fatal("cannot use both -msan and -asan")
        }
-       if Flag.Race || Flag.MSan {
-               // -race and -msan imply -d=checkptr for now.
+       if Flag.Race || Flag.MSan || Flag.ASan {
+               // -race, -msan and -asan imply -d=checkptr for now.
                if Debug.Checkptr == -1 { // if not set explicitly
                        Debug.Checkptr = 1
                }
@@ -321,6 +331,12 @@ func registerFlags() {
                case funcType:
                        f := v.Field(i).Interface().(func(string))
                        objabi.Flagfn1(name, help, f)
+               default:
+                       if val, ok := v.Field(i).Interface().(flag.Value); ok {
+                               flag.Var(val, name, help)
+                       } else {
+                               panic(fmt.Sprintf("base.Flag.%s has unexpected type %s", f.Name, f.Type))
+                       }
                }
        }
 }
@@ -348,7 +364,7 @@ func concurrentBackendAllowed() bool {
        // while writing the object file, and that is non-concurrent.
        // Adding Debug_vlog, however, causes Debug.S to also print
        // while flushing the plist, which happens concurrently.
-       if Ctxt.Debugvlog || Debug.Any() || Flag.Live > 0 {
+       if Ctxt.Debugvlog || Debug.Any || Flag.Live > 0 {
                return false
        }
        // TODO: Test and delete this condition.
@@ -356,7 +372,7 @@ func concurrentBackendAllowed() bool {
                return false
        }
        // TODO: fix races and enable the following flags
-       if Ctxt.Flag_shared || Ctxt.Flag_dynlink || Flag.Race {
+       if Ctxt.Flag_dynlink || Flag.Race {
                return false
        }
        return true
index bcac1fe351fac13c7d06850495cc13364f3d0ddd..ad7ed0a1965e9c064e2dddf0f19125dfd4fe7ed4 100644 (file)
@@ -128,10 +128,21 @@ func (bv BitVec) IsEmpty() bool {
        return true
 }
 
+func (bv BitVec) Count() int {
+       n := 0
+       for _, x := range bv.B {
+               n += bits.OnesCount32(x)
+       }
+       return n
+}
+
 func (bv BitVec) Not() {
        for i, x := range bv.B {
                bv.B[i] = ^x
        }
+       if bv.N%wordBits != 0 {
+               bv.B[len(bv.B)-1] &= 1<<uint(bv.N%wordBits) - 1 // clear bits past N in the last word
+       }
 }
 
 // union
index 520203787f02dc97968e4cd71c577f7fc646d24d..65a48b68032af3680baa5caf2f93d11305240ffb 100644 (file)
@@ -38,6 +38,7 @@ func Func(fn *ir.Func) {
                }
        }
 
+       ir.VisitList(fn.Body, markHiddenClosureDead)
        fn.Body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
 }
 
@@ -62,9 +63,11 @@ func stmts(nn *ir.Nodes) {
                        if ir.IsConst(n.Cond, constant.Bool) {
                                var body ir.Nodes
                                if ir.BoolVal(n.Cond) {
+                                       ir.VisitList(n.Else, markHiddenClosureDead)
                                        n.Else = ir.Nodes{}
                                        body = n.Body
                                } else {
+                                       ir.VisitList(n.Body, markHiddenClosureDead)
                                        n.Body = ir.Nodes{}
                                        body = n.Else
                                }
@@ -114,6 +117,7 @@ func stmts(nn *ir.Nodes) {
                }
 
                if cut {
+                       ir.VisitList((*nn)[i+1:len(*nn)], markHiddenClosureDead)
                        *nn = (*nn)[:i+1]
                        break
                }
@@ -150,3 +154,13 @@ func expr(n ir.Node) ir.Node {
        }
        return n
 }
+
+func markHiddenClosureDead(n ir.Node) {
+       if n.Op() != ir.OCLOSURE {
+               return
+       }
+       clo := n.(*ir.ClosureExpr)
+       if clo.Func.IsHiddenClosure() {
+               clo.Func.SetIsDeadcodeClosure(true)
+       }
+}
index 0e22b61bc3ff4344ba1ad7c3e74f65c76a620243..3007262db9d1b784f0c0238f6873a32d80e72203 100644 (file)
@@ -214,9 +214,10 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
                        Type:          base.Ctxt.Lookup(typename),
                        DeclFile:      declpos.RelFilename(),
                        DeclLine:      declpos.RelLine(),
-                       DeclCol:       declpos.Col(),
+                       DeclCol:       declpos.RelCol(),
                        InlIndex:      int32(inlIndex),
                        ChildIndex:    -1,
+                       DictIndex:     n.DictIndex,
                })
                // Record go type of to insure that it gets emitted by the linker.
                fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
@@ -371,9 +372,10 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
                Type:          base.Ctxt.Lookup(typename),
                DeclFile:      declpos.RelFilename(),
                DeclLine:      declpos.RelLine(),
-               DeclCol:       declpos.Col(),
+               DeclCol:       declpos.RelCol(),
                InlIndex:      int32(inlIndex),
                ChildIndex:    -1,
+               DictIndex:     n.DictIndex,
        }
 }
 
@@ -475,9 +477,10 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
                StackOffset: ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
                DeclFile:    declpos.RelFilename(),
                DeclLine:    declpos.RelLine(),
-               DeclCol:     declpos.Col(),
+               DeclCol:     declpos.RelCol(),
                InlIndex:    int32(inlIndex),
                ChildIndex:  -1,
+               DictIndex:   n.DictIndex,
        }
        list := debug.LocationLists[varID]
        if len(list) != 0 {
index 8adb36fc883da0614f760410fa8f6af8e7ccb25e..c785e064a7f48497b2f4304848efe5879c65cd33 100644 (file)
@@ -244,7 +244,7 @@ func makePreinlineDclMap(fnsym *obj.LSym) map[varPos]int {
                        DeclName: unversion(n.Sym().Name),
                        DeclFile: pos.RelFilename(),
                        DeclLine: pos.RelLine(),
-                       DeclCol:  pos.Col(),
+                       DeclCol:  pos.RelCol(),
                }
                if _, found := m[vp]; found {
                        // We can see collisions (variables with the same name/file/line/col) in obfuscated or machine-generated code -- see issue 44378 for an example. Skip duplicates in such cases, since it is unlikely that a human will be debugging such code.
index 9e5abed59142edaf7b6dba120d733f765e4cf6cb..d1215afca8331e04a9519ce14a8e701df344c037 100644 (file)
@@ -333,11 +333,32 @@ func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn
                }
        }
 
-       // Peel away any slice lits.
+       // Peel away any slice literals for better escape analyze
+       // them. For example:
+       //
+       //     go F([]int{a, b})
+       //
+       // If F doesn't escape its arguments, then the slice can
+       // be allocated on the new goroutine's stack.
+       //
+       // For variadic functions, the compiler has already rewritten:
+       //
+       //     f(a, b, c)
+       //
+       // to:
+       //
+       //     f([]T{a, b, c}...)
+       //
+       // So we need to look into slice elements to handle uintptr(ptr)
+       // arguments to syscall-like functions correctly.
        if arg := *argp; arg.Op() == ir.OSLICELIT {
                list := arg.(*ir.CompLitExpr).List
                for i := range list {
-                       visit(arg.Pos(), &list[i])
+                       el := &list[i]
+                       if list[i].Op() == ir.OKEY {
+                               el = &list[i].(*ir.KeyExpr).Value
+                       }
+                       visit(arg.Pos(), el)
                }
        } else {
                visit(call.Pos(), argp)
index 62afb5b9288cbe1c007a16ad67a3e126e67b11e8..ced90a47bcb6632a4c8df5a0a1664ab5de409429 100644 (file)
@@ -30,7 +30,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
                base.Pos = lno
        }()
 
-       if k.derefs >= 0 && !n.Type().HasPointers() {
+       if k.derefs >= 0 && !n.Type().IsUntyped() && !n.Type().HasPointers() {
                k.dst = &e.blankLoc
        }
 
index d3ae1da693e5833de105eaf563d56878f5bb0dfe..cc3d078adddf8796349ab5aa813c81615450806b 100644 (file)
@@ -117,7 +117,7 @@ func (l *location) isName(c ir.Class) bool {
        return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class == c
 }
 
-// An hole represents a context for evaluation a Go
+// A hole represents a context for evaluation of a Go
 // expression. E.g., when evaluating p in "x = **p", we'd have a hole
 // with dst==x and derefs==2.
 type hole struct {
index c71848b8a1ca678c0c78934d1b75c44e686b997f..0afb5d64ef681433aa031e2334da33c71d3e3991 100644 (file)
@@ -180,7 +180,8 @@ func (e *escape) stmt(n ir.Node) {
                e.goDeferStmt(n)
 
        case ir.OTAILCALL:
-               // TODO(mdempsky): Treat like a normal call? esc.go used to just ignore it.
+               n := n.(*ir.TailCallStmt)
+               e.call(nil, n.Call)
        }
 }
 
index 5f462ef570faaef15f9a3e37f528ba1f1d0391ae..2c6e9bcbebda07143061a9ddb631e837685db432 100644 (file)
@@ -182,11 +182,11 @@ func HeapAllocReason(n ir.Node) string {
                }
        }
 
-       if n.Type().Width > ir.MaxStackVarSize {
+       if n.Type().Size() > ir.MaxStackVarSize {
                return "too large for stack"
        }
 
-       if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Width > ir.MaxImplicitStackVarSize {
+       if (n.Op() == ir.ONEW || n.Op() == ir.OPTRLIT) && n.Type().Elem().Size() > ir.MaxImplicitStackVarSize {
                return "too large for stack"
        }
 
@@ -206,7 +206,7 @@ func HeapAllocReason(n ir.Node) string {
                if !ir.IsSmallIntConst(r) {
                        return "non-constant size"
                }
-               if t := n.Type(); t.Elem().Width != 0 && ir.Int64Val(r) > ir.MaxImplicitStackVarSize/t.Elem().Width {
+               if t := n.Type(); t.Elem().Size() != 0 && ir.Int64Val(r) > ir.MaxImplicitStackVarSize/t.Elem().Size() {
                        return "too large for stack"
                }
        }
index 9bf3c7240ac2b1aa2406d10689e313528d6e0b06..eed438705ade0f20a18451eb8a0a0f5cfc8e24c2 100644 (file)
@@ -31,14 +31,14 @@ func dumpasmhdr() {
                        if t == constant.Float || t == constant.Complex {
                                break
                        }
-                       fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym().Name, n.Val())
+                       fmt.Fprintf(b, "#define const_%s %v\n", n.Sym().Name, n.Val())
 
                case ir.OTYPE:
                        t := n.Type()
                        if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
                                break
                        }
-                       fmt.Fprintf(b, "#define %s__size %d\n", n.Sym().Name, int(t.Width))
+                       fmt.Fprintf(b, "#define %s__size %d\n", n.Sym().Name, int(t.Size()))
                        for _, f := range t.Fields().Slice() {
                                if !f.Sym.IsBlank() {
                                        fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym().Name, f.Sym.Name, int(f.Offset))
index 6a373ce33d7851cc121ec9e49833d4156e1435a5..ed81ef7bc0471458df4387387a3466c1979badf6 100644 (file)
@@ -84,7 +84,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        types.BuiltinPkg.Prefix = "go.builtin"            // not go%2ebuiltin
 
        // pseudo-package, accessed by import "unsafe"
-       ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
+       types.UnsafePkg = types.NewPkg("unsafe", "unsafe")
 
        // Pseudo-package that contains the compiler's builtin
        // declarations for package runtime. These are declared in a
@@ -107,7 +107,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        // Record flags that affect the build result. (And don't
        // record flags that don't, since that would cause spurious
        // changes in the binary.)
-       dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
+       dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "asan", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
 
        if !base.EnableTrace && base.Flag.LowerT {
                log.Fatalf("compiler not built with support for -t")
@@ -149,11 +149,12 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        if base.Compiling(base.NoInstrumentPkgs) {
                base.Flag.Race = false
                base.Flag.MSan = false
+               base.Flag.ASan = false
        }
 
        ssagen.Arch.LinkArch.Init(base.Ctxt)
        startProfile()
-       if base.Flag.Race || base.Flag.MSan {
+       if base.Flag.Race || base.Flag.MSan || base.Flag.ASan {
                base.Flag.Cfg.Instrumenting = true
        }
        if base.Flag.Dwarf {
@@ -195,18 +196,19 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        // because it generates itabs for initializing global variables.
        ssagen.InitConfig()
 
-       // Build init task.
-       if initTask := pkginit.Task(); initTask != nil {
-               typecheck.Export(initTask)
-       }
+       // Create "init" function for package-scope variable initialization
+       // statements, if any.
+       //
+       // Note: This needs to happen early, before any optimizations. The
+       // Go spec defines a precise order than initialization should be
+       // carried out in, and even mundane optimizations like dead code
+       // removal can skew the results (e.g., #43444).
+       pkginit.MakeInit()
 
        // Stability quirk: sort top-level declarations, so we're not
        // sensitive to the order that functions are added. In particular,
        // the order that noder+typecheck add function closures is very
        // subtle, and not important to reproduce.
-       //
-       // Note: This needs to happen after pkginit.Task, otherwise it risks
-       // changing the order in which top-level variables are initialized.
        if base.Debug.UnifiedQuirks != 0 {
                s := typecheck.Target.Decls
                sort.SliceStable(s, func(i, j int) bool {
@@ -243,7 +245,13 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        base.Timer.Start("fe", "inlining")
        if base.Flag.LowerL != 0 {
                inline.InlinePackage()
+               // If any new fully-instantiated types were referenced during
+               // inlining, we need to create needed instantiations.
+               if len(typecheck.GetInstTypeList()) > 0 {
+                       noder.BuildInstantiations(false)
+               }
        }
+       noder.MakeWrappers(typecheck.Target) // must happen after inlining
 
        // Devirtualize.
        for _, n := range typecheck.Target.Decls {
@@ -253,6 +261,11 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        }
        ir.CurFunc = nil
 
+       // Build init task, if needed.
+       if initTask := pkginit.Task(); initTask != nil {
+               typecheck.Export(initTask)
+       }
+
        // Generate ABI wrappers. Must happen before escape analysis
        // and doesn't benefit from dead-coding or inlining.
        symABIs.GenABIWrappers()
@@ -289,6 +302,10 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        fcount := int64(0)
        for i := 0; i < len(typecheck.Target.Decls); i++ {
                if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
+                       // Don't try compiling dead hidden closure.
+                       if fn.IsDeadcodeClosure() {
+                               continue
+                       }
                        enqueueFunc(fn)
                        fcount++
                }
index c86bf5f0847be8df3b9ceeef759fa13239b01a05..dcb54047f1fce75b577f8c32c40f0e19f88464e4 100644 (file)
@@ -249,8 +249,7 @@ func addGCLocals() {
                        }
                }
                if x := fn.StackObjects; x != nil {
-                       attr := int16(obj.RODATA)
-                       objw.Global(x, int32(len(x.P)), attr)
+                       objw.Global(x, int32(len(x.P)), obj.RODATA)
                        x.Set(obj.AttrStatic, true)
                }
                if x := fn.OpenCodedDeferInfo; x != nil {
@@ -259,7 +258,10 @@ func addGCLocals() {
                if x := fn.ArgInfo; x != nil {
                        objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
                        x.Set(obj.AttrStatic, true)
-                       x.Set(obj.AttrContentAddressable, true)
+               }
+               if x := fn.ArgLiveInfo; x != nil {
+                       objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
+                       x.Set(obj.AttrStatic, true)
                }
        }
 }
@@ -274,7 +276,7 @@ func ggloblnod(nam *ir.Name) {
        if nam.Type() != nil && !nam.Type().HasPointers() {
                flags |= obj.NOPTR
        }
-       base.Ctxt.Globl(s, nam.Type().Width, flags)
+       base.Ctxt.Globl(s, nam.Type().Size(), flags)
        if nam.LibfuzzerExtraCounter() {
                s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
        }
index 4baddbc029a8d2dc587650a1b99243bc20b9b619..56fd137de2374b96b9788417b809fec1e0a91388 100644 (file)
@@ -12,10 +12,7 @@ import (
        "cmd/compile/internal/base"
 )
 
-var (
-       memprofilerate int64
-       traceHandler   func(string)
-)
+var traceHandler func(string)
 
 func startProfile() {
        if base.Flag.CPUProfile != "" {
@@ -29,8 +26,8 @@ func startProfile() {
                base.AtExit(pprof.StopCPUProfile)
        }
        if base.Flag.MemProfile != "" {
-               if memprofilerate != 0 {
-                       runtime.MemProfileRate = int(memprofilerate)
+               if base.Flag.MemProfileRate != 0 {
+                       runtime.MemProfileRate = base.Flag.MemProfileRate
                }
                f, err := os.Create(base.Flag.MemProfile)
                if err != nil {
index a317dfc34ad634464328680c0b9fbbedc0df3902..d04ef5c34d25d468bb6fd30ac8cc3a3fc0f79112 100644 (file)
@@ -43,12 +43,12 @@ func (r *intReader) uint64() uint64 {
 
 // Keep this in sync with constants in iexport.go.
 const (
-       iexportVersionGo1_11 = 0
-       iexportVersionPosCol = 1
-       // TODO: before release, change this back to 2.
-       iexportVersionGenerics = iexportVersionPosCol
+       iexportVersionGo1_11   = 0
+       iexportVersionPosCol   = 1
+       iexportVersionGenerics = 1 // probably change to 2 before release
+       iexportVersionGo1_18   = 2
 
-       iexportVersionCurrent = iexportVersionGenerics
+       iexportVersionCurrent = 2
 )
 
 type ident struct {
@@ -72,7 +72,7 @@ const (
        structType
        interfaceType
        typeParamType
-       instType
+       instanceType
        unionType
 )
 
@@ -99,13 +99,9 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ
 
        version = int64(r.uint64())
        switch version {
-       case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11:
+       case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
        default:
-               if version > iexportVersionGenerics {
-                       errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
-               } else {
-                       errorf("unknown iexport format version %d", version)
-               }
+               errorf("unknown iexport format version %d", version)
        }
 
        sLen := int64(r.uint64())
@@ -257,7 +253,7 @@ func (p *iimporter) posBaseAt(off uint64) *syntax.PosBase {
                return posBase
        }
        filename := p.stringAt(off)
-       posBase := syntax.NewFileBase(filename)
+       posBase := syntax.NewTrimmedFileBase(filename, true)
        p.posBaseCache[off] = posBase
        return posBase
 }
@@ -309,28 +305,25 @@ func (r *importReader) obj(name string) {
                r.declare(types2.NewConst(pos, r.currPkg, name, typ, val))
 
        case 'F', 'G':
-               var tparams []*types2.TypeName
+               var tparams []*types2.TypeParam
                if tag == 'G' {
                        tparams = r.tparamList()
                }
-               sig := r.signature(nil)
-               sig.SetTParams(tparams)
+               sig := r.signature(nil, nil, tparams)
                r.declare(types2.NewFunc(pos, r.currPkg, name, sig))
 
        case 'T', 'U':
-               var tparams []*types2.TypeName
-               if tag == 'U' {
-                       tparams = r.tparamList()
-               }
-
                // Types can be recursive. We need to setup a stub
                // declaration before recursing.
                obj := types2.NewTypeName(pos, r.currPkg, name, nil)
                named := types2.NewNamed(obj, nil, nil)
+               // Declare obj before calling r.tparamList, so the new type name is recognized
+               // if used in the constraint of one of its own typeparams (see #48280).
+               r.declare(obj)
                if tag == 'U' {
-                       named.SetTParams(tparams)
+                       tparams := r.tparamList()
+                       named.SetTypeParams(tparams)
                }
-               r.declare(obj)
 
                underlying := r.p.typAt(r.uint64(), named).Underlying()
                named.SetUnderlying(underlying)
@@ -340,19 +333,19 @@ func (r *importReader) obj(name string) {
                                mpos := r.pos()
                                mname := r.ident()
                                recv := r.param()
-                               msig := r.signature(recv)
 
                                // If the receiver has any targs, set those as the
                                // rparams of the method (since those are the
                                // typeparams being used in the method sig/body).
-                               targs := baseType(msig.Recv().Type()).TArgs()
-                               if len(targs) > 0 {
-                                       rparams := make([]*types2.TypeName, len(targs))
-                                       for i, targ := range targs {
-                                               rparams[i] = types2.AsTypeParam(targ).Obj()
+                               targs := baseType(recv.Type()).TypeArgs()
+                               var rparams []*types2.TypeParam
+                               if targs.Len() > 0 {
+                                       rparams = make([]*types2.TypeParam, targs.Len())
+                                       for i := range rparams {
+                                               rparams[i], _ = targs.At(i).(*types2.TypeParam)
                                        }
-                                       msig.SetRParams(rparams)
                                }
+                               msig := r.signature(recv, rparams, nil)
 
                                named.AddMethod(types2.NewFunc(mpos, r.currPkg, mname, msig))
                        }
@@ -365,19 +358,31 @@ func (r *importReader) obj(name string) {
                if r.p.exportVersion < iexportVersionGenerics {
                        errorf("unexpected type param type")
                }
-               name0, sub := parseSubscript(name)
-               tn := types2.NewTypeName(pos, r.currPkg, name0, nil)
-               t := (*types2.Checker)(nil).NewTypeParam(tn, nil)
-               if sub == 0 {
-                       errorf("missing subscript")
+               // Remove the "path" from the type param name that makes it unique
+               ix := strings.LastIndex(name, ".")
+               if ix < 0 {
+                       errorf("missing path for type param")
                }
-               t.SetId(sub)
+               tn := types2.NewTypeName(pos, r.currPkg, name[ix+1:], nil)
+               t := types2.NewTypeParam(tn, nil)
                // To handle recursive references to the typeparam within its
                // bound, save the partial type in tparamIndex before reading the bounds.
                id := ident{r.currPkg.Name(), name}
                r.p.tparamIndex[id] = t
 
-               t.SetConstraint(r.typ())
+               var implicit bool
+               if r.p.exportVersion >= iexportVersionGo1_18 {
+                       implicit = r.bool()
+               }
+               constraint := r.typ()
+               if implicit {
+                       iface, _ := constraint.(*types2.Interface)
+                       if iface == nil {
+                               errorf("non-interface constraint marked implicit")
+                       }
+                       iface.MarkImplicit()
+               }
+               t.SetConstraint(constraint)
 
        case 'V':
                typ := r.typ()
@@ -395,6 +400,10 @@ func (r *importReader) declare(obj types2.Object) {
 
 func (r *importReader) value() (typ types2.Type, val constant.Value) {
        typ = r.typ()
+       if r.p.exportVersion >= iexportVersionGo1_18 {
+               // TODO: add support for using the kind
+               _ = constant.Kind(r.int64())
+       }
 
        switch b := typ.Underlying().(*types2.Basic); b.Info() & types2.IsConstType {
        case types2.IsBoolean:
@@ -586,7 +595,7 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
                return types2.NewMap(r.typ(), r.typ())
        case signatureType:
                r.currPkg = r.pkg()
-               return r.signature(nil)
+               return r.signature(nil, nil, nil)
 
        case structType:
                r.currPkg = r.pkg()
@@ -626,7 +635,7 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
                                recv = types2.NewVar(syntax.Pos{}, r.currPkg, "", base)
                        }
 
-                       msig := r.signature(recv)
+                       msig := r.signature(recv, nil, nil)
                        methods[i] = types2.NewFunc(mpos, r.currPkg, mname, msig)
                }
 
@@ -648,11 +657,13 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
                r.p.doDecl(pkg, name)
                return r.p.tparamIndex[id]
 
-       case instType:
+       case instanceType:
                if r.p.exportVersion < iexportVersionGenerics {
                        errorf("unexpected instantiation type")
                }
-               pos := r.pos()
+               // pos does not matter for instances: they are positioned on the original
+               // type.
+               _ = r.pos()
                len := r.uint64()
                targs := make([]types2.Type, len)
                for i := range targs {
@@ -661,8 +672,8 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
                baseType := r.typ()
                // The imported instantiated type doesn't include any methods, so
                // we must always use the methods of the base (orig) type.
-               var check *types2.Checker // TODO provide a non-nil *Checker
-               t := check.Instantiate(pos, baseType, targs, nil, false)
+               // TODO provide a non-nil *Context
+               t, _ := types2.Instantiate(nil, baseType, targs, false)
                return t
 
        case unionType:
@@ -681,22 +692,22 @@ func (r *importReader) kind() itag {
        return itag(r.uint64())
 }
 
-func (r *importReader) signature(recv *types2.Var) *types2.Signature {
+func (r *importReader) signature(recv *types2.Var, rparams, tparams []*types2.TypeParam) *types2.Signature {
        params := r.paramList()
        results := r.paramList()
        variadic := params.Len() > 0 && r.bool()
-       return types2.NewSignature(recv, params, results, variadic)
+       return types2.NewSignatureType(recv, rparams, tparams, params, results, variadic)
 }
 
-func (r *importReader) tparamList() []*types2.TypeName {
+func (r *importReader) tparamList() []*types2.TypeParam {
        n := r.uint64()
        if n == 0 {
                return nil
        }
-       xs := make([]*types2.TypeName, n)
+       xs := make([]*types2.TypeParam, n)
        for i := range xs {
                typ := r.typ()
-               xs[i] = types2.AsTypeParam(typ).Obj()
+               xs[i] = types2.AsTypeParam(typ)
        }
        return xs
 }
@@ -753,23 +764,3 @@ func baseType(typ types2.Type) *types2.Named {
        n, _ := typ.(*types2.Named)
        return n
 }
-
-func parseSubscript(name string) (string, uint64) {
-       // Extract the subscript value from the type param name. We export
-       // and import the subscript value, so that all type params have
-       // unique names.
-       sub := uint64(0)
-       startsub := -1
-       for i, r := range name {
-               if '₀' <= r && r < '₀'+10 {
-                       if startsub == -1 {
-                               startsub = i
-                       }
-                       sub = sub*10 + uint64(r-'₀')
-               }
-       }
-       if startsub >= 0 {
-               name = name[:startsub]
-       }
-       return name, sub
-}
index 06dafee98c30f82e459be13f0c0ced7e535d57af..56e4292cda9f3a0892677a20722c833165171290 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2016 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.
index a601dbccc5a0e9b76ac8bfd752e2fb7e5b6397cd..419667820078e47d4744ee7c809a8f63516c8a42 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2016 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.
index 2a720fd2c172541bbbe32976791534c06a2ecbdb..8ba3242102779d2917640f48f9178a75f503ff3b 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // 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.
index b40202616275836a6d5e43eec0f8d5cca29d1f74..c70f7d8267b2f9209cf5f52a0ca7fe1bcc303649 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2016 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.
index e412f353ad2e6d7cbca580ba24adb67acfe4c51e..c63ee821c959dafda6799ccc8df77347221ad46a 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // 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.
index a9dc1d7f083b2eae0353e51fff547b2776fc4476..e3dc98b4e1f9acdc9801c6a66e9305206f943cb5 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2018 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
index 95bef42280e9b4283bcec8bb32993ffc4999da87..8923373e5fa44d57d25ce1b4ccdc3a480360c74f 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2018 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
index 34a20eaa1451eca59573898adcad40c3a6a58e26..9e2e7057653725fc8ce963b5768828b3d9a88b42 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2016 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.
index 2f8eb5ced047c4ae88aadad7a34b688a2ad838a8..227fc092519212f30793e1266fe619858ac28bef 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2016 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.
index 45a533fcafc3dfd70baf0e04c75f50fe2e6f1083..b764aed534db7ffcf93aa18e1dad1a6c23e1036b 100644 (file)
@@ -275,14 +275,31 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
                }
                if n.X.Op() == ir.OMETHEXPR {
                        if meth := ir.MethodExprName(n.X); meth != nil {
-                               fn := meth.Func
-                               if fn != nil && types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
-                                       // Special case: explicitly allow
-                                       // mid-stack inlining of
-                                       // runtime.heapBits.next even though
-                                       // it calls slow-path
-                                       // runtime.heapBits.nextArena.
-                                       break
+                               if fn := meth.Func; fn != nil {
+                                       s := fn.Sym()
+                                       var cheap bool
+                                       if types.IsRuntimePkg(s.Pkg) && s.Name == "heapBits.nextArena" {
+                                               // Special case: explicitly allow mid-stack inlining of
+                                               // runtime.heapBits.next even though it calls slow-path
+                                               // runtime.heapBits.nextArena.
+                                               cheap = true
+                                       }
+                                       // Special case: on architectures that can do unaligned loads,
+                                       // explicitly mark encoding/binary methods as cheap,
+                                       // because in practice they are, even though our inlining
+                                       // budgeting system does not see that. See issue 42958.
+                                       if base.Ctxt.Arch.CanMergeLoads && s.Pkg.Path == "encoding/binary" {
+                                               switch s.Name {
+                                               case "littleEndian.Uint64", "littleEndian.Uint32", "littleEndian.Uint16",
+                                                       "bigEndian.Uint64", "bigEndian.Uint32", "bigEndian.Uint16",
+                                                       "littleEndian.PutUint64", "littleEndian.PutUint32", "littleEndian.PutUint16",
+                                                       "bigEndian.PutUint64", "bigEndian.PutUint32", "bigEndian.PutUint16":
+                                                       cheap = true
+                                               }
+                                       }
+                                       if cheap {
+                                               break // treat like any other node, that is, cost of 1
+                                       }
                                }
                        }
                }
@@ -341,8 +358,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
                        return true
                }
 
-       case ir.ORANGE,
-               ir.OSELECT,
+       case ir.OSELECT,
                ir.OGO,
                ir.ODEFER,
                ir.ODCLTYPE, // can't print yet
@@ -373,35 +389,18 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
                // These nodes don't produce code; omit from inlining budget.
                return false
 
-       case ir.OFOR, ir.OFORUNTIL:
-               n := n.(*ir.ForStmt)
-               if n.Label != nil {
-                       v.reason = "labeled control"
-                       return true
-               }
-       case ir.OSWITCH:
-               n := n.(*ir.SwitchStmt)
-               if n.Label != nil {
-                       v.reason = "labeled control"
-                       return true
-               }
-       // case ir.ORANGE, ir.OSELECT in "unhandled" above
-
-       case ir.OBREAK, ir.OCONTINUE:
-               n := n.(*ir.BranchStmt)
-               if n.Label != nil {
-                       // Should have short-circuited due to labeled control error above.
-                       base.Fatalf("unexpected labeled break/continue: %v", n)
-               }
-
        case ir.OIF:
                n := n.(*ir.IfStmt)
                if ir.IsConst(n.Cond, constant.Bool) {
                        // This if and the condition cost nothing.
-                       // TODO(rsc): It seems strange that we visit the dead branch.
-                       return doList(n.Init(), v.do) ||
-                               doList(n.Body, v.do) ||
-                               doList(n.Else, v.do)
+                       if doList(n.Init(), v.do) {
+                               return true
+                       }
+                       if ir.BoolVal(n.Cond) {
+                               return doList(n.Body, v.do)
+                       } else {
+                               return doList(n.Else, v.do)
+                       }
                }
 
        case ir.ONAME:
@@ -540,6 +539,9 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
                        call := call.(*ir.CallExpr)
                        call.NoInline = true
                }
+       case ir.OTAILCALL:
+               n := n.(*ir.TailCallStmt)
+               n.Call.NoInline = true // Not inline a tail call for now. Maybe we could inline it just like RETURN fn(arg)?
 
        // TODO do them here (or earlier),
        // so escape analysis can avoid more heapmoves.
@@ -683,6 +685,27 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
                return n
        }
 
+       // Don't inline a function fn that has no shape parameters, but is passed at
+       // least one shape arg. This means we must be inlining a non-generic function
+       // fn that was passed into a generic function, and can be called with a shape
+       // arg because it matches an appropriate type parameters. But fn may include
+       // an interface conversion (that may be applied to a shape arg) that was not
+       // apparent when we first created the instantiation of the generic function.
+       // We can't handle this if we actually do the inlining, since we want to know
+       // all interface conversions immediately after stenciling. So, we avoid
+       // inlining in this case. See #49309.
+       if !fn.Type().HasShape() {
+               for _, arg := range n.Args {
+                       if arg.Type().HasShape() {
+                               if logopt.Enabled() {
+                                       logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
+                                               fmt.Sprintf("inlining non-shape function %v with shape args", ir.FuncName(fn)))
+                               }
+                               return n
+                       }
+               }
+       }
+
        if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
                // Runtime package must not be instrumented.
                // Instrument skips runtime package. However, some runtime code can be
@@ -1061,6 +1084,8 @@ func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
                m.Defn = &subst.defnMarker
        case *ir.TypeSwitchGuard:
                // TODO(mdempsky): Set m.Defn properly. See discussion on #45743.
+       case *ir.RangeStmt:
+               // TODO: Set m.Defn properly if we support inlining range statement in the future.
        default:
                base.FatalfAt(n.Pos(), "unexpected Defn: %+v", defn)
        }
@@ -1218,7 +1243,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                        // Don't do special substitutions if inside a closure
                        break
                }
-               // Since we don't handle bodies with closures,
+               // Because of the above test for subst.newclofn,
                // this return is guaranteed to belong to the current inlined function.
                n := n.(*ir.ReturnStmt)
                init := subst.list(n.Init())
@@ -1246,7 +1271,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                typecheck.Stmts(init)
                return ir.NewBlockStmt(base.Pos, init)
 
-       case ir.OGOTO:
+       case ir.OGOTO, ir.OBREAK, ir.OCONTINUE:
                if subst.newclofn != nil {
                        // Don't do special substitutions if inside a closure
                        break
@@ -1254,9 +1279,8 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                n := n.(*ir.BranchStmt)
                m := ir.Copy(n).(*ir.BranchStmt)
                m.SetPos(subst.updatedPos(m.Pos()))
-               *m.PtrInit() = nil
-               p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
-               m.Label = typecheck.Lookup(p)
+               m.SetInit(nil)
+               m.Label = translateLabel(n.Label)
                return m
 
        case ir.OLABEL:
@@ -1267,9 +1291,8 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                n := n.(*ir.LabelStmt)
                m := ir.Copy(n).(*ir.LabelStmt)
                m.SetPos(subst.updatedPos(m.Pos()))
-               *m.PtrInit() = nil
-               p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
-               m.Label = typecheck.Lookup(p)
+               m.SetInit(nil)
+               m.Label = translateLabel(n.Label)
                return m
 
        case ir.OCLOSURE:
@@ -1281,6 +1304,27 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
        m.SetPos(subst.updatedPos(m.Pos()))
        ir.EditChildren(m, subst.edit)
 
+       if subst.newclofn == nil {
+               // Translate any label on FOR, RANGE loops or SWITCH
+               switch m.Op() {
+               case ir.OFOR:
+                       m := m.(*ir.ForStmt)
+                       m.Label = translateLabel(m.Label)
+                       return m
+
+               case ir.ORANGE:
+                       m := m.(*ir.RangeStmt)
+                       m.Label = translateLabel(m.Label)
+                       return m
+
+               case ir.OSWITCH:
+                       m := m.(*ir.SwitchStmt)
+                       m.Label = translateLabel(m.Label)
+                       return m
+               }
+
+       }
+
        switch m := m.(type) {
        case *ir.AssignStmt:
                if lhs, ok := m.X.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
@@ -1297,6 +1341,16 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
        return m
 }
 
+// translateLabel makes a label from an inlined function (if non-nil) be unique by
+// adding "·inlgen".
+func translateLabel(l *types.Sym) *types.Sym {
+       if l == nil {
+               return nil
+       }
+       p := fmt.Sprintf("%s·%d", l.Name, inlgen)
+       return typecheck.Lookup(p)
+}
+
 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
        if subst.noPosUpdate {
                return xpos
index dc28483907a8120a44353ed75ebe7f138cd20526..f526d987a7b20e6318655445319c30a7a1cda058 100644 (file)
@@ -275,7 +275,7 @@ func (n *ConvExpr) SetOp(op Op) {
        }
 }
 
-// An IndexExpr is an index expression X[Y].
+// An IndexExpr is an index expression X[Index].
 type IndexExpr struct {
        miniExpr
        X        Node
index d19fe453efc1b3a054463618a57368647b50a6a1..033188547b61ca65c35e4d4e671db419e30e7bdb 100644 (file)
@@ -386,7 +386,7 @@ func stmtFmt(n Node, s fmt.State) {
 
        case OTAILCALL:
                n := n.(*TailCallStmt)
-               fmt.Fprintf(s, "tailcall %v", n.Target)
+               fmt.Fprintf(s, "tailcall %v", n.Call)
 
        case OINLMARK:
                n := n.(*InlineMarkStmt)
@@ -559,7 +559,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
        }
 
        nprec := OpPrec[n.Op()]
-       if n.Op() == OTYPE && n.Type().IsPtr() {
+       if n.Op() == OTYPE && n.Type() != nil && n.Type().IsPtr() {
                nprec = OpPrec[ODEREF]
        }
 
@@ -1061,8 +1061,8 @@ func dumpNodeHeader(w io.Writer, n Node) {
                }
        }
 
-       if n.Typecheck() != 0 {
-               fmt.Fprintf(w, " tc(%d)", n.Typecheck())
+       if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE {
+               fmt.Fprintf(w, " %+v", n.Sym())
        }
 
        // Print Node-specific fields of basic type in header line.
@@ -1132,6 +1132,9 @@ func dumpNodeHeader(w io.Writer, n Node) {
                }
                fmt.Fprintf(w, " %+v", n.Type())
        }
+       if n.Typecheck() != 0 {
+               fmt.Fprintf(w, " tc(%d)", n.Typecheck())
+       }
 
        if n.Pos().IsKnown() {
                fmt.Fprint(w, " # ")
@@ -1147,6 +1150,7 @@ func dumpNodeHeader(w io.Writer, n Node) {
                        }
                        // TODO(mdempsky): Print line pragma details too.
                        file := filepath.Base(pos.Filename())
+                       // Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync.
                        fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col())
                }
        }
@@ -1247,13 +1251,6 @@ func dumpNode(w io.Writer, n Node, depth int) {
                return
        }
 
-       if n.Sym() != nil {
-               fmt.Fprintf(w, " %+v", n.Sym())
-       }
-       if n.Type() != nil {
-               fmt.Fprintf(w, " %+v", n.Type())
-       }
-
        v := reflect.ValueOf(n).Elem()
        t := reflect.TypeOf(n).Elem()
        nf := t.NumField()
index 269b6f14ec1873188c0ca353ce912cd810cfcad5..41c96079f75df3ceed4c695ed686f89f939a5415 100644 (file)
@@ -196,11 +196,12 @@ const (
        // true if closure inside a function; false if a simple function or a
        // closure in a global variable initialization
        funcIsHiddenClosure
+       funcIsDeadcodeClosure        // true if closure is deadcode
        funcHasDefer                 // contains a defer statement
        funcNilCheckDisabled         // disable nil checks when compiling this function
        funcInlinabilityChecked      // inliner has already determined whether the function is inlinable
        funcExportInline             // include inline body in export data
-       funcInstrumentBody           // add race/msan instrumentation during SSA construction
+       funcInstrumentBody           // add race/msan/asan instrumentation during SSA construction
        funcOpenCodedDeferDisallowed // can't do open-coded defers
        funcClosureCalled            // closure is only immediately called; used by escape analysis
 )
@@ -216,6 +217,7 @@ func (f *Func) ABIWrapper() bool               { return f.flags&funcABIWrapper !
 func (f *Func) Needctxt() bool                 { return f.flags&funcNeedctxt != 0 }
 func (f *Func) ReflectMethod() bool            { return f.flags&funcReflectMethod != 0 }
 func (f *Func) IsHiddenClosure() bool          { return f.flags&funcIsHiddenClosure != 0 }
+func (f *Func) IsDeadcodeClosure() bool        { return f.flags&funcIsDeadcodeClosure != 0 }
 func (f *Func) HasDefer() bool                 { return f.flags&funcHasDefer != 0 }
 func (f *Func) NilCheckDisabled() bool         { return f.flags&funcNilCheckDisabled != 0 }
 func (f *Func) InlinabilityChecked() bool      { return f.flags&funcInlinabilityChecked != 0 }
@@ -230,6 +232,7 @@ func (f *Func) SetABIWrapper(b bool)               { f.flags.set(funcABIWrapper,
 func (f *Func) SetNeedctxt(b bool)                 { f.flags.set(funcNeedctxt, b) }
 func (f *Func) SetReflectMethod(b bool)            { f.flags.set(funcReflectMethod, b) }
 func (f *Func) SetIsHiddenClosure(b bool)          { f.flags.set(funcIsHiddenClosure, b) }
+func (f *Func) SetIsDeadcodeClosure(b bool)        { f.flags.set(funcIsDeadcodeClosure, b) }
 func (f *Func) SetHasDefer(b bool)                 { f.flags.set(funcHasDefer, b) }
 func (f *Func) SetNilCheckDisabled(b bool)         { f.flags.set(funcNilCheckDisabled, b) }
 func (f *Func) SetInlinabilityChecked(b bool)      { f.flags.set(funcInlinabilityChecked, b) }
index a7ff4ac9c77a1a122b8fd558dd69f6b83e4879cb..eeb74081fb8bc51724e761f3579dc660416490bb 100644 (file)
@@ -62,7 +62,7 @@ const (
 
 func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) }
 func (n *miniNode) SetTypecheck(x uint8) {
-       if x > 3 {
+       if x > 2 {
                panic(fmt.Sprintf("cannot SetTypecheck %d", x))
        }
        n.bits.set2(miniTypecheckShift, x)
index a2eec05013e1092076ec62524c1f3235bc5d1fd1..1d4110c73cf731ac343a5b8395a917663b902e8f 100644 (file)
@@ -40,6 +40,7 @@ type Name struct {
        Class     Class      // uint8
        pragma    PragmaFlag // int16
        flags     bitset16
+       DictIndex uint16 // index of the dictionary entry describing the type of this variable declaration plus 1
        sym       *types.Sym
        Func      *Func // TODO(austin): nil for I.M, eqFor, hashfor, and hashmem
        Offset_   int64
@@ -51,6 +52,8 @@ type Name struct {
        // For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
        // For a closure var, the ONAME node of the outer captured variable.
        // For the case-local variables of a type switch, the type switch guard (OTYPESW).
+       // For a range variable, the range statement (ORANGE)
+       // For a recv variable in a case of a select statement, the receive assignment (OSELRECV2)
        // For the name of a function, points to corresponding Func node.
        Defn Node
 
@@ -143,7 +146,10 @@ func (n *Name) editChildren(edit func(Node) Node)  {}
 // That is, given "type T Defn", it returns Defn.
 // It is used by package types.
 func (n *Name) TypeDefn() *types.Type {
-       return n.Ntype.Type()
+       if n.Ntype != nil {
+               return n.Ntype.Type()
+       }
+       return n.Type()
 }
 
 // RecordFrameOffset records the frame offset for the name.
index f071cb78ce56db74703f29be24d5c06802a76e18..8784f9ef994d653c40fb2d374d8efe12bab92d36 100644 (file)
@@ -334,6 +334,16 @@ const (
        OEND
 )
 
+// IsCmp reports whether op is a comparison operation (==, !=, <, <=,
+// >, or >=).
+func (op Op) IsCmp() bool {
+       switch op {
+       case OEQ, ONE, OLT, OLE, OGT, OGE:
+               return true
+       }
+       return false
+}
+
 // Nodes is a pointer to a slice of *Node.
 // For fields that are not used in most nodes, this is used instead of
 // a slice to save space.
index aa41c03beb97dd9f0d136cdcd6b15409de733850..44988880c8c2a7a52a37517cc57d361e3b3ab144 100644 (file)
@@ -1331,15 +1331,15 @@ func (n *TailCallStmt) doChildren(do func(Node) bool) bool {
        if doNodes(n.init, do) {
                return true
        }
-       if n.Target != nil && do(n.Target) {
+       if n.Call != nil && do(n.Call) {
                return true
        }
        return false
 }
 func (n *TailCallStmt) editChildren(edit func(Node) Node) {
        editNodes(n.init, edit)
-       if n.Target != nil {
-               n.Target = edit(n.Target).(*Name)
+       if n.Call != nil {
+               n.Call = edit(n.Call).(*CallExpr)
        }
 }
 
index 2cfceaa1f627fa1e4d7773b828278ecd94dd902f..a42951c1dda2de5676c496e1b9cfe45971e54ed5 100644 (file)
@@ -116,12 +116,11 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
                var i int
                for i = len(v.stack) - 1; i >= 0; i-- {
                        x := v.stack[i]
+                       v.nodeID[x] = ^uint32(0)
                        if x == n {
                                break
                        }
-                       v.nodeID[x] = ^uint32(0)
                }
-               v.nodeID[n] = ^uint32(0)
                block := v.stack[i:]
                // Run escape analysis on this set of functions.
                v.stack = v.stack[:i]
index 8115012f97852c030d59b0e74bdd0cad17825916..e7d0d873b781ef79e43fa81d2447a139a54cdea5 100644 (file)
@@ -244,7 +244,7 @@ func NewGoDeferStmt(pos src.XPos, op Op, call Node) *GoDeferStmt {
        return n
 }
 
-// A IfStmt is a return statement: if Init; Cond { Then } else { Else }.
+// An IfStmt is a return statement: if Init; Cond { Body } else { Else }.
 type IfStmt struct {
        miniStmt
        Cond   Node
@@ -338,7 +338,7 @@ type SelectStmt struct {
        HasBreak bool
 
        // TODO(rsc): Instead of recording here, replace with a block?
-       Compiled Nodes // compiled form, after walkSwitch
+       Compiled Nodes // compiled form, after walkSelect
 }
 
 func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt {
@@ -385,14 +385,11 @@ func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
 // code generation to jump directly to another function entirely.
 type TailCallStmt struct {
        miniStmt
-       Target *Name
+       Call *CallExpr // the underlying call
 }
 
-func NewTailCallStmt(pos src.XPos, target *Name) *TailCallStmt {
-       if target.Op() != ONAME || target.Class != PFUNC {
-               base.FatalfAt(pos, "tail call to non-func %v", target)
-       }
-       n := &TailCallStmt{Target: target}
+func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt {
+       n := &TailCallStmt{Call: call}
        n.pos = pos
        n.op = OTAILCALL
        return n
index 61727fb1c4b004d52e4942631e200ce837f791f4..b204a1d544e7b4e2ba9835d1b7c27f529082adf6 100644 (file)
@@ -11,33 +11,36 @@ import (
 
 // Syms holds known symbols.
 var Syms struct {
-       AssertE2I       *obj.LSym
-       AssertE2I2      *obj.LSym
-       AssertI2I       *obj.LSym
-       AssertI2I2      *obj.LSym
-       Deferproc       *obj.LSym
-       DeferprocStack  *obj.LSym
-       Deferreturn     *obj.LSym
-       Duffcopy        *obj.LSym
-       Duffzero        *obj.LSym
-       GCWriteBarrier  *obj.LSym
-       Goschedguarded  *obj.LSym
-       Growslice       *obj.LSym
-       Msanread        *obj.LSym
-       Msanwrite       *obj.LSym
-       Msanmove        *obj.LSym
-       Newobject       *obj.LSym
-       Newproc         *obj.LSym
-       Panicdivide     *obj.LSym
-       Panicshift      *obj.LSym
-       PanicdottypeE   *obj.LSym
-       PanicdottypeI   *obj.LSym
-       Panicnildottype *obj.LSym
-       Panicoverflow   *obj.LSym
-       Raceread        *obj.LSym
-       Racereadrange   *obj.LSym
-       Racewrite       *obj.LSym
-       Racewriterange  *obj.LSym
+       AssertE2I         *obj.LSym
+       AssertE2I2        *obj.LSym
+       AssertI2I         *obj.LSym
+       AssertI2I2        *obj.LSym
+       Asanread          *obj.LSym
+       Asanwrite         *obj.LSym
+       CheckPtrAlignment *obj.LSym
+       Deferproc         *obj.LSym
+       DeferprocStack    *obj.LSym
+       Deferreturn       *obj.LSym
+       Duffcopy          *obj.LSym
+       Duffzero          *obj.LSym
+       GCWriteBarrier    *obj.LSym
+       Goschedguarded    *obj.LSym
+       Growslice         *obj.LSym
+       Msanread          *obj.LSym
+       Msanwrite         *obj.LSym
+       Msanmove          *obj.LSym
+       Newobject         *obj.LSym
+       Newproc           *obj.LSym
+       Panicdivide       *obj.LSym
+       Panicshift        *obj.LSym
+       PanicdottypeE     *obj.LSym
+       PanicdottypeI     *obj.LSym
+       Panicnildottype   *obj.LSym
+       Panicoverflow     *obj.LSym
+       Raceread          *obj.LSym
+       Racereadrange     *obj.LSym
+       Racewrite         *obj.LSym
+       Racewriterange    *obj.LSym
        // Wasm
        SigPanic        *obj.LSym
        Staticuint64s   *obj.LSym
@@ -68,5 +71,4 @@ var Pkgs struct {
        Go      *types.Pkg
        Itab    *types.Pkg
        Runtime *types.Pkg
-       Unsafe  *types.Pkg
 }
diff --git a/src/cmd/compile/internal/liveness/arg.go b/src/cmd/compile/internal/liveness/arg.go
new file mode 100644 (file)
index 0000000..2ca5d09
--- /dev/null
@@ -0,0 +1,339 @@
+// Copyright 2021 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 liveness
+
+import (
+       "fmt"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/bitvec"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/objw"
+       "cmd/compile/internal/ssa"
+       "cmd/internal/obj"
+       "cmd/internal/objabi"
+)
+
+// Argument liveness tracking.
+//
+// For arguments passed in registers, this file tracks if their spill slots
+// are live for runtime traceback. An argument spill slot is live at a PC
+// if we know that an actual value has stored into it at or before this point.
+//
+// Stack args are always live and not tracked in this code. Stack args are
+// laid out before register spill slots, so we emit the smallest offset that
+// needs tracking. Slots before that offset are always live. That offset is
+// usually the offset of the first spill slot. But if the first spill slot is
+// always live (e.g. if it is address-taken), it will be the offset of a later
+// one.
+//
+// The liveness information is emitted as a FUNCDATA and a PCDATA.
+//
+// FUNCDATA format:
+// - start (smallest) offset that needs tracking (1 byte)
+// - a list of bitmaps.
+//   In a bitmap bit i is set if the i-th spill slot is live.
+//
+// At a PC where the liveness info changes, a PCDATA indicates the
+// byte offset of the liveness map in the FUNCDATA. PCDATA -1 is a
+// special case indicating all slots are live (for binary size
+// saving).
+
+const allLiveIdx = -1
+
+// name and offset
+type nameOff struct {
+       n   *ir.Name
+       off int64
+}
+
+func (a nameOff) FrameOffset() int64 { return a.n.FrameOffset() + a.off }
+func (a nameOff) String() string     { return fmt.Sprintf("%v+%d", a.n, a.off) }
+
+type blockArgEffects struct {
+       livein  bitvec.BitVec // variables live at block entry
+       liveout bitvec.BitVec // variables live at block exit
+}
+
+type argLiveness struct {
+       fn   *ir.Func
+       f    *ssa.Func
+       args []nameOff         // name and offset of spill slots
+       idx  map[nameOff]int32 // index in args
+
+       be []blockArgEffects // indexed by block ID
+
+       bvset bvecSet // Set of liveness bitmaps, used for uniquifying.
+
+       // Liveness map indices at each Value (where it changes) and Block entry.
+       // During the computation the indices are temporarily index to bvset.
+       // At the end they will be index (offset) to the output funcdata (changed
+       // in (*argLiveness).emit).
+       blockIdx map[ssa.ID]int
+       valueIdx map[ssa.ID]int
+}
+
+// ArgLiveness computes the liveness information of register argument spill slots.
+// An argument's spill slot is "live" if we know it contains a meaningful value,
+// that is, we have stored the register value to it.
+// Returns the liveness map indices at each Block entry and at each Value (where
+// it changes).
+func ArgLiveness(fn *ir.Func, f *ssa.Func, pp *objw.Progs) (blockIdx, valueIdx map[ssa.ID]int) {
+       if f.OwnAux.ABIInfo().InRegistersUsed() == 0 || base.Flag.N != 0 {
+               // No register args. Nothing to emit.
+               // Or if -N is used we spill everything upfront so it is always live.
+               return nil, nil
+       }
+
+       lv := &argLiveness{
+               fn:       fn,
+               f:        f,
+               idx:      make(map[nameOff]int32),
+               be:       make([]blockArgEffects, f.NumBlocks()),
+               blockIdx: make(map[ssa.ID]int),
+               valueIdx: make(map[ssa.ID]int),
+       }
+       // Gather all register arg spill slots.
+       for _, a := range f.OwnAux.ABIInfo().InParams() {
+               n, ok := a.Name.(*ir.Name)
+               if !ok || len(a.Registers) == 0 {
+                       continue
+               }
+               _, offs := a.RegisterTypesAndOffsets()
+               for _, off := range offs {
+                       if n.FrameOffset()+off > 0xff {
+                               // We only print a limited number of args, with stack
+                               // offsets no larger than 255.
+                               continue
+                       }
+                       lv.args = append(lv.args, nameOff{n, off})
+               }
+       }
+       if len(lv.args) > 10 {
+               lv.args = lv.args[:10] // We print no more than 10 args.
+       }
+
+       // We spill address-taken or non-SSA-able value upfront, so they are always live.
+       alwaysLive := func(n *ir.Name) bool { return n.Addrtaken() || !f.Frontend().CanSSA(n.Type()) }
+
+       // We'll emit the smallest offset for the slots that need liveness info.
+       // No need to include a slot with a lower offset if it is always live.
+       for len(lv.args) > 0 && alwaysLive(lv.args[0].n) {
+               lv.args = lv.args[1:]
+       }
+       if len(lv.args) == 0 {
+               return // everything is always live
+       }
+
+       for i, a := range lv.args {
+               lv.idx[a] = int32(i)
+       }
+
+       nargs := int32(len(lv.args))
+       bulk := bitvec.NewBulk(nargs, int32(len(f.Blocks)*2))
+       for _, b := range f.Blocks {
+               be := &lv.be[b.ID]
+               be.livein = bulk.Next()
+               be.liveout = bulk.Next()
+
+               // initialize to all 1s, so we can AND them
+               be.livein.Not()
+               be.liveout.Not()
+       }
+
+       entrybe := &lv.be[f.Entry.ID]
+       entrybe.livein.Clear()
+       for i, a := range lv.args {
+               if alwaysLive(a.n) {
+                       entrybe.livein.Set(int32(i))
+               }
+       }
+
+       // Visit blocks in reverse-postorder, compute block effects.
+       po := f.Postorder()
+       for i := len(po) - 1; i >= 0; i-- {
+               b := po[i]
+               be := &lv.be[b.ID]
+
+               // A slot is live at block entry if it is live in all predecessors.
+               for _, pred := range b.Preds {
+                       pb := pred.Block()
+                       be.livein.And(be.livein, lv.be[pb.ID].liveout)
+               }
+
+               be.liveout.Copy(be.livein)
+               for _, v := range b.Values {
+                       lv.valueEffect(v, be.liveout)
+               }
+       }
+
+       // Coalesce identical live vectors. Compute liveness indices at each PC
+       // where it changes.
+       live := bitvec.New(nargs)
+       addToSet := func(bv bitvec.BitVec) (int, bool) {
+               if bv.Count() == int(nargs) { // special case for all live
+                       return allLiveIdx, false
+               }
+               return lv.bvset.add(bv)
+       }
+       for _, b := range lv.f.Blocks {
+               be := &lv.be[b.ID]
+               lv.blockIdx[b.ID], _ = addToSet(be.livein)
+
+               live.Copy(be.livein)
+               var lastv *ssa.Value
+               for i, v := range b.Values {
+                       if lv.valueEffect(v, live) {
+                               // Record that liveness changes but not emit a map now.
+                               // For a sequence of StoreRegs we only need to emit one
+                               // at last.
+                               lastv = v
+                       }
+                       if lastv != nil && (mayFault(v) || i == len(b.Values)-1) {
+                               // Emit the liveness map if it may fault or at the end of
+                               // the block. We may need a traceback if the instruction
+                               // may cause a panic.
+                               var added bool
+                               lv.valueIdx[lastv.ID], added = addToSet(live)
+                               if added {
+                                       // live is added to bvset and we cannot modify it now.
+                                       // Make a copy.
+                                       t := live
+                                       live = bitvec.New(nargs)
+                                       live.Copy(t)
+                               }
+                               lastv = nil
+                       }
+               }
+
+               // Sanity check.
+               if !live.Eq(be.liveout) {
+                       panic("wrong arg liveness map at block end")
+               }
+       }
+
+       // Emit funcdata symbol, update indices to offsets in the symbol data.
+       lsym := lv.emit()
+       fn.LSym.Func().ArgLiveInfo = lsym
+
+       //lv.print()
+
+       p := pp.Prog(obj.AFUNCDATA)
+       p.From.SetConst(objabi.FUNCDATA_ArgLiveInfo)
+       p.To.Type = obj.TYPE_MEM
+       p.To.Name = obj.NAME_EXTERN
+       p.To.Sym = lsym
+
+       return lv.blockIdx, lv.valueIdx
+}
+
+// valueEffect applies the effect of v to live, return whether it is changed.
+func (lv *argLiveness) valueEffect(v *ssa.Value, live bitvec.BitVec) bool {
+       if v.Op != ssa.OpStoreReg { // TODO: include other store instructions?
+               return false
+       }
+       n, off := ssa.AutoVar(v)
+       if n.Class != ir.PPARAM {
+               return false
+       }
+       i, ok := lv.idx[nameOff{n, off}]
+       if !ok || live.Get(i) {
+               return false
+       }
+       live.Set(i)
+       return true
+}
+
+func mayFault(v *ssa.Value) bool {
+       switch v.Op {
+       case ssa.OpLoadReg, ssa.OpStoreReg, ssa.OpCopy, ssa.OpPhi,
+               ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive,
+               ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult,
+               ssa.OpConvert, ssa.OpInlMark, ssa.OpGetG:
+               return false
+       }
+       if len(v.Args) == 0 {
+               return false // assume constant op cannot fault
+       }
+       return true // conservatively assume all other ops could fault
+}
+
+func (lv *argLiveness) print() {
+       fmt.Println("argument liveness:", lv.f.Name)
+       live := bitvec.New(int32(len(lv.args)))
+       for _, b := range lv.f.Blocks {
+               be := &lv.be[b.ID]
+
+               fmt.Printf("%v: live in: ", b)
+               lv.printLivenessVec(be.livein)
+               if idx, ok := lv.blockIdx[b.ID]; ok {
+                       fmt.Printf("   #%d", idx)
+               }
+               fmt.Println()
+
+               for _, v := range b.Values {
+                       if lv.valueEffect(v, live) {
+                               fmt.Printf("  %v: ", v)
+                               lv.printLivenessVec(live)
+                               if idx, ok := lv.valueIdx[v.ID]; ok {
+                                       fmt.Printf("   #%d", idx)
+                               }
+                               fmt.Println()
+                       }
+               }
+
+               fmt.Printf("%v: live out: ", b)
+               lv.printLivenessVec(be.liveout)
+               fmt.Println()
+       }
+       fmt.Println("liveness maps data:", lv.fn.LSym.Func().ArgLiveInfo.P)
+}
+
+func (lv *argLiveness) printLivenessVec(bv bitvec.BitVec) {
+       for i, a := range lv.args {
+               if bv.Get(int32(i)) {
+                       fmt.Printf("%v ", a)
+               }
+       }
+}
+
+func (lv *argLiveness) emit() *obj.LSym {
+       livenessMaps := lv.bvset.extractUnique()
+
+       // stack offsets of register arg spill slots
+       argOffsets := make([]uint8, len(lv.args))
+       for i, a := range lv.args {
+               off := a.FrameOffset()
+               if off > 0xff {
+                       panic("offset too large")
+               }
+               argOffsets[i] = uint8(off)
+       }
+
+       idx2off := make([]int, len(livenessMaps))
+
+       lsym := base.Ctxt.Lookup(lv.fn.LSym.Name + ".argliveinfo")
+       lsym.Set(obj.AttrContentAddressable, true)
+
+       off := objw.Uint8(lsym, 0, argOffsets[0]) // smallest offset that needs liveness info.
+       for idx, live := range livenessMaps {
+               idx2off[idx] = off
+               off = objw.BitVec(lsym, off, live)
+       }
+
+       // Update liveness indices to offsets.
+       for i, x := range lv.blockIdx {
+               if x != allLiveIdx {
+                       lv.blockIdx[i] = idx2off[x]
+               }
+       }
+       for i, x := range lv.valueIdx {
+               if x != allLiveIdx {
+                       lv.valueIdx[i] = idx2off[x]
+               }
+       }
+
+       return lsym
+}
index 3431f54ede84e09bec45272d044247e115eb59d2..60b25938677c85c1ce7c07be102159230f506637 100644 (file)
@@ -47,9 +47,10 @@ func (m *bvecSet) grow() {
        m.index = newIndex
 }
 
-// add adds bv to the set and returns its index in m.extractUnique.
-// The caller must not modify bv after this.
-func (m *bvecSet) add(bv bitvec.BitVec) int {
+// add adds bv to the set and returns its index in m.extractUnique,
+// and whether it is newly added.
+// If it is newly added, the caller must not modify bv after this.
+func (m *bvecSet) add(bv bitvec.BitVec) (int, bool) {
        if len(m.uniq)*4 >= len(m.index) {
                m.grow()
        }
@@ -62,12 +63,12 @@ func (m *bvecSet) add(bv bitvec.BitVec) int {
                        // New bvec.
                        index[h] = len(m.uniq)
                        m.uniq = append(m.uniq, bv)
-                       return len(m.uniq) - 1
+                       return len(m.uniq) - 1, true
                }
                jlive := m.uniq[j]
                if bv.Eq(jlive) {
                        // Existing bvec.
-                       return j
+                       return j, false
                }
 
                h++
index 2705eac4f7b9b8f4316b2e2e44efe9d589e08ef0..3202e506c8f913aef4c14aad66a388b6b8971cc2 100644 (file)
@@ -15,7 +15,6 @@
 package liveness
 
 import (
-       "crypto/md5"
        "crypto/sha1"
        "fmt"
        "os"
@@ -274,7 +273,7 @@ func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
                }
        }
 
-       if n.Class == ir.PPARAM && !n.Addrtaken() && n.Type().Width > int64(types.PtrSize) {
+       if n.Class == ir.PPARAM && !n.Addrtaken() && n.Type().Size() > int64(types.PtrSize) {
                // Only aggregate-typed arguments that are not address-taken can be
                // partially live.
                lv.partLiveArgs[n] = true
@@ -855,8 +854,9 @@ func (lv *liveness) epilogue() {
        if lv.fn.OpenCodedDeferDisallowed() {
                lv.livenessMap.DeferReturn = objw.LivenessDontCare
        } else {
+               idx, _ := lv.stackMapSet.add(livedefer)
                lv.livenessMap.DeferReturn = objw.LivenessIndex{
-                       StackMapIndex: lv.stackMapSet.add(livedefer),
+                       StackMapIndex: idx,
                        IsUnsafePoint: false,
                }
        }
@@ -903,7 +903,7 @@ func (lv *liveness) compact(b *ssa.Block) {
                isUnsafePoint := lv.allUnsafe || v.Op != ssa.OpClobber && lv.unsafePoints.Get(int32(v.ID))
                idx := objw.LivenessIndex{StackMapIndex: objw.StackMapDontCare, IsUnsafePoint: isUnsafePoint}
                if hasStackMap {
-                       idx.StackMapIndex = lv.stackMapSet.add(lv.livevars[pos])
+                       idx.StackMapIndex, _ = lv.stackMapSet.add(lv.livevars[pos])
                        pos++
                }
                if hasStackMap || isUnsafePoint {
@@ -1326,19 +1326,9 @@ func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) {
                loff = objw.BitVec(&liveSymTmp, loff, locals)
        }
 
-       // Give these LSyms content-addressable names,
-       // so that they can be de-duplicated.
-       // This provides significant binary size savings.
-       //
        // These symbols will be added to Ctxt.Data by addGCLocals
        // after parallel compilation is done.
-       makeSym := func(tmpSym *obj.LSym) *obj.LSym {
-               return base.Ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(tmpSym.P)), func(lsym *obj.LSym) {
-                       lsym.P = tmpSym.P
-                       lsym.Set(obj.AttrContentAddressable, true)
-               })
-       }
-       return makeSym(&argsSymTmp), makeSym(&liveSymTmp)
+       return base.Ctxt.GCLocalsSym(argsSymTmp.P), base.Ctxt.GCLocalsSym(liveSymTmp.P)
 }
 
 // Entry pointer for Compute analysis. Solves for the Compute of
@@ -1428,6 +1418,7 @@ func (lv *liveness) emitStackObjects() *obj.LSym {
        // Populate the stack object data.
        // Format must match runtime/stack.go:stackObjectRecord.
        x := base.Ctxt.Lookup(lv.fn.LSym.Name + ".stkobj")
+       x.Set(obj.AttrContentAddressable, true)
        lv.fn.LSym.Func().StackObjects = x
        off := 0
        off = objw.Uintptr(x, off, uint64(len(vars)))
@@ -1444,7 +1435,7 @@ func (lv *liveness) emitStackObjects() *obj.LSym {
                off = objw.Uint32(x, off, uint32(frameOffset))
 
                t := v.Type()
-               sz := t.Width
+               sz := t.Size()
                if sz != int64(int32(sz)) {
                        base.Fatalf("stack object too big: %v of type %v, size %d", v, t, sz)
                }
@@ -1454,7 +1445,7 @@ func (lv *liveness) emitStackObjects() *obj.LSym {
                }
                off = objw.Uint32(x, off, uint32(sz))
                off = objw.Uint32(x, off, uint32(ptrdata))
-               off = objw.SymPtr(x, off, lsym, 0)
+               off = objw.SymPtrOff(x, off, lsym)
        }
 
        if base.Flag.Live != 0 {
index e0447f38cbf23347c05a831d304581259eb9b092..6326f966bf2158807d6bdab361a19393c884f831 100644 (file)
@@ -475,6 +475,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p6.To.SetTarget(p2)
        case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter:
                s.Call(v)
+       case ssa.OpMIPSCALLtail:
+               s.TailCall(v)
        case ssa.OpMIPSLoweredWB:
                p := s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
@@ -841,14 +843,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        p.To.Type = obj.TYPE_BRANCH
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
        case ssa.BlockRet:
                s.Prog(obj.ARET)
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
        case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
                ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
                ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
index e821a00876fa799bc6b0a4413ed48acb445e336e..990b9788f765e39974873f07f544b218b171df6f 100644 (file)
@@ -491,6 +491,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p6.To.SetTarget(p2)
        case ssa.OpMIPS64CALLstatic, ssa.OpMIPS64CALLclosure, ssa.OpMIPS64CALLinter:
                s.Call(v)
+       case ssa.OpMIPS64CALLtail:
+               s.TailCall(v)
        case ssa.OpMIPS64LoweredWB:
                p := s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
@@ -808,14 +810,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        p.To.Type = obj.TYPE_BRANCH
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
        case ssa.BlockRet:
                s.Prog(obj.ARET)
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
        case ssa.BlockMIPS64EQ, ssa.BlockMIPS64NE,
                ssa.BlockMIPS64LTZ, ssa.BlockMIPS64GEZ,
                ssa.BlockMIPS64LEZ, ssa.BlockMIPS64GTZ,
index 429c8a14c8ad1f1b436ac25742e671ab215b46f3..82455f7d4a60dc139956a8f2ddf2b1fcf8acbdc3 100644 (file)
@@ -18,26 +18,24 @@ import (
 // TODO(mdempsky): Skip blank declarations? Probably only safe
 // for declarations without pragmas.
 
-func (g *irgen) decls(decls []syntax.Decl) []ir.Node {
-       var res ir.Nodes
+func (g *irgen) decls(res *ir.Nodes, decls []syntax.Decl) {
        for _, decl := range decls {
                switch decl := decl.(type) {
                case *syntax.ConstDecl:
-                       g.constDecl(&res, decl)
+                       g.constDecl(res, decl)
                case *syntax.FuncDecl:
-                       g.funcDecl(&res, decl)
+                       g.funcDecl(res, decl)
                case *syntax.TypeDecl:
                        if ir.CurFunc == nil {
                                continue // already handled in irgen.generate
                        }
-                       g.typeDecl(&res, decl)
+                       g.typeDecl(res, decl)
                case *syntax.VarDecl:
-                       g.varDecl(&res, decl)
+                       g.varDecl(res, decl)
                default:
                        g.unhandled("declaration", decl)
                }
        }
-       return res
 }
 
 func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
@@ -88,6 +86,17 @@ func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
 }
 
 func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
+       // Set g.curDecl to the function name, as context for the type params declared
+       // during types2-to-types1 translation if this is a generic function.
+       g.curDecl = decl.Name.Value
+       obj2 := g.info.Defs[decl.Name]
+       recv := types2.AsSignature(obj2.Type()).Recv()
+       if recv != nil {
+               t2 := deref2(recv.Type())
+               // This is a method, so set g.curDecl to recvTypeName.methName instead.
+               g.curDecl = types2.AsNamed(t2).Obj().Name() + "." + g.curDecl
+       }
+
        fn := ir.NewFunc(g.pos(decl))
        fn.Nname, _ = g.def(decl.Name)
        fn.Nname.Func = fn
@@ -97,31 +106,61 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
        if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
                base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
        }
+       if fn.Pragma&ir.Nointerface != 0 {
+               // Propagate //go:nointerface from Func.Pragma to Field.Nointerface.
+               // This is a bit roundabout, but this is the earliest point where we've
+               // processed the function's pragma flags, and we've also already created
+               // the Fields to represent the receiver's method set.
+               if recv := fn.Type().Recv(); recv != nil {
+                       typ := types.ReceiverBaseType(recv.Type)
+                       if typ.OrigSym() != nil {
+                               // For a generic method, we mark the methods on the
+                               // base generic type, since those are the methods
+                               // that will be stenciled.
+                               typ = typ.OrigSym().Def.Type()
+                       }
+                       meth := typecheck.Lookdot1(fn, typecheck.Lookup(decl.Name.Value), typ, typ.Methods(), 0)
+                       meth.SetNointerface(true)
+               }
+       }
+
+       if decl.Body != nil && fn.Pragma&ir.Noescape != 0 {
+               base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations")
+       }
 
        if decl.Name.Value == "init" && decl.Recv == nil {
                g.target.Inits = append(g.target.Inits, fn)
        }
 
-       if fn.Type().HasTParam() {
-               g.topFuncIsGeneric = true
-       }
-       g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
-       g.topFuncIsGeneric = false
-       if fn.Type().HasTParam() && fn.Body != nil {
-               // Set pointers to the dcls/body of a generic function/method in
-               // the Inl struct, so it is marked for export, is available for
-               // stenciling, and works with Inline_Flood().
-               fn.Inl = &ir.Inline{
-                       Cost: 1,
-                       Dcl:  fn.Dcl,
-                       Body: fn.Body,
+       haveEmbed := g.haveEmbed
+       g.later(func() {
+               defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
+
+               g.haveEmbed = haveEmbed
+               if fn.Type().HasTParam() {
+                       g.topFuncIsGeneric = true
+               }
+               g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
+               g.topFuncIsGeneric = false
+               if fn.Type().HasTParam() && fn.Body != nil {
+                       // Set pointers to the dcls/body of a generic function/method in
+                       // the Inl struct, so it is marked for export, is available for
+                       // stenciling, and works with Inline_Flood().
+                       fn.Inl = &ir.Inline{
+                               Cost: 1,
+                               Dcl:  fn.Dcl,
+                               Body: fn.Body,
+                       }
                }
-       }
 
-       out.Append(fn)
+               out.Append(fn)
+       })
 }
 
 func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
+       // Set g.curDecl to the type name, as context for the type params declared
+       // during types2-to-types1 translation if this is a generic type.
+       g.curDecl = decl.Name.Value
        if decl.Alias {
                name, _ := g.def(decl.Name)
                g.pragmaFlags(decl.Pragma, 0)
@@ -137,8 +176,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
        name, obj := g.def(decl.Name)
        ntyp, otyp := name.Type(), obj.Type()
        if ir.CurFunc != nil {
-               typecheck.TypeGen++
-               ntyp.Vargen = typecheck.TypeGen
+               ntyp.SetVargen()
        }
 
        pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
@@ -170,11 +208,11 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
        // object to new type pragmas.]
        ntyp.SetUnderlying(g.typeExpr(decl.Type))
 
-       tparams := otyp.(*types2.Named).TParams()
+       tparams := otyp.(*types2.Named).TypeParams()
        if n := tparams.Len(); n > 0 {
                rparams := make([]*types.Type, n)
                for i := range rparams {
-                       rparams[i] = g.typ(tparams.At(i).Type())
+                       rparams[i] = g.typ(tparams.At(i))
                }
                // This will set hasTParam flag if any rparams are not concrete types.
                ntyp.SetRParams(rparams)
@@ -185,6 +223,9 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
                methods := make([]*types.Field, otyp.NumMethods())
                for i := range methods {
                        m := otyp.Method(i)
+                       // Set g.curDecl to recvTypeName.methName, as context for the
+                       // method-specific type params in the receiver.
+                       g.curDecl = decl.Name.Value + "." + m.Name()
                        meth := g.obj(m)
                        methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
                        methods[i].Nname = meth
@@ -201,53 +242,68 @@ func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
        for i, name := range decl.NameList {
                names[i], _ = g.def(name)
        }
-       values := g.exprList(decl.Values)
 
        if decl.Pragma != nil {
                pragma := decl.Pragma.(*pragmas)
-               // TODO(mdempsky): Plumb noder.importedEmbed through to here.
-               varEmbed(g.makeXPos, names[0], decl, pragma, true)
+               varEmbed(g.makeXPos, names[0], decl, pragma, g.haveEmbed)
                g.reportUnused(pragma)
        }
 
-       var as2 *ir.AssignListStmt
-       if len(values) != 0 && len(names) != len(values) {
-               as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
-       }
+       haveEmbed := g.haveEmbed
+       do := func() {
+               defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
+
+               g.haveEmbed = haveEmbed
+               values := g.exprList(decl.Values)
 
-       for i, name := range names {
-               if ir.CurFunc != nil {
-                       out.Append(ir.NewDecl(pos, ir.ODCL, name))
+               var as2 *ir.AssignListStmt
+               if len(values) != 0 && len(names) != len(values) {
+                       as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
                }
-               if as2 != nil {
-                       as2.Lhs[i] = name
-                       name.Defn = as2
-               } else {
-                       as := ir.NewAssignStmt(pos, name, nil)
-                       if len(values) != 0 {
-                               as.Y = values[i]
-                               name.Defn = as
-                       } else if ir.CurFunc == nil {
-                               name.Defn = as
-                       }
-                       lhs := []ir.Node{as.X}
-                       rhs := []ir.Node{}
-                       if as.Y != nil {
-                               rhs = []ir.Node{as.Y}
+
+               for i, name := range names {
+                       if ir.CurFunc != nil {
+                               out.Append(ir.NewDecl(pos, ir.ODCL, name))
                        }
-                       transformAssign(as, lhs, rhs)
-                       as.X = lhs[0]
-                       if as.Y != nil {
-                               as.Y = rhs[0]
+                       if as2 != nil {
+                               as2.Lhs[i] = name
+                               name.Defn = as2
+                       } else {
+                               as := ir.NewAssignStmt(pos, name, nil)
+                               if len(values) != 0 {
+                                       as.Y = values[i]
+                                       name.Defn = as
+                               } else if ir.CurFunc == nil {
+                                       name.Defn = as
+                               }
+                               lhs := []ir.Node{as.X}
+                               rhs := []ir.Node{}
+                               if as.Y != nil {
+                                       rhs = []ir.Node{as.Y}
+                               }
+                               transformAssign(as, lhs, rhs)
+                               as.X = lhs[0]
+                               if as.Y != nil {
+                                       as.Y = rhs[0]
+                               }
+                               as.SetTypecheck(1)
+                               out.Append(as)
                        }
-                       as.SetTypecheck(1)
-                       out.Append(as)
+               }
+               if as2 != nil {
+                       transformAssign(as2, as2.Lhs, as2.Rhs)
+                       as2.SetTypecheck(1)
+                       out.Append(as2)
                }
        }
-       if as2 != nil {
-               transformAssign(as2, as2.Lhs, as2.Rhs)
-               as2.SetTypecheck(1)
-               out.Append(as2)
+
+       // If we're within a function, we need to process the assignment
+       // part of the variable declaration right away. Otherwise, we leave
+       // it to be handled after all top-level declarations are processed.
+       if ir.CurFunc != nil {
+               do()
+       } else {
+               g.later(do)
        }
 }
 
index 3dc61c6a69208e93dc0e745a5af2e334ff27cc0a..2c18727420aec23281eac633cb89f31e1b30efce 100644 (file)
@@ -255,7 +255,8 @@ func (r *decoder) strings() []string {
        return res
 }
 
-func (r *decoder) rawValue() constant.Value {
+func (r *decoder) value() constant.Value {
+       r.sync(syncValue)
        isComplex := r.bool()
        val := r.scalar()
        if isComplex {
index d8ab0f6255dbca273a8b2af2e8d4a725d3302876..b07b3a4a480573b8a2279bf9dce2df1445608e22 100644 (file)
@@ -237,7 +237,8 @@ func (w *encoder) strings(ss []string) {
        }
 }
 
-func (w *encoder) rawValue(val constant.Value) {
+func (w *encoder) value(val constant.Value) {
+       w.sync(syncValue)
        if w.bool(val.Kind() == constant.Complex) {
                w.scalar(constant.Real(val))
                w.scalar(constant.Imag(val))
index 3e3c352a32f69533ced634c035148391985498be..24e6dbefe7a7810694794ac896dc325b3b759251 100644 (file)
@@ -50,6 +50,8 @@ func (g *irgen) expr(expr syntax.Expr) ir.Node {
                base.FatalfAt(g.pos(expr), "unrecognized type-checker result")
        }
 
+       base.Assert(g.exprStmtOK)
+
        // The gc backend expects all expressions to have a concrete type, and
        // types2 mostly satisfies this expectation already. But there are a few
        // cases where the Go spec doesn't require converting to concrete type,
@@ -112,79 +114,27 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
 
        case *syntax.CallExpr:
                fun := g.expr(expr.Fun)
-
-               // The key for the Inferred map is the CallExpr (if inferring
-               // types required the function arguments) or the IndexExpr below
-               // (if types could be inferred without the function arguments).
-               if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.TArgs) > 0 {
-                       // This is the case where inferring types required the
-                       // types of the function arguments.
-                       targs := make([]ir.Node, len(inferred.TArgs))
-                       for i, targ := range inferred.TArgs {
-                               targs[i] = ir.TypeNode(g.typ(targ))
-                       }
-                       if fun.Op() == ir.OFUNCINST {
-                               // Replace explicit type args with the full list that
-                               // includes the additional inferred type args.
-                               // Substitute the type args for the type params in
-                               // the generic function's type.
-                               fun.(*ir.InstExpr).Targs = targs
-                               newt := g.substType(fun.Type(), fun.Type().TParams(), targs)
-                               typed(newt, fun)
-                       } else {
-                               // Create a function instantiation here, given there
-                               // are only inferred type args (e.g. min(5,6), where
-                               // min is a generic function). Substitute the type
-                               // args for the type params in the generic function's
-                               // type.
-                               inst := ir.NewInstExpr(pos, ir.OFUNCINST, fun, targs)
-                               newt := g.substType(fun.Type(), fun.Type().TParams(), targs)
-                               typed(newt, inst)
-                               fun = inst
-                       }
-
-               }
                return Call(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
 
        case *syntax.IndexExpr:
-               var targs []ir.Node
-
-               if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.TArgs) > 0 {
-                       // This is the partial type inference case where the types
-                       // can be inferred from other type arguments without using
-                       // the types of the function arguments.
-                       targs = make([]ir.Node, len(inferred.TArgs))
-                       for i, targ := range inferred.TArgs {
-                               targs[i] = ir.TypeNode(g.typ(targ))
-                       }
-               } else if _, ok := expr.Index.(*syntax.ListExpr); ok {
-                       targs = g.exprList(expr.Index)
-               } else {
-                       index := g.expr(expr.Index)
-                       if index.Op() != ir.OTYPE {
+               args := unpackListExpr(expr.Index)
+               if len(args) == 1 {
+                       tv, ok := g.info.Types[args[0]]
+                       assert(ok)
+                       if tv.IsValue() {
                                // This is just a normal index expression
-                               return Index(pos, g.typ(typ), g.expr(expr.X), index)
+                               n := Index(pos, g.typ(typ), g.expr(expr.X), g.expr(args[0]))
+                               if !g.delayTransform() {
+                                       // transformIndex will modify n.Type() for OINDEXMAP.
+                                       transformIndex(n)
+                               }
+                               return n
                        }
-                       // This is generic function instantiation with a single type
-                       targs = []ir.Node{index}
-               }
-               // This is a generic function instantiation (e.g. min[int]).
-               // Generic type instantiation is handled in the type
-               // section of expr() above (using g.typ).
-               x := g.expr(expr.X)
-               if x.Op() != ir.ONAME || x.Type().Kind() != types.TFUNC {
-                       panic("Incorrect argument for generic func instantiation")
-               }
-               n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs)
-               newt := g.typ(typ)
-               // Substitute the type args for the type params in the uninstantiated
-               // function's type. If there aren't enough type args, then the rest
-               // will be inferred at the call node, so don't try the substitution yet.
-               if x.Type().TParams().NumFields() == len(targs) {
-                       newt = g.substType(g.typ(typ), x.Type().TParams(), targs)
                }
-               typed(newt, n)
-               return n
+
+               // expr.Index is a list of type args, so we ignore it, since types2 has
+               // already provided this info with the Info.Instances map.
+               return g.expr(expr.X)
 
        case *syntax.SelectorExpr:
                // Qualified identifier.
@@ -196,17 +146,37 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
                return g.selectorExpr(pos, typ, expr)
 
        case *syntax.SliceExpr:
-               return Slice(pos, g.typ(typ), g.expr(expr.X), g.expr(expr.Index[0]), g.expr(expr.Index[1]), g.expr(expr.Index[2]))
+               n := Slice(pos, g.typ(typ), g.expr(expr.X), g.expr(expr.Index[0]), g.expr(expr.Index[1]), g.expr(expr.Index[2]))
+               if !g.delayTransform() {
+                       transformSlice(n)
+               }
+               return n
 
        case *syntax.Operation:
                if expr.Y == nil {
-                       return Unary(pos, g.typ(typ), g.op(expr.Op, unOps[:]), g.expr(expr.X))
+                       n := Unary(pos, g.typ(typ), g.op(expr.Op, unOps[:]), g.expr(expr.X))
+                       if n.Op() == ir.OADDR && !g.delayTransform() {
+                               transformAddr(n.(*ir.AddrExpr))
+                       }
+                       return n
                }
                switch op := g.op(expr.Op, binOps[:]); op {
                case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
-                       return Compare(pos, g.typ(typ), op, g.expr(expr.X), g.expr(expr.Y))
+                       n := Compare(pos, g.typ(typ), op, g.expr(expr.X), g.expr(expr.Y))
+                       if !g.delayTransform() {
+                               transformCompare(n)
+                       }
+                       return n
+               case ir.OANDAND, ir.OOROR:
+                       x := g.expr(expr.X)
+                       y := g.expr(expr.Y)
+                       return typed(x.Type(), ir.NewLogicalExpr(pos, op, x, y))
                default:
-                       return Binary(pos, op, g.typ(typ), g.expr(expr.X), g.expr(expr.Y))
+                       n := Binary(pos, op, g.typ(typ), g.expr(expr.X), g.expr(expr.Y))
+                       if op == ir.OADD && !g.delayTransform() {
+                               return transformAdd(n)
+                       }
+                       return n
                }
 
        default:
@@ -233,7 +203,6 @@ func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node)
                Targs:   targs1,
        }
        newt := ts.Typ(typ)
-       g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
        return newt
 }
 
@@ -247,44 +216,6 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
                // only be fully transformed once it has an instantiated type.
                n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value))
                typed(g.typ(typ), n)
-
-               // Fill in n.Selection for a generic method reference or a bound
-               // interface method, even though we won't use it directly, since it
-               // is useful for analysis. Specifically do not fill in for fields or
-               // other interfaces methods (method call on an interface value), so
-               // n.Selection being non-nil means a method reference for a generic
-               // type or a method reference due to a bound.
-               obj2 := g.info.Selections[expr].Obj()
-               sig := types2.AsSignature(obj2.Type())
-               if sig == nil || sig.Recv() == nil {
-                       return n
-               }
-               index := g.info.Selections[expr].Index()
-               last := index[len(index)-1]
-               // recvType is the receiver of the method being called.  Because of the
-               // way methods are imported, g.obj(obj2) doesn't work across
-               // packages, so we have to lookup the method via the receiver type.
-               recvType := deref2(sig.Recv().Type())
-               if types2.AsInterface(recvType.Underlying()) != nil {
-                       fieldType := n.X.Type()
-                       for _, ix := range index[:len(index)-1] {
-                               fieldType = fieldType.Field(ix).Type
-                       }
-                       if fieldType.Kind() == types.TTYPEPARAM {
-                               n.Selection = fieldType.Bound().AllMethods().Index(last)
-                               //fmt.Printf(">>>>> %v: Bound call %v\n", base.FmtPos(pos), n.Sel)
-                       } else {
-                               assert(fieldType.Kind() == types.TINTER)
-                               //fmt.Printf(">>>>> %v: Interface call %v\n", base.FmtPos(pos), n.Sel)
-                       }
-                       return n
-               }
-
-               recvObj := types2.AsNamed(recvType).Obj()
-               recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def
-               n.Selection = recv.Type().Methods().Index(last)
-               //fmt.Printf(">>>>> %v: Method call %v\n", base.FmtPos(pos), n.Sel)
-
                return n
        }
 
@@ -304,12 +235,6 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
                return DotField(pos, x, last)
        }
 
-       // TODO(danscales,mdempsky): Interface method sets are not sorted the
-       // same between types and types2. In particular, using "last" here
-       // without conversion will likely fail if an interface contains
-       // unexported methods from two different packages (due to cross-package
-       // interface embedding).
-
        var n ir.Node
        method2 := selinfo.Obj().(*types2.Func)
 
@@ -341,7 +266,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
                        if wantPtr {
                                recvType2Base = types2.AsPointer(recvType2).Elem()
                        }
-                       if types2.AsNamed(recvType2Base).TParams().Len() > 0 {
+                       if types2.AsNamed(recvType2Base).TypeParams().Len() > 0 {
                                // recvType2 is the original generic type that is
                                // instantiated for this method call.
                                // selinfo.Recv() is the instantiated type
@@ -357,12 +282,10 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
                                n.(*ir.SelectorExpr).Selection.Nname = method
                                typed(method.Type(), n)
 
-                               // selinfo.Targs() are the types used to
-                               // instantiate the type of receiver
-                               targs2 := getTargs(selinfo)
-                               targs := make([]ir.Node, len(targs2))
-                               for i, targ2 := range targs2 {
-                                       targs[i] = ir.TypeNode(g.typ(targ2))
+                               xt := deref(x.Type())
+                               targs := make([]ir.Node, len(xt.RParams()))
+                               for i := range targs {
+                                       targs[i] = ir.TypeNode(xt.RParams()[i])
                                }
 
                                // Create function instantiation with the type
@@ -385,16 +308,6 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
        return n
 }
 
-// getTargs gets the targs associated with the receiver of a selected method
-func getTargs(selinfo *types2.Selection) []types2.Type {
-       r := deref2(selinfo.Recv())
-       n := types2.AsNamed(r)
-       if n == nil {
-               base.Fatalf("Incorrect type for selinfo %v", selinfo)
-       }
-       return n.TArgs()
-}
-
 func (g *irgen) exprList(expr syntax.Expr) []ir.Node {
        return g.exprs(unpackListExpr(expr))
 }
@@ -425,7 +338,7 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node {
                return typed(g.typ(typ), n)
        }
 
-       _, isStruct := typ.Underlying().(*types2.Struct)
+       _, isStruct := types2.Structure(typ).(*types2.Struct)
 
        exprs := make([]ir.Node, len(lit.ElemList))
        for i, elem := range lit.ElemList {
@@ -437,15 +350,28 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node {
                        } else {
                                key = g.expr(elem.Key)
                        }
-                       exprs[i] = ir.NewKeyExpr(g.pos(elem), key, g.expr(elem.Value))
+                       value := wrapname(g.pos(elem.Value), g.expr(elem.Value))
+                       if value.Op() == ir.OPAREN {
+                               // Make sure any PAREN node added by wrapper has a type
+                               typed(value.(*ir.ParenExpr).X.Type(), value)
+                       }
+                       exprs[i] = ir.NewKeyExpr(g.pos(elem), key, value)
                default:
-                       exprs[i] = g.expr(elem)
+                       exprs[i] = wrapname(g.pos(elem), g.expr(elem))
+                       if exprs[i].Op() == ir.OPAREN {
+                               // Make sure any PAREN node added by wrapper has a type
+                               typed(exprs[i].(*ir.ParenExpr).X.Type(), exprs[i])
+                       }
                }
        }
 
        n := ir.NewCompLitExpr(g.pos(lit), ir.OCOMPLIT, nil, exprs)
        typed(g.typ(typ), n)
-       return transformCompLit(n)
+       var r ir.Node = n
+       if !g.delayTransform() {
+               r = transformCompLit(n)
+       }
+       return r
 }
 
 func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node {
index 702138157c53b8186760e616c9541aa0e90670d6..6077b348a5c73e6bc123ebb2091d20212ada72df 100644 (file)
@@ -37,8 +37,7 @@ func (g *irgen) funcBody(fn *ir.Func, recv *syntax.Field, sig *syntax.FuncType,
        // calculated its size, including parameter offsets. Now that we've
        // created the parameter Names, force a recalculation to ensure
        // their offsets are correct.
-       typ.Align = 0
-       types.CalcSize(typ)
+       types.RecalcSize(typ)
 
        if block != nil {
                typecheck.DeclContext = ir.PAUTO
index b9dbd030af190a0c5d34cce1b9b02f2eda7b1a1b..5524673e6679666f2befb111f8a10ec3af680c85 100644 (file)
@@ -77,10 +77,6 @@ func Nil(pos src.XPos, typ *types.Type) ir.Node {
 
 func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr {
        n := typecheck.NodAddrAt(pos, x)
-       switch x.Op() {
-       case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
-               n.SetOp(ir.OPTRLIT)
-       }
        typed(types.NewPtr(x.Type()), n)
        return n
 }
@@ -89,24 +85,16 @@ func Assert(pos src.XPos, x ir.Node, typ *types.Type) ir.Node {
        return typed(typ, ir.NewTypeAssertExpr(pos, x, nil))
 }
 
-func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) ir.Node {
+func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExpr {
        switch op {
-       case ir.OANDAND, ir.OOROR:
-               return typed(x.Type(), ir.NewLogicalExpr(pos, op, x, y))
        case ir.OADD:
                n := ir.NewBinaryExpr(pos, op, x, y)
-               if x.Type().HasTParam() || y.Type().HasTParam() {
-                       // Delay transformAdd() if either arg has a type param,
-                       // since it needs to know the exact types to decide whether
-                       // to transform OADD to OADDSTR.
-                       n.SetType(typ)
-                       n.SetTypecheck(3)
-                       return n
-               }
                typed(typ, n)
-               return transformAdd(n)
+               return n
        default:
-               return typed(x.Type(), ir.NewBinaryExpr(pos, op, x, y))
+               n := ir.NewBinaryExpr(pos, op, x, y)
+               typed(x.Type(), n)
+               return n
        }
 }
 
@@ -138,10 +126,18 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
                //    until arg type known
                // OAPPEND: transformAppend requires that the arg is a slice
                // ODELETE: transformDelete requires that the arg is a map
+               // OALIGNOF, OSIZEOF: can be eval'ed to a constant until types known.
                switch fun.BuiltinOp {
-               case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE:
+               case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
                        hasTParam := false
                        for _, arg := range args {
+                               if fun.BuiltinOp == ir.OOFFSETOF {
+                                       // It's the type of left operand of the
+                                       // selection that matters, not the type of
+                                       // the field itself (which is irrelevant for
+                                       // offsetof).
+                                       arg = arg.(*ir.SelectorExpr).X
+                               }
                                if arg.Type().HasTParam() {
                                        hasTParam = true
                                        break
@@ -181,17 +177,6 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
                // A function instantiation (even if fully concrete) shouldn't be
                // transformed yet, because we need to add the dictionary during the
                // transformation.
-               //
-               // However, if we have a function type (even though it is
-               // parameterized), then we can add in any needed CONVIFACE nodes via
-               // typecheckaste(). We need to call transformArgs() to deal first
-               // with the f(g(()) case where g returns multiple return values. We
-               // can't do anything if fun is a type param (which is probably
-               // described by a structural constraint)
-               if fun.Type().Kind() == types.TFUNC {
-                       transformArgs(n)
-                       typecheckaste(ir.OCALL, fun, n.IsDDD, fun.Type().Params(), n.Args, true)
-               }
                return typed(typ, n)
        }
 
@@ -202,24 +187,9 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
        return n
 }
 
-func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) ir.Node {
+func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
        n := ir.NewBinaryExpr(pos, op, x, y)
-       if x.Type().HasTParam() || y.Type().HasTParam() {
-               xIsInt := x.Type().IsInterface()
-               yIsInt := y.Type().IsInterface()
-               if !(xIsInt && !yIsInt || !xIsInt && yIsInt) {
-                       // If either arg is a type param, then we can still do the
-                       // transformCompare() if we know that one arg is an interface
-                       // and the other is not. Otherwise, we delay
-                       // transformCompare(), since it needs to know the exact types
-                       // to decide on any needed conversions.
-                       n.SetType(typ)
-                       n.SetTypecheck(3)
-                       return n
-               }
-       }
        typed(typ, n)
-       transformCompare(n)
        return n
 }
 
@@ -289,34 +259,19 @@ func method(typ *types.Type, index int) *types.Field {
        return types.ReceiverBaseType(typ).Methods().Index(index)
 }
 
-func Index(pos src.XPos, typ *types.Type, x, index ir.Node) ir.Node {
+func Index(pos src.XPos, typ *types.Type, x, index ir.Node) *ir.IndexExpr {
        n := ir.NewIndexExpr(pos, x, index)
-       if x.Type().HasTParam() {
-               // transformIndex needs to know exact type
-               n.SetType(typ)
-               n.SetTypecheck(3)
-               return n
-       }
        typed(typ, n)
-       // transformIndex will modify n.Type() for OINDEXMAP.
-       transformIndex(n)
        return n
 }
 
-func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) ir.Node {
+func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) *ir.SliceExpr {
        op := ir.OSLICE
        if max != nil {
                op = ir.OSLICE3
        }
        n := ir.NewSliceExpr(pos, op, x, low, high, max)
-       if x.Type().HasTParam() {
-               // transformSlice needs to know if x.Type() is a string or an array or a slice.
-               n.SetType(typ)
-               n.SetTypecheck(3)
-               return n
-       }
        typed(typ, n)
-       transformSlice(n)
        return n
 }
 
index 48f0e4802849b01ea98a69f473b5d057b4b4d8fb..58dffbad1e4d5c0c11850383ea5e391d9d6ea59d 100644 (file)
@@ -43,12 +43,12 @@ var haveLegacyImports = false
 // for an imported package by overloading writeNewExportFunc, then
 // that payload will be mapped into memory and passed to
 // newReadImportFunc.
-var newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
+var newReadImportFunc = func(data string, pkg1 *types.Pkg, env *types2.Context, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
        panic("unexpected new export data payload")
 }
 
 type gcimports struct {
-       check    *types2.Checker
+       ctxt     *types2.Context
        packages map[string]*types2.Package
 }
 
@@ -61,7 +61,7 @@ func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*ty
                panic("mode must be 0")
        }
 
-       _, pkg, err := readImportFile(path, typecheck.Target, m.check, m.packages)
+       _, pkg, err := readImportFile(path, typecheck.Target, m.ctxt, m.packages)
        return pkg, err
 }
 
@@ -127,6 +127,8 @@ func openPackage(path string) (*os.File, error) {
                        suffix = "_race"
                } else if base.Flag.MSan {
                        suffix = "_msan"
+               } else if base.Flag.ASan {
+                       suffix = "_asan"
                }
 
                if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.a", buildcfg.GOROOT, buildcfg.GOOS, buildcfg.GOARCH, suffix, path)); err == nil {
@@ -198,7 +200,7 @@ func importfile(decl *syntax.ImportDecl) *types.Pkg {
                return nil
        }
 
-       if pkg != ir.Pkgs.Unsafe && pkg.Height >= myheight {
+       if pkg != types.UnsafePkg && pkg.Height >= myheight {
                myheight = pkg.Height + 1
        }
        return pkg
@@ -224,14 +226,14 @@ func parseImportPath(pathLit *syntax.BasicLit) (string, error) {
 // readImportFile reads the import file for the given package path and
 // returns its types.Pkg representation. If packages is non-nil, the
 // types2.Package representation is also returned.
-func readImportFile(path string, target *ir.Package, check *types2.Checker, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) {
+func readImportFile(path string, target *ir.Package, env *types2.Context, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) {
        path, err = resolveImportPath(path)
        if err != nil {
                return
        }
 
        if path == "unsafe" {
-               pkg1, pkg2 = ir.Pkgs.Unsafe, types2.Unsafe
+               pkg1, pkg2 = types.UnsafePkg, types2.Unsafe
 
                // TODO(mdempsky): Investigate if this actually matters. Why would
                // the linker or runtime care whether a package imported unsafe?
@@ -279,7 +281,7 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack
                        return
                }
 
-               pkg2, err = newReadImportFunc(data, pkg1, check, packages)
+               pkg2, err = newReadImportFunc(data, pkg1, env, packages)
        } else {
                // We only have old data. Oh well, fall back to the legacy importers.
                haveLegacyImports = true
index 7bc8a6bcc32e54894ad157e256d0b3ed768838fb..e20939de6639026536b5d5a4fdb85938d689a6c9 100644 (file)
@@ -34,14 +34,16 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
        }
 
        // typechecking
+       ctxt := types2.NewContext()
        importer := gcimports{
-               packages: make(map[string]*types2.Package),
+               ctxt:     ctxt,
+               packages: map[string]*types2.Package{"unsafe": types2.Unsafe},
        }
        conf := types2.Config{
+               Context:               ctxt,
                GoVersion:             base.Flag.Lang,
                IgnoreLabels:          true, // parser already checked via syntax.CheckBranches mode
                CompilerErrorMessages: true, // use error strings matching existing compiler errors
-               AllowTypeLists:        true, // remove this line once all tests use type set syntax
                Error: func(err error) {
                        terr := err.(types2.Error)
                        base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg)
@@ -56,13 +58,11 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
                Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
                Implicits:  make(map[syntax.Node]types2.Object),
                Scopes:     make(map[syntax.Node]*types2.Scope),
-               Inferred:   make(map[syntax.Expr]types2.Inferred),
+               Instances:  make(map[*syntax.Name]types2.Instance),
                // expand as needed
        }
 
-       pkg := types2.NewPackage(base.Ctxt.Pkgpath, "")
-       importer.check = types2.NewChecker(&conf, pkg, info)
-       err := importer.check.Files(files)
+       pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info)
 
        base.ExitIfErrors()
        if err != nil {
@@ -96,39 +96,42 @@ func check2(noders []*noder) {
        }
 }
 
-// gfInfo is information gathered on a generic function.
-type gfInfo struct {
-       tparams      []*types.Type
+// dictInfo is the dictionary format for an instantiation of a generic function with
+// particular shapes. shapeParams, derivedTypes, subDictCalls, and itabConvs describe
+// the actual dictionary entries in order, and the remaining fields are other info
+// needed in doing dictionary processing during compilation.
+type dictInfo struct {
+       // Types substituted for the type parameters, which are shape types.
+       shapeParams []*types.Type
+       // All types derived from those typeparams used in the instantiation.
        derivedTypes []*types.Type
-       // Nodes in generic function that requires a subdictionary. Includes
+       // Nodes in the instantiation that requires a subdictionary. Includes
        // method and function calls (OCALL), function values (OFUNCINST), method
        // values/expressions (OXDOT).
        subDictCalls []ir.Node
-       // Nodes in generic functions that are a conversion from a typeparam/derived
+       // Nodes in the instantiation that are a conversion from a typeparam/derived
        // type to a specific interface.
        itabConvs []ir.Node
+
+       // Mapping from each shape type that substitutes a type param, to its
+       // type bound (which is also substituted with shapes if it is parameterized)
+       shapeToBound map[*types.Type]*types.Type
+
        // For type switches on nonempty interfaces, a map from OTYPE entries of
-       // HasTParam type, to the interface type we're switching from.
-       // TODO: what if the type we're switching from is a shape type?
+       // HasShape type, to the interface type we're switching from.
        type2switchType map[ir.Node]*types.Type
+
+       startSubDict  int // Start of dict entries for subdictionaries
+       startItabConv int // Start of dict entries for itab conversions
+       dictLen       int // Total number of entries in dictionary
 }
 
-// instInfo is information gathered on an gcshape (or fully concrete)
-// instantiation of a function.
+// instInfo is information gathered on an shape instantiation of a function.
 type instInfo struct {
        fun       *ir.Func // The instantiated function (with body)
        dictParam *ir.Name // The node inside fun that refers to the dictionary param
 
-       gf     *ir.Name // The associated generic function
-       gfInfo *gfInfo
-
-       startSubDict  int // Start of dict entries for subdictionaries
-       startItabConv int // Start of dict entries for itab conversions
-       dictLen       int // Total number of entries in dictionary
-
-       // Map from nodes in instantiated fun (OCALL, OCALLMETHOD, OFUNCINST, and
-       // OMETHEXPR) to the associated dictionary entry for a sub-dictionary
-       dictEntryMap map[ir.Node]int
+       dictInfo *dictInfo
 }
 
 type irgen struct {
@@ -141,35 +144,64 @@ type irgen struct {
        typs   map[types2.Type]*types.Type
        marker dwarfgen.ScopeMarker
 
-       // Fully-instantiated generic types whose methods should be instantiated
-       instTypeList []*types.Type
+       // laterFuncs records tasks that need to run after all declarations
+       // are processed.
+       laterFuncs []func()
+       // haveEmbed indicates whether the current node belongs to file that
+       // imports "embed" package.
+       haveEmbed bool
 
-       dnum int // for generating unique dictionary variables
+       // exprStmtOK indicates whether it's safe to generate expressions or
+       // statements yet.
+       exprStmtOK bool
+
+       // types which we need to finish, by doing g.fillinMethods.
+       typesToFinalize []*typeDelayInfo
 
-       // Map from generic function to information about its type params, derived
-       // types, and subdictionaries.
-       gfInfoMap map[*types.Sym]*gfInfo
+       // True when we are compiling a top-level generic function or method. Use to
+       // avoid adding closures of generic functions/methods to the target.Decls
+       // list.
+       topFuncIsGeneric bool
 
-       // Map from a name of function that been instantiated to information about
-       // its instantiated function, associated generic function/method, and the
-       // mapping from IR nodes to dictionary entries.
+       // The context during type/function/method declarations that is used to
+       // uniquely name type parameters. We need unique names for type params so we
+       // can be sure they match up correctly between types2-to-types1 translation
+       // and types1 importing.
+       curDecl string
+}
+
+// genInst has the information for creating needed instantiations and modifying
+// functions to use instantiations.
+type genInst struct {
+       dnum int // for generating unique dictionary variables
+
+       // Map from the names of all instantiations to information about the
+       // instantiations.
        instInfoMap map[*types.Sym]*instInfo
 
-       // dictionary syms which we need to finish, by writing out any itabconv
+       // Dictionary syms which we need to finish, by writing out any itabconv
        // entries.
        dictSymsToFinalize []*delayInfo
 
-       // True when we are compiling a top-level generic function or method. Use to
-       // avoid adding closures of generic functions/methods to the target.Decls
-       // list.
-       topFuncIsGeneric bool
+       // New instantiations created during this round of buildInstantiations().
+       newInsts []ir.Node
+}
+
+func (g *irgen) later(fn func()) {
+       g.laterFuncs = append(g.laterFuncs, fn)
 }
 
 type delayInfo struct {
-       gf    *ir.Name
-       targs []*types.Type
-       sym   *types.Sym
-       off   int
+       gf     *ir.Name
+       targs  []*types.Type
+       sym    *types.Sym
+       off    int
+       isMeth bool
+}
+
+type typeDelayInfo struct {
+       typ  *types2.Named
+       ntyp *types.Type
 }
 
 func (g *irgen) generate(noders []*noder) {
@@ -184,7 +216,7 @@ func (g *irgen) generate(noders []*noder) {
        // At this point, types2 has already handled name resolution and
        // type checking. We just need to map from its object and type
        // representations to those currently used by the rest of the
-       // compiler. This happens mostly in 3 passes.
+       // compiler. This happens in a few passes.
 
        // 1. Process all import declarations. We use the compiler's own
        // importer for this, rather than types2's gcimporter-derived one,
@@ -232,8 +264,20 @@ Outer:
        types.ResumeCheckSize()
 
        // 3. Process all remaining declarations.
-       for _, declList := range declLists {
-               g.target.Decls = append(g.target.Decls, g.decls(declList)...)
+       for i, declList := range declLists {
+               old := g.haveEmbed
+               g.haveEmbed = noders[i].importedEmbed
+               g.decls((*ir.Nodes)(&g.target.Decls), declList)
+               g.haveEmbed = old
+       }
+       g.exprStmtOK = true
+
+       // 4. Run any "later" tasks. Avoid using 'range' so that tasks can
+       // recursively queue further tasks. (Not currently utilized though.)
+       for len(g.laterFuncs) > 0 {
+               fn := g.laterFuncs[0]
+               g.laterFuncs = g.laterFuncs[1:]
+               fn()
        }
 
        if base.Flag.W > 1 {
@@ -243,12 +287,6 @@ Outer:
                }
        }
 
-       // Check for unusual case where noder2 encounters a type error that types2
-       // doesn't check for (e.g. notinheap incompatibility).
-       base.ExitIfErrors()
-
-       typecheck.DeclareUniverse()
-
        for _, p := range noders {
                // Process linkname and cgo pragmas.
                p.processPragmas()
@@ -261,8 +299,25 @@ Outer:
                })
        }
 
-       // Create any needed stencils of generic functions
-       g.stencil()
+       if base.Flag.Complete {
+               for _, n := range g.target.Decls {
+                       if fn, ok := n.(*ir.Func); ok {
+                               if fn.Body == nil && fn.Nname.Sym().Linkname == "" {
+                                       base.ErrorfAt(fn.Pos(), "missing function body")
+                               }
+                       }
+               }
+       }
+
+       // Check for unusual case where noder2 encounters a type error that types2
+       // doesn't check for (e.g. notinheap incompatibility).
+       base.ExitIfErrors()
+
+       typecheck.DeclareUniverse()
+
+       // Create any needed instantiations of generic functions and transform
+       // existing and new functions to use those instantiations.
+       BuildInstantiations(true)
 
        // Remove all generic functions from g.target.Decl, since they have been
        // used for stenciling, but don't compile. Generic functions will already
@@ -275,9 +330,17 @@ Outer:
                }
        }
        g.target.Decls = g.target.Decls[:j]
+
+       base.Assertf(len(g.laterFuncs) == 0, "still have %d later funcs", len(g.laterFuncs))
 }
 
 func (g *irgen) unhandled(what string, p poser) {
        base.FatalfAt(g.pos(p), "unhandled %s: %T", what, p)
        panic("unreachable")
 }
+
+// delayTransform returns true if we should delay all transforms, because we are
+// creating the nodes for a generic function/method.
+func (g *irgen) delayTransform() bool {
+       return g.topFuncIsGeneric
+}
index 6a2aacd3fea71fa5d46d361834cefc60993829f7..b36db67a507a87f8cd6bd0a56791b4f34399cedc 100644 (file)
@@ -35,7 +35,7 @@ func LoadPackage(filenames []string) {
        supportsGenerics := base.Flag.G != 0 || buildcfg.Experiment.Unified
 
        mode := syntax.CheckBranches
-       if supportsGenerics && types.AllowsGoVersion(types.LocalPkg, 1, 18) {
+       if supportsGenerics {
                mode |= syntax.AllowGenerics
        }
 
@@ -154,7 +154,6 @@ func LoadPackage(filenames []string) {
        // Phase 3: Type check function bodies.
        // Don't use range--typecheck can add closures to Target.Decls.
        base.Timer.Start("fe", "typecheck", "func")
-       var fcount int64
        for i := 0; i < len(typecheck.Target.Decls); i++ {
                if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
                        if base.Flag.W > 1 {
@@ -166,7 +165,6 @@ func LoadPackage(filenames []string) {
                                s := fmt.Sprintf("\nafter typecheck %v", fn)
                                ir.Dump(s, fn)
                        }
-                       fcount++
                }
        }
 
@@ -191,13 +189,23 @@ func (p *noder) errorAt(pos syntax.Pos, format string, args ...interface{}) {
        base.ErrorfAt(p.makeXPos(pos), format, args...)
 }
 
-// TODO(gri) Can we eliminate fileh in favor of absFilename?
-func fileh(name string) string {
-       return objabi.AbsFile("", name, base.Flag.TrimPath)
-}
-
-func absFilename(name string) string {
-       return objabi.AbsFile(base.Ctxt.Pathname, name, base.Flag.TrimPath)
+// trimFilename returns the "trimmed" filename of b, which is the
+// absolute filename after applying -trimpath processing. This
+// filename form is suitable for use in object files and export data.
+//
+// If b's filename has already been trimmed (i.e., because it was read
+// in from an imported package's export data), then the filename is
+// returned unchanged.
+func trimFilename(b *syntax.PosBase) string {
+       filename := b.Filename()
+       if !b.Trimmed() {
+               dir := ""
+               if b.IsFileBase() {
+                       dir = base.Ctxt.Pathname
+               }
+               filename = objabi.AbsFile(dir, filename, base.Flag.TrimPath)
+       }
+       return filename
 }
 
 // noder transforms package syntax's AST into a Node tree.
@@ -315,8 +323,7 @@ func (p *noder) processPragmas() {
                }
                n := ir.AsNode(typecheck.Lookup(l.local).Def)
                if n == nil || n.Op() != ir.ONAME {
-                       // TODO(mdempsky): Change to p.errorAt before Go 1.17 release.
-                       // base.WarnfAt(p.makeXPos(l.pos), "//go:linkname must refer to declared function or variable (will be an error in Go 1.17)")
+                       p.errorAt(l.pos, "//go:linkname must refer to declared function or variable")
                        continue
                }
                if n.Sym().Linkname != "" {
@@ -374,7 +381,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
                return
        }
 
-       if ipkg == ir.Pkgs.Unsafe {
+       if ipkg == types.UnsafePkg {
                p.importedUnsafe = true
        }
        if ipkg.Path == "embed" {
@@ -1230,7 +1237,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node {
        init := p.stmt(stmt.Init)
        n := ir.NewIfStmt(p.pos(stmt), p.expr(stmt.Cond), p.blockStmt(stmt.Then), nil)
        if init != nil {
-               *n.PtrInit() = []ir.Node{init}
+               n.SetInit([]ir.Node{init})
        }
        if stmt.Else != nil {
                e := p.stmt(stmt.Else)
@@ -1277,7 +1284,7 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) ir.Node {
        init := p.stmt(stmt.Init)
        n := ir.NewSwitchStmt(p.pos(stmt), p.expr(stmt.Tag), nil)
        if init != nil {
-               *n.PtrInit() = []ir.Node{init}
+               n.SetInit([]ir.Node{init})
        }
 
        var tswitch *ir.TypeSwitchGuard
@@ -1529,7 +1536,7 @@ func (p *noder) mkname(name *syntax.Name) ir.Node {
        return mkname(p.name(name))
 }
 
-func (p *noder) wrapname(n syntax.Node, x ir.Node) ir.Node {
+func wrapname(pos src.XPos, x ir.Node) ir.Node {
        // These nodes do not carry line numbers.
        // Introduce a wrapper node to give them the correct line.
        switch x.Op() {
@@ -1539,13 +1546,17 @@ func (p *noder) wrapname(n syntax.Node, x ir.Node) ir.Node {
                }
                fallthrough
        case ir.ONAME, ir.ONONAME, ir.OPACK:
-               p := ir.NewParenExpr(p.pos(n), x)
+               p := ir.NewParenExpr(pos, x)
                p.SetImplicit(true)
                return p
        }
        return x
 }
 
+func (p *noder) wrapname(n syntax.Node, x ir.Node) ir.Node {
+       return wrapname(p.pos(n), x)
+}
+
 func (p *noder) setlineno(n syntax.Node) {
        if n != nil {
                base.Pos = p.pos(n)
@@ -1723,7 +1734,7 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
 // (primarily misuse of linker flags), other files are not.
 // See golang.org/issue/23672.
 func isCgoGeneratedFile(pos syntax.Pos) bool {
-       return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_")
+       return strings.HasPrefix(filepath.Base(trimFilename(pos.Base())), "_cgo_")
 }
 
 // safeArg reports whether arg is a "safe" command-line argument,
index 40c0b9cf4222072d4b92e22bceb9a51b555ad932..37a995b5199cf70f127fd03feb92b9e27ef2973c 100644 (file)
@@ -22,9 +22,10 @@ func (g *irgen) def(name *syntax.Name) (*ir.Name, types2.Object) {
        return g.obj(obj), obj
 }
 
-// use returns the Name node associated with the use of name. The returned node
-// will have the correct type and be marked as typechecked.
-func (g *irgen) use(name *syntax.Name) *ir.Name {
+// use returns the Name or InstExpr node associated with the use of name,
+// possibly instantiated by type arguments. The returned node will have
+// the correct type and be marked as typechecked.
+func (g *irgen) use(name *syntax.Name) ir.Node {
        obj2, ok := g.info.Uses[name]
        if !ok {
                base.FatalfAt(g.pos(name), "unknown name %v", name)
@@ -36,6 +37,20 @@ func (g *irgen) use(name *syntax.Name) *ir.Name {
                obj.SetTypecheck(1)
                obj.SetType(obj.Defn.Type())
        }
+
+       if obj.Class == ir.PFUNC {
+               if inst, ok := g.info.Instances[name]; ok {
+                       // This is the case where inferring types required the
+                       // types of the function arguments.
+                       targs := make([]ir.Node, inst.TypeArgs.Len())
+                       for i := range targs {
+                               targs[i] = ir.TypeNode(g.typ(inst.TypeArgs.At(i)))
+                       }
+                       typ := g.substType(obj.Type(), obj.Type().TParams(), targs)
+                       return typed(typ, ir.NewInstExpr(g.pos(name), ir.OFUNCINST, obj, targs))
+               }
+       }
+
        return obj
 }
 
index a6d3e2d7ef4d9ac0aa241eede47c23b2c6595e85..f22628f845f7225c3862d00ada9066eaf7c0054e 100644 (file)
@@ -45,8 +45,10 @@ func (m *posMap) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
        b1, ok := m.bases[b0]
        if !ok {
                fn := b0.Filename()
+               absfn := trimFilename(b0)
+
                if b0.IsFileBase() {
-                       b1 = src.NewFileBase(fn, absFilename(fn))
+                       b1 = src.NewFileBase(fn, absfn)
                } else {
                        // line directive base
                        p0 := b0.Pos()
@@ -55,7 +57,7 @@ func (m *posMap) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
                                panic("infinite recursion in makeSrcPosBase")
                        }
                        p1 := src.MakePos(m.makeSrcPosBase(p0b), p0.Line(), p0.Col())
-                       b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
+                       b1 = src.NewLinePragmaBase(p1, fn, absfn, b0.Line(), b0.Col())
                }
                if m.bases == nil {
                        m.bases = make(map[*syntax.PosBase]*src.PosBase)
index 5481812b18d05c2f096797de8c91ad5499c876c9..0bc9135999e0f050935e0c1558516d5a2ed19190 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bytes"
        "fmt"
        "go/constant"
+       "internal/buildcfg"
        "strings"
 
        "cmd/compile/internal/base"
@@ -78,8 +79,6 @@ type reader struct {
 
        p *pkgReader
 
-       ext *reader
-
        dict *readerDict
 
        // TODO(mdempsky): The state below is all specific to reading
@@ -149,7 +148,7 @@ type readerDict struct {
        funcsObj []ir.Node
 }
 
-func (r *reader) setType(n ir.Node, typ *types.Type) {
+func setType(n ir.Node, typ *types.Type) {
        n.SetType(typ)
        n.SetTypecheck(1)
 
@@ -159,7 +158,7 @@ func (r *reader) setType(n ir.Node, typ *types.Type) {
        }
 }
 
-func (r *reader) setValue(name *ir.Name, val constant.Value) {
+func setValue(name *ir.Name, val constant.Value) {
        name.SetVal(val)
        name.Defn = nil
 }
@@ -194,16 +193,32 @@ func (pr *pkgReader) posBaseIdx(idx int) *src.PosBase {
        r := pr.newReader(relocPosBase, idx, syncPosBase)
        var b *src.PosBase
 
-       fn := r.string()
-       absfn := r.string()
+       absFilename := r.string()
+       filename := absFilename
+
+       // For build artifact stability, the export data format only
+       // contains the "absolute" filename as returned by objabi.AbsFile.
+       // However, some tests (e.g., test/run.go's asmcheck tests) expect
+       // to see the full, original filename printed out. Re-expanding
+       // "$GOROOT" to buildcfg.GOROOT is a close-enough approximation to
+       // satisfy this.
+       //
+       // TODO(mdempsky): De-duplicate this logic with similar logic in
+       // cmd/link/internal/ld's expandGoroot. However, this will probably
+       // require being more consistent about when we use native vs UNIX
+       // file paths.
+       const dollarGOROOT = "$GOROOT"
+       if strings.HasPrefix(filename, dollarGOROOT) {
+               filename = buildcfg.GOROOT + filename[len(dollarGOROOT):]
+       }
 
        if r.bool() {
-               b = src.NewFileBase(fn, absfn)
+               b = src.NewFileBase(filename, absFilename)
        } else {
                pos := r.pos0()
                line := r.uint()
                col := r.uint()
-               b = src.NewLinePragmaBase(pos, fn, absfn, line, col)
+               b = src.NewLinePragmaBase(pos, filename, absFilename, line, col)
        }
 
        pr.posBases[idx] = b
@@ -296,7 +311,13 @@ func (r *reader) doPkg() *types.Pkg {
 // @@@ Types
 
 func (r *reader) typ() *types.Type {
-       return r.p.typIdx(r.typInfo(), r.dict)
+       return r.typWrapped(true)
+}
+
+// typWrapped is like typ, but allows suppressing generation of
+// unnecessary wrappers as a compile-time optimization.
+func (r *reader) typWrapped(wrapped bool) *types.Type {
+       return r.p.typIdx(r.typInfo(), r.dict, wrapped)
 }
 
 func (r *reader) typInfo() typeInfo {
@@ -307,7 +328,7 @@ func (r *reader) typInfo() typeInfo {
        return typeInfo{idx: r.reloc(relocType), derived: false}
 }
 
-func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) *types.Type {
+func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict, wrapped bool) *types.Type {
        idx := info.idx
        var where **types.Type
        if info.derived {
@@ -371,7 +392,13 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) *types.Type {
                return prev
        }
 
-       *where = typ
+       if wrapped {
+               // Only cache if we're adding wrappers, so that other callers that
+               // find a cached type know it was wrapped.
+               *where = typ
+
+               r.needWrapper(typ)
+       }
 
        if !typ.IsUntyped() {
                types.CheckSize(typ)
@@ -429,7 +456,7 @@ func (r *reader) interfaceType() *types.Type {
                pos := r.pos()
                pkg, sym := r.selector()
                tpkg = pkg
-               mtyp := r.signature(pkg, typecheck.FakeRecv())
+               mtyp := r.signature(pkg, types.FakeRecv())
                methods[i] = types.NewField(pos, sym, mtyp)
        }
        for i := range embeddeds {
@@ -439,7 +466,7 @@ func (r *reader) interfaceType() *types.Type {
        if len(fields) == 0 {
                return types.Types[types.TINTER] // empty interface
        }
-       return r.needWrapper(types.NewInterface(tpkg, fields))
+       return types.NewInterface(tpkg, fields, false)
 }
 
 func (r *reader) structType() *types.Type {
@@ -460,7 +487,7 @@ func (r *reader) structType() *types.Type {
                }
                fields[i] = f
        }
-       return r.needWrapper(types.NewStruct(tpkg, fields))
+       return types.NewStruct(tpkg, fields)
 }
 
 func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type {
@@ -508,7 +535,7 @@ func (r *reader) obj() ir.Node {
                        fn := r.dict.funcs[idx]
                        targs := make([]*types.Type, len(fn.explicits))
                        for i, targ := range fn.explicits {
-                               targs[i] = r.p.typIdx(targ, r.dict)
+                               targs[i] = r.p.typIdx(targ, r.dict, true)
                        }
 
                        obj = r.p.objIdx(fn.idx, nil, targs)
@@ -541,7 +568,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
        if tag == objStub {
                assert(!sym.IsBlank())
                switch sym.Pkg {
-               case types.BuiltinPkg, ir.Pkgs.Unsafe:
+               case types.BuiltinPkg, types.UnsafePkg:
                        return sym.Def.(ir.Node)
                }
                if pri, ok := objReader[sym]; ok {
@@ -557,10 +584,10 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
        dict := pr.objDictIdx(sym, idx, implicits, explicits)
 
        r := pr.newReader(relocObj, idx, syncObject1)
-       r.ext = pr.newReader(relocObjExt, idx, syncObject1)
+       rext := pr.newReader(relocObjExt, idx, syncObject1)
 
        r.dict = dict
-       r.ext.dict = dict
+       rext.dict = dict
 
        sym = r.mangle(sym)
        if !sym.IsBlank() && sym.Def != nil {
@@ -591,15 +618,16 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
 
        case objAlias:
                name := do(ir.OTYPE, false)
-               r.setType(name, r.typ())
+               setType(name, r.typ())
                name.SetAlias(true)
                return name
 
        case objConst:
                name := do(ir.OLITERAL, false)
-               typ, val := r.value()
-               r.setType(name, typ)
-               r.setValue(name, val)
+               typ := r.typ()
+               val := FixValue(typ, r.value())
+               setType(name, typ)
+               setValue(name, val)
                return name
 
        case objFunc:
@@ -607,46 +635,44 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
                        sym = renameinit()
                }
                name := do(ir.ONAME, true)
-               r.setType(name, r.signature(sym.Pkg, nil))
+               setType(name, r.signature(sym.Pkg, nil))
 
                name.Func = ir.NewFunc(r.pos())
                name.Func.Nname = name
 
-               r.ext.funcExt(name)
+               rext.funcExt(name)
                return name
 
        case objType:
                name := do(ir.OTYPE, true)
                typ := types.NewNamed(name)
-               r.setType(name, typ)
+               setType(name, typ)
 
                // Important: We need to do this before SetUnderlying.
-               r.ext.typeExt(name)
+               rext.typeExt(name)
 
                // We need to defer CheckSize until we've called SetUnderlying to
                // handle recursive types.
                types.DeferCheckSize()
-               typ.SetUnderlying(r.typ())
+               typ.SetUnderlying(r.typWrapped(false))
                types.ResumeCheckSize()
 
                methods := make([]*types.Field, r.len())
                for i := range methods {
-                       methods[i] = r.method()
+                       methods[i] = r.method(rext)
                }
                if len(methods) != 0 {
                        typ.Methods().Set(methods)
                }
 
-               if !typ.IsPtr() {
-                       r.needWrapper(typ)
-               }
+               r.needWrapper(typ)
 
                return name
 
        case objVar:
                name := do(ir.ONAME, false)
-               r.setType(name, r.typ())
-               r.ext.varExt(name)
+               setType(name, r.typ())
+               rext.varExt(name)
                return name
        }
 }
@@ -728,13 +754,7 @@ func (r *reader) typeParamNames() {
        }
 }
 
-func (r *reader) value() (*types.Type, constant.Value) {
-       r.sync(syncValue)
-       typ := r.typ()
-       return typ, FixValue(typ, r.rawValue())
-}
-
-func (r *reader) method() *types.Field {
+func (r *reader) method(rext *reader) *types.Field {
        r.sync(syncMethod)
        pos := r.pos()
        pkg, sym := r.selector()
@@ -745,12 +765,12 @@ func (r *reader) method() *types.Field {
        fnsym := sym
        fnsym = ir.MethodSym(recv.Type, fnsym)
        name := ir.NewNameAt(pos, fnsym)
-       r.setType(name, typ)
+       setType(name, typ)
 
        name.Func = ir.NewFunc(r.pos())
        name.Func.Nname = name
 
-       r.ext.funcExt(name)
+       rext.funcExt(name)
 
        meth := types.NewField(name.Func.Pos(), sym, typ)
        meth.Nname = name
@@ -907,11 +927,22 @@ var bodyReader = map[*ir.Func]pkgReaderIndex{}
 // constructed.
 var todoBodies []*ir.Func
 
+// todoBodiesDone signals that we constructed all function in todoBodies.
+// This is necessary to prevent reader.addBody adds thing to todoBodies
+// when nested inlining happens.
+var todoBodiesDone = false
+
 func (r *reader) addBody(fn *ir.Func) {
        pri := pkgReaderIndex{r.p, r.reloc(relocBody), r.dict}
        bodyReader[fn] = pri
 
-       if r.curfn == nil {
+       if fn.Nname.Defn == nil {
+               // Don't read in function body for imported functions.
+               // See comment in funcExt.
+               return
+       }
+
+       if r.curfn == nil && !todoBodiesDone {
                todoBodies = append(todoBodies, fn)
                return
        }
@@ -987,7 +1018,7 @@ func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) {
        }
 
        name := ir.NewNameAt(r.updatePos(param.Pos), sym)
-       r.setType(name, param.Type)
+       setType(name, param.Type)
        r.addLocal(name, ctxt)
 
        if r.inlCall == nil {
@@ -1267,7 +1298,7 @@ func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node {
 
                name := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.BlankNode.Sym())
                name.SetAlias(true)
-               r.setType(name, types.Types[types.TINT])
+               setType(name, types.Types[types.TINT])
 
                n := ir.NewDecl(src.NoXPos, ir.ODCLTYPE, name)
                n.SetTypecheck(1)
@@ -1288,7 +1319,7 @@ func (r *reader) assignList() ([]*ir.Name, []ir.Node) {
                        name := ir.NewNameAt(pos, sym)
                        lhs[i] = name
                        names = append(names, name)
-                       r.setType(name, typ)
+                       setType(name, typ)
                        r.addLocal(name, ir.PAUTO)
                        continue
                }
@@ -1429,7 +1460,7 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
                        typ := r.typ()
 
                        name := ir.NewNameAt(pos, tswitch.Tag.Sym())
-                       r.setType(name, typ)
+                       setType(name, typ)
                        r.addLocal(name, ir.PAUTO)
                        clause.Var = name
                        name.Defn = tswitch
@@ -1523,7 +1554,8 @@ func (r *reader) expr() (res ir.Node) {
 
        case exprConst:
                pos := r.pos()
-               typ, val := r.value()
+               typ := r.typ()
+               val := FixValue(typ, r.value())
                op := r.op()
                orig := r.string()
                return typecheck.Expr(OrigConst(pos, typ, val, op, orig))
@@ -1538,7 +1570,19 @@ func (r *reader) expr() (res ir.Node) {
                x := r.expr()
                pos := r.pos()
                _, sym := r.selector()
-               return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym))
+               n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr)
+               if n.Op() == ir.OMETHVALUE {
+                       wrapper := methodValueWrapper{
+                               rcvr:   n.X.Type(),
+                               method: n.Selection,
+                       }
+                       if r.importedDef() {
+                               haveMethodValueWrappers = append(haveMethodValueWrappers, wrapper)
+                       } else {
+                               needMethodValueWrappers = append(needMethodValueWrappers, wrapper)
+                       }
+               }
+               return n
 
        case exprIndex:
                x := r.expr()
@@ -1680,12 +1724,12 @@ func (r *reader) funcLit() ir.Node {
        clo := fn.OClosure
        ir.NameClosure(clo, r.curfn)
 
-       r.setType(fn.Nname, xtype2)
+       setType(fn.Nname, xtype2)
        if quirksMode() {
                fn.Nname.Ntype = ir.TypeNodeAt(typPos, xtype2)
        }
        typecheck.Func(fn)
-       r.setType(clo, fn.Type())
+       setType(clo, fn.Type())
 
        fn.ClosureVars = make([]*ir.Name, 0, r.len())
        for len(fn.ClosureVars) < cap(fn.ClosureVars) {
@@ -1889,7 +1933,7 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
        tmpfn.Closgen = callerfn.Closgen
        defer func() { callerfn.Closgen = tmpfn.Closgen }()
 
-       r.setType(tmpfn.Nname, fn.Type())
+       setType(tmpfn.Nname, fn.Type())
        r.curfn = tmpfn
 
        r.inlCaller = callerfn
@@ -2077,7 +2121,7 @@ func expandInline(fn *ir.Func, pri pkgReaderIndex) {
 
        {
                r := pri.asReader(relocBody, syncFuncBody)
-               r.setType(tmpfn.Nname, fn.Type())
+               setType(tmpfn.Nname, fn.Type())
 
                // Don't change parameter's Sym/Nname fields.
                r.funarghack = true
@@ -2129,11 +2173,36 @@ var needWrapperTypes []*types.Type
 // method wrappers, because we found the type in an imported package.
 var haveWrapperTypes []*types.Type
 
-func (r *reader) needWrapper(typ *types.Type) *types.Type {
+// needMethodValueWrappers lists methods for which we may need to
+// generate method value wrappers.
+var needMethodValueWrappers []methodValueWrapper
+
+// haveMethodValueWrappers lists methods for which we know we already
+// have method value wrappers, because we found it in an imported
+// package.
+var haveMethodValueWrappers []methodValueWrapper
+
+type methodValueWrapper struct {
+       rcvr   *types.Type
+       method *types.Field
+}
+
+func (r *reader) needWrapper(typ *types.Type) {
        if typ.IsPtr() {
-               base.Fatalf("bad pointer type: %v", typ)
+               return
+       }
+
+       // If a type was found in an imported package, then we can assume
+       // that package (or one of its transitive dependencies) already
+       // generated method wrappers for it.
+       if r.importedDef() {
+               haveWrapperTypes = append(haveWrapperTypes, typ)
+       } else {
+               needWrapperTypes = append(needWrapperTypes, typ)
        }
+}
 
+func (r *reader) importedDef() bool {
        // If a type was found in an imported package, then we can assume
        // that package (or one of its transitive dependencies) already
        // generated method wrappers for it.
@@ -2145,51 +2214,56 @@ func (r *reader) needWrapper(typ *types.Type) *types.Type {
        // TODO(mdempsky): Distinguish when a generic function or type was
        // instantiated in an imported package so that we can add types to
        // haveWrapperTypes instead.
-       if r.p != localPkgReader && !r.hasTypeParams() {
-               haveWrapperTypes = append(haveWrapperTypes, typ)
-       } else {
-               needWrapperTypes = append(needWrapperTypes, typ)
-       }
-
-       return typ
+       return r.p != localPkgReader && !r.hasTypeParams()
 }
 
-func (r *reader) wrapTypes(target *ir.Package) {
+func MakeWrappers(target *ir.Package) {
+       // Only unified IR in non-quirks mode emits its own wrappers.
+       if base.Debug.Unified == 0 || quirksMode() {
+               return
+       }
+
        // always generate a wrapper for error.Error (#29304)
-       r.needWrapper(types.ErrorType)
+       needWrapperTypes = append(needWrapperTypes, types.ErrorType)
 
        seen := make(map[string]*types.Type)
-       addType := func(typ *types.Type) bool {
-               if typ.Sym() != nil {
-                       return true
-               }
-
-               key := typ.LinkString()
-               if prev := seen[key]; prev != nil {
-                       if !types.Identical(typ, prev) {
-                               base.Fatalf("collision: types %v and %v have short string %q", typ, prev, key)
-                       }
-                       return false
-               }
-
-               seen[key] = typ
-               return true
-       }
 
        for _, typ := range haveWrapperTypes {
-               addType(typ)
+               wrapType(typ, target, seen, false)
        }
        haveWrapperTypes = nil
 
        for _, typ := range needWrapperTypes {
-               if addType(typ) {
-                       r.wrapType(typ, target)
-               }
+               wrapType(typ, target, seen, true)
        }
        needWrapperTypes = nil
+
+       for _, wrapper := range haveMethodValueWrappers {
+               wrapMethodValue(wrapper.rcvr, wrapper.method, target, false)
+       }
+       haveMethodValueWrappers = nil
+
+       for _, wrapper := range needMethodValueWrappers {
+               wrapMethodValue(wrapper.rcvr, wrapper.method, target, true)
+       }
+       needMethodValueWrappers = nil
 }
 
-func (r *reader) wrapType(typ *types.Type, target *ir.Package) {
+func wrapType(typ *types.Type, target *ir.Package, seen map[string]*types.Type, needed bool) {
+       key := typ.LinkString()
+       if prev := seen[key]; prev != nil {
+               if !types.Identical(typ, prev) {
+                       base.Fatalf("collision: types %v and %v have link string %q", typ, prev, key)
+               }
+               return
+       }
+       seen[key] = typ
+
+       if !needed {
+               // Only called to add to 'seen'.
+               return
+       }
+
        if !typ.IsInterface() {
                typecheck.CalcMethods(typ)
        }
@@ -2198,31 +2272,29 @@ func (r *reader) wrapType(typ *types.Type, target *ir.Package) {
                        base.FatalfAt(meth.Pos, "invalid method: %v", meth)
                }
 
-               r.methodValueWrapper(typ, meth, target)
-
-               r.methodWrapper(0, typ, meth, target)
+               methodWrapper(0, typ, meth, target)
 
                // For non-interface types, we also want *T wrappers.
                if !typ.IsInterface() {
-                       r.methodWrapper(1, typ, meth, target)
+                       methodWrapper(1, typ, meth, target)
 
                        // For not-in-heap types, *T is a scalar, not pointer shaped,
                        // so the interface wrappers use **T.
                        if typ.NotInHeap() {
-                               r.methodWrapper(2, typ, meth, target)
+                               methodWrapper(2, typ, meth, target)
                        }
                }
        }
 }
 
-func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) {
+func methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) {
        wrapper := tbase
        for i := 0; i < derefs; i++ {
                wrapper = types.NewPtr(wrapper)
        }
 
        sym := ir.MethodSym(wrapper, method.Sym)
-       assert(!sym.Siggen())
+       base.Assertf(!sym.Siggen(), "already generated wrapper %v", sym)
        sym.SetSiggen(true)
 
        wrappee := method.Type.Recv().Type
@@ -2235,7 +2307,7 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
        // TODO(mdempsky): Use method.Pos instead?
        pos := base.AutogeneratedPos
 
-       fn := r.newWrapperFunc(pos, sym, wrapper, method)
+       fn := newWrapperFunc(pos, sym, wrapper, method)
 
        var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name)
 
@@ -2255,42 +2327,36 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
 
        addTailCall(pos, fn, recv, method)
 
-       r.finishWrapperFunc(fn, target)
+       finishWrapperFunc(fn, target)
 }
 
-func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, target *ir.Package) {
-       recvType := tbase
-       if !tbase.IsInterface() {
-               recvType = method.Type.Recv().Type
-               if !types.Identical(tbase, types.ReceiverBaseType(recvType)) {
-                       return
-               }
-       }
-
+func wrapMethodValue(recvType *types.Type, method *types.Field, target *ir.Package, needed bool) {
        sym := ir.MethodSymSuffix(recvType, method.Sym, "-fm")
-       assert(!sym.Uniq())
+       if sym.Uniq() {
+               return
+       }
        sym.SetUniq(true)
 
        // TODO(mdempsky): Use method.Pos instead?
        pos := base.AutogeneratedPos
 
-       fn := r.newWrapperFunc(pos, sym, nil, method)
+       fn := newWrapperFunc(pos, sym, nil, method)
        sym.Def = fn.Nname
 
        // Declare and initialize variable holding receiver.
        recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType)
 
-       if !reflectdata.NeedEmit(tbase) {
+       if !needed {
                typecheck.Func(fn)
                return
        }
 
        addTailCall(pos, fn, recv, method)
 
-       r.finishWrapperFunc(fn, target)
+       finishWrapperFunc(fn, target)
 }
 
-func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func {
+func newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func {
        fn := ir.NewFunc(pos)
        fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
 
@@ -2301,14 +2367,14 @@ func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Typ
        fn.Nname = name
 
        sig := newWrapperType(wrapper, method)
-       r.setType(name, sig)
+       setType(name, sig)
 
        // TODO(mdempsky): De-duplicate with similar logic in funcargs.
        defParams := func(class ir.Class, params *types.Type) {
                for _, param := range params.FieldSlice() {
                        name := ir.NewNameAt(param.Pos, param.Sym)
                        name.Class = class
-                       r.setType(name, param.Type)
+                       setType(name, param.Type)
 
                        name.Curfn = fn
                        fn.Dcl = append(fn.Dcl, name)
@@ -2324,13 +2390,17 @@ func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Typ
        return fn
 }
 
-func (r *reader) finishWrapperFunc(fn *ir.Func, target *ir.Package) {
+func finishWrapperFunc(fn *ir.Func, target *ir.Package) {
        typecheck.Func(fn)
 
        ir.WithFunc(fn, func() {
                typecheck.Stmts(fn.Body)
        })
 
+       // We generate wrappers after the global inlining pass,
+       // so we're responsible for applying inlining ourselves here.
+       inline.InlineCalls(fn)
+
        target.Decls = append(target.Decls, fn)
 }
 
index 97ea4fcb76dc8d0a1425bf6711bd2228364d9279..9396c0c87c5e3501fd7ffbc4a025fc7ded331ef1 100644 (file)
@@ -7,8 +7,6 @@
 package noder
 
 import (
-       "go/constant"
-
        "cmd/compile/internal/base"
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/types2"
@@ -18,7 +16,7 @@ import (
 type pkgReader2 struct {
        pkgDecoder
 
-       check   *types2.Checker
+       ctxt    *types2.Context
        imports map[string]*types2.Package
 
        posBases []*syntax.PosBase
@@ -26,11 +24,11 @@ type pkgReader2 struct {
        typs     []types2.Type
 }
 
-func readPackage2(check *types2.Checker, imports map[string]*types2.Package, input pkgDecoder) *types2.Package {
+func readPackage2(ctxt *types2.Context, imports map[string]*types2.Package, input pkgDecoder) *types2.Package {
        pr := pkgReader2{
                pkgDecoder: input,
 
-               check:   check,
+               ctxt:    ctxt,
                imports: imports,
 
                posBases: make([]*syntax.PosBase, input.numElems(relocPosBase)),
@@ -43,7 +41,12 @@ func readPackage2(check *types2.Checker, imports map[string]*types2.Package, inp
        r.bool() // has init
 
        for i, n := 0, r.len(); i < n; i++ {
-               r.obj()
+               // As if r.obj(), but avoiding the Scope.Lookup call,
+               // to avoid eager loading of imports.
+               r.sync(syncObject)
+               assert(!r.bool())
+               r.p.objIdx(r.reloc(relocObj))
+               assert(r.len() == 0)
        }
 
        r.sync(syncEOF)
@@ -109,15 +112,14 @@ func (pr *pkgReader2) posBaseIdx(idx int) *syntax.PosBase {
        var b *syntax.PosBase
 
        filename := r.string()
-       _ = r.string() // absolute file name
 
        if r.bool() {
-               b = syntax.NewFileBase(filename)
+               b = syntax.NewTrimmedFileBase(filename, true)
        } else {
                pos := r.pos()
                line := r.uint()
                col := r.uint()
-               b = syntax.NewLineBase(pos, filename, line, col)
+               b = syntax.NewLineBase(pos, filename, true, line, col)
        }
 
        pr.posBases[idx] = b
@@ -229,7 +231,8 @@ func (r *reader2) doTyp() (res types2.Type) {
                obj, targs := r.obj()
                name := obj.(*types2.TypeName)
                if len(targs) != 0 {
-                       return r.p.check.Instantiate(syntax.Pos{}, name.Type(), targs, nil, false)
+                       t, _ := types2.Instantiate(r.p.ctxt, name.Type(), targs, false)
+                       return t
                }
                return name.Type()
 
@@ -313,7 +316,7 @@ func (r *reader2) signature(recv *types2.Var) *types2.Signature {
        results := r.params()
        variadic := r.bool()
 
-       return types2.NewSignature(recv, params, results, variadic)
+       return types2.NewSignatureType(recv, nil, nil, params, results, variadic)
 }
 
 func (r *reader2) params() *types2.Tuple {
@@ -362,7 +365,7 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
        tag := codeObj(rname.code(syncCodeObj))
 
        if tag == objStub {
-               assert(objPkg == nil)
+               assert(objPkg == nil || objPkg == types2.Unsafe)
                return objPkg, objName
        }
 
@@ -383,20 +386,21 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
 
                case objConst:
                        pos := r.pos()
-                       typ, val := r.value()
+                       typ := r.typ()
+                       val := r.value()
                        return types2.NewConst(pos, objPkg, objName, typ, val)
 
                case objFunc:
                        pos := r.pos()
                        tparams := r.typeParamNames()
                        sig := r.signature(nil)
-                       sig.SetTParams(tparams)
+                       sig.SetTypeParams(tparams)
                        return types2.NewFunc(pos, objPkg, objName, sig)
 
                case objType:
                        pos := r.pos()
 
-                       return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeName, underlying types2.Type, methods []*types2.Func) {
+                       return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeParam, underlying types2.Type, methods []*types2.Func) {
                                tparams = r.typeParamNames()
 
                                // TODO(mdempsky): Rewrite receiver types to underlying is an
@@ -423,11 +427,6 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
        return objPkg, objName
 }
 
-func (r *reader2) value() (types2.Type, constant.Value) {
-       r.sync(syncValue)
-       return r.typ(), r.rawValue()
-}
-
 func (pr *pkgReader2) objDictIdx(idx int) *reader2Dict {
        r := pr.newReader(relocObjDict, idx, syncObject1)
 
@@ -453,7 +452,7 @@ func (pr *pkgReader2) objDictIdx(idx int) *reader2Dict {
        return &dict
 }
 
-func (r *reader2) typeParamNames() []*types2.TypeName {
+func (r *reader2) typeParamNames() []*types2.TypeParam {
        r.sync(syncTypeParamNames)
 
        // Note: This code assumes it only processes objects without
@@ -470,21 +469,20 @@ func (r *reader2) typeParamNames() []*types2.TypeName {
        // create all the TypeNames and TypeParams, then we construct and
        // set the bound type.
 
-       names := make([]*types2.TypeName, len(r.dict.bounds))
        r.dict.tparams = make([]*types2.TypeParam, len(r.dict.bounds))
        for i := range r.dict.bounds {
                pos := r.pos()
                pkg, name := r.localIdent()
 
-               names[i] = types2.NewTypeName(pos, pkg, name, nil)
-               r.dict.tparams[i] = r.p.check.NewTypeParam(names[i], nil)
+               tname := types2.NewTypeName(pos, pkg, name, nil)
+               r.dict.tparams[i] = types2.NewTypeParam(tname, nil)
        }
 
        for i, bound := range r.dict.bounds {
                r.dict.tparams[i].SetConstraint(r.p.typIdx(bound, r.dict))
        }
 
-       return names
+       return r.dict.tparams
 }
 
 func (r *reader2) method() *types2.Func {
@@ -494,7 +492,7 @@ func (r *reader2) method() *types2.Func {
 
        rparams := r.typeParamNames()
        sig := r.signature(r.param())
-       sig.SetRParams(rparams)
+       sig.SetRecvTypeParams(rparams)
 
        _ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
        return types2.NewFunc(pos, pkg, name, sig)
index 6736f128e31d8f77aae31792d0e65907c17a0d18..74281bc479135f0bb1e3e3985c8c9367d98394fb 100644 (file)
@@ -9,6 +9,7 @@ package noder
 
 import (
        "cmd/compile/internal/base"
+       "cmd/compile/internal/inline"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/objw"
        "cmd/compile/internal/reflectdata"
@@ -27,8 +28,8 @@ func assert(p bool) {
        base.Assert(p)
 }
 
-// Temporary - for outputting information on derived types, dictionaries, sub-dictionaries.
-// Turn off when running tests.
+// For outputting debug information on dictionary format and instantiated dictionaries
+// (type arg, derived types, sub-dictionary, and itab entries).
 var infoPrintMode = false
 
 func infoPrint(format string, a ...interface{}) {
@@ -37,207 +38,263 @@ func infoPrint(format string, a ...interface{}) {
        }
 }
 
-// stencil scans functions for instantiated generic function calls and creates the
-// required instantiations for simple generic functions. It also creates
-// instantiated methods for all fully-instantiated generic types that have been
-// encountered already or new ones that are encountered during the stenciling
-// process.
-func (g *irgen) stencil() {
-       g.instInfoMap = make(map[*types.Sym]*instInfo)
-       g.gfInfoMap = make(map[*types.Sym]*gfInfo)
+var geninst genInst
 
+func BuildInstantiations(preinliningMainScan bool) {
+       if geninst.instInfoMap == nil {
+               geninst.instInfoMap = make(map[*types.Sym]*instInfo)
+       }
+       geninst.buildInstantiations(preinliningMainScan)
+}
+
+// buildInstantiations scans functions for generic function calls and methods, and
+// creates the required instantiations. It also creates instantiated methods for all
+// fully-instantiated generic types that have been encountered already or new ones
+// that are encountered during the instantiation process. If preinliningMainScan is
+// true, it scans all declarations in typecheck.Target.Decls first, before scanning
+// any new instantiations created. If preinliningMainScan is false, we do not scan
+// any existing decls - we only scan method instantiations for any new
+// fully-instantiated types that we saw during inlining.
+func (g *genInst) buildInstantiations(preinliningMainScan bool) {
        // Instantiate the methods of instantiated generic types that we have seen so far.
        g.instantiateMethods()
 
-       // Don't use range(g.target.Decls) - we also want to process any new instantiated
-       // functions that are created during this loop, in order to handle generic
-       // functions calling other generic functions.
-       for i := 0; i < len(g.target.Decls); i++ {
-               decl := g.target.Decls[i]
-
-               // Look for function instantiations in bodies of non-generic
-               // functions or in global assignments (ignore global type and
-               // constant declarations).
-               switch decl.Op() {
-               case ir.ODCLFUNC:
-                       if decl.Type().HasTParam() {
-                               // Skip any generic functions
-                               continue
-                       }
-                       // transformCall() below depends on CurFunc being set.
-                       ir.CurFunc = decl.(*ir.Func)
+       if preinliningMainScan {
+               n := len(typecheck.Target.Decls)
+               for i := 0; i < n; i++ {
+                       g.scanForGenCalls(typecheck.Target.Decls[i])
+               }
+       }
 
-               case ir.OAS, ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV, ir.OASOP:
-                       // These are all the various kinds of global assignments,
-                       // whose right-hand-sides might contain a function
-                       // instantiation.
+       // Scan all new instantiations created due to g.instantiateMethods() and the
+       // scan of current decls (if done). This loop purposely runs until no new
+       // instantiations are created.
+       for i := 0; i < len(g.newInsts); i++ {
+               g.scanForGenCalls(g.newInsts[i])
+       }
 
-               default:
-                       // The other possible ops at the top level are ODCLCONST
-                       // and ODCLTYPE, which don't have any function
-                       // instantiations.
-                       continue
-               }
+       g.finalizeSyms()
 
-               // For all non-generic code, search for any function calls using
-               // generic function instantiations. Then create the needed
-               // instantiated function if it hasn't been created yet, and change
-               // to calling that function directly.
-               modified := false
-               closureRequired := false
-               // declInfo will be non-nil exactly if we are scanning an instantiated function
-               declInfo := g.instInfoMap[decl.Sym()]
-
-               ir.Visit(decl, func(n ir.Node) {
-                       if n.Op() == ir.OFUNCINST {
-                               // generic F, not immediately called
-                               closureRequired = true
-                       }
-                       if (n.Op() == ir.OMETHEXPR || n.Op() == ir.OMETHVALUE) && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) {
-                               // T.M or x.M, where T or x is generic, but not immediately
-                               // called. Not necessary if the method selected is
-                               // actually for an embedded interface field.
-                               closureRequired = true
-                       }
-                       if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
-                               // We have found a function call using a generic function
-                               // instantiation.
-                               call := n.(*ir.CallExpr)
-                               inst := call.X.(*ir.InstExpr)
-                               nameNode, isMeth := g.getInstNameNode(inst)
-                               targs := typecheck.TypesOf(inst.Targs)
-                               st := g.getInstantiation(nameNode, targs, isMeth)
-                               dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth)
-                               if infoPrintMode {
-                                       dictkind := "Main dictionary"
-                                       if usingSubdict {
-                                               dictkind = "Sub-dictionary"
-                                       }
-                                       if inst.X.Op() == ir.OMETHVALUE {
-                                               fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
-                                       } else {
-                                               fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call)
-                                       }
+       // All the instantiations and dictionaries have been created. Now go through
+       // each new instantiation and transform the various operations that need to make
+       // use of their dictionary.
+       l := len(g.newInsts)
+       for _, fun := range g.newInsts {
+               info := g.instInfoMap[fun.Sym()]
+               g.dictPass(info)
+               if !preinliningMainScan {
+                       // Prepare for the round of inlining below.
+                       inline.CanInline(fun.(*ir.Func))
+               }
+               if doubleCheck {
+                       ir.Visit(info.fun, func(n ir.Node) {
+                               if n.Op() != ir.OCONVIFACE {
+                                       return
                                }
+                               c := n.(*ir.ConvExpr)
+                               if c.X.Type().HasShape() && !c.X.Type().IsInterface() {
+                                       ir.Dump("BAD FUNCTION", info.fun)
+                                       ir.Dump("BAD CONVERSION", c)
+                                       base.Fatalf("converting shape type to interface")
+                               }
+                       })
+               }
+               if base.Flag.W > 1 {
+                       ir.Dump(fmt.Sprintf("\ndictpass %v", info.fun), info.fun)
+               }
+       }
+       if !preinliningMainScan {
+               // Extra round of inlining for the new instantiations (only if
+               // preinliningMainScan is false, which means we have already done the
+               // main round of inlining)
+               for _, fun := range g.newInsts {
+                       inline.InlineCalls(fun.(*ir.Func))
+               }
+       }
+       assert(l == len(g.newInsts))
+       g.newInsts = nil
+}
 
-                               // Transform the Call now, which changes OCALL to
-                               // OCALLFUNC and does typecheckaste/assignconvfn. Do
-                               // it before installing the instantiation, so we are
-                               // checking against non-shape param types in
-                               // typecheckaste.
-                               transformCall(call)
+// scanForGenCalls scans a single function (or global assignment), looking for
+// references to generic functions/methods. At each such reference, it creates any
+// required instantiation and transforms the reference.
+func (g *genInst) scanForGenCalls(decl ir.Node) {
+       switch decl.Op() {
+       case ir.ODCLFUNC:
+               if decl.Type().HasTParam() {
+                       // Skip any generic functions
+                       return
+               }
+               // transformCall() below depends on CurFunc being set.
+               ir.CurFunc = decl.(*ir.Func)
+
+       case ir.OAS, ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV, ir.OASOP:
+               // These are all the various kinds of global assignments,
+               // whose right-hand-sides might contain a function
+               // instantiation.
+
+       default:
+               // The other possible ops at the top level are ODCLCONST
+               // and ODCLTYPE, which don't have any function
+               // instantiations.
+               return
+       }
 
-                               // Replace the OFUNCINST with a direct reference to the
-                               // new stenciled function
-                               call.X = st.Nname
+       // Search for any function references using generic function/methods. Then
+       // create the needed instantiated function if it hasn't been created yet, and
+       // change to calling that function directly.
+       modified := false
+       closureRequired := false
+       // declInfo will be non-nil exactly if we are scanning an instantiated function
+       declInfo := g.instInfoMap[decl.Sym()]
+
+       ir.Visit(decl, func(n ir.Node) {
+               if n.Op() == ir.OFUNCINST {
+                       // generic F, not immediately called
+                       closureRequired = true
+               }
+               if (n.Op() == ir.OMETHEXPR || n.Op() == ir.OMETHVALUE) && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) {
+                       // T.M or x.M, where T or x is generic, but not immediately
+                       // called. Not necessary if the method selected is
+                       // actually for an embedded interface field.
+                       closureRequired = true
+               }
+               if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
+                       // We have found a function call using a generic function
+                       // instantiation.
+                       call := n.(*ir.CallExpr)
+                       inst := call.X.(*ir.InstExpr)
+                       nameNode, isMeth := g.getInstNameNode(inst)
+                       targs := typecheck.TypesOf(inst.Targs)
+                       st := g.getInstantiation(nameNode, targs, isMeth).fun
+                       dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth)
+                       if infoPrintMode {
+                               dictkind := "Main dictionary"
+                               if usingSubdict {
+                                       dictkind = "Sub-dictionary"
+                               }
                                if inst.X.Op() == ir.OMETHVALUE {
-                                       // When we create an instantiation of a method
-                                       // call, we make it a function. So, move the
-                                       // receiver to be the first arg of the function
-                                       // call.
-                                       call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
+                                       fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
+                               } else {
+                                       fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call)
                                }
-
-                               // Add dictionary to argument list.
-                               call.Args.Prepend(dictValue)
-                               modified = true
                        }
-                       if n.Op() == ir.OCALLMETH && n.(*ir.CallExpr).X.Op() == ir.ODOTMETH && len(deref(n.(*ir.CallExpr).X.Type().Recv().Type).RParams()) > 0 {
-                               // Method call on a generic type, which was instantiated by stenciling.
-                               // Method calls on explicitly instantiated types will have an OFUNCINST
-                               // and are handled above.
-                               call := n.(*ir.CallExpr)
-                               meth := call.X.(*ir.SelectorExpr)
-                               targs := deref(meth.Type().Recv().Type).RParams()
-
-                               t := meth.X.Type()
-                               baseSym := deref(t).OrigSym
-                               baseType := baseSym.Def.(*ir.Name).Type()
-                               var gf *ir.Name
-                               for _, m := range baseType.Methods().Slice() {
-                                       if meth.Sel == m.Sym {
-                                               gf = m.Nname.(*ir.Name)
-                                               break
-                                       }
-                               }
-
-                               // Transform the Call now, which changes OCALL
-                               // to OCALLFUNC and does typecheckaste/assignconvfn.
-                               transformCall(call)
 
-                               st := g.getInstantiation(gf, targs, true)
-                               dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
-                               // We have to be using a subdictionary, since this is
-                               // a generic method call.
-                               assert(usingSubdict)
-
-                               // Transform to a function call, by appending the
-                               // dictionary and the receiver to the args.
-                               call.SetOp(ir.OCALLFUNC)
-                               call.X = st.Nname
-                               call.Args.Prepend(dictValue, meth.X)
-                               modified = true
+                       // Transform the Call now, which changes OCALL to
+                       // OCALLFUNC and does typecheckaste/assignconvfn. Do
+                       // it before installing the instantiation, so we are
+                       // checking against non-shape param types in
+                       // typecheckaste.
+                       transformCall(call)
+
+                       // Replace the OFUNCINST with a direct reference to the
+                       // new stenciled function
+                       call.X = st.Nname
+                       if inst.X.Op() == ir.OMETHVALUE {
+                               // When we create an instantiation of a method
+                               // call, we make it a function. So, move the
+                               // receiver to be the first arg of the function
+                               // call.
+                               call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
                        }
-               })
-
-               // If we found a reference to a generic instantiation that wasn't an
-               // immediate call, then traverse the nodes of decl again (with
-               // EditChildren rather than Visit), where we actually change the
-               // reference to the instantiation to a closure that captures the
-               // dictionary, then does a direct call.
-               // EditChildren is more expensive than Visit, so we only do this
-               // in the infrequent case of an OFUNCINST without a corresponding
-               // call.
-               if closureRequired {
+
+                       // Add dictionary to argument list.
+                       call.Args.Prepend(dictValue)
                        modified = true
-                       var edit func(ir.Node) ir.Node
-                       var outer *ir.Func
-                       if f, ok := decl.(*ir.Func); ok {
-                               outer = f
-                       }
-                       edit = func(x ir.Node) ir.Node {
-                               if x.Op() == ir.OFUNCINST {
-                                       child := x.(*ir.InstExpr).X
-                                       if child.Op() == ir.OMETHEXPR || child.Op() == ir.OMETHVALUE {
-                                               // Call EditChildren on child (x.X),
-                                               // not x, so that we don't do
-                                               // buildClosure() on the
-                                               // METHEXPR/METHVALUE nodes as well.
-                                               ir.EditChildren(child, edit)
-                                               return g.buildClosure(outer, x)
-                                       }
+               }
+               if n.Op() == ir.OCALLMETH && n.(*ir.CallExpr).X.Op() == ir.ODOTMETH && len(deref(n.(*ir.CallExpr).X.Type().Recv().Type).RParams()) > 0 {
+                       // Method call on a generic type, which was instantiated by stenciling.
+                       // Method calls on explicitly instantiated types will have an OFUNCINST
+                       // and are handled above.
+                       call := n.(*ir.CallExpr)
+                       meth := call.X.(*ir.SelectorExpr)
+                       targs := deref(meth.Type().Recv().Type).RParams()
+
+                       t := meth.X.Type()
+                       baseSym := deref(t).OrigSym()
+                       baseType := baseSym.Def.(*ir.Name).Type()
+                       var gf *ir.Name
+                       for _, m := range baseType.Methods().Slice() {
+                               if meth.Sel == m.Sym {
+                                       gf = m.Nname.(*ir.Name)
+                                       break
                                }
-                               ir.EditChildren(x, edit)
-                               switch {
-                               case x.Op() == ir.OFUNCINST:
-                                       return g.buildClosure(outer, x)
-                               case (x.Op() == ir.OMETHEXPR || x.Op() == ir.OMETHVALUE) &&
-                                       len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
-                                       !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type):
+                       }
+
+                       // Transform the Call now, which changes OCALL
+                       // to OCALLFUNC and does typecheckaste/assignconvfn.
+                       transformCall(call)
+
+                       st := g.getInstantiation(gf, targs, true).fun
+                       dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
+                       // We have to be using a subdictionary, since this is
+                       // a generic method call.
+                       assert(usingSubdict)
+
+                       // Transform to a function call, by appending the
+                       // dictionary and the receiver to the args.
+                       call.SetOp(ir.OCALLFUNC)
+                       call.X = st.Nname
+                       call.Args.Prepend(dictValue, meth.X)
+                       modified = true
+               }
+       })
+
+       // If we found a reference to a generic instantiation that wasn't an
+       // immediate call, then traverse the nodes of decl again (with
+       // EditChildren rather than Visit), where we actually change the
+       // reference to the instantiation to a closure that captures the
+       // dictionary, then does a direct call.
+       // EditChildren is more expensive than Visit, so we only do this
+       // in the infrequent case of an OFUNCINST without a corresponding
+       // call.
+       if closureRequired {
+               modified = true
+               var edit func(ir.Node) ir.Node
+               var outer *ir.Func
+               if f, ok := decl.(*ir.Func); ok {
+                       outer = f
+               }
+               edit = func(x ir.Node) ir.Node {
+                       if x.Op() == ir.OFUNCINST {
+                               child := x.(*ir.InstExpr).X
+                               if child.Op() == ir.OMETHEXPR || child.Op() == ir.OMETHVALUE {
+                                       // Call EditChildren on child (x.X),
+                                       // not x, so that we don't do
+                                       // buildClosure() on the
+                                       // METHEXPR/METHVALUE nodes as well.
+                                       ir.EditChildren(child, edit)
                                        return g.buildClosure(outer, x)
                                }
-                               return x
                        }
-                       edit(decl)
-               }
-               if base.Flag.W > 1 && modified {
-                       ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl)
+                       ir.EditChildren(x, edit)
+                       switch {
+                       case x.Op() == ir.OFUNCINST:
+                               return g.buildClosure(outer, x)
+                       case (x.Op() == ir.OMETHEXPR || x.Op() == ir.OMETHVALUE) &&
+                               len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
+                               !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type):
+                               return g.buildClosure(outer, x)
+                       }
+                       return x
                }
-               ir.CurFunc = nil
-               // We may have seen new fully-instantiated generic types while
-               // instantiating any needed functions/methods in the above
-               // function. If so, instantiate all the methods of those types
-               // (which will then lead to more function/methods to scan in the loop).
-               g.instantiateMethods()
+               edit(decl)
        }
-
-       g.finalizeSyms()
+       if base.Flag.W > 1 && modified {
+               ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl)
+       }
+       ir.CurFunc = nil
+       // We may have seen new fully-instantiated generic types while
+       // instantiating any needed functions/methods in the above
+       // function. If so, instantiate all the methods of those types
+       // (which will then lead to more function/methods to scan in the loop).
+       g.instantiateMethods()
 }
 
-// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR
+// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR/OMETHVALUE
 // of generic type. outer is the containing function (or nil if closure is
 // in a global assignment instead of a function).
-func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
+func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
        pos := x.Pos()
        var target *ir.Func   // target instantiated function/method
        var dictValue ir.Node // dictionary to use
@@ -274,7 +331,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
                // For method values, the target expects a dictionary and the receiver
                // as its first two arguments.
                // dictValue is the value to use for the dictionary argument.
-               target = g.getInstantiation(gf, targs, rcvrValue != nil)
+               target = g.getInstantiation(gf, targs, rcvrValue != nil).fun
                dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, rcvrValue != nil)
                if infoPrintMode {
                        dictkind := "Main dictionary"
@@ -304,7 +361,12 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
                // of se.Selection, since that will be the type that actually has
                // the method.
                recv := deref(se.Selection.Type.Recv().Type)
-               baseType := recv.OrigSym.Def.Type()
+               if len(recv.RParams()) == 0 {
+                       // The embedded type that actually has the method is not
+                       // actually generic, so no need to build a closure.
+                       return x
+               }
+               baseType := recv.OrigSym().Def.Type()
                var gf *ir.Name
                for _, m := range baseType.Methods().Slice() {
                        if se.Sel == m.Sym {
@@ -316,7 +378,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
                        // Remember if value method, so we can detect (*T).M case.
                        valueMethod = true
                }
-               target = g.getInstantiation(gf, targs, true)
+               target = g.getInstantiation(gf, targs, true).fun
                dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true)
                if infoPrintMode {
                        dictkind := "Main dictionary"
@@ -372,10 +434,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
        var dictVar *ir.Name
        var dictAssign *ir.AssignStmt
        if outer != nil {
-               // Note: for now this is a compile-time constant, so we don't really need a closure
-               // to capture it (a wrapper function would work just as well). But eventually it
-               // will be a read of a subdictionary from the parent dictionary.
-               dictVar = ir.NewNameAt(pos, typecheck.LookupNum(".dict", g.dnum))
+               dictVar = ir.NewNameAt(pos, typecheck.LookupNum(typecheck.LocalDictName, g.dnum))
                g.dnum++
                dictVar.Class = ir.PAUTO
                typed(types.Types[types.TUINTPTR], dictVar)
@@ -391,13 +450,19 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
        if rcvrValue != nil {
                rcvrVar = ir.NewNameAt(pos, typecheck.LookupNum(".rcvr", g.dnum))
                g.dnum++
-               rcvrVar.Class = ir.PAUTO
                typed(rcvrValue.Type(), rcvrVar)
-               rcvrVar.Curfn = outer
                rcvrAssign = ir.NewAssignStmt(pos, rcvrVar, rcvrValue)
                rcvrAssign.SetTypecheck(1)
                rcvrVar.Defn = rcvrAssign
-               outer.Dcl = append(outer.Dcl, rcvrVar)
+               if outer == nil {
+                       rcvrVar.Class = ir.PEXTERN
+                       typecheck.Target.Decls = append(typecheck.Target.Decls, rcvrAssign)
+                       typecheck.Target.Externs = append(typecheck.Target.Externs, rcvrVar)
+               } else {
+                       rcvrVar.Class = ir.PAUTO
+                       rcvrVar.Curfn = outer
+                       outer.Dcl = append(outer.Dcl, rcvrVar)
+               }
        }
 
        // Build body of closure. This involves just calling the wrapped function directly
@@ -464,7 +529,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
        ir.FinishCaptureNames(pos, outer, fn)
 
        // Make a closure referencing our new internal function.
-       c := ir.UseClosure(fn.OClosure, g.target)
+       c := ir.UseClosure(fn.OClosure, typecheck.Target)
        var init []ir.Node
        if outer != nil {
                init = append(init, dictAssign)
@@ -476,40 +541,48 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
 }
 
 // instantiateMethods instantiates all the methods (and associated dictionaries) of
-// all fully-instantiated generic types that have been added to g.instTypeList.
-func (g *irgen) instantiateMethods() {
-       for i := 0; i < len(g.instTypeList); i++ {
-               typ := g.instTypeList[i]
-               assert(!typ.HasShape())
-               // Mark runtime type as needed, since this ensures that the
-               // compiler puts out the needed DWARF symbols, when this
-               // instantiated type has a different package from the local
-               // package.
-               typecheck.NeedRuntimeType(typ)
-               // Lookup the method on the base generic type, since methods may
-               // not be set on imported instantiated types.
-               baseSym := typ.OrigSym
-               baseType := baseSym.Def.(*ir.Name).Type()
-               for j, _ := range typ.Methods().Slice() {
-                       baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
-                       // Eagerly generate the instantiations and dictionaries that implement these methods.
-                       // We don't use the instantiations here, just generate them (and any
-                       // further instantiations those generate, etc.).
-                       // Note that we don't set the Func for any methods on instantiated
-                       // types. Their signatures don't match so that would be confusing.
-                       // Direct method calls go directly to the instantiations, implemented above.
-                       // Indirect method calls use wrappers generated in reflectcall. Those wrappers
-                       // will use these instantiations if they are needed (for interface tables or reflection).
-                       _ = g.getInstantiation(baseNname, typ.RParams(), true)
-                       _ = g.getDictionarySym(baseNname, typ.RParams(), true)
+// all fully-instantiated generic types that have been added to typecheck.instTypeList.
+// It continues until no more types are added to typecheck.instTypeList.
+func (g *genInst) instantiateMethods() {
+       for {
+               instTypeList := typecheck.GetInstTypeList()
+               if len(instTypeList) == 0 {
+                       break
+               }
+               typecheck.ClearInstTypeList()
+               for _, typ := range instTypeList {
+                       assert(!typ.HasShape())
+                       // Mark runtime type as needed, since this ensures that the
+                       // compiler puts out the needed DWARF symbols, when this
+                       // instantiated type has a different package from the local
+                       // package.
+                       typecheck.NeedRuntimeType(typ)
+                       // Lookup the method on the base generic type, since methods may
+                       // not be set on imported instantiated types.
+                       baseSym := typ.OrigSym()
+                       baseType := baseSym.Def.(*ir.Name).Type()
+                       for j, _ := range typ.Methods().Slice() {
+                               if baseType.Methods().Slice()[j].Nointerface() {
+                                       typ.Methods().Slice()[j].SetNointerface(true)
+                               }
+                               baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
+                               // Eagerly generate the instantiations and dictionaries that implement these methods.
+                               // We don't use the instantiations here, just generate them (and any
+                               // further instantiations those generate, etc.).
+                               // Note that we don't set the Func for any methods on instantiated
+                               // types. Their signatures don't match so that would be confusing.
+                               // Direct method calls go directly to the instantiations, implemented above.
+                               // Indirect method calls use wrappers generated in reflectcall. Those wrappers
+                               // will use these instantiations if they are needed (for interface tables or reflection).
+                               _ = g.getInstantiation(baseNname, typ.RParams(), true)
+                               _ = g.getDictionarySym(baseNname, typ.RParams(), true)
+                       }
                }
        }
-       g.instTypeList = nil
-
 }
 
 // getInstNameNode returns the name node for the method or function being instantiated, and a bool which is true if a method is being instantiated.
-func (g *irgen) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) {
+func (g *genInst) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) {
        if meth, ok := inst.X.(*ir.SelectorExpr); ok {
                return meth.Selection.Nname.(*ir.Name), true
        } else {
@@ -522,17 +595,22 @@ func (g *irgen) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) {
 // or main/static dictionary, as needed, and also returns a boolean indicating if a
 // sub-dictionary was accessed. nameNode is the particular function or method being
 // called/referenced, and targs are the type arguments.
-func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Name, targs []*types.Type, isMeth bool) (ir.Node, bool) {
+func (g *genInst) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Name, targs []*types.Type, isMeth bool) (ir.Node, bool) {
        var dict ir.Node
        usingSubdict := false
        if declInfo != nil {
-               // Get the dictionary arg via sub-dictionary reference
-               entry, ok := declInfo.dictEntryMap[n]
+               entry := -1
+               for i, de := range declInfo.dictInfo.subDictCalls {
+                       if n == de {
+                               entry = declInfo.dictInfo.startSubDict + i
+                               break
+                       }
+               }
                // If the entry is not found, it may be that this node did not have
                // any type args that depend on type params, so we need a main
                // dictionary, not a sub-dictionary.
-               if ok {
-                       dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictLen)
+               if entry >= 0 {
+                       dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictInfo.dictLen)
                        usingSubdict = true
                }
        }
@@ -546,7 +624,7 @@ func (g *irgen) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Nam
 // yet. If so, it imports the body.
 func checkFetchBody(nameNode *ir.Name) {
        if nameNode.Func.Body == nil && nameNode.Func.Inl != nil {
-               // If there is no body yet but Func.Inl exists, then we can can
+               // If there is no body yet but Func.Inl exists, then we can
                // import the whole generic body.
                assert(nameNode.Func.Inl.Cost == 1 && nameNode.Sym().Pkg != types.LocalPkg)
                typecheck.ImportBody(nameNode.Func)
@@ -559,66 +637,76 @@ func checkFetchBody(nameNode *ir.Name) {
 // getInstantiation gets the instantiantion and dictionary of the function or method nameNode
 // with the type arguments shapes. If the instantiated function is not already
 // cached, then it calls genericSubst to create the new instantiation.
-func (g *irgen) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *ir.Func {
-       checkFetchBody(nameNode)
+func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *instInfo {
+       if nameNode.Func == nil {
+               // If nameNode.Func is nil, this must be a reference to a method of
+               // an imported instantiated type. We will have already called
+               // g.instantiateMethods() on the fully-instantiated type, so
+               // g.instInfoMap[sym] will be non-nil below.
+               rcvr := nameNode.Type().Recv()
+               if rcvr == nil || !deref(rcvr.Type).IsFullyInstantiated() {
+                       base.FatalfAt(nameNode.Pos(), "Unexpected function instantiation %v with no body", nameNode)
+               }
+       } else {
+               checkFetchBody(nameNode)
+       }
 
        // Convert any non-shape type arguments to their shape, so we can reduce the
        // number of instantiations we have to generate. You can actually have a mix
        // of shape and non-shape arguments, because of inferred or explicitly
        // specified concrete type args.
-       var s1 []*types.Type
+       s1 := make([]*types.Type, len(shapes))
        for i, t := range shapes {
-               if !t.HasShape() {
-                       if s1 == nil {
-                               s1 = make([]*types.Type, len(shapes))
-                               copy(s1[0:i], shapes[0:i])
-                       }
-                       s1[i] = typecheck.Shapify(t)
-               } else if s1 != nil {
-                       s1[i] = shapes[i]
+               if !t.IsShape() {
+                       s1[i] = typecheck.Shapify(t, i)
+               } else {
+                       // Already a shape, but make sure it has the correct index.
+                       s1[i] = typecheck.Shapify(shapes[i].Underlying(), i)
                }
        }
-       if s1 != nil {
-               shapes = s1
-       }
+       shapes = s1
 
-       sym := typecheck.MakeInstName(nameNode.Sym(), shapes, isMeth)
+       sym := typecheck.MakeFuncInstSym(nameNode.Sym(), shapes, false, isMeth)
        info := g.instInfoMap[sym]
        if info == nil {
                // If instantiation doesn't exist yet, create it and add
                // to the list of decls.
-               gfInfo := g.getGfInfo(nameNode)
                info = &instInfo{
-                       gf:            nameNode,
-                       gfInfo:        gfInfo,
-                       startSubDict:  len(shapes) + len(gfInfo.derivedTypes),
-                       startItabConv: len(shapes) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls),
-                       dictLen:       len(shapes) + len(gfInfo.derivedTypes) + len(gfInfo.subDictCalls) + len(gfInfo.itabConvs),
-                       dictEntryMap:  make(map[ir.Node]int),
+                       dictInfo: &dictInfo{},
                }
-               // genericSubst fills in info.dictParam and info.dictEntryMap.
+               info.dictInfo.shapeToBound = make(map[*types.Type]*types.Type)
+
+               // genericSubst fills in info.dictParam and info.tparamToBound.
                st := g.genericSubst(sym, nameNode, shapes, isMeth, info)
                info.fun = st
                g.instInfoMap[sym] = info
-               // This ensures that the linker drops duplicates of this instantiation.
-               // All just works!
-               st.SetDupok(true)
-               g.target.Decls = append(g.target.Decls, st)
+
+               // getInstInfo fills in info.dictInfo.
+               g.getInstInfo(st, shapes, info)
                if base.Flag.W > 1 {
                        ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
                }
+
+               // This ensures that the linker drops duplicates of this instantiation.
+               // All just works!
+               st.SetDupok(true)
+               typecheck.Target.Decls = append(typecheck.Target.Decls, st)
+               g.newInsts = append(g.newInsts, st)
        }
-       return info.fun
+       return info
 }
 
 // Struct containing info needed for doing the substitution as we create the
 // instantiation of a generic function with specified type arguments.
 type subster struct {
-       g        *irgen
+       g        *genInst
        isMethod bool     // If a method is being instantiated
        newf     *ir.Func // Func node for the new stenciled function
        ts       typecheck.Tsubster
        info     *instInfo // Place to put extra info in the instantiation
+
+       // Map from non-nil, non-ONAME node n to slice of all m, where m.Defn = n
+       defnMap map[ir.Node][]**ir.Name
 }
 
 // genericSubst returns a new function with name newsym. The function is an
@@ -626,8 +714,8 @@ type subster struct {
 // args shapes. For a method with a generic receiver, it returns an instantiated
 // function type where the receiver becomes the first parameter. For either a generic
 // method or function, a dictionary parameter is the added as the very first
-// parameter. genericSubst fills in info.dictParam and info.dictEntryMap.
-func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*types.Type, isMethod bool, info *instInfo) *ir.Func {
+// parameter. genericSubst fills in info.dictParam and info.tparamToBound.
+func (g *genInst) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*types.Type, isMethod bool, info *instInfo) *ir.Func {
        var tparams []*types.Type
        if isMethod {
                // Get the type params from the method receiver (after skipping
@@ -667,12 +755,13 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*typ
                        Targs:   shapes,
                        Vars:    make(map[*ir.Name]*ir.Name),
                },
+               defnMap: make(map[ir.Node][]**ir.Name),
        }
 
        newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1)
 
        // Create the needed dictionary param
-       dictionarySym := newsym.Pkg.Lookup(".dict")
+       dictionarySym := newsym.Pkg.Lookup(typecheck.LocalDictName)
        dictionaryType := types.Types[types.TUINTPTR]
        dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym)
        typed(dictionaryType, dictionaryName)
@@ -680,7 +769,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*typ
        dictionaryName.Curfn = newf
        newf.Dcl = append(newf.Dcl, dictionaryName)
        for _, n := range gf.Dcl {
-               if n.Sym().Name == ".dict" {
+               if n.Sym().Name == typecheck.LocalDictName {
                        panic("already has dictionary")
                }
                newf.Dcl = append(newf.Dcl, subst.localvar(n))
@@ -718,32 +807,17 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes []*typ
        // to many->1 shape to concrete mapping.
        // newf.Body.Prepend(subst.checkDictionary(dictionaryName, shapes)...)
 
-       ir.CurFunc = savef
-       // Add any new, fully instantiated types seen during the substitution to
-       // g.instTypeList.
-       g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...)
-
-       if doubleCheck {
-               okConvs := map[ir.Node]bool{}
-               ir.Visit(newf, func(n ir.Node) {
-                       if n.Op() == ir.OIDATA {
-                               // IDATA(OCONVIFACE(x)) is ok, as we don't use the type of x.
-                               // TODO: use some other op besides OCONVIFACE. ONEW might work
-                               // (with appropriate direct vs. indirect interface cases).
-                               okConvs[n.(*ir.UnaryExpr).X] = true
-                       }
-                       if n.Op() == ir.OCONVIFACE && !okConvs[n] {
-                               c := n.(*ir.ConvExpr)
-                               if c.X.Type().HasShape() {
-                                       ir.Dump("BAD FUNCTION", newf)
-                                       ir.Dump("BAD CONVERSION", c)
-                                       base.Fatalf("converting shape type to interface")
-                               }
-                       }
-               })
+       if len(subst.defnMap) > 0 {
+               base.Fatalf("defnMap is not empty")
+       }
+
+       for i, tp := range tparams {
+               info.dictInfo.shapeToBound[shapes[i]] = subst.ts.Typ(tp.Bound())
        }
 
-       return newf
+       ir.CurFunc = savef
+
+       return subst.newf
 }
 
 // localvar creates a new name node for the specified local variable and enters it
@@ -762,6 +836,26 @@ func (subst *subster) localvar(name *ir.Name) *ir.Name {
        m.Func = name.Func
        subst.ts.Vars[name] = m
        m.SetTypecheck(1)
+       m.DictIndex = name.DictIndex
+       if name.Defn != nil {
+               if name.Defn.Op() == ir.ONAME {
+                       // This is a closure variable, so its Defn is the outer
+                       // captured variable, which has already been substituted.
+                       m.Defn = subst.node(name.Defn)
+               } else {
+                       // The other values of Defn are nodes in the body of the
+                       // function, so just remember the mapping so we can set Defn
+                       // properly in node() when we create the new body node. We
+                       // always call localvar() on all the local variables before
+                       // we substitute the body.
+                       slice := subst.defnMap[name.Defn]
+                       subst.defnMap[name.Defn] = append(slice, &m)
+               }
+       }
+       if name.Outer != nil {
+               m.Outer = subst.node(name.Outer).(*ir.Name)
+       }
+
        return m
 }
 
@@ -798,7 +892,7 @@ func (subst *subster) checkDictionary(name *ir.Name, targs []*types.Type) (code
                cond := ir.NewBinaryExpr(pos, ir.ONE, want, got)
                typed(types.Types[types.TBOOL], cond)
                panicArg := ir.NewNilExpr(pos)
-               typed(types.NewInterface(types.LocalPkg, nil), panicArg)
+               typed(types.NewInterface(types.LocalPkg, nil, false), panicArg)
                then := ir.NewUnaryExpr(pos, ir.OPANIC, panicArg)
                then.SetTypecheck(1)
                x := ir.NewIfStmt(pos, cond, []ir.Node{then}, nil)
@@ -833,11 +927,11 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node {
 // refers to a type param or a derived type that uses type params). It uses the
 // specified dictionary dictParam, rather than the one in info.dictParam.
 func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int) ir.Node {
-       if i < 0 || i >= info.startSubDict {
+       if i < 0 || i >= info.dictInfo.startSubDict {
                base.Fatalf(fmt.Sprintf("bad dict index %d", i))
        }
 
-       r := getDictionaryEntry(pos, info.dictParam, i, info.startSubDict)
+       r := getDictionaryEntry(pos, info.dictParam, i, info.dictInfo.startSubDict)
        // change type of retrieved dictionary entry to *byte, which is the
        // standard typing of a *runtime._type in the compiler
        typed(types.Types[types.TUINT8].PtrTo(), r)
@@ -845,8 +939,9 @@ func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int)
 }
 
 // node is like DeepCopy(), but substitutes ONAME nodes based on subst.ts.vars, and
-// also descends into closures. It substitutes type arguments for type parameters
-// in all the new nodes.
+// also descends into closures. It substitutes type arguments for type parameters in
+// all the new nodes and does the transformations that were delayed on the generic
+// function.
 func (subst *subster) node(n ir.Node) ir.Node {
        // Use closure to capture all state needed by the ir.EditChildren argument.
        var edit func(ir.Node) ir.Node
@@ -859,6 +954,12 @@ func (subst *subster) node(n ir.Node) ir.Node {
                        if v := subst.ts.Vars[x.(*ir.Name)]; v != nil {
                                return v
                        }
+                       if ir.IsBlank(x) {
+                               // Special case, because a blank local variable is
+                               // not in the fn.Dcl list.
+                               m := ir.NewNameAt(x.Pos(), ir.BlankNode.Sym())
+                               return typed(subst.ts.Typ(x.Type()), m)
+                       }
                        return x
                case ir.ONONAME:
                        // This handles the identifier in a type switch guard
@@ -869,78 +970,88 @@ func (subst *subster) node(n ir.Node) ir.Node {
                        }
                }
                m := ir.Copy(x)
+
+               slice, ok := subst.defnMap[x]
+               if ok {
+                       // We just copied a non-ONAME node which was the Defn value
+                       // of a local variable. Set the Defn value of the copied
+                       // local variable to this new Defn node.
+                       for _, ptr := range slice {
+                               (*ptr).Defn = m
+                       }
+                       delete(subst.defnMap, x)
+               }
+
                if _, isExpr := m.(ir.Expr); isExpr {
                        t := x.Type()
                        if t == nil {
-                               // t can be nil only if this is a call that has no
-                               // return values, so allow that and otherwise give
-                               // an error.
+                               // Check for known cases where t can be nil (call
+                               // that has no return values, and key expressions)
+                               // and otherwise cause a fatal error.
                                _, isCallExpr := m.(*ir.CallExpr)
                                _, isStructKeyExpr := m.(*ir.StructKeyExpr)
                                _, isKeyExpr := m.(*ir.KeyExpr)
                                if !isCallExpr && !isStructKeyExpr && !isKeyExpr && x.Op() != ir.OPANIC &&
                                        x.Op() != ir.OCLOSE {
-                                       base.Fatalf(fmt.Sprintf("Nil type for %v", x))
+                                       base.FatalfAt(m.Pos(), "Nil type for %v", x)
                                }
                        } else if x.Op() != ir.OCLOSURE {
                                m.SetType(subst.ts.Typ(x.Type()))
                        }
                }
 
-               for i, de := range subst.info.gfInfo.subDictCalls {
-                       if de == x {
-                               // Remember the dictionary entry associated with this
-                               // node in the instantiated function
-                               // TODO: make sure this remains correct with respect to the
-                               // transformations below.
-                               subst.info.dictEntryMap[m] = subst.info.startSubDict + i
-                               break
-                       }
-               }
-
                ir.EditChildren(m, edit)
 
                m.SetTypecheck(1)
-               if typecheck.IsCmp(x.Op()) {
+
+               // Do the transformations that we delayed on the generic function
+               // node, now that we have substituted in the type args.
+               switch x.Op() {
+               case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
                        transformCompare(m.(*ir.BinaryExpr))
-               } else {
-                       switch x.Op() {
-                       case ir.OSLICE, ir.OSLICE3:
-                               transformSlice(m.(*ir.SliceExpr))
-
-                       case ir.OADD:
-                               m = transformAdd(m.(*ir.BinaryExpr))
-
-                       case ir.OINDEX:
-                               transformIndex(m.(*ir.IndexExpr))
-
-                       case ir.OAS2:
-                               as2 := m.(*ir.AssignListStmt)
-                               transformAssign(as2, as2.Lhs, as2.Rhs)
-
-                       case ir.OAS:
-                               as := m.(*ir.AssignStmt)
-                               if as.Y != nil {
-                                       // transformAssign doesn't handle the case
-                                       // of zeroing assignment of a dcl (rhs[0] is nil).
-                                       lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
-                                       transformAssign(as, lhs, rhs)
-                               }
 
-                       case ir.OASOP:
-                               as := m.(*ir.AssignOpStmt)
-                               transformCheckAssign(as, as.X)
+               case ir.OSLICE, ir.OSLICE3:
+                       transformSlice(m.(*ir.SliceExpr))
+
+               case ir.OADD:
+                       m = transformAdd(m.(*ir.BinaryExpr))
 
-                       case ir.ORETURN:
-                               transformReturn(m.(*ir.ReturnStmt))
+               case ir.OINDEX:
+                       transformIndex(m.(*ir.IndexExpr))
 
-                       case ir.OSEND:
-                               transformSend(m.(*ir.SendStmt))
+               case ir.OAS2:
+                       as2 := m.(*ir.AssignListStmt)
+                       transformAssign(as2, as2.Lhs, as2.Rhs)
 
+               case ir.OAS:
+                       as := m.(*ir.AssignStmt)
+                       if as.Y != nil {
+                               // transformAssign doesn't handle the case
+                               // of zeroing assignment of a dcl (rhs[0] is nil).
+                               lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
+                               transformAssign(as, lhs, rhs)
+                               as.X, as.Y = lhs[0], rhs[0]
                        }
-               }
 
-               switch x.Op() {
+               case ir.OASOP:
+                       as := m.(*ir.AssignOpStmt)
+                       transformCheckAssign(as, as.X)
+
+               case ir.ORETURN:
+                       transformReturn(m.(*ir.ReturnStmt))
+
+               case ir.OSEND:
+                       transformSend(m.(*ir.SendStmt))
+
+               case ir.OSELECT:
+                       transformSelect(m.(*ir.SelectStmt))
+
+               case ir.OCOMPLIT:
+                       transformCompLit(m.(*ir.CompLitExpr))
+
+               case ir.OADDR:
+                       transformAddr(m.(*ir.AddrExpr))
+
                case ir.OLITERAL:
                        t := m.Type()
                        if t != x.Type() {
@@ -958,47 +1069,17 @@ func (subst *subster) node(n ir.Node) ir.Node {
                        }
 
                case ir.OXDOT:
-                       // A method value/call via a type param will have been
-                       // left as an OXDOT. When we see this during stenciling,
-                       // finish the transformation, now that we have the
-                       // instantiated receiver type. We need to do this now,
-                       // since the access/selection to the method for the real
-                       // type is very different from the selection for the type
-                       // param. m will be transformed to an OMETHVALUE node. It
-                       // will be transformed to an ODOTMETH or ODOTINTER node if
-                       // we find in the OCALL case below that the method value
-                       // is actually called.
+                       // Finish the transformation of an OXDOT, unless this was a
+                       // bound call (a direct call on a type param). A bound call
+                       // will be transformed during the dictPass. Otherwise, m
+                       // will be transformed to an OMETHVALUE node. It will be
+                       // transformed to an ODOTMETH or ODOTINTER node if we find in
+                       // the OCALL case below that the method value is actually
+                       // called.
                        mse := m.(*ir.SelectorExpr)
-                       if src := mse.X.Type(); src.IsShape() {
-                               // The only dot on a shape type value are methods.
-                               if mse.X.Op() == ir.OTYPE {
-                                       // Method expression T.M
-                                       m = subst.g.buildClosure2(subst, m, x)
-                                       // No need for transformDot - buildClosure2 has already
-                                       // transformed to OCALLINTER/ODOTINTER.
-                               } else {
-                                       // Implement x.M as a conversion-to-bound-interface
-                                       //  1) convert x to the bound interface
-                                       //  2) call M on that interface
-                                       gsrc := x.(*ir.SelectorExpr).X.Type()
-                                       bound := gsrc.Bound()
-                                       dst := bound
-                                       if dst.HasTParam() {
-                                               dst = subst.ts.Typ(dst)
-                                       }
-                                       if src.IsInterface() {
-                                               // If type arg is an interface (unusual case),
-                                               // we do a type assert to the type bound.
-                                               mse.X = assertToBound(subst.info, subst.info.dictParam, m.Pos(), mse.X, bound, dst)
-                                       } else {
-                                               mse.X = convertUsingDictionary(subst.info, subst.info.dictParam, m.Pos(), mse.X, x, dst, gsrc)
-                                       }
-                                       transformDot(mse, false)
-                               }
-                       } else {
+                       if src := mse.X.Type(); !src.IsShape() {
                                transformDot(mse, false)
                        }
-                       m.SetTypecheck(1)
 
                case ir.OCALL:
                        call := m.(*ir.CallExpr)
@@ -1007,7 +1088,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
                                // Transform the conversion, now that we know the
                                // type argument.
                                m = transformConvCall(call)
-                               // CONVIFACE transformation was already done in node2
+                               // CONVIFACE transformation was already done in noder2
                                assert(m.Op() != ir.OCONVIFACE)
 
                        case ir.OMETHVALUE, ir.OMETHEXPR:
@@ -1029,7 +1110,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
                                name := call.X.Name()
                                if name.BuiltinOp != ir.OXXX {
                                        switch name.BuiltinOp {
-                                       case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE:
+                                       case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
                                                // Transform these builtins now that we
                                                // know the type of the args.
                                                m = transformBuiltin(call)
@@ -1043,16 +1124,29 @@ func (subst *subster) node(n ir.Node) ir.Node {
                                        transformCall(call)
                                }
 
-                       case ir.OCLOSURE:
-                               transformCall(call)
-
                        case ir.OFUNCINST:
                                // A call with an OFUNCINST will get transformed
                                // in stencil() once we have created & attached the
                                // instantiation to be called.
+                               // We must transform the arguments of the call now, though,
+                               // so that any needed CONVIFACE nodes are exposed,
+                               // so the dictionary format is correct.
+                               transformEarlyCall(call)
+
+                       case ir.OXDOT:
+                               // This is the case of a bound call on a typeparam,
+                               // which will be handled in the dictPass.
+
+                       case ir.ODOTTYPE, ir.ODOTTYPE2:
+                               // These are DOTTYPEs that could get transformed into
+                               // ODYNAMIC DOTTYPEs by the dict pass.
 
                        default:
-                               base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op()))
+                               // Transform a call for all other values of
+                               // call.X.Op() that don't require any special
+                               // handling.
+                               transformCall(call)
+
                        }
 
                case ir.OCLOSURE:
@@ -1079,19 +1173,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
                        ir.FinishCaptureNames(oldfn.Pos(), saveNewf, newfn)
                        newfn.ClosureVars = append(newfn.ClosureVars, subst.namelist(oldfn.ClosureVars)...)
 
+                       // Copy that closure variable to a local one.
+                       // Note: this allows the dictionary to be captured by child closures.
+                       // See issue 47723.
+                       ldict := ir.NewNameAt(x.Pos(), newfn.Sym().Pkg.Lookup(typecheck.LocalDictName))
+                       typed(types.Types[types.TUINTPTR], ldict)
+                       ldict.Class = ir.PAUTO
+                       ldict.Curfn = newfn
+                       newfn.Dcl = append(newfn.Dcl, ldict)
+                       as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
+                       as.SetTypecheck(1)
+                       newfn.Body.Append(as)
+
                        // Create inst info for the instantiated closure. The dict
                        // param is the closure variable for the dictionary of the
                        // outer function. Since the dictionary is shared, use the
-                       // same entries for startSubDict, dictLen, dictEntryMap.
+                       // same dictInfo.
                        cinfo := &instInfo{
-                               fun:           newfn,
-                               dictParam:     cdict,
-                               gf:            subst.info.gf,
-                               gfInfo:        subst.info.gfInfo,
-                               startSubDict:  subst.info.startSubDict,
-                               startItabConv: subst.info.startItabConv,
-                               dictLen:       subst.info.dictLen,
-                               dictEntryMap:  subst.info.dictEntryMap,
+                               fun:       newfn,
+                               dictParam: ldict,
+                               dictInfo:  subst.info.dictInfo,
                        }
                        subst.g.instInfoMap[newfn.Nname.Sym()] = cinfo
 
@@ -1102,161 +1203,267 @@ func (subst *subster) node(n ir.Node) ir.Node {
                        outerinfo := subst.info
                        subst.info = cinfo
                        // Make sure type of closure function is set before doing body.
-                       newfn.Body = subst.list(oldfn.Body)
+                       newfn.Body.Append(subst.list(oldfn.Body)...)
                        subst.info = outerinfo
                        subst.newf = saveNewf
                        ir.CurFunc = saveNewf
 
-                       m = ir.UseClosure(newfn.OClosure, subst.g.target)
+                       m = ir.UseClosure(newfn.OClosure, typecheck.Target)
+                       subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
                        m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))
 
+               }
+               return m
+       }
+
+       return edit(n)
+}
+
+// dictPass takes a function instantiation and does the transformations on the
+// operations that need to make use of the dictionary param.
+func (g *genInst) dictPass(info *instInfo) {
+       savef := ir.CurFunc
+       ir.CurFunc = info.fun
+
+       var edit func(ir.Node) ir.Node
+       edit = func(m ir.Node) ir.Node {
+               ir.EditChildren(m, edit)
+
+               switch m.Op() {
+               case ir.OCLOSURE:
+                       newf := m.(*ir.ClosureExpr).Func
+                       ir.CurFunc = newf
+                       outerinfo := info
+                       info = g.instInfoMap[newf.Nname.Sym()]
+
+                       body := newf.Body
+                       for i, n := range body {
+                               body[i] = edit(n)
+                       }
+
+                       info = outerinfo
+                       ir.CurFunc = info.fun
+
+               case ir.OXDOT:
+                       mse := m.(*ir.SelectorExpr)
+                       src := mse.X.Type()
+                       assert(src.IsShape())
+
+                       // The only dot on a shape type value are methods.
+                       if mse.X.Op() == ir.OTYPE {
+                               // Method expression T.M
+                               m = g.buildClosure2(info, m)
+                               // No need for transformDot - buildClosure2 has already
+                               // transformed to OCALLINTER/ODOTINTER.
+                       } else {
+                               // Implement x.M as a conversion-to-bound-interface
+                               //  1) convert x to the bound interface
+                               //  2) call M on that interface
+                               dst := info.dictInfo.shapeToBound[m.(*ir.SelectorExpr).X.Type()]
+                               if src.IsInterface() {
+                                       // If type arg is an interface (unusual case),
+                                       // we do a type assert to the type bound.
+                                       mse.X = assertToBound(info, info.dictParam, m.Pos(), mse.X, dst)
+                               } else {
+                                       mse.X = convertUsingDictionary(info, info.dictParam, m.Pos(), mse.X, m, dst)
+                               }
+                               transformDot(mse, false)
+                       }
+               case ir.OCALL:
+                       op := m.(*ir.CallExpr).X.Op()
+                       if op == ir.OMETHVALUE {
+                               // Redo the transformation of OXDOT, now that we
+                               // know the method value is being called.
+                               m.(*ir.CallExpr).X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
+                               transformDot(m.(*ir.CallExpr).X.(*ir.SelectorExpr), true)
+                       }
+                       transformCall(m.(*ir.CallExpr))
+
                case ir.OCONVIFACE:
-                       x := x.(*ir.ConvExpr)
+                       if m.Type().IsEmptyInterface() && m.(*ir.ConvExpr).X.Type().IsEmptyInterface() {
+                               // Was T->interface{}, after stenciling it is now interface{}->interface{}.
+                               // No longer need the conversion. See issue 48276.
+                               m.(*ir.ConvExpr).SetOp(ir.OCONVNOP)
+                               break
+                       }
+                       mce := m.(*ir.ConvExpr)
                        // Note: x's argument is still typed as a type parameter.
                        // m's argument now has an instantiated type.
-                       if x.X.Type().HasTParam() {
-                               m = convertUsingDictionary(subst.info, subst.info.dictParam, m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type())
+                       if mce.X.Type().HasShape() || (mce.X.Type().IsInterface() && m.Type().HasShape()) {
+                               m = convertUsingDictionary(info, info.dictParam, m.Pos(), m.(*ir.ConvExpr).X, m, m.Type())
                        }
                case ir.ODOTTYPE, ir.ODOTTYPE2:
+                       if !m.Type().HasShape() {
+                               break
+                       }
                        dt := m.(*ir.TypeAssertExpr)
                        var rt ir.Node
                        if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() {
-                               ix := findDictType(subst.info, x.Type())
+                               ix := findDictType(info, m.Type())
                                assert(ix >= 0)
-                               rt = getDictionaryType(subst.info, subst.info.dictParam, dt.Pos(), ix)
+                               rt = getDictionaryType(info, info.dictParam, dt.Pos(), ix)
                        } else {
                                // nonempty interface to noninterface. Need an itab.
                                ix := -1
-                               for i, ic := range subst.info.gfInfo.itabConvs {
-                                       if ic == x {
-                                               ix = subst.info.startItabConv + i
+                               for i, ic := range info.dictInfo.itabConvs {
+                                       if ic == m {
+                                               ix = info.dictInfo.startItabConv + i
                                                break
                                        }
                                }
                                assert(ix >= 0)
-                               rt = getDictionaryEntry(dt.Pos(), subst.info.dictParam, ix, subst.info.dictLen)
+                               rt = getDictionaryEntry(dt.Pos(), info.dictParam, ix, info.dictInfo.dictLen)
                        }
                        op := ir.ODYNAMICDOTTYPE
-                       if x.Op() == ir.ODOTTYPE2 {
+                       if m.Op() == ir.ODOTTYPE2 {
                                op = ir.ODYNAMICDOTTYPE2
                        }
                        m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rt)
                        m.SetType(dt.Type())
                        m.SetTypecheck(1)
                case ir.OCASE:
-                       if _, ok := x.(*ir.CommClause); ok {
+                       if _, ok := m.(*ir.CommClause); ok {
                                // This is not a type switch. TODO: Should we use an OSWITCH case here instead of OCASE?
                                break
                        }
-                       x := x.(*ir.CaseClause)
                        m := m.(*ir.CaseClause)
-                       for i, c := range x.List {
-                               if c.Op() == ir.OTYPE && c.Type().HasTParam() {
+                       for i, c := range m.List {
+                               if c.Op() == ir.OTYPE && c.Type().HasShape() {
                                        // Use a *runtime._type for the dynamic type.
-                                       ix := findDictType(subst.info, c.Type())
+                                       ix := findDictType(info, m.List[i].Type())
                                        assert(ix >= 0)
-                                       dt := ir.NewDynamicType(c.Pos(), getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen))
+                                       dt := ir.NewDynamicType(c.Pos(), getDictionaryEntry(c.Pos(), info.dictParam, ix, info.dictInfo.dictLen))
 
                                        // For type switch from nonempty interfaces to non-interfaces, we need an itab as well.
                                        if !m.List[i].Type().IsInterface() {
-                                               if _, ok := subst.info.gfInfo.type2switchType[c]; ok {
+                                               if _, ok := info.dictInfo.type2switchType[m.List[i]]; ok {
                                                        // Type switch from nonempty interface. We need a *runtime.itab
                                                        // for the dynamic type.
                                                        ix := -1
-                                                       for i, ic := range subst.info.gfInfo.itabConvs {
-                                                               if ic == c {
-                                                                       ix = subst.info.startItabConv + i
+                                                       for j, ic := range info.dictInfo.itabConvs {
+                                                               if ic == m.List[i] {
+                                                                       ix = info.dictInfo.startItabConv + j
                                                                        break
                                                                }
                                                        }
                                                        assert(ix >= 0)
-                                                       dt.ITab = getDictionaryEntry(c.Pos(), subst.info.dictParam, ix, subst.info.dictLen)
+                                                       dt.ITab = getDictionaryEntry(c.Pos(), info.dictParam, ix, info.dictInfo.dictLen)
                                                }
                                        }
                                        typed(m.List[i].Type(), dt)
                                        m.List[i] = dt
                                }
                        }
+
                }
                return m
        }
-
-       return edit(n)
+       edit(info.fun)
+       ir.CurFunc = savef
 }
 
 // findDictType looks for type t in the typeparams or derived types in the generic
 // function info.gfInfo. This will indicate the dictionary entry with the
 // correct concrete type for the associated instantiated function.
 func findDictType(info *instInfo, t *types.Type) int {
-       for i, dt := range info.gfInfo.tparams {
+       for i, dt := range info.dictInfo.shapeParams {
                if dt == t {
                        return i
                }
        }
-       for i, dt := range info.gfInfo.derivedTypes {
-               if types.Identical(dt, t) {
-                       return i + len(info.gfInfo.tparams)
+       for i, dt := range info.dictInfo.derivedTypes {
+               if types.IdenticalStrict(dt, t) {
+                       return i + len(info.dictInfo.shapeParams)
                }
        }
        return -1
 }
 
-// convertUsingDictionary converts value v from instantiated type src to an interface
-// type dst, by returning a new set of nodes that make use of a dictionary entry. src
-// is the generic (not shape) type, and gn is the original generic node of the
-// CONVIFACE node or XDOT node (for a bound method call) that is causing the
+// convertUsingDictionary converts instantiated value v (type v.Type()) to an interface
+// type dst, by returning a new set of nodes that make use of a dictionary entry. in is the
+// instantiated node of the CONVIFACE node or XDOT node (for a bound method call) that is causing the
 // conversion.
-func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, gn ir.Node, dst, src *types.Type) ir.Node {
-       assert(src.HasTParam())
+func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type) ir.Node {
+       assert(v.Type().HasShape() || v.Type().IsInterface() && in.Type().HasShape())
        assert(dst.IsInterface())
 
+       if v.Type().IsInterface() {
+               // Converting from an interface. The shape-ness of the source doesn't really matter, as
+               // we'll be using the concrete type from the first interface word.
+               if dst.IsEmptyInterface() {
+                       // Converting I2E. OCONVIFACE does that for us, and doesn't depend
+                       // on what the empty interface was instantiated with. No dictionary entry needed.
+                       v = ir.NewConvExpr(pos, ir.OCONVIFACE, dst, v)
+                       v.SetTypecheck(1)
+                       return v
+               }
+               if !in.Type().HasShape() {
+                       // Regular OCONVIFACE works if the destination isn't parameterized.
+                       v = ir.NewConvExpr(pos, ir.OCONVIFACE, dst, v)
+                       v.SetTypecheck(1)
+                       return v
+               }
+
+               // We get the destination interface type from the dictionary and the concrete
+               // type from the argument's itab. Call runtime.convI2I to get the new itab.
+               tmp := typecheck.Temp(v.Type())
+               as := ir.NewAssignStmt(pos, tmp, v)
+               as.SetTypecheck(1)
+               itab := ir.NewUnaryExpr(pos, ir.OITAB, tmp)
+               typed(types.Types[types.TUINTPTR].PtrTo(), itab)
+               idata := ir.NewUnaryExpr(pos, ir.OIDATA, tmp)
+               typed(types.Types[types.TUNSAFEPTR], idata)
+
+               fn := typecheck.LookupRuntime("convI2I")
+               fn.SetTypecheck(1)
+               types.CalcSize(fn.Type())
+               call := ir.NewCallExpr(pos, ir.OCALLFUNC, fn, nil)
+               typed(types.Types[types.TUINT8].PtrTo(), call)
+               ix := findDictType(info, in.Type())
+               assert(ix >= 0)
+               inter := getDictionaryType(info, dictParam, pos, ix)
+               call.Args = []ir.Node{inter, itab}
+               i := ir.NewBinaryExpr(pos, ir.OEFACE, call, idata)
+               typed(dst, i)
+               i.PtrInit().Append(as)
+               return i
+       }
+
        var rt ir.Node
        if !dst.IsEmptyInterface() {
                // We should have an itab entry in the dictionary. Using this itab
                // will be more efficient than converting to an empty interface first
                // and then type asserting to dst.
                ix := -1
-               for i, ic := range info.gfInfo.itabConvs {
-                       if ic == gn {
-                               ix = info.startItabConv + i
+               for i, ic := range info.dictInfo.itabConvs {
+                       if ic == in {
+                               ix = info.dictInfo.startItabConv + i
                                break
                        }
                }
                assert(ix >= 0)
-               rt = getDictionaryEntry(pos, dictParam, ix, info.dictLen)
+               rt = getDictionaryEntry(pos, dictParam, ix, info.dictInfo.dictLen)
        } else {
-               ix := findDictType(info, src)
+               ix := findDictType(info, v.Type())
                assert(ix >= 0)
                // Load the actual runtime._type of the type parameter from the dictionary.
                rt = getDictionaryType(info, dictParam, pos, ix)
        }
 
        // Figure out what the data field of the interface will be.
-       var data ir.Node
-       if v.Type().IsInterface() {
-               data = ir.NewUnaryExpr(pos, ir.OIDATA, v)
-       } else {
-               data = ir.NewConvExpr(pos, ir.OCONVIDATA, nil, v)
-       }
+       data := ir.NewConvExpr(pos, ir.OCONVIDATA, nil, v)
        typed(types.Types[types.TUNSAFEPTR], data)
 
        // Build an interface from the type and data parts.
        var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data)
        typed(dst, i)
        return i
-
 }
 
 func (subst *subster) namelist(l []*ir.Name) []*ir.Name {
        s := make([]*ir.Name, len(l))
        for i, n := range l {
                s[i] = subst.localvar(n)
-               if n.Defn != nil {
-                       s[i].Defn = subst.node(n.Defn)
-               }
-               if n.Outer != nil {
-                       s[i].Outer = subst.node(n.Outer).(*ir.Name)
-               }
        }
        return s
 }
@@ -1316,22 +1523,17 @@ func deref(t *types.Type) *types.Type {
 // needed methods.
 func markTypeUsed(t *types.Type, lsym *obj.LSym) {
        if t.IsInterface() {
-               // Mark all the methods of the interface as used.
-               // TODO: we should really only mark the interface methods
-               // that are actually called in the application.
-               for i, _ := range t.AllMethods().Slice() {
-                       reflectdata.MarkUsedIfaceMethodIndex(lsym, t, i)
-               }
-       } else {
-               // TODO: This is somewhat overkill, we really only need it
-               // for types that are put into interfaces.
-               reflectdata.MarkTypeUsedInInterface(t, lsym)
+               return
        }
+       // TODO: This is somewhat overkill, we really only need it
+       // for types that are put into interfaces.
+       // Note: this relocation is also used in cmd/link/internal/ld/dwarf.go
+       reflectdata.MarkTypeUsedInInterface(t, lsym)
 }
 
 // getDictionarySym returns the dictionary for the named generic function gf, which
 // is instantiated with the type arguments targs.
-func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) *types.Sym {
+func (g *genInst) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) *types.Sym {
        if len(targs) == 0 {
                base.Fatalf("%s should have type arguments", gf.Sym().Name)
        }
@@ -1344,7 +1546,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
        }
 
        // Get a symbol representing the dictionary.
-       sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth)
+       sym := typecheck.MakeDictSym(gf.Sym(), targs, isMeth)
 
        // Initialize the dictionary, if we haven't yet already.
        lsym := sym.Linksym()
@@ -1353,8 +1555,6 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
                return sym
        }
 
-       info := g.getGfInfo(gf)
-
        infoPrint("=== Creating dictionary %v\n", sym.Name)
        off := 0
        // Emit an entry for each targ (concrete type or gcshape).
@@ -1364,8 +1564,12 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
                off = objw.SymPtr(lsym, off, s, 0)
                markTypeUsed(t, lsym)
        }
+
+       instInfo := g.getInstantiation(gf, targs, isMeth)
+       info := instInfo.dictInfo
+
        subst := typecheck.Tsubster{
-               Tparams: info.tparams,
+               Tparams: info.shapeParams,
                Targs:   targs,
        }
        // Emit an entry for each derived type (after substituting targs)
@@ -1380,18 +1584,33 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
        for _, n := range info.subDictCalls {
                var sym *types.Sym
                switch n.Op() {
-               case ir.OCALL:
+               case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH:
                        call := n.(*ir.CallExpr)
-                       if call.X.Op() == ir.OXDOT {
+                       if call.X.Op() == ir.OXDOT || call.X.Op() == ir.ODOTMETH {
                                var nameNode *ir.Name
                                se := call.X.(*ir.SelectorExpr)
-                               if types.IsInterfaceMethod(se.Selection.Type) {
+                               if se.X.Type().IsShape() {
                                        // This is a method call enabled by a type bound.
+
+                                       // We need this extra check for type expressions, which
+                                       // don't add in the implicit XDOTs.
                                        tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel)
                                        tmpse = typecheck.AddImplicitDots(tmpse)
                                        tparam := tmpse.X.Type()
-                                       assert(tparam.IsTypeParam())
-                                       recvType := targs[tparam.Index()]
+                                       if !tparam.IsShape() {
+                                               // The method expression is not
+                                               // really on a typeparam.
+                                               break
+                                       }
+                                       ix := -1
+                                       for i, shape := range info.shapeParams {
+                                               if shape == tparam {
+                                                       ix = i
+                                                       break
+                                               }
+                                       }
+                                       assert(ix >= 0)
+                                       recvType := targs[ix]
                                        if recvType.IsInterface() || len(recvType.RParams()) == 0 {
                                                // No sub-dictionary entry is
                                                // actually needed, since the
@@ -1404,14 +1623,16 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
                                        // instantiated type, so we need a
                                        // sub-dictionary.
                                        targs := recvType.RParams()
-                                       genRecvType := recvType.OrigSym.Def.Type()
+                                       genRecvType := recvType.OrigSym().Def.Type()
                                        nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
                                        sym = g.getDictionarySym(nameNode, targs, true)
                                } else {
                                        // This is the case of a normal
                                        // method call on a generic type.
-                                       nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name)
-                                       subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams()
+                                       recvType := deref(call.X.(*ir.SelectorExpr).X.Type())
+                                       genRecvType := recvType.OrigSym().Def.Type()
+                                       nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
+                                       subtargs := recvType.RParams()
                                        s2targs := make([]*types.Type, len(subtargs))
                                        for i, t := range subtargs {
                                                s2targs[i] = subst.Typ(t)
@@ -1444,14 +1665,16 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
                        }
                        sym = g.getDictionarySym(nameNode, subtargs, false)
 
-               case ir.OXDOT:
+               case ir.OXDOT, ir.OMETHEXPR, ir.OMETHVALUE:
                        selExpr := n.(*ir.SelectorExpr)
-                       subtargs := deref(selExpr.X.Type()).RParams()
+                       recvType := deref(selExpr.Selection.Type.Recv().Type)
+                       genRecvType := recvType.OrigSym().Def.Type()
+                       subtargs := recvType.RParams()
                        s2targs := make([]*types.Type, len(subtargs))
                        for i, t := range subtargs {
                                s2targs[i] = subst.Typ(t)
                        }
-                       nameNode := selExpr.Selection.Nname.(*ir.Name)
+                       nameNode := typecheck.Lookdot1(selExpr, selExpr.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
                        sym = g.getDictionarySym(nameNode, s2targs, true)
 
                default:
@@ -1468,14 +1691,15 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
                }
        }
 
+       g.instantiateMethods()
        delay := &delayInfo{
-               gf:    gf,
-               targs: targs,
-               sym:   sym,
-               off:   off,
+               gf:     gf,
+               targs:  targs,
+               sym:    sym,
+               off:    off,
+               isMeth: isMeth,
        }
        g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
-       g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
        return sym
 }
 
@@ -1484,15 +1708,16 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
 // dictionaries and method instantiations to be complete, so, to avoid recursive
 // dependencies, we finalize the itab lsyms only after all dictionaries syms and
 // instantiations have been created.
-func (g *irgen) finalizeSyms() {
+func (g *genInst) finalizeSyms() {
        for _, d := range g.dictSymsToFinalize {
                infoPrint("=== Finalizing dictionary %s\n", d.sym.Name)
 
                lsym := d.sym.Linksym()
-               info := g.getGfInfo(d.gf)
+               instInfo := g.getInstantiation(d.gf, d.targs, d.isMeth)
+               info := instInfo.dictInfo
 
                subst := typecheck.Tsubster{
-                       Tparams: info.tparams,
+                       Tparams: info.shapeParams,
                        Targs:   d.targs,
                }
 
@@ -1500,22 +1725,10 @@ func (g *irgen) finalizeSyms() {
                for _, n := range info.itabConvs {
                        var srctype, dsttype *types.Type
                        switch n.Op() {
-                       case ir.OXDOT:
+                       case ir.OXDOT, ir.OMETHVALUE:
                                se := n.(*ir.SelectorExpr)
                                srctype = subst.Typ(se.X.Type())
-                               dsttype = subst.Typ(se.X.Type().Bound())
-                               found := false
-                               for i, m := range dsttype.AllMethods().Slice() {
-                                       if se.Sel == m.Sym {
-                                               // Mark that this method se.Sel is
-                                               // used for the dsttype interface, so
-                                               // it won't get deadcoded.
-                                               reflectdata.MarkUsedIfaceMethodIndex(lsym, dsttype, i)
-                                               found = true
-                                               break
-                                       }
-                               }
-                               assert(found)
+                               dsttype = subst.Typ(info.shapeToBound[se.X.Type()])
                        case ir.ODOTTYPE, ir.ODOTTYPE2:
                                srctype = subst.Typ(n.(*ir.TypeAssertExpr).Type())
                                dsttype = subst.Typ(n.(*ir.TypeAssertExpr).X.Type())
@@ -1528,12 +1741,15 @@ func (g *irgen) finalizeSyms() {
                        default:
                                base.Fatalf("itab entry with unknown op %s", n.Op())
                        }
-                       if srctype.IsInterface() {
+                       if srctype.IsInterface() || dsttype.IsEmptyInterface() {
                                // No itab is wanted if src type is an interface. We
                                // will use a type assert instead.
                                d.off = objw.Uintptr(lsym, d.off, 0)
                                infoPrint(" + Unused itab entry for %v\n", srctype)
                        } else {
+                               // Make sure all new fully-instantiated types have
+                               // their methods created before generating any itabs.
+                               g.instantiateMethods()
                                itabLsym := reflectdata.ITabLsym(srctype, dsttype)
                                d.off = objw.SymPtr(lsym, d.off, itabLsym, 0)
                                infoPrint(" + Itab for (%v,%v)\n", srctype, dsttype)
@@ -1542,21 +1758,24 @@ func (g *irgen) finalizeSyms() {
 
                objw.Global(lsym, int32(d.off), obj.DUPOK|obj.RODATA)
                infoPrint("=== Finalized dictionary %s\n", d.sym.Name)
-
-               g.instTypeList = append(g.instTypeList, subst.InstTypeList...)
        }
        g.dictSymsToFinalize = nil
 }
 
-func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node {
+func (g *genInst) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node {
        sym := g.getDictionarySym(gf, targs, isMeth)
 
-       // Make a node referencing the dictionary symbol.
-       n := typecheck.NewName(sym)
-       n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
-       n.SetTypecheck(1)
-       n.Class = ir.PEXTERN
-       sym.Def = n
+       // Make (or reuse) a node referencing the dictionary symbol.
+       var n *ir.Name
+       if sym.Def != nil {
+               n = sym.Def.(*ir.Name)
+       } else {
+               n = typecheck.NewName(sym)
+               n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
+               n.SetTypecheck(1)
+               n.Class = ir.PEXTERN
+               sym.Def = n
+       }
 
        // Return the address of the dictionary.
        np := typecheck.NodAddr(n)
@@ -1569,80 +1788,71 @@ func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool
        return np
 }
 
-// hasTParamNodes returns true if the type of any node in targs has a typeparam.
-func hasTParamNodes(targs []ir.Node) bool {
+// hasShapeNodes returns true if the type of any node in targs has a shape.
+func hasShapeNodes(targs []ir.Node) bool {
        for _, n := range targs {
-               if n.Type().HasTParam() {
+               if n.Type().HasShape() {
                        return true
                }
        }
        return false
 }
 
-// hasTParamNodes returns true if any type in targs has a typeparam.
-func hasTParamTypes(targs []*types.Type) bool {
+// hasShapeTypes returns true if any type in targs has a shape.
+func hasShapeTypes(targs []*types.Type) bool {
        for _, t := range targs {
-               if t.HasTParam() {
+               if t.HasShape() {
                        return true
                }
        }
        return false
 }
 
-// getGfInfo get information for a generic function - type params, derived generic
-// types, and subdictionaries.
-func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
-       infop := g.gfInfoMap[gn.Sym()]
-       if infop != nil {
-               return infop
-       }
-
-       checkFetchBody(gn)
-       var info gfInfo
-       gf := gn.Func
-       recv := gf.Type().Recv()
-       if recv != nil {
-               info.tparams = deref(recv.Type).RParams()
-       } else {
-               tparams := gn.Type().TParams().FieldSlice()
-               info.tparams = make([]*types.Type, len(tparams))
-               for i, f := range tparams {
-                       info.tparams[i] = f.Type
-               }
-       }
+// getInstInfo get the dictionary format for a function instantiation- type params, derived
+// types, and needed subdictionaries and itabs.
+func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instInfo) {
+       info := instInfo.dictInfo
+       info.shapeParams = shapes
 
-       for _, t := range info.tparams {
-               b := t.Bound()
-               if b.HasTParam() {
+       for _, t := range info.shapeParams {
+               b := info.shapeToBound[t]
+               if b.HasShape() {
                        // If a type bound is parameterized (unusual case), then we
                        // may need its derived type to do a type assert when doing a
                        // bound call for a type arg that is an interface.
-                       addType(&info, nil, b)
+                       addType(info, nil, b)
                }
        }
 
-       for _, n := range gf.Dcl {
-               addType(&info, n, n.Type())
+       for _, n := range st.Dcl {
+               addType(info, n, n.Type())
+               n.DictIndex = uint16(findDictType(instInfo, n.Type()) + 1)
        }
 
        if infoPrintMode {
-               fmt.Printf(">>> GfInfo for %v\n", gn)
-               for _, t := range info.tparams {
+               fmt.Printf(">>> InstInfo for %v\n", st)
+               for _, t := range info.shapeParams {
                        fmt.Printf("  Typeparam %v\n", t)
                }
        }
 
+       // Map to remember when we have seen an instantiated function value or method
+       // expression/value as part of a call, so we can determine when we encounter
+       // an uncalled function value or method expression/value.
+       callMap := make(map[ir.Node]bool)
+
        var visitFunc func(ir.Node)
        visitFunc = func(n ir.Node) {
-               if n.Op() == ir.OFUNCINST && !n.(*ir.InstExpr).Implicit() {
-                       if hasTParamNodes(n.(*ir.InstExpr).Targs) {
+               switch n.Op() {
+               case ir.OFUNCINST:
+                       if !callMap[n] && hasShapeNodes(n.(*ir.InstExpr).Targs) {
                                infoPrint("  Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X)
                                info.subDictCalls = append(info.subDictCalls, n)
                        }
-               } else if n.Op() == ir.OXDOT && !n.(*ir.SelectorExpr).Implicit() &&
-                       n.(*ir.SelectorExpr).Selection != nil &&
-                       len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
-                       if hasTParamTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
+               case ir.OMETHEXPR, ir.OMETHVALUE:
+                       if !callMap[n] && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) &&
+                               len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
+                               hasShapeTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
                                if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
                                        infoPrint("  Closure&subdictionary required at generic meth expr %v\n", n)
                                } else {
@@ -1650,102 +1860,119 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
                                }
                                info.subDictCalls = append(info.subDictCalls, n)
                        }
-               }
-               if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
-                       n.(*ir.CallExpr).X.(*ir.InstExpr).SetImplicit(true)
-                       if hasTParamNodes(n.(*ir.CallExpr).X.(*ir.InstExpr).Targs) {
-                               infoPrint("  Subdictionary at generic function/method call: %v - %v\n", n.(*ir.CallExpr).X.(*ir.InstExpr).X, n)
-                               info.subDictCalls = append(info.subDictCalls, n)
+               case ir.OCALL:
+                       ce := n.(*ir.CallExpr)
+                       if ce.X.Op() == ir.OFUNCINST {
+                               callMap[ce.X] = true
+                               if hasShapeNodes(ce.X.(*ir.InstExpr).Targs) {
+                                       infoPrint("  Subdictionary at generic function/method call: %v - %v\n", ce.X.(*ir.InstExpr).X, n)
+                                       info.subDictCalls = append(info.subDictCalls, n)
+                               }
                        }
-               }
-               if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
-                       n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil &&
-                       len(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
-                       n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
-                       if hasTParamTypes(deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).RParams()) {
-                               infoPrint("  Subdictionary at generic method call: %v\n", n)
+                       if ce.X.Op() == ir.OXDOT &&
+                               isShapeDeref(ce.X.(*ir.SelectorExpr).X.Type()) {
+                               callMap[ce.X] = true
+                               infoPrint("  Optional subdictionary at generic bound call: %v\n", n)
                                info.subDictCalls = append(info.subDictCalls, n)
                        }
-               }
-               if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT &&
-                       n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil &&
-                       deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).IsTypeParam() {
-                       n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true)
-                       infoPrint("  Optional subdictionary at generic bound call: %v\n", n)
-                       info.subDictCalls = append(info.subDictCalls, n)
-               }
-               if n.Op() == ir.OCONVIFACE && n.Type().IsInterface() &&
-                       !n.Type().IsEmptyInterface() &&
-                       n.(*ir.ConvExpr).X.Type().HasTParam() {
-                       infoPrint("  Itab for interface conv: %v\n", n)
-                       info.itabConvs = append(info.itabConvs, n)
-               }
-               if n.Op() == ir.OXDOT && n.(*ir.SelectorExpr).X.Type().IsTypeParam() {
-                       infoPrint("  Itab for bound call: %v\n", n)
-                       info.itabConvs = append(info.itabConvs, n)
-               }
-               if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {
-                       infoPrint("  Itab for dot type: %v\n", n)
-                       info.itabConvs = append(info.itabConvs, n)
-               }
-               if n.Op() == ir.OCLOSURE {
+               case ir.OCALLMETH:
+                       ce := n.(*ir.CallExpr)
+                       if ce.X.Op() == ir.ODOTMETH &&
+                               len(deref(ce.X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
+                               callMap[ce.X] = true
+                               if hasShapeTypes(deref(ce.X.(*ir.SelectorExpr).X.Type()).RParams()) {
+                                       infoPrint("  Subdictionary at generic method call: %v\n", n)
+                                       info.subDictCalls = append(info.subDictCalls, n)
+                               }
+                       }
+               case ir.OCONVIFACE:
+                       if n.Type().IsInterface() && !n.Type().IsEmptyInterface() &&
+                               n.(*ir.ConvExpr).X.Type().HasShape() {
+                               infoPrint("  Itab for interface conv: %v\n", n)
+                               info.itabConvs = append(info.itabConvs, n)
+                       }
+               case ir.OXDOT:
+                       if n.(*ir.SelectorExpr).X.Type().IsShape() {
+                               infoPrint("  Itab for bound call: %v\n", n)
+                               info.itabConvs = append(info.itabConvs, n)
+                       }
+               case ir.ODOTTYPE, ir.ODOTTYPE2:
+                       if !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {
+                               infoPrint("  Itab for dot type: %v\n", n)
+                               info.itabConvs = append(info.itabConvs, n)
+                       }
+               case ir.OCLOSURE:
                        // Visit the closure body and add all relevant entries to the
                        // dictionary of the outer function (closure will just use
                        // the dictionary of the outer function).
-                       for _, n1 := range n.(*ir.ClosureExpr).Func.Body {
+                       cfunc := n.(*ir.ClosureExpr).Func
+                       for _, n1 := range cfunc.Body {
                                ir.Visit(n1, visitFunc)
                        }
-               }
-               if n.Op() == ir.OSWITCH && n.(*ir.SwitchStmt).Tag != nil && n.(*ir.SwitchStmt).Tag.Op() == ir.OTYPESW && !n.(*ir.SwitchStmt).Tag.(*ir.TypeSwitchGuard).X.Type().IsEmptyInterface() {
-                       for _, cc := range n.(*ir.SwitchStmt).Cases {
-                               for _, c := range cc.List {
-                                       if c.Op() == ir.OTYPE && c.Type().HasTParam() {
-                                               // Type switch from a non-empty interface - might need an itab.
-                                               infoPrint("  Itab for type switch: %v\n", c)
-                                               info.itabConvs = append(info.itabConvs, c)
-                                               if info.type2switchType == nil {
-                                                       info.type2switchType = map[ir.Node]*types.Type{}
+                       for _, n := range cfunc.Dcl {
+                               n.DictIndex = uint16(findDictType(instInfo, n.Type()) + 1)
+                       }
+               case ir.OSWITCH:
+                       ss := n.(*ir.SwitchStmt)
+                       if ss.Tag != nil && ss.Tag.Op() == ir.OTYPESW &&
+                               !ss.Tag.(*ir.TypeSwitchGuard).X.Type().IsEmptyInterface() {
+                               for _, cc := range ss.Cases {
+                                       for _, c := range cc.List {
+                                               if c.Op() == ir.OTYPE && c.Type().HasShape() {
+                                                       // Type switch from a non-empty interface - might need an itab.
+                                                       infoPrint("  Itab for type switch: %v\n", c)
+                                                       info.itabConvs = append(info.itabConvs, c)
+                                                       if info.type2switchType == nil {
+                                                               info.type2switchType = map[ir.Node]*types.Type{}
+                                                       }
+                                                       info.type2switchType[c] = ss.Tag.(*ir.TypeSwitchGuard).X.Type()
                                                }
-                                               info.type2switchType[c] = n.(*ir.SwitchStmt).Tag.(*ir.TypeSwitchGuard).X.Type()
                                        }
                                }
                        }
                }
-               addType(&info, n, n.Type())
+               addType(info, n, n.Type())
        }
 
-       for _, stmt := range gf.Body {
+       for _, stmt := range st.Body {
                ir.Visit(stmt, visitFunc)
        }
        if infoPrintMode {
                for _, t := range info.derivedTypes {
                        fmt.Printf("  Derived type %v\n", t)
                }
-               fmt.Printf(">>> Done Gfinfo\n")
+               fmt.Printf(">>> Done Instinfo\n")
        }
-       g.gfInfoMap[gn.Sym()] = &info
-       return &info
+       info.startSubDict = len(info.shapeParams) + len(info.derivedTypes)
+       info.startItabConv = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls)
+       info.dictLen = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs)
+}
+
+// isShapeDeref returns true if t is either a shape or a pointer to a shape. (We
+// can't just use deref(t).IsShape(), since a shape type is a complex type and may
+// have a pointer as part of its shape.)
+func isShapeDeref(t *types.Type) bool {
+       return t.IsShape() || t.IsPtr() && t.Elem().IsShape()
 }
 
 // addType adds t to info.derivedTypes if it is parameterized type (which is not
-// just a simple type param) that is different from any existing type on
+// just a simple shape) that is different from any existing type on
 // info.derivedTypes.
-func addType(info *gfInfo, n ir.Node, t *types.Type) {
-       if t == nil || !t.HasTParam() {
+func addType(info *dictInfo, n ir.Node, t *types.Type) {
+       if t == nil || !t.HasShape() {
                return
        }
-       if t.IsTypeParam() && t.Underlying() == t {
+       if t.IsShape() {
                return
        }
        if t.Kind() == types.TFUNC && n != nil &&
-               (t.Recv() != nil ||
-                       n.Op() == ir.ONAME && n.Name().Class == ir.PFUNC) {
+               (t.Recv() != nil || n.Op() == ir.ONAME && n.Name().Class == ir.PFUNC) {
                // Don't use the type of a named generic function or method,
                // since that is parameterized by other typeparams.
                // (They all come from arguments of a FUNCINST node.)
                return
        }
-       if doubleCheck && !parameterizedBy(t, info.tparams) {
+       if doubleCheck && !parameterizedBy(t, info.shapeParams) {
                base.Fatalf("adding type with invalid parameters %+v", t)
        }
        if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() {
@@ -1754,7 +1981,7 @@ func addType(info *gfInfo, n ir.Node, t *types.Type) {
        }
        // Ignore a derived type we've already added.
        for _, et := range info.derivedTypes {
-               if types.Identical(t, et) {
+               if types.IdenticalStrict(t, et) {
                        return
                }
        }
@@ -1780,8 +2007,7 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty
                }
                return true
        }
-       switch t.Kind() {
-       case types.TTYPEPARAM:
+       if t.IsShape() {
                // Check if t is one of the allowed parameters in scope.
                for _, p := range params {
                        if p == t {
@@ -1791,6 +2017,8 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty
                // Couldn't find t in the list of allowed parameters.
                return false
 
+       }
+       switch t.Kind() {
        case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN:
                return parameterizedBy1(t.Elem(), params, visited)
 
@@ -1818,7 +2046,7 @@ func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Ty
 
        case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
                types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64,
-               types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
+               types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, types.TUNSAFEPTR:
                return true
 
        case types.TUNION:
@@ -1881,17 +2109,17 @@ func startClosure(pos src.XPos, outer *ir.Func, typ *types.Type) (*ir.Func, []*t
 }
 
 // assertToBound returns a new node that converts a node rcvr with interface type to
-// the 'dst' interface type.  bound is the unsubstituted form of dst.
-func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node, bound, dst *types.Type) ir.Node {
-       if bound.HasTParam() {
-               ix := findDictType(info, bound)
+// the 'dst' interface type.
+func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node, dst *types.Type) ir.Node {
+       if dst.HasShape() {
+               ix := findDictType(info, dst)
                assert(ix >= 0)
                rt := getDictionaryType(info, dictVar, pos, ix)
                rcvr = ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, rcvr, rt)
                typed(dst, rcvr)
        } else {
                rcvr = ir.NewTypeAssertExpr(pos, rcvr, nil)
-               typed(bound, rcvr)
+               typed(dst, rcvr)
        }
        return rcvr
 }
@@ -1903,9 +2131,8 @@ func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node,
 //
 // The returned closure is fully substituted and has already had any needed
 // transformations done.
-func (g *irgen) buildClosure2(subst *subster, m, x ir.Node) ir.Node {
-       outer := subst.newf
-       info := subst.info
+func (g *genInst) buildClosure2(info *instInfo, m ir.Node) ir.Node {
+       outer := info.fun
        pos := m.Pos()
        typ := m.Type() // type of the closure
 
@@ -1928,24 +2155,18 @@ func (g *irgen) buildClosure2(subst *subster, m, x ir.Node) ir.Node {
        rcvr := args[0]
        args = args[1:]
        assert(m.(*ir.SelectorExpr).X.Type().IsShape())
-       gsrc := x.(*ir.SelectorExpr).X.Type()
-       bound := gsrc.Bound()
-       dst := bound
-       if dst.HasTParam() {
-               dst = subst.ts.Typ(bound)
-       }
+       dst := info.dictInfo.shapeToBound[m.(*ir.SelectorExpr).X.Type()]
        if m.(*ir.SelectorExpr).X.Type().IsInterface() {
                // If type arg is an interface (unusual case), we do a type assert to
                // the type bound.
-               rcvr = assertToBound(info, dictVar, pos, rcvr, bound, dst)
+               rcvr = assertToBound(info, dictVar, pos, rcvr, dst)
        } else {
-               rcvr = convertUsingDictionary(info, dictVar, pos, rcvr, x, dst, gsrc)
+               rcvr = convertUsingDictionary(info, dictVar, pos, rcvr, m, dst)
        }
-       dot := ir.NewSelectorExpr(pos, ir.ODOTINTER, rcvr, x.(*ir.SelectorExpr).Sel)
+       dot := ir.NewSelectorExpr(pos, ir.ODOTINTER, rcvr, m.(*ir.SelectorExpr).Sel)
        dot.Selection = typecheck.Lookdot1(dot, dot.Sel, dot.X.Type(), dot.X.Type().AllMethods(), 1)
 
-       // Do a type substitution on the generic bound, in case it is parameterized.
-       typed(subst.ts.Typ(x.(*ir.SelectorExpr).Selection.Type), dot)
+       typed(dot.Selection.Type, dot)
        innerCall = ir.NewCallExpr(pos, ir.OCALLINTER, dot, args)
        t := m.Type()
        if t.NumResults() == 0 {
@@ -1965,5 +2186,5 @@ func (g *irgen) buildClosure2(subst *subster, m, x ir.Node) ir.Node {
        ir.FinishCaptureNames(pos, outer, fn)
 
        // Do final checks on closure and return it.
-       return ir.UseClosure(fn.OClosure, g.target)
+       return ir.UseClosure(fn.OClosure, typecheck.Target)
 }
index 1949f56095ffb45891406dacc48e0eb07cbcc73d..aedb09e21ee74474385db3407e77f5dcba70291e 100644 (file)
@@ -5,6 +5,7 @@
 package noder
 
 import (
+       "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/typecheck"
@@ -27,6 +28,7 @@ func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node {
 }
 
 func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
+       base.Assert(g.exprStmtOK)
        switch stmt := stmt.(type) {
        case nil, *syntax.EmptyStmt:
                return nil
@@ -35,20 +37,18 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
        case *syntax.BlockStmt:
                return ir.NewBlockStmt(g.pos(stmt), g.blockStmt(stmt))
        case *syntax.ExprStmt:
-               return g.expr(stmt.X)
+               return wrapname(g.pos(stmt.X), g.expr(stmt.X))
        case *syntax.SendStmt:
                n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
-               if n.Chan.Type().HasTParam() || n.Value.Type().HasTParam() {
-                       // Delay transforming the send if the channel or value
-                       // have a type param.
-                       n.SetTypecheck(3)
-                       return n
+               if !g.delayTransform() {
+                       transformSend(n)
                }
-               transformSend(n)
                n.SetTypecheck(1)
                return n
        case *syntax.DeclStmt:
-               return ir.NewBlockStmt(g.pos(stmt), g.decls(stmt.DeclList))
+               n := ir.NewBlockStmt(g.pos(stmt), nil)
+               g.decls(&n.List, stmt.DeclList)
+               return n
 
        case *syntax.AssignStmt:
                if stmt.Op != 0 && stmt.Op != syntax.Def {
@@ -62,11 +62,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                                lhs := g.expr(stmt.Lhs)
                                n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs)
                        }
-                       if n.X.Typecheck() == 3 {
-                               n.SetTypecheck(3)
-                               return n
+                       if !g.delayTransform() {
+                               transformAsOp(n)
                        }
-                       transformAsOp(n)
                        n.SetTypecheck(1)
                        return n
                }
@@ -75,46 +73,24 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                rhs := g.exprList(stmt.Rhs)
                names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def)
 
-               // We must delay transforming the assign statement if any of the
-               // lhs or rhs nodes are also delayed, since transformAssign needs
-               // to know the types of the left and right sides in various cases.
-               delay := false
-               for _, e := range lhs {
-                       if e.Typecheck() == 3 {
-                               delay = true
-                               break
-                       }
-               }
-               for _, e := range rhs {
-                       if e.Typecheck() == 3 {
-                               delay = true
-                               break
-                       }
-               }
-
                if len(lhs) == 1 && len(rhs) == 1 {
                        n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
                        n.Def = initDefn(n, names)
 
-                       if delay {
-                               n.SetTypecheck(3)
-                               return n
+                       if !g.delayTransform() {
+                               lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
+                               transformAssign(n, lhs, rhs)
+                               n.X, n.Y = lhs[0], rhs[0]
                        }
-
-                       lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
-                       transformAssign(n, lhs, rhs)
-                       n.X, n.Y = lhs[0], rhs[0]
                        n.SetTypecheck(1)
                        return n
                }
 
                n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
                n.Def = initDefn(n, names)
-               if delay {
-                       n.SetTypecheck(3)
-                       return n
+               if !g.delayTransform() {
+                       transformAssign(n, n.Lhs, n.Rhs)
                }
-               transformAssign(n, n.Lhs, n.Rhs)
                n.SetTypecheck(1)
                return n
 
@@ -124,21 +100,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call))
        case *syntax.ReturnStmt:
                n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
-               for _, e := range n.Results {
-                       if e.Type().HasTParam() {
-                               // Delay transforming the return statement if any of the
-                               // return values have a type param.
-                               if !ir.HasNamedResults(ir.CurFunc) {
-                                       transformArgs(n)
-                                       // But add CONVIFACE nodes where needed if
-                                       // any of the return values have interface type.
-                                       typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, true)
-                               }
-                               n.SetTypecheck(3)
-                               return n
-                       }
+               if !g.delayTransform() {
+                       transformReturn(n)
                }
-               transformReturn(n)
                n.SetTypecheck(1)
                return n
        case *syntax.IfStmt:
@@ -147,7 +111,10 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                return g.forStmt(stmt)
        case *syntax.SelectStmt:
                n := g.selectStmt(stmt)
-               transformSelect(n.(*ir.SelectStmt))
+
+               if !g.delayTransform() {
+                       transformSelect(n.(*ir.SelectStmt))
+               }
                n.SetTypecheck(1)
                return n
        case *syntax.SwitchStmt:
@@ -323,6 +290,8 @@ func (g *irgen) switchStmt(stmt *syntax.SwitchStmt) ir.Node {
                if obj, ok := g.info.Implicits[clause]; ok {
                        cv = g.obj(obj)
                        cv.SetPos(g.makeXPos(clause.Colon))
+                       assert(expr.Op() == ir.OTYPESW)
+                       cv.Defn = expr
                }
                body[i] = ir.NewCaseStmt(g.pos(clause), g.exprList(clause.Cases), g.stmts(clause.Body))
                body[i].Var = cv
index 14747b7c10626c2be4da6de50a2f60749124bfc3..655cafc9502d25332bdb9c69b50a77147b701c26 100644 (file)
@@ -140,11 +140,12 @@ func _() {
        _ = x[syncTypeParamNames-130]
        _ = x[syncTypeParamBounds-131]
        _ = x[syncImplicitTypes-132]
+       _ = x[syncObjectName-133]
 }
 
-const _syncMarker_name = "NodeBoolInt64Uint64StringPosPkgSymSelectorKindTypeTypePkgSignatureParamOpObjectExprStmtDeclConstDeclFuncDeclTypeDeclVarDeclPragmaValueEOFMethodFuncBodyUseUseObjObjectIdxTypeIdxBOFEntryOpenScopeCloseScopeGlobalLocalDefineDefLocalUseLocalDefGlobalUseGlobalTypeParamsUseLabelDefLabelFuncLitCommonFuncBodyRefLinksymExtHackSetlinenoNameImportDeclDeclNamesDeclNameExprListExprsWrapnameTypeExprTypeExprOrNilChanDirParamsCloseAnotherScopeSumUnOpBinOpStructTypeInterfaceTypePacknameEmbeddedStmtsStmtsFallStmtFallBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtCompLit1234NDefImplicitUseNameUseObjLocalAddLocalBothSignatureSetUnderlyingLinknameStmt1StmtsEndDeclareTopDeclsTopConstDeclTopFuncDeclTopTypeDeclTopVarDeclObject1AddBodyLabelFuncExtMethExtOptLabelScalarStmtDeclsDeclLocalObjLocalObjLocal1DeclareLocalPublicPrivateRelocsRelocUseRelocVarExtPkgDefTypeExtValCodeObjPosBaseLocalIdentTypeParamNamesTypeParamBoundsImplicitTypes"
+const _syncMarker_name = "NodeBoolInt64Uint64StringPosPkgSymSelectorKindTypeTypePkgSignatureParamOpObjectExprStmtDeclConstDeclFuncDeclTypeDeclVarDeclPragmaValueEOFMethodFuncBodyUseUseObjObjectIdxTypeIdxBOFEntryOpenScopeCloseScopeGlobalLocalDefineDefLocalUseLocalDefGlobalUseGlobalTypeParamsUseLabelDefLabelFuncLitCommonFuncBodyRefLinksymExtHackSetlinenoNameImportDeclDeclNamesDeclNameExprListExprsWrapnameTypeExprTypeExprOrNilChanDirParamsCloseAnotherScopeSumUnOpBinOpStructTypeInterfaceTypePacknameEmbeddedStmtsStmtsFallStmtFallBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtCompLit1234NDefImplicitUseNameUseObjLocalAddLocalBothSignatureSetUnderlyingLinknameStmt1StmtsEndDeclareTopDeclsTopConstDeclTopFuncDeclTopTypeDeclTopVarDeclObject1AddBodyLabelFuncExtMethExtOptLabelScalarStmtDeclsDeclLocalObjLocalObjLocal1DeclareLocalPublicPrivateRelocsRelocUseRelocVarExtPkgDefTypeExtValCodeObjPosBaseLocalIdentTypeParamNamesTypeParamBoundsImplicitTypesObjectName"
 
-var _syncMarker_index = [...]uint16{0, 4, 8, 13, 19, 25, 28, 31, 34, 42, 46, 50, 57, 66, 71, 73, 79, 83, 87, 91, 100, 108, 116, 123, 129, 134, 137, 143, 151, 154, 160, 169, 176, 179, 184, 193, 203, 209, 214, 220, 228, 236, 245, 254, 264, 272, 280, 287, 297, 304, 314, 318, 327, 331, 341, 350, 358, 366, 371, 379, 387, 400, 407, 413, 430, 433, 437, 442, 452, 465, 473, 481, 486, 495, 503, 512, 518, 525, 535, 544, 554, 564, 574, 579, 590, 597, 598, 599, 600, 601, 602, 613, 620, 631, 639, 652, 665, 673, 678, 686, 693, 701, 713, 724, 735, 745, 752, 759, 764, 771, 778, 786, 792, 801, 810, 818, 827, 839, 845, 852, 858, 863, 871, 877, 883, 890, 893, 900, 907, 917, 931, 946, 959}
+var _syncMarker_index = [...]uint16{0, 4, 8, 13, 19, 25, 28, 31, 34, 42, 46, 50, 57, 66, 71, 73, 79, 83, 87, 91, 100, 108, 116, 123, 129, 134, 137, 143, 151, 154, 160, 169, 176, 179, 184, 193, 203, 209, 214, 220, 228, 236, 245, 254, 264, 272, 280, 287, 297, 304, 314, 318, 327, 331, 341, 350, 358, 366, 371, 379, 387, 400, 407, 413, 430, 433, 437, 442, 452, 465, 473, 481, 486, 495, 503, 512, 518, 525, 535, 544, 554, 564, 574, 579, 590, 597, 598, 599, 600, 601, 602, 613, 620, 631, 639, 652, 665, 673, 678, 686, 693, 701, 713, 724, 735, 745, 752, 759, 764, 771, 778, 786, 792, 801, 810, 818, 827, 839, 845, 852, 858, 863, 871, 877, 883, 890, 893, 900, 907, 917, 931, 946, 959, 969}
 
 func (i syncMarker) String() string {
        i -= 1
index e1eeb8e73940fa1b9adb98b3c5db043e764c082a..47e6397206d27d3e2d7966409962b2c0dd616c8e 100644 (file)
@@ -157,7 +157,7 @@ func transformCall(n *ir.CallExpr) {
                n.SetOp(ir.OCALLFUNC)
        }
 
-       typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, false)
+       typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args)
        if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 {
                typecheck.FixMethodCall(n)
        }
@@ -177,6 +177,12 @@ func transformCall(n *ir.CallExpr) {
        }
 }
 
+// transformEarlyCall transforms the arguments of a call with an OFUNCINST node.
+func transformEarlyCall(n *ir.CallExpr) {
+       transformArgs(n)
+       typecheckaste(ir.OCALL, n.X, n.IsDDD, n.X.Type().Params(), n.Args)
+}
+
 // transformCompare transforms a compare operation (currently just equals/not
 // equals). Corresponds to the "comparison operators" case in
 // typecheck.typecheck1, including tcArith.
@@ -195,7 +201,7 @@ func transformCompare(n *ir.BinaryExpr) {
                        aop, _ := typecheck.Assignop(lt, rt)
                        if aop != ir.OXXX {
                                types.CalcSize(lt)
-                               if lt.HasTParam() || rt.IsInterface() == lt.IsInterface() || lt.Width >= 1<<16 {
+                               if lt.HasShape() || rt.IsInterface() == lt.IsInterface() || lt.Size() >= 1<<16 {
                                        l = ir.NewConvExpr(base.Pos, aop, rt, l)
                                        l.SetTypecheck(1)
                                }
@@ -208,7 +214,7 @@ func transformCompare(n *ir.BinaryExpr) {
                        aop, _ := typecheck.Assignop(rt, lt)
                        if aop != ir.OXXX {
                                types.CalcSize(rt)
-                               if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Width >= 1<<16 {
+                               if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 {
                                        r = ir.NewConvExpr(base.Pos, aop, lt, r)
                                        r.SetTypecheck(1)
                                }
@@ -404,11 +410,15 @@ func assignconvfn(n ir.Node, t *types.Type) ir.Node {
                return n
        }
 
-       if types.Identical(n.Type(), t) {
+       if n.Op() == ir.OPAREN {
+               n = n.(*ir.ParenExpr).X
+       }
+
+       if types.IdenticalStrict(n.Type(), t) {
                return n
        }
 
-       op, why := typecheck.Assignop(n.Type(), t)
+       op, why := Assignop(n.Type(), t)
        if op == ir.OXXX {
                base.Fatalf("found illegal assignment %+v -> %+v; %s", n.Type(), t, why)
        }
@@ -419,11 +429,35 @@ func assignconvfn(n ir.Node, t *types.Type) ir.Node {
        return r
 }
 
+func Assignop(src, dst *types.Type) (ir.Op, string) {
+       if src == dst {
+               return ir.OCONVNOP, ""
+       }
+       if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
+               return ir.OXXX, ""
+       }
+
+       // 1. src type is identical to dst (taking shapes into account)
+       if types.Identical(src, dst) {
+               // We already know from assignconvfn above that IdenticalStrict(src,
+               // dst) is false, so the types are not exactly the same and one of
+               // src or dst is a shape. If dst is an interface (which means src is
+               // an interface too), we need a real OCONVIFACE op; otherwise we need a
+               // OCONVNOP. See issue #48453.
+               if dst.IsInterface() {
+                       return ir.OCONVIFACE, ""
+               } else {
+                       return ir.OCONVNOP, ""
+               }
+       }
+       return typecheck.Assignop1(src, dst)
+}
+
 // Corresponds to typecheck.typecheckaste, but we add an extra flag convifaceOnly
 // only. If convifaceOnly is true, we only do interface conversion. We use this to do
 // early insertion of CONVIFACE nodes during noder2, when the function or args may
 // have typeparams.
-func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes, convifaceOnly bool) {
+func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes) {
        var t *types.Type
        var i int
 
@@ -442,7 +476,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i
                        if isddd {
                                n = nl[i]
                                ir.SetPos(n)
-                               if n.Type() != nil && (!convifaceOnly || t.IsInterface()) {
+                               if n.Type() != nil {
                                        nl[i] = assignconvfn(n, t)
                                }
                                return
@@ -452,7 +486,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i
                        for ; i < len(nl); i++ {
                                n = nl[i]
                                ir.SetPos(n)
-                               if n.Type() != nil && (!convifaceOnly || t.IsInterface()) {
+                               if n.Type() != nil {
                                        nl[i] = assignconvfn(n, t.Elem())
                                }
                        }
@@ -461,7 +495,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i
 
                n = nl[i]
                ir.SetPos(n)
-               if n.Type() != nil && (!convifaceOnly || t.IsInterface()) {
+               if n.Type() != nil {
                        nl[i] = assignconvfn(n, t)
                }
                i++
@@ -483,7 +517,7 @@ func transformReturn(rs *ir.ReturnStmt) {
                return
        }
 
-       typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl, false)
+       typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl)
 }
 
 // transformSelect transforms a select node, creating an assignment list as needed
@@ -493,10 +527,16 @@ func transformSelect(sel *ir.SelectStmt) {
                if ncase.Comm != nil {
                        n := ncase.Comm
                        oselrecv2 := func(dst, recv ir.Node, def bool) {
-                               n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
-                               n.Def = def
-                               n.SetTypecheck(1)
-                               ncase.Comm = n
+                               selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
+                               if dst.Op() == ir.ONAME && dst.(*ir.Name).Defn == n {
+                                       // Must fix Defn for dst, since we are
+                                       // completely changing the node.
+                                       dst.(*ir.Name).Defn = selrecv
+                               }
+                               selrecv.Def = def
+                               selrecv.SetTypecheck(1)
+                               selrecv.SetInit(n.Init())
+                               ncase.Comm = selrecv
                        }
                        switch n.Op() {
                        case ir.OAS:
@@ -578,11 +618,7 @@ func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
 
        if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall {
                n.SetOp(ir.OMETHVALUE)
-               if len(n.X.Type().RParams()) > 0 || n.X.Type().IsPtr() && len(n.X.Type().Elem().RParams()) > 0 {
-                       // TODO: MethodValueWrapper needed for generics?
-                       // Or did we successfully desugar all that at stencil time?
-                       return n
-               }
+               // This converts a method type to a function type. See issue 47775.
                n.SetType(typecheck.NewMethodType(n.Type(), nil))
        }
        return n
@@ -815,7 +851,10 @@ func transformBuiltin(n *ir.CallExpr) ir.Node {
                        return transformRealImag(u1.(*ir.UnaryExpr))
                case ir.OPANIC:
                        return transformPanic(u1.(*ir.UnaryExpr))
-               case ir.OCLOSE, ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+               case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+                       // This corresponds to the EvalConst() call near end of typecheck().
+                       return typecheck.EvalConst(u1)
+               case ir.OCLOSE, ir.ONEW:
                        // nothing more to do
                        return u1
                }
@@ -881,7 +920,7 @@ func transformArrayLit(elemType *types.Type, bound int64, elts []ir.Node) int64
 
 // transformCompLit transforms n to an OARRAYLIT, OSLICELIT, OMAPLIT, or
 // OSTRUCTLIT node, with any needed conversions. Corresponds to
-// typecheck.tcCompLit.
+// typecheck.tcCompLit (and includes parts corresponding to tcStructLitKey).
 func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
        assert(n.Type() != nil && n.Typecheck() == 1)
        lno := base.Pos
@@ -955,12 +994,20 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
                                if id, ok := key.(*ir.Ident); ok && typecheck.DotImportRefs[id] != nil {
                                        s = typecheck.Lookup(s.Name)
                                }
+                               if types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
+                                       // Exported field names should always have
+                                       // local pkg. We only need to do this
+                                       // adjustment for generic functions that are
+                                       // being transformed after being imported
+                                       // from another package.
+                                       s = typecheck.Lookup(s.Name)
+                               }
 
                                // An OXDOT uses the Sym field to hold
                                // the field to the right of the dot,
                                // so s will be non-nil, but an OXDOT
                                // is never a valid struct literal key.
-                               assert(!(s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank()))
+                               assert(!(s == nil || key.Op() == ir.OXDOT || s.IsBlank()))
 
                                f := typecheck.Lookdot1(nil, s, t, t.Fields(), 0)
                                l := ir.NewStructKeyExpr(l.Pos(), f, kv.Value)
@@ -975,3 +1022,11 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
 
        return n
 }
+
+// transformAddr corresponds to typecheck.tcAddr.
+func transformAddr(n *ir.AddrExpr) {
+       switch n.X.Op() {
+       case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
+               n.SetOp(ir.OPTRLIT)
+       }
+}
index 8d596e599ed172a0f23d96eea0170c08737f4a36..f035e0da9787dc79d0d0a7540d2b2ec64556449b 100644 (file)
@@ -5,7 +5,6 @@
 package noder
 
 import (
-       "bytes"
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/typecheck"
@@ -22,7 +21,7 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
        case g.self:
                return types.LocalPkg
        case types2.Unsafe:
-               return ir.Pkgs.Unsafe
+               return types.UnsafePkg
        }
        return types.NewPkg(pkg.Path(), pkg.Name())
 }
@@ -30,20 +29,22 @@ func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
 // typ converts a types2.Type to a types.Type, including caching of previously
 // translated types.
 func (g *irgen) typ(typ types2.Type) *types.Type {
+       // Defer the CheckSize calls until we have fully-defined a
+       // (possibly-recursive) top-level type.
+       types.DeferCheckSize()
        res := g.typ1(typ)
-
-       // Calculate the size for all concrete types seen by the frontend. The old
-       // typechecker calls CheckSize() a lot, and we want to eliminate calling
-       // it eventually, so we should do it here instead. We only call it for
-       // top-level types (i.e. we do it here rather in typ1), to make sure that
-       // recursive types have been fully constructed before we call CheckSize.
-       if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
-               types.CheckSize(res)
-               if res.IsPtr() {
-                       // Pointers always have their size set, even though their element
-                       // may not have its size set.
-                       types.CheckSize(res.Elem())
-               }
+       types.ResumeCheckSize()
+
+       // Finish up any types on typesToFinalize, now that we are at the top of a
+       // fully-defined (possibly recursive) type. fillinMethods could create more
+       // types to finalize.
+       for len(g.typesToFinalize) > 0 {
+               l := len(g.typesToFinalize)
+               info := g.typesToFinalize[l-1]
+               g.typesToFinalize = g.typesToFinalize[:l-1]
+               types.DeferCheckSize()
+               g.fillinMethods(info.typ, info.ntyp)
+               types.ResumeCheckSize()
        }
        return res
 }
@@ -59,6 +60,12 @@ func (g *irgen) typ1(typ types2.Type) *types.Type {
        res, ok := g.typs[typ]
        if !ok {
                res = g.typ0(typ)
+               // Calculate the size for all concrete types seen by the frontend.
+               // This is the replacement for the CheckSize() calls in the types1
+               // typechecker. These will be deferred until the top-level g.typ().
+               if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
+                       types.CheckSize(res)
+               }
                g.typs[typ] = res
        }
        return res
@@ -66,27 +73,12 @@ func (g *irgen) typ1(typ types2.Type) *types.Type {
 
 // instTypeName2 creates a name for an instantiated type, base on the type args
 // (given as types2 types).
-func instTypeName2(name string, targs []types2.Type) string {
-       b := bytes.NewBufferString(name)
-       b.WriteByte('[')
-       for i, targ := range targs {
-               if i > 0 {
-                       b.WriteByte(',')
-               }
-               // Include package names for all types, including typeparams, to
-               // make sure type arguments are uniquely specified.
-               tname := types2.TypeString(targ,
-                       func(pkg *types2.Package) string { return pkg.Name() })
-               if strings.Index(tname, ", ") >= 0 {
-                       // types2.TypeString puts spaces after a comma in a type
-                       // list, but we don't want spaces in our actual type names
-                       // and method/function names derived from them.
-                       tname = strings.Replace(tname, ", ", ",", -1)
-               }
-               b.WriteString(tname)
+func (g *irgen) instTypeName2(name string, targs *types2.TypeList) string {
+       rparams := make([]*types.Type, targs.Len())
+       for i := range rparams {
+               rparams[i] = g.typ(targs.At(i))
        }
-       b.WriteByte(']')
-       return b.String()
+       return typecheck.InstTypeName(name, rparams)
 }
 
 // typ0 converts a types2.Type to a types.Type, but doesn't do the caching check
@@ -101,7 +93,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                // since that is the only use of a generic type that doesn't
                // involve instantiation. We just translate the named type in the
                // normal way below using g.obj().
-               if typ.TParams() != nil && typ.TArgs() != nil {
+               if typ.TypeParams() != nil && typ.TypeArgs() != nil {
                        // typ is an instantiation of a defined (named) generic type.
                        // This instantiation should also be a defined (named) type.
                        // types2 gives us the substituted type in t.Underlying()
@@ -111,7 +103,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                        //
                        // When converted to types.Type, typ has a unique name,
                        // based on the names of the type arguments.
-                       instName := instTypeName2(typ.Obj().Name(), typ.TArgs())
+                       instName := g.instTypeName2(typ.Obj().Name(), typ.TypeArgs())
                        s := g.pkg(typ.Obj().Pkg()).Lookup(instName)
                        if s.Def != nil {
                                // We have already encountered this instantiation.
@@ -120,9 +112,14 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                                return s.Def.Type()
                        }
 
+                       // Make sure the base generic type exists in type1 (it may
+                       // not yet if we are referecing an imported generic type, as
+                       // opposed to a generic type declared in this package).
+                       _ = g.obj(typ.Origin().Obj())
+
                        // Create a forwarding type first and put it in the g.typs
                        // map, in order to deal with recursive generic types
-                       // (including via method signatures).. Set up the extra
+                       // (including via method signatures). Set up the extra
                        // ntyp information (Def, RParams, which may set
                        // HasTParam) before translating the underlying type
                        // itself, so we handle recursion correctly.
@@ -140,17 +137,27 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                        // non-generic types used to instantiate this type. We'll
                        // use these when instantiating the methods of the
                        // instantiated type.
-                       rparams := make([]*types.Type, len(typ.TArgs()))
-                       for i, targ := range typ.TArgs() {
-                               rparams[i] = g.typ1(targ)
+                       targs := typ.TypeArgs()
+                       rparams := make([]*types.Type, targs.Len())
+                       for i := range rparams {
+                               rparams[i] = g.typ1(targs.At(i))
                        }
                        ntyp.SetRParams(rparams)
                        //fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
 
-                       ntyp.SetUnderlying(g.typ1(typ.Underlying()))
-                       g.fillinMethods(typ, ntyp)
                        // Save the symbol for the base generic type.
-                       ntyp.OrigSym = g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name())
+                       ntyp.SetOrigSym(g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name()))
+                       ntyp.SetUnderlying(g.typ1(typ.Underlying()))
+                       if typ.NumMethods() != 0 {
+                               // Save a delayed call to g.fillinMethods() (once
+                               // potentially recursive types have been fully
+                               // resolved).
+                               g.typesToFinalize = append(g.typesToFinalize,
+                                       &typeDelayInfo{
+                                               typ:  typ,
+                                               ntyp: ntyp,
+                                       })
+                       }
                        return ntyp
                }
                obj := g.obj(typ.Obj())
@@ -202,17 +209,20 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                methods := make([]*types.Field, typ.NumExplicitMethods())
                for i := range methods {
                        m := typ.ExplicitMethod(i)
-                       mtyp := g.signature(typecheck.FakeRecv(), m.Type().(*types2.Signature))
+                       mtyp := g.signature(types.FakeRecv(), m.Type().(*types2.Signature))
                        methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp)
                }
 
-               return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...))
+               return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...), typ.IsImplicit())
 
        case *types2.TypeParam:
                // Save the name of the type parameter in the sym of the type.
                // Include the types2 subscript in the sym name
                pkg := g.tpkg(typ)
-               sym := pkg.Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" }))
+               // Create the unique types1 name for a type param, using its context with a
+               // function, type, or method declaration.
+               nm := g.curDecl + "." + typ.Obj().Name()
+               sym := pkg.Lookup(nm)
                if sym.Def != nil {
                        // Make sure we use the same type param type for the same
                        // name, whether it is created during types1-import or
@@ -262,83 +272,88 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
        }
 }
 
-// fillinMethods fills in the method name nodes and types for a defined type. This
-// is needed for later typechecking when looking up methods of instantiated types,
-// and for actually generating the methods for instantiated types.
+// fillinMethods fills in the method name nodes and types for a defined type with at
+// least one method. This is needed for later typechecking when looking up methods of
+// instantiated types, and for actually generating the methods for instantiated
+// types.
 func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
-       if typ.NumMethods() != 0 {
-               targs := make([]*types.Type, len(typ.TArgs()))
-               for i, targ := range typ.TArgs() {
-                       targs[i] = g.typ1(targ)
-               }
+       targs2 := typ.TypeArgs()
+       targs := make([]*types.Type, targs2.Len())
+       for i := range targs {
+               targs[i] = g.typ1(targs2.At(i))
+       }
 
-               methods := make([]*types.Field, typ.NumMethods())
-               for i := range methods {
-                       m := typ.Method(i)
-                       recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
-                       var meth *ir.Name
-                       if m.Pkg() != g.self {
-                               // Imported methods cannot be loaded by name (what
-                               // g.obj() does) - they must be loaded via their
-                               // type.
-                               meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
+       methods := make([]*types.Field, typ.NumMethods())
+       for i := range methods {
+               m := typ.Method(i)
+               recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
+               var meth *ir.Name
+               imported := false
+               if m.Pkg() != g.self {
+                       // Imported methods cannot be loaded by name (what
+                       // g.obj() does) - they must be loaded via their
+                       // type.
+                       meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
+                       // XXX Because Obj() returns the object of the base generic
+                       // type, we have to still do the method translation below.
+                       imported = true
+               } else {
+                       meth = g.obj(m)
+               }
+               assert(recvType == types2.Type(typ))
+               if imported {
+                       // Unfortunately, meth is the type of the method of the
+                       // generic type, so we have to do a substitution to get
+                       // the name/type of the method of the instantiated type,
+                       // using m.Type().RParams() and typ.TArgs()
+                       inst2 := g.instTypeName2("", typ.TypeArgs())
+                       name := meth.Sym().Name
+                       i1 := strings.Index(name, "[")
+                       i2 := strings.Index(name[i1:], "]")
+                       assert(i1 >= 0 && i2 >= 0)
+                       // Generate the name of the instantiated method.
+                       name = name[0:i1] + inst2 + name[i1+i2+1:]
+                       newsym := meth.Sym().Pkg.Lookup(name)
+                       var meth2 *ir.Name
+                       if newsym.Def != nil {
+                               meth2 = newsym.Def.(*ir.Name)
                        } else {
-                               meth = g.obj(m)
-                       }
-                       if recvType != types2.Type(typ) {
-                               // Unfortunately, meth is the type of the method of the
-                               // generic type, so we have to do a substitution to get
-                               // the name/type of the method of the instantiated type,
-                               // using m.Type().RParams() and typ.TArgs()
-                               inst2 := instTypeName2("", typ.TArgs())
-                               name := meth.Sym().Name
-                               i1 := strings.Index(name, "[")
-                               i2 := strings.Index(name[i1:], "]")
-                               assert(i1 >= 0 && i2 >= 0)
-                               // Generate the name of the instantiated method.
-                               name = name[0:i1] + inst2 + name[i1+i2+1:]
-                               newsym := meth.Sym().Pkg.Lookup(name)
-                               var meth2 *ir.Name
-                               if newsym.Def != nil {
-                                       meth2 = newsym.Def.(*ir.Name)
-                               } else {
-                                       meth2 = ir.NewNameAt(meth.Pos(), newsym)
-                                       rparams := types2.AsSignature(m.Type()).RParams()
-                                       tparams := make([]*types.Type, rparams.Len())
-                                       for i := range tparams {
-                                               tparams[i] = g.typ1(rparams.At(i).Type())
-                                       }
-                                       assert(len(tparams) == len(targs))
-                                       ts := typecheck.Tsubster{
-                                               Tparams: tparams,
-                                               Targs:   targs,
-                                       }
-                                       // Do the substitution of the type
-                                       meth2.SetType(ts.Typ(meth.Type()))
-                                       // Add any new fully instantiated types
-                                       // seen during the substitution to
-                                       // g.instTypeList.
-                                       g.instTypeList = append(g.instTypeList, ts.InstTypeList...)
-                                       newsym.Def = meth2
+                               meth2 = ir.NewNameAt(meth.Pos(), newsym)
+                               rparams := types2.AsSignature(m.Type()).RecvTypeParams()
+                               tparams := make([]*types.Type, rparams.Len())
+                               // Set g.curDecl to be the method context, so type
+                               // params in the receiver of the method that we are
+                               // translating gets the right unique name.
+                               g.curDecl = typ.Obj().Name() + "." + m.Name()
+                               for i := range tparams {
+                                       tparams[i] = g.typ1(rparams.At(i))
+                               }
+                               assert(len(tparams) == len(targs))
+                               ts := typecheck.Tsubster{
+                                       Tparams: tparams,
+                                       Targs:   targs,
                                }
-                               meth = meth2
+                               // Do the substitution of the type
+                               meth2.SetType(ts.Typ(meth.Type()))
+                               newsym.Def = meth2
                        }
-                       methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
-                       methods[i].Nname = meth
-               }
-               ntyp.Methods().Set(methods)
-               if !ntyp.HasTParam() && !ntyp.HasShape() {
-                       // Generate all the methods for a new fully-instantiated type.
-                       g.instTypeList = append(g.instTypeList, ntyp)
+                       meth = meth2
                }
+               methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
+               methods[i].Nname = meth
+       }
+       ntyp.Methods().Set(methods)
+       if !ntyp.HasTParam() && !ntyp.HasShape() {
+               // Generate all the methods for a new fully-instantiated type.
+               typecheck.NeedInstType(ntyp)
        }
 }
 
 func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
-       tparams2 := sig.TParams()
+       tparams2 := sig.TypeParams()
        tparams := make([]*types.Field, tparams2.Len())
        for i := range tparams {
-               tp := tparams2.At(i)
+               tp := tparams2.At(i).Obj()
                tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type()))
        }
 
index 9f80ca000de317e8ca1ec2b03f05afe92922f691..ec0012db4cec44bb732597f5843ffb2db863f8b9 100644 (file)
@@ -78,12 +78,12 @@ func unified(noders []*noder) {
                base.Errorf("cannot use -G and -d=quirksmode together")
        }
 
-       newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
+       newReadImportFunc = func(data string, pkg1 *types.Pkg, ctxt *types2.Context, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
                pr := newPkgDecoder(pkg1.Path, data)
 
                // Read package descriptors for both types2 and compiler backend.
                readPackage(newPkgReader(pr), pkg1)
-               pkg2 = readPackage2(check, packages, pr)
+               pkg2 = readPackage2(ctxt, packages, pr)
                return
        }
 
@@ -106,7 +106,6 @@ func unified(noders []*noder) {
        readPackage(localPkgReader, types.LocalPkg)
 
        r := localPkgReader.newReader(relocMeta, privateRootIdx, syncPrivate)
-       r.ext = r
        r.pkgInit(types.LocalPkg, target)
 
        // Type-check any top-level assignments. We ignore non-assignments
@@ -137,11 +136,7 @@ func unified(noders []*noder) {
                }
        }
        todoBodies = nil
-
-       if !quirksMode() {
-               // TODO(mdempsky): Investigate generating wrappers in quirks mode too.
-               r.wrapTypes(target)
-       }
+       todoBodiesDone = true
 
        // Check that nothing snuck past typechecking.
        for _, n := range target.Decls {
@@ -195,7 +190,6 @@ func writePkgStub(noders []*noder) string {
 
        {
                w := privateRootWriter
-               w.ext = w
                w.pkgInit(noders)
                w.flush()
        }
index 96cc66f775d3895060e6ca69c9ad3c92ce5067a0..d7334df282885f0c4ffb2ac6542c1585da7a6c04 100644 (file)
@@ -16,6 +16,7 @@ import (
 )
 
 var (
+       flagCmp      = flag.Bool("cmp", false, "enable TestUnifiedCompare")
        flagPkgs     = flag.String("pkgs", "std", "list of packages to compare (ignored in -short mode)")
        flagAll      = flag.Bool("all", false, "enable testing of all GOOS/GOARCH targets")
        flagParallel = flag.Bool("parallel", false, "test GOOS/GOARCH targets in parallel")
@@ -37,6 +38,12 @@ var (
 // command's -run flag for subtest matching is recommended for less
 // powerful machines.
 func TestUnifiedCompare(t *testing.T) {
+       // TODO(mdempsky): Either re-enable or delete. Disabled for now to
+       // avoid impeding others' forward progress.
+       if !*flagCmp {
+               t.Skip("skipping TestUnifiedCompare (use -cmp to enable)")
+       }
+
        targets, err := exec.Command("go", "tool", "dist", "list").Output()
        if err != nil {
                t.Fatal(err)
index 68a059b96f4a29691e445dcfc5108765b41ba36f..dcacae7480c2975c50182aeb72d46d31e374d4f4 100644 (file)
@@ -81,7 +81,16 @@ func (g *irgen) validateBuiltin(name string, call *syntax.CallExpr) {
                // Check that types2+gcSizes calculates sizes the same
                // as cmd/compile does.
 
-               got, ok := constant.Int64Val(g.info.Types[call].Value)
+               tv := g.info.Types[call]
+               if !tv.IsValue() {
+                       base.FatalfAt(g.pos(call), "expected a value")
+               }
+
+               if tv.Value == nil {
+                       break // unsafe op is not a constant, so no further validation
+               }
+
+               got, ok := constant.Int64Val(tv.Value)
                if !ok {
                        base.FatalfAt(g.pos(call), "expected int64 constant value")
                }
index d971bd0d164c7f7ec96f255cb3a6480248032ba4..dde42c85d6ef2618f726e3850ee08230f6968416 100644 (file)
@@ -75,14 +75,6 @@ type writer struct {
 
        encoder
 
-       // For writing out object descriptions, ext points to the extension
-       // writer for where we can write the compiler's private extension
-       // details for the object.
-       //
-       // TODO(mdempsky): This is a little hacky, but works easiest with
-       // the way things are currently.
-       ext *writer
-
        // TODO(mdempsky): We should be able to prune localsIdx whenever a
        // scope closes, and then maybe we can just use the same map for
        // storing the TypeParams too (as their TypeName instead).
@@ -189,11 +181,7 @@ func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) int {
        w := pw.newWriter(relocPosBase, syncPosBase)
        w.p.posBasesIdx[b] = w.idx
 
-       // TODO(mdempsky): What exactly does "fileh" do anyway? Is writing
-       // out both of these strings really the right thing to do here?
-       fn := b.Filename()
-       w.string(fn)
-       w.string(fileh(fn))
+       w.string(trimFilename(b))
 
        if !w.bool(b.IsFileBase()) {
                w.pos(b)
@@ -303,16 +291,16 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
                // Type aliases can refer to uninstantiated generic types, so we
                // might see len(TParams) != 0 && len(TArgs) == 0 here.
                // TODO(mdempsky): Revisit after #46477 is resolved.
-               assert(typ.TParams().Len() == len(typ.TArgs()) || len(typ.TArgs()) == 0)
+               assert(typ.TypeParams().Len() == typ.TypeArgs().Len() || typ.TypeArgs().Len() == 0)
 
                // TODO(mdempsky): Why do we need to loop here?
                orig := typ
-               for orig.TArgs() != nil {
-                       orig = orig.Orig()
+               for orig.TypeArgs() != nil {
+                       orig = orig.Origin()
                }
 
                w.code(typeNamed)
-               w.obj(orig.Obj(), typ.TArgs())
+               w.obj(orig.Obj(), typ.TypeArgs())
 
        case *types2.TypeParam:
                index := func() int {
@@ -349,7 +337,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
                w.typ(typ.Elem())
 
        case *types2.Signature:
-               assert(typ.TParams() == nil)
+               base.Assertf(typ.TypeParams() == nil, "unexpected type params: %v", typ)
                w.code(typeSignature)
                w.signature(typ)
 
@@ -409,7 +397,7 @@ func (w *writer) interfaceType(typ *types2.Interface) {
        for i := 0; i < typ.NumExplicitMethods(); i++ {
                m := typ.ExplicitMethod(i)
                sig := m.Type().(*types2.Signature)
-               assert(sig.TParams() == nil)
+               assert(sig.TypeParams() == nil)
 
                w.pos(m)
                w.selector(m)
@@ -445,10 +433,10 @@ func (w *writer) param(param *types2.Var) {
 
 // @@@ Objects
 
-func (w *writer) obj(obj types2.Object, explicits []types2.Type) {
-       explicitInfos := make([]typeInfo, len(explicits))
-       for i, explicit := range explicits {
-               explicitInfos[i] = w.p.typIdx(explicit, w.dict)
+func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) {
+       explicitInfos := make([]typeInfo, explicits.Len())
+       for i := range explicitInfos {
+               explicitInfos[i] = w.p.typIdx(explicits.At(i), w.dict)
        }
        info := objInfo{idx: w.p.objIdx(obj), explicits: explicitInfos}
 
@@ -508,21 +496,21 @@ func (pw *pkgWriter) objIdx(obj types2.Object) int {
        }
 
        w := pw.newWriter(relocObj, syncObject1)
-       w.ext = pw.newWriter(relocObjExt, syncObject1)
+       wext := pw.newWriter(relocObjExt, syncObject1)
        wname := pw.newWriter(relocName, syncObject1)
        wdict := pw.newWriter(relocObjDict, syncObject1)
 
        pw.globalsIdx[obj] = w.idx // break cycles
-       assert(w.ext.idx == w.idx)
+       assert(wext.idx == w.idx)
        assert(wname.idx == w.idx)
        assert(wdict.idx == w.idx)
 
        w.dict = dict
-       w.ext.dict = dict
+       wext.dict = dict
 
-       code := w.doObj(obj)
+       code := w.doObj(wext, obj)
        w.flush()
-       w.ext.flush()
+       wext.flush()
 
        wname.qualifiedIdent(obj)
        wname.code(code)
@@ -534,7 +522,7 @@ func (pw *pkgWriter) objIdx(obj types2.Object) int {
        return w.idx
 }
 
-func (w *writer) doObj(obj types2.Object) codeObj {
+func (w *writer) doObj(wext *writer, obj types2.Object) codeObj {
        if obj.Pkg() != w.p.curpkg {
                return objStub
        }
@@ -546,7 +534,8 @@ func (w *writer) doObj(obj types2.Object) codeObj {
 
        case *types2.Const:
                w.pos(obj)
-               w.value(obj.Type(), obj.Val())
+               w.typ(obj.Type())
+               w.value(obj.Val())
                return objConst
 
        case *types2.Func:
@@ -555,10 +544,10 @@ func (w *writer) doObj(obj types2.Object) codeObj {
                sig := obj.Type().(*types2.Signature)
 
                w.pos(obj)
-               w.typeParamNames(sig.TParams())
+               w.typeParamNames(sig.TypeParams())
                w.signature(sig)
                w.pos(decl)
-               w.ext.funcExt(obj)
+               wext.funcExt(obj)
                return objFunc
 
        case *types2.TypeName:
@@ -572,16 +561,16 @@ func (w *writer) doObj(obj types2.Object) codeObj {
                }
 
                named := obj.Type().(*types2.Named)
-               assert(named.TArgs() == nil)
+               assert(named.TypeArgs() == nil)
 
                w.pos(obj)
-               w.typeParamNames(named.TParams())
-               w.ext.typeExt(obj)
+               w.typeParamNames(named.TypeParams())
+               wext.typeExt(obj)
                w.typExpr(decl.Type)
 
                w.len(named.NumMethods())
                for i := 0; i < named.NumMethods(); i++ {
-                       w.method(named.Method(i))
+                       w.method(wext, named.Method(i))
                }
 
                return objType
@@ -589,7 +578,7 @@ func (w *writer) doObj(obj types2.Object) codeObj {
        case *types2.Var:
                w.pos(obj)
                w.typ(obj.Type())
-               w.ext.varExt(obj)
+               wext.varExt(obj)
                return objVar
        }
 }
@@ -602,12 +591,6 @@ func (w *writer) typExpr(expr syntax.Expr) {
        w.typ(tv.Type)
 }
 
-func (w *writer) value(typ types2.Type, val constant.Value) {
-       w.sync(syncValue)
-       w.typ(typ)
-       w.rawValue(val)
-}
-
 // objDict writes the dictionary needed for reading the given object.
 func (w *writer) objDict(obj types2.Object, dict *writerDict) {
        // TODO(mdempsky): Split objDict into multiple entries? reader.go
@@ -622,7 +605,7 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) {
        ntparams := tparams.Len()
        w.len(ntparams)
        for i := 0; i < ntparams; i++ {
-               w.typ(tparams.At(i).Type().(*types2.TypeParam).Constraint())
+               w.typ(tparams.At(i).Constraint())
        }
 
        nderived := len(dict.derived)
@@ -646,18 +629,18 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) {
        assert(len(dict.funcs) == nfuncs)
 }
 
-func (w *writer) typeParamNames(tparams *types2.TParamList) {
+func (w *writer) typeParamNames(tparams *types2.TypeParamList) {
        w.sync(syncTypeParamNames)
 
        ntparams := tparams.Len()
        for i := 0; i < ntparams; i++ {
-               tparam := tparams.At(i)
+               tparam := tparams.At(i).Obj()
                w.pos(tparam)
                w.localIdent(tparam)
        }
 }
 
-func (w *writer) method(meth *types2.Func) {
+func (w *writer) method(wext *writer, meth *types2.Func) {
        decl, ok := w.p.funDecls[meth]
        assert(ok)
        sig := meth.Type().(*types2.Signature)
@@ -665,12 +648,12 @@ func (w *writer) method(meth *types2.Func) {
        w.sync(syncMethod)
        w.pos(meth)
        w.selector(meth)
-       w.typeParamNames(sig.RParams())
+       w.typeParamNames(sig.RecvTypeParams())
        w.param(sig.Recv())
        w.signature(sig)
 
        w.pos(decl) // XXX: Hack to workaround linker limitations.
-       w.ext.funcExt(meth)
+       wext.funcExt(meth)
 }
 
 // qualifiedIdent writes out the name of an object declared at package
@@ -1175,11 +1158,16 @@ func (w *writer) optLabel(label *syntax.Name) {
 func (w *writer) expr(expr syntax.Expr) {
        expr = unparen(expr) // skip parens; unneeded after typecheck
 
-       obj, targs := lookupObj(w.p.info, expr)
+       obj, inst := lookupObj(w.p.info, expr)
+       targs := inst.TypeArgs
 
        if tv, ok := w.p.info.Types[expr]; ok {
                // TODO(mdempsky): Be more judicious about which types are marked as "needed".
-               w.needType(tv.Type)
+               if inst.Type != nil {
+                       w.needType(inst.Type)
+               } else {
+                       w.needType(tv.Type)
+               }
 
                if tv.IsType() {
                        w.code(exprType)
@@ -1203,7 +1191,8 @@ func (w *writer) expr(expr syntax.Expr) {
 
                        w.code(exprConst)
                        w.pos(pos)
-                       w.value(tv.Type, tv.Value)
+                       w.typ(tv.Type)
+                       w.value(tv.Value)
 
                        // TODO(mdempsky): These details are only important for backend
                        // diagnostics. Explore writing them out separately.
@@ -1221,7 +1210,7 @@ func (w *writer) expr(expr syntax.Expr) {
                }
 
                obj := obj.(*types2.Var)
-               assert(len(targs) == 0)
+               assert(targs.Len() == 0)
 
                w.code(exprLocal)
                w.useLocal(expr.Pos(), obj)
@@ -1319,16 +1308,7 @@ func (w *writer) expr(expr syntax.Expr) {
                                }
                        }
 
-                       if inf, ok := w.p.info.Inferred[expr]; ok {
-                               obj, _ := lookupObj(w.p.info, expr.Fun)
-                               assert(obj != nil)
-
-                               // As if w.expr(expr.Fun), but using inf.TArgs instead.
-                               w.code(exprName)
-                               w.obj(obj, inf.TArgs)
-                       } else {
-                               w.expr(expr.Fun)
-                       }
+                       w.expr(expr.Fun)
                        w.bool(false) // not a method call (i.e., normal function call)
                }
 
@@ -1483,7 +1463,7 @@ func (c *declCollector) withTParams(obj types2.Object) *declCollector {
        copy := *c
        copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)]
        for i := 0; i < n; i++ {
-               copy.implicits = append(copy.implicits, tparams.At(i))
+               copy.implicits = append(copy.implicits, tparams.At(i).Obj())
        }
        return &copy
 }
@@ -1681,7 +1661,7 @@ func (w *writer) pkgDecl(decl syntax.Decl) {
                obj := w.p.info.Defs[decl.Name].(*types2.Func)
                sig := obj.Type().(*types2.Signature)
 
-               if sig.RParams() != nil || sig.TParams() != nil {
+               if sig.RecvTypeParams() != nil || sig.TypeParams() != nil {
                        break // skip generic functions
                }
 
@@ -1707,7 +1687,7 @@ func (w *writer) pkgDecl(decl syntax.Decl) {
                name := w.p.info.Defs[decl.Name].(*types2.TypeName)
                // Skip type declarations for interfaces that are only usable as
                // type parameter bounds.
-               if iface, ok := name.Type().Underlying().(*types2.Interface); ok && iface.IsConstraint() {
+               if iface, ok := name.Type().Underlying().(*types2.Interface); ok && !iface.IsMethodSet() {
                        break
                }
 
@@ -1715,7 +1695,7 @@ func (w *writer) pkgDecl(decl syntax.Decl) {
                // TODO(mdempsky): Revisit after #46477 is resolved.
                if name.IsAlias() {
                        named, ok := name.Type().(*types2.Named)
-                       if ok && named.TParams().Len() != 0 && len(named.TArgs()) == 0 {
+                       if ok && named.TypeParams().Len() != 0 && named.TypeArgs().Len() == 0 {
                                break
                        }
                }
@@ -1772,29 +1752,16 @@ func isGlobal(obj types2.Object) bool {
 }
 
 // lookupObj returns the object that expr refers to, if any. If expr
-// is an explicit instantiation of a generic object, then the type
-// arguments are returned as well.
-func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, targs []types2.Type) {
+// is an explicit instantiation of a generic object, then the instance
+// object is returned as well.
+func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, inst types2.Instance) {
        if index, ok := expr.(*syntax.IndexExpr); ok {
-               if inf, ok := info.Inferred[index]; ok {
-                       targs = inf.TArgs
-               } else {
-                       args := unpackListExpr(index.Index)
-
-                       if len(args) == 1 {
-                               tv, ok := info.Types[args[0]]
-                               assert(ok)
-                               if tv.IsValue() {
-                                       return // normal index expression
-                               }
-                       }
-
-                       targs = make([]types2.Type, len(args))
-                       for i, arg := range args {
-                               tv, ok := info.Types[arg]
-                               assert(ok)
-                               assert(tv.IsType())
-                               targs[i] = tv.Type
+               args := unpackListExpr(index.Index)
+               if len(args) == 1 {
+                       tv, ok := info.Types[args[0]]
+                       assert(ok)
+                       if tv.IsValue() {
+                               return // normal index expression
                        }
                }
 
@@ -1810,7 +1777,8 @@ func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, targs []
        }
 
        if name, ok := expr.(*syntax.Name); ok {
-               obj, _ = info.Uses[name]
+               obj = info.Uses[name]
+               inst = info.Instances[name]
        }
        return
 }
@@ -1861,17 +1829,17 @@ func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int {
 }
 
 // objTypeParams returns the type parameters on the given object.
-func objTypeParams(obj types2.Object) *types2.TParamList {
+func objTypeParams(obj types2.Object) *types2.TypeParamList {
        switch obj := obj.(type) {
        case *types2.Func:
                sig := obj.Type().(*types2.Signature)
                if sig.Recv() != nil {
-                       return sig.RParams()
+                       return sig.RecvTypeParams()
                }
-               return sig.TParams()
+               return sig.TypeParams()
        case *types2.TypeName:
                if !obj.IsAlias() {
-                       return obj.Type().(*types2.Named).TParams()
+                       return obj.Type().(*types2.Named).TypeParams()
                }
        }
        return nil
index 7cad2622146d0e580cb257348ec234ecb05ba713..40f14082600c3d1515c3d1e9350d961f4dbcb77e 100644 (file)
@@ -6,14 +6,62 @@ package pkginit
 
 import (
        "cmd/compile/internal/base"
-       "cmd/compile/internal/deadcode"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/objw"
+       "cmd/compile/internal/staticinit"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
+       "cmd/internal/src"
 )
 
+// MakeInit creates a synthetic init function to handle any
+// package-scope initialization statements.
+//
+// TODO(mdempsky): Move into noder, so that the types2-based frontends
+// can use Info.InitOrder instead.
+func MakeInit() {
+       nf := initOrder(typecheck.Target.Decls)
+       if len(nf) == 0 {
+               return
+       }
+
+       // Make a function that contains all the initialization statements.
+       base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
+       initializers := typecheck.Lookup("init")
+       fn := typecheck.DeclFunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
+       for _, dcl := range typecheck.InitTodoFunc.Dcl {
+               dcl.Curfn = fn
+       }
+       fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
+       typecheck.InitTodoFunc.Dcl = nil
+
+       // Suppress useless "can inline" diagnostics.
+       // Init functions are only called dynamically.
+       fn.SetInlinabilityChecked(true)
+
+       fn.Body = nf
+       typecheck.FinishFuncBody()
+
+       typecheck.Func(fn)
+       ir.WithFunc(fn, func() {
+               typecheck.Stmts(nf)
+       })
+       typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
+
+       // Prepend to Inits, so it runs first, before any user-declared init
+       // functions.
+       typecheck.Target.Inits = append([]*ir.Func{fn}, typecheck.Target.Inits...)
+
+       if typecheck.InitTodoFunc.Dcl != nil {
+               // We only generate temps using InitTodoFunc if there
+               // are package-scope initialization statements, so
+               // something's weird if we get here.
+               base.Fatalf("InitTodoFunc still has declarations")
+       }
+       typecheck.InitTodoFunc = nil
+}
+
 // Task makes and returns an initialization record for the package.
 // See runtime/proc.go:initTask for its layout.
 // The 3 tasks for initialization are:
@@ -21,8 +69,6 @@ import (
 //   2) Initialize all the variables that have initializers.
 //   3) Run any init functions.
 func Task() *ir.Name {
-       nf := initOrder(typecheck.Target.Decls)
-
        var deps []*obj.LSym // initTask records for packages the current package depends on
        var fns []*obj.LSym  // functions to call for package initialization
 
@@ -38,39 +84,28 @@ func Task() *ir.Name {
                deps = append(deps, n.(*ir.Name).Linksym())
        }
 
-       // Make a function that contains all the initialization statements.
-       if len(nf) > 0 {
-               base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
-               initializers := typecheck.Lookup("init")
-               fn := typecheck.DeclFunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
-               for _, dcl := range typecheck.InitTodoFunc.Dcl {
-                       dcl.Curfn = fn
-               }
-               fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
-               typecheck.InitTodoFunc.Dcl = nil
-
-               fn.Body = nf
-               typecheck.FinishFuncBody()
-
-               typecheck.Func(fn)
-               ir.CurFunc = fn
-               typecheck.Stmts(nf)
-               ir.CurFunc = nil
-               typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
-               fns = append(fns, fn.Linksym())
-       }
-       if typecheck.InitTodoFunc.Dcl != nil {
-               // We only generate temps using InitTodoFunc if there
-               // are package-scope initialization statements, so
-               // something's weird if we get here.
-               base.Fatalf("InitTodoFunc still has declarations")
-       }
-       typecheck.InitTodoFunc = nil
-
        // Record user init functions.
        for _, fn := range typecheck.Target.Inits {
-               // Must happen after initOrder; see #43444.
-               deadcode.Func(fn)
+               if fn.Sym().Name == "init" {
+                       // Synthetic init function for initialization of package-scope
+                       // variables. We can use staticinit to optimize away static
+                       // assignments.
+                       s := staticinit.Schedule{
+                               Plans: make(map[ir.Node]*staticinit.Plan),
+                               Temps: make(map[ir.Node]*ir.Name),
+                       }
+                       for _, n := range fn.Body {
+                               s.StaticInit(n)
+                       }
+                       fn.Body = s.Out
+                       ir.WithFunc(fn, func() {
+                               typecheck.Stmts(fn.Body)
+                       })
+
+                       if len(fn.Body) == 0 {
+                               fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
+                       }
+               }
 
                // Skip init functions with empty bodies.
                if len(fn.Body) == 1 {
index 0aad63a69f6b05fa6c9a41a5c5fb65d9cf092d16..a50975343fbced39fdd911c769575e0ceff8edb1 100644 (file)
@@ -11,7 +11,6 @@ import (
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
-       "cmd/compile/internal/staticinit"
 )
 
 // Package initialization
@@ -78,10 +77,7 @@ type InitOrder struct {
 // corresponding list of statements to include in the init() function
 // body.
 func initOrder(l []ir.Node) []ir.Node {
-       s := staticinit.Schedule{
-               Plans: make(map[ir.Node]*staticinit.Plan),
-               Temps: make(map[ir.Node]*ir.Name),
-       }
+       var res ir.Nodes
        o := InitOrder{
                blocking: make(map[ir.Node][]ir.Node),
                order:    make(map[ir.Node]int),
@@ -92,7 +88,7 @@ func initOrder(l []ir.Node) []ir.Node {
                switch n.Op() {
                case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
                        o.processAssign(n)
-                       o.flushReady(s.StaticInit)
+                       o.flushReady(func(n ir.Node) { res.Append(n) })
                case ir.ODCLCONST, ir.ODCLFUNC, ir.ODCLTYPE:
                        // nop
                default:
@@ -125,7 +121,7 @@ func initOrder(l []ir.Node) []ir.Node {
                base.Fatalf("expected empty map: %v", o.blocking)
        }
 
-       return s.Out
+       return res
 }
 
 func (o *InitOrder) processAssign(n ir.Node) {
index bff3e38f42dfef97e9b7013ffa1f93cbbfb568f6..6f9d1407d669d9ccbb2f8f2bdc2b5dd2d4eec8f0 100644 (file)
@@ -24,4 +24,6 @@ func Init(arch *ssagen.ArchInfo) {
        arch.SSAMarkMoves = ssaMarkMoves
        arch.SSAGenValue = ssaGenValue
        arch.SSAGenBlock = ssaGenBlock
+       arch.LoadRegResult = loadRegResult
+       arch.SpillArgReg = spillArgReg
 }
index 11226f65a0f01639359fe2992e2f266b2301be20..98316c16fab7f9b6756fa7c0cadd6f1e891c3af3 100644 (file)
@@ -8,6 +8,7 @@ import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
+       "cmd/compile/internal/objw"
        "cmd/compile/internal/ssa"
        "cmd/compile/internal/ssagen"
        "cmd/compile/internal/types"
@@ -502,6 +503,20 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.From.Reg = v.Args[0].Reg()
                ssagen.AddrAuto(&p.To, v)
 
+       case ssa.OpArgIntReg, ssa.OpArgFloatReg:
+               // The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
+               // The loop only runs once.
+               for _, a := range v.Block.Func.RegArgs {
+                       // Pass the spill/unspill information along to the assembler, offset by size of
+                       // the saved LR slot.
+                       addr := ssagen.SpillSlotAddr(a, ppc64.REGSP, base.Ctxt.FixedFrameSize())
+                       s.FuncInfo().AddSpill(
+                               obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
+               }
+               v.Block.Func.RegArgs = nil
+
+               ssagen.CheckArgReg(v)
+
        case ssa.OpPPC64DIVD:
                // For now,
                //
@@ -886,6 +901,13 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Type = obj.TYPE_REG
                p.To.Reg = v.Reg()
 
+       case ssa.OpPPC64DCBT:
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_MEM
+               p.From.Reg = v.Args[0].Reg()
+               p.To.Type = obj.TYPE_CONST
+               p.To.Offset = v.AuxInt
+
        case ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero:
                p := s.Prog(v.Op.Asm())
                p.From.Type = obj.TYPE_REG
@@ -1829,6 +1851,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
        case ssa.OpPPC64CALLstatic:
                s.Call(v)
 
+       case ssa.OpPPC64CALLtail:
+               s.TailCall(v)
+
        case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
                p := s.Prog(ppc64.AMOVD)
                p.From.Type = obj.TYPE_REG
@@ -1980,14 +2005,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        p.To.Type = obj.TYPE_BRANCH
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
        case ssa.BlockRet:
                s.Prog(obj.ARET)
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.AJMP)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
 
        case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
                ssa.BlockPPC64LT, ssa.BlockPPC64GE,
@@ -2027,3 +2047,22 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                b.Fatalf("branch not implemented: %s", b.LongString())
        }
 }
+
+func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
+       p := s.Prog(loadByType(t))
+       p.From.Type = obj.TYPE_MEM
+       p.From.Name = obj.NAME_AUTO
+       p.From.Sym = n.Linksym()
+       p.From.Offset = n.FrameOffset() + off
+       p.To.Type = obj.TYPE_REG
+       p.To.Reg = reg
+       return p
+}
+
+func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
+       p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
+       p.To.Name = obj.NAME_PARAM
+       p.To.Sym = n.Linksym()
+       p.Pos = p.Pos.WithNotStmt()
+       return p
+}
index 36ad389647ff984c4f7fa026644ea60a8aad47fd..d000618bd64f576153f24335ddfa31a30dabfb21 100644 (file)
@@ -48,12 +48,12 @@ func eqCanPanic(t *types.Type) bool {
 func AlgType(t *types.Type) types.AlgKind {
        a, _ := types.AlgType(t)
        if a == types.AMEM {
-               if t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Width {
+               if t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Size() {
                        // For example, we can't treat [2]int16 as an int32 if int32s require
                        // 4-byte alignment. See issue 46283.
                        return a
                }
-               switch t.Width {
+               switch t.Size() {
                case 0:
                        return types.AMEM0
                case 1:
@@ -110,7 +110,7 @@ func genhash(t *types.Type) *obj.LSym {
                // For other sizes of plain memory, we build a closure
                // that calls memhash_varlen. The size of the memory is
                // encoded in the first slot of the closure.
-               closure := TypeLinksymLookup(fmt.Sprintf(".hashfunc%d", t.Width))
+               closure := TypeLinksymLookup(fmt.Sprintf(".hashfunc%d", t.Size()))
                if len(closure.P) > 0 { // already generated
                        return closure
                }
@@ -119,7 +119,7 @@ func genhash(t *types.Type) *obj.LSym {
                }
                ot := 0
                ot = objw.SymPtr(closure, ot, memhashvarlen, 0)
-               ot = objw.Uintptr(closure, ot, uint64(t.Width)) // size encoded in closure
+               ot = objw.Uintptr(closure, ot, uint64(t.Size())) // size encoded in closure
                objw.Global(closure, int32(ot), obj.DUPOK|obj.RODATA)
                return closure
        case types.ASPECIAL:
@@ -354,7 +354,7 @@ func geneq(t *types.Type) *obj.LSym {
        case types.AMEM:
                // make equality closure. The size of the type
                // is encoded in the closure.
-               closure := TypeLinksymLookup(fmt.Sprintf(".eqfunc%d", t.Width))
+               closure := TypeLinksymLookup(fmt.Sprintf(".eqfunc%d", t.Size()))
                if len(closure.P) != 0 {
                        return closure
                }
@@ -363,7 +363,7 @@ func geneq(t *types.Type) *obj.LSym {
                }
                ot := 0
                ot = objw.SymPtr(closure, ot, memequalvarlen, 0)
-               ot = objw.Uintptr(closure, ot, uint64(t.Width))
+               ot = objw.Uintptr(closure, ot, uint64(t.Size()))
                objw.Global(closure, int32(ot), obj.DUPOK|obj.RODATA)
                return closure
        case types.ASPECIAL:
index 74907fca28cc7b00a34845c899da92bf7edf0b02..0d3070fd39c6d3e576afa74dcc3d6270d61cdd5c 100644 (file)
@@ -7,7 +7,6 @@ package reflectdata
 import (
        "encoding/binary"
        "fmt"
-       "internal/buildcfg"
        "os"
        "sort"
        "strings"
@@ -19,6 +18,7 @@ import (
        "cmd/compile/internal/inline"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/objw"
+       "cmd/compile/internal/staticdata"
        "cmd/compile/internal/typebits"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
@@ -39,9 +39,12 @@ func CountPTabs() int {
 
 // runtime interface and reflection data structures
 var (
-       signatmu    sync.Mutex // protects signatset and signatslice
-       signatset   = make(map[*types.Type]struct{})
-       signatslice []*types.Type
+       // protects signatset and signatslice
+       signatmu sync.Mutex
+       // Tracking which types need runtime type descriptor
+       signatset = make(map[*types.Type]struct{})
+       // Queue of types wait to be generated runtime type descriptor
+       signatslice []typeAndStr
 
        gcsymmu  sync.Mutex // protects gcsymset and gcsymslice
        gcsymset = make(map[*types.Type]struct{})
@@ -94,10 +97,10 @@ func MapBucketType(t *types.Type) *types.Type {
        elemtype := t.Elem()
        types.CalcSize(keytype)
        types.CalcSize(elemtype)
-       if keytype.Width > MAXKEYSIZE {
+       if keytype.Size() > MAXKEYSIZE {
                keytype = types.NewPtr(keytype)
        }
-       if elemtype.Width > MAXELEMSIZE {
+       if elemtype.Size() > MAXELEMSIZE {
                elemtype = types.NewPtr(elemtype)
        }
 
@@ -142,46 +145,46 @@ func MapBucketType(t *types.Type) *types.Type {
        if BUCKETSIZE < 8 {
                base.Fatalf("bucket size too small for proper alignment")
        }
-       if keytype.Align > BUCKETSIZE {
+       if uint8(keytype.Alignment()) > BUCKETSIZE {
                base.Fatalf("key align too big for %v", t)
        }
-       if elemtype.Align > BUCKETSIZE {
+       if uint8(elemtype.Alignment()) > BUCKETSIZE {
                base.Fatalf("elem align too big for %v", t)
        }
-       if keytype.Width > MAXKEYSIZE {
+       if keytype.Size() > MAXKEYSIZE {
                base.Fatalf("key size to large for %v", t)
        }
-       if elemtype.Width > MAXELEMSIZE {
+       if elemtype.Size() > MAXELEMSIZE {
                base.Fatalf("elem size to large for %v", t)
        }
-       if t.Key().Width > MAXKEYSIZE && !keytype.IsPtr() {
+       if t.Key().Size() > MAXKEYSIZE && !keytype.IsPtr() {
                base.Fatalf("key indirect incorrect for %v", t)
        }
-       if t.Elem().Width > MAXELEMSIZE && !elemtype.IsPtr() {
+       if t.Elem().Size() > MAXELEMSIZE && !elemtype.IsPtr() {
                base.Fatalf("elem indirect incorrect for %v", t)
        }
-       if keytype.Width%int64(keytype.Align) != 0 {
+       if keytype.Size()%keytype.Alignment() != 0 {
                base.Fatalf("key size not a multiple of key align for %v", t)
        }
-       if elemtype.Width%int64(elemtype.Align) != 0 {
+       if elemtype.Size()%elemtype.Alignment() != 0 {
                base.Fatalf("elem size not a multiple of elem align for %v", t)
        }
-       if bucket.Align%keytype.Align != 0 {
+       if uint8(bucket.Alignment())%uint8(keytype.Alignment()) != 0 {
                base.Fatalf("bucket align not multiple of key align %v", t)
        }
-       if bucket.Align%elemtype.Align != 0 {
+       if uint8(bucket.Alignment())%uint8(elemtype.Alignment()) != 0 {
                base.Fatalf("bucket align not multiple of elem align %v", t)
        }
-       if keys.Offset%int64(keytype.Align) != 0 {
+       if keys.Offset%keytype.Alignment() != 0 {
                base.Fatalf("bad alignment of keys in bmap for %v", t)
        }
-       if elems.Offset%int64(elemtype.Align) != 0 {
+       if elems.Offset%elemtype.Alignment() != 0 {
                base.Fatalf("bad alignment of elems in bmap for %v", t)
        }
 
        // Double-check that overflow field is final memory in struct,
        // with no padding at end.
-       if overflow.Offset != bucket.Width-int64(types.PtrSize) {
+       if overflow.Offset != bucket.Size()-int64(types.PtrSize) {
                base.Fatalf("bad offset of overflow in bmap for %v", t)
        }
 
@@ -231,8 +234,8 @@ func MapType(t *types.Type) *types.Type {
 
        // The size of hmap should be 48 bytes on 64 bit
        // and 28 bytes on 32 bit platforms.
-       if size := int64(8 + 5*types.PtrSize); hmap.Width != size {
-               base.Fatalf("hmap size not correct: got %d, want %d", hmap.Width, size)
+       if size := int64(8 + 5*types.PtrSize); hmap.Size() != size {
+               base.Fatalf("hmap size not correct: got %d, want %d", hmap.Size(), size)
        }
 
        t.MapType().Hmap = hmap
@@ -291,8 +294,8 @@ func MapIterType(t *types.Type) *types.Type {
        hiter := types.NewStruct(types.NoPkg, fields)
        hiter.SetNoalg(true)
        types.CalcSize(hiter)
-       if hiter.Width != int64(12*types.PtrSize) {
-               base.Fatalf("hash_iter size not correct %d %d", hiter.Width, 12*types.PtrSize)
+       if hiter.Size() != int64(12*types.PtrSize) {
+               base.Fatalf("hash_iter size not correct %d %d", hiter.Size(), 12*types.PtrSize)
        }
        t.MapType().Hiter = hiter
        hiter.StructType().Map = t
@@ -327,7 +330,11 @@ func methods(t *types.Type) []*typeSig {
                if f.Type.Recv() == nil {
                        base.Fatalf("receiver with no type on %v method %v %v", mt, f.Sym, f)
                }
-               if f.Nointerface() {
+               if f.Nointerface() && !t.IsFullyInstantiated() {
+                       // Skip creating method wrappers if f is nointerface. But, if
+                       // t is an instantiated type, we still have to call
+                       // methodWrapper, because methodWrapper generates the actual
+                       // generic method on the type as well.
                        continue
                }
 
@@ -346,6 +353,11 @@ func methods(t *types.Type) []*typeSig {
                        type_: typecheck.NewMethodType(f.Type, t),
                        mtype: typecheck.NewMethodType(f.Type, nil),
                }
+               if f.Nointerface() {
+                       // In the case of a nointerface method on an instantiated
+                       // type, don't actually apppend the typeSig.
+                       continue
+               }
                ms = append(ms, sig)
        }
 
@@ -705,7 +717,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
        //              ptrToThis     typeOff
        //      }
        ot := 0
-       ot = objw.Uintptr(lsym, ot, uint64(t.Width))
+       ot = objw.Uintptr(lsym, ot, uint64(t.Size()))
        ot = objw.Uintptr(lsym, ot, uint64(ptrdata))
        ot = objw.Uint32(lsym, ot, types.TypeHash(t))
 
@@ -742,16 +754,16 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
        ot = objw.Uint8(lsym, ot, tflag)
 
        // runtime (and common sense) expects alignment to be a power of two.
-       i := int(t.Align)
+       i := int(uint8(t.Alignment()))
 
        if i == 0 {
                i = 1
        }
        if i&(i-1) != 0 {
-               base.Fatalf("invalid alignment %d for %v", t.Align, t)
+               base.Fatalf("invalid alignment %d for %v", uint8(t.Alignment()), t)
        }
-       ot = objw.Uint8(lsym, ot, t.Align) // align
-       ot = objw.Uint8(lsym, ot, t.Align) // fieldAlign
+       ot = objw.Uint8(lsym, ot, uint8(t.Alignment())) // align
+       ot = objw.Uint8(lsym, ot, uint8(t.Alignment())) // fieldAlign
 
        i = kinds[t.Kind()]
        if types.IsDirectIface(t) {
@@ -924,7 +936,7 @@ func formalType(t *types.Type) *types.Type {
 
 func writeType(t *types.Type) *obj.LSym {
        t = formalType(t)
-       if t.IsUntyped() {
+       if t.IsUntyped() || t.HasTParam() {
                base.Fatalf("writeType %v", t)
        }
 
@@ -947,11 +959,6 @@ func writeType(t *types.Type) *obj.LSym {
                base.Fatalf("unresolved defined type: %v", tbase)
        }
 
-       dupok := 0
-       if tbase.Sym() == nil || tbase.HasShape() { // TODO(mdempsky): Probably need DUPOK for instantiated types too.
-               dupok = obj.DUPOK
-       }
-
        if !NeedEmit(tbase) {
                if i := typecheck.BaseTypeIndex(t); i >= 0 {
                        lsym.Pkg = tbase.Sym().Pkg.Prefix
@@ -1087,20 +1094,20 @@ func writeType(t *types.Type) *obj.LSym {
                var flags uint32
                // Note: flags must match maptype accessors in ../../../../runtime/type.go
                // and maptype builder in ../../../../reflect/type.go:MapOf.
-               if t.Key().Width > MAXKEYSIZE {
+               if t.Key().Size() > MAXKEYSIZE {
                        ot = objw.Uint8(lsym, ot, uint8(types.PtrSize))
                        flags |= 1 // indirect key
                } else {
-                       ot = objw.Uint8(lsym, ot, uint8(t.Key().Width))
+                       ot = objw.Uint8(lsym, ot, uint8(t.Key().Size()))
                }
 
-               if t.Elem().Width > MAXELEMSIZE {
+               if t.Elem().Size() > MAXELEMSIZE {
                        ot = objw.Uint8(lsym, ot, uint8(types.PtrSize))
                        flags |= 2 // indirect value
                } else {
-                       ot = objw.Uint8(lsym, ot, uint8(t.Elem().Width))
+                       ot = objw.Uint8(lsym, ot, uint8(t.Elem().Size()))
                }
-               ot = objw.Uint16(lsym, ot, uint16(MapBucketType(t).Width))
+               ot = objw.Uint16(lsym, ot, uint16(MapBucketType(t).Size()))
                if types.IsReflexive(t.Key()) {
                        flags |= 4 // reflexive key
                }
@@ -1211,7 +1218,9 @@ func writeType(t *types.Type) *obj.LSym {
        }
 
        ot = dextratypeData(lsym, ot, t)
-       objw.Global(lsym, int32(ot), int16(dupok|obj.RODATA))
+       objw.Global(lsym, int32(ot), int16(obj.DUPOK|obj.RODATA))
+       // Note: DUPOK is required to ensure that we don't end up with more
+       // than one type descriptor for a given type.
 
        // The linker will leave a table of all the typelinks for
        // types in the binary, so the runtime can find them.
@@ -1262,22 +1271,16 @@ func NeedRuntimeType(t *types.Type) {
        }
        if _, ok := signatset[t]; !ok {
                signatset[t] = struct{}{}
-               signatslice = append(signatslice, t)
+               signatslice = append(signatslice, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
        }
 }
 
 func WriteRuntimeTypes() {
-       // Process signatset. Use a loop, as writeType adds
-       // entries to signatset while it is being processed.
-       signats := make([]typeAndStr, len(signatslice))
+       // Process signatslice. Use a loop, as writeType adds
+       // entries to signatslice while it is being processed.
        for len(signatslice) > 0 {
-               signats = signats[:0]
-               // Transfer entries to a slice and sort, for reproducible builds.
-               for _, t := range signatslice {
-                       signats = append(signats, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
-                       delete(signatset, t)
-               }
-               signatslice = signatslice[:0]
+               signats := signatslice
+               // Sort for reproducible builds.
                sort.Sort(typesByString(signats))
                for _, ts := range signats {
                        t := ts.t
@@ -1286,6 +1289,7 @@ func WriteRuntimeTypes() {
                                writeType(types.NewPtr(t))
                        }
                }
+               signatslice = signatslice[len(signats):]
        }
 
        // Emit GC data symbols.
@@ -1433,6 +1437,9 @@ func WriteBasicTypes() {
                if base.Flag.MSan {
                        dimportpath(types.NewPkg("runtime/msan", ""))
                }
+               if base.Flag.ASan {
+                       dimportpath(types.NewPkg("runtime/asan", ""))
+               }
 
                dimportpath(types.NewPkg("main", ""))
        }
@@ -1586,7 +1593,7 @@ func fillptrmask(t *types.Type, ptrmask []byte) {
 // For non-trivial arrays, the program describes the full t.Width size.
 func dgcprog(t *types.Type, write bool) (*obj.LSym, int64) {
        types.CalcSize(t)
-       if t.Width == types.BADWIDTH {
+       if t.Size() == types.BADWIDTH {
                base.Fatalf("dgcprog: %v badwidth", t)
        }
        lsym := TypeLinksymPrefix(".gcprog", t)
@@ -1595,8 +1602,8 @@ func dgcprog(t *types.Type, write bool) (*obj.LSym, int64) {
        p.emit(t, 0)
        offset := p.w.BitIndex() * int64(types.PtrSize)
        p.end()
-       if ptrdata := types.PtrDataSize(t); offset < ptrdata || offset > t.Width {
-               base.Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
+       if ptrdata := types.PtrDataSize(t); offset < ptrdata || offset > t.Size() {
+               base.Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Size())
        }
        return lsym, offset
 }
@@ -1645,7 +1652,7 @@ func (p *gcProg) emit(t *types.Type, offset int64) {
        if !t.HasPointers() {
                return
        }
-       if t.Width == int64(types.PtrSize) {
+       if t.Size() == int64(types.PtrSize) {
                p.w.Ptr(offset / int64(types.PtrSize))
                return
        }
@@ -1677,16 +1684,16 @@ func (p *gcProg) emit(t *types.Type, offset int64) {
                        elem = elem.Elem()
                }
 
-               if !p.w.ShouldRepeat(elem.Width/int64(types.PtrSize), count) {
+               if !p.w.ShouldRepeat(elem.Size()/int64(types.PtrSize), count) {
                        // Cheaper to just emit the bits.
                        for i := int64(0); i < count; i++ {
-                               p.emit(elem, offset+i*elem.Width)
+                               p.emit(elem, offset+i*elem.Size())
                        }
                        return
                }
                p.emit(elem, offset)
-               p.w.ZeroUntil((offset + elem.Width) / int64(types.PtrSize))
-               p.w.Repeat(elem.Width/int64(types.PtrSize), count-1)
+               p.w.ZeroUntil((offset + elem.Size()) / int64(types.PtrSize))
+               p.w.Repeat(elem.Size()/int64(types.PtrSize), count-1)
 
        case types.TSTRUCT:
                for _, t1 := range t.Fields().Slice() {
@@ -1755,7 +1762,7 @@ func NeedEmit(typ *types.Type) bool {
                // Local defined type; our responsibility.
                return true
 
-       case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe):
+       case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg):
                // Package runtime is responsible for including code for builtin
                // types (predeclared and package unsafe).
                return true
@@ -1818,19 +1825,13 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
        // We don't need a dictionary if we are reaching a method (possibly via an
        // embedded field) which is an interface method.
        if !types.IsInterfaceMethod(method.Type) {
-               rcvr1 := rcvr
-               if rcvr1.IsPtr() {
-                       rcvr1 = rcvr.Elem()
-               }
+               rcvr1 := deref(rcvr)
                if len(rcvr1.RParams()) > 0 {
                        // If rcvr has rparams, remember method as generic, which
                        // means we need to add a dictionary to the wrapper.
                        generic = true
-                       targs := rcvr1.RParams()
-                       for _, t := range targs {
-                               if t.HasShape() {
-                                       base.Fatalf("method on type instantiated with shapes targ:%+v rcvr:%+v", t, rcvr)
-                               }
+                       if rcvr.HasShape() {
+                               base.Fatalf("method on type instantiated with shapes, rcvr:%+v", rcvr)
                        }
                }
        }
@@ -1847,9 +1848,10 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
                return lsym
        }
 
+       methodrcvr := method.Type.Recv().Type
        // For generic methods, we need to generate the wrapper even if the receiver
        // types are identical, because we want to add the dictionary.
-       if !generic && types.Identical(rcvr, method.Type.Recv().Type) {
+       if !generic && types.Identical(rcvr, methodrcvr) {
                return lsym
        }
 
@@ -1873,7 +1875,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
 
        nthis := ir.AsNode(tfn.Type().Recv().Nname)
 
-       methodrcvr := method.Type.Recv().Type
        indirect := rcvr.IsPtr() && rcvr.Elem() == methodrcvr
 
        // generate nil pointer check for better error
@@ -1894,52 +1895,36 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
        // the TOC to the appropriate value for that module. But if it returns
        // directly to the wrapper's caller, nothing will reset it to the correct
        // value for that function.
-       //
-       // Disable tailcall for RegabiArgs for now. The IR does not connect the
-       // arguments with the OTAILCALL node, and the arguments are not marshaled
-       // correctly.
-       if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !buildcfg.Experiment.RegabiArgs && !generic {
-               // generate tail call: adjust pointer receiver and jump to embedded method.
-               left := dot.X // skip final .M
-               if !left.Type().IsPtr() {
-                       left = typecheck.NodAddr(left)
-               }
-               as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
-               fn.Body.Append(as)
-               fn.Body.Append(ir.NewTailCallStmt(base.Pos, method.Nname.(*ir.Name)))
+       if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !generic {
+               call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
+               call.Args = ir.ParamNames(tfn.Type())
+               call.IsDDD = tfn.Type().IsVariadic()
+               fn.Body.Append(ir.NewTailCallStmt(base.Pos, call))
        } else {
                fn.SetWrapper(true) // ignore frame for panic+recover matching
                var call *ir.CallExpr
 
                if generic && dot.X != nthis {
-                       // TODO: for now, we don't try to generate dictionary wrappers for
-                       // any methods involving embedded fields, because we're not
-                       // generating the needed dictionaries in instantiateMethods.
+                       // If there is embedding involved, then we should do the
+                       // normal non-generic embedding wrapper below, which calls
+                       // the wrapper for the real receiver type using dot as an
+                       // argument. There is no need for generic processing (adding
+                       // a dictionary) for this wrapper.
                        generic = false
                }
 
                if generic {
-                       var args []ir.Node
-                       var targs []*types.Type
-                       if rcvr.IsPtr() {
-                               targs = rcvr.Elem().RParams()
-                       } else {
-                               targs = rcvr.RParams()
-                       }
-                       if strings.HasPrefix(ir.MethodSym(orig, method.Sym).Name, ".inst.") {
-                               fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name)
-                               panic("multiple .inst.")
-                       }
+                       targs := deref(rcvr).RParams()
                        // The wrapper for an auto-generated pointer/non-pointer
                        // receiver method should share the same dictionary as the
                        // corresponding original (user-written) method.
                        baseOrig := orig
-                       if baseOrig.IsPtr() && !method.Type.Recv().Type.IsPtr() {
+                       if baseOrig.IsPtr() && !methodrcvr.IsPtr() {
                                baseOrig = baseOrig.Elem()
-                       } else if !baseOrig.IsPtr() && method.Type.Recv().Type.IsPtr() {
+                       } else if !baseOrig.IsPtr() && methodrcvr.IsPtr() {
                                baseOrig = types.NewPtr(baseOrig)
                        }
-                       args = append(args, getDictionary(ir.MethodSym(baseOrig, method.Sym), targs))
+                       args := []ir.Node{getDictionary(ir.MethodSym(baseOrig, method.Sym), targs)}
                        if indirect {
                                args = append(args, ir.NewStarExpr(base.Pos, dot.X))
                        } else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() {
@@ -1954,11 +1939,11 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
                        // Target method uses shaped names.
                        targs2 := make([]*types.Type, len(targs))
                        for i, t := range targs {
-                               targs2[i] = typecheck.Shapify(t)
+                               targs2[i] = typecheck.Shapify(t, i)
                        }
                        targs = targs2
 
-                       sym := typecheck.MakeInstName(ir.MethodSym(methodrcvr, method.Sym), targs, true)
+                       sym := typecheck.MakeFuncInstSym(ir.MethodSym(methodrcvr, method.Sym), targs, false, true)
                        if sym.Def == nil {
                                // Currently we make sure that we have all the instantiations
                                // we need by generating them all in ../noder/stencil.go:instantiateMethods
@@ -2037,6 +2022,34 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
        }
        dot := n.X.(*ir.SelectorExpr)
        ityp := dot.X.Type()
+       if ityp.HasShape() {
+               // Here we're calling a method on a generic interface. Something like:
+               //
+               // type I[T any] interface { foo() T }
+               // func f[T any](x I[T]) {
+               //     ... = x.foo()
+               // }
+               // f[int](...)
+               // f[string](...)
+               //
+               // In this case, in f we're calling foo on a generic interface.
+               // Which method could that be? Normally we could match the method
+               // both by name and by type. But in this case we don't really know
+               // the type of the method we're calling. It could be func()int
+               // or func()string. So we match on just the function name, instead
+               // of both the name and the type used for the non-generic case below.
+               // TODO: instantiations at least know the shape of the instantiated
+               // type, and the linker could do more complicated matching using
+               // some sort of fuzzy shape matching. For now, only use the name
+               // of the method for matching.
+               r := obj.Addrel(ir.CurFunc.LSym)
+               // We use a separate symbol just to tell the linker the method name.
+               // (The symbol itself is not needed in the final binary.)
+               r.Sym = staticdata.StringSym(src.NoXPos, dot.Sel.Name)
+               r.Type = objabi.R_USEGENERICIFACEMETHOD
+               return
+       }
+
        tsym := TypeLinksym(ityp)
        r := obj.Addrel(ir.CurFunc.LSym)
        r.Sym = tsym
@@ -2047,16 +2060,6 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
        r.Type = objabi.R_USEIFACEMETHOD
 }
 
-// MarkUsedIfaceMethodIndex marks that that method number ix (in the AllMethods list)
-// of interface type ityp is used, and should be attached to lsym.
-func MarkUsedIfaceMethodIndex(lsym *obj.LSym, ityp *types.Type, ix int) {
-       tsym := TypeLinksym(ityp)
-       r := obj.Addrel(lsym)
-       r.Sym = tsym
-       r.Add = InterfaceMethodOffset(ityp, int64(ix))
-       r.Type = objabi.R_USEIFACEMETHOD
-}
-
 // getDictionary returns the dictionary for the given named generic function
 // or method, with the given type arguments.
 func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
@@ -2069,19 +2072,24 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
                }
        }
 
-       sym := typecheck.MakeDictName(gf, targs, true)
+       sym := typecheck.MakeDictSym(gf, targs, true)
 
-       // Initialize the dictionary, if we haven't yet already.
+       // Dictionary should already have been generated by instantiateMethods().
        if lsym := sym.Linksym(); len(lsym.P) == 0 {
                base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
        }
 
-       // Make a node referencing the dictionary symbol.
-       n := typecheck.NewName(sym)
-       n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
-       n.SetTypecheck(1)
-       n.Class = ir.PEXTERN
-       sym.Def = n
+       // Make (or reuse) a node referencing the dictionary symbol.
+       var n *ir.Name
+       if sym.Def != nil {
+               n = sym.Def.(*ir.Name)
+       } else {
+               n = typecheck.NewName(sym)
+               n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
+               n.SetTypecheck(1)
+               n.Class = ir.PEXTERN
+               sym.Def = n
+       }
 
        // Return the address of the dictionary.
        np := typecheck.NodAddr(n)
@@ -2092,3 +2100,10 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
        np.SetTypecheck(1)
        return np
 }
+
+func deref(t *types.Type) *types.Type {
+       if t.IsPtr() {
+               return t.Elem()
+       }
+       return t
+}
index 64a9b3b33b9aca34cfd15284ff14eb765a67d52a..1359b6a0c388b416dbcda35ef746d0c88497ef44 100644 (file)
@@ -272,7 +272,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpRISCV64FADDS, ssa.OpRISCV64FSUBS, ssa.OpRISCV64FMULS, ssa.OpRISCV64FDIVS,
                ssa.OpRISCV64FEQS, ssa.OpRISCV64FNES, ssa.OpRISCV64FLTS, ssa.OpRISCV64FLES,
                ssa.OpRISCV64FADDD, ssa.OpRISCV64FSUBD, ssa.OpRISCV64FMULD, ssa.OpRISCV64FDIVD,
-               ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED:
+               ssa.OpRISCV64FEQD, ssa.OpRISCV64FNED, ssa.OpRISCV64FLTD, ssa.OpRISCV64FLED,
+               ssa.OpRISCV64FSGNJD:
                r := v.Reg()
                r1 := v.Args[0].Reg()
                r2 := v.Args[1].Reg()
@@ -282,7 +283,54 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.Reg = r1
                p.To.Type = obj.TYPE_REG
                p.To.Reg = r
-       case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD,
+       case ssa.OpRISCV64LoweredMuluhilo:
+               r0 := v.Args[0].Reg()
+               r1 := v.Args[1].Reg()
+               p := s.Prog(riscv.AMULHU)
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = r1
+               p.Reg = r0
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = v.Reg0()
+               p1 := s.Prog(riscv.AMUL)
+               p1.From.Type = obj.TYPE_REG
+               p1.From.Reg = r1
+               p1.Reg = r0
+               p1.To.Type = obj.TYPE_REG
+               p1.To.Reg = v.Reg1()
+       case ssa.OpRISCV64LoweredMuluover:
+               r0 := v.Args[0].Reg()
+               r1 := v.Args[1].Reg()
+               p := s.Prog(riscv.AMULHU)
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = r1
+               p.Reg = r0
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = v.Reg1()
+               p1 := s.Prog(riscv.AMUL)
+               p1.From.Type = obj.TYPE_REG
+               p1.From.Reg = r1
+               p1.Reg = r0
+               p1.To.Type = obj.TYPE_REG
+               p1.To.Reg = v.Reg0()
+               p2 := s.Prog(riscv.ASNEZ)
+               p2.From.Type = obj.TYPE_REG
+               p2.From.Reg = v.Reg1()
+               p2.To.Type = obj.TYPE_REG
+               p2.To.Reg = v.Reg1()
+       case ssa.OpRISCV64FMADDD, ssa.OpRISCV64FMSUBD, ssa.OpRISCV64FNMADDD, ssa.OpRISCV64FNMSUBD:
+               r := v.Reg()
+               r1 := v.Args[0].Reg()
+               r2 := v.Args[1].Reg()
+               r3 := v.Args[2].Reg()
+               p := s.Prog(v.Op.Asm())
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = r2
+               p.Reg = r1
+               p.SetRestArgs([]obj.Addr{{Type: obj.TYPE_REG, Reg: r3}})
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = r
+       case ssa.OpRISCV64FSQRTS, ssa.OpRISCV64FNEGS, ssa.OpRISCV64FABSD, ssa.OpRISCV64FSQRTD, ssa.OpRISCV64FNEGD,
                ssa.OpRISCV64FMVSX, ssa.OpRISCV64FMVDX,
                ssa.OpRISCV64FCVTSW, ssa.OpRISCV64FCVTSL, ssa.OpRISCV64FCVTWS, ssa.OpRISCV64FCVTLS,
                ssa.OpRISCV64FCVTDW, ssa.OpRISCV64FCVTDL, ssa.OpRISCV64FCVTWD, ssa.OpRISCV64FCVTLD, ssa.OpRISCV64FCVTDS, ssa.OpRISCV64FCVTSD,
@@ -365,6 +413,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Reg = v.Reg()
        case ssa.OpRISCV64CALLstatic, ssa.OpRISCV64CALLclosure, ssa.OpRISCV64CALLinter:
                s.Call(v)
+       case ssa.OpRISCV64CALLtail:
+               s.TailCall(v)
        case ssa.OpRISCV64LoweredWB:
                p := s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
@@ -677,14 +727,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        p.To.Type = obj.TYPE_BRANCH
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
        case ssa.BlockRet:
                s.Prog(obj.ARET)
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
        case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ,
                ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ,
                ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
index ddc05b36add0fa1b9fd22c3697c12be3b124e6eb..deb6c790069ca29870bbe2a96ba9e6c53725a554 100644 (file)
@@ -556,6 +556,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Reg = v.Reg()
        case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter:
                s.Call(v)
+       case ssa.OpS390XCALLtail:
+               s.TailCall(v)
        case ssa.OpS390XLoweredWB:
                p := s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
@@ -899,17 +901,11 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        s.Br(s390x.ABR, b.Succs[0].Block())
                }
                return
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
                return
        case ssa.BlockRet:
                s.Prog(obj.ARET)
                return
-       case ssa.BlockRetJmp:
-               p := s.Prog(s390x.ABR)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
-               return
        }
 
        // Handle s390x-specific blocks. These blocks all have a
index 71ca774431e33cb99a4344d1aaa6e341a052997a..6ff3188f9b20159bcd71cefd626c1221e03d40ef 100644 (file)
@@ -279,7 +279,8 @@ func (b *Block) AddEdgeTo(c *Block) {
 
 // removePred removes the ith input edge from b.
 // It is the responsibility of the caller to remove
-// the corresponding successor edge.
+// the corresponding successor edge, and adjust any
+// phi values by calling b.removePhiArg(v, i).
 func (b *Block) removePred(i int) {
        n := len(b.Preds) - 1
        if i != n {
@@ -322,6 +323,28 @@ func (b *Block) swapSuccessors() {
        b.Likely *= -1
 }
 
+// removePhiArg removes the ith arg from phi.
+// It must be called after calling b.removePred(i) to
+// adjust the corresponding phi value of the block:
+//
+// b.removePred(i)
+// for _, v := range b.Values {
+//     if v.Op != OpPhi {
+//         continue
+//     }
+//     b.removeArg(v, i)
+// }
+func (b *Block) removePhiArg(phi *Value, i int) {
+       n := len(b.Preds)
+       if numPhiArgs := len(phi.Args); numPhiArgs-1 != n {
+               b.Fatalf("inconsistent state, num predecessors: %d, num phi args: %d", n, numPhiArgs)
+       }
+       phi.Args[i].Uses--
+       phi.Args[i] = phi.Args[n]
+       phi.Args[n] = nil
+       phi.Args = phi.Args[:n]
+}
+
 // LackingPos indicates whether b is a block whose position should be inherited
 // from its successors.  This is true if all the values within it have unreliable positions
 // and if it is "plain", meaning that there is no control flow that is also very likely
index 1d34f8160b1ea50a5b9d30fa7fdbb4e01c0bc393..be5f9e0a8b45454df60cf16b423d5f05347a8775 100644 (file)
@@ -22,7 +22,7 @@ import "cmd/internal/src"
 func branchelim(f *Func) {
        // FIXME: add support for lowering CondSelects on more architectures
        switch f.Config.arch {
-       case "arm64", "amd64", "wasm":
+       case "arm64", "ppc64le", "ppc64", "amd64", "wasm":
                // implemented
        default:
                return
index 969fd96dbf573cf67483a1f740f5880fb5d8940e..28edfd2237d9253c88731c3c6791e2db5700663b 100644 (file)
@@ -66,9 +66,6 @@ func checkFunc(f *Func) {
                        if !b.Controls[0].Type.IsMemory() {
                                f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Controls[0].LongString())
                        }
-                       if b.Aux == nil {
-                               f.Fatalf("retjmp block %s has nil Aux field", b)
-                       }
                case BlockPlain:
                        if len(b.Succs) != 1 {
                                f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
index cd8eba405d5c7bc95fa23175aca1652bde7b13db..f87ea5b893ef7561d06144bea1805232b9185ef4 100644 (file)
@@ -10,9 +10,11 @@ import (
        "fmt"
        "hash/crc32"
        "internal/buildcfg"
+       "io"
        "log"
        "math/rand"
        "os"
+       "path/filepath"
        "regexp"
        "runtime"
        "sort"
@@ -59,7 +61,7 @@ func Compile(f *Func) {
                printFunc(f)
        }
        f.HTMLWriter.WritePhase("start", "start")
-       if BuildDump != "" && BuildDump == f.Name {
+       if BuildDump[f.Name] {
                f.dumpFile("build")
        }
        if checkEnabled {
@@ -163,25 +165,37 @@ func Compile(f *Func) {
        phaseName = ""
 }
 
-// dumpFile creates a file from the phase name and function name
-// Dumping is done to files to avoid buffering huge strings before
-// output.
-func (f *Func) dumpFile(phaseName string) {
+// DumpFileForPhase creates a file from the function name and phase name,
+// warning and returning nil if this is not possible.
+func (f *Func) DumpFileForPhase(phaseName string) io.WriteCloser {
        f.dumpFileSeq++
        fname := fmt.Sprintf("%s_%02d__%s.dump", f.Name, int(f.dumpFileSeq), phaseName)
        fname = strings.Replace(fname, " ", "_", -1)
        fname = strings.Replace(fname, "/", "_", -1)
        fname = strings.Replace(fname, ":", "_", -1)
 
+       if ssaDir := os.Getenv("GOSSADIR"); ssaDir != "" {
+               fname = filepath.Join(ssaDir, fname)
+       }
+
        fi, err := os.Create(fname)
        if err != nil {
                f.Warnl(src.NoXPos, "Unable to create after-phase dump file %s", fname)
-               return
+               return nil
        }
+       return fi
+}
 
-       p := stringFuncPrinter{w: fi}
-       fprintFunc(p, f)
-       fi.Close()
+// dumpFile creates a file from the phase name and function name
+// Dumping is done to files to avoid buffering huge strings before
+// output.
+func (f *Func) dumpFile(phaseName string) {
+       fi := f.DumpFileForPhase(phaseName)
+       if fi != nil {
+               p := stringFuncPrinter{w: fi}
+               fprintFunc(p, f)
+               fi.Close()
+       }
 }
 
 type pass struct {
@@ -224,7 +238,9 @@ var IntrinsicsDisable bool
 var BuildDebug int
 var BuildTest int
 var BuildStats int
-var BuildDump string // name of function to dump after initial build of ssa
+var BuildDump map[string]bool = make(map[string]bool) // names of functions to dump after initial build of ssa
+
+var GenssaDump map[string]bool = make(map[string]bool) // names of functions to dump after ssa has been converted to asm
 
 // PhaseOption sets the specified flag in the specified ssa phase,
 // returning empty string if this was successful or a string explaining
@@ -248,7 +264,7 @@ func PhaseOption(phase, flag string, val int, valString string) string {
        switch phase {
        case "", "help":
                lastcr := 0
-               phasenames := "    check, all, build, intrinsics"
+               phasenames := "    check, all, build, intrinsics, genssa"
                for _, p := range passes {
                        pn := strings.Replace(p.name, " ", "_", -1)
                        if len(pn)+len(phasenames)-lastcr > 70 {
@@ -278,6 +294,7 @@ where:
 
 Phase "all" supports flags "time", "mem", and "dump".
 Phase "intrinsics" supports flags "on", "off", and "debug".
+Phase "genssa" (assembly generation) supports the flag "dump".
 
 If the "dump" flag is specified, the output is written on a file named
 <phase>__<function_name>_<seq>.dump; otherwise it is directed to stdout.
@@ -339,10 +356,11 @@ commas. For example:
                case "dump":
                        alldump = val != 0
                        if alldump {
-                               BuildDump = valString
+                               BuildDump[valString] = true
+                               GenssaDump[valString] = true
                        }
                default:
-                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option (expected ssa/all/{time,mem,dump=function_name})", flag, phase)
                }
        }
 
@@ -355,7 +373,7 @@ commas. For example:
                case "debug":
                        IntrinsicsDebug = val
                default:
-                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option (expected ssa/intrinsics/{on,off,debug})", flag, phase)
                }
                return ""
        }
@@ -368,9 +386,18 @@ commas. For example:
                case "stats":
                        BuildStats = val
                case "dump":
-                       BuildDump = valString
+                       BuildDump[valString] = true
+               default:
+                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option (expected ssa/build/{debug,test,stats,dump=function_name})", flag, phase)
+               }
+               return ""
+       }
+       if phase == "genssa" {
+               switch flag {
+               case "dump":
+                       GenssaDump[valString] = true
                default:
-                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+                       return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option (expected ssa/genssa/dump=function_name)", flag, phase)
                }
                return ""
        }
index 32e3a0860e3dadc9417063665566082e824a021c..5ab7240acf683da59192ba04fc91c12770bfe664 100644 (file)
@@ -239,9 +239,10 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
                c.registers = registersPPC64[:]
                c.gpRegMask = gpRegMaskPPC64
                c.fpRegMask = fpRegMaskPPC64
+               c.intParamRegs = paramIntRegPPC64
+               c.floatParamRegs = paramFloatRegPPC64
                c.FPReg = framepointerRegPPC64
                c.LinkReg = linkRegPPC64
-               c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
                c.hasGReg = true
        case "mips64":
                c.BigEndian = true
index b85721eba488323fa1ce39c6aeb8707157f4e832..500ce3ae61ce093de51b3c703160d042db2121ca 100644 (file)
@@ -91,14 +91,13 @@ func critical(f *Func) {
                                b.removePred(i)
 
                                // Update corresponding phi args
-                               n := len(b.Preds)
-                               phi.Args[i].Uses--
-                               phi.Args[i] = phi.Args[n]
-                               phi.Args[n] = nil
-                               phi.Args = phi.Args[:n]
+                               b.removePhiArg(phi, i)
+
                                // splitting occasionally leads to a phi having
                                // a single argument (occurs with -N)
-                               if n == 1 {
+                               // TODO(cuonglm,khr): replace this with phielimValue, and
+                               //                    make removePhiArg incorporates that.
+                               if len(b.Preds) == 1 {
                                        phi.Op = OpCopy
                                }
                                // Don't increment i in this case because we moved
index 5d10dfe025e97ccd2dcad6af9500eeb04f7df40f..b47b106975ac13f36b4b14784019dcdd1f673cf1 100644 (file)
@@ -348,15 +348,11 @@ func (b *Block) removeEdge(i int) {
        c.removePred(j)
 
        // Remove phi args from c's phis.
-       n := len(c.Preds)
        for _, v := range c.Values {
                if v.Op != OpPhi {
                        continue
                }
-               v.Args[j].Uses--
-               v.Args[j] = v.Args[n]
-               v.Args[n] = nil
-               v.Args = v.Args[:n]
+               c.removePhiArg(v, j)
                phielimValue(v)
                // Note: this is trickier than it looks. Replacing
                // a Phi with a Copy can in general cause problems because
index 8e2872363b6edbceaa5a3c1c00c396569092b9bc..e78eb5c0e4b6868010b104c4660a841082730f72 100644 (file)
@@ -378,7 +378,7 @@ func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) {
                split, _ = sc.lookup(*ls.SplitOf)
        }
        k := slotKey{
-               name: ls.N, offset: ls.Off, width: ls.Type.Width,
+               name: ls.N, offset: ls.Off, width: ls.Type.Size(),
                splitOf: split, splitOffset: ls.SplitOffset,
        }
        if idx, ok := sc.slmap[k]; ok {
@@ -1649,7 +1649,7 @@ func BuildFuncDebugNoOptimized(ctxt *obj.Link, f *Func, loggingEnabled bool, sta
                        }
                        if len(inp.Registers) > 1 {
                                list = append(list, dwarf.DW_OP_piece)
-                               ts := rtypes[k].Width
+                               ts := rtypes[k].Size()
                                list = dwarf.AppendUleb128(list, uint64(ts))
                                if padding[k] > 0 {
                                        if loggingEnabled {
diff --git a/src/cmd/compile/internal/ssa/debug_lines_test.go b/src/cmd/compile/internal/ssa/debug_lines_test.go
new file mode 100644 (file)
index 0000000..da04e5b
--- /dev/null
@@ -0,0 +1,208 @@
+// Copyright 2021 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_test
+
+import (
+       "bufio"
+       "bytes"
+       "flag"
+       "runtime"
+       "sort"
+
+       // "flag"
+       "fmt"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "reflect"
+       "regexp"
+       "strconv"
+       "testing"
+)
+
+// Matches lines in genssa output that are marked "isstmt", and the parenthesized plus-prefixed line number is a submatch
+var asmLine *regexp.Regexp = regexp.MustCompile(`^\s[vb][0-9]+\s+[0-9]+\s\(\+([0-9]+)\)`)
+
+// this matches e.g.                            `   v123456789   000007   (+9876654310) MOVUPS X15, ""..autotmp_2-32(SP)`
+
+// Matches lines in genssa output that describe an inlined file.
+// Note it expects an unadventurous choice of basename.
+var sepRE = regexp.QuoteMeta(string(filepath.Separator))
+var inlineLine *regexp.Regexp = regexp.MustCompile(`^#\s.*` + sepRE + `[-a-zA-Z0-9_]+\.go:([0-9]+)`)
+
+// this matches e.g.                                 #  /pa/inline-dumpxxxx.go:6
+
+var testGoArchFlag = flag.String("arch", "", "run test for specified architecture")
+
+func testGoArch() string {
+       if *testGoArchFlag == "" {
+               return runtime.GOARCH
+       }
+       return *testGoArchFlag
+}
+
+func TestDebugLines(t *testing.T) {
+       // This test is potentially fragile, the goal is that debugging should step properly through "sayhi"
+       // If the blocks are reordered in a way that changes the statement order but execution flows correctly,
+       // then rearrange the expected numbers.  Register abi and not-register-abi also have different sequences,
+       // at least for now.
+
+       switch testGoArch() {
+       case "arm64", "amd64": // register ABI
+               testDebugLines(t, "sayhi.go", "sayhi", []int{8, 9, 10, 11})
+
+       case "arm", "386": // probably not register ABI for a while
+               testDebugLines(t, "sayhi.go", "sayhi", []int{9, 10, 11})
+
+       default: // expect ppc64le and riscv will pick up register ABI soonish, not sure about others
+               t.Skip("skipped for many architectures, also changes w/ register ABI")
+       }
+}
+
+func TestInlineLines(t *testing.T) {
+       if runtime.GOARCH != "amd64" && *testGoArchFlag == "" {
+               // As of september 2021, works for everything except mips64, but still potentially fragile
+               t.Skip("only runs for amd64 unless -arch explicitly supplied")
+       }
+
+       want := [][]int{{3}, {4, 10}, {4, 10, 16}, {4, 10}, {4, 11, 16}, {4, 11}, {4}, {5, 10}, {5, 10, 16}, {5, 10}, {5, 11, 16}, {5, 11}, {5}}
+       testInlineStack(t, "inline-dump.go", "f", want)
+}
+
+func compileAndDump(t *testing.T, file, function, moreGCFlags string) []byte {
+       testenv.MustHaveGoBuild(t)
+
+       tmpdir, err := ioutil.TempDir("", "debug_lines_test")
+       if err != nil {
+               panic(fmt.Sprintf("Problem creating TempDir, error %v", err))
+       }
+       if testing.Verbose() {
+               fmt.Printf("Preserving temporary directory %s\n", tmpdir)
+       } else {
+               defer os.RemoveAll(tmpdir)
+       }
+
+       source, err := filepath.Abs(filepath.Join("testdata", file))
+       if err != nil {
+               panic(fmt.Sprintf("Could not get abspath of testdata directory and file, %v", err))
+       }
+
+       cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "foo.o", "-gcflags=-d=ssa/genssa/dump="+function+" "+moreGCFlags, source)
+       cmd.Dir = tmpdir
+       cmd.Env = replaceEnv(cmd.Env, "GOSSADIR", tmpdir)
+       testGoos := "linux" // default to linux
+       if testGoArch() == "wasm" {
+               testGoos = "js"
+       }
+       cmd.Env = replaceEnv(cmd.Env, "GOOS", testGoos)
+       cmd.Env = replaceEnv(cmd.Env, "GOARCH", testGoArch())
+
+       if testing.Verbose() {
+               fmt.Printf("About to run %s\n", asCommandLine("", cmd))
+       }
+
+       var stdout, stderr bytes.Buffer
+       cmd.Stdout = &stdout
+       cmd.Stderr = &stderr
+
+       if err := cmd.Run(); err != nil {
+               t.Fatalf("error running cmd %s: %v\nstdout:\n%sstderr:\n%s\n", asCommandLine("", cmd), err, stdout.String(), stderr.String())
+       }
+
+       if s := stderr.String(); s != "" {
+               t.Fatalf("Wanted empty stderr, instead got:\n%s\n", s)
+       }
+
+       dumpFile := filepath.Join(tmpdir, function+"_01__genssa.dump")
+       dumpBytes, err := os.ReadFile(dumpFile)
+       if err != nil {
+               t.Fatalf("Could not read dump file %s, err=%v", dumpFile, err)
+       }
+       return dumpBytes
+}
+
+func sortInlineStacks(x [][]int) {
+       sort.Slice(x, func(i, j int) bool {
+               if len(x[i]) != len(x[j]) {
+                       return len(x[i]) < len(x[j])
+               }
+               for k := range x[i] {
+                       if x[i][k] != x[j][k] {
+                               return x[i][k] < x[j][k]
+                       }
+               }
+               return false
+       })
+}
+
+// testInlineStack ensures that inlining is described properly in the comments in the dump file
+func testInlineStack(t *testing.T, file, function string, wantStacks [][]int) {
+       // this is an inlining reporting test, not an optimization test.  -N makes it less fragile
+       dumpBytes := compileAndDump(t, file, function, "-N")
+       dump := bufio.NewScanner(bytes.NewReader(dumpBytes))
+       dumpLineNum := 0
+       var gotStmts []int
+       var gotStacks [][]int
+       for dump.Scan() {
+               line := dump.Text()
+               dumpLineNum++
+               matches := inlineLine.FindStringSubmatch(line)
+               if len(matches) == 2 {
+                       stmt, err := strconv.ParseInt(matches[1], 10, 32)
+                       if err != nil {
+                               t.Fatalf("Expected to parse a line number but saw %s instead on dump line #%d, error %v", matches[1], dumpLineNum, err)
+                       }
+                       if testing.Verbose() {
+                               fmt.Printf("Saw stmt# %d for submatch '%s' on dump line #%d = '%s'\n", stmt, matches[1], dumpLineNum, line)
+                       }
+                       gotStmts = append(gotStmts, int(stmt))
+               } else if len(gotStmts) > 0 {
+                       gotStacks = append(gotStacks, gotStmts)
+                       gotStmts = nil
+               }
+       }
+       if len(gotStmts) > 0 {
+               gotStacks = append(gotStacks, gotStmts)
+               gotStmts = nil
+       }
+       sortInlineStacks(gotStacks)
+       sortInlineStacks(wantStacks)
+       if !reflect.DeepEqual(wantStacks, gotStacks) {
+               t.Errorf("wanted inlines %+v but got %+v", wantStacks, gotStacks)
+       }
+
+}
+
+// testDebugLines compiles testdata/<file> with flags -N -l and -d=ssa/genssa/dump=<function>
+// then verifies that the statement-marked lines in that file are the same as those in wantStmts
+// These files must all be short because this is super-fragile.
+// "go build" is run in a temporary directory that is normally deleted, unless -test.v
+func testDebugLines(t *testing.T, file, function string, wantStmts []int) {
+       dumpBytes := compileAndDump(t, file, function, "-N -l")
+       dump := bufio.NewScanner(bytes.NewReader(dumpBytes))
+       var gotStmts []int
+       dumpLineNum := 0
+       for dump.Scan() {
+               line := dump.Text()
+               dumpLineNum++
+               matches := asmLine.FindStringSubmatch(line)
+               if len(matches) == 2 {
+                       stmt, err := strconv.ParseInt(matches[1], 10, 32)
+                       if err != nil {
+                               t.Fatalf("Expected to parse a line number but saw %s instead on dump line #%d, error %v", matches[1], dumpLineNum, err)
+                       }
+                       if testing.Verbose() {
+                               fmt.Printf("Saw stmt# %d for submatch '%s' on dump line #%d = '%s'\n", stmt, matches[1], dumpLineNum, line)
+                       }
+                       gotStmts = append(gotStmts, int(stmt))
+               }
+       }
+       if !reflect.DeepEqual(wantStmts, gotStmts) {
+               t.Errorf("wanted stmts %v but got %v", wantStmts, gotStmts)
+       }
+
+}
index 33463125424f27b8185ca2c7cd392894cdedf4cf..b20041c1b575a02926aefcf591c5993fe16c349a 100644 (file)
@@ -952,6 +952,9 @@ func (s *ioState) readSimpleExpecting(expectedRE string) tstring {
 // replaceEnv returns a new environment derived from env
 // by removing any existing definition of ev and adding ev=evv.
 func replaceEnv(env []string, ev string, evv string) []string {
+       if env == nil {
+               env = os.Environ()
+       }
        evplus := ev + "="
        var found bool
        for i, v := range env {
index a8c6c26dadc0eea1e0a7c8952727ddacf0d5dbc6..91ff9f87f93107e81dac562a63898845505b4041 100644 (file)
@@ -24,7 +24,7 @@ type selKey struct {
 type Abi1RO uint8 // An offset within a parameter's slice of register indices, for abi1.
 
 func isBlockMultiValueExit(b *Block) bool {
-       return (b.Kind == BlockRet || b.Kind == BlockRetJmp) && len(b.Controls) > 0 && b.Controls[0].Op == OpMakeResult
+       return (b.Kind == BlockRet || b.Kind == BlockRetJmp) && b.Controls[0] != nil && b.Controls[0].Op == OpMakeResult
 }
 
 func badVal(s string, v *Value) error {
@@ -176,7 +176,7 @@ func (c *registerCursor) hasRegs() bool {
 type expandState struct {
        f                  *Func
        abi1               *abi.ABIConfig
-       debug              bool
+       debug              int // odd values log lost statement markers, so likely settings are 1 (stmts), 2 (expansion), and 3 (both)
        canSSAType         func(*types.Type) bool
        regSize            int64
        sp                 *Value
@@ -302,7 +302,7 @@ func (x *expandState) Printf(format string, a ...interface{}) (n int, err error)
 //
 // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
 func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []*LocalSlot {
-       if x.debug {
+       if x.debug > 1 {
                x.indent(3)
                defer x.indent(-3)
                x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset)
@@ -325,7 +325,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
                } else {
                        x.f.Fatalf("Unexpected %s type, selector=%s, leaf=%s\n", selector.Op.String(), selector.LongString(), leaf.LongString())
                }
-               if x.debug {
+               if x.debug > 1 {
                        x.Printf("---%s, break\n", selector.Op.String())
                }
        case OpArg:
@@ -335,7 +335,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
                        } else {
                                x.f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString())
                        }
-                       if x.debug {
+                       if x.debug > 1 {
                                x.Printf("---OpArg, break\n")
                        }
                        break
@@ -381,7 +381,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
                // This case removes that StructSelect.
                if leafType != selector.Type {
                        if x.f.Config.SoftFloat && selector.Type.IsFloat() {
-                               if x.debug {
+                               if x.debug > 1 {
                                        x.Printf("---OpLoad, break\n")
                                }
                                break // softfloat pass will take care of that
@@ -468,7 +468,7 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
                                        } else {
                                                w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call)
                                                leaf.copyOf(w)
-                                               if x.debug {
+                                               if x.debug > 1 {
                                                        x.Printf("---new %s\n", w.LongString())
                                                }
                                        }
@@ -534,8 +534,8 @@ func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64,
                locs = x.splitSlots(ls, ".real", 0, selector.Type)
 
        case OpComplexImag:
-               ls := x.rewriteSelect(leaf, selector.Args[0], offset+selector.Type.Width, regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part.
-               locs = x.splitSlots(ls, ".imag", selector.Type.Width, selector.Type)
+               ls := x.rewriteSelect(leaf, selector.Args[0], offset+selector.Type.Size(), regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part.
+               locs = x.splitSlots(ls, ".imag", selector.Type.Size(), selector.Type)
 
        case OpStringLen, OpSliceLen:
                ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_slice_len)
@@ -616,7 +616,7 @@ outer:
                        }
                        return path
                case types.TINT64, types.TUINT64:
-                       if container.Width == x.regSize {
+                       if container.Size() == x.regSize {
                                return path
                        }
                        if offset == x.hiOffset {
@@ -682,19 +682,19 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t
                        for i := 0; i < len(rts); i++ {
                                rt := rts[i]
                                off := offs[i]
-                               fmt.Printf("rt=%s, off=%d, rt.Width=%d, rt.Align=%d\n", rt.String(), off, rt.Width, rt.Align)
+                               fmt.Printf("rt=%s, off=%d, rt.Width=%d, rt.Align=%d\n", rt.String(), off, rt.Size(), uint8(rt.Alignment()))
                        }
                        panic(fmt.Errorf("offset %d of requested register %d should be zero, source=%s", offs[loadRegOffset], loadRegOffset, source.LongString()))
                }
 
-               if x.debug {
+               if x.debug > 1 {
                        x.Printf("decompose arg %s has %d locs\n", source.LongString(), len(locs))
                }
 
                for i := loadRegOffset; i < last; i++ {
                        rt := rts[i]
                        off := offs[i]
-                       w := x.commonArgs[selKey{source, off, rt.Width, rt}]
+                       w := x.commonArgs[selKey{source, off, rt.Size(), rt}]
                        if w == nil {
                                w = x.newArgToMemOrRegs(source, w, off, i, rt, pos)
                                suffix := x.pathTo(source.Type, rt, off)
@@ -705,7 +705,7 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t
                        if t.IsPtrShaped() {
                                // Preserve the original store type. This ensures pointer type
                                // properties aren't discarded (e.g, notinheap).
-                               if rt.Width != t.Width || len(pa.Registers) != 1 || i != loadRegOffset {
+                               if rt.Size() != t.Size() || len(pa.Registers) != 1 || i != loadRegOffset {
                                        b.Func.Fatalf("incompatible store type %v and %v, i=%d", t, rt, i)
                                }
                                rt = t
@@ -736,7 +736,7 @@ func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t
                }
                return mem
        case types.TINT64, types.TUINT64:
-               if t.Width == x.regSize {
+               if t.Size() == x.regSize {
                        break
                }
                tHi, tLo := x.intPairTypes(t.Kind())
@@ -810,7 +810,7 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value,
                }
                return mem
        case types.TINT64, types.TUINT64:
-               if t.Width == x.regSize {
+               if t.Size() == x.regSize {
                        break
                }
                tHi, tLo := x.intPairTypes(t.Kind())
@@ -836,13 +836,13 @@ func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value,
 // pos and b locate the store instruction, source is the "base" of the value input,
 // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
 func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
-       if x.debug {
+       if x.debug > 1 {
                x.indent(3)
                defer x.indent(-3)
                x.Printf("storeOneArg(%s;  %s;  %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String())
        }
 
-       w := x.commonArgs[selKey{source, argOffset, t.Width, t}]
+       w := x.commonArgs[selKey{source, argOffset, t.Size(), t}]
        if w == nil {
                w = x.newArgToMemOrRegs(source, w, argOffset, loadRegOffset, t, pos)
                x.splitSlotsIntoNames(locs, suffix, argOffset, t, w)
@@ -852,7 +852,7 @@ func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suff
 
 // storeOneLoad creates a decomposed (one step) load that is then stored.
 func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
-       from := x.offsetFrom(b, source.Args[0], offArg, types.NewPtr(t))
+       from := x.offsetFrom(source.Block, source.Args[0], offArg, types.NewPtr(t))
        w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem)
        return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
 }
@@ -877,7 +877,7 @@ func storeTwoLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1
 // stores of non-aggregate types.  It recursively walks up a chain of selectors until it reaches a Load or an Arg.
 // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering.
 func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
-       if x.debug {
+       if x.debug > 1 {
                x.indent(3)
                defer x.indent(-3)
                x.Printf("storeArgOrLoad(%s;  %s;  %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), storeOffset, storeRc.String())
@@ -923,7 +923,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
 
        case OpComplexMake:
                tPart := x.typs.Float32
-               wPart := t.Width / 2
+               wPart := t.Size() / 2
                if wPart == 8 {
                        tPart = x.typs.Float64
                }
@@ -952,22 +952,23 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
        switch t.Kind() {
        case types.TARRAY:
                elt := t.Elem()
-               if source.Type != t && t.NumElem() == 1 && elt.Width == t.Width && t.Width == x.regSize {
+               if source.Type != t && t.NumElem() == 1 && elt.Size() == t.Size() && t.Size() == x.regSize {
                        t = removeTrivialWrapperTypes(t)
+                       source.Type = t
                        // it could be a leaf type, but the "leaf" could be complex64 (for example)
                        return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
                }
                eltRO := x.regWidth(elt)
                for i := int64(0); i < t.NumElem(); i++ {
                        sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
-                       mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Width, loadRegOffset, storeRc.at(t, 0))
+                       mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Size(), loadRegOffset, storeRc.at(t, 0))
                        loadRegOffset += eltRO
                        pos = pos.WithNotStmt()
                }
                return mem
 
        case types.TSTRUCT:
-               if source.Type != t && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == x.regSize {
+               if source.Type != t && t.NumFields() == 1 && t.Field(0).Type.Size() == t.Size() && t.Size() == x.regSize {
                        // This peculiar test deals with accesses to immediate interface data.
                        // It works okay because everything is the same size.
                        // Example code that triggers this can be found in go/constant/value.go, function ToComplex
@@ -987,6 +988,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
                        // v139 is later stored as an intVal == struct{val *big.Int} which naively requires the fields of
                        // of a *uint8, which does not succeed.
                        t = removeTrivialWrapperTypes(t)
+                       source.Type = t
                        // it could be a leaf type, but the "leaf" could be complex64 (for example)
                        return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
                }
@@ -1001,7 +1003,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
                return mem
 
        case types.TINT64, types.TUINT64:
-               if t.Width == x.regSize {
+               if t.Size() == x.regSize {
                        break
                }
                tHi, tLo := x.intPairTypes(t.Kind())
@@ -1060,7 +1062,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
                dst := x.offsetFrom(b, storeRc.storeDest, storeOffset, types.NewPtr(t))
                s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem)
        }
-       if x.debug {
+       if x.debug > 1 {
                x.Printf("-->storeArg returns %s, storeRc=%s\n", s.LongString(), storeRc.String())
        }
        return s
@@ -1071,18 +1073,23 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value,
 // to account for any parameter stores required.
 // Any of the old Args that have their use count fall to zero are marked OpInvalid.
 func (x *expandState) rewriteArgs(v *Value, firstArg int) {
-       if x.debug {
+       if x.debug > 1 {
                x.indent(3)
                defer x.indent(-3)
                x.Printf("rewriteArgs(%s; %d)\n", v.LongString(), firstArg)
        }
        // Thread the stores on the memory arg
        aux := v.Aux.(*AuxCall)
-       pos := v.Pos.WithNotStmt()
        m0 := v.MemoryArg()
        mem := m0
        newArgs := []*Value{}
        oldArgs := []*Value{}
+       sp := x.sp
+       if v.Op == OpTailLECall {
+               // For tail call, we unwind the frame before the call so we'll use the caller's
+               // SP.
+               sp = x.f.Entry.NewValue0(src.NoXPos, OpGetCallerSP, x.typs.Uintptr)
+       }
        for i, a := range v.Args[firstArg : len(v.Args)-1] { // skip leading non-parameter SSA Args and trailing mem SSA Arg.
                oldArgs = append(oldArgs, a)
                auxI := int64(i)
@@ -1093,9 +1100,20 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) {
                        if a.MemoryArg() != m0 {
                                x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString())
                        }
+                       if v.Op == OpTailLECall {
+                               // It's common for a tail call passing the same arguments (e.g. method wrapper),
+                               // so this would be a self copy. Detect this and optimize it out.
+                               a0 := a.Args[0]
+                               if a0.Op == OpLocalAddr {
+                                       n := a0.Aux.(*ir.Name)
+                                       if n.Class == ir.PPARAM && n.FrameOffset()+x.f.Config.ctxt.FixedFrameSize() == aOffset {
+                                               continue
+                                       }
+                               }
+                       }
                        // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move
                        // TODO(register args) this will be more complicated with registers in the picture.
-                       mem = x.rewriteDereference(v.Block, x.sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, pos)
+                       mem = x.rewriteDereference(v.Block, sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, a.Pos)
                } else {
                        var rc registerCursor
                        var result *[]*Value
@@ -1105,11 +1123,19 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) {
                        } else {
                                aOffset = aux.OffsetOfArg(auxI)
                        }
-                       if x.debug {
+                       if v.Op == OpTailLECall && a.Op == OpArg && a.AuxInt == 0 {
+                               // It's common for a tail call passing the same arguments (e.g. method wrapper),
+                               // so this would be a self copy. Detect this and optimize it out.
+                               n := a.Aux.(*ir.Name)
+                               if n.Class == ir.PPARAM && n.FrameOffset()+x.f.Config.ctxt.FixedFrameSize() == aOffset {
+                                       continue
+                               }
+                       }
+                       if x.debug > 1 {
                                x.Printf("...storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
                        }
-                       rc.init(aRegs, aux.abiInfo, result, x.sp)
-                       mem = x.storeArgOrLoad(pos, v.Block, a, mem, aType, aOffset, 0, rc)
+                       rc.init(aRegs, aux.abiInfo, result, sp)
+                       mem = x.storeArgOrLoad(a.Pos, v.Block, a, mem, aType, aOffset, 0, rc)
                }
        }
        var preArgStore [2]*Value
@@ -1120,16 +1146,31 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) {
        v.AddArg(mem)
        for _, a := range oldArgs {
                if a.Uses == 0 {
-                       if x.debug {
-                               x.Printf("...marking %v unused\n", a.LongString())
-                       }
-                       a.invalidateRecursively()
+                       x.invalidateRecursively(a)
                }
        }
 
        return
 }
 
+func (x *expandState) invalidateRecursively(a *Value) {
+       var s string
+       if x.debug > 0 {
+               plus := " "
+               if a.Pos.IsStmt() == src.PosIsStmt {
+                       plus = " +"
+               }
+               s = a.String() + plus + a.Pos.LineNumber() + " " + a.LongString()
+               if x.debug > 1 {
+                       x.Printf("...marking %v unused\n", s)
+               }
+       }
+       lost := a.invalidateRecursively()
+       if x.debug&1 != 0 && lost { // For odd values of x.debug, do this.
+               x.Printf("Lost statement marker in %s on former %s\n", base.Ctxt.Pkgpath+"."+x.f.Name, s)
+       }
+}
+
 // expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form
 // that is more oriented to a platform's ABI.  The SelectN operations that extract results are rewritten into
 // more appropriate forms, and any StructMake or ArrayMake inputs are decomposed until non-struct values are
@@ -1148,7 +1189,7 @@ func expandCalls(f *Func) {
        x := &expandState{
                f:                  f,
                abi1:               f.ABI1,
-               debug:              f.pass.debug > 0,
+               debug:              f.pass.debug,
                canSSAType:         f.fe.CanSSA,
                regSize:            f.Config.RegSize,
                sp:                 sp,
@@ -1170,7 +1211,7 @@ func expandCalls(f *Func) {
                x.loRo, x.hiRo = 0, 1
        }
 
-       if x.debug {
+       if x.debug > 1 {
                x.Printf("\nexpandsCalls(%s)\n", f.Name)
        }
 
@@ -1193,7 +1234,7 @@ func expandCalls(f *Func) {
                for _, v := range b.Values {
                        firstArg := 0
                        switch v.Op {
-                       case OpStaticLECall:
+                       case OpStaticLECall, OpTailLECall:
                        case OpInterLECall:
                                firstArg = 1
                        case OpClosureLECall:
@@ -1210,9 +1251,8 @@ func expandCalls(f *Func) {
                        m0 := v.MemoryArg()
                        mem := m0
                        aux := f.OwnAux
-                       pos := v.Pos.WithNotStmt()
                        allResults := []*Value{}
-                       if x.debug {
+                       if x.debug > 1 {
                                x.Printf("multiValueExit rewriting %s\n", v.LongString())
                        }
                        var oldArgs []*Value
@@ -1233,7 +1273,7 @@ func expandCalls(f *Func) {
                                                }
                                                continue
                                        }
-                                       mem = x.rewriteDereference(v.Block, auxBase, a, mem, auxOffset, auxSize, auxType, pos)
+                                       mem = x.rewriteDereference(v.Block, auxBase, a, mem, auxOffset, auxSize, auxType, a.Pos)
                                } else {
                                        if a.Op == OpLoad && a.Args[0].Op == OpLocalAddr {
                                                addr := a.Args[0] // This is a self-move. // TODO(register args) do what here for registers?
@@ -1257,13 +1297,13 @@ func expandCalls(f *Func) {
                        b.SetControl(v)
                        for _, a := range oldArgs {
                                if a.Uses == 0 {
-                                       if x.debug {
+                                       if x.debug > 1 {
                                                x.Printf("...marking %v unused\n", a.LongString())
                                        }
-                                       a.invalidateRecursively()
+                                       x.invalidateRecursively(a)
                                }
                        }
-                       if x.debug {
+                       if x.debug > 1 {
                                x.Printf("...multiValueExit new result %s\n", v.LongString())
                        }
                        x.indent(-3)
@@ -1317,7 +1357,7 @@ func expandCalls(f *Func) {
                                switch w.Op {
                                case OpStructSelect, OpArraySelect, OpSelectN, OpArg:
                                        val2Preds[w] += 1
-                                       if x.debug {
+                                       if x.debug > 1 {
                                                x.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w])
                                        }
                                }
@@ -1326,7 +1366,7 @@ func expandCalls(f *Func) {
                        case OpSelectN:
                                if _, ok := val2Preds[v]; !ok {
                                        val2Preds[v] = 0
-                                       if x.debug {
+                                       if x.debug > 1 {
                                                x.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
                                        }
                                }
@@ -1337,7 +1377,7 @@ func expandCalls(f *Func) {
                                }
                                if _, ok := val2Preds[v]; !ok {
                                        val2Preds[v] = 0
-                                       if x.debug {
+                                       if x.debug > 1 {
                                                x.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
                                        }
                                }
@@ -1422,7 +1462,7 @@ func expandCalls(f *Func) {
                if typ.IsMemory() {
                        continue // handled elsewhere, not an indexable result
                }
-               size := typ.Width
+               size := typ.Size()
                offset := int64(0)
                switch v.Op {
                case OpStructSelect:
@@ -1451,7 +1491,7 @@ func expandCalls(f *Func) {
                if dupe == nil {
                        x.commonSelectors[sk] = v
                } else if x.sdom.IsAncestorEq(dupe.Block, v.Block) {
-                       if x.debug {
+                       if x.debug > 1 {
                                x.Printf("Duplicate, make %s copy of %s\n", v, dupe)
                        }
                        v.copyOf(dupe)
@@ -1467,12 +1507,12 @@ func expandCalls(f *Func) {
 
        // Rewrite selectors.
        for i, v := range allOrdered {
-               if x.debug {
+               if x.debug > 1 {
                        b := v.Block
                        x.Printf("allOrdered[%d] = b%d, %s, uses=%d\n", i, b.ID, v.LongString(), v.Uses)
                }
                if v.Uses == 0 {
-                       v.invalidateRecursively()
+                       x.invalidateRecursively(v)
                        continue
                }
                if v.Op == OpCopy {
@@ -1512,6 +1552,10 @@ func expandCalls(f *Func) {
                                v.Op = OpStaticCall
                                rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
                                v.Type = types.NewResults(append(rts, types.TypeMem))
+                       case OpTailLECall:
+                               v.Op = OpTailCall
+                               rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
+                               v.Type = types.NewResults(append(rts, types.TypeMem))
                        case OpClosureLECall:
                                v.Op = OpClosureCall
                                rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
@@ -1534,7 +1578,7 @@ func expandCalls(f *Func) {
                case OpArgIntReg:
                        i := v.AuxInt
                        if w := IArg[i]; w != nil {
-                               if w.Type.Width != v.Type.Width {
+                               if w.Type.Size() != v.Type.Size() {
                                        f.Fatalf("incompatible OpArgIntReg [%d]: %s and %s", i, v.LongString(), w.LongString())
                                }
                                if w.Type.IsUnsafePtr() && !v.Type.IsUnsafePtr() {
@@ -1549,7 +1593,7 @@ func expandCalls(f *Func) {
                case OpArgFloatReg:
                        i := v.AuxInt
                        if w := FArg[i]; w != nil {
-                               if w.Type.Width != v.Type.Width {
+                               if w.Type.Size() != v.Type.Size() {
                                        f.Fatalf("incompatible OpArgFloatReg [%d]: %v and %v", i, v, w)
                                }
                                v.copyOf(w)
@@ -1583,7 +1627,7 @@ func expandCalls(f *Func) {
                                v.SetArg(i, aa)
                                for a.Uses == 0 {
                                        b := a.Args[0]
-                                       a.invalidateRecursively()
+                                       x.invalidateRecursively(a)
                                        a = b
                                }
                        }
@@ -1619,7 +1663,7 @@ func expandCalls(f *Func) {
 // rewriteArgToMemOrRegs converts OpArg v in-place into the register version of v,
 // if that is appropriate.
 func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
-       if x.debug {
+       if x.debug > 1 {
                x.indent(3)
                defer x.indent(-3)
                x.Printf("rewriteArgToMemOrRegs(%s)\n", v.LongString())
@@ -1634,9 +1678,9 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
                }
        case 1:
                t := v.Type
-               key := selKey{v, 0, t.Width, t}
+               key := selKey{v, 0, t.Size(), t}
                w := x.commonArgs[key]
-               if w != nil {
+               if w != nil && w.Uses != 0 { // do not reuse dead value
                        v.copyOf(w)
                        break
                }
@@ -1650,7 +1694,7 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
        default:
                panic(badVal("Saw unexpanded OpArg", v))
        }
-       if x.debug {
+       if x.debug > 1 {
                x.Printf("-->%s\n", v.LongString())
        }
        return v
@@ -1660,16 +1704,22 @@ func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
 // or rewrites it into a copy of the appropriate OpArgXXX.  The actual OpArgXXX is determined by combining baseArg (an OpArg)
 // with offset, regOffset, and t to determine which portion of it to reference (either all or a part, in memory or in registers).
 func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, regOffset Abi1RO, t *types.Type, pos src.XPos) *Value {
-       if x.debug {
+       if x.debug > 1 {
                x.indent(3)
                defer x.indent(-3)
                x.Printf("newArgToMemOrRegs(base=%s; toReplace=%s; t=%s; memOff=%d; regOff=%d)\n", baseArg.String(), toReplace.LongString(), t.String(), offset, regOffset)
        }
-       key := selKey{baseArg, offset, t.Width, t}
+       key := selKey{baseArg, offset, t.Size(), t}
        w := x.commonArgs[key]
-       if w != nil {
+       if w != nil && w.Uses != 0 { // do not reuse dead value
                if toReplace != nil {
                        toReplace.copyOf(w)
+                       if x.debug > 1 {
+                               x.Printf("...replace %s\n", toReplace.LongString())
+                       }
+               }
+               if x.debug > 1 {
+                       x.Printf("-->%s\n", w.LongString())
                }
                return w
        }
@@ -1696,7 +1746,7 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64,
                if toReplace != nil {
                        toReplace.copyOf(w)
                }
-               if x.debug {
+               if x.debug > 1 {
                        x.Printf("-->%s\n", w.LongString())
                }
                return w
@@ -1727,7 +1777,7 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64,
        if toReplace != nil {
                toReplace.copyOf(w)
        }
-       if x.debug {
+       if x.debug > 1 {
                x.Printf("-->%s\n", w.LongString())
        }
        return w
index 6d3c0f3ccbda17fb89ef7b4152fcf5a1f570c589..c4e87ec7d0f9e8c74d5ff10703f27f09b5e5fa01 100644 (file)
@@ -5,14 +5,16 @@
 package ssa
 
 import (
+       "testing"
+
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/obj/arm64"
        "cmd/internal/obj/s390x"
        "cmd/internal/obj/x86"
        "cmd/internal/src"
-       "testing"
 )
 
 var CheckFunc = checkFunc
@@ -104,33 +106,12 @@ func (d TestFrontend) MyImportPath() string {
 var testTypes Types
 
 func init() {
-       // Initialize just enough of the universe and the types package to make our tests function.
-       // TODO(josharian): move universe initialization to the types package,
-       // so this test setup can share it.
-
-       for _, typ := range [...]struct {
-               width int64
-               et    types.Kind
-       }{
-               {1, types.TINT8},
-               {1, types.TUINT8},
-               {1, types.TBOOL},
-               {2, types.TINT16},
-               {2, types.TUINT16},
-               {4, types.TINT32},
-               {4, types.TUINT32},
-               {4, types.TFLOAT32},
-               {4, types.TFLOAT64},
-               {8, types.TUINT64},
-               {8, types.TINT64},
-               {8, types.TINT},
-               {8, types.TUINTPTR},
-       } {
-               t := types.New(typ.et)
-               t.Width = typ.width
-               t.Align = uint8(typ.width)
-               types.Types[typ.et] = t
-       }
+       // TODO(mdempsky): Push into types.InitUniverse or typecheck.InitUniverse.
+       types.PtrSize = 8
+       types.RegSize = 8
+       types.MaxWidth = 1 << 50
+
+       typecheck.InitUniverse()
        testTypes.SetTypPtrs()
 }
 
index fac876c23ebc2eede4fabfc5a085a962bb99f11b..7728a395e05cb666e242631d1e219570623cc3b2 100644 (file)
@@ -43,7 +43,7 @@ type Func struct {
        logfiles       map[string]writeSyncer
        HTMLWriter     *HTMLWriter    // html writer, for debugging
        DebugTest      bool           // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
-       PrintOrHtmlSSA bool           // true if GOSSAFUNC matches, true even if fe.Log() (spew phase results to stdout) is false.
+       PrintOrHtmlSSA bool           // true if GOSSAFUNC matches, true even if fe.Log() (spew phase results to stdout) is false.  There's an odd dependence on this in debug.go for method logf.
        ruleMatches    map[string]int // number of times countRule was called during compilation for any given string
        ABI0           *abi.ABIConfig // A copy, for no-sync access
        ABI1           *abi.ABIConfig // A copy, for no-sync access
index 1b8b307bcac7a213880b25ca64f71eff41639dc7..751dca7468bc748af777e83d3565511e002473d6 100644 (file)
@@ -78,7 +78,7 @@ func fuseBranchRedirect(f *Func) bool {
                                        if v.Op != OpPhi {
                                                continue
                                        }
-                                       v.RemoveArg(k)
+                                       b.removePhiArg(v, k)
                                        phielimValue(v)
                                }
                                // Fix up child to have one more predecessor.
index 199b73c42f436fcfc88e422d196ffd8904780787..7bdebedafef81f6a1e1f3821e1a5fc1d59322365 100644 (file)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // Miscellaneous
 (IsNonNil p) => (SETNE (TESTL p p))
index 91f33c837457a3c944029de97383e8ebee9698af..f4c89b0bb3152926b03599f1e48bf87b78d8f6ba 100644 (file)
@@ -298,7 +298,7 @@ func init() {
                // unary ops
                {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0
 
-               {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, clobberFlags: true}, // ^arg0
+               {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
 
                {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL", clobberFlags: true}, // arg0 # of low-order zeroes ; undef if zero
                {name: "BSFW", argLength: 1, reg: gp11, asm: "BSFW", clobberFlags: true}, // arg0 # of low-order zeroes ; undef if zero
@@ -455,6 +455,7 @@ func init() {
                },
 
                {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                              // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                        // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
index 45c023831729f6458697c346f5082627b64bd47c..47a6af003c9ecd9b6d9f376d608e646cdc8d0296 100644 (file)
 (OffPtr [off] ptr) => (ADDQ (MOVQconst [off]) ptr)
 
 // Lowering other arithmetic
-(Ctz64 <t> x) => (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <types.TypeFlags> (BSFQ x)))
-(Ctz32 x) => (Select0 (BSFQ (BTSQconst <typ.UInt64> [32] x)))
+(Ctz64 x)     && buildcfg.GOAMD64 >= 3 => (TZCNTQ x)
+(Ctz32 x)     && buildcfg.GOAMD64 >= 3 => (TZCNTL x)
+(Ctz64 <t> x) && buildcfg.GOAMD64 <  3 => (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <types.TypeFlags> (BSFQ x)))
+(Ctz32 x)     && buildcfg.GOAMD64 <  3 => (Select0 (BSFQ (BTSQconst <typ.UInt64> [32] x)))
 (Ctz16 x) => (BSFL (BTSLconst <typ.UInt32> [16] x))
 (Ctz8  x) => (BSFL (BTSLconst <typ.UInt32> [ 8] x))
 
-(Ctz64NonZero x) => (Select0 (BSFQ x))
-(Ctz32NonZero ...) => (BSFL ...)
-(Ctz16NonZero ...) => (BSFL ...)
-(Ctz8NonZero  ...) => (BSFL ...)
+(Ctz64NonZero x) && buildcfg.GOAMD64 >= 3 => (TZCNTQ x)
+(Ctz32NonZero x) && buildcfg.GOAMD64 >= 3 => (TZCNTL x)
+(Ctz16NonZero x) && buildcfg.GOAMD64 >= 3 => (TZCNTL x)
+(Ctz8NonZero  x) && buildcfg.GOAMD64 >= 3 => (TZCNTL x)
+(Ctz64NonZero x) && buildcfg.GOAMD64 <  3 => (Select0 (BSFQ x))
+(Ctz32NonZero x) && buildcfg.GOAMD64 <  3 => (BSFL x)
+(Ctz16NonZero x) && buildcfg.GOAMD64 <  3 => (BSFL x)
+(Ctz8NonZero  x) && buildcfg.GOAMD64 <  3 => (BSFL x)
 
 // BitLen64 of a 64 bit value x requires checking whether x == 0, since BSRQ is undefined when x == 0.
 // However, for zero-extended values, we can cheat a bit, and calculate
 // Adjust zeros to be a multiple of 16 bytes.
 (Zero [s] destptr mem) && s%16 != 0 && s > 16 && s%16 > 8 && config.useSSE =>
        (Zero [s-s%16] (OffPtr <destptr.Type> destptr [s%16])
-               (MOVOstorezero destptr mem))
+               (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))
 
 (Zero [s] destptr mem) && s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE =>
        (Zero [s-s%16] (OffPtr <destptr.Type> destptr [s%16])
-               (MOVQstoreconst [makeValAndOff(0,0)] destptr mem))
+               (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))
 
 (Zero [16] destptr mem) && config.useSSE =>
-       (MOVOstorezero destptr mem)
+       (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)
 (Zero [32] destptr mem) && config.useSSE =>
-       (MOVOstorezero (OffPtr <destptr.Type> destptr [16])
-               (MOVOstorezero destptr mem))
+       (MOVOstoreconst [makeValAndOff(0,16)] destptr
+               (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))
 (Zero [48] destptr mem) && config.useSSE =>
-       (MOVOstorezero (OffPtr <destptr.Type> destptr [32])
-               (MOVOstorezero (OffPtr <destptr.Type> destptr [16])
-                       (MOVOstorezero destptr mem)))
+       (MOVOstoreconst [makeValAndOff(0,32)] destptr
+               (MOVOstoreconst [makeValAndOff(0,16)] destptr
+                       (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)))
 (Zero [64] destptr mem) && config.useSSE =>
-       (MOVOstorezero (OffPtr <destptr.Type> destptr [48])
-               (MOVOstorezero (OffPtr <destptr.Type> destptr [32])
-                       (MOVOstorezero (OffPtr <destptr.Type> destptr [16])
-                               (MOVOstorezero destptr mem))))
+       (MOVOstoreconst [makeValAndOff(0,48)] destptr
+               (MOVOstoreconst [makeValAndOff(0,32)] destptr
+                       (MOVOstoreconst [makeValAndOff(0,16)] destptr
+                               (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))))
 
 // Medium zeroing uses a duff device.
 (Zero [s] destptr mem)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // Lowering conditional moves
 // If the condition is a SETxx, we can just run a CMOV from the comparison that was
 (GetCallerPC ...) => (LoweredGetCallerPC ...)
 (GetCallerSP ...) => (LoweredGetCallerSP ...)
 
-(HasCPUFeature {s}) => (SETNE (CMPQconst [0] (LoweredHasCPUFeature {s})))
+(HasCPUFeature {s}) => (SETNE (CMPLconst [0] (LoweredHasCPUFeature {s})))
 (Addr {sym} base) => (LEAQ {sym} base)
 (LocalAddr {sym} base _) => (LEAQ {sym} base)
 
 
 // Recognize bit clearing: a &^= 1<<b
 (AND(Q|L) (NOT(Q|L) (SHL(Q|L) (MOV(Q|L)const [1]) y)) x) => (BTR(Q|L) x y)
+(ANDN(Q|L) x (SHL(Q|L) (MOV(Q|L)const [1]) y)) => (BTR(Q|L) x y)
 (ANDQconst [c] x) && isUint64PowerOfTwo(int64(^c)) && uint64(^c) >= 128
     => (BTRQconst [int8(log32(^c))] x)
 (ANDLconst [c] x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
        (MOVBstoreconst [makeValAndOff(int32(int8(c)),off)] {sym} ptr mem)
 
 // Fold address offsets into constant stores.
-(MOV(Q|L|W|B)storeconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd32(off) =>
-       (MOV(Q|L|W|B)storeconst [ValAndOff(sc).addOffset32(off)] {s} ptr mem)
+(MOV(Q|L|W|B|O)storeconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd32(off) =>
+       (MOV(Q|L|W|B|O)storeconst [ValAndOff(sc).addOffset32(off)] {s} ptr mem)
 
 // We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
 // what variables are being read/written by the ops.
 (MOV(Q|L|W|B|SS|SD|O)store [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
        && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
        (MOV(Q|L|W|B|SS|SD|O)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOV(Q|L|W|B)storeconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd32(off) =>
-       (MOV(Q|L|W|B)storeconst [ValAndOff(sc).addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOV(Q|L|W|B|O)storeconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd32(off) =>
+       (MOV(Q|L|W|B|O)storeconst [ValAndOff(sc).addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
 (SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
        && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
        (SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
   && a.Off() + 4 == c.Off()
   && clobber(x)
   => (MOVQstore [a.Off()] {s} p (MOVQconst [a.Val64()&0xffffffff | c.Val64()<<32]) mem)
-(MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem))
+(MOVQstoreconst [c] {s} p x:(MOVQstoreconst [a] {s} p mem))
+  && config.useSSE
+  && x.Uses == 1
+  && a.Off() + 8 == c.Off()
+  && a.Val() == 0
+  && c.Val() == 0
+  && clobber(x)
+  => (MOVOstoreconst [makeValAndOff(0,a.Off())] {s} p mem)
+(MOVQstoreconst [a] {s} p x:(MOVQstoreconst [c] {s} p mem))
   && config.useSSE
   && x.Uses == 1
-  && c2.Off() + 8 == c.Off()
+  && a.Off() + 8 == c.Off()
+  && a.Val() == 0
   && c.Val() == 0
-  && c2.Val() == 0
   && clobber(x)
-  => (MOVOstorezero [c2.Off()] {s} p mem)
+  => (MOVOstoreconst [makeValAndOff(0,a.Off())] {s} p mem)
 
 // Combine stores into larger (unaligned) stores. Little endian.
 (MOVBstore [i] {s} p (SHR(W|L|Q)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
   && clobber(x1, x2, mem2)
   => (MOVQstore [i-4] {s} p (MOVQload [j-4] {s2} p2 mem) mem)
 
-(MOVQload  [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVLload  [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVLload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVWload  [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
-(MOVBload  [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVBload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
-
-(MOVQstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVQstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVLstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVWstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-(MOVBstore  [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
-       (MOVBstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-
-(MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
-       (MOVQstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
-       (MOVLstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
-       (MOVWstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
-       (MOVBstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-
-(MOVQload  [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVQload  [off1+off2] {sym} ptr mem)
-(MOVLload  [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVLload  [off1+off2] {sym} ptr mem)
-(MOVWload  [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVWload  [off1+off2] {sym} ptr mem)
-(MOVBload  [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVBload  [off1+off2] {sym} ptr mem)
-(MOVQstore  [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(int64(off1)+int64(off2)) => (MOVQstore  [off1+off2] {sym} ptr val mem)
-(MOVLstore  [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(int64(off1)+int64(off2)) => (MOVLstore  [off1+off2] {sym} ptr val mem)
-(MOVWstore  [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(int64(off1)+int64(off2)) => (MOVWstore  [off1+off2] {sym} ptr val mem)
-(MOVBstore  [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(int64(off1)+int64(off2)) => (MOVBstore  [off1+off2] {sym} ptr val mem)
-(MOVQstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && sc.canAdd32(off) =>
-       (MOVQstoreconst [sc.addOffset32(off)] {s} ptr mem)
-(MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && sc.canAdd32(off) =>
-       (MOVLstoreconst [sc.addOffset32(off)] {s} ptr mem)
-(MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && sc.canAdd32(off) =>
-       (MOVWstoreconst [sc.addOffset32(off)] {s} ptr mem)
-(MOVBstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && sc.canAdd32(off) =>
-       (MOVBstoreconst [sc.addOffset32(off)] {s} ptr mem)
-
 // Merge load and op
 // TODO: add indexed variants?
 ((ADD|SUB|AND|OR|XOR)Q x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|AND|OR|XOR)Qload x [off] {sym} ptr mem)
        && isInlinableMemmove(dst, src, sz, config)
        && clobber(call)
        => (Move [sz] dst src mem)
+
+// Prefetch instructions
+(PrefetchCache ...)   => (PrefetchT0 ...)
+(PrefetchCacheStreamed ...) => (PrefetchNTA ...)
+
+// CPUID feature: BMI1.
+(AND(Q|L) x (NOT(Q|L) y))           && buildcfg.GOAMD64 >= 3 => (ANDN(Q|L) x y)
+(AND(Q|L) x (NEG(Q|L) x))           && buildcfg.GOAMD64 >= 3 => (BLSI(Q|L) x)
+(XOR(Q|L) x (ADD(Q|L)const [-1] x)) && buildcfg.GOAMD64 >= 3 => (BLSMSK(Q|L) x)
+(AND(Q|L) x (ADD(Q|L)const [-1] x)) && buildcfg.GOAMD64 >= 3 => (BLSR(Q|L) x)
+
+(BSWAP(Q|L) (BSWAP(Q|L) p)) => p
+
+// CPUID feature: MOVBE.
+(MOV(Q|L)store [i] {s} p x:(BSWAP(Q|L) w) mem) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBE(Q|L)store [i] {s} p w mem)
+(BSWAP(Q|L) x:(MOV(Q|L)load [i] {s} p mem))    && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBE(Q|L)load [i] {s} p mem)
+(BSWAP(Q|L) (MOVBE(Q|L)load [i] {s} p m))    => (MOV(Q|L)load [i] {s} p m)
+(MOVBE(Q|L)store [i] {s} p (BSWAP(Q|L) x) m) => (MOV(Q|L)store [i] {s} p x m)
+
+(ORQ                   x0:(MOVBELload [i0] {s} p mem)
+    sh:(SHLQconst [32] x1:(MOVBELload [i1] {s} p mem)))
+  && i0 == i1+4
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0, x1, sh)
+  => @mergePoint(b,x0,x1) (MOVBEQload [i1] {s} p mem)
+
+(ORQ                   x0:(MOVBELload [i] {s} p0 mem)
+    sh:(SHLQconst [32] x1:(MOVBELload [i] {s} p1 mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && sh.Uses == 1
+  && sequentialAddresses(p1, p0, 4)
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0, x1, sh)
+  => @mergePoint(b,x0,x1) (MOVBEQload [i] {s} p1 mem)
index 67b3293903cd915f5ef2e3839b806fe0230370fd..a6906bec7c74eae3768d6577524ba3661beb2382 100644 (file)
@@ -169,6 +169,8 @@ func init() {
 
                fpstore    = regInfo{inputs: []regMask{gpspsb, fp, 0}}
                fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}}
+
+               prefreg = regInfo{inputs: []regMask{gpspsbg}}
        )
 
        var AMD64ops = []opData{
@@ -511,8 +513,8 @@ func init() {
                {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true, clobberFlags: true}, // -arg0
                {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0
 
-               {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true, clobberFlags: true}, // ^arg0
-               {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, clobberFlags: true}, // ^arg0
+               {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true}, // ^arg0
+               {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
 
                // BS{F,R}Q returns a tuple [result, flags]
                // result is undefined if the input is zero.
@@ -679,20 +681,19 @@ func init() {
                // Note: LEAx{1,2,4,8} must not have OpSB as either argument.
 
                // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
-               {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},                                   // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
-               {name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},                                              // ditto, sign extend to int64
-               {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"},                                  // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-               {name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},                                              // ditto, sign extend to int64
-               {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},                                     // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
-               {name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},                                              // ditto, sign extend to int64
-               {name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},                                     // load 8 bytes from arg0+auxint+aux. arg1=mem
-               {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},                                     // store byte in arg1 to arg0+auxint+aux. arg2=mem
-               {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},                                     // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
-               {name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},                                     // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
-               {name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},                                     // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
-               {name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128", faultOnNilArg0: true, symEffect: "Read"},                                   // load 16 bytes from arg0+auxint+aux. arg1=mem
-               {name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},                                   // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
-               {name: "MOVOstorezero", argLength: 2, reg: regInfo{inputs: []regMask{gpspsb, 0}}, asm: "MOVUPS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 16 bytes of zero to arg0+auxint+aux. arg1=mem
+               {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
+               {name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int64
+               {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+               {name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int64
+               {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},    // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+               {name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"},             // ditto, sign extend to int64
+               {name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},    // load 8 bytes from arg0+auxint+aux. arg1=mem
+               {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store byte in arg1 to arg0+auxint+aux. arg2=mem
+               {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
+               {name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+               {name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},    // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
+               {name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128", faultOnNilArg0: true, symEffect: "Read"},  // load 16 bytes from arg0+auxint+aux. arg1=mem
+               {name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
 
                // indexed loads/stores
                {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", scale: 1, aux: "SymOff", typ: "UInt8", symEffect: "Read"},  // load a byte from arg0+arg1+auxint+aux. arg2=mem
@@ -717,10 +718,11 @@ func init() {
                // For storeconst ops, the AuxInt field encodes both
                // the value to store and an address offset of the store.
                // Cast AuxInt to a ValAndOff to extract Val and Off fields.
-               {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
-               {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 2 bytes of ...
-               {name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store low 4 bytes of ...
-               {name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of ...
+               {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
+               {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store low 2 bytes of ...
+               {name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store low 4 bytes of ...
+               {name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},   // store 8 bytes of ...
+               {name: "MOVOstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVUPS", aux: "SymValAndOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 16 bytes of ...
 
                {name: "MOVBstoreconstidx1", argLength: 3, reg: gpstoreconstidx, commutative: true, asm: "MOVB", scale: 1, aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+1*arg1+ValAndOff(AuxInt).Off()+aux.  arg2=mem
                {name: "MOVWstoreconstidx1", argLength: 3, reg: gpstoreconstidx, commutative: true, asm: "MOVW", scale: 1, aux: "SymValAndOff", typ: "Mem", symEffect: "Write"}, // store low 2 bytes of ... arg1 ...
@@ -763,6 +765,7 @@ func init() {
 
                // With a register ABI, the actual register info for these instructions (i.e., what is used in regalloc) is augmented with per-call-site bindings of additional arguments to specific in and out registers.
                {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                              // call static function aux.(*obj.LSym).  last arg=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                // tail call static function aux.(*obj.LSym).  last arg=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("DX"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                        // call fn by pointer.  arg0=codeptr, last arg=mem, auxint=argsize, returns mem
 
@@ -900,6 +903,31 @@ func init() {
                {name: "ANDLlock", argLength: 3, reg: gpstore, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
                {name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},   // *(arg0+auxint+aux) |= arg1
                {name: "ORLlock", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"},   // *(arg0+auxint+aux) |= arg1
+
+               // Prefetch instructions
+               // Do prefetch arg0 address. arg0=addr, arg1=memory. Instruction variant selects locality hint
+               {name: "PrefetchT0", argLength: 2, reg: prefreg, asm: "PREFETCHT0", hasSideEffects: true},
+               {name: "PrefetchNTA", argLength: 2, reg: prefreg, asm: "PREFETCHNTA", hasSideEffects: true},
+
+               // CPUID feature: BMI1.
+               {name: "ANDNQ", argLength: 2, reg: gp21, asm: "ANDNQ", clobberFlags: true},     // arg0 &^ arg1
+               {name: "ANDNL", argLength: 2, reg: gp21, asm: "ANDNL", clobberFlags: true},     // arg0 &^ arg1
+               {name: "BLSIQ", argLength: 1, reg: gp11, asm: "BLSIQ", clobberFlags: true},     // arg0 & -arg0
+               {name: "BLSIL", argLength: 1, reg: gp11, asm: "BLSIL", clobberFlags: true},     // arg0 & -arg0
+               {name: "BLSMSKQ", argLength: 1, reg: gp11, asm: "BLSMSKQ", clobberFlags: true}, // arg0 ^ (arg0 - 1)
+               {name: "BLSMSKL", argLength: 1, reg: gp11, asm: "BLSMSKL", clobberFlags: true}, // arg0 ^ (arg0 - 1)
+               {name: "BLSRQ", argLength: 1, reg: gp11, asm: "BLSRQ", clobberFlags: true},     // arg0 & (arg0 - 1)
+               {name: "BLSRL", argLength: 1, reg: gp11, asm: "BLSRL", clobberFlags: true},     // arg0 & (arg0 - 1)
+               // count the number of trailing zero bits, prefer TZCNTQ over BSFQ, as TZCNTQ(0)==64
+               // and BSFQ(0) is undefined. Same for TZCNTL(0)==32
+               {name: "TZCNTQ", argLength: 1, reg: gp11, asm: "TZCNTQ", clobberFlags: true},
+               {name: "TZCNTL", argLength: 1, reg: gp11, asm: "TZCNTL", clobberFlags: true},
+
+               // CPUID feature: MOVBE
+               {name: "MOVBELload", argLength: 2, reg: gpload, asm: "MOVBEL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load and swap 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+               {name: "MOVBELstore", argLength: 3, reg: gpstore, asm: "MOVBEL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // swap and store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+               {name: "MOVBEQload", argLength: 2, reg: gpload, asm: "MOVBEQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load and swap 8 bytes from arg0+auxint+aux. arg1=mem
+               {name: "MOVBEQstore", argLength: 3, reg: gpstore, asm: "MOVBEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // swap and store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
        }
 
        var AMD64blocks = []blockData{
index bcacbafe3a5f0299dd47e45962a46170bd9896d4..2bc58a3c47c82c0280414ca094f848ac61c07e02 100644 (file)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // checks
 (NilCheck ...) => (LoweredNilCheck ...)
 (XOR x (MOVWconst [c])) => (XORconst [c] x)
 (BIC x (MOVWconst [c])) => (BICconst [c] x)
 
-(SLL x (MOVWconst [c])) => (SLLconst x [c&31]) // Note: I don't think we ever generate bad constant shifts (i.e. c>=32)
-(SRL x (MOVWconst [c])) => (SRLconst x [c&31])
-(SRA x (MOVWconst [c])) => (SRAconst x [c&31])
+(SLL x (MOVWconst [c])) && 0 <= c && c < 32 => (SLLconst x [c])
+(SRL x (MOVWconst [c])) && 0 <= c && c < 32 => (SRLconst x [c])
+(SRA x (MOVWconst [c])) && 0 <= c && c < 32 => (SRAconst x [c])
 
 (CMP x (MOVWconst [c])) => (CMPconst [c] x)
 (CMP (MOVWconst [c]) x) => (InvertFlags (CMPconst [c] x))
 (TST x (MOVWconst [c])) => (TSTconst [c] x)
 (TEQ x (MOVWconst [c])) => (TEQconst [c] x)
 
+(SRR x (MOVWconst [c])) => (SRRconst x [c&31])
+
 // Canonicalize the order of arguments to comparisons - helps with CSE.
 (CMP x y) && canonLessThan(x,y) => (InvertFlags (CMP y x))
 
 (CMNshiftRL x (MOVWconst [c]) [d]) => (CMNconst x [int32(uint32(c)>>uint64(d))])
 (CMNshiftRA x (MOVWconst [c]) [d]) => (CMNconst x [c>>uint64(d)])
 
-(ADDshiftLLreg x y (MOVWconst [c])) => (ADDshiftLL x y [c])
-(ADDshiftRLreg x y (MOVWconst [c])) => (ADDshiftRL x y [c])
-(ADDshiftRAreg x y (MOVWconst [c])) => (ADDshiftRA x y [c])
-(ADCshiftLLreg x y (MOVWconst [c]) flags) => (ADCshiftLL x y [c] flags)
-(ADCshiftRLreg x y (MOVWconst [c]) flags) => (ADCshiftRL x y [c] flags)
-(ADCshiftRAreg x y (MOVWconst [c]) flags) => (ADCshiftRA x y [c] flags)
-(ADDSshiftLLreg x y (MOVWconst [c])) => (ADDSshiftLL x y [c])
-(ADDSshiftRLreg x y (MOVWconst [c])) => (ADDSshiftRL x y [c])
-(ADDSshiftRAreg x y (MOVWconst [c])) => (ADDSshiftRA x y [c])
-(SUBshiftLLreg x y (MOVWconst [c])) => (SUBshiftLL x y [c])
-(SUBshiftRLreg x y (MOVWconst [c])) => (SUBshiftRL x y [c])
-(SUBshiftRAreg x y (MOVWconst [c])) => (SUBshiftRA x y [c])
-(SBCshiftLLreg x y (MOVWconst [c]) flags) => (SBCshiftLL x y [c] flags)
-(SBCshiftRLreg x y (MOVWconst [c]) flags) => (SBCshiftRL x y [c] flags)
-(SBCshiftRAreg x y (MOVWconst [c]) flags) => (SBCshiftRA x y [c] flags)
-(SUBSshiftLLreg x y (MOVWconst [c])) => (SUBSshiftLL x y [c])
-(SUBSshiftRLreg x y (MOVWconst [c])) => (SUBSshiftRL x y [c])
-(SUBSshiftRAreg x y (MOVWconst [c])) => (SUBSshiftRA x y [c])
-(RSBshiftLLreg x y (MOVWconst [c])) => (RSBshiftLL x y [c])
-(RSBshiftRLreg x y (MOVWconst [c])) => (RSBshiftRL x y [c])
-(RSBshiftRAreg x y (MOVWconst [c])) => (RSBshiftRA x y [c])
-(RSCshiftLLreg x y (MOVWconst [c]) flags) => (RSCshiftLL x y [c] flags)
-(RSCshiftRLreg x y (MOVWconst [c]) flags) => (RSCshiftRL x y [c] flags)
-(RSCshiftRAreg x y (MOVWconst [c]) flags) => (RSCshiftRA x y [c] flags)
-(RSBSshiftLLreg x y (MOVWconst [c])) => (RSBSshiftLL x y [c])
-(RSBSshiftRLreg x y (MOVWconst [c])) => (RSBSshiftRL x y [c])
-(RSBSshiftRAreg x y (MOVWconst [c])) => (RSBSshiftRA x y [c])
-(ANDshiftLLreg x y (MOVWconst [c])) => (ANDshiftLL x y [c])
-(ANDshiftRLreg x y (MOVWconst [c])) => (ANDshiftRL x y [c])
-(ANDshiftRAreg x y (MOVWconst [c])) => (ANDshiftRA x y [c])
-(ORshiftLLreg x y (MOVWconst [c])) => (ORshiftLL x y [c])
-(ORshiftRLreg x y (MOVWconst [c])) => (ORshiftRL x y [c])
-(ORshiftRAreg x y (MOVWconst [c])) => (ORshiftRA x y [c])
-(XORshiftLLreg x y (MOVWconst [c])) => (XORshiftLL x y [c])
-(XORshiftRLreg x y (MOVWconst [c])) => (XORshiftRL x y [c])
-(XORshiftRAreg x y (MOVWconst [c])) => (XORshiftRA x y [c])
-(BICshiftLLreg x y (MOVWconst [c])) => (BICshiftLL x y [c])
-(BICshiftRLreg x y (MOVWconst [c])) => (BICshiftRL x y [c])
-(BICshiftRAreg x y (MOVWconst [c])) => (BICshiftRA x y [c])
-(MVNshiftLLreg x (MOVWconst [c])) => (MVNshiftLL x [c])
-(MVNshiftRLreg x (MOVWconst [c])) => (MVNshiftRL x [c])
-(MVNshiftRAreg x (MOVWconst [c])) => (MVNshiftRA x [c])
-(CMPshiftLLreg x y (MOVWconst [c])) => (CMPshiftLL x y [c])
-(CMPshiftRLreg x y (MOVWconst [c])) => (CMPshiftRL x y [c])
-(CMPshiftRAreg x y (MOVWconst [c])) => (CMPshiftRA x y [c])
-(TSTshiftLLreg x y (MOVWconst [c])) => (TSTshiftLL x y [c])
-(TSTshiftRLreg x y (MOVWconst [c])) => (TSTshiftRL x y [c])
-(TSTshiftRAreg x y (MOVWconst [c])) => (TSTshiftRA x y [c])
-(TEQshiftLLreg x y (MOVWconst [c])) => (TEQshiftLL x y [c])
-(TEQshiftRLreg x y (MOVWconst [c])) => (TEQshiftRL x y [c])
-(TEQshiftRAreg x y (MOVWconst [c])) => (TEQshiftRA x y [c])
-(CMNshiftLLreg x y (MOVWconst [c])) => (CMNshiftLL x y [c])
-(CMNshiftRLreg x y (MOVWconst [c])) => (CMNshiftRL x y [c])
-(CMNshiftRAreg x y (MOVWconst [c])) => (CMNshiftRA x y [c])
+(ADDshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftLL x y [c])
+(ADDshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftRL x y [c])
+(ADDshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDshiftRA x y [c])
+(ADCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftLL x y [c] flags)
+(ADCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftRL x y [c] flags)
+(ADCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (ADCshiftRA x y [c] flags)
+(ADDSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftLL x y [c])
+(ADDSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftRL x y [c])
+(ADDSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ADDSshiftRA x y [c])
+(SUBshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftLL x y [c])
+(SUBshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftRL x y [c])
+(SUBshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBshiftRA x y [c])
+(SBCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftLL x y [c] flags)
+(SBCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftRL x y [c] flags)
+(SBCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (SBCshiftRA x y [c] flags)
+(SUBSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftLL x y [c])
+(SUBSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftRL x y [c])
+(SUBSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (SUBSshiftRA x y [c])
+(RSBshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftLL x y [c])
+(RSBshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftRL x y [c])
+(RSBshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBshiftRA x y [c])
+(RSCshiftLLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftLL x y [c] flags)
+(RSCshiftRLreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftRL x y [c] flags)
+(RSCshiftRAreg x y (MOVWconst [c]) flags) && 0 <= c && c < 32 => (RSCshiftRA x y [c] flags)
+(RSBSshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftLL x y [c])
+(RSBSshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftRL x y [c])
+(RSBSshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (RSBSshiftRA x y [c])
+(ANDshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftLL x y [c])
+(ANDshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftRL x y [c])
+(ANDshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ANDshiftRA x y [c])
+(ORshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftLL x y [c])
+(ORshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftRL x y [c])
+(ORshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (ORshiftRA x y [c])
+(XORshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftLL x y [c])
+(XORshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftRL x y [c])
+(XORshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (XORshiftRA x y [c])
+(BICshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftLL x y [c])
+(BICshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftRL x y [c])
+(BICshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (BICshiftRA x y [c])
+(MVNshiftLLreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftLL x [c])
+(MVNshiftRLreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftRL x [c])
+(MVNshiftRAreg x (MOVWconst [c])) && 0 <= c && c < 32 => (MVNshiftRA x [c])
+(CMPshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftLL x y [c])
+(CMPshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftRL x y [c])
+(CMPshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMPshiftRA x y [c])
+(TSTshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftLL x y [c])
+(TSTshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftRL x y [c])
+(TSTshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TSTshiftRA x y [c])
+(TEQshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftLL x y [c])
+(TEQshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftRL x y [c])
+(TEQshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (TEQshiftRA x y [c])
+(CMNshiftLLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftLL x y [c])
+(CMNshiftRLreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftRL x y [c])
+(CMNshiftRAreg x y (MOVWconst [c])) && 0 <= c && c < 32 => (CMNshiftRA x y [c])
 
 // Generate rotates
 (ADDshiftLL [c] (SRLconst x [32-c]) x) => (SRRconst [32-c] x)
 ( ORshiftRL [c] (SLLconst x [32-c]) x) => (SRRconst [   c] x)
 (XORshiftRL [c] (SLLconst x [32-c]) x) => (SRRconst [   c] x)
 
-(RotateLeft32 x (MOVWconst [c])) => (SRRconst [-c&31] x)
 (RotateLeft16 <t> x (MOVWconst [c])) => (Or16 (Lsh16x32 <t> x (MOVWconst [c&15])) (Rsh16Ux32 <t> x (MOVWconst [-c&15])))
 (RotateLeft8 <t> x (MOVWconst [c])) => (Or8 (Lsh8x32 <t> x (MOVWconst [c&7])) (Rsh8Ux32 <t> x (MOVWconst [-c&7])))
 (RotateLeft32 x y) => (SRR x (RSBconst [0] <y.Type> y))
 (AND x (MVN y)) => (BIC x y)
 
 // simplification with *shift ops
-(SUBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(SUBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(SUBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
-(RSBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(RSBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(RSBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
-(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
-(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
-(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
-(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
-(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
-(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
-(XORshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(XORshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(XORshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
-(BICshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(BICshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVWconst [0])
-(BICshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVWconst [0])
+(SUBshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
+(SUBshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
+(SUBshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
+(RSBshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
+(RSBshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
+(RSBshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
+(ANDshiftLL y:(SLLconst x [c]) x [c]) => y
+(ANDshiftRL y:(SRLconst x [c]) x [c]) => y
+(ANDshiftRA y:(SRAconst x [c]) x [c]) => y
+(ORshiftLL y:(SLLconst x [c]) x [c]) => y
+(ORshiftRL y:(SRLconst x [c]) x [c]) => y
+(ORshiftRA y:(SRAconst x [c]) x [c]) => y
+(XORshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
+(XORshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
+(XORshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
+(BICshiftLL (SLLconst x [c]) x [c]) => (MOVWconst [0])
+(BICshiftRL (SRLconst x [c]) x [c]) => (MOVWconst [0])
+(BICshiftRA (SRAconst x [c]) x [c]) => (MOVWconst [0])
 (AND x (MVNshiftLL y [c])) => (BICshiftLL x y [c])
 (AND x (MVNshiftRL y [c])) => (BICshiftRL x y [c])
 (AND x (MVNshiftRA y [c])) => (BICshiftRA x y [c])
index 530e48bcb259a4e84a039d2896b020c93967386b..d34e1899db50909a1e0cabd212840c36400bef88 100644 (file)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // checks
 (NilCheck ...) => (LoweredNilCheck ...)
 // Write barrier.
 (WB ...) => (LoweredWB ...)
 
+// Publication barrier (0xe is ST option)
+(PubBarrier mem) => (DMB [0xe] mem)
+
 (PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
 (PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
 (PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
 (CMPW x (MOVDconst [c])) => (CMPWconst [int32(c)] x)
 (CMPW (MOVDconst [c]) x) => (InvertFlags (CMPWconst [int32(c)] x))
 
+(ROR x (MOVDconst [c])) => (RORconst x [c&63])
+(RORW x (MOVDconst [c])) => (RORWconst x [c&31])
+
 // Canonicalize the order of arguments to comparisons - helps with CSE.
 ((CMP|CMPW) x y) && canonLessThan(x,y) => (InvertFlags ((CMP|CMPW) y x))
 
 (XOR x (MVN y)) => (EON x y)
 (OR  x (MVN y)) => (ORN x y)
 (MVN (XOR x y)) => (EON x y)
+(NEG (NEG x)) => x
 
 (CSEL [cc] (MOVDconst [-1]) (MOVDconst [0]) flag) => (CSETM [cc] flag)
 (CSEL [cc] (MOVDconst [0]) (MOVDconst [-1]) flag) => (CSETM [arm64Negate(cc)] flag)
 (MVN x:(SLLconst [c] y)) && clobberIfDead(x) => (MVNshiftLL [c] y)
 (MVN x:(SRLconst [c] y)) && clobberIfDead(x) => (MVNshiftRL [c] y)
 (MVN x:(SRAconst [c] y)) && clobberIfDead(x) => (MVNshiftRA [c] y)
+(MVN x:(RORconst [c] y)) && clobberIfDead(x) => (MVNshiftRO [c] y)
 (ADD x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (ADDshiftLL x0 y [c])
 (ADD x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (ADDshiftRL x0 y [c])
 (ADD x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (ADDshiftRA x0 y [c])
 (AND x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (ANDshiftLL x0 y [c])
 (AND x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (ANDshiftRL x0 y [c])
 (AND x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (ANDshiftRA x0 y [c])
+(AND x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (ANDshiftRO x0 y [c])
 (OR  x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (ORshiftLL  x0 y [c]) // useful for combined load
 (OR  x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (ORshiftRL  x0 y [c])
 (OR  x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (ORshiftRA  x0 y [c])
+(OR  x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (ORshiftRO  x0 y [c])
 (XOR x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (XORshiftLL x0 y [c])
 (XOR x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (XORshiftRL x0 y [c])
 (XOR x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (XORshiftRA x0 y [c])
+(XOR x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (XORshiftRO x0 y [c])
 (BIC x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (BICshiftLL x0 y [c])
 (BIC x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (BICshiftRL x0 y [c])
 (BIC x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (BICshiftRA x0 y [c])
+(BIC x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (BICshiftRO x0 y [c])
 (ORN x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (ORNshiftLL x0 y [c])
 (ORN x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (ORNshiftRL x0 y [c])
 (ORN x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (ORNshiftRA x0 y [c])
+(ORN x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (ORNshiftRO x0 y [c])
 (EON x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (EONshiftLL x0 y [c])
 (EON x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (EONshiftRL x0 y [c])
 (EON x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (EONshiftRA x0 y [c])
+(EON x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (EONshiftRO x0 y [c])
 (CMP x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (CMPshiftLL x0 y [c])
 (CMP x0:(SLLconst [c] y) x1) && clobberIfDead(x0) => (InvertFlags (CMPshiftLL x1 y [c]))
 (CMP x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (CMPshiftRL x0 y [c])
 (TST x0 x1:(SLLconst [c] y)) && clobberIfDead(x1) => (TSTshiftLL x0 y [c])
 (TST x0 x1:(SRLconst [c] y)) && clobberIfDead(x1) => (TSTshiftRL x0 y [c])
 (TST x0 x1:(SRAconst [c] y)) && clobberIfDead(x1) => (TSTshiftRA x0 y [c])
+(TST x0 x1:(RORconst [c] y)) && clobberIfDead(x1) => (TSTshiftRO x0 y [c])
 
 // prefer *const ops to *shift ops
 (ADDshiftLL (MOVDconst [c]) x [d]) => (ADDconst [c] (SLLconst <x.Type> x [d]))
 (ANDshiftLL (MOVDconst [c]) x [d]) => (ANDconst [c] (SLLconst <x.Type> x [d]))
 (ANDshiftRL (MOVDconst [c]) x [d]) => (ANDconst [c] (SRLconst <x.Type> x [d]))
 (ANDshiftRA (MOVDconst [c]) x [d]) => (ANDconst [c] (SRAconst <x.Type> x [d]))
+(ANDshiftRO (MOVDconst [c]) x [d]) => (ANDconst [c] (RORconst <x.Type> x [d]))
 (ORshiftLL  (MOVDconst [c]) x [d]) => (ORconst  [c] (SLLconst <x.Type> x [d]))
 (ORshiftRL  (MOVDconst [c]) x [d]) => (ORconst  [c] (SRLconst <x.Type> x [d]))
 (ORshiftRA  (MOVDconst [c]) x [d]) => (ORconst  [c] (SRAconst <x.Type> x [d]))
+(ORshiftRO  (MOVDconst [c]) x [d]) => (ORconst  [c] (RORconst <x.Type> x [d]))
 (XORshiftLL (MOVDconst [c]) x [d]) => (XORconst [c] (SLLconst <x.Type> x [d]))
 (XORshiftRL (MOVDconst [c]) x [d]) => (XORconst [c] (SRLconst <x.Type> x [d]))
 (XORshiftRA (MOVDconst [c]) x [d]) => (XORconst [c] (SRAconst <x.Type> x [d]))
+(XORshiftRO (MOVDconst [c]) x [d]) => (XORconst [c] (RORconst <x.Type> x [d]))
 (CMPshiftLL (MOVDconst [c]) x [d]) => (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
 (CMPshiftRL (MOVDconst [c]) x [d]) => (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
 (CMPshiftRA (MOVDconst [c]) x [d]) => (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
 (TSTshiftLL (MOVDconst [c]) x [d]) => (TSTconst [c] (SLLconst <x.Type> x [d]))
 (TSTshiftRL (MOVDconst [c]) x [d]) => (TSTconst [c] (SRLconst <x.Type> x [d]))
 (TSTshiftRA (MOVDconst [c]) x [d]) => (TSTconst [c] (SRAconst <x.Type> x [d]))
+(TSTshiftRO (MOVDconst [c]) x [d]) => (TSTconst [c] (RORconst <x.Type> x [d]))
 
 // constant folding in *shift ops
 (MVNshiftLL (MOVDconst [c]) [d]) => (MOVDconst [^int64(uint64(c)<<uint64(d))])
 (MVNshiftRL (MOVDconst [c]) [d]) => (MOVDconst [^int64(uint64(c)>>uint64(d))])
 (MVNshiftRA (MOVDconst [c]) [d]) => (MOVDconst [^(c>>uint64(d))])
+(MVNshiftRO (MOVDconst [c]) [d]) => (MOVDconst [^rotateRight64(c, d)])
 (NEGshiftLL (MOVDconst [c]) [d]) => (MOVDconst [-int64(uint64(c)<<uint64(d))])
 (NEGshiftRL (MOVDconst [c]) [d]) => (MOVDconst [-int64(uint64(c)>>uint64(d))])
 (NEGshiftRA (MOVDconst [c]) [d]) => (MOVDconst [-(c>>uint64(d))])
 (ANDshiftLL x (MOVDconst [c]) [d]) => (ANDconst x [int64(uint64(c)<<uint64(d))])
 (ANDshiftRL x (MOVDconst [c]) [d]) => (ANDconst x [int64(uint64(c)>>uint64(d))])
 (ANDshiftRA x (MOVDconst [c]) [d]) => (ANDconst x [c>>uint64(d)])
+(ANDshiftRO x (MOVDconst [c]) [d]) => (ANDconst x [rotateRight64(c, d)])
 (ORshiftLL  x (MOVDconst [c]) [d]) => (ORconst  x [int64(uint64(c)<<uint64(d))])
 (ORshiftRL  x (MOVDconst [c]) [d]) => (ORconst  x [int64(uint64(c)>>uint64(d))])
 (ORshiftRA  x (MOVDconst [c]) [d]) => (ORconst  x [c>>uint64(d)])
+(ORshiftRO  x (MOVDconst [c]) [d]) => (ORconst  x [rotateRight64(c, d)])
 (XORshiftLL x (MOVDconst [c]) [d]) => (XORconst x [int64(uint64(c)<<uint64(d))])
 (XORshiftRL x (MOVDconst [c]) [d]) => (XORconst x [int64(uint64(c)>>uint64(d))])
 (XORshiftRA x (MOVDconst [c]) [d]) => (XORconst x [c>>uint64(d)])
+(XORshiftRO x (MOVDconst [c]) [d]) => (XORconst x [rotateRight64(c, d)])
 (BICshiftLL x (MOVDconst [c]) [d]) => (ANDconst x [^int64(uint64(c)<<uint64(d))])
 (BICshiftRL x (MOVDconst [c]) [d]) => (ANDconst x [^int64(uint64(c)>>uint64(d))])
 (BICshiftRA x (MOVDconst [c]) [d]) => (ANDconst x [^(c>>uint64(d))])
+(BICshiftRO x (MOVDconst [c]) [d]) => (ANDconst x [^rotateRight64(c, d)])
 (ORNshiftLL x (MOVDconst [c]) [d]) => (ORconst  x [^int64(uint64(c)<<uint64(d))])
 (ORNshiftRL x (MOVDconst [c]) [d]) => (ORconst  x [^int64(uint64(c)>>uint64(d))])
 (ORNshiftRA x (MOVDconst [c]) [d]) => (ORconst  x [^(c>>uint64(d))])
+(ORNshiftRO x (MOVDconst [c]) [d]) => (ORconst  x [^rotateRight64(c, d)])
 (EONshiftLL x (MOVDconst [c]) [d]) => (XORconst x [^int64(uint64(c)<<uint64(d))])
 (EONshiftRL x (MOVDconst [c]) [d]) => (XORconst x [^int64(uint64(c)>>uint64(d))])
 (EONshiftRA x (MOVDconst [c]) [d]) => (XORconst x [^(c>>uint64(d))])
+(EONshiftRO x (MOVDconst [c]) [d]) => (XORconst x [^rotateRight64(c, d)])
 (CMPshiftLL x (MOVDconst [c]) [d]) => (CMPconst x [int64(uint64(c)<<uint64(d))])
 (CMPshiftRL x (MOVDconst [c]) [d]) => (CMPconst x [int64(uint64(c)>>uint64(d))])
 (CMPshiftRA x (MOVDconst [c]) [d]) => (CMPconst x [c>>uint64(d)])
 (TSTshiftLL x (MOVDconst [c]) [d]) => (TSTconst x [int64(uint64(c)<<uint64(d))])
 (TSTshiftRL x (MOVDconst [c]) [d]) => (TSTconst x [int64(uint64(c)>>uint64(d))])
 (TSTshiftRA x (MOVDconst [c]) [d]) => (TSTconst x [c>>uint64(d)])
+(TSTshiftRO x (MOVDconst [c]) [d]) => (TSTconst x [rotateRight64(c, d)])
 
 // simplification with *shift ops
-(SUBshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
-(SUBshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
-(SUBshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
-(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d => y
-(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d => y
-(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d => y
-(ORshiftLL  x y:(SLLconst x [c]) [d]) && c==d => y
-(ORshiftRL  x y:(SRLconst x [c]) [d]) && c==d => y
-(ORshiftRA  x y:(SRAconst x [c]) [d]) && c==d => y
-(XORshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
-(XORshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
-(XORshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
-(BICshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [0])
-(BICshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [0])
-(BICshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [0])
-(EONshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [-1])
-(EONshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [-1])
-(EONshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [-1])
-(ORNshiftLL x (SLLconst x [c]) [d]) && c==d => (MOVDconst [-1])
-(ORNshiftRL x (SRLconst x [c]) [d]) && c==d => (MOVDconst [-1])
-(ORNshiftRA x (SRAconst x [c]) [d]) && c==d => (MOVDconst [-1])
+(SUBshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
+(SUBshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
+(SUBshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
+(ANDshiftLL y:(SLLconst x [c]) x [c]) => y
+(ANDshiftRL y:(SRLconst x [c]) x [c]) => y
+(ANDshiftRA y:(SRAconst x [c]) x [c]) => y
+(ANDshiftRO y:(RORconst x [c]) x [c]) => y
+(ORshiftLL  y:(SLLconst x [c]) x [c]) => y
+(ORshiftRL  y:(SRLconst x [c]) x [c]) => y
+(ORshiftRA  y:(SRAconst x [c]) x [c]) => y
+(ORshiftRO  y:(RORconst x [c]) x [c]) => y
+(XORshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
+(XORshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
+(XORshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
+(XORshiftRO (RORconst x [c]) x [c]) => (MOVDconst [0])
+(BICshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [0])
+(BICshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [0])
+(BICshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [0])
+(BICshiftRO (RORconst x [c]) x [c]) => (MOVDconst [0])
+(EONshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [-1])
+(EONshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [-1])
+(EONshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [-1])
+(EONshiftRO (RORconst x [c]) x [c]) => (MOVDconst [-1])
+(ORNshiftLL (SLLconst x [c]) x [c]) => (MOVDconst [-1])
+(ORNshiftRL (SRLconst x [c]) x [c]) => (MOVDconst [-1])
+(ORNshiftRA (SRAconst x [c]) x [c]) => (MOVDconst [-1])
+(ORNshiftRO (RORconst x [c]) x [c]) => (MOVDconst [-1])
 
 // Generate rotates with const shift
 (ADDshiftLL [c] (SRLconst x [64-c]) x) => (RORconst [64-c] x)
 // sbfiz
 // (x << lc) >> rc
 (SRAconst [rc] (SLLconst [lc] x)) && lc > rc => (SBFIZ [armBFAuxInt(lc-rc, 64-lc)] x)
+// int64(x << lc)
 (MOVWreg (SLLconst [lc] x)) && lc < 32 => (SBFIZ [armBFAuxInt(lc, 32-lc)] x)
 (MOVHreg (SLLconst [lc] x)) && lc < 16 => (SBFIZ [armBFAuxInt(lc, 16-lc)] x)
 (MOVBreg (SLLconst [lc] x)) && lc < 8 => (SBFIZ [armBFAuxInt(lc, 8-lc)] x)
+// int64(x) << lc
+(SLLconst [lc] (MOVWreg x))  => (SBFIZ [armBFAuxInt(lc, min(32, 64-lc))] x)
+(SLLconst [lc] (MOVHreg x))  => (SBFIZ [armBFAuxInt(lc, min(16, 64-lc))] x)
+(SLLconst [lc] (MOVBreg x))  => (SBFIZ [armBFAuxInt(lc, min(8, 64-lc))] x)
 
 // sbfx
 // (x << lc) >> rc
 (SRAconst [rc] (SLLconst [lc] x)) && lc <= rc => (SBFX [armBFAuxInt(rc-lc, 64-rc)] x)
+// int64(x) >> rc
 (SRAconst [rc] (MOVWreg x)) && rc < 32 => (SBFX [armBFAuxInt(rc, 32-rc)] x)
 (SRAconst [rc] (MOVHreg x)) && rc < 16 => (SBFX [armBFAuxInt(rc, 16-rc)] x)
 (SRAconst [rc] (MOVBreg x)) && rc < 8 => (SBFX [armBFAuxInt(rc, 8-rc)] x)
+// merge sbfx and sign-extension into sbfx
+(MOVWreg (SBFX [bfc] x)) && bfc.getARM64BFwidth() <= 32 => (SBFX [bfc] x)
+(MOVHreg (SBFX [bfc] x)) && bfc.getARM64BFwidth() <= 16 => (SBFX [bfc] x)
+(MOVBreg (SBFX [bfc] x)) && bfc.getARM64BFwidth() <=  8 => (SBFX [bfc] x)
 
 // sbfiz/sbfx combinations: merge shifts into bitfield ops
 (SRAconst [sc] (SBFIZ [bfc] x)) && sc < bfc.getARM64BFlsb()
        => (SBFX [armBFAuxInt(sc-bfc.getARM64BFlsb(), bfc.getARM64BFlsb()+bfc.getARM64BFwidth()-sc)] x)
 
 // ubfiz
+// (x << lc) >> rc
+(SRLconst [rc] (SLLconst [lc] x)) && lc > rc => (UBFIZ [armBFAuxInt(lc-rc, 64-lc)] x)
+// uint64(x) << lc
+(SLLconst [lc] (MOVWUreg x))  => (UBFIZ [armBFAuxInt(lc, min(32, 64-lc))] x)
+(SLLconst [lc] (MOVHUreg x))  => (UBFIZ [armBFAuxInt(lc, min(16, 64-lc))] x)
+(SLLconst [lc] (MOVBUreg x))  => (UBFIZ [armBFAuxInt(lc, min(8, 64-lc))] x)
+// uint64(x << lc)
+(MOVWUreg (SLLconst [lc] x)) && lc < 32 => (UBFIZ [armBFAuxInt(lc, 32-lc)] x)
+(MOVHUreg (SLLconst [lc] x)) && lc < 16 => (UBFIZ [armBFAuxInt(lc, 16-lc)] x)
+(MOVBUreg (SLLconst [lc] x)) && lc < 8 => (UBFIZ [armBFAuxInt(lc, 8-lc)] x)
+
+// merge ANDconst into ubfiz
 // (x & ac) << sc
 (SLLconst [sc] (ANDconst [ac] x)) && isARM64BFMask(sc, ac, 0)
        => (UBFIZ [armBFAuxInt(sc, arm64BFWidth(ac, 0))] x)
-(SLLconst [sc] (MOVWUreg x)) && isARM64BFMask(sc, 1<<32-1, 0) => (UBFIZ [armBFAuxInt(sc, 32)] x)
-(SLLconst [sc] (MOVHUreg x)) && isARM64BFMask(sc, 1<<16-1, 0) => (UBFIZ [armBFAuxInt(sc, 16)] x)
-(SLLconst [sc] (MOVBUreg x)) && isARM64BFMask(sc, 1<<8-1, 0) => (UBFIZ [armBFAuxInt(sc, 8)] x)
 // (x << sc) & ac
 (ANDconst [ac] (SLLconst [sc] x)) && isARM64BFMask(sc, ac, sc)
        => (UBFIZ [armBFAuxInt(sc, arm64BFWidth(ac, sc))] x)
-(MOVWUreg (SLLconst [sc] x)) && isARM64BFMask(sc, 1<<32-1, sc)
-       => (UBFIZ [armBFAuxInt(sc, arm64BFWidth(1<<32-1, sc))] x)
-(MOVHUreg (SLLconst [sc] x)) && isARM64BFMask(sc, 1<<16-1, sc)
-       => (UBFIZ [armBFAuxInt(sc, arm64BFWidth(1<<16-1, sc))] x)
-(MOVBUreg (SLLconst [sc] x)) && isARM64BFMask(sc, 1<<8-1, sc)
-       => (UBFIZ [armBFAuxInt(sc, arm64BFWidth(1<<8-1, sc))] x)
-// (x << lc) >> rc
-(SRLconst [rc] (SLLconst [lc] x)) && lc > rc => (UBFIZ [armBFAuxInt(lc-rc, 64-lc)] x)
 
 // ubfx
+// (x << lc) >> rc
+(SRLconst [rc] (SLLconst [lc] x)) && lc < rc => (UBFX [armBFAuxInt(rc-lc, 64-rc)] x)
+// uint64(x) >> rc
+(SRLconst [rc] (MOVWUreg x)) && rc < 32 => (UBFX [armBFAuxInt(rc, 32-rc)] x)
+(SRLconst [rc] (MOVHUreg x)) && rc < 16 => (UBFX [armBFAuxInt(rc, 16-rc)] x)
+(SRLconst [rc] (MOVBUreg x)) && rc < 8 => (UBFX [armBFAuxInt(rc, 8-rc)] x)
+// uint64(x >> rc)
+(MOVWUreg (SRLconst [rc] x)) && rc < 32 => (UBFX [armBFAuxInt(rc, 32)] x)
+(MOVHUreg (SRLconst [rc] x)) && rc < 16 => (UBFX [armBFAuxInt(rc, 16)] x)
+(MOVBUreg (SRLconst [rc] x)) && rc < 8 => (UBFX [armBFAuxInt(rc, 8)] x)
+// merge ANDconst into ubfx
 // (x >> sc) & ac
 (ANDconst [ac] (SRLconst [sc] x)) && isARM64BFMask(sc, ac, 0)
        => (UBFX [armBFAuxInt(sc, arm64BFWidth(ac, 0))] x)
-(MOVWUreg (SRLconst [sc] x)) && isARM64BFMask(sc, 1<<32-1, 0) => (UBFX [armBFAuxInt(sc, 32)] x)
-(MOVHUreg (SRLconst [sc] x)) && isARM64BFMask(sc, 1<<16-1, 0) => (UBFX [armBFAuxInt(sc, 16)] x)
-(MOVBUreg (SRLconst [sc] x)) && isARM64BFMask(sc, 1<<8-1, 0) => (UBFX [armBFAuxInt(sc, 8)] x)
 // (x & ac) >> sc
 (SRLconst [sc] (ANDconst [ac] x)) && isARM64BFMask(sc, ac, sc)
        => (UBFX [armBFAuxInt(sc, arm64BFWidth(ac, sc))] x)
-(SRLconst [sc] (MOVWUreg x)) && isARM64BFMask(sc, 1<<32-1, sc)
-       => (UBFX [armBFAuxInt(sc, arm64BFWidth(1<<32-1, sc))] x)
-(SRLconst [sc] (MOVHUreg x)) && isARM64BFMask(sc, 1<<16-1, sc)
-       => (UBFX [armBFAuxInt(sc, arm64BFWidth(1<<16-1, sc))] x)
-(SRLconst [sc] (MOVBUreg x)) && isARM64BFMask(sc, 1<<8-1, sc)
-       => (UBFX [armBFAuxInt(sc, arm64BFWidth(1<<8-1, sc))] x)
-// (x << lc) >> rc
-(SRLconst [rc] (SLLconst [lc] x)) && lc < rc => (UBFX [armBFAuxInt(rc-lc, 64-rc)] x)
+
+// merge ubfx and zerso-extension into ubfx
+(MOVWUreg (UBFX [bfc] x)) && bfc.getARM64BFwidth() <= 32 => (UBFX [bfc] x)
+(MOVHUreg (UBFX [bfc] x)) && bfc.getARM64BFwidth() <= 16 => (UBFX [bfc] x)
+(MOVBUreg (UBFX [bfc] x)) && bfc.getARM64BFwidth() <=  8 => (UBFX [bfc] x)
 
 // ubfiz/ubfx combinations: merge shifts into bitfield ops
 (SRLconst [sc] (UBFX [bfc] x)) && sc < bfc.getARM64BFwidth()
 (MOVWUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))])
 (MOVDload  [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read64(sym, int64(off), config.ctxt.Arch.ByteOrder))])
 
+// Prefetch instructions (aux is option: 0 - PLDL1KEEP; 1 - PLDL1STRM)
+(PrefetchCache addr mem)         => (PRFM [0] addr mem)
+(PrefetchCacheStreamed addr mem) => (PRFM [1] addr mem)
+
 // Arch-specific inlining for small or disjoint runtime.memmove
 (SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore  _ src s3:(MOVDstore {t} _ dst mem)))))
        && sz >= 0
        && isInlinableMemmove(dst, src, sz, config)
        && clobber(call)
        => (Move [sz] dst src mem)
+
+((REV|REVW) ((REV|REVW) p)) => p
index 5de0b5f02031fc2ac980278a6becde57a0f5f407..e052ce09f423bee903fe537da9655546d7a572c2 100644 (file)
@@ -175,6 +175,7 @@ func init() {
                fpstore        = regInfo{inputs: []regMask{gpspsbg, fp}}
                fpstore2       = regInfo{inputs: []regMask{gpspsbg, gpg, fp}}
                readflags      = regInfo{inputs: nil, outputs: []regMask{gp}}
+               prefreg        = regInfo{inputs: []regMask{gpspsbg}}
        )
        ops := []opData{
                // binary ops
@@ -301,6 +302,7 @@ func init() {
                {name: "MVNshiftLL", argLength: 1, reg: gp11, asm: "MVN", aux: "Int64"},                   // ^(arg0<<auxInt), auxInt should be in the range 0 to 63.
                {name: "MVNshiftRL", argLength: 1, reg: gp11, asm: "MVN", aux: "Int64"},                   // ^(arg0>>auxInt), unsigned shift, auxInt should be in the range 0 to 63.
                {name: "MVNshiftRA", argLength: 1, reg: gp11, asm: "MVN", aux: "Int64"},                   // ^(arg0>>auxInt), signed shift, auxInt should be in the range 0 to 63.
+               {name: "MVNshiftRO", argLength: 1, reg: gp11, asm: "MVN", aux: "Int64"},                   // ^(arg0 ROR auxInt), signed shift, auxInt should be in the range 0 to 63.
                {name: "NEGshiftLL", argLength: 1, reg: gp11, asm: "NEG", aux: "Int64"},                   // -(arg0<<auxInt), auxInt should be in the range 0 to 63.
                {name: "NEGshiftRL", argLength: 1, reg: gp11, asm: "NEG", aux: "Int64"},                   // -(arg0>>auxInt), unsigned shift, auxInt should be in the range 0 to 63.
                {name: "NEGshiftRA", argLength: 1, reg: gp11, asm: "NEG", aux: "Int64"},                   // -(arg0>>auxInt), signed shift, auxInt should be in the range 0 to 63.
@@ -313,21 +315,27 @@ func init() {
                {name: "ANDshiftLL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"},                   // arg0 & (arg1<<auxInt), auxInt should be in the range 0 to 63.
                {name: "ANDshiftRL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"},                   // arg0 & (arg1>>auxInt), unsigned shift, auxInt should be in the range 0 to 63.
                {name: "ANDshiftRA", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"},                   // arg0 & (arg1>>auxInt), signed shift, auxInt should be in the range 0 to 63.
+               {name: "ANDshiftRO", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"},                   // arg0 & (arg1 ROR auxInt), signed shift, auxInt should be in the range 0 to 63.
                {name: "ORshiftLL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"},                    // arg0 | arg1<<auxInt, auxInt should be in the range 0 to 63.
                {name: "ORshiftRL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"},                    // arg0 | arg1>>auxInt, unsigned shift, auxInt should be in the range 0 to 63.
                {name: "ORshiftRA", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"},                    // arg0 | arg1>>auxInt, signed shift, auxInt should be in the range 0 to 63.
+               {name: "ORshiftRO", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"},                    // arg0 | arg1 ROR auxInt, signed shift, auxInt should be in the range 0 to 63.
                {name: "XORshiftLL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"},                   // arg0 ^ arg1<<auxInt, auxInt should be in the range 0 to 63.
                {name: "XORshiftRL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"},                   // arg0 ^ arg1>>auxInt, unsigned shift, auxInt should be in the range 0 to 63.
                {name: "XORshiftRA", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"},                   // arg0 ^ arg1>>auxInt, signed shift, auxInt should be in the range 0 to 63.
+               {name: "XORshiftRO", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"},                   // arg0 ^ arg1 ROR auxInt, signed shift, auxInt should be in the range 0 to 63.
                {name: "BICshiftLL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"},                   // arg0 &^ (arg1<<auxInt), auxInt should be in the range 0 to 63.
                {name: "BICshiftRL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"},                   // arg0 &^ (arg1>>auxInt), unsigned shift, auxInt should be in the range 0 to 63.
                {name: "BICshiftRA", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"},                   // arg0 &^ (arg1>>auxInt), signed shift, auxInt should be in the range 0 to 63.
+               {name: "BICshiftRO", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"},                   // arg0 &^ (arg1 ROR auxInt), signed shift, auxInt should be in the range 0 to 63.
                {name: "EONshiftLL", argLength: 2, reg: gp21, asm: "EON", aux: "Int64"},                   // arg0 ^ ^(arg1<<auxInt), auxInt should be in the range 0 to 63.
                {name: "EONshiftRL", argLength: 2, reg: gp21, asm: "EON", aux: "Int64"},                   // arg0 ^ ^(arg1>>auxInt), unsigned shift, auxInt should be in the range 0 to 63.
                {name: "EONshiftRA", argLength: 2, reg: gp21, asm: "EON", aux: "Int64"},                   // arg0 ^ ^(arg1>>auxInt), signed shift, auxInt should be in the range 0 to 63.
+               {name: "EONshiftRO", argLength: 2, reg: gp21, asm: "EON", aux: "Int64"},                   // arg0 ^ ^(arg1 ROR auxInt), signed shift, auxInt should be in the range 0 to 63.
                {name: "ORNshiftLL", argLength: 2, reg: gp21, asm: "ORN", aux: "Int64"},                   // arg0 | ^(arg1<<auxInt), auxInt should be in the range 0 to 63.
                {name: "ORNshiftRL", argLength: 2, reg: gp21, asm: "ORN", aux: "Int64"},                   // arg0 | ^(arg1>>auxInt), unsigned shift, auxInt should be in the range 0 to 63.
                {name: "ORNshiftRA", argLength: 2, reg: gp21, asm: "ORN", aux: "Int64"},                   // arg0 | ^(arg1>>auxInt), signed shift, auxInt should be in the range 0 to 63.
+               {name: "ORNshiftRO", argLength: 2, reg: gp21, asm: "ORN", aux: "Int64"},                   // arg0 | ^(arg1 ROR auxInt), signed shift, auxInt should be in the range 0 to 63.
                {name: "CMPshiftLL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1<<auxInt, auxInt should be in the range 0 to 63.
                {name: "CMPshiftRL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, unsigned shift, auxInt should be in the range 0 to 63.
                {name: "CMPshiftRA", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, signed shift, auxInt should be in the range 0 to 63.
@@ -337,6 +345,7 @@ func init() {
                {name: "TSTshiftLL", argLength: 2, reg: gp2flags, asm: "TST", aux: "Int64", typ: "Flags"}, // (arg0 & arg1<<auxInt) compare to 0, auxInt should be in the range 0 to 63.
                {name: "TSTshiftRL", argLength: 2, reg: gp2flags, asm: "TST", aux: "Int64", typ: "Flags"}, // (arg0 & arg1>>auxInt) compare to 0, unsigned shift, auxInt should be in the range 0 to 63.
                {name: "TSTshiftRA", argLength: 2, reg: gp2flags, asm: "TST", aux: "Int64", typ: "Flags"}, // (arg0 & arg1>>auxInt) compare to 0, signed shift, auxInt should be in the range 0 to 63.
+               {name: "TSTshiftRO", argLength: 2, reg: gp2flags, asm: "TST", aux: "Int64", typ: "Flags"}, // (arg0 & arg1 ROR auxInt) compare to 0, signed shift, auxInt should be in the range 0 to 63.
 
                // bitfield ops
                // for all bitfield ops lsb is auxInt>>8, width is auxInt&0xff
@@ -483,6 +492,7 @@ func init() {
 
                // function calls
                {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                               // call static function aux.(*obj.LSym).  last arg=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                 // tail call static function aux.(*obj.LSym).  last arg=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{gpsp, buildReg("R26"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, last arg=mem, auxint=argsize, returns mem
 
@@ -729,6 +739,13 @@ func init() {
                {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
                {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
                {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r0, r1}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
+
+               // Prefetch instruction
+               // Do prefetch arg0 address with option aux. arg0=addr, arg1=memory, aux=option.
+               {name: "PRFM", argLength: 2, aux: "Int64", reg: prefreg, asm: "PRFM", hasSideEffects: true},
+
+               // Publication barrier
+               {name: "DMB", argLength: 1, aux: "Int64", asm: "DMB", hasSideEffects: true}, // Do data barrier. arg0=memory, aux=option.
        }
 
        blocks := []blockData{
index d1f86039a36e5c98ab7d6681928d67ea50e66302..2f004205a55b357406a8f5cc32b42eeba653a0a8 100644 (file)
@@ -228,14 +228,15 @@ func init() {
 
                // shifts
                {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 256
-               {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
+               {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, 0 <= auxInt < 32
                {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 256
-               {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
+               {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned, 0 <= auxInt < 32
                {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 256
-               {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
+               {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, 0 <= auxInt < 32
                {name: "SRR", argLength: 2, reg: gp21},                                // arg0 right rotate by arg1 bits
-               {name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"},             // arg0 right rotate by auxInt bits
+               {name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"},             // arg0 right rotate by auxInt bits, 0 <= auxInt < 32
 
+               // auxInt for all of these satisfy 0 <= auxInt < 32
                {name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt
                {name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift
                {name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift
@@ -431,6 +432,7 @@ func init() {
 
                // function calls
                {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                              // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                        // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
index 4ac9668ea9cb566154a506ba1c3c0ecac7a144e7..639dda4b075492d3d8a499b71fa6616a2cbcb10c 100644 (file)
 (StaticCall ...)  => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...)   => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // atomic intrinsics
 (AtomicLoad(8|32) ...) => (LoweredAtomicLoad(8|32) ...)
index fd04a6c3a85c7ae768fa36d3a4a9bafb65b53012..292ff2fc7966092fac267f78a39a1d939e221c12 100644 (file)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // atomic intrinsics
 (AtomicLoad(8|32|64) ...) => (LoweredAtomicLoad(8|32|64) ...)
index a18cd4289d4fc6b735311158e994ec1b4b8c1155..7b18c42ffb91e35c73e202a7e0b62f9dbb3b9754 100644 (file)
@@ -276,6 +276,7 @@ func init() {
 
                // function calls
                {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                               // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                 // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
index 8177c7e2d17cfff541418718755150f7947cf54c..523847badc9ce2d77db0c54757e81e50e2d706bd 100644 (file)
@@ -258,6 +258,7 @@ func init() {
 
                // function calls
                {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                               // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                 //  tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
index ce4b324b5e10227bef0406b69f33b2bdef3652c9..c3f07a4e22cf3929a4af63e5a7482d70d7aafa60 100644 (file)
 ((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(OR x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (ORCC x y) yes no)
 ((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(XOR x y)) yes no) && z.Uses == 1 => ((EQ|NE|LT|LE|GT|GE) (XORCC x y) yes no)
 
-(CondSelect x y bool) && flagArg(bool) != nil => (ISEL [2] x y bool)
-(CondSelect x y bool) && flagArg(bool) == nil => (ISEL [2] x y (CMPWconst [0] bool))
+// Only lower after bool is lowered. It should always lower. This helps ensure the folding below happens reliably.
+(CondSelect x y bool) && flagArg(bool) == nil => (ISEL [6] x y (CMPWconst [0] bool))
+// Fold any CR -> GPR -> CR transfers when applying the above rule.
+(ISEL [6] x y (CMPWconst [0] (ISELB [c] one cmp))) => (ISEL [c] x y cmp)
 
 // Lowering loads
 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) => (MOVDload ptr mem)
 (Store {t} ptr val mem) && t.Size() == 8 && is64BitFloat(val.Type) => (FMOVDstore ptr val mem)
 (Store {t} ptr val mem) && t.Size() == 8 && is32BitFloat(val.Type) => (FMOVDstore ptr val mem) // glitch from (Cvt32Fto64F x) => x -- type is wrong
 (Store {t} ptr val mem) && t.Size() == 4 && is32BitFloat(val.Type) => (FMOVSstore ptr val mem)
-(Store {t} ptr val mem) && t.Size() == 8 && (is64BitInt(val.Type) || isPtr(val.Type)) => (MOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.Size() == 8 && !is64BitFloat(val.Type) => (MOVDstore ptr val mem)
 (Store {t} ptr val mem) && t.Size() == 4 && is32BitInt(val.Type) => (MOVWstore ptr val mem)
 (Store {t} ptr val mem) && t.Size() == 2 => (MOVHstore ptr val mem)
 (Store {t} ptr val mem) && t.Size() == 1 => (MOVBstore ptr val mem)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // Miscellaneous
 (GetClosurePtr ...) => (LoweredGetClosurePtr ...)
 (ADDconst [c] (SUBFCconst [d] x)) && is32Bit(c+d) => (SUBFCconst [c+d] x)
 (NEG (ADDconst [c] x)) && is32Bit(-c) => (SUBFCconst [-c] x)
 (NEG (SUBFCconst [c] x)) && is32Bit(-c) => (ADDconst [-c] x)
+(NEG (SUB x y)) => (SUB y x)
+(NEG (NEG x)) => x
 
 // Use register moves instead of stores and loads to move int<=>float values
 // Common with math Float64bits, Float64frombits
 (MOVWZreg x:(MOVWZloadidx _ _ _)) => x
 (MOVWreg x:(MOVWload _ _)) => x
 (MOVWreg x:(MOVWloadidx _ _ _)) => x
+(MOVBZreg x:(Select0 (LoweredAtomicLoad8 _ _))) => x
+(MOVWZreg x:(Select0 (LoweredAtomicLoad32 _ _))) => x
 
 // don't extend if argument is already extended
 (MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) => x
 ((CMP|CMPW|CMPU|CMPWU) x y) && canonLessThan(x,y) => (InvertFlags ((CMP|CMPW|CMPU|CMPWU) y x))
 
 // ISEL auxInt values 0=LT 1=GT 2=EQ   arg2 ? arg0 : arg1
-// ISEL auxInt values 4=GE 5=LE 6=NE   arg2 ? arg1 : arg0
+// ISEL auxInt values 4=GE 5=LE 6=NE   !arg2 ? arg1 : arg0
 // ISELB special case where arg0, arg1 values are 0, 1
 
 (Equal cmp) => (ISELB [2] (MOVDconst [1]) cmp)
 (ISEL [n] x y (InvertFlags bool)) && n%4 == 0 => (ISEL [n+1] x y bool)
 (ISEL [n] x y (InvertFlags bool)) && n%4 == 1 => (ISEL [n-1] x y bool)
 (ISEL [n] x y (InvertFlags bool)) && n%4 == 2 => (ISEL [n] x y bool)
+(XORconst [1] (ISELB [6] (MOVDconst [1]) cmp)) => (ISELB [2] (MOVDconst [1]) cmp)
+(XORconst [1] (ISELB [5] (MOVDconst [1]) cmp)) => (ISELB [1] (MOVDconst [1]) cmp)
+(XORconst [1] (ISELB [4] (MOVDconst [1]) cmp)) => (ISELB [0] (MOVDconst [1]) cmp)
 
 // A particular pattern seen in cgo code:
 (AND (MOVDconst [c]) x:(MOVBZload _ _)) => (ANDconst [c&0xFF] x)
         && i1 == i0+1 && i2 == i0+2 && i3 == i0+3 && i4 == i0+4 && i5 == i0+5 && i6 == i0+6 && i7 == i0+7
         && clobber(x0, x1, x2, x3, x4, x5, x6)
           => (MOVDBRstore (MOVDaddr <typ.Uintptr> [i0] {s} p) w mem)
+
+// Arch-specific inlining for small or disjoint runtime.memmove
+(SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore  _ src s3:(MOVDstore {t} _ dst mem)))))
+        && sz >= 0
+        && isSameCall(sym, "runtime.memmove")
+        && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1
+        && isInlinableMemmove(dst, src, sz, config)
+        && clobber(s1, s2, s3, call)
+        => (Move [sz] dst src mem)
+
+// Match post-lowering calls, register version.
+(SelectN [0] call:(CALLstatic {sym} dst src (MOVDconst [sz]) mem))
+        && sz >= 0
+        && isSameCall(sym, "runtime.memmove")
+        && call.Uses == 1
+        && isInlinableMemmove(dst, src, sz, config)
+        && clobber(call)
+        => (Move [sz] dst src mem)
+
+// Prefetch instructions (aux is option: 0 - DCBT ; 8 - DCBT stream)
+(PrefetchCache ptr mem)          => (DCBT ptr mem [0])
+(PrefetchCacheStreamed ptr mem)  => (DCBT ptr mem [8])
+
index d7d8a33a0a10a52f8bd19ddb5ab2f5bbdc14e1cc..59d8af1a9d3952fb1bfeee88af01200fc618cf6a 100644 (file)
@@ -149,6 +149,7 @@ func init() {
                crgp21      = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
                gpload      = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
                gploadidx   = regInfo{inputs: []regMask{gp | sp | sb, gp}, outputs: []regMask{gp}}
+               prefreg     = regInfo{inputs: []regMask{gp | sp | sb}}
                gpstore     = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
                gpstoreidx  = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}}
                gpstorezero = regInfo{inputs: []regMask{gp | sp | sb}} // ppc64.REGZERO is reserved zero value
@@ -336,6 +337,10 @@ func init() {
                {name: "FMOVDloadidx", argLength: 3, reg: fploadidx, asm: "FMOVD", typ: "Float64"},
                {name: "FMOVSloadidx", argLength: 3, reg: fploadidx, asm: "FMOVS", typ: "Float32"},
 
+               // Prefetch instruction
+               // Do prefetch of address generated with arg0 and arg1 with option aux. arg0=addr,arg1=memory, aux=option.
+               {name: "DCBT", argLength: 2, aux: "Int64", reg: prefreg, asm: "DCBT", hasSideEffects: true},
+
                // Store bytes in the reverse endian order of the arch into arg0.
                // These are indexed stores with no offset field in the instruction so the auxint fields are not used.
                {name: "MOVDBRstore", argLength: 3, reg: gpstore, asm: "MOVDBR", aux: "Sym", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes reverse order
@@ -391,7 +396,7 @@ func init() {
                {name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
 
                // ISEL auxInt values 0=LT 1=GT 2=EQ   arg2 ? arg0 : arg1
-               // ISEL auxInt values 4=GE 5=LE 6=NE   arg2 ? arg1 : arg0
+               // ISEL auxInt values 4=GE 5=LE 6=NE   !arg2 ? arg1 : arg0
                // ISELB special case where arg0, arg1 values are 0, 1 for boolean result
                {name: "ISEL", argLength: 3, reg: crgp21, asm: "ISEL", aux: "Int32", typ: "Int32"},  // see above
                {name: "ISELB", argLength: 2, reg: crgp11, asm: "ISEL", aux: "Int32", typ: "Int32"}, // see above
@@ -428,9 +433,10 @@ func init() {
                {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
                {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true},
 
-               {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                       // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
-               {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{callptr, ctxt, 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-               {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},            // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+               {name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                       // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                         // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{callptr, ctxt, 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
+               {name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{callptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},            // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
                // large or unaligned zeroing
                // arg0 = address of memory to zero (in R3, changed as side effect)
@@ -704,15 +710,17 @@ func init() {
        }
 
        archs = append(archs, arch{
-               name:            "PPC64",
-               pkg:             "cmd/internal/obj/ppc64",
-               genfile:         "../../ppc64/ssa.go",
-               ops:             ops,
-               blocks:          blocks,
-               regnames:        regNamesPPC64,
-               gpregmask:       gp,
-               fpregmask:       fp,
-               framepointerreg: int8(num["SP"]),
-               linkreg:         -1, // not used
+               name:               "PPC64",
+               pkg:                "cmd/internal/obj/ppc64",
+               genfile:            "../../ppc64/ssa.go",
+               ops:                ops,
+               blocks:             blocks,
+               regnames:           regNamesPPC64,
+               ParamIntRegNames:   "R3 R4 R5 R6 R7 R8 R9 R10 R14 R15 R16 R17",
+               ParamFloatRegNames: "F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12",
+               gpregmask:          gp,
+               fpregmask:          fp,
+               framepointerreg:    -1,
+               linkreg:            -1, // not used
        })
 }
index 9cdd62edbe01c004f4b79951d38a4d5cd123a2a3..3379e1dac50cc36720367505e474cc4fba901e78 100644 (file)
@@ -6,9 +6,7 @@
 // * Use SLTI and SLTIU for comparisons to constants, instead of SLT/SLTU with constants in registers
 // * Use the zero register instead of moving 0 into a register.
 // * Add rules to avoid generating a temp bool value for (If (SLT[U] ...) ...).
-// * Optimize left and right shift by simplifying SLTIU, Neg, and ADD for constants.
 // * Arrange for non-trivial Zero and Move lowerings to use aligned loads and stores.
-// * Eliminate zero immediate shifts, adds, etc.
 // * Avoid using Neq32 for writeBarrier.enabled checks.
 
 // Lowering arithmetic
@@ -29,6 +27,8 @@
 (Sub64F ...) => (FSUBD ...)
 
 (Mul64 ...) => (MUL  ...)
+(Mul64uhilo ...) => (LoweredMuluhilo ...)
+(Mul64uover ...) => (LoweredMuluover ...)
 (Mul32 ...) => (MULW ...)
 (Mul16 x y) => (MULW (SignExt16to32 x) (SignExt16to32 y))
 (Mul8 x y)  => (MULW (SignExt8to32 x)  (SignExt8to32 y))
 (Sqrt ...) => (FSQRTD ...)
 (Sqrt32 ...) => (FSQRTS ...)
 
+(Copysign ...) => (FSGNJD ...)
+
+(Abs ...) => (FABSD ...)
+
+(FMA ...) => (FMADDD ...)
+
 // Sign and zero extension.
 
 (SignExt8to16  ...) => (MOVBreg ...)
 (Rsh64x32 <t> x y) => (SRA <t> x                 (OR <y.Type> y (ADDI <y.Type> [-1] (SLTIU <y.Type> [64] (ZeroExt32to64 y)))))
 (Rsh64x64 <t> x y) => (SRA <t> x                 (OR <y.Type> y (ADDI <y.Type> [-1] (SLTIU <y.Type> [64] y))))
 
-// rotates
+// Rotates.
 (RotateLeft8  <t> x (MOVDconst [c])) => (Or8  (Lsh8x64  <t> x (MOVDconst [c&7]))  (Rsh8Ux64  <t> x (MOVDconst [-c&7])))
 (RotateLeft16 <t> x (MOVDconst [c])) => (Or16 (Lsh16x64 <t> x (MOVDconst [c&15])) (Rsh16Ux64 <t> x (MOVDconst [-c&15])))
 (RotateLeft32 <t> x (MOVDconst [c])) => (Or32 (Lsh32x64 <t> x (MOVDconst [c&31])) (Rsh32Ux64 <t> x (MOVDconst [-c&31])))
 (StaticCall  ...) => (CALLstatic  ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall   ...) => (CALLinter   ...)
+(TailCall ...) => (CALLtail ...)
 
 // Atomic Intrinsics
 (AtomicLoad8   ...) => (LoweredAtomicLoad8  ...)
 (BNEZ (SEQZ x) yes no) => (BEQZ x yes no)
 (BNEZ (SNEZ x) yes no) => (BNEZ x yes no)
 
+// Absorb NEG into branch when possible.
+(BEQZ x:(NEG y) yes no) && x.Uses == 1 => (BEQZ y yes no)
+(BNEZ x:(NEG y) yes no) && x.Uses == 1 => (BNEZ y 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 (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.
+// Convert branch with zero to more optimal branch zero.
 (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)
+(BLT (MOVDconst [0]) cond yes no) => (BGTZ cond yes no)
+(BLT cond (MOVDconst [0]) yes no) => (BLTZ cond yes no)
+(BGE (MOVDconst [0]) cond yes no) => (BLEZ cond yes no)
+(BGE cond (MOVDconst [0]) yes no) => (BGEZ cond yes no)
 
 // Store zero
 (MOVBstore [off] {sym} ptr (MOVDconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
 (SUB x (MOVDconst [val])) && is32Bit(-val) => (ADDI [-val] x)
 
 // Subtraction of zero.
-(SUB x (MOVDconst [0])) => x
-
-// Subtraction of zero with sign extension.
+(SUB  x (MOVDconst [0])) => x
 (SUBW x (MOVDconst [0])) => (ADDIW [0] x)
 
 // Subtraction from zero.
-(SUB (MOVDconst [0]) x) => (NEG x)
-
-// Subtraction from zero with sign extension.
+(SUB  (MOVDconst [0]) x) => (NEG x)
 (SUBW (MOVDconst [0]) x) => (NEGW x)
 
-// Addition of zero.
+// Addition of zero or two constants.
 (ADDI [0] x) => x
+(ADDI [x] (MOVDconst [y])) && is32Bit(x + y) => (MOVDconst [x + y])
+
+// ANDI with all zeros, all ones or two constants.
+(ANDI [0]  x) => (MOVDconst [0])
+(ANDI [-1] x) => x
+(ANDI [x] (MOVDconst [y])) => (MOVDconst [x & y])
+
+// ORI with all zeroes, all ones or two constants.
+(ORI [0]  x) => x
+(ORI [-1] x) => (MOVDconst [-1])
+(ORI [x] (MOVDconst [y])) => (MOVDconst [x | y])
+
+// Negation of a constant.
+(NEG  (MOVDconst [x])) => (MOVDconst [-x])
+(NEGW (MOVDconst [x])) => (MOVDconst [int64(int32(-x))])
+
+// Shift of a constant.
+(SLLI [x] (MOVDconst [y])) && is32Bit(y << x) => (MOVDconst [y << x])
+(SRLI [x] (MOVDconst [y])) => (MOVDconst [int64(uint64(y) >> x)])
+(SRAI [x] (MOVDconst [y])) => (MOVDconst [int64(y) >> x])
+
+// SLTI/SLTIU with constants.
+(SLTI  [x] (MOVDconst [y])) => (MOVDconst [b2i(int64(y) < int64(x))])
+(SLTIU [x] (MOVDconst [y])) => (MOVDconst [b2i(uint64(y) < uint64(x))])
+
+// Merge negation into fused multiply-add and multiply-subtract.
+//
+// Key:
+//
+//   [+ -](x * y) [+ -] z.
+//    _ N          A S
+//                 D U
+//                 D B
+//
+// Note: multiplication commutativity handled by rule generator.
+(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z)
+(F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z)
index 0774d4c654f95728d024eee48fef23444567a82b..076919773b47a3deb19862f5ebf74e6b5e79fa65 100644 (file)
@@ -29,6 +29,7 @@ const (
        riscv64REG_CTXT = 20
        riscv64REG_LR   = 1
        riscv64REG_SP   = 2
+       riscv64REG_GP   = 3
        riscv64REG_TP   = 4
        riscv64REG_TMP  = 31
        riscv64REG_ZERO = 0
@@ -80,8 +81,8 @@ func init() {
 
                // Add general purpose registers to gpMask.
                switch r {
-               // ZERO, TP and TMP are not in any gp mask.
-               case riscv64REG_ZERO, riscv64REG_TP, riscv64REG_TMP:
+               // ZERO, GP, TP and TMP are not in any gp mask.
+               case riscv64REG_ZERO, riscv64REG_GP, riscv64REG_TP, riscv64REG_TMP:
                case riscv64REG_G:
                        gpgMask |= mask
                        gpspsbgMask |= mask
@@ -123,6 +124,7 @@ func init() {
                gp01     = regInfo{outputs: []regMask{gpMask}}
                gp11     = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}
                gp21     = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}}
+               gp22     = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask, gpMask}}
                gpload   = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}}
                gp11sb   = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}}
                gpxchg   = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}, outputs: []regMask{gpMask}}
@@ -131,6 +133,7 @@ func init() {
 
                fp11    = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{fpMask}}
                fp21    = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{fpMask}}
+               fp31    = regInfo{inputs: []regMask{fpMask, fpMask, fpMask}, outputs: []regMask{fpMask}}
                gpfp    = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{fpMask}}
                fpgp    = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{gpMask}}
                fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, 0}}
@@ -157,6 +160,9 @@ func init() {
                {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, typ: "Int32"},
                {name: "MULH", argLength: 2, reg: gp21, asm: "MULH", commutative: true, typ: "Int64"},
                {name: "MULHU", argLength: 2, reg: gp21, asm: "MULHU", commutative: true, typ: "UInt64"},
+               {name: "LoweredMuluhilo", argLength: 2, reg: gp22, resultNotInArgs: true}, // arg0 * arg1, return (hi, lo)
+               {name: "LoweredMuluover", argLength: 2, reg: gp22, resultNotInArgs: true}, // arg0 * arg1, return (64 bits of arg0*arg1, overflow)
+
                {name: "DIV", argLength: 2, reg: gp21, asm: "DIV", typ: "Int64"}, // arg0 / arg1
                {name: "DIVU", argLength: 2, reg: gp21, asm: "DIVU", typ: "UInt64"},
                {name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},
@@ -235,9 +241,10 @@ func init() {
                {name: "MOVconvert", argLength: 2, reg: gp11, asm: "MOV"}, // arg0, but converted to int/ptr as appropriate; arg1=mem
 
                // Calls
-               {name: "CALLstatic", argLength: 1, reg: call, aux: "CallOff", call: true},         // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
-               {name: "CALLclosure", argLength: 3, reg: callClosure, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
-               {name: "CALLinter", argLength: 2, reg: callInter, aux: "CallOff", call: true},     // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+               {name: "CALLstatic", argLength: 1, reg: call, aux: "CallOff", call: true},               // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: 1, reg: call, aux: "CallOff", call: true, tailCall: true}, // tail call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
+               {name: "CALLclosure", argLength: 3, reg: callClosure, aux: "CallOff", call: true},       // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
+               {name: "CALLinter", argLength: 2, reg: callInter, aux: "CallOff", call: true},           // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
                // duffzero
                // arg0 = address of memory to zero (in X10, changed as side effect)
@@ -421,8 +428,14 @@ func init() {
                {name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD", commutative: false, typ: "Float64"},                                          // arg0 - arg1
                {name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true, typ: "Float64"},                                           // arg0 * arg1
                {name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD", commutative: false, typ: "Float64"},                                          // arg0 / arg1
+               {name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", commutative: true, typ: "Float64"},                                         // (arg0 * arg1) + arg2
+               {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD", commutative: true, typ: "Float64"},                                         // (arg0 * arg1) - arg2
+               {name: "FNMADDD", argLength: 3, reg: fp31, asm: "FNMADDD", commutative: true, typ: "Float64"},                                       // -(arg0 * arg1) + arg2
+               {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD", commutative: true, typ: "Float64"},                                       // -(arg0 * arg1) - arg2
                {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD", typ: "Float64"},                                                            // sqrt(arg0)
                {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD", typ: "Float64"},                                                              // -arg0
+               {name: "FABSD", argLength: 1, reg: fp11, asm: "FABSD", typ: "Float64"},                                                              // abs(arg0)
+               {name: "FSGNJD", argLength: 2, reg: fp21, asm: "FSGNJD", typ: "Float64"},                                                            // copy sign of arg1 to arg0
                {name: "FMVDX", argLength: 1, reg: gpfp, asm: "FMVDX", typ: "Float64"},                                                              // reinterpret arg0 as float
                {name: "FCVTDW", argLength: 1, reg: gpfp, asm: "FCVTDW", typ: "Float64"},                                                            // float64(low 32 bits of arg0)
                {name: "FCVTDL", argLength: 1, reg: gpfp, asm: "FCVTDL", typ: "Float64"},                                                            // float64(arg0)
index 88762f704589067c018bb110090397d7d51261de..b3928c6a1e6e4df84c241835c310dde974287b1d 100644 (file)
 (StaticCall ...) => (CALLstatic ...)
 (ClosureCall ...) => (CALLclosure ...)
 (InterCall ...) => (CALLinter ...)
+(TailCall ...) => (CALLtail ...)
 
 // Miscellaneous
 (IsNonNil p) => (LOCGR {s390x.NotEqual} (MOVDconst [0]) (MOVDconst [1]) (CMPconst p [0]))
index 00fce8e0e58b9a12728418aff98de10c0cbb28d0..cd7bad7acb676fec3b0df09704ce02e001aa0c3a 100644 (file)
@@ -480,6 +480,7 @@ func init() {
                {name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},
 
                {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                                // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
+               {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true},                                  // tail call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
                {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
                {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
index 7ad3d1c72e1fb04db56f2b937410dd030de4fea7..9e683b116c1613423505e365cc7ffc3bfd071901 100644 (file)
 (StaticCall ...) => (LoweredStaticCall ...)
 (ClosureCall ...) => (LoweredClosureCall ...)
 (InterCall ...) => (LoweredInterCall ...)
+(TailCall ...) => (LoweredTailCall ...)
 
 // Miscellaneous
 (Convert ...) => (LoweredConvert ...)
index 7f7ae5e83701f17278102596ac3819ed0fcd4455..edfba4ee99b774962a26cedf43994527ee939d11 100644 (file)
@@ -124,6 +124,7 @@ func init() {
 
        var WasmOps = []opData{
                {name: "LoweredStaticCall", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", call: true},                                // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
+               {name: "LoweredTailCall", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", call: true, tailCall: true},                  // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
                {name: "LoweredClosureCall", argLength: 3, reg: regInfo{inputs: []regMask{gp, gp, 0}, clobbers: callerSave}, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
                {name: "LoweredInterCall", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", call: true},          // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
 
index 5cbc70cf41d1c68c928c203c9fc77c53baa8882d..6dbe9b47d011fabd3c83e493b126a981efa45191 100644 (file)
 (Leq32 (Const32 [0]) (Rsh32Ux64 _ (Const64 [c]))) && c > 0 => (ConstBool [true])
 (Leq64 (Const64 [0]) (Rsh64Ux64 _ (Const64 [c]))) && c > 0 => (ConstBool [true])
 
+(Less(64|32|16|8) (Const(64|32|16|8) <t> [0]) x) && isNonNegative(x) => (Neq(64|32|16|8) (Const(64|32|16|8) <t> [0]) x)
+(Less(64|32|16|8) x (Const(64|32|16|8) <t> [1])) && isNonNegative(x) => (Eq(64|32|16|8) (Const(64|32|16|8) <t> [0]) x)
+
 // constant floating point comparisons
 (Eq32F   (Const32F [c]) (Const32F [d])) => (ConstBool [c == d])
 (Eq64F   (Const64F [c]) (Const64F [d])) => (ConstBool [c == d])
 // simplifications often used for lengths.  e.g. len(s[i:i+5])==5
 (Sub(64|32|16|8) (Add(64|32|16|8) x y) x) => y
 (Sub(64|32|16|8) (Add(64|32|16|8) x y) y) => x
+(Sub(64|32|16|8) (Sub(64|32|16|8) x y) x) => (Neg(64|32|16|8) y)
+(Sub(64|32|16|8) x (Add(64|32|16|8) x y)) => (Neg(64|32|16|8) y)
+(Add(64|32|16|8) x (Sub(64|32|16|8) y x)) => y
+(Add(64|32|16|8) x (Add(64|32|16|8) y (Sub(64|32|16|8) z x))) => (Add(64|32|16|8) y z)
 
 // basic phi simplifications
 (Phi (Const8  [c]) (Const8  [c])) => (Const8  [c])
        => (Invalid)
 
 // for late-expanded calls, recognize memequal applied to a single constant byte
-// TODO figure out breakeven number of bytes for this optimization.
+// Support is limited by 1, 2, 4, 8 byte sizes
 (StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [1]) mem)
   && isSameCall(callAux, "runtime.memequal")
   && symIsRO(scon)
   => (MakeResult (Eq8 (Load <typ.Int8> sptr mem) (Const8 <typ.Int8> [int8(read8(scon,0))])) mem)
 
+(StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [2]) mem)
+  && isSameCall(callAux, "runtime.memequal")
+  && symIsRO(scon)
+  && canLoadUnaligned(config)
+  => (MakeResult (Eq16 (Load <typ.Int16> sptr mem) (Const16 <typ.Int16> [int16(read16(scon,0,config.ctxt.Arch.ByteOrder))])) mem)
+
+(StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [4]) mem)
+  && isSameCall(callAux, "runtime.memequal")
+  && symIsRO(scon)
+  && canLoadUnaligned(config)
+  => (MakeResult (Eq32 (Load <typ.Int32> sptr mem) (Const32 <typ.Int32> [int32(read32(scon,0,config.ctxt.Arch.ByteOrder))])) mem)
+
+(StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [8]) mem)
+  && isSameCall(callAux, "runtime.memequal")
+  && symIsRO(scon)
+  && canLoadUnaligned(config) && config.PtrSize == 8
+  => (MakeResult (Eq64 (Load <typ.Int64> sptr mem) (Const64 <typ.Int64> [int64(read64(scon,0,config.ctxt.Arch.ByteOrder))])) mem)
+
 // Evaluate constant address comparisons.
 (EqPtr  x x) => (ConstBool [true])
 (NeqPtr x x) => (ConstBool [false])
index 9f6664386c9d1749e51c4d6bd3a29c6fecd7d37d..4f133b1ff6a1b85de79dec35a4360d9cb2d2a231 100644 (file)
@@ -106,7 +106,7 @@ var genericOps = []opData{
 
        // For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
        // Shift amounts are considered unsigned.
-       // If arg1 is known to be less than the number of bits in arg0,
+       // If arg1 is known to be nonnegative and less than the number of bits in arg0,
        // then auxInt may be set to 1.
        // This enables better code generation on some platforms.
        {name: "Lsh8x8", argLength: 2, aux: "Bool"}, // arg0 << arg1
@@ -417,10 +417,12 @@ var genericOps = []opData{
        {name: "ClosureCall", argLength: -1, aux: "CallOff", call: true}, // arg0=code pointer, arg1=context ptr, arg2..argN-1 are register inputs, argN=memory.  auxint=arg size.  Returns Result of register results, plus memory.
        {name: "StaticCall", argLength: -1, aux: "CallOff", call: true},  // call function aux.(*obj.LSym), arg0..argN-1 are register inputs, argN=memory.  auxint=arg size.  Returns Result of register results, plus memory.
        {name: "InterCall", argLength: -1, aux: "CallOff", call: true},   // interface call.  arg0=code pointer, arg1..argN-1 are register inputs, argN=memory, auxint=arg size.  Returns Result of register results, plus memory.
+       {name: "TailCall", argLength: -1, aux: "CallOff", call: true},    // tail call function aux.(*obj.LSym), arg0..argN-1 are register inputs, argN=memory.  auxint=arg size.  Returns Result of register results, plus memory.
 
        {name: "ClosureLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded closure call. arg0=code pointer, arg1=context ptr,  arg2..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
        {name: "StaticLECall", argLength: -1, aux: "CallOff", call: true},  // late-expanded static call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
        {name: "InterLECall", argLength: -1, aux: "CallOff", call: true},   // late-expanded interface call. arg0=code pointer, arg1..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
+       {name: "TailLECall", argLength: -1, aux: "CallOff", call: true},    // late-expanded static tail call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
 
        // Conversions: signed extensions, zero (unsigned) extensions, truncations
        {name: "SignExt8to16", argLength: 1, typ: "Int16"},
@@ -615,9 +617,16 @@ var genericOps = []opData{
        {name: "AtomicOr8Variant", argLength: 3, typ: "Mem", hasSideEffects: true},                     // *arg0 |= arg1.  arg2=memory.  Returns memory.
        {name: "AtomicOr32Variant", argLength: 3, typ: "Mem", hasSideEffects: true},                    // *arg0 |= arg1.  arg2=memory.  Returns memory.
 
+       // Publication barrier
+       {name: "PubBarrier", argLength: 1, hasSideEffects: true}, // Do data barrier. arg0=memory.
+
        // Clobber experiment op
        {name: "Clobber", argLength: 0, typ: "Void", aux: "SymOff", symEffect: "None"}, // write an invalid pointer value to the given pointer slot of a stack variable
        {name: "ClobberReg", argLength: 0, typ: "Void"},                                // clobber a register
+
+       // Prefetch instruction
+       {name: "PrefetchCache", argLength: 2, hasSideEffects: true},         // Do prefetch arg0 to cache. arg0=addr, arg1=memory.
+       {name: "PrefetchCacheStreamed", argLength: 2, hasSideEffects: true}, // Do non-temporal or streamed prefetch arg0 to cache. arg0=addr, arg1=memory.
 }
 
 //     kind          controls        successors   implicit exit
@@ -634,7 +643,7 @@ var genericBlocks = []blockData{
        {name: "If", controls: 1},     // if Controls[0] goto Succs[0] else goto Succs[1]
        {name: "Defer", controls: 1},  // Succs[0]=defer queued, Succs[1]=defer recovered. Controls[0] is call op (of memory type)
        {name: "Ret", controls: 1},    // no successors, Controls[0] value is memory result
-       {name: "RetJmp", controls: 1}, // no successors, Controls[0] value is memory result, jumps to b.Aux.(*gc.Sym)
+       {name: "RetJmp", controls: 1}, // no successors, Controls[0] value is a tail call
        {name: "Exit", controls: 1},   // no successors, Controls[0] value generates a panic
 
        // transient block state used for dead code removal
index 8e5997b25a447339b1bd80b1604a772e2ef82b16..2cf0a919fa6ebc2b07871249ce391439c44bb4e9 100644 (file)
@@ -63,6 +63,7 @@ type opData struct {
        resultNotInArgs   bool   // outputs must not be allocated to the same registers as inputs
        clobberFlags      bool   // this op clobbers flags register
        call              bool   // is a function call
+       tailCall          bool   // is a tail call
        nilCheck          bool   // this op is a nil check on arg0
        faultOnNilArg0    bool   // this op will fault if arg0 is nil (and aux encodes a small offset)
        faultOnNilArg1    bool   // this op will fault if arg1 is nil (and aux encodes a small offset)
@@ -307,6 +308,9 @@ func genOp() {
                        if v.call {
                                fmt.Fprintln(w, "call: true,")
                        }
+                       if v.tailCall {
+                               fmt.Fprintln(w, "tailCall: true,")
+                       }
                        if v.nilCheck {
                                fmt.Fprintln(w, "nilCheck: true,")
                        }
@@ -405,6 +409,7 @@ func genOp() {
 
        fmt.Fprintln(w, "func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }")
        fmt.Fprintln(w, "func (o Op) IsCall() bool { return opcodeTable[o].call }")
+       fmt.Fprintln(w, "func (o Op) IsTailCall() bool { return opcodeTable[o].tailCall }")
        fmt.Fprintln(w, "func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }")
        fmt.Fprintln(w, "func (o Op) UnsafePoint() bool { return opcodeTable[o].unsafePoint }")
        fmt.Fprintln(w, "func (o Op) ResultInArg0() bool { return opcodeTable[o].resultInArg0 }")
index 4d191199fbafe1b3f5f61882a40aced0e836cf36..d9a78b396243beb32e912549f89a83ef72c692a5 100644 (file)
@@ -903,15 +903,12 @@ func (w *HTMLWriter) WriteAST(phase string, buf *bytes.Buffer) {
                        if strings.HasPrefix(l, "buildssa") {
                                escaped = fmt.Sprintf("<b>%v</b>", l)
                        } else {
-                               // Parse the line number from the format l(123).
-                               idx := strings.Index(l, " l(")
-                               if idx != -1 {
-                                       subl := l[idx+3:]
-                                       idxEnd := strings.Index(subl, ")")
-                                       if idxEnd != -1 {
-                                               if _, err := strconv.Atoi(subl[:idxEnd]); err == nil {
-                                                       lineNo = subl[:idxEnd]
-                                               }
+                               // Parse the line number from the format file:line:col.
+                               // See the implementation in ir/fmt.go:dumpNodeHeader.
+                               sl := strings.Split(l, ":")
+                               if len(sl) >= 3 {
+                                       if _, err := strconv.Atoi(sl[len(sl)-2]); err == nil {
+                                               lineNo = sl[len(sl)-2]
                                        }
                                }
                                escaped = html.EscapeString(l)
@@ -1221,7 +1218,7 @@ func (p htmlFuncPrinter) startBlock(b *Block, reachable bool) {
        }
 }
 
-func (p htmlFuncPrinter) endBlock(b *Block) {
+func (p htmlFuncPrinter) endBlock(b *Block, reachable bool) {
        if len(b.Values) > 0 { // end list of values
                io.WriteString(p.w, "</ul>")
                io.WriteString(p.w, "</li>")
index 252c47cdebc8b6ab4a4523e4042c3d34724520be..b575febd72741158bab236eeea768e8ac2677874 100644 (file)
@@ -91,8 +91,8 @@ func (t LocPair) String() string {
 type LocResults []Location
 
 func (t LocResults) String() string {
-       s := "<"
-       a := ""
+       s := ""
+       a := "<"
        for _, r := range t {
                a += s
                s = ","
index f09a08abcf752102944a3aba872105ac9ebe392d..a1835dcd3026ecb3f9ef137e38af0033831440cf 100644 (file)
@@ -34,6 +34,7 @@ type opInfo struct {
        resultNotInArgs   bool      // outputs must not be allocated to the same registers as inputs
        clobberFlags      bool      // this op clobbers flags register
        call              bool      // is a function call
+       tailCall          bool      // is a tail call
        nilCheck          bool      // this op is a nil check on arg0
        faultOnNilArg0    bool      // this op will fault if arg0 is nil (and aux encodes a small offset)
        faultOnNilArg1    bool      // this op will fault if arg1 is nil (and aux encodes a small offset)
@@ -102,6 +103,10 @@ func (a *AuxNameOffset) String() string {
        return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset)
 }
 
+func (a *AuxNameOffset) FrameOffset() int64 {
+       return a.Name.FrameOffset() + a.Offset
+}
+
 type AuxCall struct {
        Fn      *obj.LSym
        reg     *regInfo // regInfo for this call
@@ -254,13 +259,13 @@ func (a *AuxCall) TypeOfArg(which int64) *types.Type {
 
 // SizeOfResult returns the size of result which (indexed 0, 1, etc).
 func (a *AuxCall) SizeOfResult(which int64) int64 {
-       return a.TypeOfResult(which).Width
+       return a.TypeOfResult(which).Size()
 }
 
 // SizeOfArg returns the size of argument which (indexed 0, 1, etc).
 // If the call is to a method, the receiver is the first argument (i.e., index 0)
 func (a *AuxCall) SizeOfArg(which int64) int64 {
-       return a.TypeOfArg(which).Width
+       return a.TypeOfArg(which).Size()
 }
 
 // NResults returns the number of results
index df15c2edda49450934b617ae96d7c01753dfca17..2038575b0cfc5207c27f27f2790384052e397141 100644 (file)
@@ -515,6 +515,7 @@ const (
        Op386DUFFZERO
        Op386REPSTOSL
        Op386CALLstatic
+       Op386CALLtail
        Op386CALLclosure
        Op386CALLinter
        Op386DUFFCOPY
@@ -962,7 +963,6 @@ const (
        OpAMD64MOVQstore
        OpAMD64MOVOload
        OpAMD64MOVOstore
-       OpAMD64MOVOstorezero
        OpAMD64MOVBloadidx1
        OpAMD64MOVWloadidx1
        OpAMD64MOVWloadidx2
@@ -983,6 +983,7 @@ const (
        OpAMD64MOVWstoreconst
        OpAMD64MOVLstoreconst
        OpAMD64MOVQstoreconst
+       OpAMD64MOVOstoreconst
        OpAMD64MOVBstoreconstidx1
        OpAMD64MOVWstoreconstidx1
        OpAMD64MOVWstoreconstidx2
@@ -993,6 +994,7 @@ const (
        OpAMD64DUFFZERO
        OpAMD64REPSTOSQ
        OpAMD64CALLstatic
+       OpAMD64CALLtail
        OpAMD64CALLclosure
        OpAMD64CALLinter
        OpAMD64DUFFCOPY
@@ -1029,6 +1031,22 @@ const (
        OpAMD64ANDLlock
        OpAMD64ORBlock
        OpAMD64ORLlock
+       OpAMD64PrefetchT0
+       OpAMD64PrefetchNTA
+       OpAMD64ANDNQ
+       OpAMD64ANDNL
+       OpAMD64BLSIQ
+       OpAMD64BLSIL
+       OpAMD64BLSMSKQ
+       OpAMD64BLSMSKL
+       OpAMD64BLSRQ
+       OpAMD64BLSRL
+       OpAMD64TZCNTQ
+       OpAMD64TZCNTL
+       OpAMD64MOVBELload
+       OpAMD64MOVBELstore
+       OpAMD64MOVBEQload
+       OpAMD64MOVBEQstore
 
        OpARMADD
        OpARMADDconst
@@ -1267,6 +1285,7 @@ const (
        OpARMCMOVWLSconst
        OpARMSRAcond
        OpARMCALLstatic
+       OpARMCALLtail
        OpARMCALLclosure
        OpARMCALLinter
        OpARMLoweredNilCheck
@@ -1407,6 +1426,7 @@ const (
        OpARM64MVNshiftLL
        OpARM64MVNshiftRL
        OpARM64MVNshiftRA
+       OpARM64MVNshiftRO
        OpARM64NEGshiftLL
        OpARM64NEGshiftRL
        OpARM64NEGshiftRA
@@ -1419,21 +1439,27 @@ const (
        OpARM64ANDshiftLL
        OpARM64ANDshiftRL
        OpARM64ANDshiftRA
+       OpARM64ANDshiftRO
        OpARM64ORshiftLL
        OpARM64ORshiftRL
        OpARM64ORshiftRA
+       OpARM64ORshiftRO
        OpARM64XORshiftLL
        OpARM64XORshiftRL
        OpARM64XORshiftRA
+       OpARM64XORshiftRO
        OpARM64BICshiftLL
        OpARM64BICshiftRL
        OpARM64BICshiftRA
+       OpARM64BICshiftRO
        OpARM64EONshiftLL
        OpARM64EONshiftRL
        OpARM64EONshiftRA
+       OpARM64EONshiftRO
        OpARM64ORNshiftLL
        OpARM64ORNshiftRL
        OpARM64ORNshiftRA
+       OpARM64ORNshiftRO
        OpARM64CMPshiftLL
        OpARM64CMPshiftRL
        OpARM64CMPshiftRA
@@ -1443,6 +1469,7 @@ const (
        OpARM64TSTshiftLL
        OpARM64TSTshiftRL
        OpARM64TSTshiftRA
+       OpARM64TSTshiftRO
        OpARM64BFI
        OpARM64BFXIL
        OpARM64SBFIZ
@@ -1550,6 +1577,7 @@ const (
        OpARM64CSNEG
        OpARM64CSETM
        OpARM64CALLstatic
+       OpARM64CALLtail
        OpARM64CALLclosure
        OpARM64CALLinter
        OpARM64LoweredNilCheck
@@ -1610,6 +1638,8 @@ const (
        OpARM64LoweredPanicBoundsA
        OpARM64LoweredPanicBoundsB
        OpARM64LoweredPanicBoundsC
+       OpARM64PRFM
+       OpARM64DMB
 
        OpMIPSADD
        OpMIPSADDconst
@@ -1694,6 +1724,7 @@ const (
        OpMIPSMOVFD
        OpMIPSMOVDF
        OpMIPSCALLstatic
+       OpMIPSCALLtail
        OpMIPSCALLclosure
        OpMIPSCALLinter
        OpMIPSLoweredAtomicLoad8
@@ -1810,6 +1841,7 @@ const (
        OpMIPS64MOVFD
        OpMIPS64MOVDF
        OpMIPS64CALLstatic
+       OpMIPS64CALLtail
        OpMIPS64CALLclosure
        OpMIPS64CALLinter
        OpMIPS64DUFFZERO
@@ -1966,6 +1998,7 @@ const (
        OpPPC64MOVDBRloadidx
        OpPPC64FMOVDloadidx
        OpPPC64FMOVSloadidx
+       OpPPC64DCBT
        OpPPC64MOVDBRstore
        OpPPC64MOVWBRstore
        OpPPC64MOVHBRstore
@@ -2022,6 +2055,7 @@ const (
        OpPPC64LoweredRound32F
        OpPPC64LoweredRound64F
        OpPPC64CALLstatic
+       OpPPC64CALLtail
        OpPPC64CALLclosure
        OpPPC64CALLinter
        OpPPC64LoweredZero
@@ -2069,6 +2103,8 @@ const (
        OpRISCV64MULW
        OpRISCV64MULH
        OpRISCV64MULHU
+       OpRISCV64LoweredMuluhilo
+       OpRISCV64LoweredMuluover
        OpRISCV64DIV
        OpRISCV64DIVU
        OpRISCV64DIVW
@@ -2123,6 +2159,7 @@ const (
        OpRISCV64SLTIU
        OpRISCV64MOVconvert
        OpRISCV64CALLstatic
+       OpRISCV64CALLtail
        OpRISCV64CALLclosure
        OpRISCV64CALLinter
        OpRISCV64DUFFZERO
@@ -2172,8 +2209,14 @@ const (
        OpRISCV64FSUBD
        OpRISCV64FMULD
        OpRISCV64FDIVD
+       OpRISCV64FMADDD
+       OpRISCV64FMSUBD
+       OpRISCV64FNMADDD
+       OpRISCV64FNMSUBD
        OpRISCV64FSQRTD
        OpRISCV64FNEGD
+       OpRISCV64FABSD
+       OpRISCV64FSGNJD
        OpRISCV64FMVDX
        OpRISCV64FCVTDW
        OpRISCV64FCVTDL
@@ -2375,6 +2418,7 @@ const (
        OpS390XMOVDstoreconst
        OpS390XCLEAR
        OpS390XCALLstatic
+       OpS390XCALLtail
        OpS390XCALLclosure
        OpS390XCALLinter
        OpS390XInvertFlags
@@ -2428,6 +2472,7 @@ const (
        OpS390XLoweredZero
 
        OpWasmLoweredStaticCall
+       OpWasmLoweredTailCall
        OpWasmLoweredClosureCall
        OpWasmLoweredInterCall
        OpWasmLoweredAddr
@@ -2774,9 +2819,11 @@ const (
        OpClosureCall
        OpStaticCall
        OpInterCall
+       OpTailCall
        OpClosureLECall
        OpStaticLECall
        OpInterLECall
+       OpTailLECall
        OpSignExt8to16
        OpSignExt8to32
        OpSignExt8to64
@@ -2910,8 +2957,11 @@ const (
        OpAtomicAnd32Variant
        OpAtomicOr8Variant
        OpAtomicOr32Variant
+       OpPubBarrier
        OpClobber
        OpClobberReg
+       OpPrefetchCache
+       OpPrefetchCacheStreamed
 )
 
 var opcodeTable = [...]opInfo{
@@ -4687,7 +4737,6 @@ var opcodeTable = [...]opInfo{
                name:         "NOTL",
                argLen:       1,
                resultInArg0: true,
-               clobberFlags: true,
                asm:          x86.ANOTL,
                reg: regInfo{
                        inputs: []inputInfo{
@@ -5893,6 +5942,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -10721,7 +10781,6 @@ var opcodeTable = [...]opInfo{
                name:         "NOTQ",
                argLen:       1,
                resultInArg0: true,
-               clobberFlags: true,
                asm:          x86.ANOTQ,
                reg: regInfo{
                        inputs: []inputInfo{
@@ -10736,7 +10795,6 @@ var opcodeTable = [...]opInfo{
                name:         "NOTL",
                argLen:       1,
                resultInArg0: true,
-               clobberFlags: true,
                asm:          x86.ANOTL,
                reg: regInfo{
                        inputs: []inputInfo{
@@ -12623,19 +12681,6 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
-       {
-               name:           "MOVOstorezero",
-               auxType:        auxSymOff,
-               argLen:         2,
-               faultOnNilArg0: true,
-               symEffect:      SymWrite,
-               asm:            x86.AMOVUPS,
-               reg: regInfo{
-                       inputs: []inputInfo{
-                               {0, 4295016447}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 SB
-                       },
-               },
-       },
        {
                name:        "MOVBloadidx1",
                auxType:     auxSymOff,
@@ -12952,6 +12997,19 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:           "MOVOstoreconst",
+               auxType:        auxSymValAndOff,
+               argLen:         2,
+               faultOnNilArg0: true,
+               symEffect:      SymWrite,
+               asm:            x86.AMOVUPS,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+               },
+       },
        {
                name:        "MOVBstoreconstidx1",
                auxType:     auxSymValAndOff,
@@ -13090,6 +13148,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 2147483631, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 g R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       -1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 2147483631, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 g R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -13553,6 +13622,230 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:           "PrefetchT0",
+               argLen:         2,
+               hasSideEffects: true,
+               asm:            x86.APREFETCHT0,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+               },
+       },
+       {
+               name:           "PrefetchNTA",
+               argLen:         2,
+               hasSideEffects: true,
+               asm:            x86.APREFETCHNTA,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+               },
+       },
+       {
+               name:         "ANDNQ",
+               argLen:       2,
+               clobberFlags: true,
+               asm:          x86.AANDNQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                               {1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "ANDNL",
+               argLen:       2,
+               clobberFlags: true,
+               asm:          x86.AANDNL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                               {1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "BLSIQ",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ABLSIQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "BLSIL",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ABLSIL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "BLSMSKQ",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ABLSMSKQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "BLSMSKL",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ABLSMSKL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "BLSRQ",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ABLSRQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "BLSRL",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ABLSRL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "TZCNTQ",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ATZCNTQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:         "TZCNTL",
+               argLen:       1,
+               clobberFlags: true,
+               asm:          x86.ATZCNTL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:           "MOVBELload",
+               auxType:        auxSymOff,
+               argLen:         2,
+               faultOnNilArg0: true,
+               symEffect:      SymRead,
+               asm:            x86.AMOVBEL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:           "MOVBELstore",
+               auxType:        auxSymOff,
+               argLen:         3,
+               faultOnNilArg0: true,
+               symEffect:      SymWrite,
+               asm:            x86.AMOVBEL,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {1, 49151},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+               },
+       },
+       {
+               name:           "MOVBEQload",
+               auxType:        auxSymOff,
+               argLen:         2,
+               faultOnNilArg0: true,
+               symEffect:      SymRead,
+               asm:            x86.AMOVBEQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+                       outputs: []outputInfo{
+                               {0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
+                       },
+               },
+       },
+       {
+               name:           "MOVBEQstore",
+               auxType:        auxSymOff,
+               argLen:         3,
+               faultOnNilArg0: true,
+               symEffect:      SymWrite,
+               asm:            x86.AMOVBEQ,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {1, 49151},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
+                               {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
+                       },
+               },
+       },
 
        {
                name:        "ADD",
@@ -16904,6 +17197,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 4294924287, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 4294924287, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -18730,6 +19034,20 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "MVNshiftRO",
+               auxType: auxInt64,
+               argLen:  1,
+               asm:     arm64.AMVN,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "NEGshiftLL",
                auxType: auxInt64,
@@ -18907,6 +19225,21 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "ANDshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.AAND,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "ORshiftLL",
                auxType: auxInt64,
@@ -18952,6 +19285,21 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "ORshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.AORR,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "XORshiftLL",
                auxType: auxInt64,
@@ -18997,6 +19345,21 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "XORshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.AEOR,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "BICshiftLL",
                auxType: auxInt64,
@@ -19042,6 +19405,21 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "BICshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.ABIC,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "EONshiftLL",
                auxType: auxInt64,
@@ -19087,6 +19465,21 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "EONshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.AEON,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "ORNshiftLL",
                auxType: auxInt64,
@@ -19132,6 +19525,21 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "ORNshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.AORN,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:    "CMPshiftLL",
                auxType: auxInt64,
@@ -19240,6 +19648,18 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:    "TSTshiftRO",
+               auxType: auxInt64,
+               argLen:  2,
+               asm:     arm64.ATST,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                               {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+                       },
+               },
+       },
        {
                name:         "BFI",
                auxType:      auxARM64BitField,
@@ -20671,6 +21091,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 9223372035512336383, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       -1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 9223372035512336383, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -21445,6 +21876,26 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:           "PRFM",
+               auxType:        auxInt64,
+               argLen:         2,
+               hasSideEffects: true,
+               asm:            arm64.APRFM,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
+                       },
+               },
+       },
+       {
+               name:           "DMB",
+               auxType:        auxInt64,
+               argLen:         1,
+               hasSideEffects: true,
+               asm:            arm64.ADMB,
+               reg:            regInfo{},
+       },
 
        {
                name:        "ADD",
@@ -22592,6 +23043,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 140737421246462, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31 F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 HI LO
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 140737421246462, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31 F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30 HI LO
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -24151,6 +24613,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 4611686018393833470, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 HI LO
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 4611686018393833470, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 HI LO
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -26310,6 +26783,18 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:           "DCBT",
+               auxType:        auxInt64,
+               argLen:         2,
+               hasSideEffects: true,
+               asm:            ppc64.ADCBT,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+                       },
+               },
+       },
        {
                name:           "MOVDBRstore",
                auxType:        auxSym,
@@ -26972,9 +27457,20 @@ var opcodeTable = [...]opInfo{
        {
                name:         "CALLstatic",
                auxType:      auxCallOff,
-               argLen:       1,
+               argLen:       -1,
+               clobberFlags: true,
+               call:         true,
+               reg: regInfo{
+                       clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
+               },
+       },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       -1,
                clobberFlags: true,
                call:         true,
+               tailCall:     true,
                reg: regInfo{
                        clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26
                },
@@ -26982,7 +27478,7 @@ var opcodeTable = [...]opInfo{
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
-               argLen:       3,
+               argLen:       -1,
                clobberFlags: true,
                call:         true,
                reg: regInfo{
@@ -26996,7 +27492,7 @@ var opcodeTable = [...]opInfo{
        {
                name:         "CALLinter",
                auxType:      auxCallOff,
-               argLen:       2,
+               argLen:       -1,
                clobberFlags: true,
                call:         true,
                reg: regInfo{
@@ -27453,11 +27949,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AADD,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27468,10 +27964,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.AADDI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27482,10 +27978,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.AADDIW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27495,10 +27991,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ANEG,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27508,10 +28004,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ANEGW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27521,11 +28017,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASUB,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27535,11 +28031,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASUBW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27550,11 +28046,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AMUL,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27565,11 +28061,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AMULW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27580,11 +28076,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AMULH,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27595,11 +28091,41 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AMULHU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                       },
+                       outputs: []outputInfo{
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                       },
+               },
+       },
+       {
+               name:            "LoweredMuluhilo",
+               argLen:          2,
+               resultNotInArgs: true,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                       },
+               },
+       },
+       {
+               name:            "LoweredMuluover",
+               argLen:          2,
+               resultNotInArgs: true,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                       },
+                       outputs: []outputInfo{
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27609,11 +28135,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ADIV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27623,11 +28149,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ADIVU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27637,11 +28163,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ADIVW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27651,11 +28177,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ADIVUW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27665,11 +28191,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AREM,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27679,11 +28205,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AREMU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27693,11 +28219,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AREMW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27707,11 +28233,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AREMUW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27724,10 +28250,10 @@ var opcodeTable = [...]opInfo{
                asm:               riscv.AMOV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27739,7 +28265,7 @@ var opcodeTable = [...]opInfo{
                asm:               riscv.AMOV,
                reg: regInfo{
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27752,10 +28278,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVB,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27768,10 +28294,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVH,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27784,10 +28310,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27800,10 +28326,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27816,10 +28342,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVBU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27832,10 +28358,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVHU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27848,10 +28374,10 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVWU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27864,8 +28390,8 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVB,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27878,8 +28404,8 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVH,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27892,8 +28418,8 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27906,8 +28432,8 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27920,7 +28446,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVB,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27933,7 +28459,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVH,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27946,7 +28472,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27959,7 +28485,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -27969,10 +28495,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOVB,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27982,10 +28508,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOVH,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -27995,10 +28521,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOVW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28008,10 +28534,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28021,10 +28547,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOVBU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28034,10 +28560,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOVHU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28047,10 +28573,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOVWU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28060,10 +28586,10 @@ var opcodeTable = [...]opInfo{
                resultInArg0: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28073,11 +28599,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASLL,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28087,11 +28613,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASRA,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28101,11 +28627,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASRL,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28116,10 +28642,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.ASLLI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28130,10 +28656,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.ASRAI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28144,10 +28670,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.ASRLI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28158,11 +28684,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AXOR,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28173,10 +28699,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.AXORI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28187,11 +28713,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AOR,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28202,10 +28728,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.AORI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28216,11 +28742,11 @@ var opcodeTable = [...]opInfo{
                asm:         riscv.AAND,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28231,10 +28757,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.AANDI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28244,10 +28770,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ANOT,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28257,10 +28783,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASEQZ,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28270,10 +28796,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASNEZ,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28283,11 +28809,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASLT,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28298,10 +28824,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.ASLTI,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28311,11 +28837,11 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.ASLTU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28326,10 +28852,10 @@ var opcodeTable = [...]opInfo{
                asm:     riscv.ASLTIU,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28339,10 +28865,10 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AMOV,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28352,7 +28878,17 @@ var opcodeTable = [...]opInfo{
                argLen:  1,
                call:    true,
                reg: regInfo{
-                       clobbers: 9223372035781033972, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       clobbers: 9223372035781033968, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+               },
+       },
+       {
+               name:     "CALLtail",
+               auxType:  auxCallOff,
+               argLen:   1,
+               call:     true,
+               tailCall: true,
+               reg: regInfo{
+                       clobbers: 9223372035781033968, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                },
        },
        {
@@ -28363,9 +28899,9 @@ var opcodeTable = [...]opInfo{
                reg: regInfo{
                        inputs: []inputInfo{
                                {1, 524288},     // X20
-                               {0, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632946}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
-                       clobbers: 9223372035781033972, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       clobbers: 9223372035781033968, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                },
        },
        {
@@ -28375,9 +28911,9 @@ var opcodeTable = [...]opInfo{
                call:    true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
-                       clobbers: 9223372035781033972, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       clobbers: 9223372035781033968, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                },
        },
        {
@@ -28414,7 +28950,7 @@ var opcodeTable = [...]opInfo{
                reg: regInfo{
                        inputs: []inputInfo{
                                {0, 16},         // X5
-                               {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {1, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        clobbers: 16, // X5
                },
@@ -28429,7 +28965,7 @@ var opcodeTable = [...]opInfo{
                        inputs: []inputInfo{
                                {0, 16},         // X5
                                {1, 32},         // X6
-                               {2, 1006632884}, // X3 X5 X6 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {2, 1006632880}, // X5 X6 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        clobbers: 112, // X5 X6 X7
                },
@@ -28440,10 +28976,10 @@ var opcodeTable = [...]opInfo{
                faultOnNilArg0: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28453,10 +28989,10 @@ var opcodeTable = [...]opInfo{
                faultOnNilArg0: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28466,10 +29002,10 @@ var opcodeTable = [...]opInfo{
                faultOnNilArg0: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28480,8 +29016,8 @@ var opcodeTable = [...]opInfo{
                hasSideEffects: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -28492,8 +29028,8 @@ var opcodeTable = [...]opInfo{
                hasSideEffects: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -28504,8 +29040,8 @@ var opcodeTable = [...]opInfo{
                hasSideEffects: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1006632950},          // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {1, 1006632946},          // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                },
        },
@@ -28517,11 +29053,11 @@ var opcodeTable = [...]opInfo{
                hasSideEffects:  true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28533,11 +29069,11 @@ var opcodeTable = [...]opInfo{
                hasSideEffects:  true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28550,11 +29086,11 @@ var opcodeTable = [...]opInfo{
                unsafePoint:     true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28567,11 +29103,11 @@ var opcodeTable = [...]opInfo{
                unsafePoint:     true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28584,12 +29120,12 @@ var opcodeTable = [...]opInfo{
                unsafePoint:     true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {2, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {2, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28602,12 +29138,12 @@ var opcodeTable = [...]opInfo{
                unsafePoint:     true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {2, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {2, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28619,8 +29155,8 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AAMOANDW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                },
        },
@@ -28632,8 +29168,8 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AAMOORW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {1, 1073741812},          // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
-                               {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
+                               {1, 1073741808},          // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+                               {0, 9223372037928517618}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
                        },
                },
        },
@@ -28644,7 +29180,7 @@ var opcodeTable = [...]opInfo{
                faultOnNilArg0: true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632946}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28663,7 +29199,7 @@ var opcodeTable = [...]opInfo{
                rematerializeable: true,
                reg: regInfo{
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28673,7 +29209,7 @@ var opcodeTable = [...]opInfo{
                rematerializeable: true,
                reg: regInfo{
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28817,7 +29353,7 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AFMVSX,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -28830,7 +29366,7 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AFCVTSW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -28843,7 +29379,7 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AFCVTSL,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -28859,7 +29395,7 @@ var opcodeTable = [...]opInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28872,7 +29408,7 @@ var opcodeTable = [...]opInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28885,7 +29421,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVF,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -28901,7 +29437,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVF,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                },
@@ -28917,7 +29453,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28932,7 +29468,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28946,7 +29482,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -28960,7 +29496,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -29022,6 +29558,70 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:        "FMADDD",
+               argLen:      3,
+               commutative: true,
+               asm:         riscv.AFMADDD,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+                       outputs: []outputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+               },
+       },
+       {
+               name:        "FMSUBD",
+               argLen:      3,
+               commutative: true,
+               asm:         riscv.AFMSUBD,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+                       outputs: []outputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+               },
+       },
+       {
+               name:        "FNMADDD",
+               argLen:      3,
+               commutative: true,
+               asm:         riscv.AFNMADDD,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+                       outputs: []outputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+               },
+       },
+       {
+               name:        "FNMSUBD",
+               argLen:      3,
+               commutative: true,
+               asm:         riscv.AFNMSUBD,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+                       outputs: []outputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+               },
+       },
        {
                name:   "FSQRTD",
                argLen: 1,
@@ -29048,13 +29648,40 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:   "FABSD",
+               argLen: 1,
+               asm:    riscv.AFABSD,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+                       outputs: []outputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+               },
+       },
+       {
+               name:   "FSGNJD",
+               argLen: 2,
+               asm:    riscv.AFSGNJD,
+               reg: regInfo{
+                       inputs: []inputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                               {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+                       outputs: []outputInfo{
+                               {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
+                       },
+               },
+       },
        {
                name:   "FMVDX",
                argLen: 1,
                asm:    riscv.AFMVDX,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -29067,7 +29694,7 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AFCVTDW,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -29080,7 +29707,7 @@ var opcodeTable = [...]opInfo{
                asm:    riscv.AFCVTDL,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -29096,7 +29723,7 @@ var opcodeTable = [...]opInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -29109,7 +29736,7 @@ var opcodeTable = [...]opInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -29148,7 +29775,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVD,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                        },
                        outputs: []outputInfo{
                                {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
@@ -29164,7 +29791,7 @@ var opcodeTable = [...]opInfo{
                asm:            riscv.AMOVD,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+                               {0, 9223372037861408754}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                },
@@ -29180,7 +29807,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -29195,7 +29822,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -29209,7 +29836,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -29223,7 +29850,7 @@ var opcodeTable = [...]opInfo{
                                {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31
                        },
                        outputs: []outputInfo{
-                               {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+                               {0, 1006632944}, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
                        },
                },
        },
@@ -32019,6 +32646,17 @@ var opcodeTable = [...]opInfo{
                        clobbers: 4294933503, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 g R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
                },
        },
+       {
+               name:         "CALLtail",
+               auxType:      auxCallOff,
+               argLen:       1,
+               clobberFlags: true,
+               call:         true,
+               tailCall:     true,
+               reg: regInfo{
+                       clobbers: 4294933503, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 g R14 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+               },
+       },
        {
                name:         "CALLclosure",
                auxType:      auxCallOff,
@@ -32689,6 +33327,16 @@ var opcodeTable = [...]opInfo{
                        clobbers: 844424930131967, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 g
                },
        },
+       {
+               name:     "LoweredTailCall",
+               auxType:  auxCallOff,
+               argLen:   1,
+               call:     true,
+               tailCall: true,
+               reg: regInfo{
+                       clobbers: 844424930131967, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 g
+               },
+       },
        {
                name:    "LoweredClosureCall",
                auxType: auxCallOff,
@@ -35465,6 +36113,13 @@ var opcodeTable = [...]opInfo{
                call:    true,
                generic: true,
        },
+       {
+               name:    "TailCall",
+               auxType: auxCallOff,
+               argLen:  -1,
+               call:    true,
+               generic: true,
+       },
        {
                name:    "ClosureLECall",
                auxType: auxCallOff,
@@ -35486,6 +36141,13 @@ var opcodeTable = [...]opInfo{
                call:    true,
                generic: true,
        },
+       {
+               name:    "TailLECall",
+               auxType: auxCallOff,
+               argLen:  -1,
+               call:    true,
+               generic: true,
+       },
        {
                name:    "SignExt8to16",
                argLen:  1,
@@ -36201,6 +36863,12 @@ var opcodeTable = [...]opInfo{
                hasSideEffects: true,
                generic:        true,
        },
+       {
+               name:           "PubBarrier",
+               argLen:         1,
+               hasSideEffects: true,
+               generic:        true,
+       },
        {
                name:      "Clobber",
                auxType:   auxSymOff,
@@ -36213,6 +36881,18 @@ var opcodeTable = [...]opInfo{
                argLen:  0,
                generic: true,
        },
+       {
+               name:           "PrefetchCache",
+               argLen:         2,
+               hasSideEffects: true,
+               generic:        true,
+       },
+       {
+               name:           "PrefetchCacheStreamed",
+               argLen:         2,
+               hasSideEffects: true,
+               generic:        true,
+       },
 }
 
 func (o Op) Asm() obj.As          { return opcodeTable[o].asm }
@@ -36220,6 +36900,7 @@ func (o Op) Scale() int16         { return int16(opcodeTable[o].scale) }
 func (o Op) String() string       { return opcodeTable[o].name }
 func (o Op) SymEffect() SymEffect { return opcodeTable[o].symEffect }
 func (o Op) IsCall() bool         { return opcodeTable[o].call }
+func (o Op) IsTailCall() bool     { return opcodeTable[o].tailCall }
 func (o Op) HasSideEffects() bool { return opcodeTable[o].hasSideEffects }
 func (o Op) UnsafePoint() bool    { return opcodeTable[o].unsafePoint }
 func (o Op) ResultInArg0() bool   { return opcodeTable[o].resultInArg0 }
@@ -36602,44 +37283,44 @@ var registersPPC64 = [...]Register{
        {62, ppc64.REG_F30, -1, "F30"},
        {63, ppc64.REG_F31, -1, "F31"},
 }
-var paramIntRegPPC64 = []int8(nil)
-var paramFloatRegPPC64 = []int8(nil)
+var paramIntRegPPC64 = []int8{3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16, 17}
+var paramFloatRegPPC64 = []int8{33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}
 var gpRegMaskPPC64 = regMask(1073733624)
 var fpRegMaskPPC64 = regMask(576460743713488896)
 var specialRegMaskPPC64 = regMask(0)
-var framepointerRegPPC64 = int8(1)
+var framepointerRegPPC64 = int8(-1)
 var linkRegPPC64 = int8(-1)
 var registersRISCV64 = [...]Register{
        {0, riscv.REG_X0, -1, "X0"},
        {1, riscv.REGSP, -1, "SP"},
-       {2, riscv.REG_X3, 0, "X3"},
+       {2, riscv.REG_X3, -1, "X3"},
        {3, riscv.REG_X4, -1, "X4"},
-       {4, riscv.REG_X5, 1, "X5"},
-       {5, riscv.REG_X6, 2, "X6"},
-       {6, riscv.REG_X7, 3, "X7"},
-       {7, riscv.REG_X8, 4, "X8"},
-       {8, riscv.REG_X9, 5, "X9"},
-       {9, riscv.REG_X10, 6, "X10"},
-       {10, riscv.REG_X11, 7, "X11"},
-       {11, riscv.REG_X12, 8, "X12"},
-       {12, riscv.REG_X13, 9, "X13"},
-       {13, riscv.REG_X14, 10, "X14"},
-       {14, riscv.REG_X15, 11, "X15"},
-       {15, riscv.REG_X16, 12, "X16"},
-       {16, riscv.REG_X17, 13, "X17"},
-       {17, riscv.REG_X18, 14, "X18"},
-       {18, riscv.REG_X19, 15, "X19"},
-       {19, riscv.REG_X20, 16, "X20"},
-       {20, riscv.REG_X21, 17, "X21"},
-       {21, riscv.REG_X22, 18, "X22"},
-       {22, riscv.REG_X23, 19, "X23"},
-       {23, riscv.REG_X24, 20, "X24"},
-       {24, riscv.REG_X25, 21, "X25"},
-       {25, riscv.REG_X26, 22, "X26"},
+       {4, riscv.REG_X5, 0, "X5"},
+       {5, riscv.REG_X6, 1, "X6"},
+       {6, riscv.REG_X7, 2, "X7"},
+       {7, riscv.REG_X8, 3, "X8"},
+       {8, riscv.REG_X9, 4, "X9"},
+       {9, riscv.REG_X10, 5, "X10"},
+       {10, riscv.REG_X11, 6, "X11"},
+       {11, riscv.REG_X12, 7, "X12"},
+       {12, riscv.REG_X13, 8, "X13"},
+       {13, riscv.REG_X14, 9, "X14"},
+       {14, riscv.REG_X15, 10, "X15"},
+       {15, riscv.REG_X16, 11, "X16"},
+       {16, riscv.REG_X17, 12, "X17"},
+       {17, riscv.REG_X18, 13, "X18"},
+       {18, riscv.REG_X19, 14, "X19"},
+       {19, riscv.REG_X20, 15, "X20"},
+       {20, riscv.REG_X21, 16, "X21"},
+       {21, riscv.REG_X22, 17, "X22"},
+       {22, riscv.REG_X23, 18, "X23"},
+       {23, riscv.REG_X24, 19, "X24"},
+       {24, riscv.REG_X25, 20, "X25"},
+       {25, riscv.REG_X26, 21, "X26"},
        {26, riscv.REGG, -1, "g"},
-       {27, riscv.REG_X28, 23, "X28"},
-       {28, riscv.REG_X29, 24, "X29"},
-       {29, riscv.REG_X30, 25, "X30"},
+       {27, riscv.REG_X28, 22, "X28"},
+       {28, riscv.REG_X29, 23, "X29"},
+       {29, riscv.REG_X30, 24, "X30"},
        {30, riscv.REG_X31, -1, "X31"},
        {31, riscv.REG_F0, -1, "F0"},
        {32, riscv.REG_F1, -1, "F1"},
@@ -36677,7 +37358,7 @@ var registersRISCV64 = [...]Register{
 }
 var paramIntRegRISCV64 = []int8(nil)
 var paramFloatRegRISCV64 = []int8(nil)
-var gpRegMaskRISCV64 = regMask(1006632948)
+var gpRegMaskRISCV64 = regMask(1006632944)
 var fpRegMaskRISCV64 = regMask(9223372034707292160)
 var specialRegMaskRISCV64 = regMask(0)
 var framepointerRegRISCV64 = int8(-1)
index d917183c70f5e8f23ff904a6421983e8a1770b25..96cd2c7c90a539677ec393f03708c49106a6372d 100644 (file)
@@ -6,6 +6,7 @@ package ssa
 
 import (
        "bytes"
+       "cmd/internal/src"
        "crypto/sha256"
        "fmt"
        "io"
@@ -17,22 +18,30 @@ func printFunc(f *Func) {
 
 func hashFunc(f *Func) []byte {
        h := sha256.New()
-       p := stringFuncPrinter{w: h}
+       p := stringFuncPrinter{w: h, printDead: true}
        fprintFunc(p, f)
        return h.Sum(nil)
 }
 
 func (f *Func) String() string {
        var buf bytes.Buffer
-       p := stringFuncPrinter{w: &buf}
+       p := stringFuncPrinter{w: &buf, printDead: true}
        fprintFunc(p, f)
        return buf.String()
 }
 
+// rewriteHash returns a hash of f suitable for detecting rewrite cycles.
+func (f *Func) rewriteHash() string {
+       h := sha256.New()
+       p := stringFuncPrinter{w: h, printDead: false}
+       fprintFunc(p, f)
+       return fmt.Sprintf("%x", h.Sum(nil))
+}
+
 type funcPrinter interface {
        header(f *Func)
        startBlock(b *Block, reachable bool)
-       endBlock(b *Block)
+       endBlock(b *Block, reachable bool)
        value(v *Value, live bool)
        startDepCycle()
        endDepCycle()
@@ -40,7 +49,8 @@ type funcPrinter interface {
 }
 
 type stringFuncPrinter struct {
-       w io.Writer
+       w         io.Writer
+       printDead bool
 }
 
 func (p stringFuncPrinter) header(f *Func) {
@@ -50,6 +60,9 @@ func (p stringFuncPrinter) header(f *Func) {
 }
 
 func (p stringFuncPrinter) startBlock(b *Block, reachable bool) {
+       if !p.printDead && !reachable {
+               return
+       }
        fmt.Fprintf(p.w, "  b%d:", b.ID)
        if len(b.Preds) > 0 {
                io.WriteString(p.w, " <-")
@@ -64,14 +77,33 @@ func (p stringFuncPrinter) startBlock(b *Block, reachable bool) {
        io.WriteString(p.w, "\n")
 }
 
-func (p stringFuncPrinter) endBlock(b *Block) {
+func (p stringFuncPrinter) endBlock(b *Block, reachable bool) {
+       if !p.printDead && !reachable {
+               return
+       }
        fmt.Fprintln(p.w, "    "+b.LongString())
 }
 
+func StmtString(p src.XPos) string {
+       linenumber := "(?) "
+       if p.IsKnown() {
+               pfx := ""
+               if p.IsStmt() == src.PosIsStmt {
+                       pfx = "+"
+               }
+               if p.IsStmt() == src.PosNotStmt {
+                       pfx = "-"
+               }
+               linenumber = fmt.Sprintf("(%s%d) ", pfx, p.Line())
+       }
+       return linenumber
+}
+
 func (p stringFuncPrinter) value(v *Value, live bool) {
-       fmt.Fprint(p.w, "    ")
-       //fmt.Fprint(p.w, v.Block.Func.fe.Pos(v.Pos))
-       //fmt.Fprint(p.w, ": ")
+       if !p.printDead && !live {
+               return
+       }
+       fmt.Fprintf(p.w, "    %s", StmtString(v.Pos))
        fmt.Fprint(p.w, v.LongString())
        if !live {
                fmt.Fprint(p.w, " DEAD")
@@ -103,7 +135,7 @@ func fprintFunc(p funcPrinter, f *Func) {
                                p.value(v, live[v.ID])
                                printed[v.ID] = true
                        }
-                       p.endBlock(b)
+                       p.endBlock(b, reachable[b.ID])
                        continue
                }
 
@@ -151,7 +183,7 @@ func fprintFunc(p funcPrinter, f *Func) {
                        }
                }
 
-               p.endBlock(b)
+               p.endBlock(b, reachable[b.ID])
        }
        for _, name := range f.Names {
                p.named(*name, f.NamedValues[*name])
index 3b90b8769c2f1d8ffe484b0ab40d832aea650175..64792d0c80b241663f70ae336024fd773bc20a97 100644 (file)
@@ -559,7 +559,8 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos
 func isLeaf(f *Func) bool {
        for _, b := range f.Blocks {
                for _, v := range b.Values {
-                       if opcodeTable[v.Op].call {
+                       if v.Op.IsCall() && !v.Op.IsTailCall() {
+                               // tail call is not counted as it does not save the return PC or need a frame
                                return false
                        }
                }
@@ -620,20 +621,22 @@ func (s *regAllocState) init(f *Func) {
        }
        if s.f.Config.ctxt.Flag_dynlink {
                switch s.f.Config.arch {
-               case "amd64":
-                       s.allocatable &^= 1 << 15 // R15
-               case "arm":
-                       s.allocatable &^= 1 << 9 // R9
-               case "ppc64le": // R2 already reserved.
-                       // nothing to do
-               case "arm64":
-                       // nothing to do?
                case "386":
                        // nothing to do.
                        // Note that for Flag_shared (position independent code)
                        // we do need to be careful, but that carefulness is hidden
                        // in the rewrite rules so we always have a free register
                        // available for global load/stores. See gen/386.rules (search for Flag_shared).
+               case "amd64":
+                       s.allocatable &^= 1 << 15 // R15
+               case "arm":
+                       s.allocatable &^= 1 << 9 // R9
+               case "arm64":
+                       // nothing to do
+               case "ppc64le": // R2 already reserved.
+                       // nothing to do
+               case "riscv64": // X3 (aka GP) and X4 (aka TP) already reserved.
+                       // nothing to do
                case "s390x":
                        s.allocatable &^= 1 << 11 // R11
                default:
@@ -1840,7 +1843,7 @@ func (s *regAllocState) regalloc(f *Func) {
                                if s.f.pass.debug > regDebug {
                                        fmt.Printf("delete copied value %s\n", c.LongString())
                                }
-                               c.RemoveArg(0)
+                               c.resetArgs()
                                f.freeValue(c)
                                delete(s.copies, c)
                                progress = true
@@ -1865,23 +1868,6 @@ func (s *regAllocState) regalloc(f *Func) {
 }
 
 func (s *regAllocState) placeSpills() {
-       f := s.f
-
-       // Precompute some useful info.
-       phiRegs := make([]regMask, f.NumBlocks())
-       for _, b := range s.visitOrder {
-               var m regMask
-               for _, v := range b.Values {
-                       if v.Op != OpPhi {
-                               break
-                       }
-                       if r, ok := f.getHome(v.ID).(*Register); ok {
-                               m |= regMask(1) << uint(r.num)
-                       }
-               }
-               phiRegs[b.ID] = m
-       }
-
        mustBeFirst := func(op Op) bool {
                return op.isLoweredGetClosurePtr() || op == OpPhi || op == OpArgIntReg || op == OpArgFloatReg
        }
index 115d5639333d89fd876f6fabbe7713d6a8fa77bd..9136c59e65494f8ee56341965a652f04bd1466ab 100644 (file)
@@ -36,6 +36,8 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValu
        if debug > 1 {
                fmt.Printf("%s: rewriting for %s\n", f.pass.name, f.Name)
        }
+       var iters int
+       var states map[string]bool
        for {
                change := false
                for _, b := range f.Blocks {
@@ -146,6 +148,30 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValu
                if !change {
                        break
                }
+               iters++
+               if iters > 1000 || debug >= 2 {
+                       // We've done a suspiciously large number of rewrites (or we're in debug mode).
+                       // As of Sep 2021, 90% of rewrites complete in 4 iterations or fewer
+                       // and the maximum value encountered during make.bash is 12.
+                       // Start checking for cycles. (This is too expensive to do routinely.)
+                       if states == nil {
+                               states = make(map[string]bool)
+                       }
+                       h := f.rewriteHash()
+                       if _, ok := states[h]; ok {
+                               // We've found a cycle.
+                               // To diagnose it, set debug to 2 and start again,
+                               // so that we'll print all rules applied until we complete another cycle.
+                               // If debug is already >= 2, we've already done that, so it's time to crash.
+                               if debug < 2 {
+                                       debug = 2
+                                       states = make(map[string]bool)
+                               } else {
+                                       f.Fatalf("rewrite cycle detected")
+                               }
+                       }
+                       states[h] = true
+               }
        }
        // remove clobbered values
        for _, b := range f.Blocks {
@@ -389,6 +415,11 @@ func isSameCall(sym interface{}, name string) bool {
        return fn != nil && fn.String() == name
 }
 
+// canLoadUnaligned reports if the achitecture supports unaligned load operations
+func canLoadUnaligned(c *Config) bool {
+       return c.ctxt.Arch.Alignment == 1
+}
+
 // nlz returns the number of leading zeros.
 func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
 func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
@@ -785,7 +816,11 @@ func devirtLECall(v *Value, sym *obj.LSym) *Value {
        v.Op = OpStaticLECall
        auxcall := v.Aux.(*AuxCall)
        auxcall.Fn = sym
-       v.RemoveArg(0)
+       // Remove first arg
+       v.Args[0].Uses--
+       copy(v.Args[0:], v.Args[1:])
+       v.Args[len(v.Args)-1] = nil // aid GC
+       v.Args = v.Args[:len(v.Args)-1]
        return v
 }
 
@@ -1253,7 +1288,7 @@ func zeroUpper32Bits(x *Value, depth int) bool {
                OpAMD64SHLL, OpAMD64SHLLconst:
                return true
        case OpArg:
-               return x.Type.Width == 4
+               return x.Type.Size() == 4
        case OpPhi, OpSelect0, OpSelect1:
                // Phis can use each-other as an arguments, instead of tracking visited values,
                // just limit recursion depth.
@@ -1277,7 +1312,7 @@ func zeroUpper48Bits(x *Value, depth int) bool {
        case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2:
                return true
        case OpArg:
-               return x.Type.Width == 2
+               return x.Type.Size() == 2
        case OpPhi, OpSelect0, OpSelect1:
                // Phis can use each-other as an arguments, instead of tracking visited values,
                // just limit recursion depth.
@@ -1301,7 +1336,7 @@ func zeroUpper56Bits(x *Value, depth int) bool {
        case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1:
                return true
        case OpArg:
-               return x.Type.Width == 1
+               return x.Type.Size() == 1
        case OpPhi, OpSelect0, OpSelect1:
                // Phis can use each-other as an arguments, instead of tracking visited values,
                // just limit recursion depth.
@@ -1541,12 +1576,16 @@ func rotateLeft32(v, rotate int64) int64 {
        return int64(bits.RotateLeft32(uint32(v), int(rotate)))
 }
 
+func rotateRight64(v, rotate int64) int64 {
+       return int64(bits.RotateLeft64(uint64(v), int(-rotate)))
+}
+
 // encodes the lsb and width for arm(64) bitfield ops into the expected auxInt format.
 func armBFAuxInt(lsb, width int64) arm64BitField {
        if lsb < 0 || lsb > 63 {
                panic("ARM(64) bit field lsb constant out of range")
        }
-       if width < 1 || width > 64 {
+       if width < 1 || lsb+width > 64 {
                panic("ARM(64) bit field width constant out of range")
        }
        return arm64BitField(width | lsb<<8)
index 1ec2d26f750f6b7998933fca8cbeb668d9188f1a..34f37867cf6149140eb883b4f67f37e26c1cb179 100644 (file)
@@ -652,6 +652,9 @@ func rewriteValue386(v *Value) bool {
        case OpSubPtr:
                v.Op = Op386SUBL
                return true
+       case OpTailCall:
+               v.Op = Op386CALLtail
+               return true
        case OpTrunc16to8:
                v.Op = OpCopy
                return true
index 89d32c06572cff466f3390c6757a84f0c839a25f..0c789d6b496477c66c4213b220d1cd9d4a2e6708 100644 (file)
@@ -3,6 +3,7 @@
 
 package ssa
 
+import "internal/buildcfg"
 import "math"
 import "cmd/internal/obj"
 import "cmd/compile/internal/types"
@@ -53,6 +54,10 @@ func rewriteValueAMD64(v *Value) bool {
                return rewriteValueAMD64_OpAMD64ANDLload(v)
        case OpAMD64ANDLmodify:
                return rewriteValueAMD64_OpAMD64ANDLmodify(v)
+       case OpAMD64ANDNL:
+               return rewriteValueAMD64_OpAMD64ANDNL(v)
+       case OpAMD64ANDNQ:
+               return rewriteValueAMD64_OpAMD64ANDNQ(v)
        case OpAMD64ANDQ:
                return rewriteValueAMD64_OpAMD64ANDQ(v)
        case OpAMD64ANDQconst:
@@ -65,6 +70,10 @@ func rewriteValueAMD64(v *Value) bool {
                return rewriteValueAMD64_OpAMD64ANDQmodify(v)
        case OpAMD64BSFQ:
                return rewriteValueAMD64_OpAMD64BSFQ(v)
+       case OpAMD64BSWAPL:
+               return rewriteValueAMD64_OpAMD64BSWAPL(v)
+       case OpAMD64BSWAPQ:
+               return rewriteValueAMD64_OpAMD64BSWAPQ(v)
        case OpAMD64BTCLconst:
                return rewriteValueAMD64_OpAMD64BTCLconst(v)
        case OpAMD64BTCQconst:
@@ -213,6 +222,10 @@ func rewriteValueAMD64(v *Value) bool {
                return rewriteValueAMD64_OpAMD64LEAQ4(v)
        case OpAMD64LEAQ8:
                return rewriteValueAMD64_OpAMD64LEAQ8(v)
+       case OpAMD64MOVBELstore:
+               return rewriteValueAMD64_OpAMD64MOVBELstore(v)
+       case OpAMD64MOVBEQstore:
+               return rewriteValueAMD64_OpAMD64MOVBEQstore(v)
        case OpAMD64MOVBQSX:
                return rewriteValueAMD64_OpAMD64MOVBQSX(v)
        case OpAMD64MOVBQSXload:
@@ -249,6 +262,8 @@ func rewriteValueAMD64(v *Value) bool {
                return rewriteValueAMD64_OpAMD64MOVOload(v)
        case OpAMD64MOVOstore:
                return rewriteValueAMD64_OpAMD64MOVOstore(v)
+       case OpAMD64MOVOstoreconst:
+               return rewriteValueAMD64_OpAMD64MOVOstoreconst(v)
        case OpAMD64MOVQatomicload:
                return rewriteValueAMD64_OpAMD64MOVQatomicload(v)
        case OpAMD64MOVQf2i:
@@ -640,13 +655,11 @@ func rewriteValueAMD64(v *Value) bool {
        case OpCtz16:
                return rewriteValueAMD64_OpCtz16(v)
        case OpCtz16NonZero:
-               v.Op = OpAMD64BSFL
-               return true
+               return rewriteValueAMD64_OpCtz16NonZero(v)
        case OpCtz32:
                return rewriteValueAMD64_OpCtz32(v)
        case OpCtz32NonZero:
-               v.Op = OpAMD64BSFL
-               return true
+               return rewriteValueAMD64_OpCtz32NonZero(v)
        case OpCtz64:
                return rewriteValueAMD64_OpCtz64(v)
        case OpCtz64NonZero:
@@ -654,8 +667,7 @@ func rewriteValueAMD64(v *Value) bool {
        case OpCtz8:
                return rewriteValueAMD64_OpCtz8(v)
        case OpCtz8NonZero:
-               v.Op = OpAMD64BSFL
-               return true
+               return rewriteValueAMD64_OpCtz8NonZero(v)
        case OpCvt32Fto32:
                v.Op = OpAMD64CVTTSS2SL
                return true
@@ -949,6 +961,12 @@ func rewriteValueAMD64(v *Value) bool {
                return true
        case OpPopCount8:
                return rewriteValueAMD64_OpPopCount8(v)
+       case OpPrefetchCache:
+               v.Op = OpAMD64PrefetchT0
+               return true
+       case OpPrefetchCacheStreamed:
+               v.Op = OpAMD64PrefetchNTA
+               return true
        case OpRotateLeft16:
                v.Op = OpAMD64ROLW
                return true
@@ -1095,6 +1113,9 @@ func rewriteValueAMD64(v *Value) bool {
        case OpSubPtr:
                v.Op = OpAMD64SUBQ
                return true
+       case OpTailCall:
+               v.Op = OpAMD64CALLtail
+               return true
        case OpTrunc:
                return rewriteValueAMD64_OpTrunc(v)
        case OpTrunc16to8:
@@ -2748,6 +2769,55 @@ func rewriteValueAMD64_OpAMD64ANDL(v *Value) bool {
                }
                break
        }
+       // match: (ANDL x (NOTL y))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (ANDNL x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64NOTL {
+                               continue
+                       }
+                       y := v_1.Args[0]
+                       if !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64ANDNL)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
+       // match: (ANDL x (NEGL x))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (BLSIL x)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64NEGL || x != v_1.Args[0] || !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64BLSIL)
+                       v.AddArg(x)
+                       return true
+               }
+               break
+       }
+       // match: (ANDL x (ADDLconst [-1] x))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (BLSRL x)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64ADDLconst || auxIntToInt32(v_1.AuxInt) != -1 || x != v_1.Args[0] || !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64BLSRL)
+                       v.AddArg(x)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64ANDLconst(v *Value) bool {
@@ -3026,6 +3096,48 @@ func rewriteValueAMD64_OpAMD64ANDLmodify(v *Value) bool {
        }
        return false
 }
+func rewriteValueAMD64_OpAMD64ANDNL(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (ANDNL x (SHLL (MOVLconst [1]) y))
+       // result: (BTRL x y)
+       for {
+               x := v_0
+               if v_1.Op != OpAMD64SHLL {
+                       break
+               }
+               y := v_1.Args[1]
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpAMD64MOVLconst || auxIntToInt32(v_1_0.AuxInt) != 1 {
+                       break
+               }
+               v.reset(OpAMD64BTRL)
+               v.AddArg2(x, y)
+               return true
+       }
+       return false
+}
+func rewriteValueAMD64_OpAMD64ANDNQ(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (ANDNQ x (SHLQ (MOVQconst [1]) y))
+       // result: (BTRQ x y)
+       for {
+               x := v_0
+               if v_1.Op != OpAMD64SHLQ {
+                       break
+               }
+               y := v_1.Args[1]
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpAMD64MOVQconst || auxIntToInt64(v_1_0.AuxInt) != 1 {
+                       break
+               }
+               v.reset(OpAMD64BTRQ)
+               v.AddArg2(x, y)
+               return true
+       }
+       return false
+}
 func rewriteValueAMD64_OpAMD64ANDQ(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -3127,6 +3239,55 @@ func rewriteValueAMD64_OpAMD64ANDQ(v *Value) bool {
                }
                break
        }
+       // match: (ANDQ x (NOTQ y))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (ANDNQ x y)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64NOTQ {
+                               continue
+                       }
+                       y := v_1.Args[0]
+                       if !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64ANDNQ)
+                       v.AddArg2(x, y)
+                       return true
+               }
+               break
+       }
+       // match: (ANDQ x (NEGQ x))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (BLSIQ x)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64NEGQ || x != v_1.Args[0] || !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64BLSIQ)
+                       v.AddArg(x)
+                       return true
+               }
+               break
+       }
+       // match: (ANDQ x (ADDQconst [-1] x))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (BLSRQ x)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64ADDQconst || auxIntToInt32(v_1.AuxInt) != -1 || x != v_1.Args[0] || !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64BLSRQ)
+                       v.AddArg(x)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64ANDQconst(v *Value) bool {
@@ -3454,6 +3615,108 @@ func rewriteValueAMD64_OpAMD64BSFQ(v *Value) bool {
        }
        return false
 }
+func rewriteValueAMD64_OpAMD64BSWAPL(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (BSWAPL (BSWAPL p))
+       // result: p
+       for {
+               if v_0.Op != OpAMD64BSWAPL {
+                       break
+               }
+               p := v_0.Args[0]
+               v.copyOf(p)
+               return true
+       }
+       // match: (BSWAPL x:(MOVLload [i] {s} p mem))
+       // cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
+       // result: (MOVBELload [i] {s} p mem)
+       for {
+               x := v_0
+               if x.Op != OpAMD64MOVLload {
+                       break
+               }
+               i := auxIntToInt32(x.AuxInt)
+               s := auxToSym(x.Aux)
+               mem := x.Args[1]
+               p := x.Args[0]
+               if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64MOVBELload)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg2(p, mem)
+               return true
+       }
+       // match: (BSWAPL (MOVBELload [i] {s} p m))
+       // result: (MOVLload [i] {s} p m)
+       for {
+               if v_0.Op != OpAMD64MOVBELload {
+                       break
+               }
+               i := auxIntToInt32(v_0.AuxInt)
+               s := auxToSym(v_0.Aux)
+               m := v_0.Args[1]
+               p := v_0.Args[0]
+               v.reset(OpAMD64MOVLload)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg2(p, m)
+               return true
+       }
+       return false
+}
+func rewriteValueAMD64_OpAMD64BSWAPQ(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (BSWAPQ (BSWAPQ p))
+       // result: p
+       for {
+               if v_0.Op != OpAMD64BSWAPQ {
+                       break
+               }
+               p := v_0.Args[0]
+               v.copyOf(p)
+               return true
+       }
+       // match: (BSWAPQ x:(MOVQload [i] {s} p mem))
+       // cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
+       // result: (MOVBEQload [i] {s} p mem)
+       for {
+               x := v_0
+               if x.Op != OpAMD64MOVQload {
+                       break
+               }
+               i := auxIntToInt32(x.AuxInt)
+               s := auxToSym(x.Aux)
+               mem := x.Args[1]
+               p := x.Args[0]
+               if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64MOVBEQload)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg2(p, mem)
+               return true
+       }
+       // match: (BSWAPQ (MOVBEQload [i] {s} p m))
+       // result: (MOVQload [i] {s} p m)
+       for {
+               if v_0.Op != OpAMD64MOVBEQload {
+                       break
+               }
+               i := auxIntToInt32(v_0.AuxInt)
+               s := auxToSym(v_0.Aux)
+               m := v_0.Args[1]
+               p := v_0.Args[0]
+               v.reset(OpAMD64MOVQload)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg2(p, m)
+               return true
+       }
+       return false
+}
 func rewriteValueAMD64_OpAMD64BTCLconst(v *Value) bool {
        v_0 := v.Args[0]
        // match: (BTCLconst [c] (XORLconst [d] x))
@@ -9210,6 +9473,52 @@ func rewriteValueAMD64_OpAMD64LEAQ8(v *Value) bool {
        }
        return false
 }
+func rewriteValueAMD64_OpAMD64MOVBELstore(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (MOVBELstore [i] {s} p (BSWAPL x) m)
+       // result: (MOVLstore [i] {s} p x m)
+       for {
+               i := auxIntToInt32(v.AuxInt)
+               s := auxToSym(v.Aux)
+               p := v_0
+               if v_1.Op != OpAMD64BSWAPL {
+                       break
+               }
+               x := v_1.Args[0]
+               m := v_2
+               v.reset(OpAMD64MOVLstore)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg3(p, x, m)
+               return true
+       }
+       return false
+}
+func rewriteValueAMD64_OpAMD64MOVBEQstore(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (MOVBEQstore [i] {s} p (BSWAPQ x) m)
+       // result: (MOVQstore [i] {s} p x m)
+       for {
+               i := auxIntToInt32(v.AuxInt)
+               s := auxToSym(v.Aux)
+               p := v_0
+               if v_1.Op != OpAMD64BSWAPQ {
+                       break
+               }
+               x := v_1.Args[0]
+               m := v_2
+               v.reset(OpAMD64MOVQstore)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg3(p, x, m)
+               return true
+       }
+       return false
+}
 func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
@@ -9630,49 +9939,6 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value) bool {
                v.AddArg2(base, mem)
                return true
        }
-       // match: (MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVBload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(base, mem)
-               return true
-       }
-       // match: (MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVBload [off1+off2] {sym} ptr mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVBload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        // match: (MOVBload [off] {sym} (SB) _)
        // cond: symIsRO(sym)
        // result: (MOVLconst [int32(read8(sym, int64(off)))])
@@ -10877,51 +11143,6 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool {
                v.AddArg3(p, v0, mem)
                return true
        }
-       // match: (MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVBstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg3(base, val, mem)
-               return true
-       }
-       // match: (MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVBstore [off1+off2] {sym} ptr val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVBstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg3(ptr, val, mem)
-               return true
-       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool {
@@ -11020,49 +11241,6 @@ func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value) bool {
                v.AddArg2(p, mem)
                return true
        }
-       // match: (MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && sc.canAdd32(off)
-       // result: (MOVBstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && sc.canAdd32(off)) {
-                       break
-               }
-               v.reset(OpAMD64MOVBstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(ptr, mem)
-               return true
-       }
-       // match: (MOVBstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
-       // cond: sc.canAdd32(off)
-       // result: (MOVBstoreconst [sc.addOffset32(off)] {s} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               s := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(sc.canAdd32(off)) {
-                       break
-               }
-               v.reset(OpAMD64MOVBstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(s)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value) bool {
@@ -11491,49 +11669,6 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value) bool {
                v.AddArg2(base, mem)
                return true
        }
-       // match: (MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVLload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(base, mem)
-               return true
-       }
-       // match: (MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVLload [off1+off2] {sym} ptr mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVLload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        // match: (MOVLload [off] {sym} ptr (MOVSSstore [off] {sym} ptr val _))
        // result: (MOVLf2i val)
        for {
@@ -11835,51 +11970,6 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
                v.AddArg3(p, v0, mem)
                return true
        }
-       // match: (MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVLstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg3(base, val, mem)
-               return true
-       }
-       // match: (MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVLstore [off1+off2] {sym} ptr val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVLstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg3(ptr, val, mem)
-               return true
-       }
        // match: (MOVLstore {sym} [off] ptr y:(ADDLload x [off] {sym} ptr mem) mem)
        // cond: y.Uses==1 && clobber(y)
        // result: (ADDLmodify [off] {sym} ptr x mem)
@@ -12259,6 +12349,28 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value) bool {
                v.AddArg3(ptr, val, mem)
                return true
        }
+       // match: (MOVLstore [i] {s} p x:(BSWAPL w) mem)
+       // cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
+       // result: (MOVBELstore [i] {s} p w mem)
+       for {
+               i := auxIntToInt32(v.AuxInt)
+               s := auxToSym(v.Aux)
+               p := v_0
+               x := v_1
+               if x.Op != OpAMD64BSWAPL {
+                       break
+               }
+               w := x.Args[0]
+               mem := v_2
+               if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64MOVBELstore)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg3(p, w, mem)
+               return true
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool {
@@ -12363,49 +12475,6 @@ func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value) bool {
                v.AddArg3(p, v0, mem)
                return true
        }
-       // match: (MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && sc.canAdd32(off)
-       // result: (MOVLstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && sc.canAdd32(off)) {
-                       break
-               }
-               v.reset(OpAMD64MOVLstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(ptr, mem)
-               return true
-       }
-       // match: (MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
-       // cond: sc.canAdd32(off)
-       // result: (MOVLstoreconst [sc.addOffset32(off)] {s} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               s := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(sc.canAdd32(off)) {
-                       break
-               }
-               v.reset(OpAMD64MOVLstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(s)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MOVOload(v *Value) bool {
@@ -12544,6 +12613,54 @@ func rewriteValueAMD64_OpAMD64MOVOstore(v *Value) bool {
        }
        return false
 }
+func rewriteValueAMD64_OpAMD64MOVOstoreconst(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (MOVOstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+       // cond: ValAndOff(sc).canAdd32(off)
+       // result: (MOVOstoreconst [ValAndOff(sc).addOffset32(off)] {s} ptr mem)
+       for {
+               sc := auxIntToValAndOff(v.AuxInt)
+               s := auxToSym(v.Aux)
+               if v_0.Op != OpAMD64ADDQconst {
+                       break
+               }
+               off := auxIntToInt32(v_0.AuxInt)
+               ptr := v_0.Args[0]
+               mem := v_1
+               if !(ValAndOff(sc).canAdd32(off)) {
+                       break
+               }
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(ValAndOff(sc).addOffset32(off))
+               v.Aux = symToAux(s)
+               v.AddArg2(ptr, mem)
+               return true
+       }
+       // match: (MOVOstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+       // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd32(off)
+       // result: (MOVOstoreconst [ValAndOff(sc).addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
+       for {
+               sc := auxIntToValAndOff(v.AuxInt)
+               sym1 := auxToSym(v.Aux)
+               if v_0.Op != OpAMD64LEAQ {
+                       break
+               }
+               off := auxIntToInt32(v_0.AuxInt)
+               sym2 := auxToSym(v_0.Aux)
+               ptr := v_0.Args[0]
+               mem := v_1
+               if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd32(off)) {
+                       break
+               }
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(ValAndOff(sc).addOffset32(off))
+               v.Aux = symToAux(mergeSym(sym1, sym2))
+               v.AddArg2(ptr, mem)
+               return true
+       }
+       return false
+}
 func rewriteValueAMD64_OpAMD64MOVQatomicload(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -12712,49 +12829,6 @@ func rewriteValueAMD64_OpAMD64MOVQload(v *Value) bool {
                v.AddArg2(base, mem)
                return true
        }
-       // match: (MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVQload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(base, mem)
-               return true
-       }
-       // match: (MOVQload [off1] {sym} (ADDLconst [off2] ptr) mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVQload [off1+off2] {sym} ptr mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVQload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        // match: (MOVQload [off] {sym} ptr (MOVSDstore [off] {sym} ptr val _))
        // result: (MOVQf2i val)
        for {
@@ -12857,51 +12931,6 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
                v.AddArg3(base, val, mem)
                return true
        }
-       // match: (MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVQstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg3(base, val, mem)
-               return true
-       }
-       // match: (MOVQstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVQstore [off1+off2] {sym} ptr val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVQstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg3(ptr, val, mem)
-               return true
-       }
        // match: (MOVQstore {sym} [off] ptr y:(ADDQload x [off] {sym} ptr mem) mem)
        // cond: y.Uses==1 && clobber(y)
        // result: (ADDQmodify [off] {sym} ptr x mem)
@@ -13281,6 +13310,28 @@ func rewriteValueAMD64_OpAMD64MOVQstore(v *Value) bool {
                v.AddArg3(ptr, val, mem)
                return true
        }
+       // match: (MOVQstore [i] {s} p x:(BSWAPQ w) mem)
+       // cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
+       // result: (MOVBEQstore [i] {s} p w mem)
+       for {
+               i := auxIntToInt32(v.AuxInt)
+               s := auxToSym(v.Aux)
+               p := v_0
+               x := v_1
+               if x.Op != OpAMD64BSWAPQ {
+                       break
+               }
+               w := x.Args[0]
+               mem := v_2
+               if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64MOVBEQstore)
+               v.AuxInt = int32ToAuxInt(i)
+               v.Aux = symToAux(s)
+               v.AddArg3(p, w, mem)
+               return true
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool {
@@ -13331,9 +13382,9 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool {
                v.AddArg2(ptr, mem)
                return true
        }
-       // match: (MOVQstoreconst [c] {s} p x:(MOVQstoreconst [c2] {s} p mem))
-       // cond: config.useSSE && x.Uses == 1 && c2.Off() + 8 == c.Off() && c.Val() == 0 && c2.Val() == 0 && clobber(x)
-       // result: (MOVOstorezero [c2.Off()] {s} p mem)
+       // match: (MOVQstoreconst [c] {s} p x:(MOVQstoreconst [a] {s} p mem))
+       // cond: config.useSSE && x.Uses == 1 && a.Off() + 8 == c.Off() && a.Val() == 0 && c.Val() == 0 && clobber(x)
+       // result: (MOVOstoreconst [makeValAndOff(0,a.Off())] {s} p mem)
        for {
                c := auxIntToValAndOff(v.AuxInt)
                s := auxToSym(v.Aux)
@@ -13342,61 +13393,43 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value) bool {
                if x.Op != OpAMD64MOVQstoreconst {
                        break
                }
-               c2 := auxIntToValAndOff(x.AuxInt)
+               a := auxIntToValAndOff(x.AuxInt)
                if auxToSym(x.Aux) != s {
                        break
                }
                mem := x.Args[1]
-               if p != x.Args[0] || !(config.useSSE && x.Uses == 1 && c2.Off()+8 == c.Off() && c.Val() == 0 && c2.Val() == 0 && clobber(x)) {
+               if p != x.Args[0] || !(config.useSSE && x.Uses == 1 && a.Off()+8 == c.Off() && a.Val() == 0 && c.Val() == 0 && clobber(x)) {
                        break
                }
-               v.reset(OpAMD64MOVOstorezero)
-               v.AuxInt = int32ToAuxInt(c2.Off())
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, a.Off()))
                v.Aux = symToAux(s)
                v.AddArg2(p, mem)
                return true
        }
-       // match: (MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && sc.canAdd32(off)
-       // result: (MOVQstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
+       // match: (MOVQstoreconst [a] {s} p x:(MOVQstoreconst [c] {s} p mem))
+       // cond: config.useSSE && x.Uses == 1 && a.Off() + 8 == c.Off() && a.Val() == 0 && c.Val() == 0 && clobber(x)
+       // result: (MOVOstoreconst [makeValAndOff(0,a.Off())] {s} p mem)
        for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && sc.canAdd32(off)) {
+               a := auxIntToValAndOff(v.AuxInt)
+               s := auxToSym(v.Aux)
+               p := v_0
+               x := v_1
+               if x.Op != OpAMD64MOVQstoreconst {
                        break
                }
-               v.reset(OpAMD64MOVQstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(ptr, mem)
-               return true
-       }
-       // match: (MOVQstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
-       // cond: sc.canAdd32(off)
-       // result: (MOVQstoreconst [sc.addOffset32(off)] {s} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               s := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
+               c := auxIntToValAndOff(x.AuxInt)
+               if auxToSym(x.Aux) != s {
                        break
                }
-               off := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(sc.canAdd32(off)) {
+               mem := x.Args[1]
+               if p != x.Args[0] || !(config.useSSE && x.Uses == 1 && a.Off()+8 == c.Off() && a.Val() == 0 && c.Val() == 0 && clobber(x)) {
                        break
                }
-               v.reset(OpAMD64MOVQstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, a.Off()))
                v.Aux = symToAux(s)
-               v.AddArg2(ptr, mem)
+               v.AddArg2(p, mem)
                return true
        }
        return false
@@ -14017,49 +14050,6 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value) bool {
                v.AddArg2(base, mem)
                return true
        }
-       // match: (MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVWload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(base, mem)
-               return true
-       }
-       // match: (MOVWload [off1] {sym} (ADDLconst [off2] ptr) mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVWload [off1+off2] {sym} ptr mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVWload)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        // match: (MOVWload [off] {sym} (SB) _)
        // cond: symIsRO(sym)
        // result: (MOVLconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
@@ -14453,51 +14443,6 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool {
                v.AddArg3(p, v0, mem)
                return true
        }
-       // match: (MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
-       // cond: canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))
-       // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               base := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVWstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg3(base, val, mem)
-               return true
-       }
-       // match: (MOVWstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
-       // cond: is32Bit(int64(off1)+int64(off2))
-       // result: (MOVWstore [off1+off2] {sym} ptr val mem)
-       for {
-               off1 := auxIntToInt32(v.AuxInt)
-               sym := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off2 := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               val := v_1
-               mem := v_2
-               if !(is32Bit(int64(off1) + int64(off2))) {
-                       break
-               }
-               v.reset(OpAMD64MOVWstore)
-               v.AuxInt = int32ToAuxInt(off1 + off2)
-               v.Aux = symToAux(sym)
-               v.AddArg3(ptr, val, mem)
-               return true
-       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool {
@@ -14596,49 +14541,6 @@ func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool {
                v.AddArg2(p, mem)
                return true
        }
-       // match: (MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
-       // cond: canMergeSym(sym1, sym2) && sc.canAdd32(off)
-       // result: (MOVWstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               sym1 := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64LEAL {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               sym2 := auxToSym(v_0.Aux)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(canMergeSym(sym1, sym2) && sc.canAdd32(off)) {
-                       break
-               }
-               v.reset(OpAMD64MOVWstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(mergeSym(sym1, sym2))
-               v.AddArg2(ptr, mem)
-               return true
-       }
-       // match: (MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
-       // cond: sc.canAdd32(off)
-       // result: (MOVWstoreconst [sc.addOffset32(off)] {s} ptr mem)
-       for {
-               sc := auxIntToValAndOff(v.AuxInt)
-               s := auxToSym(v.Aux)
-               if v_0.Op != OpAMD64ADDLconst {
-                       break
-               }
-               off := auxIntToInt32(v_0.AuxInt)
-               ptr := v_0.Args[0]
-               mem := v_1
-               if !(sc.canAdd32(off)) {
-                       break
-               }
-               v.reset(OpAMD64MOVWstoreconst)
-               v.AuxInt = valAndOffToAuxInt(sc.addOffset32(off))
-               v.Aux = symToAux(s)
-               v.AddArg2(ptr, mem)
-               return true
-       }
        return false
 }
 func rewriteValueAMD64_OpAMD64MULL(v *Value) bool {
@@ -18923,6 +18825,81 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value) bool {
                }
                break
        }
+       // match: (ORQ x0:(MOVBELload [i0] {s} p mem) sh:(SHLQconst [32] x1:(MOVBELload [i1] {s} p mem)))
+       // cond: i0 == i1+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh)
+       // result: @mergePoint(b,x0,x1) (MOVBEQload [i1] {s} p mem)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x0 := v_0
+                       if x0.Op != OpAMD64MOVBELload {
+                               continue
+                       }
+                       i0 := auxIntToInt32(x0.AuxInt)
+                       s := auxToSym(x0.Aux)
+                       mem := x0.Args[1]
+                       p := x0.Args[0]
+                       sh := v_1
+                       if sh.Op != OpAMD64SHLQconst || auxIntToInt8(sh.AuxInt) != 32 {
+                               continue
+                       }
+                       x1 := sh.Args[0]
+                       if x1.Op != OpAMD64MOVBELload {
+                               continue
+                       }
+                       i1 := auxIntToInt32(x1.AuxInt)
+                       if auxToSym(x1.Aux) != s {
+                               continue
+                       }
+                       _ = x1.Args[1]
+                       if p != x1.Args[0] || mem != x1.Args[1] || !(i0 == i1+4 && x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) {
+                               continue
+                       }
+                       b = mergePoint(b, x0, x1)
+                       v0 := b.NewValue0(x1.Pos, OpAMD64MOVBEQload, typ.UInt64)
+                       v.copyOf(v0)
+                       v0.AuxInt = int32ToAuxInt(i1)
+                       v0.Aux = symToAux(s)
+                       v0.AddArg2(p, mem)
+                       return true
+               }
+               break
+       }
+       // match: (ORQ x0:(MOVBELload [i] {s} p0 mem) sh:(SHLQconst [32] x1:(MOVBELload [i] {s} p1 mem)))
+       // cond: x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p1, p0, 4) && mergePoint(b,x0,x1) != nil && clobber(x0, x1, sh)
+       // result: @mergePoint(b,x0,x1) (MOVBEQload [i] {s} p1 mem)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x0 := v_0
+                       if x0.Op != OpAMD64MOVBELload {
+                               continue
+                       }
+                       i := auxIntToInt32(x0.AuxInt)
+                       s := auxToSym(x0.Aux)
+                       mem := x0.Args[1]
+                       p0 := x0.Args[0]
+                       sh := v_1
+                       if sh.Op != OpAMD64SHLQconst || auxIntToInt8(sh.AuxInt) != 32 {
+                               continue
+                       }
+                       x1 := sh.Args[0]
+                       if x1.Op != OpAMD64MOVBELload || auxIntToInt32(x1.AuxInt) != i || auxToSym(x1.Aux) != s {
+                               continue
+                       }
+                       _ = x1.Args[1]
+                       p1 := x1.Args[0]
+                       if mem != x1.Args[1] || !(x0.Uses == 1 && x1.Uses == 1 && sh.Uses == 1 && sequentialAddresses(p1, p0, 4) && mergePoint(b, x0, x1) != nil && clobber(x0, x1, sh)) {
+                               continue
+                       }
+                       b = mergePoint(b, x0, x1)
+                       v0 := b.NewValue0(x1.Pos, OpAMD64MOVBEQload, typ.UInt64)
+                       v.copyOf(v0)
+                       v0.AuxInt = int32ToAuxInt(i)
+                       v0.Aux = symToAux(s)
+                       v0.AddArg2(p1, mem)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64ORQconst(v *Value) bool {
@@ -26914,6 +26891,21 @@ func rewriteValueAMD64_OpAMD64XORL(v *Value) bool {
                }
                break
        }
+       // match: (XORL x (ADDLconst [-1] x))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (BLSMSKL x)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64ADDLconst || auxIntToInt32(v_1.AuxInt) != -1 || x != v_1.Args[0] || !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64BLSMSKL)
+                       v.AddArg(x)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64XORLconst(v *Value) bool {
@@ -27390,6 +27382,21 @@ func rewriteValueAMD64_OpAMD64XORQ(v *Value) bool {
                }
                break
        }
+       // match: (XORQ x (ADDQconst [-1] x))
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (BLSMSKQ x)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAMD64ADDQconst || auxIntToInt32(v_1.AuxInt) != -1 || x != v_1.Args[0] || !(buildcfg.GOAMD64 >= 3) {
+                               continue
+                       }
+                       v.reset(OpAMD64BLSMSKQ)
+                       v.AddArg(x)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueAMD64_OpAMD64XORQconst(v *Value) bool {
@@ -28959,14 +28966,58 @@ func rewriteValueAMD64_OpCtz16(v *Value) bool {
                return true
        }
 }
+func rewriteValueAMD64_OpCtz16NonZero(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (Ctz16NonZero x)
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (TZCNTL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64TZCNTL)
+               v.AddArg(x)
+               return true
+       }
+       // match: (Ctz16NonZero x)
+       // cond: buildcfg.GOAMD64 < 3
+       // result: (BSFL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 < 3) {
+                       break
+               }
+               v.reset(OpAMD64BSFL)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
 func rewriteValueAMD64_OpCtz32(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
        typ := &b.Func.Config.Types
        // match: (Ctz32 x)
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (TZCNTL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64TZCNTL)
+               v.AddArg(x)
+               return true
+       }
+       // match: (Ctz32 x)
+       // cond: buildcfg.GOAMD64 < 3
        // result: (Select0 (BSFQ (BTSQconst <typ.UInt64> [32] x)))
        for {
                x := v_0
+               if !(buildcfg.GOAMD64 < 3) {
+                       break
+               }
                v.reset(OpSelect0)
                v0 := b.NewValue0(v.Pos, OpAMD64BSFQ, types.NewTuple(typ.UInt64, types.TypeFlags))
                v1 := b.NewValue0(v.Pos, OpAMD64BTSQconst, typ.UInt64)
@@ -28976,16 +29027,61 @@ func rewriteValueAMD64_OpCtz32(v *Value) bool {
                v.AddArg(v0)
                return true
        }
+       return false
+}
+func rewriteValueAMD64_OpCtz32NonZero(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (Ctz32NonZero x)
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (TZCNTL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64TZCNTL)
+               v.AddArg(x)
+               return true
+       }
+       // match: (Ctz32NonZero x)
+       // cond: buildcfg.GOAMD64 < 3
+       // result: (BSFL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 < 3) {
+                       break
+               }
+               v.reset(OpAMD64BSFL)
+               v.AddArg(x)
+               return true
+       }
+       return false
 }
 func rewriteValueAMD64_OpCtz64(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
        typ := &b.Func.Config.Types
+       // match: (Ctz64 x)
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (TZCNTQ x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64TZCNTQ)
+               v.AddArg(x)
+               return true
+       }
        // match: (Ctz64 <t> x)
+       // cond: buildcfg.GOAMD64 < 3
        // result: (CMOVQEQ (Select0 <t> (BSFQ x)) (MOVQconst <t> [64]) (Select1 <types.TypeFlags> (BSFQ x)))
        for {
                t := v.Type
                x := v_0
+               if !(buildcfg.GOAMD64 < 3) {
+                       break
+               }
                v.reset(OpAMD64CMOVQEQ)
                v0 := b.NewValue0(v.Pos, OpSelect0, t)
                v1 := b.NewValue0(v.Pos, OpAMD64BSFQ, types.NewTuple(typ.UInt64, types.TypeFlags))
@@ -28998,21 +29094,39 @@ func rewriteValueAMD64_OpCtz64(v *Value) bool {
                v.AddArg3(v0, v2, v3)
                return true
        }
+       return false
 }
 func rewriteValueAMD64_OpCtz64NonZero(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
        typ := &b.Func.Config.Types
        // match: (Ctz64NonZero x)
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (TZCNTQ x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64TZCNTQ)
+               v.AddArg(x)
+               return true
+       }
+       // match: (Ctz64NonZero x)
+       // cond: buildcfg.GOAMD64 < 3
        // result: (Select0 (BSFQ x))
        for {
                x := v_0
+               if !(buildcfg.GOAMD64 < 3) {
+                       break
+               }
                v.reset(OpSelect0)
                v0 := b.NewValue0(v.Pos, OpAMD64BSFQ, types.NewTuple(typ.UInt64, types.TypeFlags))
                v0.AddArg(x)
                v.AddArg(v0)
                return true
        }
+       return false
 }
 func rewriteValueAMD64_OpCtz8(v *Value) bool {
        v_0 := v.Args[0]
@@ -29030,6 +29144,34 @@ func rewriteValueAMD64_OpCtz8(v *Value) bool {
                return true
        }
 }
+func rewriteValueAMD64_OpCtz8NonZero(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (Ctz8NonZero x)
+       // cond: buildcfg.GOAMD64 >= 3
+       // result: (TZCNTL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 >= 3) {
+                       break
+               }
+               v.reset(OpAMD64TZCNTL)
+               v.AddArg(x)
+               return true
+       }
+       // match: (Ctz8NonZero x)
+       // cond: buildcfg.GOAMD64 < 3
+       // result: (BSFL x)
+       for {
+               x := v_0
+               if !(buildcfg.GOAMD64 < 3) {
+                       break
+               }
+               v.reset(OpAMD64BSFL)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
 func rewriteValueAMD64_OpDiv16(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -29355,11 +29497,11 @@ func rewriteValueAMD64_OpHasCPUFeature(v *Value) bool {
        b := v.Block
        typ := &b.Func.Config.Types
        // match: (HasCPUFeature {s})
-       // result: (SETNE (CMPQconst [0] (LoweredHasCPUFeature {s})))
+       // result: (SETNE (CMPLconst [0] (LoweredHasCPUFeature {s})))
        for {
                s := auxToSym(v.Aux)
                v.reset(OpAMD64SETNE)
-               v0 := b.NewValue0(v.Pos, OpAMD64CMPQconst, types.TypeFlags)
+               v0 := b.NewValue0(v.Pos, OpAMD64CMPLconst, types.TypeFlags)
                v0.AuxInt = int32ToAuxInt(0)
                v1 := b.NewValue0(v.Pos, OpAMD64LoweredHasCPUFeature, typ.UInt64)
                v1.Aux = symToAux(s)
@@ -33458,7 +33600,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
        }
        // match: (Zero [s] destptr mem)
        // cond: s%16 != 0 && s > 16 && s%16 > 8 && config.useSSE
-       // result: (Zero [s-s%16] (OffPtr <destptr.Type> destptr [s%16]) (MOVOstorezero destptr mem))
+       // result: (Zero [s-s%16] (OffPtr <destptr.Type> destptr [s%16]) (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))
        for {
                s := auxIntToInt64(v.AuxInt)
                destptr := v_0
@@ -33471,14 +33613,15 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
                v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
                v0.AuxInt = int64ToAuxInt(s % 16)
                v0.AddArg(destptr)
-               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
+               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0))
                v1.AddArg2(destptr, mem)
                v.AddArg2(v0, v1)
                return true
        }
        // match: (Zero [s] destptr mem)
        // cond: s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE
-       // result: (Zero [s-s%16] (OffPtr <destptr.Type> destptr [s%16]) (MOVQstoreconst [makeValAndOff(0,0)] destptr mem))
+       // result: (Zero [s-s%16] (OffPtr <destptr.Type> destptr [s%16]) (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))
        for {
                s := auxIntToInt64(v.AuxInt)
                destptr := v_0
@@ -33491,7 +33634,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
                v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
                v0.AuxInt = int64ToAuxInt(s % 16)
                v0.AddArg(destptr)
-               v1 := b.NewValue0(v.Pos, OpAMD64MOVQstoreconst, types.TypeMem)
+               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
                v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0))
                v1.AddArg2(destptr, mem)
                v.AddArg2(v0, v1)
@@ -33499,7 +33642,7 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
        }
        // match: (Zero [16] destptr mem)
        // cond: config.useSSE
-       // result: (MOVOstorezero destptr mem)
+       // result: (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)
        for {
                if auxIntToInt64(v.AuxInt) != 16 {
                        break
@@ -33509,13 +33652,14 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
                if !(config.useSSE) {
                        break
                }
-               v.reset(OpAMD64MOVOstorezero)
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0))
                v.AddArg2(destptr, mem)
                return true
        }
        // match: (Zero [32] destptr mem)
        // cond: config.useSSE
-       // result: (MOVOstorezero (OffPtr <destptr.Type> destptr [16]) (MOVOstorezero destptr mem))
+       // result: (MOVOstoreconst [makeValAndOff(0,16)] destptr (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))
        for {
                if auxIntToInt64(v.AuxInt) != 32 {
                        break
@@ -33525,18 +33669,17 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
                if !(config.useSSE) {
                        break
                }
-               v.reset(OpAMD64MOVOstorezero)
-               v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
-               v0.AuxInt = int64ToAuxInt(16)
-               v0.AddArg(destptr)
-               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
-               v1.AddArg2(destptr, mem)
-               v.AddArg2(v0, v1)
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 16))
+               v0 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0))
+               v0.AddArg2(destptr, mem)
+               v.AddArg2(destptr, v0)
                return true
        }
        // match: (Zero [48] destptr mem)
        // cond: config.useSSE
-       // result: (MOVOstorezero (OffPtr <destptr.Type> destptr [32]) (MOVOstorezero (OffPtr <destptr.Type> destptr [16]) (MOVOstorezero destptr mem)))
+       // result: (MOVOstoreconst [makeValAndOff(0,32)] destptr (MOVOstoreconst [makeValAndOff(0,16)] destptr (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)))
        for {
                if auxIntToInt64(v.AuxInt) != 48 {
                        break
@@ -33546,23 +33689,20 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
                if !(config.useSSE) {
                        break
                }
-               v.reset(OpAMD64MOVOstorezero)
-               v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
-               v0.AuxInt = int64ToAuxInt(32)
-               v0.AddArg(destptr)
-               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
-               v2 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
-               v2.AuxInt = int64ToAuxInt(16)
-               v2.AddArg(destptr)
-               v3 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
-               v3.AddArg2(destptr, mem)
-               v1.AddArg2(v2, v3)
-               v.AddArg2(v0, v1)
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 32))
+               v0 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 16))
+               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0))
+               v1.AddArg2(destptr, mem)
+               v0.AddArg2(destptr, v1)
+               v.AddArg2(destptr, v0)
                return true
        }
        // match: (Zero [64] destptr mem)
        // cond: config.useSSE
-       // result: (MOVOstorezero (OffPtr <destptr.Type> destptr [48]) (MOVOstorezero (OffPtr <destptr.Type> destptr [32]) (MOVOstorezero (OffPtr <destptr.Type> destptr [16]) (MOVOstorezero destptr mem))))
+       // result: (MOVOstoreconst [makeValAndOff(0,48)] destptr (MOVOstoreconst [makeValAndOff(0,32)] destptr (MOVOstoreconst [makeValAndOff(0,16)] destptr (MOVOstoreconst [makeValAndOff(0,0)] destptr mem))))
        for {
                if auxIntToInt64(v.AuxInt) != 64 {
                        break
@@ -33572,23 +33712,18 @@ func rewriteValueAMD64_OpZero(v *Value) bool {
                if !(config.useSSE) {
                        break
                }
-               v.reset(OpAMD64MOVOstorezero)
-               v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
-               v0.AuxInt = int64ToAuxInt(48)
-               v0.AddArg(destptr)
-               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
-               v2 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
-               v2.AuxInt = int64ToAuxInt(32)
-               v2.AddArg(destptr)
-               v3 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
-               v4 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type)
-               v4.AuxInt = int64ToAuxInt(16)
-               v4.AddArg(destptr)
-               v5 := b.NewValue0(v.Pos, OpAMD64MOVOstorezero, types.TypeMem)
-               v5.AddArg2(destptr, mem)
-               v3.AddArg2(v4, v5)
-               v1.AddArg2(v2, v3)
-               v.AddArg2(v0, v1)
+               v.reset(OpAMD64MOVOstoreconst)
+               v.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 48))
+               v0 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v0.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 32))
+               v1 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 16))
+               v2 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem)
+               v2.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0))
+               v2.AddArg2(destptr, mem)
+               v1.AddArg2(destptr, v2)
+               v0.AddArg2(destptr, v1)
+               v.AddArg2(destptr, v0)
                return true
        }
        // match: (Zero [s] destptr mem)
index febb5566e338492cb6f42e30d013b454b579fa4a..496f9b4ae2ef117031e08f43f97c575c371721d1 100644 (file)
@@ -338,6 +338,8 @@ func rewriteValueARM(v *Value) bool {
                return rewriteValueARM_OpARMSRL(v)
        case OpARMSRLconst:
                return rewriteValueARM_OpARMSRLconst(v)
+       case OpARMSRR:
+               return rewriteValueARM_OpARMSRR(v)
        case OpARMSUB:
                return rewriteValueARM_OpARMSUB(v)
        case OpARMSUBD:
@@ -855,6 +857,9 @@ func rewriteValueARM(v *Value) bool {
        case OpSubPtr:
                v.Op = OpARMSUB
                return true
+       case OpTailCall:
+               v.Op = OpARMCALLtail
+               return true
        case OpTrunc16to8:
                v.Op = OpCopy
                return true
@@ -1119,6 +1124,7 @@ func rewriteValueARM_OpARMADCshiftLLreg(v *Value) bool {
                return true
        }
        // match: (ADCshiftLLreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (ADCshiftLL x y [c] flags)
        for {
                x := v_0
@@ -1128,6 +1134,9 @@ func rewriteValueARM_OpARMADCshiftLLreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADCshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -1199,6 +1208,7 @@ func rewriteValueARM_OpARMADCshiftRAreg(v *Value) bool {
                return true
        }
        // match: (ADCshiftRAreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (ADCshiftRA x y [c] flags)
        for {
                x := v_0
@@ -1208,6 +1218,9 @@ func rewriteValueARM_OpARMADCshiftRAreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADCshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -1279,6 +1292,7 @@ func rewriteValueARM_OpARMADCshiftRLreg(v *Value) bool {
                return true
        }
        // match: (ADCshiftRLreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (ADCshiftRL x y [c] flags)
        for {
                x := v_0
@@ -1288,6 +1302,9 @@ func rewriteValueARM_OpARMADCshiftRLreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADCshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -1740,6 +1757,7 @@ func rewriteValueARM_OpARMADDSshiftLLreg(v *Value) bool {
                return true
        }
        // match: (ADDSshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ADDSshiftLL x y [c])
        for {
                x := v_0
@@ -1748,6 +1766,9 @@ func rewriteValueARM_OpARMADDSshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADDSshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -1814,6 +1835,7 @@ func rewriteValueARM_OpARMADDSshiftRAreg(v *Value) bool {
                return true
        }
        // match: (ADDSshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ADDSshiftRA x y [c])
        for {
                x := v_0
@@ -1822,6 +1844,9 @@ func rewriteValueARM_OpARMADDSshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADDSshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -1888,6 +1913,7 @@ func rewriteValueARM_OpARMADDSshiftRLreg(v *Value) bool {
                return true
        }
        // match: (ADDSshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ADDSshiftRL x y [c])
        for {
                x := v_0
@@ -1896,6 +1922,9 @@ func rewriteValueARM_OpARMADDSshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADDSshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -2124,6 +2153,7 @@ func rewriteValueARM_OpARMADDshiftLLreg(v *Value) bool {
                return true
        }
        // match: (ADDshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ADDshiftLL x y [c])
        for {
                x := v_0
@@ -2132,6 +2162,9 @@ func rewriteValueARM_OpARMADDshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADDshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -2198,6 +2231,7 @@ func rewriteValueARM_OpARMADDshiftRAreg(v *Value) bool {
                return true
        }
        // match: (ADDshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ADDshiftRA x y [c])
        for {
                x := v_0
@@ -2206,6 +2240,9 @@ func rewriteValueARM_OpARMADDshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADDshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -2288,6 +2325,7 @@ func rewriteValueARM_OpARMADDshiftRLreg(v *Value) bool {
                return true
        }
        // match: (ADDshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ADDshiftRL x y [c])
        for {
                x := v_0
@@ -2296,6 +2334,9 @@ func rewriteValueARM_OpARMADDshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMADDshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -2614,18 +2655,16 @@ func rewriteValueARM_OpARMANDshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ANDshiftLL x y:(SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (ANDshiftLL y:(SLLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARMSLLconst {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if y.Op != OpARMSLLconst || auxIntToInt32(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -2655,6 +2694,7 @@ func rewriteValueARM_OpARMANDshiftLLreg(v *Value) bool {
                return true
        }
        // match: (ANDshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ANDshiftLL x y [c])
        for {
                x := v_0
@@ -2663,6 +2703,9 @@ func rewriteValueARM_OpARMANDshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMANDshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -2705,18 +2748,16 @@ func rewriteValueARM_OpARMANDshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ANDshiftRA x y:(SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (ANDshiftRA y:(SRAconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARMSRAconst {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if y.Op != OpARMSRAconst || auxIntToInt32(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -2746,6 +2787,7 @@ func rewriteValueARM_OpARMANDshiftRAreg(v *Value) bool {
                return true
        }
        // match: (ANDshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ANDshiftRA x y [c])
        for {
                x := v_0
@@ -2754,6 +2796,9 @@ func rewriteValueARM_OpARMANDshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMANDshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -2796,18 +2841,16 @@ func rewriteValueARM_OpARMANDshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ANDshiftRL x y:(SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (ANDshiftRL y:(SRLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARMSRLconst {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if y.Op != OpARMSRLconst || auxIntToInt32(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -2837,6 +2880,7 @@ func rewriteValueARM_OpARMANDshiftRLreg(v *Value) bool {
                return true
        }
        // match: (ANDshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ANDshiftRL x y [c])
        for {
                x := v_0
@@ -2845,6 +2889,9 @@ func rewriteValueARM_OpARMANDshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMANDshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -3091,17 +3138,15 @@ func rewriteValueARM_OpARMBICshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (BICshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (BICshiftLL (SLLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSLLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSLLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -3115,6 +3160,7 @@ func rewriteValueARM_OpARMBICshiftLLreg(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (BICshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (BICshiftLL x y [c])
        for {
                x := v_0
@@ -3123,6 +3169,9 @@ func rewriteValueARM_OpARMBICshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMBICshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -3147,17 +3196,15 @@ func rewriteValueARM_OpARMBICshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (BICshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (BICshiftRA (SRAconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRAconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRAconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -3171,6 +3218,7 @@ func rewriteValueARM_OpARMBICshiftRAreg(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (BICshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (BICshiftRA x y [c])
        for {
                x := v_0
@@ -3179,6 +3227,9 @@ func rewriteValueARM_OpARMBICshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMBICshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -3203,17 +3254,15 @@ func rewriteValueARM_OpARMBICshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (BICshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (BICshiftRL (SRLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -3227,6 +3276,7 @@ func rewriteValueARM_OpARMBICshiftRLreg(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (BICshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (BICshiftRL x y [c])
        for {
                x := v_0
@@ -3235,6 +3285,9 @@ func rewriteValueARM_OpARMBICshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMBICshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -3437,6 +3490,7 @@ func rewriteValueARM_OpARMCMNshiftLLreg(v *Value) bool {
                return true
        }
        // match: (CMNshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (CMNshiftLL x y [c])
        for {
                x := v_0
@@ -3445,6 +3499,9 @@ func rewriteValueARM_OpARMCMNshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMCMNshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -3511,6 +3568,7 @@ func rewriteValueARM_OpARMCMNshiftRAreg(v *Value) bool {
                return true
        }
        // match: (CMNshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (CMNshiftRA x y [c])
        for {
                x := v_0
@@ -3519,6 +3577,9 @@ func rewriteValueARM_OpARMCMNshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMCMNshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -3585,6 +3646,7 @@ func rewriteValueARM_OpARMCMNshiftRLreg(v *Value) bool {
                return true
        }
        // match: (CMNshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (CMNshiftRL x y [c])
        for {
                x := v_0
@@ -3593,6 +3655,9 @@ func rewriteValueARM_OpARMCMNshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMCMNshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -4090,6 +4155,7 @@ func rewriteValueARM_OpARMCMPshiftLLreg(v *Value) bool {
                return true
        }
        // match: (CMPshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (CMPshiftLL x y [c])
        for {
                x := v_0
@@ -4098,6 +4164,9 @@ func rewriteValueARM_OpARMCMPshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMCMPshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -4168,6 +4237,7 @@ func rewriteValueARM_OpARMCMPshiftRAreg(v *Value) bool {
                return true
        }
        // match: (CMPshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (CMPshiftRA x y [c])
        for {
                x := v_0
@@ -4176,6 +4246,9 @@ func rewriteValueARM_OpARMCMPshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMCMPshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -4246,6 +4319,7 @@ func rewriteValueARM_OpARMCMPshiftRLreg(v *Value) bool {
                return true
        }
        // match: (CMPshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (CMPshiftRL x y [c])
        for {
                x := v_0
@@ -4254,6 +4328,9 @@ func rewriteValueARM_OpARMCMPshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMCMPshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -8101,6 +8178,7 @@ func rewriteValueARM_OpARMMVNshiftLLreg(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (MVNshiftLLreg x (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (MVNshiftLL x [c])
        for {
                x := v_0
@@ -8108,6 +8186,9 @@ func rewriteValueARM_OpARMMVNshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_1.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMMVNshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg(x)
@@ -8135,6 +8216,7 @@ func rewriteValueARM_OpARMMVNshiftRAreg(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (MVNshiftRAreg x (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (MVNshiftRA x [c])
        for {
                x := v_0
@@ -8142,6 +8224,9 @@ func rewriteValueARM_OpARMMVNshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_1.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMMVNshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg(x)
@@ -8169,6 +8254,7 @@ func rewriteValueARM_OpARMMVNshiftRLreg(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (MVNshiftRLreg x (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (MVNshiftRL x [c])
        for {
                x := v_0
@@ -8176,6 +8262,9 @@ func rewriteValueARM_OpARMMVNshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_1.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMMVNshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg(x)
@@ -8556,18 +8645,16 @@ func rewriteValueARM_OpARMORshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORshiftLL x y:(SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (ORshiftLL y:(SLLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARMSLLconst {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if y.Op != OpARMSLLconst || auxIntToInt32(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -8597,6 +8684,7 @@ func rewriteValueARM_OpARMORshiftLLreg(v *Value) bool {
                return true
        }
        // match: (ORshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ORshiftLL x y [c])
        for {
                x := v_0
@@ -8605,6 +8693,9 @@ func rewriteValueARM_OpARMORshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMORshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -8647,18 +8738,16 @@ func rewriteValueARM_OpARMORshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORshiftRA x y:(SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (ORshiftRA y:(SRAconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARMSRAconst {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if y.Op != OpARMSRAconst || auxIntToInt32(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -8688,6 +8777,7 @@ func rewriteValueARM_OpARMORshiftRAreg(v *Value) bool {
                return true
        }
        // match: (ORshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ORshiftRA x y [c])
        for {
                x := v_0
@@ -8696,6 +8786,9 @@ func rewriteValueARM_OpARMORshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMORshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -8754,18 +8847,16 @@ func rewriteValueARM_OpARMORshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORshiftRL x y:(SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (ORshiftRL y:(SRLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARMSRLconst {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if y.Op != OpARMSRLconst || auxIntToInt32(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -8795,6 +8886,7 @@ func rewriteValueARM_OpARMORshiftRLreg(v *Value) bool {
                return true
        }
        // match: (ORshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (ORshiftRL x y [c])
        for {
                x := v_0
@@ -8803,6 +8895,9 @@ func rewriteValueARM_OpARMORshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMORshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9090,6 +9185,7 @@ func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value) bool {
                return true
        }
        // match: (RSBSshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (RSBSshiftLL x y [c])
        for {
                x := v_0
@@ -9098,6 +9194,9 @@ func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSBSshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9164,6 +9263,7 @@ func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value) bool {
                return true
        }
        // match: (RSBSshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (RSBSshiftRA x y [c])
        for {
                x := v_0
@@ -9172,6 +9272,9 @@ func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSBSshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9238,6 +9341,7 @@ func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value) bool {
                return true
        }
        // match: (RSBSshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (RSBSshiftRL x y [c])
        for {
                x := v_0
@@ -9246,6 +9350,9 @@ func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSBSshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9346,17 +9453,15 @@ func rewriteValueARM_OpARMRSBshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (RSBshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (RSBshiftLL (SLLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSLLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSLLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -9387,6 +9492,7 @@ func rewriteValueARM_OpARMRSBshiftLLreg(v *Value) bool {
                return true
        }
        // match: (RSBshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (RSBshiftLL x y [c])
        for {
                x := v_0
@@ -9395,6 +9501,9 @@ func rewriteValueARM_OpARMRSBshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSBshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9437,17 +9546,15 @@ func rewriteValueARM_OpARMRSBshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (RSBshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (RSBshiftRA (SRAconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRAconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRAconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -9478,6 +9585,7 @@ func rewriteValueARM_OpARMRSBshiftRAreg(v *Value) bool {
                return true
        }
        // match: (RSBshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (RSBshiftRA x y [c])
        for {
                x := v_0
@@ -9486,6 +9594,9 @@ func rewriteValueARM_OpARMRSBshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSBshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9528,17 +9639,15 @@ func rewriteValueARM_OpARMRSBshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (RSBshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (RSBshiftRL (SRLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -9569,6 +9678,7 @@ func rewriteValueARM_OpARMRSBshiftRLreg(v *Value) bool {
                return true
        }
        // match: (RSBshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (RSBshiftRL x y [c])
        for {
                x := v_0
@@ -9577,6 +9687,9 @@ func rewriteValueARM_OpARMRSBshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSBshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -9683,6 +9796,7 @@ func rewriteValueARM_OpARMRSCshiftLLreg(v *Value) bool {
                return true
        }
        // match: (RSCshiftLLreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (RSCshiftLL x y [c] flags)
        for {
                x := v_0
@@ -9692,6 +9806,9 @@ func rewriteValueARM_OpARMRSCshiftLLreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSCshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -9763,6 +9880,7 @@ func rewriteValueARM_OpARMRSCshiftRAreg(v *Value) bool {
                return true
        }
        // match: (RSCshiftRAreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (RSCshiftRA x y [c] flags)
        for {
                x := v_0
@@ -9772,6 +9890,9 @@ func rewriteValueARM_OpARMRSCshiftRAreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSCshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -9843,6 +9964,7 @@ func rewriteValueARM_OpARMRSCshiftRLreg(v *Value) bool {
                return true
        }
        // match: (RSCshiftRLreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (RSCshiftRL x y [c] flags)
        for {
                x := v_0
@@ -9852,6 +9974,9 @@ func rewriteValueARM_OpARMRSCshiftRLreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMRSCshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -10166,6 +10291,7 @@ func rewriteValueARM_OpARMSBCshiftLLreg(v *Value) bool {
                return true
        }
        // match: (SBCshiftLLreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (SBCshiftLL x y [c] flags)
        for {
                x := v_0
@@ -10175,6 +10301,9 @@ func rewriteValueARM_OpARMSBCshiftLLreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSBCshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -10246,6 +10375,7 @@ func rewriteValueARM_OpARMSBCshiftRAreg(v *Value) bool {
                return true
        }
        // match: (SBCshiftRAreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (SBCshiftRA x y [c] flags)
        for {
                x := v_0
@@ -10255,6 +10385,9 @@ func rewriteValueARM_OpARMSBCshiftRAreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSBCshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -10326,6 +10459,7 @@ func rewriteValueARM_OpARMSBCshiftRLreg(v *Value) bool {
                return true
        }
        // match: (SBCshiftRLreg x y (MOVWconst [c]) flags)
+       // cond: 0 <= c && c < 32
        // result: (SBCshiftRL x y [c] flags)
        for {
                x := v_0
@@ -10335,6 +10469,9 @@ func rewriteValueARM_OpARMSBCshiftRLreg(v *Value) bool {
                }
                c := auxIntToInt32(v_2.AuxInt)
                flags := v_3
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSBCshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg3(x, y, flags)
@@ -10346,15 +10483,19 @@ func rewriteValueARM_OpARMSLL(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (SLL x (MOVWconst [c]))
-       // result: (SLLconst x [c&31])
+       // cond: 0 <= c && c < 32
+       // result: (SLLconst x [c])
        for {
                x := v_0
                if v_1.Op != OpARMMOVWconst {
                        break
                }
                c := auxIntToInt32(v_1.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSLLconst)
-               v.AuxInt = int32ToAuxInt(c & 31)
+               v.AuxInt = int32ToAuxInt(c)
                v.AddArg(x)
                return true
        }
@@ -10380,15 +10521,19 @@ func rewriteValueARM_OpARMSRA(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (SRA x (MOVWconst [c]))
-       // result: (SRAconst x [c&31])
+       // cond: 0 <= c && c < 32
+       // result: (SRAconst x [c])
        for {
                x := v_0
                if v_1.Op != OpARMMOVWconst {
                        break
                }
                c := auxIntToInt32(v_1.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSRAconst)
-               v.AuxInt = int32ToAuxInt(c & 31)
+               v.AuxInt = int32ToAuxInt(c)
                v.AddArg(x)
                return true
        }
@@ -10472,15 +10617,19 @@ func rewriteValueARM_OpARMSRL(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        // match: (SRL x (MOVWconst [c]))
-       // result: (SRLconst x [c&31])
+       // cond: 0 <= c && c < 32
+       // result: (SRLconst x [c])
        for {
                x := v_0
                if v_1.Op != OpARMMOVWconst {
                        break
                }
                c := auxIntToInt32(v_1.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSRLconst)
-               v.AuxInt = int32ToAuxInt(c & 31)
+               v.AuxInt = int32ToAuxInt(c)
                v.AddArg(x)
                return true
        }
@@ -10520,6 +10669,24 @@ func rewriteValueARM_OpARMSRLconst(v *Value) bool {
        }
        return false
 }
+func rewriteValueARM_OpARMSRR(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (SRR x (MOVWconst [c]))
+       // result: (SRRconst x [c&31])
+       for {
+               x := v_0
+               if v_1.Op != OpARMMOVWconst {
+                       break
+               }
+               c := auxIntToInt32(v_1.AuxInt)
+               v.reset(OpARMSRRconst)
+               v.AuxInt = int32ToAuxInt(c & 31)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
 func rewriteValueARM_OpARMSUB(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -11058,6 +11225,7 @@ func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value) bool {
                return true
        }
        // match: (SUBSshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (SUBSshiftLL x y [c])
        for {
                x := v_0
@@ -11066,6 +11234,9 @@ func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSUBSshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11132,6 +11303,7 @@ func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value) bool {
                return true
        }
        // match: (SUBSshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (SUBSshiftRA x y [c])
        for {
                x := v_0
@@ -11140,6 +11312,9 @@ func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSUBSshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11206,6 +11381,7 @@ func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value) bool {
                return true
        }
        // match: (SUBSshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (SUBSshiftRL x y [c])
        for {
                x := v_0
@@ -11214,6 +11390,9 @@ func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSUBSshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11368,17 +11547,15 @@ func rewriteValueARM_OpARMSUBshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SUBshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (SUBshiftLL (SLLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSLLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSLLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -11409,6 +11586,7 @@ func rewriteValueARM_OpARMSUBshiftLLreg(v *Value) bool {
                return true
        }
        // match: (SUBshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (SUBshiftLL x y [c])
        for {
                x := v_0
@@ -11417,6 +11595,9 @@ func rewriteValueARM_OpARMSUBshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSUBshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11459,17 +11640,15 @@ func rewriteValueARM_OpARMSUBshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SUBshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (SUBshiftRA (SRAconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRAconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRAconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -11500,6 +11679,7 @@ func rewriteValueARM_OpARMSUBshiftRAreg(v *Value) bool {
                return true
        }
        // match: (SUBshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (SUBshiftRA x y [c])
        for {
                x := v_0
@@ -11508,6 +11688,9 @@ func rewriteValueARM_OpARMSUBshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSUBshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11550,17 +11733,15 @@ func rewriteValueARM_OpARMSUBshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SUBshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (SUBshiftRL (SRLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -11591,6 +11772,7 @@ func rewriteValueARM_OpARMSUBshiftRLreg(v *Value) bool {
                return true
        }
        // match: (SUBshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (SUBshiftRL x y [c])
        for {
                x := v_0
@@ -11599,6 +11781,9 @@ func rewriteValueARM_OpARMSUBshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMSUBshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11801,6 +11986,7 @@ func rewriteValueARM_OpARMTEQshiftLLreg(v *Value) bool {
                return true
        }
        // match: (TEQshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (TEQshiftLL x y [c])
        for {
                x := v_0
@@ -11809,6 +11995,9 @@ func rewriteValueARM_OpARMTEQshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMTEQshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11875,6 +12064,7 @@ func rewriteValueARM_OpARMTEQshiftRAreg(v *Value) bool {
                return true
        }
        // match: (TEQshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (TEQshiftRA x y [c])
        for {
                x := v_0
@@ -11883,6 +12073,9 @@ func rewriteValueARM_OpARMTEQshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMTEQshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -11949,6 +12142,7 @@ func rewriteValueARM_OpARMTEQshiftRLreg(v *Value) bool {
                return true
        }
        // match: (TEQshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (TEQshiftRL x y [c])
        for {
                x := v_0
@@ -11957,6 +12151,9 @@ func rewriteValueARM_OpARMTEQshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMTEQshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -12159,6 +12356,7 @@ func rewriteValueARM_OpARMTSTshiftLLreg(v *Value) bool {
                return true
        }
        // match: (TSTshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (TSTshiftLL x y [c])
        for {
                x := v_0
@@ -12167,6 +12365,9 @@ func rewriteValueARM_OpARMTSTshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMTSTshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -12233,6 +12434,7 @@ func rewriteValueARM_OpARMTSTshiftRAreg(v *Value) bool {
                return true
        }
        // match: (TSTshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (TSTshiftRA x y [c])
        for {
                x := v_0
@@ -12241,6 +12443,9 @@ func rewriteValueARM_OpARMTSTshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMTSTshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -12307,6 +12512,7 @@ func rewriteValueARM_OpARMTSTshiftRLreg(v *Value) bool {
                return true
        }
        // match: (TSTshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (TSTshiftRL x y [c])
        for {
                x := v_0
@@ -12315,6 +12521,9 @@ func rewriteValueARM_OpARMTSTshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMTSTshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -12595,17 +12804,15 @@ func rewriteValueARM_OpARMXORshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (XORshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (XORshiftLL (SLLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSLLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSLLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -12636,6 +12843,7 @@ func rewriteValueARM_OpARMXORshiftLLreg(v *Value) bool {
                return true
        }
        // match: (XORshiftLLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (XORshiftLL x y [c])
        for {
                x := v_0
@@ -12644,6 +12852,9 @@ func rewriteValueARM_OpARMXORshiftLLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMXORshiftLL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -12686,17 +12897,15 @@ func rewriteValueARM_OpARMXORshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (XORshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (XORshiftRA (SRAconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRAconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRAconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -12727,6 +12936,7 @@ func rewriteValueARM_OpARMXORshiftRAreg(v *Value) bool {
                return true
        }
        // match: (XORshiftRAreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (XORshiftRA x y [c])
        for {
                x := v_0
@@ -12735,6 +12945,9 @@ func rewriteValueARM_OpARMXORshiftRAreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMXORshiftRA)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -12793,17 +13006,15 @@ func rewriteValueARM_OpARMXORshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (XORshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (XORshiftRL (SRLconst x [c]) x [c])
        // result: (MOVWconst [0])
        for {
-               d := auxIntToInt32(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARMSRLconst {
+               c := auxIntToInt32(v.AuxInt)
+               if v_0.Op != OpARMSRLconst || auxIntToInt32(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt32(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARMMOVWconst)
@@ -12834,6 +13045,7 @@ func rewriteValueARM_OpARMXORshiftRLreg(v *Value) bool {
                return true
        }
        // match: (XORshiftRLreg x y (MOVWconst [c]))
+       // cond: 0 <= c && c < 32
        // result: (XORshiftRL x y [c])
        for {
                x := v_0
@@ -12842,6 +13054,9 @@ func rewriteValueARM_OpARMXORshiftRLreg(v *Value) bool {
                        break
                }
                c := auxIntToInt32(v_2.AuxInt)
+               if !(0 <= c && c < 32) {
+                       break
+               }
                v.reset(OpARMXORshiftRL)
                v.AuxInt = int32ToAuxInt(c)
                v.AddArg2(x, y)
@@ -14901,19 +15116,6 @@ func rewriteValueARM_OpRotateLeft32(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
        b := v.Block
-       // match: (RotateLeft32 x (MOVWconst [c]))
-       // result: (SRRconst [-c&31] x)
-       for {
-               x := v_0
-               if v_1.Op != OpARMMOVWconst {
-                       break
-               }
-               c := auxIntToInt32(v_1.AuxInt)
-               v.reset(OpARMSRRconst)
-               v.AuxInt = int32ToAuxInt(-c & 31)
-               v.AddArg(x)
-               return true
-       }
        // match: (RotateLeft32 x y)
        // result: (SRR x (RSBconst [0] <y.Type> y))
        for {
index f7840c5503975476d26d3d9531762cd5d41123a9..ad34855c30f6be4e70f6c4af52e5104c1f54abf8 100644 (file)
@@ -29,6 +29,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64ANDshiftRA(v)
        case OpARM64ANDshiftRL:
                return rewriteValueARM64_OpARM64ANDshiftRL(v)
+       case OpARM64ANDshiftRO:
+               return rewriteValueARM64_OpARM64ANDshiftRO(v)
        case OpARM64BIC:
                return rewriteValueARM64_OpARM64BIC(v)
        case OpARM64BICshiftLL:
@@ -37,6 +39,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64BICshiftRA(v)
        case OpARM64BICshiftRL:
                return rewriteValueARM64_OpARM64BICshiftRL(v)
+       case OpARM64BICshiftRO:
+               return rewriteValueARM64_OpARM64BICshiftRO(v)
        case OpARM64CMN:
                return rewriteValueARM64_OpARM64CMN(v)
        case OpARM64CMNW:
@@ -89,6 +93,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64EONshiftRA(v)
        case OpARM64EONshiftRL:
                return rewriteValueARM64_OpARM64EONshiftRL(v)
+       case OpARM64EONshiftRO:
+               return rewriteValueARM64_OpARM64EONshiftRO(v)
        case OpARM64Equal:
                return rewriteValueARM64_OpARM64Equal(v)
        case OpARM64FADDD:
@@ -295,6 +301,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64MVNshiftRA(v)
        case OpARM64MVNshiftRL:
                return rewriteValueARM64_OpARM64MVNshiftRL(v)
+       case OpARM64MVNshiftRO:
+               return rewriteValueARM64_OpARM64MVNshiftRO(v)
        case OpARM64NEG:
                return rewriteValueARM64_OpARM64NEG(v)
        case OpARM64NEGshiftLL:
@@ -315,6 +323,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64ORNshiftRA(v)
        case OpARM64ORNshiftRL:
                return rewriteValueARM64_OpARM64ORNshiftRL(v)
+       case OpARM64ORNshiftRO:
+               return rewriteValueARM64_OpARM64ORNshiftRO(v)
        case OpARM64ORconst:
                return rewriteValueARM64_OpARM64ORconst(v)
        case OpARM64ORshiftLL:
@@ -323,6 +333,16 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64ORshiftRA(v)
        case OpARM64ORshiftRL:
                return rewriteValueARM64_OpARM64ORshiftRL(v)
+       case OpARM64ORshiftRO:
+               return rewriteValueARM64_OpARM64ORshiftRO(v)
+       case OpARM64REV:
+               return rewriteValueARM64_OpARM64REV(v)
+       case OpARM64REVW:
+               return rewriteValueARM64_OpARM64REVW(v)
+       case OpARM64ROR:
+               return rewriteValueARM64_OpARM64ROR(v)
+       case OpARM64RORW:
+               return rewriteValueARM64_OpARM64RORW(v)
        case OpARM64RORWconst:
                return rewriteValueARM64_OpARM64RORWconst(v)
        case OpARM64RORconst:
@@ -367,6 +387,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64TSTshiftRA(v)
        case OpARM64TSTshiftRL:
                return rewriteValueARM64_OpARM64TSTshiftRL(v)
+       case OpARM64TSTshiftRO:
+               return rewriteValueARM64_OpARM64TSTshiftRO(v)
        case OpARM64UBFIZ:
                return rewriteValueARM64_OpARM64UBFIZ(v)
        case OpARM64UBFX:
@@ -389,6 +411,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64XORshiftRA(v)
        case OpARM64XORshiftRL:
                return rewriteValueARM64_OpARM64XORshiftRL(v)
+       case OpARM64XORshiftRO:
+               return rewriteValueARM64_OpARM64XORshiftRO(v)
        case OpAbs:
                v.Op = OpARM64FABSD
                return true
@@ -896,6 +920,12 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpPopCount32(v)
        case OpPopCount64:
                return rewriteValueARM64_OpPopCount64(v)
+       case OpPrefetchCache:
+               return rewriteValueARM64_OpPrefetchCache(v)
+       case OpPrefetchCacheStreamed:
+               return rewriteValueARM64_OpPrefetchCacheStreamed(v)
+       case OpPubBarrier:
+               return rewriteValueARM64_OpPubBarrier(v)
        case OpRotateLeft16:
                return rewriteValueARM64_OpRotateLeft16(v)
        case OpRotateLeft32:
@@ -1038,6 +1068,9 @@ func rewriteValueARM64(v *Value) bool {
        case OpSubPtr:
                v.Op = OpARM64SUB
                return true
+       case OpTailCall:
+               v.Op = OpARM64CALLtail
+               return true
        case OpTrunc:
                v.Op = OpARM64FRINTZD
                return true
@@ -2103,6 +2136,28 @@ func rewriteValueARM64_OpARM64AND(v *Value) bool {
                }
                break
        }
+       // match: (AND x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (ANDshiftRO x0 y [c])
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x0 := v_0
+                       x1 := v_1
+                       if x1.Op != OpARM64RORconst {
+                               continue
+                       }
+                       c := auxIntToInt64(x1.AuxInt)
+                       y := x1.Args[0]
+                       if !(clobberIfDead(x1)) {
+                               continue
+                       }
+                       v.reset(OpARM64ANDshiftRO)
+                       v.AuxInt = int64ToAuxInt(c)
+                       v.AddArg2(x0, y)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueARM64_OpARM64ANDconst(v *Value) bool {
@@ -2265,18 +2320,16 @@ func rewriteValueARM64_OpARM64ANDshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ANDshiftLL x y:(SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (ANDshiftLL y:(SLLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64SLLconst || auxIntToInt64(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -2319,18 +2372,16 @@ func rewriteValueARM64_OpARM64ANDshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ANDshiftRA x y:(SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (ANDshiftRA y:(SRAconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64SRAconst || auxIntToInt64(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -2373,18 +2424,68 @@ func rewriteValueARM64_OpARM64ANDshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ANDshiftRL x y:(SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (ANDshiftRL y:(SRLconst x [c]) x [c])
        // result: y
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64SRLconst || auxIntToInt64(y.AuxInt) != c {
+                       break
+               }
+               x := y.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.copyOf(y)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64ANDshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       b := v.Block
+       // match: (ANDshiftRO (MOVDconst [c]) x [d])
+       // result: (ANDconst [c] (RORconst <x.Type> x [d]))
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_1
+               v.reset(OpARM64ANDconst)
+               v.AuxInt = int64ToAuxInt(c)
+               v0 := b.NewValue0(v.Pos, OpARM64RORconst, x.Type)
+               v0.AuxInt = int64ToAuxInt(d)
+               v0.AddArg(x)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (ANDshiftRO x (MOVDconst [c]) [d])
+       // result: (ANDconst x [rotateRight64(c, d)])
        for {
                d := auxIntToInt64(v.AuxInt)
                x := v_0
-               y := v_1
-               if y.Op != OpARM64SRLconst {
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               v.reset(OpARM64ANDconst)
+               v.AuxInt = int64ToAuxInt(rotateRight64(c, d))
+               v.AddArg(x)
+               return true
+       }
+       // match: (ANDshiftRO y:(RORconst x [c]) x [c])
+       // result: y
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64RORconst || auxIntToInt64(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -2476,6 +2577,25 @@ func rewriteValueARM64_OpARM64BIC(v *Value) bool {
                v.AddArg2(x0, y)
                return true
        }
+       // match: (BIC x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (BICshiftRO x0 y [c])
+       for {
+               x0 := v_0
+               x1 := v_1
+               if x1.Op != OpARM64RORconst {
+                       break
+               }
+               c := auxIntToInt64(x1.AuxInt)
+               y := x1.Args[0]
+               if !(clobberIfDead(x1)) {
+                       break
+               }
+               v.reset(OpARM64BICshiftRO)
+               v.AuxInt = int64ToAuxInt(c)
+               v.AddArg2(x0, y)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64BICshiftLL(v *Value) bool {
@@ -2495,17 +2615,15 @@ func rewriteValueARM64_OpARM64BICshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (BICshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (BICshiftLL (SLLconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -2531,17 +2649,15 @@ func rewriteValueARM64_OpARM64BICshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (BICshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (BICshiftRA (SRAconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -2567,17 +2683,49 @@ func rewriteValueARM64_OpARM64BICshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (BICshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (BICshiftRL (SRLconst x [c]) x [c])
        // result: (MOVDconst [0])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpARM64MOVDconst)
+               v.AuxInt = int64ToAuxInt(0)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64BICshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (BICshiftRO x (MOVDconst [c]) [d])
+       // result: (ANDconst x [^rotateRight64(c, d)])
        for {
                d := auxIntToInt64(v.AuxInt)
                x := v_0
-               if v_1.Op != OpARM64SRLconst {
+               if v_1.Op != OpARM64MOVDconst {
                        break
                }
                c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               v.reset(OpARM64ANDconst)
+               v.AuxInt = int64ToAuxInt(^rotateRight64(c, d))
+               v.AddArg(x)
+               return true
+       }
+       // match: (BICshiftRO (RORconst x [c]) x [c])
+       // result: (MOVDconst [0])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64RORconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -3926,6 +4074,25 @@ func rewriteValueARM64_OpARM64EON(v *Value) bool {
                v.AddArg2(x0, y)
                return true
        }
+       // match: (EON x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (EONshiftRO x0 y [c])
+       for {
+               x0 := v_0
+               x1 := v_1
+               if x1.Op != OpARM64RORconst {
+                       break
+               }
+               c := auxIntToInt64(x1.AuxInt)
+               y := x1.Args[0]
+               if !(clobberIfDead(x1)) {
+                       break
+               }
+               v.reset(OpARM64EONshiftRO)
+               v.AuxInt = int64ToAuxInt(c)
+               v.AddArg2(x0, y)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64EONshiftLL(v *Value) bool {
@@ -3945,17 +4112,15 @@ func rewriteValueARM64_OpARM64EONshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (EONshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (EONshiftLL (SLLconst x [c]) x [c])
        // result: (MOVDconst [-1])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -3981,17 +4146,15 @@ func rewriteValueARM64_OpARM64EONshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (EONshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (EONshiftRA (SRAconst x [c]) x [c])
        // result: (MOVDconst [-1])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -4017,17 +4180,49 @@ func rewriteValueARM64_OpARM64EONshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (EONshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (EONshiftRL (SRLconst x [c]) x [c])
        // result: (MOVDconst [-1])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpARM64MOVDconst)
+               v.AuxInt = int64ToAuxInt(-1)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64EONshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (EONshiftRO x (MOVDconst [c]) [d])
+       // result: (XORconst x [^rotateRight64(c, d)])
        for {
                d := auxIntToInt64(v.AuxInt)
                x := v_0
-               if v_1.Op != OpARM64SRLconst {
+               if v_1.Op != OpARM64MOVDconst {
                        break
                }
                c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               v.reset(OpARM64XORconst)
+               v.AuxInt = int64ToAuxInt(^rotateRight64(c, d))
+               v.AddArg(x)
+               return true
+       }
+       // match: (EONshiftRO (RORconst x [c]) x [c])
+       // result: (MOVDconst [-1])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64RORconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -7153,37 +7348,54 @@ func rewriteValueARM64_OpARM64MOVBUreg(v *Value) bool {
                v.AuxInt = int64ToAuxInt(0)
                return true
        }
-       // match: (MOVBUreg (SLLconst [sc] x))
-       // cond: isARM64BFMask(sc, 1<<8-1, sc)
-       // result: (UBFIZ [armBFAuxInt(sc, arm64BFWidth(1<<8-1, sc))] x)
+       // match: (MOVBUreg (SLLconst [lc] x))
+       // cond: lc < 8
+       // result: (UBFIZ [armBFAuxInt(lc, 8-lc)] x)
        for {
                if v_0.Op != OpARM64SLLconst {
                        break
                }
-               sc := auxIntToInt64(v_0.AuxInt)
+               lc := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<8-1, sc)) {
+               if !(lc < 8) {
                        break
                }
                v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(1<<8-1, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, 8-lc))
                v.AddArg(x)
                return true
        }
-       // match: (MOVBUreg (SRLconst [sc] x))
-       // cond: isARM64BFMask(sc, 1<<8-1, 0)
-       // result: (UBFX [armBFAuxInt(sc, 8)] x)
+       // match: (MOVBUreg (SRLconst [rc] x))
+       // cond: rc < 8
+       // result: (UBFX [armBFAuxInt(rc, 8)] x)
        for {
                if v_0.Op != OpARM64SRLconst {
                        break
                }
-               sc := auxIntToInt64(v_0.AuxInt)
+               rc := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(rc < 8) {
+                       break
+               }
+               v.reset(OpARM64UBFX)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc, 8))
+               v.AddArg(x)
+               return true
+       }
+       // match: (MOVBUreg (UBFX [bfc] x))
+       // cond: bfc.getARM64BFwidth() <= 8
+       // result: (UBFX [bfc] x)
+       for {
+               if v_0.Op != OpARM64UBFX {
+                       break
+               }
+               bfc := auxIntToArm64BitField(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<8-1, 0)) {
+               if !(bfc.getARM64BFwidth() <= 8) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, 8))
+               v.AuxInt = arm64BitFieldToAuxInt(bfc)
                v.AddArg(x)
                return true
        }
@@ -7401,6 +7613,23 @@ func rewriteValueARM64_OpARM64MOVBreg(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (MOVBreg (SBFX [bfc] x))
+       // cond: bfc.getARM64BFwidth() <= 8
+       // result: (SBFX [bfc] x)
+       for {
+               if v_0.Op != OpARM64SBFX {
+                       break
+               }
+               bfc := auxIntToArm64BitField(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(bfc.getARM64BFwidth() <= 8) {
+                       break
+               }
+               v.reset(OpARM64SBFX)
+               v.AuxInt = arm64BitFieldToAuxInt(bfc)
+               v.AddArg(x)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64MOVBstore(v *Value) bool {
@@ -10665,37 +10894,54 @@ func rewriteValueARM64_OpARM64MOVHUreg(v *Value) bool {
                v.AuxInt = int64ToAuxInt(0)
                return true
        }
-       // match: (MOVHUreg (SLLconst [sc] x))
-       // cond: isARM64BFMask(sc, 1<<16-1, sc)
-       // result: (UBFIZ [armBFAuxInt(sc, arm64BFWidth(1<<16-1, sc))] x)
+       // match: (MOVHUreg (SLLconst [lc] x))
+       // cond: lc < 16
+       // result: (UBFIZ [armBFAuxInt(lc, 16-lc)] x)
        for {
                if v_0.Op != OpARM64SLLconst {
                        break
                }
-               sc := auxIntToInt64(v_0.AuxInt)
+               lc := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<16-1, sc)) {
+               if !(lc < 16) {
                        break
                }
                v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(1<<16-1, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, 16-lc))
                v.AddArg(x)
                return true
        }
-       // match: (MOVHUreg (SRLconst [sc] x))
-       // cond: isARM64BFMask(sc, 1<<16-1, 0)
-       // result: (UBFX [armBFAuxInt(sc, 16)] x)
+       // match: (MOVHUreg (SRLconst [rc] x))
+       // cond: rc < 16
+       // result: (UBFX [armBFAuxInt(rc, 16)] x)
        for {
                if v_0.Op != OpARM64SRLconst {
                        break
                }
-               sc := auxIntToInt64(v_0.AuxInt)
+               rc := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(rc < 16) {
+                       break
+               }
+               v.reset(OpARM64UBFX)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc, 16))
+               v.AddArg(x)
+               return true
+       }
+       // match: (MOVHUreg (UBFX [bfc] x))
+       // cond: bfc.getARM64BFwidth() <= 16
+       // result: (UBFX [bfc] x)
+       for {
+               if v_0.Op != OpARM64UBFX {
+                       break
+               }
+               bfc := auxIntToArm64BitField(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<16-1, 0)) {
+               if !(bfc.getARM64BFwidth() <= 16) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, 16))
+               v.AuxInt = arm64BitFieldToAuxInt(bfc)
                v.AddArg(x)
                return true
        }
@@ -11096,17 +11342,34 @@ func rewriteValueARM64_OpARM64MOVHreg(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       return false
-}
-func rewriteValueARM64_OpARM64MOVHstore(v *Value) bool {
-       v_2 := v.Args[2]
-       v_1 := v.Args[1]
-       v_0 := v.Args[0]
-       b := v.Block
-       config := b.Func.Config
-       // match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
-       // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
-       // result: (MOVHstore [off1+int32(off2)] {sym} ptr val mem)
+       // match: (MOVHreg (SBFX [bfc] x))
+       // cond: bfc.getARM64BFwidth() <= 16
+       // result: (SBFX [bfc] x)
+       for {
+               if v_0.Op != OpARM64SBFX {
+                       break
+               }
+               bfc := auxIntToArm64BitField(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(bfc.getARM64BFwidth() <= 16) {
+                       break
+               }
+               v.reset(OpARM64SBFX)
+               v.AuxInt = arm64BitFieldToAuxInt(bfc)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64MOVHstore(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       b := v.Block
+       config := b.Func.Config
+       // match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+       // cond: is32Bit(int64(off1)+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
+       // result: (MOVHstore [off1+int32(off2)] {sym} ptr val mem)
        for {
                off1 := auxIntToInt32(v.AuxInt)
                sym := auxToSym(v.Aux)
@@ -12777,37 +13040,54 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value) bool {
                v.AuxInt = int64ToAuxInt(0)
                return true
        }
-       // match: (MOVWUreg (SLLconst [sc] x))
-       // cond: isARM64BFMask(sc, 1<<32-1, sc)
-       // result: (UBFIZ [armBFAuxInt(sc, arm64BFWidth(1<<32-1, sc))] x)
+       // match: (MOVWUreg (SLLconst [lc] x))
+       // cond: lc < 32
+       // result: (UBFIZ [armBFAuxInt(lc, 32-lc)] x)
        for {
                if v_0.Op != OpARM64SLLconst {
                        break
                }
-               sc := auxIntToInt64(v_0.AuxInt)
+               lc := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<32-1, sc)) {
+               if !(lc < 32) {
                        break
                }
                v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(1<<32-1, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, 32-lc))
                v.AddArg(x)
                return true
        }
-       // match: (MOVWUreg (SRLconst [sc] x))
-       // cond: isARM64BFMask(sc, 1<<32-1, 0)
-       // result: (UBFX [armBFAuxInt(sc, 32)] x)
+       // match: (MOVWUreg (SRLconst [rc] x))
+       // cond: rc < 32
+       // result: (UBFX [armBFAuxInt(rc, 32)] x)
        for {
                if v_0.Op != OpARM64SRLconst {
                        break
                }
-               sc := auxIntToInt64(v_0.AuxInt)
+               rc := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(rc < 32) {
+                       break
+               }
+               v.reset(OpARM64UBFX)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc, 32))
+               v.AddArg(x)
+               return true
+       }
+       // match: (MOVWUreg (UBFX [bfc] x))
+       // cond: bfc.getARM64BFwidth() <= 32
+       // result: (UBFX [bfc] x)
+       for {
+               if v_0.Op != OpARM64UBFX {
+                       break
+               }
+               bfc := auxIntToArm64BitField(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<32-1, 0)) {
+               if !(bfc.getARM64BFwidth() <= 32) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, 32))
+               v.AuxInt = arm64BitFieldToAuxInt(bfc)
                v.AddArg(x)
                return true
        }
@@ -13266,6 +13546,23 @@ func rewriteValueARM64_OpARM64MOVWreg(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (MOVWreg (SBFX [bfc] x))
+       // cond: bfc.getARM64BFwidth() <= 32
+       // result: (SBFX [bfc] x)
+       for {
+               if v_0.Op != OpARM64SBFX {
+                       break
+               }
+               bfc := auxIntToArm64BitField(v_0.AuxInt)
+               x := v_0.Args[0]
+               if !(bfc.getARM64BFwidth() <= 32) {
+                       break
+               }
+               v.reset(OpARM64SBFX)
+               v.AuxInt = arm64BitFieldToAuxInt(bfc)
+               v.AddArg(x)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64MOVWstore(v *Value) bool {
@@ -15502,6 +15799,24 @@ func rewriteValueARM64_OpARM64MVN(v *Value) bool {
                v.AddArg(y)
                return true
        }
+       // match: (MVN x:(RORconst [c] y))
+       // cond: clobberIfDead(x)
+       // result: (MVNshiftRO [c] y)
+       for {
+               x := v_0
+               if x.Op != OpARM64RORconst {
+                       break
+               }
+               c := auxIntToInt64(x.AuxInt)
+               y := x.Args[0]
+               if !(clobberIfDead(x)) {
+                       break
+               }
+               v.reset(OpARM64MVNshiftRO)
+               v.AuxInt = int64ToAuxInt(c)
+               v.AddArg(y)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64MVNshiftLL(v *Value) bool {
@@ -15552,6 +15867,22 @@ func rewriteValueARM64_OpARM64MVNshiftRL(v *Value) bool {
        }
        return false
 }
+func rewriteValueARM64_OpARM64MVNshiftRO(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (MVNshiftRO (MOVDconst [c]) [d])
+       // result: (MOVDconst [^rotateRight64(c, d)])
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpARM64MOVDconst)
+               v.AuxInt = int64ToAuxInt(^rotateRight64(c, d))
+               return true
+       }
+       return false
+}
 func rewriteValueARM64_OpARM64NEG(v *Value) bool {
        v_0 := v.Args[0]
        // match: (NEG (MUL x y))
@@ -15578,6 +15909,16 @@ func rewriteValueARM64_OpARM64NEG(v *Value) bool {
                v.AddArg2(x, y)
                return true
        }
+       // match: (NEG (NEG x))
+       // result: x
+       for {
+               if v_0.Op != OpARM64NEG {
+                       break
+               }
+               x := v_0.Args[0]
+               v.copyOf(x)
+               return true
+       }
        // match: (NEG (MOVDconst [c]))
        // result: (MOVDconst [-c])
        for {
@@ -15831,6 +16172,28 @@ func rewriteValueARM64_OpARM64OR(v *Value) bool {
                }
                break
        }
+       // match: (OR x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (ORshiftRO x0 y [c])
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x0 := v_0
+                       x1 := v_1
+                       if x1.Op != OpARM64RORconst {
+                               continue
+                       }
+                       c := auxIntToInt64(x1.AuxInt)
+                       y := x1.Args[0]
+                       if !(clobberIfDead(x1)) {
+                               continue
+                       }
+                       v.reset(OpARM64ORshiftRO)
+                       v.AuxInt = int64ToAuxInt(c)
+                       v.AddArg2(x0, y)
+                       return true
+               }
+               break
+       }
        // match: (OR (SLL x (ANDconst <t> [63] y)) (CSEL0 <typ.UInt64> [cc] (SRL <typ.UInt64> x (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y))) (CMPconst [64] (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y)))))
        // cond: cc == OpARM64LessThanU
        // result: (ROR x (NEG <t> y))
@@ -17800,6 +18163,25 @@ func rewriteValueARM64_OpARM64ORN(v *Value) bool {
                v.AddArg2(x0, y)
                return true
        }
+       // match: (ORN x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (ORNshiftRO x0 y [c])
+       for {
+               x0 := v_0
+               x1 := v_1
+               if x1.Op != OpARM64RORconst {
+                       break
+               }
+               c := auxIntToInt64(x1.AuxInt)
+               y := x1.Args[0]
+               if !(clobberIfDead(x1)) {
+                       break
+               }
+               v.reset(OpARM64ORNshiftRO)
+               v.AuxInt = int64ToAuxInt(c)
+               v.AddArg2(x0, y)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64ORNshiftLL(v *Value) bool {
@@ -17819,17 +18201,15 @@ func rewriteValueARM64_OpARM64ORNshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORNshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (ORNshiftLL (SLLconst x [c]) x [c])
        // result: (MOVDconst [-1])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -17855,17 +18235,15 @@ func rewriteValueARM64_OpARM64ORNshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORNshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (ORNshiftRA (SRAconst x [c]) x [c])
        // result: (MOVDconst [-1])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -17891,17 +18269,49 @@ func rewriteValueARM64_OpARM64ORNshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORNshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (ORNshiftRL (SRLconst x [c]) x [c])
        // result: (MOVDconst [-1])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpARM64MOVDconst)
+               v.AuxInt = int64ToAuxInt(-1)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64ORNshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (ORNshiftRO x (MOVDconst [c]) [d])
+       // result: (ORconst x [^rotateRight64(c, d)])
        for {
                d := auxIntToInt64(v.AuxInt)
                x := v_0
-               if v_1.Op != OpARM64SRLconst {
+               if v_1.Op != OpARM64MOVDconst {
                        break
                }
                c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               v.reset(OpARM64ORconst)
+               v.AuxInt = int64ToAuxInt(^rotateRight64(c, d))
+               v.AddArg(x)
+               return true
+       }
+       // match: (ORNshiftRO (RORconst x [c]) x [c])
+       // result: (MOVDconst [-1])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64RORconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -18014,18 +18424,16 @@ func rewriteValueARM64_OpARM64ORshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORshiftLL x y:(SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (ORshiftLL y:(SLLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64SLLconst || auxIntToInt64(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -19694,18 +20102,16 @@ func rewriteValueARM64_OpARM64ORshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORshiftRA x y:(SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (ORshiftRA y:(SRAconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64SRAconst || auxIntToInt64(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -19748,18 +20154,16 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (ORshiftRL x y:(SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (ORshiftRL y:(SRLconst x [c]) x [c])
        // result: y
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               if y.Op != OpARM64SRLconst {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64SRLconst || auxIntToInt64(y.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(y.AuxInt)
-               if x != y.Args[0] || !(c == d) {
+               x := y.Args[0]
+               if x != v_1 {
                        break
                }
                v.copyOf(y)
@@ -19847,58 +20251,174 @@ func rewriteValueARM64_OpARM64ORshiftRL(v *Value) bool {
        }
        return false
 }
-func rewriteValueARM64_OpARM64RORWconst(v *Value) bool {
+func rewriteValueARM64_OpARM64ORshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
        v_0 := v.Args[0]
-       // match: (RORWconst [c] (RORWconst [d] x))
-       // result: (RORWconst [(c+d)&31] x)
+       b := v.Block
+       // match: (ORshiftRO (MOVDconst [c]) x [d])
+       // result: (ORconst [c] (RORconst <x.Type> x [d]))
        for {
-               c := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64RORWconst {
+               d := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVDconst {
                        break
                }
-               d := auxIntToInt64(v_0.AuxInt)
-               x := v_0.Args[0]
-               v.reset(OpARM64RORWconst)
-               v.AuxInt = int64ToAuxInt((c + d) & 31)
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_1
+               v.reset(OpARM64ORconst)
+               v.AuxInt = int64ToAuxInt(c)
+               v0 := b.NewValue0(v.Pos, OpARM64RORconst, x.Type)
+               v0.AuxInt = int64ToAuxInt(d)
+               v0.AddArg(x)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (ORshiftRO x (MOVDconst [c]) [d])
+       // result: (ORconst x [rotateRight64(c, d)])
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               x := v_0
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               v.reset(OpARM64ORconst)
+               v.AuxInt = int64ToAuxInt(rotateRight64(c, d))
                v.AddArg(x)
                return true
        }
+       // match: (ORshiftRO y:(RORconst x [c]) x [c])
+       // result: y
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if y.Op != OpARM64RORconst || auxIntToInt64(y.AuxInt) != c {
+                       break
+               }
+               x := y.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.copyOf(y)
+               return true
+       }
        return false
 }
-func rewriteValueARM64_OpARM64RORconst(v *Value) bool {
+func rewriteValueARM64_OpARM64REV(v *Value) bool {
        v_0 := v.Args[0]
-       // match: (RORconst [c] (RORconst [d] x))
-       // result: (RORconst [(c+d)&63] x)
+       // match: (REV (REV p))
+       // result: p
        for {
-               c := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64RORconst {
+               if v_0.Op != OpARM64REV {
                        break
                }
-               d := auxIntToInt64(v_0.AuxInt)
-               x := v_0.Args[0]
-               v.reset(OpARM64RORconst)
-               v.AuxInt = int64ToAuxInt((c + d) & 63)
-               v.AddArg(x)
+               p := v_0.Args[0]
+               v.copyOf(p)
                return true
        }
        return false
 }
-func rewriteValueARM64_OpARM64SBCSflags(v *Value) bool {
-       v_2 := v.Args[2]
-       v_1 := v.Args[1]
+func rewriteValueARM64_OpARM64REVW(v *Value) bool {
        v_0 := v.Args[0]
-       b := v.Block
-       typ := &b.Func.Config.Types
-       // match: (SBCSflags x y (Select1 <types.TypeFlags> (NEGSflags (NEG <typ.UInt64> (NGCzerocarry <typ.UInt64> bo)))))
-       // result: (SBCSflags x y bo)
+       // match: (REVW (REVW p))
+       // result: p
        for {
-               x := v_0
-               y := v_1
-               if v_2.Op != OpSelect1 || v_2.Type != types.TypeFlags {
+               if v_0.Op != OpARM64REVW {
                        break
                }
-               v_2_0 := v_2.Args[0]
-               if v_2_0.Op != OpARM64NEGSflags {
+               p := v_0.Args[0]
+               v.copyOf(p)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64ROR(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (ROR x (MOVDconst [c]))
+       // result: (RORconst x [c&63])
+       for {
+               x := v_0
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               v.reset(OpARM64RORconst)
+               v.AuxInt = int64ToAuxInt(c & 63)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64RORW(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (RORW x (MOVDconst [c]))
+       // result: (RORWconst x [c&31])
+       for {
+               x := v_0
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               v.reset(OpARM64RORWconst)
+               v.AuxInt = int64ToAuxInt(c & 31)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64RORWconst(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (RORWconst [c] (RORWconst [d] x))
+       // result: (RORWconst [(c+d)&31] x)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64RORWconst {
+                       break
+               }
+               d := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               v.reset(OpARM64RORWconst)
+               v.AuxInt = int64ToAuxInt((c + d) & 31)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64RORconst(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (RORconst [c] (RORconst [d] x))
+       // result: (RORconst [(c+d)&63] x)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64RORconst {
+                       break
+               }
+               d := auxIntToInt64(v_0.AuxInt)
+               x := v_0.Args[0]
+               v.reset(OpARM64RORconst)
+               v.AuxInt = int64ToAuxInt((c + d) & 63)
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64SBCSflags(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       b := v.Block
+       typ := &b.Func.Config.Types
+       // match: (SBCSflags x y (Select1 <types.TypeFlags> (NEGSflags (NEG <typ.UInt64> (NGCzerocarry <typ.UInt64> bo)))))
+       // result: (SBCSflags x y bo)
+       for {
+               x := v_0
+               y := v_1
+               if v_2.Op != OpSelect1 || v_2.Type != types.TypeFlags {
+                       break
+               }
+               v_2_0 := v_2.Args[0]
+               if v_2_0.Op != OpARM64NEGSflags {
                        break
                }
                v_2_0_0 := v_2_0.Args[0]
@@ -19985,72 +20505,99 @@ func rewriteValueARM64_OpARM64SLLconst(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SLLconst [sc] (ANDconst [ac] x))
-       // cond: isARM64BFMask(sc, ac, 0)
-       // result: (UBFIZ [armBFAuxInt(sc, arm64BFWidth(ac, 0))] x)
+       // match: (SLLconst [lc] (MOVWreg x))
+       // result: (SBFIZ [armBFAuxInt(lc, min(32, 64-lc))] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64ANDconst {
+               lc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVWreg {
                        break
                }
-               ac := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, ac, 0)) {
+               v.reset(OpARM64SBFIZ)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, min(32, 64-lc)))
+               v.AddArg(x)
+               return true
+       }
+       // match: (SLLconst [lc] (MOVHreg x))
+       // result: (SBFIZ [armBFAuxInt(lc, min(16, 64-lc))] x)
+       for {
+               lc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVHreg {
                        break
                }
-               v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(ac, 0)))
+               x := v_0.Args[0]
+               v.reset(OpARM64SBFIZ)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, min(16, 64-lc)))
                v.AddArg(x)
                return true
        }
-       // match: (SLLconst [sc] (MOVWUreg x))
-       // cond: isARM64BFMask(sc, 1<<32-1, 0)
-       // result: (UBFIZ [armBFAuxInt(sc, 32)] x)
+       // match: (SLLconst [lc] (MOVBreg x))
+       // result: (SBFIZ [armBFAuxInt(lc, min(8, 64-lc))] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64MOVWUreg {
+               lc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVBreg {
                        break
                }
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<32-1, 0)) {
+               v.reset(OpARM64SBFIZ)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, min(8, 64-lc)))
+               v.AddArg(x)
+               return true
+       }
+       // match: (SLLconst [lc] (MOVWUreg x))
+       // result: (UBFIZ [armBFAuxInt(lc, min(32, 64-lc))] x)
+       for {
+               lc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVWUreg {
                        break
                }
+               x := v_0.Args[0]
                v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, 32))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, min(32, 64-lc)))
                v.AddArg(x)
                return true
        }
-       // match: (SLLconst [sc] (MOVHUreg x))
-       // cond: isARM64BFMask(sc, 1<<16-1, 0)
-       // result: (UBFIZ [armBFAuxInt(sc, 16)] x)
+       // match: (SLLconst [lc] (MOVHUreg x))
+       // result: (UBFIZ [armBFAuxInt(lc, min(16, 64-lc))] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
+               lc := auxIntToInt64(v.AuxInt)
                if v_0.Op != OpARM64MOVHUreg {
                        break
                }
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<16-1, 0)) {
+               v.reset(OpARM64UBFIZ)
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, min(16, 64-lc)))
+               v.AddArg(x)
+               return true
+       }
+       // match: (SLLconst [lc] (MOVBUreg x))
+       // result: (UBFIZ [armBFAuxInt(lc, min(8, 64-lc))] x)
+       for {
+               lc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVBUreg {
                        break
                }
+               x := v_0.Args[0]
                v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, 16))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(lc, min(8, 64-lc)))
                v.AddArg(x)
                return true
        }
-       // match: (SLLconst [sc] (MOVBUreg x))
-       // cond: isARM64BFMask(sc, 1<<8-1, 0)
-       // result: (UBFIZ [armBFAuxInt(sc, 8)] x)
+       // match: (SLLconst [sc] (ANDconst [ac] x))
+       // cond: isARM64BFMask(sc, ac, 0)
+       // result: (UBFIZ [armBFAuxInt(sc, arm64BFWidth(ac, 0))] x)
        for {
                sc := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64MOVBUreg {
+               if v_0.Op != OpARM64ANDconst {
                        break
                }
+               ac := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<8-1, 0)) {
+               if !(isARM64BFMask(sc, ac, 0)) {
                        break
                }
                v.reset(OpARM64UBFIZ)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, 8))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(ac, 0)))
                v.AddArg(x)
                return true
        }
@@ -20343,90 +20890,90 @@ func rewriteValueARM64_OpARM64SRLconst(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SRLconst [sc] (ANDconst [ac] x))
-       // cond: isARM64BFMask(sc, ac, sc)
-       // result: (UBFX [armBFAuxInt(sc, arm64BFWidth(ac, sc))] x)
+       // match: (SRLconst [rc] (SLLconst [lc] x))
+       // cond: lc < rc
+       // result: (UBFX [armBFAuxInt(rc-lc, 64-rc)] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64ANDconst {
+               rc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SLLconst {
                        break
                }
-               ac := auxIntToInt64(v_0.AuxInt)
+               lc := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, ac, sc)) {
+               if !(lc < rc) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(ac, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc-lc, 64-rc))
                v.AddArg(x)
                return true
        }
-       // match: (SRLconst [sc] (MOVWUreg x))
-       // cond: isARM64BFMask(sc, 1<<32-1, sc)
-       // result: (UBFX [armBFAuxInt(sc, arm64BFWidth(1<<32-1, sc))] x)
+       // match: (SRLconst [rc] (MOVWUreg x))
+       // cond: rc < 32
+       // result: (UBFX [armBFAuxInt(rc, 32-rc)] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
+               rc := auxIntToInt64(v.AuxInt)
                if v_0.Op != OpARM64MOVWUreg {
                        break
                }
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<32-1, sc)) {
+               if !(rc < 32) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(1<<32-1, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc, 32-rc))
                v.AddArg(x)
                return true
        }
-       // match: (SRLconst [sc] (MOVHUreg x))
-       // cond: isARM64BFMask(sc, 1<<16-1, sc)
-       // result: (UBFX [armBFAuxInt(sc, arm64BFWidth(1<<16-1, sc))] x)
+       // match: (SRLconst [rc] (MOVHUreg x))
+       // cond: rc < 16
+       // result: (UBFX [armBFAuxInt(rc, 16-rc)] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
+               rc := auxIntToInt64(v.AuxInt)
                if v_0.Op != OpARM64MOVHUreg {
                        break
                }
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<16-1, sc)) {
+               if !(rc < 16) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(1<<16-1, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc, 16-rc))
                v.AddArg(x)
                return true
        }
-       // match: (SRLconst [sc] (MOVBUreg x))
-       // cond: isARM64BFMask(sc, 1<<8-1, sc)
-       // result: (UBFX [armBFAuxInt(sc, arm64BFWidth(1<<8-1, sc))] x)
+       // match: (SRLconst [rc] (MOVBUreg x))
+       // cond: rc < 8
+       // result: (UBFX [armBFAuxInt(rc, 8-rc)] x)
        for {
-               sc := auxIntToInt64(v.AuxInt)
+               rc := auxIntToInt64(v.AuxInt)
                if v_0.Op != OpARM64MOVBUreg {
                        break
                }
                x := v_0.Args[0]
-               if !(isARM64BFMask(sc, 1<<8-1, sc)) {
+               if !(rc < 8) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(1<<8-1, sc)))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc, 8-rc))
                v.AddArg(x)
                return true
        }
-       // match: (SRLconst [rc] (SLLconst [lc] x))
-       // cond: lc < rc
-       // result: (UBFX [armBFAuxInt(rc-lc, 64-rc)] x)
+       // match: (SRLconst [sc] (ANDconst [ac] x))
+       // cond: isARM64BFMask(sc, ac, sc)
+       // result: (UBFX [armBFAuxInt(sc, arm64BFWidth(ac, sc))] x)
        for {
-               rc := auxIntToInt64(v.AuxInt)
-               if v_0.Op != OpARM64SLLconst {
+               sc := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64ANDconst {
                        break
                }
-               lc := auxIntToInt64(v_0.AuxInt)
+               ac := auxIntToInt64(v_0.AuxInt)
                x := v_0.Args[0]
-               if !(lc < rc) {
+               if !(isARM64BFMask(sc, ac, sc)) {
                        break
                }
                v.reset(OpARM64UBFX)
-               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(rc-lc, 64-rc))
+               v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(sc, arm64BFWidth(ac, sc)))
                v.AddArg(x)
                return true
        }
@@ -20836,17 +21383,15 @@ func rewriteValueARM64_OpARM64SUBshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SUBshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (SUBshiftLL (SLLconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -20872,17 +21417,15 @@ func rewriteValueARM64_OpARM64SUBshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SUBshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (SUBshiftRA (SRAconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -20908,17 +21451,15 @@ func rewriteValueARM64_OpARM64SUBshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (SUBshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (SUBshiftRL (SRLconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -21012,6 +21553,28 @@ func rewriteValueARM64_OpARM64TST(v *Value) bool {
                }
                break
        }
+       // match: (TST x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (TSTshiftRO x0 y [c])
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x0 := v_0
+                       x1 := v_1
+                       if x1.Op != OpARM64RORconst {
+                               continue
+                       }
+                       c := auxIntToInt64(x1.AuxInt)
+                       y := x1.Args[0]
+                       if !(clobberIfDead(x1)) {
+                               continue
+                       }
+                       v.reset(OpARM64TSTshiftRO)
+                       v.AuxInt = int64ToAuxInt(c)
+                       v.AddArg2(x0, y)
+                       return true
+               }
+               break
+       }
        return false
 }
 func rewriteValueARM64_OpARM64TSTW(v *Value) bool {
@@ -21178,6 +21741,43 @@ func rewriteValueARM64_OpARM64TSTshiftRL(v *Value) bool {
        }
        return false
 }
+func rewriteValueARM64_OpARM64TSTshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       b := v.Block
+       // match: (TSTshiftRO (MOVDconst [c]) x [d])
+       // result: (TSTconst [c] (RORconst <x.Type> x [d]))
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_1
+               v.reset(OpARM64TSTconst)
+               v.AuxInt = int64ToAuxInt(c)
+               v0 := b.NewValue0(v.Pos, OpARM64RORconst, x.Type)
+               v0.AuxInt = int64ToAuxInt(d)
+               v0.AddArg(x)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (TSTshiftRO x (MOVDconst [c]) [d])
+       // result: (TSTconst x [rotateRight64(c, d)])
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               x := v_0
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               v.reset(OpARM64TSTconst)
+               v.AuxInt = int64ToAuxInt(rotateRight64(c, d))
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
 func rewriteValueARM64_OpARM64UBFIZ(v *Value) bool {
        v_0 := v.Args[0]
        // match: (UBFIZ [bfc] (SLLconst [sc] x))
@@ -21637,6 +22237,28 @@ func rewriteValueARM64_OpARM64XOR(v *Value) bool {
                }
                break
        }
+       // match: (XOR x0 x1:(RORconst [c] y))
+       // cond: clobberIfDead(x1)
+       // result: (XORshiftRO x0 y [c])
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x0 := v_0
+                       x1 := v_1
+                       if x1.Op != OpARM64RORconst {
+                               continue
+                       }
+                       c := auxIntToInt64(x1.AuxInt)
+                       y := x1.Args[0]
+                       if !(clobberIfDead(x1)) {
+                               continue
+                       }
+                       v.reset(OpARM64XORshiftRO)
+                       v.AuxInt = int64ToAuxInt(c)
+                       v.AddArg2(x0, y)
+                       return true
+               }
+               break
+       }
        // match: (XOR (SLL x (ANDconst <t> [63] y)) (CSEL0 <typ.UInt64> [cc] (SRL <typ.UInt64> x (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y))) (CMPconst [64] (SUB <t> (MOVDconst [64]) (ANDconst <t> [63] y)))))
        // cond: cc == OpARM64LessThanU
        // result: (ROR x (NEG <t> y))
@@ -22007,17 +22629,15 @@ func rewriteValueARM64_OpARM64XORshiftLL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (XORshiftLL x (SLLconst x [c]) [d])
-       // cond: c==d
+       // match: (XORshiftLL (SLLconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SLLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SLLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -22219,17 +22839,15 @@ func rewriteValueARM64_OpARM64XORshiftRA(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (XORshiftRA x (SRAconst x [c]) [d])
-       // cond: c==d
+       // match: (XORshiftRA (SRAconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRAconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRAconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -22273,17 +22891,15 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value) bool {
                v.AddArg(x)
                return true
        }
-       // match: (XORshiftRL x (SRLconst x [c]) [d])
-       // cond: c==d
+       // match: (XORshiftRL (SRLconst x [c]) x [c])
        // result: (MOVDconst [0])
        for {
-               d := auxIntToInt64(v.AuxInt)
-               x := v_0
-               if v_1.Op != OpARM64SRLconst {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64SRLconst || auxIntToInt64(v_0.AuxInt) != c {
                        break
                }
-               c := auxIntToInt64(v_1.AuxInt)
-               if x != v_1.Args[0] || !(c == d) {
+               x := v_0.Args[0]
+               if x != v_1 {
                        break
                }
                v.reset(OpARM64MOVDconst)
@@ -22326,6 +22942,58 @@ func rewriteValueARM64_OpARM64XORshiftRL(v *Value) bool {
        }
        return false
 }
+func rewriteValueARM64_OpARM64XORshiftRO(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       b := v.Block
+       // match: (XORshiftRO (MOVDconst [c]) x [d])
+       // result: (XORconst [c] (RORconst <x.Type> x [d]))
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               x := v_1
+               v.reset(OpARM64XORconst)
+               v.AuxInt = int64ToAuxInt(c)
+               v0 := b.NewValue0(v.Pos, OpARM64RORconst, x.Type)
+               v0.AuxInt = int64ToAuxInt(d)
+               v0.AddArg(x)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (XORshiftRO x (MOVDconst [c]) [d])
+       // result: (XORconst x [rotateRight64(c, d)])
+       for {
+               d := auxIntToInt64(v.AuxInt)
+               x := v_0
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               v.reset(OpARM64XORconst)
+               v.AuxInt = int64ToAuxInt(rotateRight64(c, d))
+               v.AddArg(x)
+               return true
+       }
+       // match: (XORshiftRO (RORconst x [c]) x [c])
+       // result: (MOVDconst [0])
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpARM64RORconst || auxIntToInt64(v_0.AuxInt) != c {
+                       break
+               }
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpARM64MOVDconst)
+               v.AuxInt = int64ToAuxInt(0)
+               return true
+       }
+       return false
+}
 func rewriteValueARM64_OpAddr(v *Value) bool {
        v_0 := v.Args[0]
        // match: (Addr {sym} base)
@@ -24951,6 +25619,46 @@ func rewriteValueARM64_OpPopCount64(v *Value) bool {
                return true
        }
 }
+func rewriteValueARM64_OpPrefetchCache(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (PrefetchCache addr mem)
+       // result: (PRFM [0] addr mem)
+       for {
+               addr := v_0
+               mem := v_1
+               v.reset(OpARM64PRFM)
+               v.AuxInt = int64ToAuxInt(0)
+               v.AddArg2(addr, mem)
+               return true
+       }
+}
+func rewriteValueARM64_OpPrefetchCacheStreamed(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (PrefetchCacheStreamed addr mem)
+       // result: (PRFM [1] addr mem)
+       for {
+               addr := v_0
+               mem := v_1
+               v.reset(OpARM64PRFM)
+               v.AuxInt = int64ToAuxInt(1)
+               v.AddArg2(addr, mem)
+               return true
+       }
+}
+func rewriteValueARM64_OpPubBarrier(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (PubBarrier mem)
+       // result: (DMB [0xe] mem)
+       for {
+               mem := v_0
+               v.reset(OpARM64DMB)
+               v.AuxInt = int64ToAuxInt(0xe)
+               v.AddArg(mem)
+               return true
+       }
+}
 func rewriteValueARM64_OpRotateLeft16(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
index 429369d631eb37bf910c4b6a845fbac06da68463..811ea9d9d326f239a20e3d2c1d06fd62a7f9c914 100644 (file)
@@ -544,6 +544,9 @@ func rewriteValueMIPS(v *Value) bool {
        case OpSubPtr:
                v.Op = OpMIPSSUB
                return true
+       case OpTailCall:
+               v.Op = OpMIPSCALLtail
+               return true
        case OpTrunc16to8:
                v.Op = OpCopy
                return true
index 772d7b66efeebdf3bd3048c2d5285be80ea69b03..1fbd556b5cbcd7d32cb9ad6424d5c5d2a14580e7 100644 (file)
@@ -625,6 +625,9 @@ func rewriteValueMIPS64(v *Value) bool {
        case OpSubPtr:
                v.Op = OpMIPS64SUBV
                return true
+       case OpTailCall:
+               v.Op = OpMIPS64CALLtail
+               return true
        case OpTrunc16to8:
                v.Op = OpCopy
                return true
index 96dee0bd21baf6d9f753dcbf615fee2797506fee..7592b4f50582405812ba82999ed599e8e3a43cce 100644 (file)
@@ -639,6 +639,10 @@ func rewriteValuePPC64(v *Value) bool {
                return true
        case OpPopCount8:
                return rewriteValuePPC64_OpPopCount8(v)
+       case OpPrefetchCache:
+               return rewriteValuePPC64_OpPrefetchCache(v)
+       case OpPrefetchCacheStreamed:
+               return rewriteValuePPC64_OpPrefetchCacheStreamed(v)
        case OpRotateLeft16:
                return rewriteValuePPC64_OpRotateLeft16(v)
        case OpRotateLeft32:
@@ -720,6 +724,8 @@ func rewriteValuePPC64(v *Value) bool {
                return rewriteValuePPC64_OpRsh8x64(v)
        case OpRsh8x8:
                return rewriteValuePPC64_OpRsh8x8(v)
+       case OpSelectN:
+               return rewriteValuePPC64_OpSelectN(v)
        case OpSignExt16to32:
                v.Op = OpPPC64MOVHreg
                return true
@@ -772,6 +778,9 @@ func rewriteValuePPC64(v *Value) bool {
        case OpSubPtr:
                v.Op = OpPPC64SUB
                return true
+       case OpTailCall:
+               v.Op = OpPPC64CALLtail
+               return true
        case OpTrunc:
                v.Op = OpPPC64FTRUNC
                return true
@@ -1159,23 +1168,8 @@ func rewriteValuePPC64_OpCondSelect(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
        // match: (CondSelect x y bool)
-       // cond: flagArg(bool) != nil
-       // result: (ISEL [2] x y bool)
-       for {
-               x := v_0
-               y := v_1
-               bool := v_2
-               if !(flagArg(bool) != nil) {
-                       break
-               }
-               v.reset(OpPPC64ISEL)
-               v.AuxInt = int32ToAuxInt(2)
-               v.AddArg3(x, y, bool)
-               return true
-       }
-       // match: (CondSelect x y bool)
        // cond: flagArg(bool) == nil
-       // result: (ISEL [2] x y (CMPWconst [0] bool))
+       // result: (ISEL [6] x y (CMPWconst [0] bool))
        for {
                x := v_0
                y := v_1
@@ -1184,7 +1178,7 @@ func rewriteValuePPC64_OpCondSelect(v *Value) bool {
                        break
                }
                v.reset(OpPPC64ISEL)
-               v.AuxInt = int32ToAuxInt(2)
+               v.AuxInt = int32ToAuxInt(6)
                v0 := b.NewValue0(v.Pos, OpPPC64CMPWconst, types.TypeFlags)
                v0.AuxInt = int32ToAuxInt(0)
                v0.AddArg(bool)
@@ -5901,6 +5895,28 @@ func rewriteValuePPC64_OpPPC64ISEL(v *Value) bool {
                v.AddArg(y)
                return true
        }
+       // match: (ISEL [6] x y (CMPWconst [0] (ISELB [c] one cmp)))
+       // result: (ISEL [c] x y cmp)
+       for {
+               if auxIntToInt32(v.AuxInt) != 6 {
+                       break
+               }
+               x := v_0
+               y := v_1
+               if v_2.Op != OpPPC64CMPWconst || auxIntToInt32(v_2.AuxInt) != 0 {
+                       break
+               }
+               v_2_0 := v_2.Args[0]
+               if v_2_0.Op != OpPPC64ISELB {
+                       break
+               }
+               c := auxIntToInt32(v_2_0.AuxInt)
+               cmp := v_2_0.Args[1]
+               v.reset(OpPPC64ISEL)
+               v.AuxInt = int32ToAuxInt(c)
+               v.AddArg3(x, y, cmp)
+               return true
+       }
        // match: (ISEL [2] x _ (FlagEQ))
        // result: x
        for {
@@ -7084,6 +7100,20 @@ func rewriteValuePPC64_OpPPC64MOVBZreg(v *Value) bool {
                v.copyOf(x)
                return true
        }
+       // match: (MOVBZreg x:(Select0 (LoweredAtomicLoad8 _ _)))
+       // result: x
+       for {
+               x := v_0
+               if x.Op != OpSelect0 {
+                       break
+               }
+               x_0 := x.Args[0]
+               if x_0.Op != OpPPC64LoweredAtomicLoad8 {
+                       break
+               }
+               v.copyOf(x)
+               return true
+       }
        // match: (MOVBZreg x:(Arg <t>))
        // cond: is8BitInt(t) && !isSigned(t)
        // result: x
@@ -10540,6 +10570,20 @@ func rewriteValuePPC64_OpPPC64MOVWZreg(v *Value) bool {
                v.copyOf(x)
                return true
        }
+       // match: (MOVWZreg x:(Select0 (LoweredAtomicLoad32 _ _)))
+       // result: x
+       for {
+               x := v_0
+               if x.Op != OpSelect0 {
+                       break
+               }
+               x_0 := x.Args[0]
+               if x_0.Op != OpPPC64LoweredAtomicLoad32 {
+                       break
+               }
+               v.copyOf(x)
+               return true
+       }
        // match: (MOVWZreg x:(Arg <t>))
        // cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)
        // result: x
@@ -11335,6 +11379,28 @@ func rewriteValuePPC64_OpPPC64NEG(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (NEG (SUB x y))
+       // result: (SUB y x)
+       for {
+               if v_0.Op != OpPPC64SUB {
+                       break
+               }
+               y := v_0.Args[1]
+               x := v_0.Args[0]
+               v.reset(OpPPC64SUB)
+               v.AddArg2(y, x)
+               return true
+       }
+       // match: (NEG (NEG x))
+       // result: x
+       for {
+               if v_0.Op != OpPPC64NEG {
+                       break
+               }
+               x := v_0.Args[0]
+               v.copyOf(x)
+               return true
+       }
        return false
 }
 func rewriteValuePPC64_OpPPC64NOR(v *Value) bool {
@@ -13875,6 +13941,8 @@ func rewriteValuePPC64_OpPPC64XOR(v *Value) bool {
 }
 func rewriteValuePPC64_OpPPC64XORconst(v *Value) bool {
        v_0 := v.Args[0]
+       b := v.Block
+       typ := &b.Func.Config.Types
        // match: (XORconst [c] (XORconst [d] x))
        // result: (XORconst [c^d] x)
        for {
@@ -13899,6 +13967,60 @@ func rewriteValuePPC64_OpPPC64XORconst(v *Value) bool {
                v.copyOf(x)
                return true
        }
+       // match: (XORconst [1] (ISELB [6] (MOVDconst [1]) cmp))
+       // result: (ISELB [2] (MOVDconst [1]) cmp)
+       for {
+               if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpPPC64ISELB || auxIntToInt32(v_0.AuxInt) != 6 {
+                       break
+               }
+               cmp := v_0.Args[1]
+               v_0_0 := v_0.Args[0]
+               if v_0_0.Op != OpPPC64MOVDconst || auxIntToInt64(v_0_0.AuxInt) != 1 {
+                       break
+               }
+               v.reset(OpPPC64ISELB)
+               v.AuxInt = int32ToAuxInt(2)
+               v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
+               v0.AuxInt = int64ToAuxInt(1)
+               v.AddArg2(v0, cmp)
+               return true
+       }
+       // match: (XORconst [1] (ISELB [5] (MOVDconst [1]) cmp))
+       // result: (ISELB [1] (MOVDconst [1]) cmp)
+       for {
+               if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpPPC64ISELB || auxIntToInt32(v_0.AuxInt) != 5 {
+                       break
+               }
+               cmp := v_0.Args[1]
+               v_0_0 := v_0.Args[0]
+               if v_0_0.Op != OpPPC64MOVDconst || auxIntToInt64(v_0_0.AuxInt) != 1 {
+                       break
+               }
+               v.reset(OpPPC64ISELB)
+               v.AuxInt = int32ToAuxInt(1)
+               v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
+               v0.AuxInt = int64ToAuxInt(1)
+               v.AddArg2(v0, cmp)
+               return true
+       }
+       // match: (XORconst [1] (ISELB [4] (MOVDconst [1]) cmp))
+       // result: (ISELB [0] (MOVDconst [1]) cmp)
+       for {
+               if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpPPC64ISELB || auxIntToInt32(v_0.AuxInt) != 4 {
+                       break
+               }
+               cmp := v_0.Args[1]
+               v_0_0 := v_0.Args[0]
+               if v_0_0.Op != OpPPC64MOVDconst || auxIntToInt64(v_0_0.AuxInt) != 1 {
+                       break
+               }
+               v.reset(OpPPC64ISELB)
+               v.AuxInt = int32ToAuxInt(0)
+               v0 := b.NewValue0(v.Pos, OpPPC64MOVDconst, typ.Int64)
+               v0.AuxInt = int64ToAuxInt(1)
+               v.AddArg2(v0, cmp)
+               return true
+       }
        return false
 }
 func rewriteValuePPC64_OpPanicBounds(v *Value) bool {
@@ -14000,6 +14122,34 @@ func rewriteValuePPC64_OpPopCount8(v *Value) bool {
                return true
        }
 }
+func rewriteValuePPC64_OpPrefetchCache(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (PrefetchCache ptr mem)
+       // result: (DCBT ptr mem [0])
+       for {
+               ptr := v_0
+               mem := v_1
+               v.reset(OpPPC64DCBT)
+               v.AuxInt = int64ToAuxInt(0)
+               v.AddArg2(ptr, mem)
+               return true
+       }
+}
+func rewriteValuePPC64_OpPrefetchCacheStreamed(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (PrefetchCacheStreamed ptr mem)
+       // result: (DCBT ptr mem [8])
+       for {
+               ptr := v_0
+               mem := v_1
+               v.reset(OpPPC64DCBT)
+               v.AuxInt = int64ToAuxInt(8)
+               v.AddArg2(ptr, mem)
+               return true
+       }
+}
 func rewriteValuePPC64_OpRotateLeft16(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -16436,6 +16586,82 @@ func rewriteValuePPC64_OpRsh8x8(v *Value) bool {
                return true
        }
 }
+func rewriteValuePPC64_OpSelectN(v *Value) bool {
+       v_0 := v.Args[0]
+       b := v.Block
+       config := b.Func.Config
+       // match: (SelectN [0] call:(CALLstatic {sym} s1:(MOVDstore _ (MOVDconst [sz]) s2:(MOVDstore _ src s3:(MOVDstore {t} _ dst mem)))))
+       // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call)
+       // result: (Move [sz] dst src mem)
+       for {
+               if auxIntToInt64(v.AuxInt) != 0 {
+                       break
+               }
+               call := v_0
+               if call.Op != OpPPC64CALLstatic || len(call.Args) != 1 {
+                       break
+               }
+               sym := auxToCall(call.Aux)
+               s1 := call.Args[0]
+               if s1.Op != OpPPC64MOVDstore {
+                       break
+               }
+               _ = s1.Args[2]
+               s1_1 := s1.Args[1]
+               if s1_1.Op != OpPPC64MOVDconst {
+                       break
+               }
+               sz := auxIntToInt64(s1_1.AuxInt)
+               s2 := s1.Args[2]
+               if s2.Op != OpPPC64MOVDstore {
+                       break
+               }
+               _ = s2.Args[2]
+               src := s2.Args[1]
+               s3 := s2.Args[2]
+               if s3.Op != OpPPC64MOVDstore {
+                       break
+               }
+               mem := s3.Args[2]
+               dst := s3.Args[1]
+               if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(s1, s2, s3, call)) {
+                       break
+               }
+               v.reset(OpMove)
+               v.AuxInt = int64ToAuxInt(sz)
+               v.AddArg3(dst, src, mem)
+               return true
+       }
+       // match: (SelectN [0] call:(CALLstatic {sym} dst src (MOVDconst [sz]) mem))
+       // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call)
+       // result: (Move [sz] dst src mem)
+       for {
+               if auxIntToInt64(v.AuxInt) != 0 {
+                       break
+               }
+               call := v_0
+               if call.Op != OpPPC64CALLstatic || len(call.Args) != 4 {
+                       break
+               }
+               sym := auxToCall(call.Aux)
+               mem := call.Args[3]
+               dst := call.Args[0]
+               src := call.Args[1]
+               call_2 := call.Args[2]
+               if call_2.Op != OpPPC64MOVDconst {
+                       break
+               }
+               sz := auxIntToInt64(call_2.AuxInt)
+               if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && call.Uses == 1 && isInlinableMemmove(dst, src, sz, config) && clobber(call)) {
+                       break
+               }
+               v.reset(OpMove)
+               v.AuxInt = int64ToAuxInt(sz)
+               v.AddArg3(dst, src, mem)
+               return true
+       }
+       return false
+}
 func rewriteValuePPC64_OpSlicemask(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
@@ -16502,14 +16728,14 @@ func rewriteValuePPC64_OpStore(v *Value) bool {
                return true
        }
        // match: (Store {t} ptr val mem)
-       // cond: t.Size() == 8 && (is64BitInt(val.Type) || isPtr(val.Type))
+       // cond: t.Size() == 8 && !is64BitFloat(val.Type)
        // result: (MOVDstore ptr val mem)
        for {
                t := auxToType(v.Aux)
                ptr := v_0
                val := v_1
                mem := v_2
-               if !(t.Size() == 8 && (is64BitInt(val.Type) || isPtr(val.Type))) {
+               if !(t.Size() == 8 && !is64BitFloat(val.Type)) {
                        break
                }
                v.reset(OpPPC64MOVDstore)
index 431fb1aaf66e0dd288704707d9ed909780533d4b..885bbaf4a1d0bf1cd3732264da50f23ed8deeaa0 100644 (file)
@@ -8,6 +8,9 @@ import "cmd/compile/internal/types"
 
 func rewriteValueRISCV64(v *Value) bool {
        switch v.Op {
+       case OpAbs:
+               v.Op = OpRISCV64FABSD
+               return true
        case OpAdd16:
                v.Op = OpRISCV64ADD
                return true
@@ -134,6 +137,9 @@ func rewriteValueRISCV64(v *Value) bool {
        case OpConvert:
                v.Op = OpRISCV64MOVconvert
                return true
+       case OpCopysign:
+               v.Op = OpRISCV64FSGNJD
+               return true
        case OpCvt32Fto32:
                v.Op = OpRISCV64FCVTWS
                return true
@@ -209,6 +215,9 @@ func rewriteValueRISCV64(v *Value) bool {
                return rewriteValueRISCV64_OpEqB(v)
        case OpEqPtr:
                return rewriteValueRISCV64_OpEqPtr(v)
+       case OpFMA:
+               v.Op = OpRISCV64FMADDD
+               return true
        case OpGetCallerPC:
                v.Op = OpRISCV64LoweredGetCallerPC
                return true
@@ -356,6 +365,12 @@ func rewriteValueRISCV64(v *Value) bool {
        case OpMul64F:
                v.Op = OpRISCV64FMULD
                return true
+       case OpMul64uhilo:
+               v.Op = OpRISCV64LoweredMuluhilo
+               return true
+       case OpMul64uover:
+               v.Op = OpRISCV64LoweredMuluover
+               return true
        case OpMul8:
                return rewriteValueRISCV64_OpMul8(v)
        case OpNeg16:
@@ -426,6 +441,16 @@ func rewriteValueRISCV64(v *Value) bool {
                return rewriteValueRISCV64_OpRISCV64ADDI(v)
        case OpRISCV64AND:
                return rewriteValueRISCV64_OpRISCV64AND(v)
+       case OpRISCV64ANDI:
+               return rewriteValueRISCV64_OpRISCV64ANDI(v)
+       case OpRISCV64FMADDD:
+               return rewriteValueRISCV64_OpRISCV64FMADDD(v)
+       case OpRISCV64FMSUBD:
+               return rewriteValueRISCV64_OpRISCV64FMSUBD(v)
+       case OpRISCV64FNMADDD:
+               return rewriteValueRISCV64_OpRISCV64FNMADDD(v)
+       case OpRISCV64FNMSUBD:
+               return rewriteValueRISCV64_OpRISCV64FNMSUBD(v)
        case OpRISCV64MOVBUload:
                return rewriteValueRISCV64_OpRISCV64MOVBUload(v)
        case OpRISCV64MOVBUreg:
@@ -472,14 +497,30 @@ func rewriteValueRISCV64(v *Value) bool {
                return rewriteValueRISCV64_OpRISCV64MOVWstore(v)
        case OpRISCV64MOVWstorezero:
                return rewriteValueRISCV64_OpRISCV64MOVWstorezero(v)
+       case OpRISCV64NEG:
+               return rewriteValueRISCV64_OpRISCV64NEG(v)
+       case OpRISCV64NEGW:
+               return rewriteValueRISCV64_OpRISCV64NEGW(v)
        case OpRISCV64OR:
                return rewriteValueRISCV64_OpRISCV64OR(v)
+       case OpRISCV64ORI:
+               return rewriteValueRISCV64_OpRISCV64ORI(v)
        case OpRISCV64SLL:
                return rewriteValueRISCV64_OpRISCV64SLL(v)
+       case OpRISCV64SLLI:
+               return rewriteValueRISCV64_OpRISCV64SLLI(v)
+       case OpRISCV64SLTI:
+               return rewriteValueRISCV64_OpRISCV64SLTI(v)
+       case OpRISCV64SLTIU:
+               return rewriteValueRISCV64_OpRISCV64SLTIU(v)
        case OpRISCV64SRA:
                return rewriteValueRISCV64_OpRISCV64SRA(v)
+       case OpRISCV64SRAI:
+               return rewriteValueRISCV64_OpRISCV64SRAI(v)
        case OpRISCV64SRL:
                return rewriteValueRISCV64_OpRISCV64SRL(v)
+       case OpRISCV64SRLI:
+               return rewriteValueRISCV64_OpRISCV64SRLI(v)
        case OpRISCV64SUB:
                return rewriteValueRISCV64_OpRISCV64SUB(v)
        case OpRISCV64SUBW:
@@ -616,6 +657,9 @@ func rewriteValueRISCV64(v *Value) bool {
        case OpSubPtr:
                v.Op = OpRISCV64SUB
                return true
+       case OpTailCall:
+               v.Op = OpRISCV64CALLtail
+               return true
        case OpTrunc16to8:
                v.Op = OpCopy
                return true
@@ -2796,6 +2840,22 @@ func rewriteValueRISCV64_OpRISCV64ADDI(v *Value) bool {
                v.copyOf(x)
                return true
        }
+       // match: (ADDI [x] (MOVDconst [y]))
+       // cond: is32Bit(x + y)
+       // result: (MOVDconst [x + y])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               if !(is32Bit(x + y)) {
+                       break
+               }
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(x + y)
+               return true
+       }
        return false
 }
 func rewriteValueRISCV64_OpRISCV64AND(v *Value) bool {
@@ -2823,6 +2883,222 @@ func rewriteValueRISCV64_OpRISCV64AND(v *Value) bool {
        }
        return false
 }
+func rewriteValueRISCV64_OpRISCV64ANDI(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (ANDI [0] x)
+       // result: (MOVDconst [0])
+       for {
+               if auxIntToInt64(v.AuxInt) != 0 {
+                       break
+               }
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(0)
+               return true
+       }
+       // match: (ANDI [-1] x)
+       // result: x
+       for {
+               if auxIntToInt64(v.AuxInt) != -1 {
+                       break
+               }
+               x := v_0
+               v.copyOf(x)
+               return true
+       }
+       // match: (ANDI [x] (MOVDconst [y]))
+       // result: (MOVDconst [x & y])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(x & y)
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (FMADDD neg:(FNEGD x) y z)
+       // cond: neg.Uses == 1
+       // result: (FNMADDD x y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       neg := v_0
+                       if neg.Op != OpRISCV64FNEGD {
+                               continue
+                       }
+                       x := neg.Args[0]
+                       y := v_1
+                       z := v_2
+                       if !(neg.Uses == 1) {
+                               continue
+                       }
+                       v.reset(OpRISCV64FNMADDD)
+                       v.AddArg3(x, y, z)
+                       return true
+               }
+               break
+       }
+       // match: (FMADDD x y neg:(FNEGD z))
+       // cond: neg.Uses == 1
+       // result: (FMSUBD x y z)
+       for {
+               x := v_0
+               y := v_1
+               neg := v_2
+               if neg.Op != OpRISCV64FNEGD {
+                       break
+               }
+               z := neg.Args[0]
+               if !(neg.Uses == 1) {
+                       break
+               }
+               v.reset(OpRISCV64FMSUBD)
+               v.AddArg3(x, y, z)
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (FMSUBD neg:(FNEGD x) y z)
+       // cond: neg.Uses == 1
+       // result: (FNMSUBD x y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       neg := v_0
+                       if neg.Op != OpRISCV64FNEGD {
+                               continue
+                       }
+                       x := neg.Args[0]
+                       y := v_1
+                       z := v_2
+                       if !(neg.Uses == 1) {
+                               continue
+                       }
+                       v.reset(OpRISCV64FNMSUBD)
+                       v.AddArg3(x, y, z)
+                       return true
+               }
+               break
+       }
+       // match: (FMSUBD x y neg:(FNEGD z))
+       // cond: neg.Uses == 1
+       // result: (FMADDD x y z)
+       for {
+               x := v_0
+               y := v_1
+               neg := v_2
+               if neg.Op != OpRISCV64FNEGD {
+                       break
+               }
+               z := neg.Args[0]
+               if !(neg.Uses == 1) {
+                       break
+               }
+               v.reset(OpRISCV64FMADDD)
+               v.AddArg3(x, y, z)
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (FNMADDD neg:(FNEGD x) y z)
+       // cond: neg.Uses == 1
+       // result: (FMADDD x y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       neg := v_0
+                       if neg.Op != OpRISCV64FNEGD {
+                               continue
+                       }
+                       x := neg.Args[0]
+                       y := v_1
+                       z := v_2
+                       if !(neg.Uses == 1) {
+                               continue
+                       }
+                       v.reset(OpRISCV64FMADDD)
+                       v.AddArg3(x, y, z)
+                       return true
+               }
+               break
+       }
+       // match: (FNMADDD x y neg:(FNEGD z))
+       // cond: neg.Uses == 1
+       // result: (FNMSUBD x y z)
+       for {
+               x := v_0
+               y := v_1
+               neg := v_2
+               if neg.Op != OpRISCV64FNEGD {
+                       break
+               }
+               z := neg.Args[0]
+               if !(neg.Uses == 1) {
+                       break
+               }
+               v.reset(OpRISCV64FNMSUBD)
+               v.AddArg3(x, y, z)
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (FNMSUBD neg:(FNEGD x) y z)
+       // cond: neg.Uses == 1
+       // result: (FMSUBD x y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       neg := v_0
+                       if neg.Op != OpRISCV64FNEGD {
+                               continue
+                       }
+                       x := neg.Args[0]
+                       y := v_1
+                       z := v_2
+                       if !(neg.Uses == 1) {
+                               continue
+                       }
+                       v.reset(OpRISCV64FMSUBD)
+                       v.AddArg3(x, y, z)
+                       return true
+               }
+               break
+       }
+       // match: (FNMSUBD x y neg:(FNEGD z))
+       // cond: neg.Uses == 1
+       // result: (FNMADDD x y z)
+       for {
+               x := v_0
+               y := v_1
+               neg := v_2
+               if neg.Op != OpRISCV64FNEGD {
+                       break
+               }
+               z := neg.Args[0]
+               if !(neg.Uses == 1) {
+                       break
+               }
+               v.reset(OpRISCV64FNMADDD)
+               v.AddArg3(x, y, z)
+               return true
+       }
+       return false
+}
 func rewriteValueRISCV64_OpRISCV64MOVBUload(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -4413,6 +4689,36 @@ func rewriteValueRISCV64_OpRISCV64MOVWstorezero(v *Value) bool {
        }
        return false
 }
+func rewriteValueRISCV64_OpRISCV64NEG(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (NEG (MOVDconst [x]))
+       // result: (MOVDconst [-x])
+       for {
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               x := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(-x)
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64NEGW(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (NEGW (MOVDconst [x]))
+       // result: (MOVDconst [int64(int32(-x))])
+       for {
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               x := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(int64(int32(-x)))
+               return true
+       }
+       return false
+}
 func rewriteValueRISCV64_OpRISCV64OR(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -4438,6 +4744,42 @@ func rewriteValueRISCV64_OpRISCV64OR(v *Value) bool {
        }
        return false
 }
+func rewriteValueRISCV64_OpRISCV64ORI(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (ORI [0] x)
+       // result: x
+       for {
+               if auxIntToInt64(v.AuxInt) != 0 {
+                       break
+               }
+               x := v_0
+               v.copyOf(x)
+               return true
+       }
+       // match: (ORI [-1] x)
+       // result: (MOVDconst [-1])
+       for {
+               if auxIntToInt64(v.AuxInt) != -1 {
+                       break
+               }
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(-1)
+               return true
+       }
+       // match: (ORI [x] (MOVDconst [y]))
+       // result: (MOVDconst [x | y])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(x | y)
+               return true
+       }
+       return false
+}
 func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -4456,6 +4798,58 @@ func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool {
        }
        return false
 }
+func rewriteValueRISCV64_OpRISCV64SLLI(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (SLLI [x] (MOVDconst [y]))
+       // cond: is32Bit(y << x)
+       // result: (MOVDconst [y << x])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               if !(is32Bit(y << x)) {
+                       break
+               }
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(y << x)
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64SLTI(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (SLTI [x] (MOVDconst [y]))
+       // result: (MOVDconst [b2i(int64(y) < int64(x))])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(b2i(int64(y) < int64(x)))
+               return true
+       }
+       return false
+}
+func rewriteValueRISCV64_OpRISCV64SLTIU(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (SLTIU [x] (MOVDconst [y]))
+       // result: (MOVDconst [b2i(uint64(y) < uint64(x))])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(b2i(uint64(y) < uint64(x)))
+               return true
+       }
+       return false
+}
 func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -4474,6 +4868,22 @@ func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
        }
        return false
 }
+func rewriteValueRISCV64_OpRISCV64SRAI(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (SRAI [x] (MOVDconst [y]))
+       // result: (MOVDconst [int64(y) >> x])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(int64(y) >> x)
+               return true
+       }
+       return false
+}
 func rewriteValueRISCV64_OpRISCV64SRL(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -4492,6 +4902,22 @@ func rewriteValueRISCV64_OpRISCV64SRL(v *Value) bool {
        }
        return false
 }
+func rewriteValueRISCV64_OpRISCV64SRLI(v *Value) bool {
+       v_0 := v.Args[0]
+       // match: (SRLI [x] (MOVDconst [y]))
+       // result: (MOVDconst [int64(uint64(y) >> x)])
+       for {
+               x := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpRISCV64MOVDconst {
+                       break
+               }
+               y := auxIntToInt64(v_0.AuxInt)
+               v.reset(OpRISCV64MOVDconst)
+               v.AuxInt = int64ToAuxInt(int64(uint64(y) >> x))
+               return true
+       }
+       return false
+}
 func rewriteValueRISCV64_OpRISCV64SUB(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
@@ -6096,6 +6522,18 @@ func rewriteBlockRISCV64(b *Block) bool {
                        b.resetWithControl(BlockRISCV64BEQZ, x)
                        return true
                }
+               // match: (BEQZ x:(NEG y) yes no)
+               // cond: x.Uses == 1
+               // result: (BEQZ y yes no)
+               for b.Controls[0].Op == OpRISCV64NEG {
+                       x := b.Controls[0]
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.resetWithControl(BlockRISCV64BEQZ, y)
+                       return true
+               }
                // match: (BEQZ (SUB x y) yes no)
                // result: (BEQ x y yes no)
                for b.Controls[0].Op == OpRISCV64SUB {
@@ -6123,6 +6561,52 @@ func rewriteBlockRISCV64(b *Block) bool {
                        b.resetWithControl2(BlockRISCV64BGEU, x, y)
                        return true
                }
+       case BlockRISCV64BGE:
+               // match: (BGE (MOVDconst [0]) cond yes no)
+               // result: (BLEZ 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(BlockRISCV64BLEZ, cond)
+                       return true
+               }
+               // match: (BGE cond (MOVDconst [0]) yes no)
+               // result: (BGEZ 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(BlockRISCV64BGEZ, cond)
+                       return true
+               }
+       case BlockRISCV64BLT:
+               // match: (BLT (MOVDconst [0]) cond yes no)
+               // result: (BGTZ 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(BlockRISCV64BGTZ, cond)
+                       return true
+               }
+               // match: (BLT cond (MOVDconst [0]) yes no)
+               // result: (BLTZ 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(BlockRISCV64BLTZ, cond)
+                       return true
+               }
        case BlockRISCV64BNE:
                // match: (BNE (MOVDconst [0]) cond yes no)
                // result: (BNEZ cond yes no)
@@ -6163,6 +6647,18 @@ func rewriteBlockRISCV64(b *Block) bool {
                        b.resetWithControl(BlockRISCV64BNEZ, x)
                        return true
                }
+               // match: (BNEZ x:(NEG y) yes no)
+               // cond: x.Uses == 1
+               // result: (BNEZ y yes no)
+               for b.Controls[0].Op == OpRISCV64NEG {
+                       x := b.Controls[0]
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.resetWithControl(BlockRISCV64BNEZ, y)
+                       return true
+               }
                // match: (BNEZ (SUB x y) yes no)
                // result: (BNE x y yes no)
                for b.Controls[0].Op == OpRISCV64SUB {
index 8b41d62c315bd25de6fa2adbdd553c17e1ca2a3e..0d6358614929c1adc323bd5eaadd7bb12c41a796 100644 (file)
@@ -819,6 +819,9 @@ func rewriteValueS390X(v *Value) bool {
        case OpSubPtr:
                v.Op = OpS390XSUB
                return true
+       case OpTailCall:
+               v.Op = OpS390XCALLtail
+               return true
        case OpTrunc:
                return rewriteValueS390X_OpTrunc(v)
        case OpTrunc16to8:
index 5dab09f85b35780f7113c4cb5e89e70337c7ae49..defd40ddd195e6a233e6205fcb74896ce5b52550 100644 (file)
@@ -556,6 +556,9 @@ func rewriteValueWasm(v *Value) bool {
        case OpSubPtr:
                v.Op = OpWasmI64Sub
                return true
+       case OpTailCall:
+               v.Op = OpWasmLoweredTailCall
+               return true
        case OpTrunc:
                v.Op = OpWasmF64Trunc
                return true
index 52258201ca105163e20197a200794c7604176ad2..fbf227562a92fc4e708aaa94746c6800d9a07918 100644 (file)
@@ -533,6 +533,52 @@ func rewriteValuegeneric_OpAdd16(v *Value) bool {
                }
                break
        }
+       // match: (Add16 x (Sub16 y x))
+       // result: y
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpSub16 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       y := v_1.Args[0]
+                       if x != v_1.Args[1] {
+                               continue
+                       }
+                       v.copyOf(y)
+                       return true
+               }
+               break
+       }
+       // match: (Add16 x (Add16 y (Sub16 z x)))
+       // result: (Add16 y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAdd16 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       v_1_0 := v_1.Args[0]
+                       v_1_1 := v_1.Args[1]
+                       for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
+                               y := v_1_0
+                               if v_1_1.Op != OpSub16 {
+                                       continue
+                               }
+                               _ = v_1_1.Args[1]
+                               z := v_1_1.Args[0]
+                               if x != v_1_1.Args[1] {
+                                       continue
+                               }
+                               v.reset(OpAdd16)
+                               v.AddArg2(y, z)
+                               return true
+                       }
+               }
+               break
+       }
        // match: (Add16 (Add16 i:(Const16 <t>) z) x)
        // cond: (z.Op != OpConst16 && x.Op != OpConst16)
        // result: (Add16 i (Add16 <t> z x))
@@ -732,6 +778,52 @@ func rewriteValuegeneric_OpAdd32(v *Value) bool {
                }
                break
        }
+       // match: (Add32 x (Sub32 y x))
+       // result: y
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpSub32 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       y := v_1.Args[0]
+                       if x != v_1.Args[1] {
+                               continue
+                       }
+                       v.copyOf(y)
+                       return true
+               }
+               break
+       }
+       // match: (Add32 x (Add32 y (Sub32 z x)))
+       // result: (Add32 y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAdd32 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       v_1_0 := v_1.Args[0]
+                       v_1_1 := v_1.Args[1]
+                       for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
+                               y := v_1_0
+                               if v_1_1.Op != OpSub32 {
+                                       continue
+                               }
+                               _ = v_1_1.Args[1]
+                               z := v_1_1.Args[0]
+                               if x != v_1_1.Args[1] {
+                                       continue
+                               }
+                               v.reset(OpAdd32)
+                               v.AddArg2(y, z)
+                               return true
+                       }
+               }
+               break
+       }
        // match: (Add32 (Add32 i:(Const32 <t>) z) x)
        // cond: (z.Op != OpConst32 && x.Op != OpConst32)
        // result: (Add32 i (Add32 <t> z x))
@@ -958,6 +1050,52 @@ func rewriteValuegeneric_OpAdd64(v *Value) bool {
                }
                break
        }
+       // match: (Add64 x (Sub64 y x))
+       // result: y
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpSub64 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       y := v_1.Args[0]
+                       if x != v_1.Args[1] {
+                               continue
+                       }
+                       v.copyOf(y)
+                       return true
+               }
+               break
+       }
+       // match: (Add64 x (Add64 y (Sub64 z x)))
+       // result: (Add64 y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAdd64 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       v_1_0 := v_1.Args[0]
+                       v_1_1 := v_1.Args[1]
+                       for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
+                               y := v_1_0
+                               if v_1_1.Op != OpSub64 {
+                                       continue
+                               }
+                               _ = v_1_1.Args[1]
+                               z := v_1_1.Args[0]
+                               if x != v_1_1.Args[1] {
+                                       continue
+                               }
+                               v.reset(OpAdd64)
+                               v.AddArg2(y, z)
+                               return true
+                       }
+               }
+               break
+       }
        // match: (Add64 (Add64 i:(Const64 <t>) z) x)
        // cond: (z.Op != OpConst64 && x.Op != OpConst64)
        // result: (Add64 i (Add64 <t> z x))
@@ -1184,6 +1322,52 @@ func rewriteValuegeneric_OpAdd8(v *Value) bool {
                }
                break
        }
+       // match: (Add8 x (Sub8 y x))
+       // result: y
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpSub8 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       y := v_1.Args[0]
+                       if x != v_1.Args[1] {
+                               continue
+                       }
+                       v.copyOf(y)
+                       return true
+               }
+               break
+       }
+       // match: (Add8 x (Add8 y (Sub8 z x)))
+       // result: (Add8 y z)
+       for {
+               for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+                       x := v_0
+                       if v_1.Op != OpAdd8 {
+                               continue
+                       }
+                       _ = v_1.Args[1]
+                       v_1_0 := v_1.Args[0]
+                       v_1_1 := v_1.Args[1]
+                       for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 {
+                               y := v_1_0
+                               if v_1_1.Op != OpSub8 {
+                                       continue
+                               }
+                               _ = v_1_1.Args[1]
+                               z := v_1_1.Args[0]
+                               if x != v_1_1.Args[1] {
+                                       continue
+                               }
+                               v.reset(OpAdd8)
+                               v.AddArg2(y, z)
+                               return true
+                       }
+               }
+               break
+       }
        // match: (Add8 (Add8 i:(Const8 <t>) z) x)
        // cond: (z.Op != OpConst8 && x.Op != OpConst8)
        // result: (Add8 i (Add8 <t> z x))
@@ -9899,6 +10083,7 @@ func rewriteValuegeneric_OpLeq8U(v *Value) bool {
 func rewriteValuegeneric_OpLess16(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
+       b := v.Block
        // match: (Less16 (Const16 [c]) (Const16 [d]))
        // result: (ConstBool [c < d])
        for {
@@ -9914,6 +10099,45 @@ func rewriteValuegeneric_OpLess16(v *Value) bool {
                v.AuxInt = boolToAuxInt(c < d)
                return true
        }
+       // match: (Less16 (Const16 <t> [0]) x)
+       // cond: isNonNegative(x)
+       // result: (Neq16 (Const16 <t> [0]) x)
+       for {
+               if v_0.Op != OpConst16 {
+                       break
+               }
+               t := v_0.Type
+               if auxIntToInt16(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_1
+               if !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpNeq16)
+               v0 := b.NewValue0(v.Pos, OpConst16, t)
+               v0.AuxInt = int16ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
+       // match: (Less16 x (Const16 <t> [1]))
+       // cond: isNonNegative(x)
+       // result: (Eq16 (Const16 <t> [0]) x)
+       for {
+               x := v_0
+               if v_1.Op != OpConst16 {
+                       break
+               }
+               t := v_1.Type
+               if auxIntToInt16(v_1.AuxInt) != 1 || !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpEq16)
+               v0 := b.NewValue0(v.Pos, OpConst16, t)
+               v0.AuxInt = int16ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
        return false
 }
 func rewriteValuegeneric_OpLess16U(v *Value) bool {
@@ -9949,6 +10173,7 @@ func rewriteValuegeneric_OpLess16U(v *Value) bool {
 func rewriteValuegeneric_OpLess32(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
+       b := v.Block
        // match: (Less32 (Const32 [c]) (Const32 [d]))
        // result: (ConstBool [c < d])
        for {
@@ -9964,6 +10189,45 @@ func rewriteValuegeneric_OpLess32(v *Value) bool {
                v.AuxInt = boolToAuxInt(c < d)
                return true
        }
+       // match: (Less32 (Const32 <t> [0]) x)
+       // cond: isNonNegative(x)
+       // result: (Neq32 (Const32 <t> [0]) x)
+       for {
+               if v_0.Op != OpConst32 {
+                       break
+               }
+               t := v_0.Type
+               if auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_1
+               if !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpNeq32)
+               v0 := b.NewValue0(v.Pos, OpConst32, t)
+               v0.AuxInt = int32ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
+       // match: (Less32 x (Const32 <t> [1]))
+       // cond: isNonNegative(x)
+       // result: (Eq32 (Const32 <t> [0]) x)
+       for {
+               x := v_0
+               if v_1.Op != OpConst32 {
+                       break
+               }
+               t := v_1.Type
+               if auxIntToInt32(v_1.AuxInt) != 1 || !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpEq32)
+               v0 := b.NewValue0(v.Pos, OpConst32, t)
+               v0.AuxInt = int32ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
        return false
 }
 func rewriteValuegeneric_OpLess32F(v *Value) bool {
@@ -10019,6 +10283,7 @@ func rewriteValuegeneric_OpLess32U(v *Value) bool {
 func rewriteValuegeneric_OpLess64(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
+       b := v.Block
        // match: (Less64 (Const64 [c]) (Const64 [d]))
        // result: (ConstBool [c < d])
        for {
@@ -10034,6 +10299,45 @@ func rewriteValuegeneric_OpLess64(v *Value) bool {
                v.AuxInt = boolToAuxInt(c < d)
                return true
        }
+       // match: (Less64 (Const64 <t> [0]) x)
+       // cond: isNonNegative(x)
+       // result: (Neq64 (Const64 <t> [0]) x)
+       for {
+               if v_0.Op != OpConst64 {
+                       break
+               }
+               t := v_0.Type
+               if auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_1
+               if !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpNeq64)
+               v0 := b.NewValue0(v.Pos, OpConst64, t)
+               v0.AuxInt = int64ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
+       // match: (Less64 x (Const64 <t> [1]))
+       // cond: isNonNegative(x)
+       // result: (Eq64 (Const64 <t> [0]) x)
+       for {
+               x := v_0
+               if v_1.Op != OpConst64 {
+                       break
+               }
+               t := v_1.Type
+               if auxIntToInt64(v_1.AuxInt) != 1 || !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpEq64)
+               v0 := b.NewValue0(v.Pos, OpConst64, t)
+               v0.AuxInt = int64ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
        return false
 }
 func rewriteValuegeneric_OpLess64F(v *Value) bool {
@@ -10089,6 +10393,7 @@ func rewriteValuegeneric_OpLess64U(v *Value) bool {
 func rewriteValuegeneric_OpLess8(v *Value) bool {
        v_1 := v.Args[1]
        v_0 := v.Args[0]
+       b := v.Block
        // match: (Less8 (Const8 [c]) (Const8 [d]))
        // result: (ConstBool [c < d])
        for {
@@ -10104,6 +10409,45 @@ func rewriteValuegeneric_OpLess8(v *Value) bool {
                v.AuxInt = boolToAuxInt(c < d)
                return true
        }
+       // match: (Less8 (Const8 <t> [0]) x)
+       // cond: isNonNegative(x)
+       // result: (Neq8 (Const8 <t> [0]) x)
+       for {
+               if v_0.Op != OpConst8 {
+                       break
+               }
+               t := v_0.Type
+               if auxIntToInt8(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_1
+               if !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpNeq8)
+               v0 := b.NewValue0(v.Pos, OpConst8, t)
+               v0.AuxInt = int8ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
+       // match: (Less8 x (Const8 <t> [1]))
+       // cond: isNonNegative(x)
+       // result: (Eq8 (Const8 <t> [0]) x)
+       for {
+               x := v_0
+               if v_1.Op != OpConst8 {
+                       break
+               }
+               t := v_1.Type
+               if auxIntToInt8(v_1.AuxInt) != 1 || !(isNonNegative(x)) {
+                       break
+               }
+               v.reset(OpEq8)
+               v0 := b.NewValue0(v.Pos, OpConst8, t)
+               v0.AuxInt = int8ToAuxInt(0)
+               v.AddArg2(v0, x)
+               return true
+       }
        return false
 }
 func rewriteValuegeneric_OpLess8U(v *Value) bool {
@@ -21402,6 +21746,7 @@ func rewriteValuegeneric_OpSqrt(v *Value) bool {
 }
 func rewriteValuegeneric_OpStaticLECall(v *Value) bool {
        b := v.Block
+       config := b.Func.Config
        typ := &b.Func.Config.Types
        // match: (StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [1]) mem)
        // cond: isSameCall(callAux, "runtime.memequal") && symIsRO(scon)
@@ -21436,6 +21781,105 @@ func rewriteValuegeneric_OpStaticLECall(v *Value) bool {
                v.AddArg2(v0, mem)
                return true
        }
+       // match: (StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [2]) mem)
+       // cond: isSameCall(callAux, "runtime.memequal") && symIsRO(scon) && canLoadUnaligned(config)
+       // result: (MakeResult (Eq16 (Load <typ.Int16> sptr mem) (Const16 <typ.Int16> [int16(read16(scon,0,config.ctxt.Arch.ByteOrder))])) mem)
+       for {
+               if len(v.Args) != 4 {
+                       break
+               }
+               callAux := auxToCall(v.Aux)
+               mem := v.Args[3]
+               sptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpAddr {
+                       break
+               }
+               scon := auxToSym(v_1.Aux)
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpSB {
+                       break
+               }
+               v_2 := v.Args[2]
+               if v_2.Op != OpConst64 || auxIntToInt64(v_2.AuxInt) != 2 || !(isSameCall(callAux, "runtime.memequal") && symIsRO(scon) && canLoadUnaligned(config)) {
+                       break
+               }
+               v.reset(OpMakeResult)
+               v0 := b.NewValue0(v.Pos, OpEq16, typ.Bool)
+               v1 := b.NewValue0(v.Pos, OpLoad, typ.Int16)
+               v1.AddArg2(sptr, mem)
+               v2 := b.NewValue0(v.Pos, OpConst16, typ.Int16)
+               v2.AuxInt = int16ToAuxInt(int16(read16(scon, 0, config.ctxt.Arch.ByteOrder)))
+               v0.AddArg2(v1, v2)
+               v.AddArg2(v0, mem)
+               return true
+       }
+       // match: (StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [4]) mem)
+       // cond: isSameCall(callAux, "runtime.memequal") && symIsRO(scon) && canLoadUnaligned(config)
+       // result: (MakeResult (Eq32 (Load <typ.Int32> sptr mem) (Const32 <typ.Int32> [int32(read32(scon,0,config.ctxt.Arch.ByteOrder))])) mem)
+       for {
+               if len(v.Args) != 4 {
+                       break
+               }
+               callAux := auxToCall(v.Aux)
+               mem := v.Args[3]
+               sptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpAddr {
+                       break
+               }
+               scon := auxToSym(v_1.Aux)
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpSB {
+                       break
+               }
+               v_2 := v.Args[2]
+               if v_2.Op != OpConst64 || auxIntToInt64(v_2.AuxInt) != 4 || !(isSameCall(callAux, "runtime.memequal") && symIsRO(scon) && canLoadUnaligned(config)) {
+                       break
+               }
+               v.reset(OpMakeResult)
+               v0 := b.NewValue0(v.Pos, OpEq32, typ.Bool)
+               v1 := b.NewValue0(v.Pos, OpLoad, typ.Int32)
+               v1.AddArg2(sptr, mem)
+               v2 := b.NewValue0(v.Pos, OpConst32, typ.Int32)
+               v2.AuxInt = int32ToAuxInt(int32(read32(scon, 0, config.ctxt.Arch.ByteOrder)))
+               v0.AddArg2(v1, v2)
+               v.AddArg2(v0, mem)
+               return true
+       }
+       // match: (StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [8]) mem)
+       // cond: isSameCall(callAux, "runtime.memequal") && symIsRO(scon) && canLoadUnaligned(config) && config.PtrSize == 8
+       // result: (MakeResult (Eq64 (Load <typ.Int64> sptr mem) (Const64 <typ.Int64> [int64(read64(scon,0,config.ctxt.Arch.ByteOrder))])) mem)
+       for {
+               if len(v.Args) != 4 {
+                       break
+               }
+               callAux := auxToCall(v.Aux)
+               mem := v.Args[3]
+               sptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpAddr {
+                       break
+               }
+               scon := auxToSym(v_1.Aux)
+               v_1_0 := v_1.Args[0]
+               if v_1_0.Op != OpSB {
+                       break
+               }
+               v_2 := v.Args[2]
+               if v_2.Op != OpConst64 || auxIntToInt64(v_2.AuxInt) != 8 || !(isSameCall(callAux, "runtime.memequal") && symIsRO(scon) && canLoadUnaligned(config) && config.PtrSize == 8) {
+                       break
+               }
+               v.reset(OpMakeResult)
+               v0 := b.NewValue0(v.Pos, OpEq64, typ.Bool)
+               v1 := b.NewValue0(v.Pos, OpLoad, typ.Int64)
+               v1.AddArg2(sptr, mem)
+               v2 := b.NewValue0(v.Pos, OpConst64, typ.Int64)
+               v2.AuxInt = int64ToAuxInt(int64(read64(scon, 0, config.ctxt.Arch.ByteOrder)))
+               v0.AddArg2(v1, v2)
+               v.AddArg2(v0, mem)
+               return true
+       }
        return false
 }
 func rewriteValuegeneric_OpStore(v *Value) bool {
@@ -22590,6 +23034,42 @@ func rewriteValuegeneric_OpSub16(v *Value) bool {
                }
                break
        }
+       // match: (Sub16 (Sub16 x y) x)
+       // result: (Neg16 y)
+       for {
+               if v_0.Op != OpSub16 {
+                       break
+               }
+               y := v_0.Args[1]
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpNeg16)
+               v.AddArg(y)
+               return true
+       }
+       // match: (Sub16 x (Add16 x y))
+       // result: (Neg16 y)
+       for {
+               x := v_0
+               if v_1.Op != OpAdd16 {
+                       break
+               }
+               _ = v_1.Args[1]
+               v_1_0 := v_1.Args[0]
+               v_1_1 := v_1.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
+                       if x != v_1_0 {
+                               continue
+                       }
+                       y := v_1_1
+                       v.reset(OpNeg16)
+                       v.AddArg(y)
+                       return true
+               }
+               break
+       }
        // match: (Sub16 x (Sub16 i:(Const16 <t>) z))
        // cond: (z.Op != OpConst16 && x.Op != OpConst16)
        // result: (Sub16 (Add16 <t> x z) i)
@@ -22869,6 +23349,42 @@ func rewriteValuegeneric_OpSub32(v *Value) bool {
                }
                break
        }
+       // match: (Sub32 (Sub32 x y) x)
+       // result: (Neg32 y)
+       for {
+               if v_0.Op != OpSub32 {
+                       break
+               }
+               y := v_0.Args[1]
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpNeg32)
+               v.AddArg(y)
+               return true
+       }
+       // match: (Sub32 x (Add32 x y))
+       // result: (Neg32 y)
+       for {
+               x := v_0
+               if v_1.Op != OpAdd32 {
+                       break
+               }
+               _ = v_1.Args[1]
+               v_1_0 := v_1.Args[0]
+               v_1_1 := v_1.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
+                       if x != v_1_0 {
+                               continue
+                       }
+                       y := v_1_1
+                       v.reset(OpNeg32)
+                       v.AddArg(y)
+                       return true
+               }
+               break
+       }
        // match: (Sub32 x (Sub32 i:(Const32 <t>) z))
        // cond: (z.Op != OpConst32 && x.Op != OpConst32)
        // result: (Sub32 (Add32 <t> x z) i)
@@ -23172,6 +23688,42 @@ func rewriteValuegeneric_OpSub64(v *Value) bool {
                }
                break
        }
+       // match: (Sub64 (Sub64 x y) x)
+       // result: (Neg64 y)
+       for {
+               if v_0.Op != OpSub64 {
+                       break
+               }
+               y := v_0.Args[1]
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpNeg64)
+               v.AddArg(y)
+               return true
+       }
+       // match: (Sub64 x (Add64 x y))
+       // result: (Neg64 y)
+       for {
+               x := v_0
+               if v_1.Op != OpAdd64 {
+                       break
+               }
+               _ = v_1.Args[1]
+               v_1_0 := v_1.Args[0]
+               v_1_1 := v_1.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
+                       if x != v_1_0 {
+                               continue
+                       }
+                       y := v_1_1
+                       v.reset(OpNeg64)
+                       v.AddArg(y)
+                       return true
+               }
+               break
+       }
        // match: (Sub64 x (Sub64 i:(Const64 <t>) z))
        // cond: (z.Op != OpConst64 && x.Op != OpConst64)
        // result: (Sub64 (Add64 <t> x z) i)
@@ -23475,6 +24027,42 @@ func rewriteValuegeneric_OpSub8(v *Value) bool {
                }
                break
        }
+       // match: (Sub8 (Sub8 x y) x)
+       // result: (Neg8 y)
+       for {
+               if v_0.Op != OpSub8 {
+                       break
+               }
+               y := v_0.Args[1]
+               x := v_0.Args[0]
+               if x != v_1 {
+                       break
+               }
+               v.reset(OpNeg8)
+               v.AddArg(y)
+               return true
+       }
+       // match: (Sub8 x (Add8 x y))
+       // result: (Neg8 y)
+       for {
+               x := v_0
+               if v_1.Op != OpAdd8 {
+                       break
+               }
+               _ = v_1.Args[1]
+               v_1_0 := v_1.Args[0]
+               v_1_1 := v_1.Args[1]
+               for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 {
+                       if x != v_1_0 {
+                               continue
+                       }
+                       y := v_1_1
+                       v.reset(OpNeg8)
+                       v.AddArg(y)
+                       return true
+               }
+               break
+       }
        // match: (Sub8 x (Sub8 i:(Const8 <t>) z))
        // cond: (z.Op != OpConst8 && x.Op != OpConst8)
        // result: (Sub8 (Add8 <t> x z) i)
index 29abf3c591f902748ef2affd7869d8636e053d12..c0b9eacf4174d8bbb80784d7fb026a87e0bc9835 100644 (file)
@@ -196,11 +196,7 @@ func shortcircuitBlock(b *Block) bool {
 
        // Remove b's incoming edge from p.
        b.removePred(cidx)
-       n := len(b.Preds)
-       ctl.Args[cidx].Uses--
-       ctl.Args[cidx] = ctl.Args[n]
-       ctl.Args[n] = nil
-       ctl.Args = ctl.Args[:n]
+       b.removePhiArg(ctl, cidx)
 
        // Redirect p's outgoing edge to t.
        p.Succs[pi] = Edge{t, len(t.Preds)}
index a510d0b3d0607c268d76b444790ed7744bd1a802..90dd261c557fec7d5603cd7b3d3c5520f9382a19 100644 (file)
@@ -2,6 +2,7 @@ package ssa_test
 
 import (
        cmddwarf "cmd/internal/dwarf"
+       "cmd/internal/quoted"
        "debug/dwarf"
        "debug/elf"
        "debug/macho"
@@ -57,7 +58,11 @@ func TestStmtLines(t *testing.T) {
                if extld == "" {
                        extld = "gcc"
                }
-               enabled, err := cmddwarf.IsDWARFEnabledOnAIXLd(extld)
+               extldArgs, err := quoted.Split(extld)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               enabled, err := cmddwarf.IsDWARFEnabledOnAIXLd(extldArgs)
                if err != nil {
                        t.Fatal(err)
                }
diff --git a/src/cmd/compile/internal/ssa/testdata/inline-dump.go b/src/cmd/compile/internal/ssa/testdata/inline-dump.go
new file mode 100644 (file)
index 0000000..97893b6
--- /dev/null
@@ -0,0 +1,17 @@
+package foo
+
+func f(m, n int) int {
+       a := g(n)
+       b := g(m)
+       return a + b
+}
+
+func g(x int) int {
+       y := h(x + 1)
+       z := h(x - 1)
+       return y + z
+}
+
+func h(x int) int {
+       return x * x
+}
diff --git a/src/cmd/compile/internal/ssa/testdata/sayhi.go b/src/cmd/compile/internal/ssa/testdata/sayhi.go
new file mode 100644 (file)
index 0000000..680e1eb
--- /dev/null
@@ -0,0 +1,12 @@
+package foo
+
+import (
+       "fmt"
+       "sync"
+)
+
+func sayhi(n int, wg *sync.WaitGroup) {
+       fmt.Println("hi", n)
+       fmt.Println("hi", n)
+       wg.Done()
+}
index 630e4814b99f1b38c182d684bb2b6c16f30de704..7b411a46124130b6fea4d5e04d53bd931b21c031 100644 (file)
@@ -302,12 +302,6 @@ func (v *Value) SetArg(i int, w *Value) {
        v.Args[i] = w
        w.Uses++
 }
-func (v *Value) RemoveArg(i int) {
-       v.Args[i].Uses--
-       copy(v.Args[i:], v.Args[i+1:])
-       v.Args[len(v.Args)-1] = nil // aid GC
-       v.Args = v.Args[:len(v.Args)-1]
-}
 func (v *Value) SetArgs1(a *Value) {
        v.resetArgs()
        v.AddArg(a)
@@ -351,11 +345,13 @@ func (v *Value) reset(op Op) {
 // invalidateRecursively marks a value as invalid (unused)
 // and after decrementing reference counts on its Args,
 // also recursively invalidates any of those whose use
-// count goes to zero.
+// count goes to zero.  It returns whether any of the
+// invalidated values was marked with IsStmt.
 //
 // BEWARE of doing this *before* you've applied intended
 // updates to SSA.
-func (v *Value) invalidateRecursively() {
+func (v *Value) invalidateRecursively() bool {
+       lostStmt := v.Pos.IsStmt() == src.PosIsStmt
        if v.InCache {
                v.Block.Func.unCache(v)
        }
@@ -364,7 +360,8 @@ func (v *Value) invalidateRecursively() {
        for _, a := range v.Args {
                a.Uses--
                if a.Uses == 0 {
-                       a.invalidateRecursively()
+                       lost := a.invalidateRecursively()
+                       lostStmt = lost || lostStmt
                }
        }
 
@@ -375,6 +372,7 @@ func (v *Value) invalidateRecursively() {
 
        v.AuxInt = 0
        v.Aux = nil
+       return lostStmt
 }
 
 // copyOf is called from rewrite rules.
index 419d91d0d367e609dcf9874cced1a58c04acdb4a..5120cd1086ac6088b54636180a6f44364d4dc550 100644 (file)
@@ -544,7 +544,7 @@ func IsStackAddr(v *Value) bool {
                v = v.Args[0]
        }
        switch v.Op {
-       case OpSP, OpLocalAddr, OpSelectNAddr:
+       case OpSP, OpLocalAddr, OpSelectNAddr, OpGetCallerSP:
                return true
        }
        return false
@@ -552,6 +552,9 @@ func IsStackAddr(v *Value) bool {
 
 // IsGlobalAddr reports whether v is known to be an address of a global (or nil).
 func IsGlobalAddr(v *Value) bool {
+       for v.Op == OpOffPtr || v.Op == OpAddPtr || v.Op == OpPtrIndex || v.Op == OpCopy {
+               v = v.Args[0]
+       }
        if v.Op == OpAddr && v.Args[0].Op == OpSB {
                return true // address of a global
        }
@@ -647,7 +650,7 @@ func IsSanitizerSafeAddr(v *Value) bool {
                // read-only once initialized.
                return true
        case OpAddr:
-               return v.Aux.(*obj.LSym).Type == objabi.SRODATA
+               return v.Aux.(*obj.LSym).Type == objabi.SRODATA || v.Aux.(*obj.LSym).Type == objabi.SLIBFUZZER_EXTRA_COUNTER
        }
        return false
 }
index 6d8c53e7225fd93893852a1348171be89cc1d7f2..3a653e46b4b542c744feaf90b780e78cafee76b1 100644 (file)
@@ -218,8 +218,6 @@ func (s *SymABIs) GenABIWrappers() {
                }
 
                if !buildcfg.Experiment.RegabiWrappers {
-                       // We'll generate ABI aliases instead of
-                       // wrappers once we have LSyms in InitLSym.
                        continue
                }
 
@@ -251,16 +249,11 @@ func InitLSym(f *ir.Func, hasBody bool) {
                        // the funcsym for either the defining
                        // function or its wrapper as appropriate.
                        //
-                       // If we're using ABI aliases instead of
-                       // wrappers, we only InitLSym for the defining
-                       // ABI of a function, so we make the funcsym
-                       // when we see that.
+                       // If we're not using ABI wrappers, we only
+                       // InitLSym for the defining ABI of a function,
+                       // so we make the funcsym when we see that.
                        staticdata.NeedFuncSym(f)
                }
-               if !buildcfg.Experiment.RegabiWrappers {
-                       // Create ABI aliases instead of wrappers.
-                       forEachWrapperABI(f, makeABIAlias)
-               }
        }
        if hasBody {
                setupTextLSym(f, 0)
@@ -281,22 +274,6 @@ func forEachWrapperABI(fn *ir.Func, cb func(fn *ir.Func, wrapperABI obj.ABI)) {
        }
 }
 
-// makeABIAlias creates a new ABI alias so calls to f via wrapperABI
-// will be resolved directly to f's ABI by the linker.
-func makeABIAlias(f *ir.Func, wrapperABI obj.ABI) {
-       // These LSyms have the same name as the native function, so
-       // we create them directly rather than looking them up.
-       // The uniqueness of f.lsym ensures uniqueness of asym.
-       asym := &obj.LSym{
-               Name: f.LSym.Name,
-               Type: objabi.SABIALIAS,
-               R:    []obj.Reloc{{Sym: f.LSym}}, // 0 size, so "informational"
-       }
-       asym.SetABI(wrapperABI)
-       asym.Set(obj.AttrDuplicateOK, true)
-       base.Ctxt.ABIAliases = append(base.Ctxt.ABIAliases, asym)
-}
-
 // makeABIWrapper creates a new function that will be called with
 // wrapperABI and calls "f" using f.ABI.
 func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
@@ -382,18 +359,16 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
        }
 
        var tail ir.Node
+       call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
+       call.Args = ir.ParamNames(tfn.Type())
+       call.IsDDD = tfn.Type().IsVariadic()
+       tail = call
        if tailcall {
-               tail = ir.NewTailCallStmt(base.Pos, f.Nname)
-       } else {
-               call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
-               call.Args = ir.ParamNames(tfn.Type())
-               call.IsDDD = tfn.Type().IsVariadic()
-               tail = call
-               if tfn.Type().NumResults() > 0 {
-                       n := ir.NewReturnStmt(base.Pos, nil)
-                       n.Results = []ir.Node{call}
-                       tail = n
-               }
+               tail = ir.NewTailCallStmt(base.Pos, call)
+       } else if tfn.Type().NumResults() > 0 {
+               n := ir.NewReturnStmt(base.Pos, nil)
+               n.Results = []ir.Node{call}
+               tail = n
        }
        fn.Body.Append(tail)
 
index 93157bfa11b56a93592ce93dc9f0bf621b307782..86d40e239d67a11816fc109bd90ab1504fa72e66 100644 (file)
@@ -57,8 +57,8 @@ func cmpstackvarlt(a, b *ir.Name) bool {
                return ap
        }
 
-       if a.Type().Width != b.Type().Width {
-               return a.Type().Width > b.Type().Width
+       if a.Type().Size() != b.Type().Size() {
+               return a.Type().Size() > b.Type().Size()
        }
 
        return a.Sym().Name < b.Sym().Name
@@ -75,7 +75,22 @@ func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 // allocate space. In particular, it excludes arguments and results, which are in
 // the callers frame.
 func needAlloc(n *ir.Name) bool {
-       return n.Class == ir.PAUTO || n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters()
+       if n.Op() != ir.ONAME {
+               base.FatalfAt(n.Pos(), "%v has unexpected Op %v", n, n.Op())
+       }
+
+       switch n.Class {
+       case ir.PAUTO:
+               return true
+       case ir.PPARAM:
+               return false
+       case ir.PPARAMOUT:
+               return n.IsOutputParamInRegisters()
+
+       default:
+               base.FatalfAt(n.Pos(), "%v has unexpected Class %v", n, n.Class)
+               return false
+       }
 }
 
 func (s *ssafn) AllocFrame(f *ssa.Func) {
@@ -132,7 +147,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
                }
 
                types.CalcSize(n.Type())
-               w := n.Type().Width
+               w := n.Type().Size()
                if w >= types.MaxWidth || w < 0 {
                        base.Fatalf("bad width")
                }
@@ -144,7 +159,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
                        w = 1
                }
                s.stksize += w
-               s.stksize = types.Rnd(s.stksize, int64(n.Type().Align))
+               s.stksize = types.Rnd(s.stksize, n.Type().Alignment())
                if n.Type().HasPointers() {
                        s.stkptrsize = s.stksize
                        lastHasPtr = true
diff --git a/src/cmd/compile/internal/ssagen/pgen_test.go b/src/cmd/compile/internal/ssagen/pgen_test.go
deleted file mode 100644 (file)
index 69ed8ad..0000000
+++ /dev/null
@@ -1,209 +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.
-
-package ssagen
-
-import (
-       "reflect"
-       "sort"
-       "testing"
-
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
-       "cmd/internal/src"
-)
-
-func typeWithoutPointers() *types.Type {
-       return types.NewStruct(types.NoPkg, []*types.Field{
-               types.NewField(src.NoXPos, nil, types.New(types.TINT)),
-       })
-}
-
-func typeWithPointers() *types.Type {
-       return types.NewStruct(types.NoPkg, []*types.Field{
-               types.NewField(src.NoXPos, nil, types.NewPtr(types.New(types.TINT))),
-       })
-}
-
-func markUsed(n *ir.Name) *ir.Name {
-       n.SetUsed(true)
-       return n
-}
-
-func markNeedZero(n *ir.Name) *ir.Name {
-       n.SetNeedzero(true)
-       return n
-}
-
-// Test all code paths for cmpstackvarlt.
-func TestCmpstackvar(t *testing.T) {
-       nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
-               if s == nil {
-                       s = &types.Sym{Name: "."}
-               }
-               n := typecheck.NewName(s)
-               n.SetType(t)
-               n.SetFrameOffset(xoffset)
-               n.Class = cl
-               return n
-       }
-       testdata := []struct {
-               a, b *ir.Name
-               lt   bool
-       }{
-               {
-                       nod(0, nil, nil, ir.PAUTO),
-                       nod(0, nil, nil, ir.PFUNC),
-                       false,
-               },
-               {
-                       nod(0, nil, nil, ir.PFUNC),
-                       nod(0, nil, nil, ir.PAUTO),
-                       true,
-               },
-               {
-                       nod(0, nil, nil, ir.PFUNC),
-                       nod(10, nil, nil, ir.PFUNC),
-                       true,
-               },
-               {
-                       nod(20, nil, nil, ir.PFUNC),
-                       nod(10, nil, nil, ir.PFUNC),
-                       false,
-               },
-               {
-                       nod(10, nil, nil, ir.PFUNC),
-                       nod(10, nil, nil, ir.PFUNC),
-                       false,
-               },
-               {
-                       nod(10, nil, nil, ir.PPARAM),
-                       nod(20, nil, nil, ir.PPARAMOUT),
-                       true,
-               },
-               {
-                       nod(10, nil, nil, ir.PPARAMOUT),
-                       nod(20, nil, nil, ir.PPARAM),
-                       true,
-               },
-               {
-                       markUsed(nod(0, nil, nil, ir.PAUTO)),
-                       nod(0, nil, nil, ir.PAUTO),
-                       true,
-               },
-               {
-                       nod(0, nil, nil, ir.PAUTO),
-                       markUsed(nod(0, nil, nil, ir.PAUTO)),
-                       false,
-               },
-               {
-                       nod(0, typeWithoutPointers(), nil, ir.PAUTO),
-                       nod(0, typeWithPointers(), nil, ir.PAUTO),
-                       false,
-               },
-               {
-                       nod(0, typeWithPointers(), nil, ir.PAUTO),
-                       nod(0, typeWithoutPointers(), nil, ir.PAUTO),
-                       true,
-               },
-               {
-                       markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
-                       nod(0, &types.Type{}, nil, ir.PAUTO),
-                       true,
-               },
-               {
-                       nod(0, &types.Type{}, nil, ir.PAUTO),
-                       markNeedZero(nod(0, &types.Type{}, nil, ir.PAUTO)),
-                       false,
-               },
-               {
-                       nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
-                       nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
-                       false,
-               },
-               {
-                       nod(0, &types.Type{Width: 2}, nil, ir.PAUTO),
-                       nod(0, &types.Type{Width: 1}, nil, ir.PAUTO),
-                       true,
-               },
-               {
-                       nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-                       nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-                       true,
-               },
-               {
-                       nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-                       nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-                       false,
-               },
-               {
-                       nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-                       nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-                       false,
-               },
-       }
-       for _, d := range testdata {
-               got := cmpstackvarlt(d.a, d.b)
-               if got != d.lt {
-                       t.Errorf("want %v < %v", d.a, d.b)
-               }
-               // If we expect a < b to be true, check that b < a is false.
-               if d.lt && cmpstackvarlt(d.b, d.a) {
-                       t.Errorf("unexpected %v < %v", d.b, d.a)
-               }
-       }
-}
-
-func TestStackvarSort(t *testing.T) {
-       nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
-               n := typecheck.NewName(s)
-               n.SetType(t)
-               n.SetFrameOffset(xoffset)
-               n.Class = cl
-               return n
-       }
-       inp := []*ir.Name{
-               nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-               nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-               markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-               nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-       }
-       want := []*ir.Name{
-               nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               nod(20, &types.Type{}, &types.Sym{}, ir.PFUNC),
-               markUsed(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-               markNeedZero(nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO)),
-               nod(0, &types.Type{Width: 2}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{Width: 1}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
-               nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
-               nod(0, typeWithoutPointers(), &types.Sym{}, ir.PAUTO),
-       }
-       sort.Sort(byStackVar(inp))
-       if !reflect.DeepEqual(want, inp) {
-               t.Error("sort failed")
-               for i := range inp {
-                       g := inp[i]
-                       w := want[i]
-                       eq := reflect.DeepEqual(w, g)
-                       if !eq {
-                               t.Log(i, w, g)
-                       }
-               }
-       }
-}
index b0f2585e3ab5abf6c70fba31bb74debbfeef925e..b84199790f9f5f70d19a20fca95a3b5284c87a37 100644 (file)
@@ -96,6 +96,7 @@ func InitConfig() {
        ir.Syms.AssertE2I2 = typecheck.LookupRuntimeFunc("assertE2I2")
        ir.Syms.AssertI2I = typecheck.LookupRuntimeFunc("assertI2I")
        ir.Syms.AssertI2I2 = typecheck.LookupRuntimeFunc("assertI2I2")
+       ir.Syms.CheckPtrAlignment = typecheck.LookupRuntimeFunc("checkptrAlignment")
        ir.Syms.Deferproc = typecheck.LookupRuntimeFunc("deferproc")
        ir.Syms.DeferprocStack = typecheck.LookupRuntimeFunc("deferprocStack")
        ir.Syms.Deferreturn = typecheck.LookupRuntimeFunc("deferreturn")
@@ -107,6 +108,8 @@ func InitConfig() {
        ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread")
        ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite")
        ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove")
+       ir.Syms.Asanread = typecheck.LookupRuntimeFunc("asanread")
+       ir.Syms.Asanwrite = typecheck.LookupRuntimeFunc("asanwrite")
        ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject")
        ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc")
        ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide")
@@ -317,6 +320,7 @@ func dvarint(x *obj.LSym, off int, v int64) int {
 //    - Offset of the closure value to call
 func (s *state) emitOpenDeferInfo() {
        x := base.Ctxt.Lookup(s.curfn.LSym.Name + ".opendefer")
+       x.Set(obj.AttrContentAddressable, true)
        s.curfn.LSym.Func().OpenCodedDeferInfo = x
        off := 0
        off = dvarint(x, off, -s.deferBitsTemp.FrameOffset())
@@ -366,6 +370,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
        if fn.Pragma&ir.CgoUnsafeArgs != 0 {
                s.cgoUnsafeArgs = true
        }
+       s.checkPtrEnabled = ir.ShouldCheckPtr(fn, 1)
 
        fe := ssafn{
                curfn: fn,
@@ -709,6 +714,31 @@ func (s *state) newObject(typ *types.Type) *ssa.Value {
        return s.rtcall(ir.Syms.Newobject, true, []*types.Type{types.NewPtr(typ)}, s.reflectType(typ))[0]
 }
 
+func (s *state) checkPtrAlignment(n *ir.ConvExpr, v *ssa.Value, count *ssa.Value) {
+       if !n.Type().IsPtr() {
+               s.Fatalf("expected pointer type: %v", n.Type())
+       }
+       elem := n.Type().Elem()
+       if count != nil {
+               if !elem.IsArray() {
+                       s.Fatalf("expected array type: %v", elem)
+               }
+               elem = elem.Elem()
+       }
+       size := elem.Size()
+       // Casting from larger type to smaller one is ok, so for smallest type, do nothing.
+       if elem.Alignment() == 1 && (size == 0 || size == 1 || count == nil) {
+               return
+       }
+       if count == nil {
+               count = s.constInt(types.Types[types.TUINTPTR], 1)
+       }
+       if count.Type.Size() != s.config.PtrSize {
+               s.Fatalf("expected count fit to an uintptr size, have: %d, want: %d", count.Type.Size(), s.config.PtrSize)
+       }
+       s.rtcall(ir.Syms.CheckPtrAlignment, true, nil, v, s.reflectType(elem), count)
+}
+
 // reflectType returns an SSA value representing a pointer to typ's
 // reflection type descriptor.
 func (s *state) reflectType(typ *types.Type) *ssa.Value {
@@ -861,10 +891,11 @@ type state struct {
        // Used to deduplicate panic calls.
        panics map[funcLine]*ssa.Block
 
-       cgoUnsafeArgs bool
-       hasdefer      bool // whether the function contains a defer statement
-       softFloat     bool
-       hasOpenDefers bool // whether we are doing open-coded defers
+       cgoUnsafeArgs   bool
+       hasdefer        bool // whether the function contains a defer statement
+       softFloat       bool
+       hasOpenDefers   bool // whether we are doing open-coded defers
+       checkPtrEnabled bool // whether to insert checkptr instrumentation
 
        // If doing open-coded defers, list of info about the defer calls in
        // scanning order. Hence, at exit we should run these defers in reverse
@@ -1216,10 +1247,10 @@ func (s *state) instrument(t *types.Type, addr *ssa.Value, kind instrumentKind)
 }
 
 // instrumentFields instruments a read/write operation on addr.
-// If it is instrumenting for MSAN and t is a struct type, it instruments
+// If it is instrumenting for MSAN or ASAN and t is a struct type, it instruments
 // operation for each field, instead of for the whole struct.
 func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrumentKind) {
-       if !base.Flag.MSan || !t.IsStruct() {
+       if !(base.Flag.MSan || base.Flag.ASan) || !t.IsStruct() {
                s.instrument(t, addr, kind)
                return
        }
@@ -1298,6 +1329,16 @@ func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrume
                default:
                        panic("unreachable")
                }
+       } else if base.Flag.ASan {
+               switch kind {
+               case instrumentRead:
+                       fn = ir.Syms.Asanread
+               case instrumentWrite:
+                       fn = ir.Syms.Asanwrite
+               default:
+                       panic("unreachable")
+               }
+               needWidth = true
        } else {
                panic("unreachable")
        }
@@ -1668,9 +1709,11 @@ func (s *state) stmt(n ir.Node) {
 
        case ir.OTAILCALL:
                n := n.(*ir.TailCallStmt)
-               b := s.exit()
-               b.Kind = ssa.BlockRetJmp // override BlockRet
-               b.Aux = callTargetLSym(n.Target)
+               s.callResult(n.Call, callTail)
+               call := s.mem()
+               b := s.endBlock()
+               b.Kind = ssa.BlockRetJmp // could use BlockExit. BlockRetJmp is mostly for clarity.
+               b.SetControl(call)
 
        case ir.OCONTINUE, ir.OBREAK:
                n := n.(*ir.BranchStmt)
@@ -2323,8 +2366,181 @@ func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssa.Op {
        return x
 }
 
+func (s *state) conv(n ir.Node, v *ssa.Value, ft, tt *types.Type) *ssa.Value {
+       if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
+               // Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
+               return s.newValue1(ssa.OpCopy, tt, v)
+       }
+       if ft.IsInteger() && tt.IsInteger() {
+               var op ssa.Op
+               if tt.Size() == ft.Size() {
+                       op = ssa.OpCopy
+               } else if tt.Size() < ft.Size() {
+                       // truncation
+                       switch 10*ft.Size() + tt.Size() {
+                       case 21:
+                               op = ssa.OpTrunc16to8
+                       case 41:
+                               op = ssa.OpTrunc32to8
+                       case 42:
+                               op = ssa.OpTrunc32to16
+                       case 81:
+                               op = ssa.OpTrunc64to8
+                       case 82:
+                               op = ssa.OpTrunc64to16
+                       case 84:
+                               op = ssa.OpTrunc64to32
+                       default:
+                               s.Fatalf("weird integer truncation %v -> %v", ft, tt)
+                       }
+               } else if ft.IsSigned() {
+                       // sign extension
+                       switch 10*ft.Size() + tt.Size() {
+                       case 12:
+                               op = ssa.OpSignExt8to16
+                       case 14:
+                               op = ssa.OpSignExt8to32
+                       case 18:
+                               op = ssa.OpSignExt8to64
+                       case 24:
+                               op = ssa.OpSignExt16to32
+                       case 28:
+                               op = ssa.OpSignExt16to64
+                       case 48:
+                               op = ssa.OpSignExt32to64
+                       default:
+                               s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
+                       }
+               } else {
+                       // zero extension
+                       switch 10*ft.Size() + tt.Size() {
+                       case 12:
+                               op = ssa.OpZeroExt8to16
+                       case 14:
+                               op = ssa.OpZeroExt8to32
+                       case 18:
+                               op = ssa.OpZeroExt8to64
+                       case 24:
+                               op = ssa.OpZeroExt16to32
+                       case 28:
+                               op = ssa.OpZeroExt16to64
+                       case 48:
+                               op = ssa.OpZeroExt32to64
+                       default:
+                               s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
+                       }
+               }
+               return s.newValue1(op, tt, v)
+       }
+
+       if ft.IsFloat() || tt.IsFloat() {
+               conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
+               if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
+                       if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
+                               conv = conv1
+                       }
+               }
+               if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
+                       if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
+                               conv = conv1
+                       }
+               }
+
+               if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
+                       if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
+                               // tt is float32 or float64, and ft is also unsigned
+                               if tt.Size() == 4 {
+                                       return s.uint32Tofloat32(n, v, ft, tt)
+                               }
+                               if tt.Size() == 8 {
+                                       return s.uint32Tofloat64(n, v, ft, tt)
+                               }
+                       } else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
+                               // ft is float32 or float64, and tt is unsigned integer
+                               if ft.Size() == 4 {
+                                       return s.float32ToUint32(n, v, ft, tt)
+                               }
+                               if ft.Size() == 8 {
+                                       return s.float64ToUint32(n, v, ft, tt)
+                               }
+                       }
+               }
+
+               if !ok {
+                       s.Fatalf("weird float conversion %v -> %v", ft, tt)
+               }
+               op1, op2, it := conv.op1, conv.op2, conv.intermediateType
+
+               if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
+                       // normal case, not tripping over unsigned 64
+                       if op1 == ssa.OpCopy {
+                               if op2 == ssa.OpCopy {
+                                       return v
+                               }
+                               return s.newValueOrSfCall1(op2, tt, v)
+                       }
+                       if op2 == ssa.OpCopy {
+                               return s.newValueOrSfCall1(op1, tt, v)
+                       }
+                       return s.newValueOrSfCall1(op2, tt, s.newValueOrSfCall1(op1, types.Types[it], v))
+               }
+               // Tricky 64-bit unsigned cases.
+               if ft.IsInteger() {
+                       // tt is float32 or float64, and ft is also unsigned
+                       if tt.Size() == 4 {
+                               return s.uint64Tofloat32(n, v, ft, tt)
+                       }
+                       if tt.Size() == 8 {
+                               return s.uint64Tofloat64(n, v, ft, tt)
+                       }
+                       s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
+               }
+               // ft is float32 or float64, and tt is unsigned integer
+               if ft.Size() == 4 {
+                       return s.float32ToUint64(n, v, ft, tt)
+               }
+               if ft.Size() == 8 {
+                       return s.float64ToUint64(n, v, ft, tt)
+               }
+               s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
+               return nil
+       }
+
+       if ft.IsComplex() && tt.IsComplex() {
+               var op ssa.Op
+               if ft.Size() == tt.Size() {
+                       switch ft.Size() {
+                       case 8:
+                               op = ssa.OpRound32F
+                       case 16:
+                               op = ssa.OpRound64F
+                       default:
+                               s.Fatalf("weird complex conversion %v -> %v", ft, tt)
+                       }
+               } else if ft.Size() == 8 && tt.Size() == 16 {
+                       op = ssa.OpCvt32Fto64F
+               } else if ft.Size() == 16 && tt.Size() == 8 {
+                       op = ssa.OpCvt64Fto32F
+               } else {
+                       s.Fatalf("weird complex conversion %v -> %v", ft, tt)
+               }
+               ftp := types.FloatForComplex(ft)
+               ttp := types.FloatForComplex(tt)
+               return s.newValue2(ssa.OpComplexMake, tt,
+                       s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, v)),
+                       s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, v)))
+       }
+
+       s.Fatalf("unhandled OCONV %s -> %s", ft.Kind(), tt.Kind())
+       return nil
+}
+
 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
 func (s *state) expr(n ir.Node) *ssa.Value {
+       return s.exprCheckPtr(n, true)
+}
+
+func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
        if ir.HasUniquePos(n) {
                // ONAMEs and named OLITERALs have the line number
                // of the decl, not the use. See issue 14742.
@@ -2472,6 +2688,9 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 
                // unsafe.Pointer <--> *T
                if to.IsUnsafePtr() && from.IsPtrShaped() || from.IsUnsafePtr() && to.IsPtrShaped() {
+                       if s.checkPtrEnabled && checkPtrOK && to.IsPtr() && from.IsUnsafePtr() {
+                               s.checkPtrAlignment(n, v, nil)
+                       }
                        return v
                }
 
@@ -2483,8 +2702,8 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 
                types.CalcSize(from)
                types.CalcSize(to)
-               if from.Width != to.Width {
-                       s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
+               if from.Size() != to.Size() {
+                       s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Size(), to, to.Size())
                        return nil
                }
                if etypesign(from.Kind()) != etypesign(to.Kind()) {
@@ -2510,174 +2729,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
        case ir.OCONV:
                n := n.(*ir.ConvExpr)
                x := s.expr(n.X)
-               ft := n.X.Type() // from type
-               tt := n.Type()   // to type
-               if ft.IsBoolean() && tt.IsKind(types.TUINT8) {
-                       // Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
-                       return s.newValue1(ssa.OpCopy, n.Type(), x)
-               }
-               if ft.IsInteger() && tt.IsInteger() {
-                       var op ssa.Op
-                       if tt.Size() == ft.Size() {
-                               op = ssa.OpCopy
-                       } else if tt.Size() < ft.Size() {
-                               // truncation
-                               switch 10*ft.Size() + tt.Size() {
-                               case 21:
-                                       op = ssa.OpTrunc16to8
-                               case 41:
-                                       op = ssa.OpTrunc32to8
-                               case 42:
-                                       op = ssa.OpTrunc32to16
-                               case 81:
-                                       op = ssa.OpTrunc64to8
-                               case 82:
-                                       op = ssa.OpTrunc64to16
-                               case 84:
-                                       op = ssa.OpTrunc64to32
-                               default:
-                                       s.Fatalf("weird integer truncation %v -> %v", ft, tt)
-                               }
-                       } else if ft.IsSigned() {
-                               // sign extension
-                               switch 10*ft.Size() + tt.Size() {
-                               case 12:
-                                       op = ssa.OpSignExt8to16
-                               case 14:
-                                       op = ssa.OpSignExt8to32
-                               case 18:
-                                       op = ssa.OpSignExt8to64
-                               case 24:
-                                       op = ssa.OpSignExt16to32
-                               case 28:
-                                       op = ssa.OpSignExt16to64
-                               case 48:
-                                       op = ssa.OpSignExt32to64
-                               default:
-                                       s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
-                               }
-                       } else {
-                               // zero extension
-                               switch 10*ft.Size() + tt.Size() {
-                               case 12:
-                                       op = ssa.OpZeroExt8to16
-                               case 14:
-                                       op = ssa.OpZeroExt8to32
-                               case 18:
-                                       op = ssa.OpZeroExt8to64
-                               case 24:
-                                       op = ssa.OpZeroExt16to32
-                               case 28:
-                                       op = ssa.OpZeroExt16to64
-                               case 48:
-                                       op = ssa.OpZeroExt32to64
-                               default:
-                                       s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
-                               }
-                       }
-                       return s.newValue1(op, n.Type(), x)
-               }
-
-               if ft.IsFloat() || tt.IsFloat() {
-                       conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
-                       if s.config.RegSize == 4 && Arch.LinkArch.Family != sys.MIPS && !s.softFloat {
-                               if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
-                                       conv = conv1
-                               }
-                       }
-                       if Arch.LinkArch.Family == sys.ARM64 || Arch.LinkArch.Family == sys.Wasm || Arch.LinkArch.Family == sys.S390X || s.softFloat {
-                               if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
-                                       conv = conv1
-                               }
-                       }
-
-                       if Arch.LinkArch.Family == sys.MIPS && !s.softFloat {
-                               if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() {
-                                       // tt is float32 or float64, and ft is also unsigned
-                                       if tt.Size() == 4 {
-                                               return s.uint32Tofloat32(n, x, ft, tt)
-                                       }
-                                       if tt.Size() == 8 {
-                                               return s.uint32Tofloat64(n, x, ft, tt)
-                                       }
-                               } else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
-                                       // ft is float32 or float64, and tt is unsigned integer
-                                       if ft.Size() == 4 {
-                                               return s.float32ToUint32(n, x, ft, tt)
-                                       }
-                                       if ft.Size() == 8 {
-                                               return s.float64ToUint32(n, x, ft, tt)
-                                       }
-                               }
-                       }
-
-                       if !ok {
-                               s.Fatalf("weird float conversion %v -> %v", ft, tt)
-                       }
-                       op1, op2, it := conv.op1, conv.op2, conv.intermediateType
-
-                       if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
-                               // normal case, not tripping over unsigned 64
-                               if op1 == ssa.OpCopy {
-                                       if op2 == ssa.OpCopy {
-                                               return x
-                                       }
-                                       return s.newValueOrSfCall1(op2, n.Type(), x)
-                               }
-                               if op2 == ssa.OpCopy {
-                                       return s.newValueOrSfCall1(op1, n.Type(), x)
-                               }
-                               return s.newValueOrSfCall1(op2, n.Type(), s.newValueOrSfCall1(op1, types.Types[it], x))
-                       }
-                       // Tricky 64-bit unsigned cases.
-                       if ft.IsInteger() {
-                               // tt is float32 or float64, and ft is also unsigned
-                               if tt.Size() == 4 {
-                                       return s.uint64Tofloat32(n, x, ft, tt)
-                               }
-                               if tt.Size() == 8 {
-                                       return s.uint64Tofloat64(n, x, ft, tt)
-                               }
-                               s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
-                       }
-                       // ft is float32 or float64, and tt is unsigned integer
-                       if ft.Size() == 4 {
-                               return s.float32ToUint64(n, x, ft, tt)
-                       }
-                       if ft.Size() == 8 {
-                               return s.float64ToUint64(n, x, ft, tt)
-                       }
-                       s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
-                       return nil
-               }
-
-               if ft.IsComplex() && tt.IsComplex() {
-                       var op ssa.Op
-                       if ft.Size() == tt.Size() {
-                               switch ft.Size() {
-                               case 8:
-                                       op = ssa.OpRound32F
-                               case 16:
-                                       op = ssa.OpRound64F
-                               default:
-                                       s.Fatalf("weird complex conversion %v -> %v", ft, tt)
-                               }
-                       } else if ft.Size() == 8 && tt.Size() == 16 {
-                               op = ssa.OpCvt32Fto64F
-                       } else if ft.Size() == 16 && tt.Size() == 8 {
-                               op = ssa.OpCvt64Fto32F
-                       } else {
-                               s.Fatalf("weird complex conversion %v -> %v", ft, tt)
-                       }
-                       ftp := types.FloatForComplex(ft)
-                       ttp := types.FloatForComplex(tt)
-                       return s.newValue2(ssa.OpComplexMake, tt,
-                               s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
-                               s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
-               }
-
-               s.Fatalf("unhandled OCONV %s -> %s", n.X.Type().Kind(), n.Type().Kind())
-               return nil
+               return s.conv(n, x, n.X.Type(), n.Type())
 
        case ir.ODOTTYPE:
                n := n.(*ir.TypeAssertExpr)
@@ -2962,7 +3014,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                }
                // If n is addressable and can't be represented in
                // SSA, then load just the selected field. This
-               // prevents false memory dependencies in race/msan
+               // prevents false memory dependencies in race/msan/asan
                // instrumentation.
                if ir.IsAddressable(n) && !s.canSSA(n) {
                        p := s.addr(n)
@@ -3014,7 +3066,8 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                                        z := s.constInt(types.Types[types.TINT], 0)
                                        s.boundsCheck(z, z, ssa.BoundsIndex, false)
                                        // The return value won't be live, return junk.
-                                       return s.newValue0(ssa.OpUnknown, n.Type())
+                                       // But not quite junk, in case bounds checks are turned off. See issue 48092.
+                                       return s.zeroVal(n.Type())
                                }
                                len := s.constInt(types.Types[types.TINT], bound)
                                s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded()) // checks i == 0
@@ -3078,7 +3131,8 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 
        case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
                n := n.(*ir.SliceExpr)
-               v := s.expr(n.X)
+               check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
+               v := s.exprCheckPtr(n.X, !check)
                var i, j, k *ssa.Value
                if n.Low != nil {
                        i = s.expr(n.Low)
@@ -3090,6 +3144,10 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                        k = s.expr(n.Max)
                }
                p, l, c := s.slice(v, i, j, k, n.Bounded())
+               if check {
+                       // Emit checkptr instrumentation after bound check to prevent false positive, see #46938.
+                       s.checkPtrAlignment(n.X.(*ir.ConvExpr), v, s.conv(n.Max, k, k.Type, types.Types[types.TUINTPTR]))
+               }
                return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
 
        case ir.OSLICESTR:
@@ -3161,6 +3219,11 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                n := n.(*ir.BinaryExpr)
                ptr := s.expr(n.X)
                len := s.expr(n.Y)
+
+               // Force len to uintptr to prevent misuse of garbage bits in the
+               // upper part of the register (#48536).
+               len = s.conv(n, len, len.Type, types.Types[types.TUINTPTR])
+
                return s.newValue2(ssa.OpAddPtr, n.Type(), ptr, len)
 
        default:
@@ -3602,6 +3665,7 @@ const (
        callDefer
        callDeferStack
        callGo
+       callTail
 )
 
 type sfRtCallDef struct {
@@ -3779,7 +3843,7 @@ func InitTables() {
                        }
                        return s.newValue2(ssa.OpMul64uover, types.NewTuple(types.Types[types.TUINT], types.Types[types.TUINT]), args[0], args[1])
                },
-               sys.AMD64, sys.I386, sys.MIPS64)
+               sys.AMD64, sys.I386, sys.MIPS64, sys.RISCV64)
        add("runtime", "KeepAlive",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0])
@@ -3805,6 +3869,13 @@ func InitTables() {
                },
                all...)
 
+       addF("runtime", "publicationBarrier",
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+                       s.vars[memVar] = s.newValue1(ssa.OpPubBarrier, types.TypeMem, s.mem())
+                       return nil
+               },
+               sys.ARM64)
+
        /******** runtime/internal/sys ********/
        addF("runtime/internal/sys", "Ctz32",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
@@ -3827,6 +3898,21 @@ func InitTables() {
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
 
+       /****** Prefetch ******/
+       makePrefetchFunc := func(op ssa.Op) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+               return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+                       s.vars[memVar] = s.newValue2(op, types.TypeMem, args[0], s.mem())
+                       return nil
+               }
+       }
+
+       // Make Prefetch intrinsics for supported platforms
+       // On the unsupported platforms stub function will be eliminated
+       addF("runtime/internal/sys", "Prefetch", makePrefetchFunc(ssa.OpPrefetchCache),
+               sys.AMD64, sys.ARM64, sys.PPC64)
+       addF("runtime/internal/sys", "PrefetchStreamed", makePrefetchFunc(ssa.OpPrefetchCacheStreamed),
+               sys.AMD64, sys.ARM64, sys.PPC64)
+
        /******** runtime/internal/atomic ********/
        addF("runtime/internal/atomic", "Load",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
@@ -4154,23 +4240,28 @@ func InitTables() {
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpAbs, types.Types[types.TFLOAT64], args[0])
                },
-               sys.ARM64, sys.ARM, sys.PPC64, sys.Wasm)
+               sys.ARM64, sys.ARM, sys.PPC64, sys.RISCV64, sys.Wasm)
        addF("math", "Copysign",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpCopysign, types.Types[types.TFLOAT64], args[0], args[1])
                },
-               sys.PPC64, sys.Wasm)
+               sys.PPC64, sys.RISCV64, sys.Wasm)
        addF("math", "FMA",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue3(ssa.OpFMA, types.Types[types.TFLOAT64], args[0], args[1], args[2])
                },
-               sys.ARM64, sys.PPC64, sys.S390X)
+               sys.ARM64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("math", "FMA",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if !s.config.UseFMA {
                                s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
                                return s.variable(n, types.Types[types.TFLOAT64])
                        }
+
+                       if buildcfg.GOAMD64 >= 3 {
+                               return s.newValue3(ssa.OpFMA, types.Types[types.TFLOAT64], args[0], args[1], args[2])
+                       }
+
                        v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], ir.Syms.X86HasFMA)
                        b := s.endBlock()
                        b.Kind = ssa.BlockIf
@@ -4233,6 +4324,10 @@ func InitTables() {
 
        makeRoundAMD64 := func(op ssa.Op) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+                       if buildcfg.GOAMD64 >= 2 {
+                               return s.newValue1(op, types.Types[types.TFLOAT64], args[0])
+                       }
+
                        v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], ir.Syms.X86HasSSE41)
                        b := s.endBlock()
                        b.Kind = ssa.BlockIf
@@ -4338,7 +4433,7 @@ func InitTables() {
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
                },
-               sys.AMD64, sys.ARM64)
+               sys.AMD64, sys.ARM64, sys.PPC64)
        addF("math/bits", "Len32",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
@@ -4347,7 +4442,7 @@ func InitTables() {
                        x := s.newValue1(ssa.OpZeroExt32to64, types.Types[types.TUINT64], args[0])
                        return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], x)
                },
-               sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+               sys.ARM, sys.S390X, sys.MIPS, sys.Wasm)
        addF("math/bits", "Len16",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
@@ -4437,8 +4532,12 @@ func InitTables() {
                sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
        alias("math/bits", "RotateLeft", "math/bits", "RotateLeft64", p8...)
 
-       makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+       makeOnesCountAMD64 := func(op ssa.Op) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+                       if buildcfg.GOAMD64 >= 2 {
+                               return s.newValue1(op, types.Types[types.TINT], args[0])
+                       }
+
                        v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], ir.Syms.X86HasPOPCNT)
                        b := s.endBlock()
                        b.Kind = ssa.BlockIf
@@ -4452,10 +4551,6 @@ func InitTables() {
 
                        // We have the intrinsic - use it directly.
                        s.startBlock(bTrue)
-                       op := op64
-                       if s.config.PtrSize == 4 {
-                               op = op32
-                       }
                        s.vars[n] = s.newValue1(op, types.Types[types.TINT], args[0])
                        s.endBlock().AddEdgeTo(bEnd)
 
@@ -4470,7 +4565,7 @@ func InitTables() {
                }
        }
        addF("math/bits", "OnesCount64",
-               makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount64),
+               makeOnesCountAMD64(ssa.OpPopCount64),
                sys.AMD64)
        addF("math/bits", "OnesCount64",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
@@ -4478,7 +4573,7 @@ func InitTables() {
                },
                sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
        addF("math/bits", "OnesCount32",
-               makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32),
+               makeOnesCountAMD64(ssa.OpPopCount32),
                sys.AMD64)
        addF("math/bits", "OnesCount32",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
@@ -4486,7 +4581,7 @@ func InitTables() {
                },
                sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
        addF("math/bits", "OnesCount16",
-               makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16),
+               makeOnesCountAMD64(ssa.OpPopCount16),
                sys.AMD64)
        addF("math/bits", "OnesCount16",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
@@ -4499,15 +4594,15 @@ func InitTables() {
                },
                sys.S390X, sys.PPC64, sys.Wasm)
        addF("math/bits", "OnesCount",
-               makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
+               makeOnesCountAMD64(ssa.OpPopCount64),
                sys.AMD64)
        addF("math/bits", "Mul64",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1])
                },
-               sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X, sys.MIPS64)
-       alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchPPC64LE, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE)
-       alias("runtime/internal/math", "Mul64", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchPPC64LE, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE)
+               sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X, sys.MIPS64, sys.RISCV64)
+       alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchPPC64LE, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE, sys.ArchRISCV64)
+       alias("runtime/internal/math", "Mul64", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchPPC64LE, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE, sys.ArchRISCV64)
        addF("math/bits", "Add64",
                func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue3(ssa.OpAdd64carry, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1], args[2])
@@ -4853,13 +4948,13 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
                }
        }
 
-       if k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
+       if k != callNormal && k != callTail && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
                s.Fatalf("go/defer call with arguments: %v", n)
        }
 
        switch n.Op() {
        case ir.OCALLFUNC:
-               if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
+               if (k == callNormal || k == callTail) && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
                        fn := fn.(*ir.Name)
                        callee = fn
                        if buildcfg.Experiment.RegabiArgs {
@@ -4913,7 +5008,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
        stksize := params.ArgWidth() // includes receiver, args, and results
 
        res := n.X.Type().Results()
-       if k == callNormal {
+       if k == callNormal || k == callTail {
                for _, p := range params.OutParams() {
                        ACResults = append(ACResults, p.Type)
                }
@@ -4960,7 +5055,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
                // These are written in SP-offset order.
                argStart := base.Ctxt.FixedFrameSize()
                // Defer/go args.
-               if k != callNormal {
+               if k != callNormal && k != callTail {
                        // Write closure (arg to newproc/deferproc).
                        ACArgs = append(ACArgs, types.Types[types.TUINTPTR]) // not argExtra
                        callArgs = append(callArgs, closure)
@@ -5010,6 +5105,10 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
                case callee != nil:
                        aux := ssa.StaticAuxCall(callTargetLSym(callee), params)
                        call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+                       if k == callTail {
+                               call.Op = ssa.OpTailLECall
+                               stksize = 0 // Tail call does not use stack. We reuse caller's frame.
+                       }
                default:
                        s.Fatalf("bad call type %v %v", n.Op(), n)
                }
@@ -5246,12 +5345,6 @@ func (s *state) canSSAName(name *ir.Name) bool {
                        return false
                }
        }
-       if name.Class == ir.PPARAM && name.Sym() != nil && name.Sym().Name == ".this" {
-               // wrappers generated by genwrapper need to update
-               // the .this pointer in place.
-               // TODO: treat as a PPARAMOUT?
-               return false
-       }
        return true
        // TODO: try to make more variables SSAable?
 }
@@ -5259,7 +5352,7 @@ func (s *state) canSSAName(name *ir.Name) bool {
 // TypeOK reports whether variables of type t are SSA-able.
 func TypeOK(t *types.Type) bool {
        types.CalcSize(t)
-       if t.Width > int64(4*types.PtrSize) {
+       if t.Size() > int64(4*types.PtrSize) {
                // 4*Widthptr is an arbitrary constant. We want it
                // to be at least 3*Widthptr so slices can be registerized.
                // Too big and we'll introduce too much register pressure.
@@ -5749,7 +5842,7 @@ func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value)
        //
        // Where mask(x) is 0 if x==0 and -1 if x>0 and stride is the width
        // of the element type.
-       stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Width)
+       stride := s.constInt(types.Types[types.TINT], ptr.Type.Elem().Size())
 
        // The delta is the number of bytes to offset ptr by.
        delta := s.newValue2(mulOp, types.Types[types.TINT], i, stride)
@@ -5804,7 +5897,6 @@ func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n ir.Node, x *ssa.Value, ft,
        // } else {
        //        y = uintX(x) ; y = x & 1
        //        z = uintX(x) ; z = z >> 1
-       //        z = z >> 1
        //        z = z | y
        //        result = floatY(z)
        //        result = result + result
@@ -5957,7 +6049,7 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
                s.vars[n] = s.load(lenType, x)
        case ir.OCAP:
                // capacity is stored in the second word for chan
-               sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
+               sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Size(), x)
                s.vars[n] = s.load(lenType, sw)
        default:
                s.Fatalf("op must be OLEN or OCAP")
@@ -6478,6 +6570,7 @@ func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) {
        }
 
        x := EmitArgInfo(e.curfn, f.OwnAux.ABIInfo())
+       x.Set(obj.AttrContentAddressable, true)
        e.curfn.LSym.Func().ArgInfo = x
 
        // Emit a funcdata pointing at the arg info data.
@@ -6491,6 +6584,9 @@ func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) {
 // emit argument info (locations on stack) of f for traceback.
 func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
        x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
+       // NOTE: do not set ContentAddressable here. This may be referenced from
+       // assembly code by name (in this case f is a declaration).
+       // Instead, set it in emitArgInfo above.
 
        PtrSize := int64(types.PtrSize)
        uintptrTyp := types.Types[types.TUINTPTR]
@@ -6605,7 +6701,13 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
                return true
        }
 
-       for _, a := range abiInfo.InParams() {
+       start := 0
+       if strings.Contains(f.LSym.Name, "[") {
+               // Skip the dictionary argument - it is implicit and the user doesn't need to see it.
+               start = 1
+       }
+
+       for _, a := range abiInfo.InParams()[start:] {
                if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
                        break
                }
@@ -6627,6 +6729,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
 
        s.livenessMap, s.partLiveArgs = liveness.Compute(e.curfn, f, e.stkptrsize, pp)
        emitArgInfo(e, f, pp)
+       argLiveBlockMap, argLiveValueMap := liveness.ArgLiveness(e.curfn, f, pp)
 
        openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
        if openDeferInfo != nil {
@@ -6645,7 +6748,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
        var progToValue map[*obj.Prog]*ssa.Value
        var progToBlock map[*obj.Prog]*ssa.Block
        var valueToProgAfter []*obj.Prog // The first Prog following computation of a value v; v is visible at this point.
-       if f.PrintOrHtmlSSA {
+       gatherPrintInfo := f.PrintOrHtmlSSA || ssa.GenssaDump[f.Name]
+       if gatherPrintInfo {
                progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
                progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
                f.Logf("genssa %s\n", f.Name)
@@ -6683,6 +6787,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
        // Progs that are in the set above and have that source position.
        var inlMarksByPos map[src.XPos][]*obj.Prog
 
+       var argLiveIdx int = -1 // argument liveness info index
+
        // Emit basic blocks
        for i, b := range f.Blocks {
                s.bstart[b.ID] = s.pp.Next
@@ -6696,6 +6802,13 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
                // preemptible, unless this function is "all unsafe".
                s.pp.NextLive = objw.LivenessIndex{StackMapIndex: -1, IsUnsafePoint: liveness.IsUnsafe(f)}
 
+               if idx, ok := argLiveBlockMap[b.ID]; ok && idx != argLiveIdx {
+                       argLiveIdx = idx
+                       p := s.pp.Prog(obj.APCDATA)
+                       p.From.SetConst(objabi.PCDATA_ArgLiveIndex)
+                       p.To.SetConst(int64(idx))
+               }
+
                // Emit values in block
                Arch.SSAMarkMoves(&s, b)
                for _, v := range b.Values {
@@ -6752,11 +6865,18 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
                                Arch.SSAGenValue(&s, v)
                        }
 
+                       if idx, ok := argLiveValueMap[v.ID]; ok && idx != argLiveIdx {
+                               argLiveIdx = idx
+                               p := s.pp.Prog(obj.APCDATA)
+                               p.From.SetConst(objabi.PCDATA_ArgLiveIndex)
+                               p.To.SetConst(int64(idx))
+                       }
+
                        if base.Ctxt.Flag_locationlists {
                                valueToProgAfter[v.ID] = s.pp.Next
                        }
 
-                       if f.PrintOrHtmlSSA {
+                       if gatherPrintInfo {
                                for ; x != s.pp.Next; x = x.Link {
                                        progToValue[x] = v
                                }
@@ -6786,7 +6906,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
                x := s.pp.Next
                s.SetPos(b.Pos)
                Arch.SSAGenBlock(&s, b, next)
-               if f.PrintOrHtmlSSA {
+               if gatherPrintInfo {
                        for ; x != s.pp.Next; x = x.Link {
                                progToBlock[x] = b
                        }
@@ -6965,6 +7085,54 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
                buf.WriteString("</code>")
                f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
        }
+       if ssa.GenssaDump[f.Name] {
+               fi := f.DumpFileForPhase("genssa")
+               if fi != nil {
+
+                       // inliningDiffers if any filename changes or if any line number except the innermost (index 0) changes.
+                       inliningDiffers := func(a, b []src.Pos) bool {
+                               if len(a) != len(b) {
+                                       return true
+                               }
+                               for i := range a {
+                                       if a[i].Filename() != b[i].Filename() {
+                                               return true
+                                       }
+                                       if i > 0 && a[i].Line() != b[i].Line() {
+                                               return true
+                                       }
+                               }
+                               return false
+                       }
+
+                       var allPosOld []src.Pos
+                       var allPos []src.Pos
+
+                       for p := pp.Text; p != nil; p = p.Link {
+                               if p.Pos.IsKnown() {
+                                       allPos = p.AllPos(allPos)
+                                       if inliningDiffers(allPos, allPosOld) {
+                                               for i := len(allPos) - 1; i >= 0; i-- {
+                                                       pos := allPos[i]
+                                                       fmt.Fprintf(fi, "# %s:%d\n", pos.Filename(), pos.Line())
+                                               }
+                                               allPos, allPosOld = allPosOld, allPos // swap, not copy, so that they do not share slice storage.
+                                       }
+                               }
+
+                               var s string
+                               if v, ok := progToValue[p]; ok {
+                                       s = v.String()
+                               } else if b, ok := progToBlock[p]; ok {
+                                       s = b.String()
+                               } else {
+                                       s = "   " // most value and branch strings are 2-3 characters long
+                               }
+                               fmt.Fprintf(fi, " %-6s\t%.5d %s\t%s\n", s, p.Pc, ssa.StmtString(p.Pos), p.InstructionString())
+                       }
+                       fi.Close()
+               }
+       }
 
        defframe(&s, e, f)
 
@@ -7342,6 +7510,14 @@ func (s *State) Call(v *ssa.Value) *obj.Prog {
        return p
 }
 
+// TailCall returns a new tail call instruction for the SSA value v.
+// It is like Call, but for a tail call.
+func (s *State) TailCall(v *ssa.Value) *obj.Prog {
+       p := s.Call(v)
+       p.As = obj.ARET
+       return p
+}
+
 // PrepareCall prepares to emit a CALL instruction for v and does call-related bookkeeping.
 // It must be called immediately before emitting the actual CALL instruction,
 // since it emits PCDATA for the stack map at the call (calls are safe points).
index abb0bba646e0caacf183e436cc084784b5907250..57c15a34a0cd4c82bc1add58b3eb61dfeea8a6a9 100644 (file)
@@ -92,6 +92,10 @@ func StringSym(pos src.XPos, s string) (data *obj.LSym) {
        return symdata
 }
 
+// maxFileSize is the maximum file size permitted by the linker
+// (see issue #9862).
+const maxFileSize = int64(2e9)
+
 // fileStringSym returns a symbol for the contents and the size of file.
 // If readonly is true, the symbol shares storage with any literal string
 // or other file with the same content and is placed in a read-only section.
@@ -133,12 +137,12 @@ func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.
                }
                return sym, size, nil
        }
-       if size > 2e9 {
+       if size > maxFileSize {
                // ggloblsym takes an int32,
                // and probably the rest of the toolchain
                // can't handle such big symbols either.
                // See golang.org/issue/9862.
-               return nil, 0, fmt.Errorf("file too large")
+               return nil, 0, fmt.Errorf("file too large (%d bytes > %d bytes)", size, maxFileSize)
        }
 
        // File is too big to read and keep in memory.
@@ -275,7 +279,7 @@ func NeedFuncSym(fn *ir.Func) {
                // entry points, so it doesn't make sense to create a
                // funcsym for other ABIs.
                //
-               // (If we're using ABI aliases, it doesn't matter.)
+               // (If we're not using ABI wrappers, it doesn't matter.)
                base.Fatalf("expected ABIInternal: %v has %v", fn.Nname, fn.ABI)
        }
        if ir.IsBlank(fn.Nname) {
index 0730d346b2402da1c9e7ea65f8bc1106b3559ed2..627c98ba447f004b1c78394a291cab1f40467103 100644 (file)
@@ -73,7 +73,7 @@ func embedKind(typ *types.Type) int {
        if typ.Kind() == types.TSTRING {
                return embedString
        }
-       if typ.Sym() == nil && typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
+       if typ.IsSlice() && typ.Elem().Kind() == types.TUINT8 {
                return embedBytes
        }
        return embedUnknown
index 9329a469899981f8865212de82e51b7b5aa9a3cb..636199de47642a3bae215ae0897769a205fd545c 100644 (file)
@@ -133,7 +133,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
                if ir.IsZero(r) {
                        return true
                }
-               staticdata.InitConst(l, loff, r, int(typ.Width))
+               staticdata.InitConst(l, loff, r, int(typ.Size()))
                return true
 
        case ir.OADDR:
@@ -165,7 +165,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
                        e := &p.E[i]
                        typ := e.Expr.Type()
                        if e.Expr.Op() == ir.OLITERAL || e.Expr.Op() == ir.ONIL {
-                               staticdata.InitConst(l, loff+e.Xoffset, e.Expr, int(typ.Width))
+                               staticdata.InitConst(l, loff+e.Xoffset, e.Expr, int(typ.Size()))
                                continue
                        }
                        x := e.Expr
@@ -229,7 +229,7 @@ func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Ty
                if ir.IsZero(r) {
                        return true
                }
-               staticdata.InitConst(l, loff, r, int(typ.Width))
+               staticdata.InitConst(l, loff, r, int(typ.Size()))
                return true
 
        case ir.OADDR:
@@ -286,7 +286,7 @@ func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Ty
                for i := range p.E {
                        e := &p.E[i]
                        if e.Expr.Op() == ir.OLITERAL || e.Expr.Op() == ir.ONIL {
-                               staticdata.InitConst(l, loff+e.Xoffset, e.Expr, int(e.Expr.Type().Width))
+                               staticdata.InitConst(l, loff+e.Xoffset, e.Expr, int(e.Expr.Type().Size()))
                                continue
                        }
                        ir.SetPos(e.Expr)
@@ -392,7 +392,7 @@ func (s *Schedule) initplan(n ir.Node) {
                                }
                                a = kv.Value
                        }
-                       s.addvalue(p, k*n.Type().Elem().Width, a)
+                       s.addvalue(p, k*n.Type().Elem().Size(), a)
                        k++
                }
 
@@ -499,10 +499,10 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
                }
 
                // Check for overflow.
-               if n.Type().Width != 0 && types.MaxWidth/n.Type().Width <= int64(l) {
+               if n.Type().Size() != 0 && types.MaxWidth/n.Type().Size() <= int64(l) {
                        break
                }
-               offset += int64(l) * n.Type().Width
+               offset += int64(l) * n.Type().Size()
                return name, offset, true
        }
 
index 22680dce786c52214dce93b05b579cecc8f89b51..033283a3528784ce6dde2cfc13ebf7a57b08d9e5 100644 (file)
@@ -13,11 +13,7 @@ func TestDump(t *testing.T) {
                t.Skip("skipping test in short mode")
        }
 
-       // provide a no-op error handler so parsing doesn't stop after first error
-       ast, err := ParseFile(*src_, func(error) {}, nil, CheckBranches)
-       if err != nil {
-               t.Error(err)
-       }
+       ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics)
 
        if ast != nil {
                Fdump(testOut(), ast)
index e4bedf54fdc04fec00253a41a00640c5fdafc7c8..d87e8eaee3213e8b31f6f19c1d8e61a4a306e1ab 100644 (file)
@@ -154,11 +154,11 @@ func testSyntaxErrors(t *testing.T, filename string) {
                if found {
                        rx, err := regexp.Compile(pattern)
                        if err != nil {
-                               t.Errorf("%s: %v", pos, err)
+                               t.Errorf("%s:%s: %v", filename, pos, err)
                                return
                        }
                        if match := rx.MatchString(e.Msg); !match {
-                               t.Errorf("%s: %q does not match %q", pos, e.Msg, pattern)
+                               t.Errorf("%s:%s: %q does not match %q", filename, pos, e.Msg, pattern)
                                return
                        }
                        // we have a match - eliminate this error
index fb9786daa325c580d5402603e9241ae67ab36ddc..2f9b43edef98ad42edd4ad01e676fff5d83c26e0 100644 (file)
@@ -275,14 +275,14 @@ type (
        // Name Type
        //      Type
        Field struct {
-               Name *Name // nil means anonymous field/parameter (structs/parameters), or embedded interface (interfaces)
+               Name *Name // nil means anonymous field/parameter (structs/parameters), or embedded element (interfaces)
                Type Expr  // field names declared in a list share the same Type (identical pointers)
                node
        }
 
        // interface { MethodList[0]; MethodList[1]; ... }
        InterfaceType struct {
-               MethodList []*Field // a field named "type" means a type constraint
+               MethodList []*Field
                expr
        }
 
index 4fb6de10a820a527125a1e4bcd62e519e0dce7ef..770175fe54f8d2b5aee7071e924d37cea019a2df 100644 (file)
@@ -87,6 +87,8 @@ func (p *parser) init(file *PosBase, r io.Reader, errh ErrorHandler, pragh Pragm
        p.indent = nil
 }
 
+func (p *parser) allowGenerics() bool { return p.mode&AllowGenerics != 0 }
+
 // takePragma returns the current parsed pragmas
 // and clears them from the parser state.
 func (p *parser) takePragma() Pragma {
@@ -146,11 +148,13 @@ func (p *parser) updateBase(pos Pos, tline, tcol uint, text string) {
        // If we have a column (//line filename:line:col form),
        // an empty filename means to use the previous filename.
        filename := text[:i-1] // lop off ":line"
+       trimmed := false
        if filename == "" && ok2 {
                filename = p.base.Filename()
+               trimmed = p.base.Trimmed()
        }
 
-       p.base = NewLineBase(pos, filename, line, col)
+       p.base = NewLineBase(pos, filename, trimmed, line, col)
 }
 
 func commentText(s string) string {
@@ -274,7 +278,9 @@ func (p *parser) syntaxErrorAt(pos Pos, msg string) {
 }
 
 // tokstring returns the English word for selected punctuation tokens
-// for more readable error messages.
+// for more readable error messages. Use tokstring (not tok.String())
+// for user-facing (error) messages; use tok.String() for debugging
+// output.
 func tokstring(tok token) string {
        switch tok {
        case _Comma:
@@ -580,35 +586,54 @@ func (p *parser) typeDecl(group *Group) Decl {
        d.Pragma = p.takePragma()
 
        d.Name = p.name()
-       if p.tok == _Lbrack {
-               // array/slice or generic type
+       if p.allowGenerics() && p.tok == _Lbrack {
+               // d.Name "[" ...
+               // array/slice or type parameter list
                pos := p.pos()
                p.next()
                switch p.tok {
-               case _Rbrack:
-                       p.next()
-                       d.Type = p.sliceType(pos)
                case _Name:
-                       // array or generic type
-                       p.xnest++
-                       x := p.expr()
-                       p.xnest--
-                       if name0, ok := x.(*Name); p.mode&AllowGenerics != 0 && ok && p.tok != _Rbrack {
-                               // generic type
-                               d.TParamList = p.paramList(name0, _Rbrack, true)
-                               pos := p.pos()
-                               if p.gotAssign() {
-                                       p.syntaxErrorAt(pos, "generic type cannot be alias")
+                       // d.Name "[" name ...
+                       // array or type parameter list
+                       name := p.name()
+                       // Index or slice expressions are never constant and thus invalid
+                       // array length expressions. Thus, if we see a "[" following name
+                       // we can safely assume that "[" name starts a type parameter list.
+                       var x Expr // x != nil means x is the array length expression
+                       if p.tok != _Lbrack {
+                               // d.Name "[" name ...
+                               // If we reach here, the next token is not a "[", and we need to
+                               // parse the expression starting with name. If that expression is
+                               // just that name, not followed by a "]" (in which case we might
+                               // have the array length "[" name "]"), we can also safely assume
+                               // a type parameter list.
+                               p.xnest++
+                               // To parse the expression starting with name, expand the call
+                               // sequence we would get by passing in name to parser.expr, and
+                               // pass in name to parser.pexpr.
+                               x = p.binaryExpr(p.pexpr(name, false), 0)
+                               p.xnest--
+                               if x == name && p.tok != _Rbrack {
+                                       x = nil
                                }
+                       }
+                       if x == nil {
+                               // d.Name "[" name ...
+                               // type parameter list
+                               d.TParamList = p.paramList(name, _Rbrack, true)
+                               d.Alias = p.gotAssign()
                                d.Type = p.typeOrNil()
                        } else {
+                               // d.Name "[" x "]" ...
                                // x is the array length expression
-                               if debug && x == nil {
-                                       panic("length expression is nil")
-                               }
                                d.Type = p.arrayType(pos, x)
                        }
+               case _Rbrack:
+                       // d.Name "[" "]" ...
+                       p.next()
+                       d.Type = p.sliceType(pos)
                default:
+                       // d.Name "[" ...
                        d.Type = p.arrayType(pos, nil)
                }
        } else {
@@ -683,15 +708,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        }
 
        f.Name = p.name()
-       if p.mode&AllowGenerics != 0 && p.got(_Lbrack) {
-               if p.tok == _Rbrack {
-                       p.syntaxError("empty type parameter list")
-                       p.next()
-               } else {
-                       f.TParamList = p.paramList(nil, _Rbrack, true)
-               }
-       }
-       f.Type = p.funcType()
+       f.TParamList, f.Type = p.funcType("")
        if p.tok == _Lbrace {
                f.Body = p.funcBody()
        }
@@ -723,14 +740,16 @@ func (p *parser) expr() Expr {
                defer p.trace("expr")()
        }
 
-       return p.binaryExpr(0)
+       return p.binaryExpr(nil, 0)
 }
 
 // Expression = UnaryExpr | Expression binary_op Expression .
-func (p *parser) binaryExpr(prec int) Expr {
+func (p *parser) binaryExpr(x Expr, prec int) Expr {
        // don't trace binaryExpr - only leads to overly nested trace output
 
-       x := p.unaryExpr()
+       if x == nil {
+               x = p.unaryExpr()
+       }
        for (p.tok == _Operator || p.tok == _Star) && p.prec > prec {
                t := new(Operation)
                t.pos = p.pos()
@@ -738,7 +757,7 @@ func (p *parser) binaryExpr(prec int) Expr {
                tprec := p.prec
                p.next()
                t.X = x
-               t.Y = p.binaryExpr(tprec)
+               t.Y = p.binaryExpr(nil, tprec)
                x = t
        }
        return x
@@ -833,7 +852,7 @@ func (p *parser) unaryExpr() Expr {
        // TODO(mdempsky): We need parens here so we can report an
        // error for "(x) := true". It should be possible to detect
        // and reject that more efficiently though.
-       return p.pexpr(true)
+       return p.pexpr(nil, true)
 }
 
 // callStmt parses call-like statements that can be preceded by 'defer' and 'go'.
@@ -847,7 +866,7 @@ func (p *parser) callStmt() *CallStmt {
        s.Tok = p.tok // _Defer or _Go
        p.next()
 
-       x := p.pexpr(p.tok == _Lparen) // keep_parens so we can report error below
+       x := p.pexpr(nil, p.tok == _Lparen) // keep_parens so we can report error below
        if t := unparen(x); t != x {
                p.errorAt(x.Pos(), fmt.Sprintf("expression in %s must not be parenthesized", s.Tok))
                // already progressed, no need to advance
@@ -917,7 +936,7 @@ func (p *parser) operand(keep_parens bool) Expr {
        case _Func:
                pos := p.pos()
                p.next()
-               ftyp := p.funcType()
+               _, ftyp := p.funcType("function literal")
                if p.tok == _Lbrace {
                        p.xnest++
 
@@ -963,12 +982,14 @@ func (p *parser) operand(keep_parens bool) Expr {
 //                  "]" .
 // TypeAssertion  = "." "(" Type ")" .
 // Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
-func (p *parser) pexpr(keep_parens bool) Expr {
+func (p *parser) pexpr(x Expr, keep_parens bool) Expr {
        if trace {
                defer p.trace("pexpr")()
        }
 
-       x := p.operand(keep_parens)
+       if x == nil {
+               x = p.operand(keep_parens)
+       }
 
 loop:
        for {
@@ -1255,7 +1276,8 @@ func (p *parser) typeOrNil() Expr {
        case _Func:
                // fntype
                p.next()
-               return p.funcType()
+               _, t := p.funcType("function type")
+               return t
 
        case _Lbrack:
                // '[' oexpr ']' ntype
@@ -1328,18 +1350,34 @@ func (p *parser) typeInstance(typ Expr) Expr {
        return x
 }
 
-func (p *parser) funcType() *FuncType {
+// If context != "", type parameters are not permitted.
+func (p *parser) funcType(context string) ([]*Field, *FuncType) {
        if trace {
                defer p.trace("funcType")()
        }
 
        typ := new(FuncType)
        typ.pos = p.pos()
+
+       var tparamList []*Field
+       if p.allowGenerics() && p.got(_Lbrack) {
+               if context != "" {
+                       // accept but complain
+                       p.syntaxErrorAt(typ.pos, context+" cannot have type parameters")
+               }
+               if p.tok == _Rbrack {
+                       p.syntaxError("empty type parameter list")
+                       p.next()
+               } else {
+                       tparamList = p.paramList(nil, _Rbrack, true)
+               }
+       }
+
        p.want(_Lparen)
        typ.ParamList = p.paramList(nil, _Rparen, false)
        typ.ResultList = p.funcResult()
 
-       return typ
+       return tparamList, typ
 }
 
 // "[" has already been consumed, and pos is its position.
@@ -1421,7 +1459,7 @@ func (p *parser) interfaceType() *InterfaceType {
                switch p.tok {
                case _Name:
                        f := p.methodDecl()
-                       if f.Name == nil && p.mode&AllowGenerics != 0 {
+                       if f.Name == nil && p.allowGenerics() {
                                f = p.embeddedElem(f)
                        }
                        typ.MethodList = append(typ.MethodList, f)
@@ -1439,37 +1477,13 @@ func (p *parser) interfaceType() *InterfaceType {
                        return false
 
                case _Operator:
-                       if p.op == Tilde && p.mode&AllowGenerics != 0 {
+                       if p.op == Tilde && p.allowGenerics() {
                                typ.MethodList = append(typ.MethodList, p.embeddedElem(nil))
                                return false
                        }
 
-               case _Type:
-                       // TODO(gri) remove TypeList syntax if we accept #45346
-                       if p.mode&AllowGenerics != 0 {
-                               type_ := NewName(p.pos(), "type") // cannot have a method named "type"
-                               p.next()
-                               if p.tok != _Semi && p.tok != _Rbrace {
-                                       f := new(Field)
-                                       f.pos = p.pos()
-                                       f.Name = type_
-                                       f.Type = p.type_()
-                                       typ.MethodList = append(typ.MethodList, f)
-                                       for p.got(_Comma) {
-                                               f := new(Field)
-                                               f.pos = p.pos()
-                                               f.Name = type_
-                                               f.Type = p.type_()
-                                               typ.MethodList = append(typ.MethodList, f)
-                                       }
-                               } else {
-                                       p.syntaxError("expecting type")
-                               }
-                               return false
-                       }
-
                default:
-                       if p.mode&AllowGenerics != 0 {
+                       if p.allowGenerics() {
                                pos := p.pos()
                                if t := p.typeOrNil(); t != nil {
                                        f := new(Field)
@@ -1481,9 +1495,9 @@ func (p *parser) interfaceType() *InterfaceType {
                        }
                }
 
-               if p.mode&AllowGenerics != 0 {
-                       p.syntaxError("expecting method, type list, or embedded element")
-                       p.advance(_Semi, _Rbrace, _Type) // TODO(gri) remove _Type if we don't accept it anymore
+               if p.allowGenerics() {
+                       p.syntaxError("expecting method or embedded element")
+                       p.advance(_Semi, _Rbrace)
                        return false
                }
 
@@ -1561,7 +1575,7 @@ func (p *parser) fieldDecl(styp *StructType) {
 
                // Careful dance: We don't know if we have an embedded instantiated
                // type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
-               if p.mode&AllowGenerics != 0 && len(names) == 1 && p.tok == _Lbrack {
+               if p.allowGenerics() && len(names) == 1 && p.tok == _Lbrack {
                        typ = p.arrayOrTArgs()
                        if typ, ok := typ.(*IndexExpr); ok {
                                // embedded type T[P1, P2, ...]
@@ -1692,14 +1706,16 @@ func (p *parser) methodDecl() *Field {
                // already progressed, no need to advance
        }
 
+       const context = "interface method"
+
        switch p.tok {
        case _Lparen:
                // method
                f.Name = name
-               f.Type = p.funcType()
+               _, f.Type = p.funcType(context)
 
        case _Lbrack:
-               if p.mode&AllowGenerics != 0 {
+               if p.allowGenerics() {
                        // Careful dance: We don't know if we have a generic method m[T C](x T)
                        // or an embedded instantiated type T[P1, P2] (we accept generic methods
                        // for generality and robustness of parsing).
@@ -1716,7 +1732,7 @@ func (p *parser) methodDecl() *Field {
                                        // name[](
                                        p.errorAt(pos, "empty type parameter list")
                                        f.Name = name
-                                       f.Type = p.funcType()
+                                       _, f.Type = p.funcType(context)
                                } else {
                                        p.errorAt(pos, "empty type argument list")
                                        f.Type = name
@@ -1733,7 +1749,7 @@ func (p *parser) methodDecl() *Field {
                                // as if [] were absent.
                                if p.tok == _Lparen {
                                        f.Name = name
-                                       f.Type = p.funcType()
+                                       _, f.Type = p.funcType(context)
                                } else {
                                        f.Type = name
                                }
@@ -1744,7 +1760,7 @@ func (p *parser) methodDecl() *Field {
                        if list[0].Name != nil {
                                // generic method
                                f.Name = name
-                               f.Type = p.funcType()
+                               _, f.Type = p.funcType(context)
                                // TODO(gri) Record list as type parameter list with f.Type
                                //           if we want to type-check the generic method.
                                //           For now, report an error so this is not a silent event.
@@ -1832,39 +1848,70 @@ func (p *parser) embeddedTerm() Expr {
 }
 
 // ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) paramDeclOrNil(name *Name) *Field {
+func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
        if trace {
-               defer p.trace("paramDecl")()
+               defer p.trace("paramDeclOrNil")()
+       }
+
+       // type set notation is ok in type parameter lists
+       typeSetsOk := follow == _Rbrack
+
+       pos := p.pos()
+       if name != nil {
+               pos = name.pos
+       } else if typeSetsOk && p.tok == _Operator && p.op == Tilde {
+               // "~" ...
+               return p.embeddedElem(nil)
        }
 
        f := new(Field)
-       f.pos = p.pos()
+       f.pos = pos
 
        if p.tok == _Name || name != nil {
+               // name
                if name == nil {
                        name = p.name()
                }
 
-               if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
+               if p.allowGenerics() && p.tok == _Lbrack {
+                       // name "[" ...
                        f.Type = p.arrayOrTArgs()
                        if typ, ok := f.Type.(*IndexExpr); ok {
+                               // name "[" ... "]"
                                typ.X = name
                        } else {
+                               // name "[" n "]" E
                                f.Name = name
                        }
+                       if typeSetsOk && p.tok == _Operator && p.op == Or {
+                               // name "[" ... "]" "|" ...
+                               // name "[" n "]" E "|" ...
+                               f = p.embeddedElem(f)
+                       }
                        return f
                }
 
                if p.tok == _Dot {
-                       // name_or_type
+                       // name "." ...
                        f.Type = p.qualifiedName(name)
+                       if typeSetsOk && p.tok == _Operator && p.op == Or {
+                               // name "." name "|" ...
+                               f = p.embeddedElem(f)
+                       }
                        return f
                }
 
+               if typeSetsOk && p.tok == _Operator && p.op == Or {
+                       // name "|" ...
+                       f.Type = name
+                       return p.embeddedElem(f)
+               }
+
                f.Name = name
        }
 
        if p.tok == _DotDotDot {
+               // [name] "..." ...
                t := new(DotsType)
                t.pos = p.pos()
                p.next()
@@ -1877,13 +1924,23 @@ func (p *parser) paramDeclOrNil(name *Name) *Field {
                return f
        }
 
+       if typeSetsOk && p.tok == _Operator && p.op == Tilde {
+               // [name] "~" ...
+               f.Type = p.embeddedElem(nil).Type
+               return f
+       }
+
        f.Type = p.typeOrNil()
+       if typeSetsOk && p.tok == _Operator && p.op == Or && f.Type != nil {
+               // [name] type "|"
+               f = p.embeddedElem(f)
+       }
        if f.Name != nil || f.Type != nil {
                return f
        }
 
-       p.syntaxError("expecting )")
-       p.advance(_Comma, _Rparen)
+       p.syntaxError("expecting " + tokstring(follow))
+       p.advance(_Comma, follow)
        return nil
 }
 
@@ -1897,9 +1954,10 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
                defer p.trace("paramList")()
        }
 
-       var named int // number of parameters that have an explicit name and type/bound
-       p.list(_Comma, close, func() bool {
-               par := p.paramDeclOrNil(name)
+       var named int // number of parameters that have an explicit name and type
+       var typed int // number of parameters that have an explicit type
+       end := p.list(_Comma, close, func() bool {
+               par := p.paramDeclOrNil(name, close)
                name = nil // 1st name was consumed if present
                if par != nil {
                        if debug && par.Name == nil && par.Type == nil {
@@ -1908,6 +1966,9 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
                        if par.Name != nil && par.Type != nil {
                                named++
                        }
+                       if par.Type != nil {
+                               typed++
+                       }
                        list = append(list, par)
                }
                return false
@@ -1918,7 +1979,7 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
        }
 
        // distribute parameter types (len(list) > 0)
-       if named == 0 {
+       if named == 0 && !requireNames {
                // all unnamed => found names are named types
                for _, par := range list {
                        if typ := par.Name; typ != nil {
@@ -1926,18 +1987,16 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
                                par.Name = nil
                        }
                }
-               if requireNames {
-                       p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named")
-               }
        } else if named != len(list) {
                // some named => all must have names and types
-               var pos Pos // left-most error position (or unknown)
-               var typ Expr
+               var pos Pos  // left-most error position (or unknown)
+               var typ Expr // current type (from right to left)
                for i := len(list) - 1; i >= 0; i-- {
-                       if par := list[i]; par.Type != nil {
+                       par := list[i]
+                       if par.Type != nil {
                                typ = par.Type
                                if par.Name == nil {
-                                       pos = typ.Pos()
+                                       pos = StartPos(typ)
                                        par.Name = NewName(pos, "_")
                                }
                        } else if typ != nil {
@@ -1953,7 +2012,12 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*
                if pos.IsKnown() {
                        var msg string
                        if requireNames {
-                               msg = "type parameters must be named"
+                               if named == typed {
+                                       pos = end // position error at closing ]
+                                       msg = "missing type constraint"
+                               } else {
+                                       msg = "type parameters must be named"
+                               }
                        } else {
                                msg = "mixed named and unnamed parameters"
                        }
@@ -2193,7 +2257,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS
        if p.tok != _Semi {
                // accept potential varDecl but complain
                if p.got(_Var) {
-                       p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", keyword.String()))
+                       p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", tokstring(keyword)))
                }
                init = p.simpleStmt(nil, keyword)
                // If we have a range clause, we are done (can only happen for keyword == _For).
@@ -2634,7 +2698,7 @@ func (p *parser) qualifiedName(name *Name) Expr {
                x = s
        }
 
-       if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
+       if p.allowGenerics() && p.tok == _Lbrack {
                x = p.typeInstance(x)
        }
 
index 340ca6bb6f637b05d5756a44f09a371eec69819f..68f3c376c929216693493d99894f0273c8f86e67 100644 (file)
@@ -51,10 +51,7 @@ func TestParseGo2(t *testing.T) {
        }
 }
 
-func TestStdLib(t *testing.T)        { testStdLib(t, 0) }
-func TestStdLibGeneric(t *testing.T) { testStdLib(t, AllowGenerics) }
-
-func testStdLib(t *testing.T, mode Mode) {
+func TestStdLib(t *testing.T) {
        if testing.Short() {
                t.Skip("skipping test in short mode")
        }
@@ -93,7 +90,7 @@ func testStdLib(t *testing.T, mode Mode) {
                                if debug {
                                        fmt.Printf("parsing %s\n", filename)
                                }
-                               ast, err := ParseFile(filename, nil, nil, mode)
+                               ast, err := ParseFile(filename, nil, nil, AllowGenerics)
                                if err != nil {
                                        t.Error(err)
                                        return
index baebcc995c759bbcb4719600e658b0a4920f881a..1494c0989fb11a1258649f6f0e45c39f7e147747 100644 (file)
@@ -133,13 +133,19 @@ type PosBase struct {
        pos       Pos
        filename  string
        line, col uint32
+       trimmed   bool // whether -trimpath has been applied
 }
 
 // NewFileBase returns a new PosBase for the given filename.
 // A file PosBase's position is relative to itself, with the
 // position being filename:1:1.
 func NewFileBase(filename string) *PosBase {
-       base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase}
+       return NewTrimmedFileBase(filename, false)
+}
+
+// NewTrimmedFileBase is like NewFileBase, but allows specifying Trimmed.
+func NewTrimmedFileBase(filename string, trimmed bool) *PosBase {
+       base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase, trimmed}
        base.pos.base = base
        return base
 }
@@ -149,8 +155,8 @@ func NewFileBase(filename string) *PosBase {
 // the comment containing the line directive. For a directive in a line comment,
 // that position is the beginning of the next line (i.e., the newline character
 // belongs to the line comment).
-func NewLineBase(pos Pos, filename string, line, col uint) *PosBase {
-       return &PosBase{pos, filename, sat32(line), sat32(col)}
+func NewLineBase(pos Pos, filename string, trimmed bool, line, col uint) *PosBase {
+       return &PosBase{pos, filename, sat32(line), sat32(col), trimmed}
 }
 
 func (base *PosBase) IsFileBase() bool {
@@ -188,6 +194,13 @@ func (base *PosBase) Col() uint {
        return uint(base.col)
 }
 
+func (base *PosBase) Trimmed() bool {
+       if base == nil {
+               return false
+       }
+       return base.trimmed
+}
+
 func sat32(x uint) uint32 {
        if x > PosMax {
                return PosMax
index e557f5d9247b521a67984f5b60d8963174b45a1d..c8d31799afcb4e479f31e6a07b004b8de028d5ae 100644 (file)
@@ -494,39 +494,16 @@ func (p *printer) printRawNode(n Node) {
                p.printSignature(n)
 
        case *InterfaceType:
-               // separate type list and method list
-               var types []Expr
-               var methods []*Field
-               for _, f := range n.MethodList {
-                       if f.Name != nil && f.Name.Value == "type" {
-                               types = append(types, f.Type)
-                       } else {
-                               // method or embedded interface
-                               methods = append(methods, f)
-                       }
-               }
-
-               multiLine := len(n.MethodList) > 0 && p.linebreaks
                p.print(_Interface)
-               if multiLine {
+               if p.linebreaks && len(n.MethodList) > 1 {
                        p.print(blank)
-               }
-               p.print(_Lbrace)
-               if multiLine {
+                       p.print(_Lbrace)
                        p.print(newline, indent)
-               }
-               if len(types) > 0 {
-                       p.print(_Type, blank)
-                       p.printExprList(types)
-                       if len(methods) > 0 {
-                               p.print(_Semi, blank)
-                       }
-               }
-               if len(methods) > 0 {
-                       p.printMethodList(methods)
-               }
-               if multiLine {
+                       p.printMethodList(n.MethodList)
                        p.print(outdent, newline)
+               } else {
+                       p.print(_Lbrace)
+                       p.printMethodList(n.MethodList)
                }
                p.print(_Rbrace)
 
index ec4b1de573f6bec08883996037bccf320cb210ad..604f1fc1ca71a296ed449126a4e685a47145aeb4 100644 (file)
@@ -18,11 +18,7 @@ func TestPrint(t *testing.T) {
                t.Skip("skipping test in short mode")
        }
 
-       // provide a no-op error handler so parsing doesn't stop after first error
-       ast, err := ParseFile(*src_, func(error) {}, nil, 0)
-       if err != nil {
-               t.Error(err)
-       }
+       ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
 
        if ast != nil {
                Fprint(testOut(), ast, LineForm)
@@ -64,18 +60,22 @@ var stringTests = []string{
        // generic type declarations
        "package p; type _[T any] struct{}",
        "package p; type _[A, B, C interface{m()}] struct{}",
-       "package p; type _[T any, A, B, C interface{m()}, X, Y, Z interface{type int}] struct{}",
+       "package p; type _[T any, A, B, C interface{m()}, X, Y, Z interface{~int}] struct{}",
 
        // generic function declarations
        "package p; func _[T any]()",
        "package p; func _[A, B, C interface{m()}]()",
-       "package p; func _[T any, A, B, C interface{m()}, X, Y, Z interface{type int}]()",
+       "package p; func _[T any, A, B, C interface{m()}, X, Y, Z interface{~int}]()",
 
        // methods with generic receiver types
        "package p; func (R[T]) _()",
        "package p; func (*R[A, B, C]) _()",
        "package p; func (_ *R[A, B, C]) _()",
 
+       // type constraint literals with elided interfaces
+       "package p; func _[P ~int, Q int | string]() {}",
+       "package p; func _[P struct{f int}, Q *P]() {}",
+
        // channels
        "package p; type _ chan chan int",
        "package p; type _ chan (<-chan int)",
@@ -140,10 +140,10 @@ var exprTests = [][2]string{
        dup("func(int, float32) string"),
        dup("interface{m()}"),
        dup("interface{m() string; n(x int)}"),
-       dup("interface{type int}"),
-       dup("interface{type int, float64, string}"),
-       dup("interface{type int; m()}"),
-       dup("interface{type int, float64, string; m() string; n(x int)}"),
+       dup("interface{~int}"),
+       dup("interface{~int | ~float64 | ~string}"),
+       dup("interface{~int; m()}"),
+       dup("interface{~int | ~float64 | ~string; m() string; n(x int)}"),
        dup("map[string]int"),
        dup("chan E"),
        dup("<-chan E"),
@@ -155,7 +155,7 @@ var exprTests = [][2]string{
        dup("interface{~int}"),
        dup("interface{int | string}"),
        dup("interface{~int | ~string; float64; m()}"),
-       dup("interface{type a, b, c; ~int | ~string; float64; m()}"),
+       dup("interface{~a | ~b | ~c; ~int | ~string; float64; m()}"),
        dup("interface{~T[int, string] | string}"),
 
        // non-type expressions
index f3deb703b6770077251c213c517e252c84b98161..76b8d5591fbf99cfa49264e51f13c67e6d154046 100644 (file)
@@ -148,31 +148,7 @@ func _[T any](r R2[T, int], p *R2[string, T]) {
        p.pm()
 }
 
-// An interface can (explicitly) declare at most one type list.
-type _ interface {
-       m0()
-       type int, string, bool
-       type /* ERROR multiple type lists */ float32, float64
-       m1()
-       m2()
-       type /* ERROR multiple type lists */ complex64, complex128
-       type /* ERROR multiple type lists */ rune
-}
-
-// Interface type lists may contain each type at most once.
-// (If there are multiple lists, we assume the author intended
-// for them to be all in a single list, and we report the error
-// as well.)
-type _ interface {
-       type int, int /* ERROR duplicate type int */
-       type /* ERROR multiple type lists */ int /* ERROR duplicate type int */
-}
-
-type _ interface {
-       type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int}
-}
-
-// Interface type lists can contain any type, incl. *Named types.
+// Interface type constraints can contain any type, incl. *Named types.
 // Verify that we use the underlying type to compute the operational type.
 type MyInt int
 func add1[T interface{ ~MyInt }](x T) T {
@@ -184,9 +160,9 @@ func double[T interface{ ~MyInt | ~MyString }](x T) T {
        return x + x
 }
 
-// Embedding of interfaces with type lists leads to interfaces
-// with type lists that are the intersection of the embedded
-// type lists.
+// Embedding of interfaces with type constraints leads to interfaces
+// with type constraints that are the intersection of the embedded
+// type constraints.
 
 type E0 interface {
        ~int | ~bool | ~string
@@ -246,7 +222,7 @@ var _ = f12[float64]
 
 type I0_ interface {
        E0
-       type int
+       ~int
 }
 
 func f0_[T I0_]()
index b399d7514889f39c5e8889088dd2c4ada0d2c857..dbc41879896920495d064f92cb1c16cc0c8d71fb 100644 (file)
@@ -4,16 +4,11 @@
 
 // This file contains test cases for interfaces containing
 // constraint elements.
-//
-// For now, we accept both ordinary type lists and the
-// more complex constraint elements.
 
 package p
 
 type _ interface {
        m()
-       type int
-       type int, string
        E
 }
 
@@ -31,7 +26,6 @@ type _ interface {
        T[int, string] | string
        int | ~T[string, struct{}]
        ~int | ~string
-       type bool, int, float64
 }
 
 type _ interface {
diff --git a/src/cmd/compile/internal/syntax/testdata/issue43527.go2 b/src/cmd/compile/internal/syntax/testdata/issue43527.go2
new file mode 100644 (file)
index 0000000..dd2c9b1
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 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 (
+        // 0 and 1-element []-lists are syntactically valid
+        _[A, B /* ERROR missing type constraint */ ] int
+        _[A, /* ERROR type parameters must be named */ interface{}] int
+        _[A, B, C /* ERROR missing type constraint */ ] int
+        _[A B, C /* ERROR missing type constraint */ ] int
+        _[A B, /* ERROR type parameters must be named */ interface{}] int
+        _[A B, /* ERROR type parameters must be named */ interface{}, C D] int
+        _[A B, /* ERROR type parameters must be named */ interface{}, C, D] int
+        _[A B, /* ERROR type parameters must be named */ interface{}, C, interface{}] int
+        _[A B, C interface{}, D, /* ERROR type parameters must be named */ interface{}] int
+)
+
+// function type parameters use the same parsing routine - just have a couple of tests
+
+func _[A, B /* ERROR missing type constraint */ ]() {}
+func _[A, /* ERROR type parameters must be named */ interface{}]() {}
diff --git a/src/cmd/compile/internal/syntax/testdata/issue48382.go2 b/src/cmd/compile/internal/syntax/testdata/issue48382.go2
new file mode 100644 (file)
index 0000000..1e8f4b0
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 _ func /* ERROR function type cannot have type parameters */ [ /* ERROR empty type parameter list */ ]()
+type _ func /* ERROR function type cannot have type parameters */ [ x /* ERROR missing type constraint */ ]()
+type _ func /* ERROR function type cannot have type parameters */ [P any]()
+
+var _ = func /* ERROR function literal cannot have type parameters */ [P any]() {}
+
+type _ interface{
+        m /* ERROR interface method cannot have type parameters */ [P any]()
+}
index 42031c32774f9419625b21b3ea14d005a2cf5449..80e155bfe05213df73abaa04ffea861e377cfd49 100644 (file)
@@ -4,8 +4,8 @@
 
 package p
 
-type t[ /* ERROR type parameters must be named */ a, b] struct{}
-type t[a t, b t, /* ERROR type parameters must be named */ c] struct{}
+type t[a, b /* ERROR missing type constraint */ ] struct{}
+type t[a t, b t, c /* ERROR missing type constraint */ ] struct{}
 type t struct {
        t [n]byte
        t[a]
@@ -18,5 +18,7 @@ type t interface {
 }
 
 func f[ /* ERROR empty type parameter list */ ]()
-func f[ /* ERROR type parameters must be named */ a, b]()
-func f[a t, b t, /* ERROR type parameters must be named */ c]()
+func f[a, b /* ERROR missing type constraint */ ]()
+func f[a t, b t, c /* ERROR missing type constraint */ ]()
+
+func f[a b,  /* ERROR expecting ] */ 0] ()
diff --git a/src/cmd/compile/internal/syntax/testdata/typeset.go2 b/src/cmd/compile/internal/syntax/testdata/typeset.go2
new file mode 100644 (file)
index 0000000..19b74f2
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains test cases for typeset-only constraint elements.
+
+package p
+
+type (
+        _[_ t] t
+        _[_ ~t] t
+        _[_ t|t] t
+        _[_ ~t|t] t
+        _[_ t|~t] t
+        _[_ ~t|~t] t
+
+        _[_ t, _, _ t|t] t
+        _[_ t, _, _ ~t|t] t
+        _[_ t, _, _ t|~t] t
+        _[_ t, _, _ ~t|~t] t
+
+        _[_ t.t] t
+        _[_ ~t.t] t
+        _[_ t.t|t.t] t
+        _[_ ~t.t|t.t] t
+        _[_ t.t|~t.t] t
+        _[_ ~t.t|~t.t] t
+
+        _[_ t, _, _ t.t|t.t] t
+        _[_ t, _, _ ~t.t|t.t] t
+        _[_ t, _, _ t.t|~t.t] t
+        _[_ t, _, _ ~t.t|~t.t] t
+
+        _[_ struct{}] t
+        _[_ ~struct{}] t
+
+        _[_ struct{}|t] t
+        _[_ ~struct{}|t] t
+        _[_ struct{}|~t] t
+        _[_ ~struct{}|~t] t
+
+        _[_ t|struct{}] t
+        _[_ ~t|struct{}] t
+        _[_ t|~struct{}] t
+        _[_ ~t|~struct{}] t
+
+        // test cases for issue #49175
+        _[_ []t]t
+        _[_ [1]t]t
+        _[_ ~[]t]t
+        _[_ ~[1]t]t
+        t [ /* ERROR type parameters must be named */ t[0]]t
+)
+
+// test cases for issue #49174
+func _[_ t]() {}
+func _[_ []t]() {}
+func _[_ [1]t]() {}
+func _[_ []t | t]() {}
+func _[_ [1]t | t]() {}
+func _[_ t | []t]() {}
+func _[_ []t | []t]() {}
+func _[_ [1]t | [1]t]() {}
+func _[_ t[t] | t[t]]() {}
+
+// Single-expression type parameter lists and those that don't start
+// with a (type parameter) name are considered array sizes.
+// The term must be a valid expression (it could be a type - and then
+// a type-checker will complain - but we don't allow ~ in the expr).
+type (
+        _[t] t
+        _[/* ERROR unexpected ~ */ ~t] t
+        _[t|t] t
+        _[/* ERROR unexpected ~ */ ~t|t] t
+        _[t| /* ERROR unexpected ~ */ ~t] t
+        _[/* ERROR unexpected ~ */ ~t|~t] t
+)
+
+type (
+        _[_ t, t /* ERROR missing type constraint */ ] t
+        _[_ ~t, t /* ERROR missing type constraint */ ] t
+        _[_ t, /* ERROR type parameters must be named */ ~t] t
+        _[_ ~t, /* ERROR type parameters must be named */ ~t] t
+
+        _[_ t|t, /* ERROR type parameters must be named */ t|t] t
+        _[_ ~t|t, /* ERROR type parameters must be named */ t|t] t
+        _[_ t|t, /* ERROR type parameters must be named */ ~t|t] t
+        _[_ ~t|t, /* ERROR type parameters must be named */ ~t|t] t
+)
index 839546bcb8a726f46b40d04b937656b6e131dd44..12b4a0c361360564e9d7bab8a45bbe6045577828 100644 (file)
@@ -247,7 +247,7 @@ func TestABIUtilsSliceString(t *testing.T) {
        //      p6 int64, p6 []intr32) (r1 string, r2 int64, r3 string, r4 []int32)
        i32 := types.Types[types.TINT32]
        sli32 := types.NewSlice(i32)
-       str := types.New(types.TSTRING)
+       str := types.Types[types.TSTRING]
        i8 := types.Types[types.TINT8]
        i64 := types.Types[types.TINT64]
        ft := mkFuncType(nil, []*types.Type{sli32, i8, sli32, i8, str, i8, i64, sli32},
@@ -313,7 +313,7 @@ func TestABIUtilsInterfaces(t *testing.T) {
        fldt := mkFuncType(types.FakeRecvType(), []*types.Type{},
                []*types.Type{types.Types[types.TSTRING]})
        field := types.NewField(src.NoXPos, typecheck.Lookup("F"), fldt)
-       nei := types.NewInterface(types.LocalPkg, []*types.Field{field})
+       nei := types.NewInterface(types.LocalPkg, []*types.Field{field}, false)
        i16 := types.Types[types.TINT16]
        tb := types.Types[types.TBOOL]
        s1 := mkstruct([]*types.Type{i16, i16, tb})
index bbdbe0c37ca6269d1e0efe117fddcf9a9cda922b..b10d37a17cfd0d242775b60ece9eaed8b30bfbb0 100644 (file)
@@ -46,6 +46,7 @@ func TestIntendedInlining(t *testing.T) {
                        "fastlog2",
                        "fastrand",
                        "float64bits",
+                       "funcspdelta",
                        "getArgInfoFast",
                        "getm",
                        "getMCache",
@@ -65,6 +66,7 @@ func TestIntendedInlining(t *testing.T) {
                        "(*bmap).keys",
                        "(*bmap).overflow",
                        "(*waitq).enqueue",
+                       "funcInfo.entry",
 
                        // GC-related ones
                        "cgoInRange",
@@ -122,9 +124,14 @@ func TestIntendedInlining(t *testing.T) {
                        "FullRune",
                        "FullRuneInString",
                        "RuneLen",
+                       "AppendRune",
                        "ValidRune",
                },
                "reflect": {
+                       "Value.CanInt",
+                       "Value.CanUint",
+                       "Value.CanFloat",
+                       "Value.CanComplex",
                        "Value.CanAddr",
                        "Value.CanSet",
                        "Value.CanInterface",
diff --git a/src/cmd/compile/internal/test/inst_test.go b/src/cmd/compile/internal/test/inst_test.go
new file mode 100644 (file)
index 0000000..951f6a0
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2021 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 test
+
+import (
+       "internal/goexperiment"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "regexp"
+       "testing"
+)
+
+// TestInst tests that only one instantiation of Sort is created, even though generic
+// Sort is used for multiple pointer types across two packages.
+func TestInst(t *testing.T) {
+       if goexperiment.Unified {
+               t.Skip("unified currently does stenciling, not dictionaries")
+       }
+       testenv.MustHaveGoBuild(t)
+       testenv.MustHaveGoRun(t)
+
+       var tmpdir string
+       var err error
+       tmpdir, err = ioutil.TempDir("", "TestDict")
+       if err != nil {
+               t.Fatalf("Failed to create temporary directory: %v", err)
+       }
+       defer os.RemoveAll(tmpdir)
+
+       // Build ptrsort.go, which uses package mysort.
+       var output []byte
+       filename := "ptrsort.go"
+       exename := "ptrsort"
+       outname := "ptrsort.out"
+       gotool := testenv.GoToolPath(t)
+       dest := filepath.Join(tmpdir, exename)
+       cmd := exec.Command(gotool, "build", "-o", dest, filepath.Join("testdata", filename))
+       if output, err = cmd.CombinedOutput(); err != nil {
+               t.Fatalf("Failed: %v:\nOutput: %s\n", err, output)
+       }
+
+       // Test that there is exactly one shape-based instantiation of Sort in
+       // the executable.
+       cmd = exec.Command(gotool, "tool", "nm", dest)
+       if output, err = cmd.CombinedOutput(); err != nil {
+               t.Fatalf("Failed: %v:\nOut: %s\n", err, output)
+       }
+       // Look for shape-based instantiation of Sort, but ignore any extra wrapper
+       // ending in "-tramp" (which are created on riscv).
+       re := regexp.MustCompile(`\bSort\[.*shape.*\][^-]`)
+       r := re.FindAllIndex(output, -1)
+       if len(r) != 1 {
+               t.Fatalf("Wanted 1 instantiations of Sort function, got %d\n", len(r))
+       }
+
+       // Actually run the test and make sure output is correct.
+       cmd = exec.Command(gotool, "run", filepath.Join("testdata", filename))
+       if output, err = cmd.CombinedOutput(); err != nil {
+               t.Fatalf("Failed: %v:\nOut: %s\n", err, output)
+       }
+       out, err := ioutil.ReadFile(filepath.Join("testdata", outname))
+       if err != nil {
+               t.Fatalf("Could not find %s\n", outname)
+       }
+       if string(out) != string(output) {
+               t.Fatalf("Wanted output %v, got %v\n", string(out), string(output))
+       }
+}
index 2f3e24c2d37ca0b6c9b6226e6611de369ff39cc9..af7d9626f95f9efb596614bf2c6061d5a502eed3 100644 (file)
@@ -162,7 +162,7 @@ func TestCode(t *testing.T) {
        }
 
        flags := []string{""}
-       if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
+       if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" || runtime.GOARCH == "386" {
                flags = append(flags, ",softfloat")
        }
        for _, flag := range flags {
diff --git a/src/cmd/compile/internal/test/testdata/mysort/mysort.go b/src/cmd/compile/internal/test/testdata/mysort/mysort.go
new file mode 100644 (file)
index 0000000..14852c8
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2021 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.
+
+// Generic sort function, tested with two different pointer types.
+
+package mysort
+
+import (
+       "fmt"
+)
+
+type LessConstraint[T any] interface {
+       Less(T) bool
+}
+
+//go:noinline
+func Sort[T LessConstraint[T]](x []T) {
+       n := len(x)
+       for i := 1; i < n; i++ {
+               for j := i; j > 0 && x[j].Less(x[j-1]); j-- {
+                       x[j], x[j-1] = x[j-1], x[j]
+               }
+       }
+}
+
+type MyInt struct {
+       Value int
+}
+
+func (a *MyInt) Less(b *MyInt) bool {
+       return a.Value < b.Value
+}
+
+//go:noinline
+func F() {
+       sl1 := []*MyInt{&MyInt{4}, &MyInt{3}, &MyInt{8}, &MyInt{7}}
+       Sort(sl1)
+       fmt.Printf("%v %v %v %v\n", sl1[0], sl1[1], sl1[2], sl1[3])
+}
diff --git a/src/cmd/compile/internal/test/testdata/ptrsort.go b/src/cmd/compile/internal/test/testdata/ptrsort.go
new file mode 100644 (file)
index 0000000..6cc7ba4
--- /dev/null
@@ -0,0 +1,30 @@
+package main
+
+// Test generic sort function with two different pointer types in different packages,
+// make sure only one instantiation is created.
+
+import (
+       "fmt"
+
+       "./mysort"
+)
+
+type MyString struct {
+       string
+}
+
+func (a *MyString) Less(b *MyString) bool {
+       return a.string < b.string
+}
+
+func main() {
+       mysort.F()
+
+       sl1 := []*mysort.MyInt{{7}, {1}, {4}, {6}}
+       mysort.Sort(sl1)
+       fmt.Printf("%v %v %v %v\n", sl1[0], sl1[1], sl1[2], sl1[3])
+
+       sl2 := []*MyString{{"when"}, {"in"}, {"the"}, {"course"}, {"of"}}
+       mysort.Sort(sl2)
+       fmt.Printf("%v %v %v %v %v\n", sl2[0], sl2[1], sl2[2], sl2[3], sl2[4])
+}
diff --git a/src/cmd/compile/internal/test/testdata/ptrsort.out b/src/cmd/compile/internal/test/testdata/ptrsort.out
new file mode 100644 (file)
index 0000000..41f1621
--- /dev/null
@@ -0,0 +1,3 @@
+&{3} &{4} &{7} &{8}
+&{1} &{4} &{6} &{7}
+&{course} &{in} &{of} &{the} &{when}
index 1c1b077423dc973c20767f0b6d96280e07899e88..fddad6e7e84b8176fd3d2865433d53d0b95236b2 100644 (file)
@@ -14,8 +14,8 @@ import (
 // the first run and then simply copied into bv at the correct offset
 // on future calls with the same type t.
 func Set(t *types.Type, off int64, bv bitvec.BitVec) {
-       if t.Align > 0 && off&int64(t.Align-1) != 0 {
-               base.Fatalf("typebits.Set: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off)
+       if uint8(t.Alignment()) > 0 && off&int64(uint8(t.Alignment())-1) != 0 {
+               base.Fatalf("typebits.Set: invalid initial alignment: type %v has alignment %d, but offset is %v", t, uint8(t.Alignment()), off)
        }
        if !t.HasPointers() {
                // Note: this case ensures that pointers to go:notinheap types
@@ -67,13 +67,13 @@ func Set(t *types.Type, off int64, bv bitvec.BitVec) {
 
        case types.TARRAY:
                elt := t.Elem()
-               if elt.Width == 0 {
+               if elt.Size() == 0 {
                        // Short-circuit for #20739.
                        break
                }
                for i := int64(0); i < t.NumElem(); i++ {
                        Set(elt, off, bv)
-                       off += elt.Width
+                       off += elt.Size()
                }
 
        case types.TSTRUCT:
index cc7f91f9372af4665131f801bf459cde47dd0aac..352f7a96ad3eac4ec468bfb6d4baf4e276a2920b 100644 (file)
@@ -99,6 +99,9 @@ func predeclared() []*types.Type {
 
                        // comparable
                        types.ComparableType,
+
+                       // any
+                       types.AnyType,
                }
        }
        return predecl
index 3f177d91732c03a601794338961d16d59b34945c..67597cebb463025cc3db34e74b052eec973b83ca 100644 (file)
@@ -176,30 +176,34 @@ var runtimeDecls = [...]struct {
        {"float64touint64", funcTag, 130},
        {"float64touint32", funcTag, 131},
        {"int64tofloat64", funcTag, 132},
-       {"uint64tofloat64", funcTag, 133},
-       {"uint32tofloat64", funcTag, 134},
-       {"complex128div", funcTag, 135},
-       {"getcallerpc", funcTag, 136},
-       {"getcallersp", funcTag, 136},
+       {"int64tofloat32", funcTag, 134},
+       {"uint64tofloat64", funcTag, 135},
+       {"uint64tofloat32", funcTag, 136},
+       {"uint32tofloat64", funcTag, 137},
+       {"complex128div", funcTag, 138},
+       {"getcallerpc", funcTag, 139},
+       {"getcallersp", funcTag, 139},
        {"racefuncenter", funcTag, 31},
        {"racefuncexit", funcTag, 9},
        {"raceread", funcTag, 31},
        {"racewrite", funcTag, 31},
-       {"racereadrange", funcTag, 137},
-       {"racewriterange", funcTag, 137},
-       {"msanread", funcTag, 137},
-       {"msanwrite", funcTag, 137},
-       {"msanmove", funcTag, 138},
-       {"checkptrAlignment", funcTag, 139},
-       {"checkptrArithmetic", funcTag, 141},
-       {"libfuzzerTraceCmp1", funcTag, 142},
-       {"libfuzzerTraceCmp2", funcTag, 143},
-       {"libfuzzerTraceCmp4", funcTag, 144},
-       {"libfuzzerTraceCmp8", funcTag, 145},
-       {"libfuzzerTraceConstCmp1", funcTag, 142},
-       {"libfuzzerTraceConstCmp2", funcTag, 143},
-       {"libfuzzerTraceConstCmp4", funcTag, 144},
-       {"libfuzzerTraceConstCmp8", funcTag, 145},
+       {"racereadrange", funcTag, 140},
+       {"racewriterange", funcTag, 140},
+       {"msanread", funcTag, 140},
+       {"msanwrite", funcTag, 140},
+       {"msanmove", funcTag, 141},
+       {"asanread", funcTag, 140},
+       {"asanwrite", funcTag, 140},
+       {"checkptrAlignment", funcTag, 142},
+       {"checkptrArithmetic", funcTag, 144},
+       {"libfuzzerTraceCmp1", funcTag, 145},
+       {"libfuzzerTraceCmp2", funcTag, 146},
+       {"libfuzzerTraceCmp4", funcTag, 147},
+       {"libfuzzerTraceCmp8", funcTag, 148},
+       {"libfuzzerTraceConstCmp1", funcTag, 145},
+       {"libfuzzerTraceConstCmp2", funcTag, 146},
+       {"libfuzzerTraceConstCmp4", funcTag, 147},
+       {"libfuzzerTraceConstCmp8", funcTag, 148},
        {"x86HasPOPCNT", varTag, 6},
        {"x86HasSSE41", varTag, 6},
        {"x86HasFMA", varTag, 6},
@@ -222,7 +226,7 @@ func params(tlist ...*types.Type) []*types.Field {
 }
 
 func runtimeTypes() []*types.Type {
-       var typs [146]*types.Type
+       var typs [149]*types.Type
        typs[0] = types.ByteType
        typs[1] = types.NewPtr(typs[0])
        typs[2] = types.Types[types.TANY]
@@ -356,18 +360,21 @@ func runtimeTypes() []*types.Type {
        typs[130] = newSig(params(typs[20]), params(typs[24]))
        typs[131] = newSig(params(typs[20]), params(typs[62]))
        typs[132] = newSig(params(typs[22]), params(typs[20]))
-       typs[133] = newSig(params(typs[24]), params(typs[20]))
-       typs[134] = newSig(params(typs[62]), params(typs[20]))
-       typs[135] = newSig(params(typs[26], typs[26]), params(typs[26]))
-       typs[136] = newSig(nil, params(typs[5]))
-       typs[137] = newSig(params(typs[5], typs[5]), nil)
-       typs[138] = newSig(params(typs[5], typs[5], typs[5]), nil)
-       typs[139] = newSig(params(typs[7], typs[1], typs[5]), nil)
-       typs[140] = types.NewSlice(typs[7])
-       typs[141] = newSig(params(typs[7], typs[140]), nil)
-       typs[142] = newSig(params(typs[66], typs[66]), nil)
-       typs[143] = newSig(params(typs[60], typs[60]), nil)
-       typs[144] = newSig(params(typs[62], typs[62]), nil)
-       typs[145] = newSig(params(typs[24], typs[24]), nil)
+       typs[133] = types.Types[types.TFLOAT32]
+       typs[134] = newSig(params(typs[22]), params(typs[133]))
+       typs[135] = newSig(params(typs[24]), params(typs[20]))
+       typs[136] = newSig(params(typs[24]), params(typs[133]))
+       typs[137] = newSig(params(typs[62]), params(typs[20]))
+       typs[138] = newSig(params(typs[26], typs[26]), params(typs[26]))
+       typs[139] = newSig(nil, params(typs[5]))
+       typs[140] = newSig(params(typs[5], typs[5]), nil)
+       typs[141] = newSig(params(typs[5], typs[5], typs[5]), nil)
+       typs[142] = newSig(params(typs[7], typs[1], typs[5]), nil)
+       typs[143] = types.NewSlice(typs[7])
+       typs[144] = newSig(params(typs[7], typs[143]), nil)
+       typs[145] = newSig(params(typs[66], typs[66]), nil)
+       typs[146] = newSig(params(typs[60], typs[60]), nil)
+       typs[147] = newSig(params(typs[62], typs[62]), nil)
+       typs[148] = newSig(params(typs[24], typs[24]), nil)
        return typs[:]
 }
index 605b9042880ca2e18fdee04d7b4048d89c6a071d..04ae4f23a387790c11cc5d9e98360c55beff5019 100644 (file)
@@ -227,7 +227,9 @@ func float64toint64(float64) int64
 func float64touint64(float64) uint64
 func float64touint32(float64) uint32
 func int64tofloat64(int64) float64
+func int64tofloat32(int64) float32
 func uint64tofloat64(uint64) float64
+func uint64tofloat32(uint64) float32
 func uint32tofloat64(uint32) float64
 
 func complex128div(num complex128, den complex128) (quo complex128)
@@ -248,6 +250,10 @@ func msanread(addr, size uintptr)
 func msanwrite(addr, size uintptr)
 func msanmove(dst, src, size uintptr)
 
+// address sanitizer
+func asanread(addr, size uintptr)
+func asanwrite(addr, size uintptr)
+
 func checkptrAlignment(unsafe.Pointer, *byte, uintptr)
 func checkptrArithmetic(unsafe.Pointer, []unsafe.Pointer)
 
index f8150d249a61c624d328814a9288fbb3ad2fb2ca..fbe7c02c49821eb587ea97bf5e27b9f507e3bff6 100644 (file)
@@ -874,14 +874,16 @@ func evalunsafe(n ir.Node) int64 {
                }
                types.CalcSize(tr)
                if n.Op() == ir.OALIGNOF {
-                       return int64(tr.Align)
+                       return tr.Alignment()
                }
-               return tr.Width
+               return tr.Size()
 
        case ir.OOFFSETOF:
                // must be a selector.
                n := n.(*ir.UnaryExpr)
-               if n.X.Op() != ir.OXDOT {
+               // ODOT and ODOTPTR are allowed in case the OXDOT transformation has
+               // already happened (e.g. during -G=3 stenciling).
+               if n.X.Op() != ir.OXDOT && n.X.Op() != ir.ODOT && n.X.Op() != ir.ODOTPTR {
                        base.Errorf("invalid expression %v", n)
                        return 0
                }
index 9a348b9f37401dc28a557192486eaa5893390dbf..ae2b3b1df4e1ca8d95692533071e71128cf6d325 100644 (file)
@@ -10,14 +10,17 @@ import (
        "cmd/compile/internal/types"
 )
 
-// crawlExports crawls the type/object graph rooted at the given list
-// of exported objects. Any functions that are found to be potentially
-// callable by importers are marked with ExportInline so that
-// iexport.go knows to re-export their inline body.
+// crawlExports crawls the type/object graph rooted at the given list of exported
+// objects. It descends through all parts of types and follows any methods on defined
+// types. Any functions that are found to be potentially callable by importers are
+// marked with ExportInline, so that iexport.go knows to re-export their inline body.
+// Also, any function or global referenced by a function marked by ExportInline() is
+// marked for export (whether its name is exported or not).
 func crawlExports(exports []*ir.Name) {
        p := crawler{
                marked:   make(map[*types.Type]bool),
                embedded: make(map[*types.Type]bool),
+               generic:  make(map[*types.Type]bool),
        }
        for _, n := range exports {
                p.markObject(n)
@@ -27,9 +30,10 @@ func crawlExports(exports []*ir.Name) {
 type crawler struct {
        marked   map[*types.Type]bool // types already seen by markType
        embedded map[*types.Type]bool // types already seen by markEmbed
+       generic  map[*types.Type]bool // types already seen by markGeneric
 }
 
-// markObject visits a reachable object.
+// markObject visits a reachable object (function, method, global type, or global variable)
 func (p *crawler) markObject(n *ir.Name) {
        if n.Op() == ir.ONAME && n.Class == ir.PFUNC {
                p.markInlBody(n)
@@ -44,12 +48,13 @@ func (p *crawler) markObject(n *ir.Name) {
        p.markType(n.Type())
 }
 
-// markType recursively visits types reachable from t to identify
-// functions whose inline bodies may be needed.
+// markType recursively visits types reachable from t to identify functions whose
+// inline bodies may be needed. For instantiated generic types, it visits the base
+// generic type, which has the relevant methods.
 func (p *crawler) markType(t *types.Type) {
-       if t.IsInstantiatedGeneric() {
-               // Re-instantiated types don't add anything new, so don't follow them.
-               return
+       if t.OrigSym() != nil {
+               // Convert to the base generic type.
+               t = t.OrigSym().Def.Type()
        }
        if p.marked[t] {
                return
@@ -92,8 +97,16 @@ func (p *crawler) markType(t *types.Type) {
                p.markType(t.Elem())
 
        case types.TSTRUCT:
+               if t.IsFuncArgStruct() {
+                       break
+               }
                for _, f := range t.FieldSlice() {
-                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
+                       // Mark the type of a unexported field if it is a
+                       // fully-instantiated type, since we create and instantiate
+                       // the methods of any fully-instantiated type that we see
+                       // during import (see end of typecheck.substInstType).
+                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 ||
+                               isPtrFullyInstantiated(f.Type) {
                                p.markType(f.Type)
                        }
                }
@@ -104,8 +117,6 @@ func (p *crawler) markType(t *types.Type) {
                }
 
        case types.TINTER:
-               // TODO(danscales) - will have to deal with the types in interface
-               // elements here when implemented in types2 and represented in types1.
                for _, f := range t.AllMethods().Slice() {
                        if types.IsExported(f.Sym.Name) {
                                p.markType(f.Type)
@@ -129,9 +140,9 @@ func (p *crawler) markEmbed(t *types.Type) {
                t = t.Elem()
        }
 
-       if t.IsInstantiatedGeneric() {
-               // Re-instantiated types don't add anything new, so don't follow them.
-               return
+       if t.OrigSym() != nil {
+               // Convert to the base generic type.
+               t = t.OrigSym().Def.Type()
        }
 
        if p.embedded[t] {
@@ -159,6 +170,30 @@ func (p *crawler) markEmbed(t *types.Type) {
        }
 }
 
+// markGeneric takes an instantiated type or a base generic type t, and
+// marks all the methods of the base generic type of t. If a base generic
+// type is written to export file, even if not explicitly marked for export,
+// all of its methods need to be available for instantiation if needed.
+func (p *crawler) markGeneric(t *types.Type) {
+       if t.IsPtr() {
+               t = t.Elem()
+       }
+       if t.OrigSym() != nil {
+               // Convert to the base generic type.
+               t = t.OrigSym().Def.Type()
+       }
+       if p.generic[t] {
+               return
+       }
+       p.generic[t] = true
+
+       if t.Sym() != nil && t.Kind() != types.TINTER {
+               for _, m := range t.Methods().Slice() {
+                       p.markObject(m.Nname.(*ir.Name))
+               }
+       }
+}
+
 // markInlBody marks n's inline body for export and recursively
 // ensures all called functions are marked too.
 func (p *crawler) markInlBody(n *ir.Name) {
@@ -185,10 +220,37 @@ func (p *crawler) markInlBody(n *ir.Name) {
 
        var doFlood func(n ir.Node)
        doFlood = func(n ir.Node) {
+               t := n.Type()
+               if t != nil {
+                       if t.HasTParam() || t.IsFullyInstantiated() {
+                               p.markGeneric(t)
+                       }
+                       if base.Debug.Unified == 0 {
+                               // If a method of un-exported type is promoted and accessible by
+                               // embedding in an exported type, it makes that type reachable.
+                               //
+                               // Example:
+                               //
+                               //     type t struct {}
+                               //     func (t) M() {}
+                               //
+                               //     func F() interface{} { return struct{ t }{} }
+                               //
+                               // We generate the wrapper for "struct{ t }".M, and inline call
+                               // to "struct{ t }".M, which makes "t.M" reachable.
+                               if t.IsStruct() {
+                                       for _, f := range t.FieldSlice() {
+                                               if f.Embedded != 0 {
+                                                       p.markEmbed(f.Type)
+                                               }
+                                       }
+                               }
+                       }
+               }
+
                switch n.Op() {
                case ir.OMETHEXPR, ir.ODOTMETH:
                        p.markInlBody(ir.MethodExprName(n))
-
                case ir.ONAME:
                        n := n.(*ir.Name)
                        switch n.Class {
@@ -198,9 +260,6 @@ func (p *crawler) markInlBody(n *ir.Name) {
                        case ir.PEXTERN:
                                Export(n)
                        }
-                       p.checkGenericType(n.Type())
-               case ir.OTYPE:
-                       p.checkGenericType(n.Type())
                case ir.OMETHVALUE:
                        // Okay, because we don't yet inline indirect
                        // calls to method values.
@@ -217,15 +276,9 @@ func (p *crawler) markInlBody(n *ir.Name) {
        ir.VisitList(fn.Inl.Body, doFlood)
 }
 
-// checkGenerictype ensures that we call markType() on any base generic type that
-// is written to the export file (even if not explicitly marked
-// for export), so its methods will be available for inlining if needed.
-func (p *crawler) checkGenericType(t *types.Type) {
-       if t != nil && t.HasTParam() {
-               if t.OrigSym != nil {
-                       // Convert to the base generic type.
-                       t = t.OrigSym.Def.Type()
-               }
-               p.markType(t)
-       }
+// isPtrFullyInstantiated returns true if t is a fully-instantiated type, or it is a
+// pointer to a fully-instantiated type.
+func isPtrFullyInstantiated(t *types.Type) bool {
+       return t.IsPtr() && t.Elem().IsFullyInstantiated() ||
+               t.IsFullyInstantiated()
 }
index 11e20f0f0762e96c2f7919cd3ec9220b912ad6d0..68ab05a538e8fd52e56686892025dab8e59663e1 100644 (file)
@@ -314,13 +314,6 @@ func checkembeddedtype(t *types.Type) {
        }
 }
 
-// TODO(mdempsky): Move to package types.
-func FakeRecv() *types.Field {
-       return types.NewField(src.NoXPos, nil, types.FakeRecvType())
-}
-
-var fakeRecvField = FakeRecv
-
 var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext
 
 type funcStackEnt struct {
@@ -367,8 +360,7 @@ func funcargs(nt *ir.FuncType) {
                if n.Sym == nil {
                        // Name so that escape analysis can track it. ~r stands for 'result'.
                        n.Sym = LookupNum("~r", i)
-               }
-               if n.Sym.IsBlank() {
+               } else if n.Sym.IsBlank() {
                        // Give it a name so we can assign to it during return. ~b stands for 'blank'.
                        // The name must be different from ~r above because if you have
                        //      func f() (_ int)
@@ -479,6 +471,12 @@ func autotmpname(n int) string {
 // f is method type, with receiver.
 // return function type, receiver as first argument (or not).
 func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
+       if sig.HasTParam() {
+               base.Fatalf("NewMethodType with type parameters in signature %+v", sig)
+       }
+       if recv != nil && recv.HasTParam() {
+               base.Fatalf("NewMethodType with type parameters in receiver %+v", recv)
+       }
        nrecvs := 0
        if recv != nil {
                nrecvs++
index 7e974dfda863a0bc378d68fc0be98a8ec30bb222..9b74bf7a9d3762ce60c7fbc414fc9e2770885fcd 100644 (file)
@@ -77,10 +77,6 @@ func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
        return l, r, t
 }
 
-func IsCmp(op ir.Op) bool {
-       return iscmp[op]
-}
-
 // tcArith typechecks operands of a binary arithmetic expression.
 // The result of tcArith MUST be assigned back to original operands,
 // t is the type of the expression, and should be set by the caller. e.g:
@@ -96,7 +92,7 @@ func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type)
                t = r.Type()
        }
        aop := ir.OXXX
-       if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
+       if n.Op().IsCmp() && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
                // comparison is okay as long as one side is
                // assignable to the other.  convert so they have
                // the same type.
@@ -114,7 +110,7 @@ func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type)
                                }
 
                                types.CalcSize(l.Type())
-                               if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
+                               if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Size() >= 1<<16 {
                                        l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
                                        l.SetTypecheck(1)
                                }
@@ -133,7 +129,7 @@ func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type)
                                }
 
                                types.CalcSize(r.Type())
-                               if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
+                               if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Size() >= 1<<16 {
                                        r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
                                        r.SetTypecheck(1)
                                }
index 75b4931c310b272096e4a18cf5f87b88d55eee42..f685851e40c370031339827b04b3cea345d341e9 100644 (file)
@@ -63,8 +63,9 @@
 //     }
 //
 //     type Func struct {
-//         Tag       byte // 'F'
+//         Tag       byte // 'F' or 'G'
 //         Pos       Pos
+//         TypeParams []typeOff  // only present if Tag == 'G'
 //         Signature Signature
 //     }
 //
@@ -75,8 +76,9 @@
 //     }
 //
 //     type Type struct {
-//         Tag        byte // 'T'
+//         Tag        byte // 'T' or 'U'
 //         Pos        Pos
+//         TypeParams []typeOff  // only present if Tag == 'U'
 //         Underlying typeOff
 //
 //         Methods []struct{  // omitted if Underlying is an interface type
 //         Type typeOff
 //     }
 //
+//     // "Automatic" declaration of each typeparam
+//     type TypeParam struct {
+//         Tag        byte // 'P'
+//         Pos        Pos
+//         Implicit   bool
+//         Constraint typeOff
+//     }
 //
 // typeOff means a uvarint that either indicates a predeclared type,
 // or an offset into the Data section. If the uvarint is less than
 // types list (see predeclared in bexport.go for order). Otherwise,
 // subtracting predeclReserved yields the offset of a type descriptor.
 //
-// Value means a type and type-specific value. See
+// Value means a type, kind, and type-specific value. See
 // (*exportWriter).value for details.
 //
 //
-// There are nine kinds of type descriptors, distinguished by an itag:
+// There are twelve kinds of type descriptors, distinguished by an itag:
 //
 //     type DefinedType struct {
 //         Tag     itag // definedType
 //         }
 //     }
 //
+//     // Reference to a type param declaration
+//     type TypeParamType struct {
+//         Tag     itag // typeParamType
+//         Name    stringOff
+//         PkgPath stringOff
+//     }
+//
+//     // Instantiation of a generic type (like List[T2] or List[int])
+//     type InstanceType struct {
+//         Tag     itag // instanceType
+//         Pos     pos
+//         TypeArgs []typeOff
+//         BaseType typeOff
+//     }
+//
+//     type UnionType struct {
+//         Tag     itag // interfaceType
+//         Terms   []struct {
+//             tilde bool
+//             Type  typeOff
+//         }
+//     }
+//
 //
-//  TODO(danscales): fill in doc for 'type TypeParamType' and 'type InstType'
 //
 //     type Signature struct {
 //         Params   []Param
@@ -224,15 +255,16 @@ import (
 // Current indexed export format version. Increase with each format change.
 // 0: Go1.11 encoding
 // 1: added column details to Pos
-// 2: added information for generic function/types (currently unstable)
+// 2: added information for generic function/types.  The export of non-generic
+// functions/types remains largely backward-compatible.  Breaking changes include:
+//    - a 'kind' byte is added to constant values
 const (
-       iexportVersionGo1_11 = 0
-       iexportVersionPosCol = 1
-       // TODO: before release, change this back to 2.  Kept at previous version
-       // for now (for testing).
-       iexportVersionGenerics = iexportVersionPosCol
+       iexportVersionGo1_11   = 0
+       iexportVersionPosCol   = 1
+       iexportVersionGenerics = 1 // probably change to 2 before release
+       iexportVersionGo1_18   = 2
 
-       iexportVersionCurrent = iexportVersionGenerics
+       iexportVersionCurrent = 2
 )
 
 // predeclReserved is the number of type offsets reserved for types
@@ -255,7 +287,7 @@ const (
        structType
        interfaceType
        typeParamType
-       instType
+       instanceType // Instantiation of a generic type
        unionType
 )
 
@@ -430,7 +462,7 @@ func (p *iexporter) pushDecl(n *ir.Name) {
        }
 
        // Don't export predeclared declarations.
-       if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == ir.Pkgs.Unsafe {
+       if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == types.UnsafePkg {
                return
        }
 
@@ -531,6 +563,10 @@ func (p *iexporter) doDecl(n *ir.Name) {
                        // A typeparam has a name, and has a type bound rather
                        // than an underlying type.
                        w.pos(n.Pos())
+                       if iexportVersionCurrent >= iexportVersionGo1_18 {
+                               implicit := n.Type().Bound().IsImplicit()
+                               w.bool(implicit)
+                       }
                        w.typ(n.Type().Bound())
                        break
                }
@@ -566,6 +602,14 @@ func (p *iexporter) doDecl(n *ir.Name) {
                        // for predeclared objects).
                        underlying = types.ErrorType
                }
+               if underlying == types.ComparableType.Underlying() {
+                       // Do same for ComparableType as for ErrorType.
+                       underlying = types.ComparableType
+               }
+               if base.Flag.G > 0 && underlying == types.AnyType.Underlying() {
+                       // Do same for AnyType as for ErrorType.
+                       underlying = types.AnyType
+               }
                w.typ(underlying)
 
                t := n.Type()
@@ -578,7 +622,9 @@ func (p *iexporter) doDecl(n *ir.Name) {
 
                // Sort methods, for consistency with types2.
                methods := append([]*types.Field(nil), t.Methods().Slice()...)
-               sort.Sort(types.MethodsByName(methods))
+               if base.Debug.UnifiedQuirks != 0 {
+                       sort.Sort(types.MethodsByName(methods))
+               }
 
                w.uint64(uint64(len(methods)))
                for _, m := range methods {
@@ -876,14 +922,14 @@ func (w *exportWriter) startType(k itag) {
 
 func (w *exportWriter) doTyp(t *types.Type) {
        s := t.Sym()
-       if s != nil && t.OrigSym != nil {
+       if s != nil && t.OrigSym() != nil {
                assert(base.Flag.G > 0)
                // This is an instantiated type - could be a re-instantiation like
                // Value[T2] or a full instantiation like Value[int].
                if strings.Index(s.Name, "[") < 0 {
                        base.Fatalf("incorrect name for instantiated type")
                }
-               w.startType(instType)
+               w.startType(instanceType)
                w.pos(t.Pos())
                // Export the type arguments for the instantiated type. The
                // instantiated type could be in a method header (e.g. "func (v
@@ -893,7 +939,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
                // types or existing typeparams from the function/method header.
                w.typeList(t.RParams())
                // Export a reference to the base type.
-               baseType := t.OrigSym.Def.(*ir.Name).Type()
+               baseType := t.OrigSym().Def.(*ir.Name).Type()
                w.typ(baseType)
                return
        }
@@ -903,7 +949,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
        // type orderedAbs[T any] T
        if t.IsTypeParam() && t.Underlying() == t {
                assert(base.Flag.G > 0)
-               if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe {
+               if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
                        base.Fatalf("builtin type missing from typIndex: %v", t)
                }
                // Write out the first use of a type param as a qualified ident.
@@ -914,7 +960,7 @@ func (w *exportWriter) doTyp(t *types.Type) {
        }
 
        if s != nil {
-               if s.Pkg == types.BuiltinPkg || s.Pkg == ir.Pkgs.Unsafe {
+               if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
                        base.Fatalf("builtin type missing from typIndex: %v", t)
                }
 
@@ -978,8 +1024,10 @@ func (w *exportWriter) doTyp(t *types.Type) {
                // Sort methods and embedded types, for consistency with types2.
                // Note: embedded types may be anonymous, and types2 sorts them
                // with sort.Stable too.
-               sort.Sort(types.MethodsByName(methods))
-               sort.Stable(types.EmbeddedsByName(embeddeds))
+               if base.Debug.UnifiedQuirks != 0 {
+                       sort.Sort(types.MethodsByName(methods))
+                       sort.Stable(types.EmbeddedsByName(embeddeds))
+               }
 
                w.startType(interfaceType)
                w.setPkg(t.Pkg(), true)
@@ -1095,17 +1143,24 @@ func constTypeOf(typ *types.Type) constant.Kind {
 
 func (w *exportWriter) value(typ *types.Type, v constant.Value) {
        w.typ(typ)
+
+       if iexportVersionCurrent >= iexportVersionGo1_18 {
+               w.int64(int64(v.Kind()))
+       }
+
        var kind constant.Kind
        var valType *types.Type
 
        if typ.IsTypeParam() {
-               // A constant will have a TYPEPARAM type if it appears in a place
-               // where it must match that typeparam type (e.g. in a binary
-               // operation with a variable of that typeparam type). If so, then
-               // we must write out its actual constant kind as well, so its
-               // constant val can be read in properly during import.
                kind = v.Kind()
-               w.int64(int64(kind))
+               if iexportVersionCurrent < iexportVersionGo1_18 {
+                       // A constant will have a TYPEPARAM type if it appears in a place
+                       // where it must match that typeparam type (e.g. in a binary
+                       // operation with a variable of that typeparam type). If so, then
+                       // we must write out its actual constant kind as well, so its
+                       // constant val can be read in properly during import.
+                       w.int64(int64(kind))
+               }
 
                switch kind {
                case constant.Int:
@@ -1444,10 +1499,23 @@ func (w *exportWriter) node(n ir.Node) {
        }
 }
 
-// Caution: stmt will emit more than one node for statement nodes n that have a non-empty
-// n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
+func isNonEmptyAssign(n ir.Node) bool {
+       switch n.Op() {
+       case ir.OAS:
+               if n.(*ir.AssignStmt).Y != nil {
+                       return true
+               }
+       case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
+               return true
+       }
+       return false
+}
+
+// Caution: stmt will emit more than one node for statement nodes n that have a
+// non-empty n.Ninit and where n is not a non-empty assignment or a node with a natural init
+// section (such as in "if", "for", etc.).
 func (w *exportWriter) stmt(n ir.Node) {
-       if len(n.Init()) > 0 && !ir.StmtWithInit(n.Op()) {
+       if len(n.Init()) > 0 && !ir.StmtWithInit(n.Op()) && !isNonEmptyAssign(n) && n.Op() != ir.ORANGE {
                // can't use stmtList here since we don't want the final OEND
                for _, n := range n.Init() {
                        w.stmt(n)
@@ -1483,8 +1551,10 @@ func (w *exportWriter) stmt(n ir.Node) {
                if n.Y != nil {
                        w.op(ir.OAS)
                        w.pos(n.Pos())
+                       w.stmtList(n.Init())
                        w.expr(n.X)
                        w.expr(n.Y)
+                       w.bool(n.Def)
                }
 
        case ir.OASOP:
@@ -1505,8 +1575,10 @@ func (w *exportWriter) stmt(n ir.Node) {
                        w.op(ir.OAS2)
                }
                w.pos(n.Pos())
+               w.stmtList(n.Init())
                w.exprList(n.Lhs)
                w.exprList(n.Rhs)
+               w.bool(n.Def)
 
        case ir.ORETURN:
                n := n.(*ir.ReturnStmt)
@@ -1544,6 +1616,7 @@ func (w *exportWriter) stmt(n ir.Node) {
                n := n.(*ir.RangeStmt)
                w.op(ir.ORANGE)
                w.pos(n.Pos())
+               w.stmtList(n.Init())
                w.exprsOrNil(n.Key, n.Value)
                w.expr(n.X)
                w.stmtList(n.Body)
@@ -1680,18 +1753,42 @@ func (w *exportWriter) expr(n ir.Node) {
                isBuiltin := n.BuiltinOp != ir.OXXX
                w.bool(isBuiltin)
                if isBuiltin {
+                       w.bool(n.Sym().Pkg == types.UnsafePkg)
                        w.string(n.Sym().Name)
                        break
                }
                w.localName(n)
 
-       // case OPACK, ONONAME:
+       case ir.ONONAME:
+               w.op(ir.ONONAME)
+               // This should only be for OKEY nodes in generic functions
+               s := n.Sym()
+               w.string(s.Name)
+               w.pkg(s.Pkg)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
+
+       // case OPACK:
        //      should have been resolved by typechecking - handled by default case
 
        case ir.OTYPE:
                w.op(ir.OTYPE)
                w.typ(n.Type())
 
+       case ir.ODYNAMICTYPE:
+               n := n.(*ir.DynamicType)
+               w.op(ir.ODYNAMICTYPE)
+               w.pos(n.Pos())
+               w.expr(n.X)
+               if n.ITab != nil {
+                       w.bool(true)
+                       w.expr(n.ITab)
+               } else {
+                       w.bool(false)
+               }
+               w.typ(n.Type())
+
        case ir.OTYPESW:
                n := n.(*ir.TypeSwitchGuard)
                w.op(ir.OTYPESW)
@@ -1757,7 +1854,7 @@ func (w *exportWriter) expr(n ir.Node) {
                w.typ(n.Type())
                w.fieldList(n.List) // special handling of field names
 
-       case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
+       case ir.OCOMPLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
                n := n.(*ir.CompLitExpr)
                if go117ExportTypes {
                        w.op(n.Op())
@@ -1817,6 +1914,14 @@ func (w *exportWriter) expr(n ir.Node) {
                w.expr(n.X)
                w.typ(n.Type())
 
+       case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
+               n := n.(*ir.DynamicTypeAssertExpr)
+               w.op(n.Op())
+               w.pos(n.Pos())
+               w.expr(n.X)
+               w.expr(n.T)
+               w.typ(n.Type())
+
        case ir.OINDEX, ir.OINDEXMAP:
                n := n.(*ir.IndexExpr)
                if go117ExportTypes {
@@ -2052,8 +2157,10 @@ func (w *exportWriter) expr(n ir.Node) {
                n := n.(*ir.AssignListStmt)
                w.op(ir.OSELRECV2)
                w.pos(n.Pos())
+               w.stmtList(n.Init())
                w.exprList(n.Lhs)
                w.exprList(n.Rhs)
+               w.bool(n.Def)
 
        default:
                base.Fatalf("cannot export %v (%d) node\n"+
@@ -2133,7 +2240,7 @@ func (w *exportWriter) localIdent(s *types.Sym) {
                return
        }
 
-       if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".dict") { // TODO: just use autotmp names for dictionaries?
+       if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, LocalDictName) {
                base.Fatalf("unexpected dot in identifier: %v", name)
        }
 
@@ -2169,3 +2276,6 @@ func (w *intWriter) uint64(x uint64) {
 // information (e.g. length field for OSLICELIT).
 const go117ExportTypes = true
 const Go117ExportTypes = go117ExportTypes
+
+// The name used for dictionary parameters or local variables.
+const LocalDictName = ".dict"
index 2e3fdbc1bc99b365bc8524a1742f95a23ae75f04..7c6c23e73714515a322c25c20c2672223d398236 100644 (file)
@@ -8,7 +8,6 @@
 package typecheck
 
 import (
-       "bytes"
        "encoding/binary"
        "fmt"
        "go/constant"
@@ -119,13 +118,9 @@ func ReadImports(pkg *types.Pkg, data string) {
 
        version := ird.uint64()
        switch version {
-       case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11:
+       case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
        default:
-               if version > iexportVersionGenerics {
-                       base.Errorf("import %q: unstable export format version %d, just recompile", pkg.Path, version)
-               } else {
-                       base.Errorf("import %q: unknown export format version %d", pkg.Path, version)
-               }
+               base.Errorf("import %q: unknown export format version %d", pkg.Path, version)
                base.ErrorExit()
        }
 
@@ -177,7 +172,7 @@ func ReadImports(pkg *types.Pkg, data string) {
                }
 
                for nSyms := ird.uint64(); nSyms > 0; nSyms-- {
-                       s := pkg.Lookup(p.stringAt(ird.uint64()))
+                       s := pkg.Lookup(p.nameAt(ird.uint64()))
                        off := ird.uint64()
 
                        if _, ok := DeclImporter[s]; !ok {
@@ -191,7 +186,7 @@ func ReadImports(pkg *types.Pkg, data string) {
                pkg := p.pkgAt(ird.uint64())
 
                for nSyms := ird.uint64(); nSyms > 0; nSyms-- {
-                       s := pkg.Lookup(p.stringAt(ird.uint64()))
+                       s := pkg.Lookup(p.nameAt(ird.uint64()))
                        off := ird.uint64()
 
                        if _, ok := inlineImporter[s]; !ok {
@@ -225,6 +220,22 @@ func (p *iimporter) stringAt(off uint64) string {
        return p.stringData[spos : spos+slen]
 }
 
+// nameAt is the same as stringAt, except it replaces instances
+// of "" with the path of the package being imported.
+func (p *iimporter) nameAt(off uint64) string {
+       s := p.stringAt(off)
+       // Names of objects (functions, methods, globals) may include ""
+       // to represent the path name of the imported package.
+       // Replace "" with the imported package prefix. This occurs
+       // specifically for generics where the names of instantiations
+       // and dictionaries contain package-qualified type names.
+       // Include the dot to avoid matching with struct tags ending in '"'.
+       if strings.Contains(s, "\"\".") {
+               s = strings.Replace(s, "\"\".", p.ipkg.Prefix+".", -1)
+       }
+       return s
+}
+
 func (p *iimporter) posBaseAt(off uint64) *src.PosBase {
        if posBase, ok := p.posBaseCache[off]; ok {
                return posBase
@@ -280,6 +291,7 @@ func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
 }
 
 func (r *importReader) string() string        { return r.p.stringAt(r.uint64()) }
+func (r *importReader) name() string          { return r.p.nameAt(r.uint64()) }
 func (r *importReader) posBase() *src.PosBase { return r.p.posBaseAt(r.uint64()) }
 func (r *importReader) pkg() *types.Pkg       { return r.p.pkgAt(r.uint64()) }
 
@@ -317,16 +329,12 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
                return n
 
        case 'T', 'U':
-               var rparams []*types.Type
-               if tag == 'U' {
-                       rparams = r.typeList()
-               }
-
                // Types can be recursive. We need to setup a stub
                // declaration before recursing.
                n := importtype(pos, sym)
                t := n.Type()
                if tag == 'U' {
+                       rparams := r.typeList()
                        t.SetRParams(rparams)
                }
 
@@ -396,8 +404,15 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
                sym.Def = nname
                nname.SetType(t)
                t.SetNod(nname)
-
-               t.SetBound(r.typ())
+               implicit := false
+               if r.p.exportVersion >= iexportVersionGo1_18 {
+                       implicit = r.bool()
+               }
+               bound := r.typ()
+               if implicit {
+                       bound.MarkImplicit()
+               }
+               t.SetBound(bound)
                return nname
 
        case 'V':
@@ -417,10 +432,17 @@ func (r *importReader) value(typ *types.Type) constant.Value {
        var kind constant.Kind
        var valType *types.Type
 
-       if typ.IsTypeParam() {
-               // If a constant had a typeparam type, then we wrote out its
-               // actual constant kind as well.
+       if r.p.exportVersion >= iexportVersionGo1_18 {
+               // TODO: add support for using the kind in the non-typeparam case.
                kind = constant.Kind(r.int64())
+       }
+
+       if typ.IsTypeParam() {
+               if r.p.exportVersion < iexportVersionGo1_18 {
+                       // If a constant had a typeparam type, then we wrote out its
+                       // actual constant kind as well.
+                       kind = constant.Kind(r.int64())
+               }
                switch kind {
                case constant.Int:
                        valType = types.Types[types.TINT64]
@@ -535,7 +557,7 @@ func (r *importReader) localIdent() *types.Sym { return r.ident(false) }
 func (r *importReader) selector() *types.Sym   { return r.ident(true) }
 
 func (r *importReader) qualifiedIdent() *ir.Ident {
-       name := r.string()
+       name := r.name()
        pkg := r.pkg()
        sym := pkg.Lookup(name)
        return ir.NewIdent(src.NoXPos, sym)
@@ -608,7 +630,7 @@ func (r *importReader) exoticType() *types.Type {
        case exoticTypeRecv:
                var rcvr *types.Field
                if r.bool() { // isFakeRecv
-                       rcvr = fakeRecvField()
+                       rcvr = types.FakeRecv()
                } else {
                        rcvr = r.exoticParam()
                }
@@ -715,7 +737,7 @@ func (p *iimporter) typAt(off uint64) *types.Type {
                // No need to calc sizes for re-instantiated generic types, and
                // they are not necessarily resolved until the top-level type is
                // defined (because of recursive types).
-               if t.OrigSym == nil || !t.HasTParam() {
+               if t.OrigSym() == nil || !t.HasTParam() {
                        types.CheckSize(t)
                }
                p.typCache[off] = t
@@ -794,7 +816,7 @@ func (r *importReader) typ1() *types.Type {
                for i := range methods {
                        pos := r.pos()
                        sym := r.selector()
-                       typ := r.signature(fakeRecvField(), nil)
+                       typ := r.signature(types.FakeRecv(), nil)
 
                        methods[i] = types.NewField(pos, sym, typ)
                }
@@ -803,7 +825,7 @@ func (r *importReader) typ1() *types.Type {
                        return types.Types[types.TINTER]
                }
 
-               t := types.NewInterface(r.currPkg, append(embeddeds, methods...))
+               t := types.NewInterface(r.currPkg, append(embeddeds, methods...), false)
 
                // Ensure we expand the interface in the frontend (#25055).
                types.CheckSize(t)
@@ -826,7 +848,7 @@ func (r *importReader) typ1() *types.Type {
                }
                return n.Type()
 
-       case instType:
+       case instanceType:
                if r.p.exportVersion < iexportVersionGenerics {
                        base.Fatalf("unexpected instantiation type")
                }
@@ -1171,10 +1193,26 @@ func (r *importReader) stmtList() []ir.Node {
                if n.Op() == ir.OBLOCK {
                        n := n.(*ir.BlockStmt)
                        list = append(list, n.List...)
-               } else {
-                       list = append(list, n)
+                       continue
                }
-
+               if len(list) > 0 {
+                       // check for an optional label that can only immediately
+                       // precede a for/range/select/switch statement.
+                       if last := list[len(list)-1]; last.Op() == ir.OLABEL {
+                               label := last.(*ir.LabelStmt).Label
+                               switch n.Op() {
+                               case ir.OFOR:
+                                       n.(*ir.ForStmt).Label = label
+                               case ir.ORANGE:
+                                       n.(*ir.RangeStmt).Label = label
+                               case ir.OSELECT:
+                                       n.(*ir.SelectStmt).Label = label
+                               case ir.OSWITCH:
+                                       n.(*ir.SwitchStmt).Label = label
+                               }
+                       }
+               }
+               list = append(list, n)
        }
        return list
 }
@@ -1270,7 +1308,11 @@ func (r *importReader) node() ir.Node {
        case ir.ONAME:
                isBuiltin := r.bool()
                if isBuiltin {
-                       return types.BuiltinPkg.Lookup(r.string()).Def.(*ir.Name)
+                       pkg := types.BuiltinPkg
+                       if r.bool() {
+                               pkg = types.UnsafePkg
+                       }
+                       return pkg.Lookup(r.string()).Def.(*ir.Name)
                }
                return r.localName()
 
@@ -1280,6 +1322,14 @@ func (r *importReader) node() ir.Node {
        case ir.OTYPE:
                return ir.TypeNode(r.typ())
 
+       case ir.ODYNAMICTYPE:
+               n := ir.NewDynamicType(r.pos(), r.expr())
+               if r.bool() {
+                       n.ITab = r.expr()
+               }
+               n.SetType(r.typ())
+               return n
+
        case ir.OTYPESW:
                pos := r.pos()
                var tag *ir.Ident
@@ -1344,7 +1394,11 @@ func (r *importReader) node() ir.Node {
                return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.fieldList())
 
        case ir.OCOMPLIT:
-               return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.exprList())
+               pos := r.pos()
+               t := r.typ()
+               n := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ir.TypeNode(t), r.exprList())
+               n.SetType(t)
+               return n
 
        case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
                if !go117ExportTypes {
@@ -1396,7 +1450,7 @@ func (r *importReader) node() ir.Node {
                                        } else {
                                                genType := types.ReceiverBaseType(n1.X.Type())
                                                if genType.IsInstantiatedGeneric() {
-                                                       genType = genType.OrigSym.Def.Type()
+                                                       genType = genType.OrigSym().Def.Type()
                                                }
                                                m = Lookdot1(n1, sel, genType, genType.Methods(), 1)
                                        }
@@ -1405,12 +1459,14 @@ func (r *importReader) node() ir.Node {
                                }
                        case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER:
                                n.Selection = r.exoticField()
-                       case ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
+                       case ir.OMETHEXPR:
+                               n = typecheckMethodExpr(n).(*ir.SelectorExpr)
+                       case ir.ODOTMETH, ir.OMETHVALUE:
                                // These require a Lookup to link to the correct declaration.
                                rcvrType := expr.Type()
                                typ := n.Type()
                                n.Selection = Lookdot(n, rcvrType, 1)
-                               if op == ir.OMETHVALUE || op == ir.OMETHEXPR {
+                               if op == ir.OMETHVALUE {
                                        // Lookdot clobbers the opcode and type, undo that.
                                        n.SetOp(op)
                                        n.SetType(typ)
@@ -1427,6 +1483,11 @@ func (r *importReader) node() ir.Node {
                }
                return n
 
+       case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
+               n := ir.NewDynamicTypeAssertExpr(r.pos(), op, r.expr(), r.expr())
+               n.SetType(r.typ())
+               return n
+
        case ir.OINDEX, ir.OINDEXMAP:
                n := ir.NewIndexExpr(r.pos(), r.expr(), r.expr())
                if go117ExportTypes {
@@ -1498,7 +1559,7 @@ func (r *importReader) node() ir.Node {
                if go117ExportTypes {
                        n.SetOp(op)
                }
-               *n.PtrInit() = init
+               n.SetInit(init)
                n.IsDDD = r.bool()
                if go117ExportTypes {
                        n.SetType(r.exoticType())
@@ -1602,7 +1663,12 @@ func (r *importReader) node() ir.Node {
        //      unreachable - never exported
 
        case ir.OAS:
-               return ir.NewAssignStmt(r.pos(), r.expr(), r.expr())
+               pos := r.pos()
+               init := r.stmtList()
+               n := ir.NewAssignStmt(pos, r.expr(), r.expr())
+               n.SetInit(init)
+               n.Def = r.bool()
+               return n
 
        case ir.OASOP:
                n := ir.NewAssignOpStmt(r.pos(), r.op(), r.expr(), nil)
@@ -1619,7 +1685,12 @@ func (r *importReader) node() ir.Node {
                        // unreachable - mapped to case OAS2 by exporter
                        goto error
                }
-               return ir.NewAssignListStmt(r.pos(), op, r.exprList(), r.exprList())
+               pos := r.pos()
+               init := r.stmtList()
+               n := ir.NewAssignListStmt(pos, op, r.exprList(), r.exprList())
+               n.SetInit(init)
+               n.Def = r.bool()
+               return n
 
        case ir.ORETURN:
                return ir.NewReturnStmt(r.pos(), r.exprList())
@@ -1633,26 +1704,28 @@ func (r *importReader) node() ir.Node {
        case ir.OIF:
                pos, init := r.pos(), r.stmtList()
                n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
-               *n.PtrInit() = init
+               n.SetInit(init)
                return n
 
        case ir.OFOR:
                pos, init := r.pos(), r.stmtList()
                cond, post := r.exprsOrNil()
                n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
-               *n.PtrInit() = init
+               n.SetInit(init)
                return n
 
        case ir.ORANGE:
-               pos := r.pos()
+               pos, init := r.pos(), r.stmtList()
                k, v := r.exprsOrNil()
-               return ir.NewRangeStmt(pos, k, v, r.expr(), r.stmtList())
+               n := ir.NewRangeStmt(pos, k, v, r.expr(), r.stmtList())
+               n.SetInit(init)
+               return n
 
        case ir.OSELECT:
                pos := r.pos()
                init := r.stmtList()
                n := ir.NewSelectStmt(pos, r.commList())
-               *n.PtrInit() = init
+               n.SetInit(init)
                return n
 
        case ir.OSWITCH:
@@ -1660,7 +1733,7 @@ func (r *importReader) node() ir.Node {
                init := r.stmtList()
                x, _ := r.exprsOrNil()
                n := ir.NewSwitchStmt(pos, x, r.caseList(x))
-               *n.PtrInit() = init
+               n.SetInit(init)
                return n
 
        // case OCASE:
@@ -1704,7 +1777,12 @@ func (r *importReader) node() ir.Node {
                return n
 
        case ir.OSELRECV2:
-               return ir.NewAssignListStmt(r.pos(), ir.OSELRECV2, r.exprList(), r.exprList())
+               pos := r.pos()
+               init := r.stmtList()
+               n := ir.NewAssignListStmt(pos, ir.OSELRECV2, r.exprList(), r.exprList())
+               n.SetInit(init)
+               n.Def = r.bool()
+               return n
 
        default:
                base.Fatalf("cannot import %v (%d) node\n"+
@@ -1751,34 +1829,11 @@ func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
        return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
 }
 
-// InstTypeName creates a name for an instantiated type, based on the name of the
-// generic type and the type args.
-func InstTypeName(name string, targs []*types.Type) string {
-       b := bytes.NewBufferString(name)
-       b.WriteByte('[')
-       for i, targ := range targs {
-               if i > 0 {
-                       b.WriteByte(',')
-               }
-               // WriteString() does not include the package name for the local
-               // package, but we want it to make sure type arguments (including
-               // type params) are uniquely specified.
-               if targ.Sym() != nil && targ.Sym().Pkg == types.LocalPkg {
-                       b.WriteString(targ.Sym().Pkg.Name)
-                       b.WriteByte('.')
-               }
-               // types1 uses "interface {" and types2 uses "interface{" - convert
-               // to consistent types2 format.
-               tstring := targ.String()
-               tstring = strings.Replace(tstring, "interface {", "interface{", -1)
-               b.WriteString(tstring)
-       }
-       b.WriteByte(']')
-       return b.String()
-}
-
 // NewIncompleteNamedType returns a TFORW type t with name specified by sym, such
-// that t.nod and sym.Def are set correctly.
+// that t.nod and sym.Def are set correctly. If there are any RParams for the type,
+// they should be set soon after creating the TFORW type, before creating the
+// underlying type. That ensures that the HasTParam and HasShape flags will be set
+// properly, in case this type is part of some mutually recursive type.
 func NewIncompleteNamedType(pos src.XPos, sym *types.Sym) *types.Type {
        name := ir.NewDeclNameAt(pos, ir.OTYPE, sym)
        forw := types.NewNamed(name)
@@ -1798,14 +1853,30 @@ func Instantiate(pos src.XPos, baseType *types.Type, targs []*types.Type) *types
        instSym := baseSym.Pkg.Lookup(name)
        if instSym.Def != nil {
                // May match existing type from previous import or
-               // types2-to-types1 conversion, or from in-progress instantiation
-               // in the current type import stack.
-               return instSym.Def.Type()
+               // types2-to-types1 conversion.
+               t := instSym.Def.Type()
+               if t.Kind() != types.TFORW {
+                       return t
+               }
+               // Or, we have started creating this type in (*TSubster).Typ, but its
+               // underlying type was not completed yet, so we need to add this type
+               // to deferredInstStack, if not already there.
+               found := false
+               for _, t2 := range deferredInstStack {
+                       if t2 == t {
+                               found = true
+                               break
+                       }
+               }
+               if !found {
+                       deferredInstStack = append(deferredInstStack, t)
+               }
+               return t
        }
 
        t := NewIncompleteNamedType(baseType.Pos(), instSym)
        t.SetRParams(targs)
-       t.OrigSym = baseSym
+       t.SetOrigSym(baseSym)
 
        // baseType may still be TFORW or its methods may not be fully filled in
        // (since we are in the middle of importing it). So, delay call to
@@ -1830,7 +1901,7 @@ func resumeDoInst() {
                for len(deferredInstStack) > 0 {
                        t := deferredInstStack[0]
                        deferredInstStack = deferredInstStack[1:]
-                       substInstType(t, t.OrigSym.Def.(*ir.Name).Type(), t.RParams())
+                       substInstType(t, t.OrigSym().Def.(*ir.Name).Type(), t.RParams())
                }
        }
        deferInst--
@@ -1841,7 +1912,8 @@ func resumeDoInst() {
 // during a type substitution for an instantiation. This is needed for
 // instantiations of mutually recursive types.
 func doInst(t *types.Type) *types.Type {
-       return Instantiate(t.Pos(), t.OrigSym.Def.(*ir.Name).Type(), t.RParams())
+       assert(t.Kind() == types.TFORW)
+       return Instantiate(t.Pos(), t.OrigSym().Def.(*ir.Name).Type(), t.RParams())
 }
 
 // substInstType completes the instantiation of a generic type by doing a
@@ -1849,6 +1921,7 @@ func doInst(t *types.Type) *types.Type {
 // instantiation being created, baseType is the base generic type, and targs are
 // the type arguments that baseType is being instantiated with.
 func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
+       assert(t.Kind() == types.TFORW)
        subst := Tsubster{
                Tparams:       baseType.RParams(),
                Targs:         targs,
@@ -1879,17 +1952,23 @@ func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
                }
                t2 := msubst.Typ(f.Type)
                oldsym := f.Nname.Sym()
-               newsym := MakeInstName(oldsym, targs, true)
+               newsym := MakeFuncInstSym(oldsym, targs, true, true)
                var nname *ir.Name
                if newsym.Def != nil {
                        nname = newsym.Def.(*ir.Name)
                } else {
                        nname = ir.NewNameAt(f.Pos, newsym)
                        nname.SetType(t2)
+                       ir.MarkFunc(nname)
                        newsym.Def = nname
                }
                newfields[i] = types.NewField(f.Pos, f.Sym, t2)
                newfields[i].Nname = nname
        }
        t.Methods().Set(newfields)
+       if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TINTER && t.Methods().Len() > 0 {
+               // Generate all the methods for a new fully-instantiated,
+               // non-interface, non-shape type.
+               NeedInstType(t)
+       }
 }
index c322d490e5b2a07ac6524afd40900b182bd18392..9a02c1752caf13f6c89e26866e01ba553a767e62 100644 (file)
@@ -395,10 +395,11 @@ func tcSelect(sel *ir.SelectStmt) {
                        n := Stmt(ncase.Comm)
                        ncase.Comm = n
                        oselrecv2 := func(dst, recv ir.Node, def bool) {
-                               n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
-                               n.Def = def
-                               n.SetTypecheck(1)
-                               ncase.Comm = n
+                               selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
+                               selrecv.Def = def
+                               selrecv.SetTypecheck(1)
+                               selrecv.SetInit(n.Init())
+                               ncase.Comm = selrecv
                        }
                        switch n.Op() {
                        default:
index c7a3718b31cea4a962a2c067fe5c15ee57a2f95b..1986845f64299df7151cd9179dbe89ceaf3fe11f 100644 (file)
@@ -14,6 +14,7 @@ import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
+       "cmd/internal/objabi"
        "cmd/internal/src"
 )
 
@@ -352,7 +353,10 @@ func Assignop(src, dst *types.Type) (ir.Op, string) {
        if types.Identical(src, dst) {
                return ir.OCONVNOP, ""
        }
+       return Assignop1(src, dst)
+}
 
+func Assignop1(src, dst *types.Type) (ir.Op, string) {
        // 2. src and dst have identical underlying types and
        //   a. either src or dst is not a named type, or
        //   b. both are empty interface types, or
@@ -740,9 +744,16 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
 
        if t.IsInterface() || t.IsTypeParam() {
                if t.IsTypeParam() {
-                       // A typeparam satisfies an interface if its type bound
-                       // has all the methods of that interface.
-                       t = t.Bound()
+                       // If t is a simple type parameter T, its type and underlying is the same.
+                       // If t is a type definition:'type P[T any] T', its type is P[T] and its
+                       // underlying is T. Therefore we use 't.Underlying() != t' to distinguish them.
+                       if t.Underlying() != t {
+                               CalcMethods(t)
+                       } else {
+                               // A typeparam satisfies an interface if its type bound
+                               // has all the methods of that interface.
+                               t = t.Bound()
+                       }
                }
                i := 0
                tms := t.AllMethods().Slice()
@@ -900,6 +911,32 @@ func TypesOf(x []ir.Node) []*types.Type {
        return r
 }
 
+// addTargs writes out the targs to buffer b as a comma-separated list enclosed by
+// brackets.
+func addTargs(b *bytes.Buffer, targs []*types.Type) {
+       b.WriteByte('[')
+       for i, targ := range targs {
+               if i > 0 {
+                       b.WriteByte(',')
+               }
+               // Make sure that type arguments (including type params), are
+               // uniquely specified. LinkString() eliminates all spaces
+               // and includes the package path (local package path is "" before
+               // linker substitution).
+               tstring := targ.LinkString()
+               b.WriteString(tstring)
+       }
+       b.WriteString("]")
+}
+
+// InstTypeName creates a name for an instantiated type, based on the name of the
+// generic type and the type args.
+func InstTypeName(name string, targs []*types.Type) string {
+       b := bytes.NewBufferString(name)
+       addTargs(b, targs)
+       return b.String()
+}
+
 // makeInstName1 returns the name of the generic function instantiated with the
 // given types, which can have type params or shapes, or be concrete types. name is
 // the name of the generic function or method.
@@ -912,38 +949,18 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
        } else {
                b.WriteString(name)
        }
-       b.WriteString("[")
-       for i, targ := range targs {
-               if i > 0 {
-                       b.WriteString(",")
-               }
-               // WriteString() does not include the package name for the local
-               // package, but we want it for uniqueness.
-               if targ.Sym() != nil && targ.Sym().Pkg == types.LocalPkg {
-                       b.WriteString(targ.Sym().Pkg.Name)
-                       b.WriteByte('.')
-               }
-               // types1 uses "interface {" and types2 uses "interface{" - convert
-               // to consistent types2 format.
-               tstring := targ.String()
-               tstring = strings.Replace(tstring, "interface {", "interface{", -1)
-               b.WriteString(tstring)
-       }
-       b.WriteString("]")
+       addTargs(b, targs)
        if i >= 0 {
                i2 := strings.LastIndex(name[i:], "]")
                assert(i2 >= 0)
                b.WriteString(name[i+i2+1:])
        }
-       if strings.HasPrefix(b.String(), ".inst..inst.") {
-               panic(fmt.Sprintf("multiple .inst. prefix in %s", b.String()))
-       }
        return b.String()
 }
 
-// MakeInstName makes the unique name for a stenciled generic function or method,
-// based on the name of the function fnsym and the targs. It replaces any
-// existing bracket type list in the name. MakeInstName asserts that fnsym has
+// MakeFuncInstSym makes the unique sym for a stenciled generic function or method,
+// based on the name of the function gf and the targs. It replaces any
+// existing bracket type list in the name. MakeInstName asserts that gf has
 // brackets in its name if and only if hasBrackets is true.
 //
 // Names of declared generic functions have no brackets originally, so hasBrackets
@@ -953,11 +970,22 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
 //
 // The standard naming is something like: 'genFn[int,bool]' for functions and
 // '(*genType[int,bool]).methodName' for methods
-func MakeInstName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
-       return gf.Pkg.Lookup(makeInstName1(gf.Name, targs, hasBrackets))
+//
+// isMethodNode specifies if the name of a method node is being generated (as opposed
+// to a name of an instantiation of generic function or name of the shape-based
+// function that helps implement a method of an instantiated type). For method nodes
+// on shape types, we prepend "nofunc.", because method nodes for shape types will
+// have no body, and we want to avoid a name conflict with the shape-based function
+// that helps implement the same method for fully-instantiated types.
+func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, isMethodNode, hasBrackets bool) *types.Sym {
+       nm := makeInstName1(gf.Name, targs, hasBrackets)
+       if targs[0].HasShape() && isMethodNode {
+               nm = "nofunc." + nm
+       }
+       return gf.Pkg.Lookup(nm)
 }
 
-func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
+func MakeDictSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
        for _, targ := range targs {
                if targ.HasTParam() {
                        fmt.Printf("FUNCTION %s\n", gf.Name)
@@ -968,7 +996,7 @@ func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.S
                }
        }
        name := makeInstName1(gf.Name, targs, hasBrackets)
-       name = ".dict." + name
+       name = fmt.Sprintf("%s.%s", objabi.GlobalDictPrefix, name)
        return gf.Pkg.Lookup(name)
 }
 
@@ -976,6 +1004,25 @@ func assert(p bool) {
        base.Assert(p)
 }
 
+// List of newly fully-instantiated types who should have their methods generated.
+var instTypeList []*types.Type
+
+// NeedInstType adds a new fully-instantiated type to instTypeList.
+func NeedInstType(t *types.Type) {
+       instTypeList = append(instTypeList, t)
+}
+
+// GetInstTypeList returns the current contents of instTypeList.
+func GetInstTypeList() []*types.Type {
+       r := instTypeList
+       return r
+}
+
+// ClearInstTypeList clears the contents of instTypeList.
+func ClearInstTypeList() {
+       instTypeList = nil
+}
+
 // General type substituter, for replacing typeparams with type args.
 type Tsubster struct {
        Tparams []*types.Type
@@ -983,25 +1030,33 @@ type Tsubster struct {
        // If non-nil, the substitution map from name nodes in the generic function to the
        // name nodes in the new stenciled function.
        Vars map[*ir.Name]*ir.Name
-       // New fully-instantiated generic types whose methods should be instantiated.
-       InstTypeList []*types.Type
        // If non-nil, function to substitute an incomplete (TFORW) type.
        SubstForwFunc func(*types.Type) *types.Type
 }
 
-// Typ computes the type obtained by substituting any type parameter in t with the
-// corresponding type argument in subst. If t contains no type parameters, the
-// result is t; otherwise the result is a new type. It deals with recursive types
-// by using TFORW types and finding partially or fully created types via sym.Def.
+// Typ computes the type obtained by substituting any type parameter or shape in t
+// that appears in subst.Tparams with the corresponding type argument in subst.Targs.
+// If t contains no type parameters, the result is t; otherwise the result is a new
+// type. It deals with recursive types by using TFORW types and finding partially or
+// fully created types via sym.Def.
 func (ts *Tsubster) Typ(t *types.Type) *types.Type {
-       if !t.HasTParam() && t.Kind() != types.TFUNC {
+       // Defer the CheckSize calls until we have fully-defined
+       // (possibly-recursive) top-level type.
+       types.DeferCheckSize()
+       r := ts.typ1(t)
+       types.ResumeCheckSize()
+       return r
+}
+
+func (ts *Tsubster) typ1(t *types.Type) *types.Type {
+       if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TFUNC {
                // Note: function types need to be copied regardless, as the
                // types of closures may contain declarations that need
                // to be copied. See #45738.
                return t
        }
 
-       if t.IsTypeParam() {
+       if t.IsTypeParam() || t.IsShape() {
                for i, tp := range ts.Tparams {
                        if tp == t {
                                return ts.Targs[i]
@@ -1033,13 +1088,14 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
        var targsChanged bool
        var forw *types.Type
 
-       if t.Sym() != nil {
+       if t.Sym() != nil && (t.HasTParam() || t.HasShape()) {
+               // Need to test for t.HasTParam() again because of special TFUNC case above.
                // Translate the type params for this type according to
                // the tparam/targs mapping from subst.
                neededTargs = make([]*types.Type, len(t.RParams()))
                for i, rparam := range t.RParams() {
-                       neededTargs[i] = ts.Typ(rparam)
-                       if !types.Identical(neededTargs[i], rparam) {
+                       neededTargs[i] = ts.typ1(rparam)
+                       if !types.IdenticalStrict(neededTargs[i], rparam) {
                                targsChanged = true
                        }
                }
@@ -1062,8 +1118,8 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
                forw.SetRParams(neededTargs)
                // Copy the OrigSym from the re-instantiated type (which is the sym of
                // the base generic type).
-               assert(t.OrigSym != nil)
-               forw.OrigSym = t.OrigSym
+               assert(t.OrigSym() != nil)
+               forw.SetOrigSym(t.OrigSym())
        }
 
        var newt *types.Type
@@ -1076,26 +1132,26 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
                }
                // Substitute the underlying typeparam (e.g. T in P[T], see
                // the example describing type P[T] above).
-               newt = ts.Typ(t.Underlying())
+               newt = ts.typ1(t.Underlying())
                assert(newt != t)
 
        case types.TARRAY:
                elem := t.Elem()
-               newelem := ts.Typ(elem)
+               newelem := ts.typ1(elem)
                if newelem != elem || targsChanged {
                        newt = types.NewArray(newelem, t.NumElem())
                }
 
        case types.TPTR:
                elem := t.Elem()
-               newelem := ts.Typ(elem)
+               newelem := ts.typ1(elem)
                if newelem != elem || targsChanged {
                        newt = types.NewPtr(newelem)
                }
 
        case types.TSLICE:
                elem := t.Elem()
-               newelem := ts.Typ(elem)
+               newelem := ts.typ1(elem)
                if newelem != elem || targsChanged {
                        newt = types.NewSlice(newelem)
                }
@@ -1144,38 +1200,33 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
                }
 
        case types.TINTER:
-               newt = ts.tinter(t)
-               if newt == t && !targsChanged {
+               newt = ts.tinter(t, targsChanged)
+               if newt == t {
                        newt = nil
                }
 
        case types.TMAP:
-               newkey := ts.Typ(t.Key())
-               newval := ts.Typ(t.Elem())
+               newkey := ts.typ1(t.Key())
+               newval := ts.typ1(t.Elem())
                if newkey != t.Key() || newval != t.Elem() || targsChanged {
                        newt = types.NewMap(newkey, newval)
                }
 
        case types.TCHAN:
                elem := t.Elem()
-               newelem := ts.Typ(elem)
+               newelem := ts.typ1(elem)
                if newelem != elem || targsChanged {
                        newt = types.NewChan(newelem, t.ChanDir())
-                       if !newt.HasTParam() {
-                               // TODO(danscales): not sure why I have to do this
-                               // only for channels.....
-                               types.CheckSize(newt)
-                       }
                }
        case types.TFORW:
                if ts.SubstForwFunc != nil {
-                       newt = ts.SubstForwFunc(t)
+                       return ts.SubstForwFunc(forw)
                } else {
                        assert(false)
                }
        case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
                types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64,
-               types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
+               types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, types.TUNSAFEPTR:
                newt = t.Underlying()
        case types.TUNION:
                nt := t.NumTerms()
@@ -1185,7 +1236,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
                for i := 0; i < nt; i++ {
                        term, tilde := t.Term(i)
                        tildes[i] = tilde
-                       newterms[i] = ts.Typ(term)
+                       newterms[i] = ts.typ1(term)
                        if newterms[i] != term {
                                changed = true
                        }
@@ -1203,32 +1254,33 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
                return t
        }
 
-       if t.Sym() == nil && t.Kind() != types.TINTER {
-               // Not a named type or interface type, so there was no forwarding type
-               // and there are no methods to substitute.
-               assert(t.Methods().Len() == 0)
-               return newt
-       }
-
        if forw != nil {
                forw.SetUnderlying(newt)
                newt = forw
        }
 
+       if !newt.HasTParam() && !newt.IsFuncArgStruct() {
+               // Calculate the size of any new types created. These will be
+               // deferred until the top-level ts.Typ() or g.typ() (if this is
+               // called from g.fillinMethods()).
+               types.CheckSize(newt)
+       }
+
        if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
                // Fill in the method info for the new type.
                var newfields []*types.Field
                newfields = make([]*types.Field, t.Methods().Len())
                for i, f := range t.Methods().Slice() {
-                       t2 := ts.Typ(f.Type)
+                       t2 := ts.typ1(f.Type)
                        oldsym := f.Nname.Sym()
-                       newsym := MakeInstName(oldsym, ts.Targs, true)
+                       newsym := MakeFuncInstSym(oldsym, ts.Targs, true, true)
                        var nname *ir.Name
                        if newsym.Def != nil {
                                nname = newsym.Def.(*ir.Name)
                        } else {
                                nname = ir.NewNameAt(f.Pos, newsym)
                                nname.SetType(t2)
+                               ir.MarkFunc(nname)
                                newsym.Def = nname
                        }
                        newfields[i] = types.NewField(f.Pos, f.Sym, t2)
@@ -1237,7 +1289,8 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
                newt.Methods().Set(newfields)
                if !newt.HasTParam() && !newt.HasShape() {
                        // Generate all the methods for a new fully-instantiated type.
-                       ts.InstTypeList = append(ts.InstTypeList, newt)
+
+                       NeedInstType(newt)
                }
        }
        return newt
@@ -1250,7 +1303,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
 // fields, set force to true.
 func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
        if t.NumFields() == 0 {
-               if t.HasTParam() {
+               if t.HasTParam() || t.HasShape() {
                        // For an empty struct, we need to return a new type,
                        // since it may now be fully instantiated (HasTParam
                        // becomes false).
@@ -1263,7 +1316,7 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
                newfields = make([]*types.Field, t.NumFields())
        }
        for i, f := range t.Fields().Slice() {
-               t2 := ts.Typ(f.Type)
+               t2 := ts.typ1(f.Type)
                if (t2 != f.Type || f.Nname != nil) && newfields == nil {
                        newfields = make([]*types.Field, t.NumFields())
                        for j := 0; j < i; j++ {
@@ -1271,11 +1324,9 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
                        }
                }
                if newfields != nil {
-                       // TODO(danscales): make sure this works for the field
-                       // names of embedded types (which should keep the name of
-                       // the type param, not the instantiated type).
                        newfields[i] = types.NewField(f.Pos, f.Sym, t2)
                        newfields[i].Embedded = f.Embedded
+                       newfields[i].Note = f.Note
                        if f.IsDDD() {
                                newfields[i].SetIsDDD(true)
                        }
@@ -1303,20 +1354,31 @@ func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
                }
        }
        if newfields != nil {
-               return types.NewStruct(t.Pkg(), newfields)
+               news := types.NewStruct(t.Pkg(), newfields)
+               news.StructType().Funarg = t.StructType().Funarg
+               return news
        }
        return t
 
 }
 
 // tinter substitutes type params in types of the methods of an interface type.
-func (ts *Tsubster) tinter(t *types.Type) *types.Type {
+func (ts *Tsubster) tinter(t *types.Type, force bool) *types.Type {
        if t.Methods().Len() == 0 {
+               if t.HasTParam() {
+                       // For an empty interface, we need to return a new type,
+                       // since it may now be fully instantiated (HasTParam
+                       // becomes false).
+                       return types.NewInterface(t.Pkg(), nil, false)
+               }
                return t
        }
        var newfields []*types.Field
+       if force {
+               newfields = make([]*types.Field, t.Methods().Len())
+       }
        for i, f := range t.Methods().Slice() {
-               t2 := ts.Typ(f.Type)
+               t2 := ts.typ1(f.Type)
                if (t2 != f.Type || f.Nname != nil) && newfields == nil {
                        newfields = make([]*types.Field, t.Methods().Len())
                        for j := 0; j < i; j++ {
@@ -1328,7 +1390,7 @@ func (ts *Tsubster) tinter(t *types.Type) *types.Type {
                }
        }
        if newfields != nil {
-               return types.NewInterface(t.Pkg(), newfields)
+               return types.NewInterface(t.Pkg(), newfields, t.IsImplicit())
        }
        return t
 }
@@ -1340,44 +1402,61 @@ func genericTypeName(sym *types.Sym) string {
        return sym.Name[0:strings.Index(sym.Name, "[")]
 }
 
-// Shapify takes a concrete type and returns a GCshape type that can
+// Shapify takes a concrete type and a type param index, and returns a GCshape type that can
 // be used in place of the input type and still generate identical code.
 // No methods are added - all methods calls directly on a shape should
 // be done by converting to an interface using the dictionary.
 //
-// TODO: this could take the generic function and base its decisions
-// on how that generic function uses this type argument. For instance,
-// if it doesn't use it as a function argument/return value, then
-// we don't need to distinguish int64 and float64 (because they only
-// differ in how they get passed as arguments). For now, we only
-// unify two different types if they are identical in every possible way.
-func Shapify(t *types.Type) *types.Type {
-       assert(!t.HasShape())
+// For now, we only consider two types to have the same shape, if they have exactly
+// the same underlying type or they are both pointer types.
+//
+//  Shape types are also distinguished by the index of the type in a type param/arg
+//  list. We need to do this so we can distinguish and substitute properly for two
+//  type params in the same function that have the same shape for a particular
+//  instantiation.
+func Shapify(t *types.Type, index int) *types.Type {
+       assert(!t.IsShape())
        // Map all types with the same underlying type to the same shape.
        u := t.Underlying()
 
        // All pointers have the same shape.
        // TODO: Make unsafe.Pointer the same shape as normal pointers.
-       if u.Kind() == types.TPTR {
+       // Note: pointers to arrays are special because of slice-to-array-pointer
+       // conversions. See issue 49295.
+       if u.Kind() == types.TPTR && u.Elem().Kind() != types.TARRAY {
                u = types.Types[types.TUINT8].PtrTo()
        }
 
-       if s := shaped[u]; s != nil {
+       if shapeMap == nil {
+               shapeMap = map[int]map[*types.Type]*types.Type{}
+       }
+       submap := shapeMap[index]
+       if submap == nil {
+               submap = map[*types.Type]*types.Type{}
+               shapeMap[index] = submap
+       }
+       if s := submap[u]; s != nil {
                return s
        }
 
-       sym := shapePkg.Lookup(u.LinkString())
+       // LinkString specifies the type uniquely, but has no spaces.
+       nm := fmt.Sprintf("%s_%d", u.LinkString(), index)
+       sym := types.ShapePkg.Lookup(nm)
+       if sym.Def != nil {
+               // Use any existing type with the same name
+               submap[u] = sym.Def.Type()
+               return submap[u]
+       }
        name := ir.NewDeclNameAt(u.Pos(), ir.OTYPE, sym)
        s := types.NewNamed(name)
+       sym.Def = name
        s.SetUnderlying(u)
        s.SetIsShape(true)
        s.SetHasShape(true)
        name.SetType(s)
        name.SetTypecheck(1)
-       shaped[u] = s
+       submap[u] = s
        return s
 }
 
-var shaped = map[*types.Type]*types.Type{}
-
-var shapePkg = types.NewPkg(".shape", ".shape")
+var shapeMap map[int]map[*types.Type]*types.Type
index af694c2d94a30fb4a5bf1a74e3afd1a48fddfaa8..c4c1ef58cadb103a91c1a0e79d3c1aa6acd4cbda 100644 (file)
@@ -108,7 +108,7 @@ func tcInterfaceType(n *ir.InterfaceType) ir.Node {
        methods := tcFields(n.Methods, nil)
        base.Pos = lno
 
-       n.SetOTYPE(types.NewInterface(types.LocalPkg, methods))
+       n.SetOTYPE(types.NewInterface(types.LocalPkg, methods, false))
        return n
 }
 
index db1b11c4cfd0a952a4aa22f1b4d3751381d25e19..42970f6a5e279fa4a133c2d56d946d7d3dbfe9b2 100644 (file)
@@ -879,6 +879,7 @@ func typecheck1(n ir.Node, top int) ir.Node {
 
        case ir.OTAILCALL:
                n := n.(*ir.TailCallStmt)
+               n.Call = typecheck(n.Call, ctxStmt|ctxExpr).(*ir.CallExpr)
                return n
 
        case ir.OCHECKNIL:
@@ -1736,11 +1737,6 @@ func CheckMapKeys() {
        mapqueue = nil
 }
 
-// TypeGen tracks the number of function-scoped defined types that
-// have been declared. It's used to generate unique linker symbols for
-// their runtime type descriptors.
-var TypeGen int32
-
 func typecheckdeftype(n *ir.Name) {
        if base.EnableTrace && base.Flag.LowerT {
                defer tracePrint("typecheckdeftype", n)(nil)
@@ -1748,8 +1744,7 @@ func typecheckdeftype(n *ir.Name) {
 
        t := types.NewNamed(n)
        if n.Curfn != nil {
-               TypeGen++
-               t.Vargen = TypeGen
+               t.SetVargen()
        }
 
        if n.Pragma()&ir.NotInHeap != 0 {
index 54f3c89c24544cff2d1ad345726e9e74b4573274..0254d96e6825e5adac1735e78df950694e0d62b7 100644 (file)
@@ -29,37 +29,6 @@ var (
        okforarith [types.NTYPE]bool
 )
 
-var basicTypes = [...]struct {
-       name  string
-       etype types.Kind
-}{
-       {"int8", types.TINT8},
-       {"int16", types.TINT16},
-       {"int32", types.TINT32},
-       {"int64", types.TINT64},
-       {"uint8", types.TUINT8},
-       {"uint16", types.TUINT16},
-       {"uint32", types.TUINT32},
-       {"uint64", types.TUINT64},
-       {"float32", types.TFLOAT32},
-       {"float64", types.TFLOAT64},
-       {"complex64", types.TCOMPLEX64},
-       {"complex128", types.TCOMPLEX128},
-       {"bool", types.TBOOL},
-       {"string", types.TSTRING},
-}
-
-var typedefs = [...]struct {
-       name     string
-       etype    types.Kind
-       sameas32 types.Kind
-       sameas64 types.Kind
-}{
-       {"int", types.TINT, types.TINT32, types.TINT64},
-       {"uint", types.TUINT, types.TUINT32, types.TUINT64},
-       {"uintptr", types.TUINTPTR, types.TUINT32, types.TUINT64},
-}
-
 var builtinFuncs = [...]struct {
        name string
        op   ir.Op
@@ -94,86 +63,12 @@ var unsafeFuncs = [...]struct {
 
 // InitUniverse initializes the universe block.
 func InitUniverse() {
-       if types.PtrSize == 0 {
-               base.Fatalf("typeinit before betypeinit")
-       }
-
-       types.SlicePtrOffset = 0
-       types.SliceLenOffset = types.Rnd(types.SlicePtrOffset+int64(types.PtrSize), int64(types.PtrSize))
-       types.SliceCapOffset = types.Rnd(types.SliceLenOffset+int64(types.PtrSize), int64(types.PtrSize))
-       types.SliceSize = types.Rnd(types.SliceCapOffset+int64(types.PtrSize), int64(types.PtrSize))
-
-       // string is same as slice wo the cap
-       types.StringSize = types.Rnd(types.SliceLenOffset+int64(types.PtrSize), int64(types.PtrSize))
-
-       for et := types.Kind(0); et < types.NTYPE; et++ {
-               types.SimType[et] = et
-       }
-
-       types.Types[types.TANY] = types.New(types.TANY)
-       types.Types[types.TINTER] = types.NewInterface(types.LocalPkg, nil)
-
-       defBasic := func(kind types.Kind, pkg *types.Pkg, name string) *types.Type {
-               sym := pkg.Lookup(name)
+       types.InitTypes(func(sym *types.Sym, typ *types.Type) types.Object {
                n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
-               t := types.NewBasic(kind, n)
-               n.SetType(t)
+               n.SetType(typ)
                sym.Def = n
-               if kind != types.TANY {
-                       types.CalcSize(t)
-               }
-               return t
-       }
-
-       for _, s := range &basicTypes {
-               types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
-       }
-
-       for _, s := range &typedefs {
-               sameas := s.sameas32
-               if types.PtrSize == 8 {
-                       sameas = s.sameas64
-               }
-               types.SimType[s.etype] = sameas
-
-               types.Types[s.etype] = defBasic(s.etype, types.BuiltinPkg, s.name)
-       }
-
-       // We create separate byte and rune types for better error messages
-       // rather than just creating type alias *types.Sym's for the uint8 and
-       // int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
-       // TODO(gri) Should we get rid of this special case (at the cost
-       // of less informative error messages involving bytes and runes)?
-       // (Alternatively, we could introduce an OTALIAS node representing
-       // type aliases, albeit at the cost of having to deal with it everywhere).
-       types.ByteType = defBasic(types.TUINT8, types.BuiltinPkg, "byte")
-       types.RuneType = defBasic(types.TINT32, types.BuiltinPkg, "rune")
-
-       // error type
-       s := types.BuiltinPkg.Lookup("error")
-       n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s)
-       types.ErrorType = types.NewNamed(n)
-       types.ErrorType.SetUnderlying(makeErrorInterface())
-       n.SetType(types.ErrorType)
-       s.Def = n
-       types.CalcSize(types.ErrorType)
-
-       // comparable type (interface)
-       s = types.BuiltinPkg.Lookup("comparable")
-       n = ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, s)
-       types.ComparableType = types.NewNamed(n)
-       types.ComparableType.SetUnderlying(makeComparableInterface())
-       n.SetType(types.ComparableType)
-       s.Def = n
-       types.CalcSize(types.ComparableType)
-
-       types.Types[types.TUNSAFEPTR] = defBasic(types.TUNSAFEPTR, ir.Pkgs.Unsafe, "Pointer")
-
-       // simple aliases
-       types.SimType[types.TMAP] = types.TPTR
-       types.SimType[types.TCHAN] = types.TPTR
-       types.SimType[types.TFUNC] = types.TPTR
-       types.SimType[types.TUNSAFEPTR] = types.TPTR
+               return n
+       })
 
        for _, s := range &builtinFuncs {
                s2 := types.BuiltinPkg.Lookup(s.name)
@@ -183,13 +78,13 @@ func InitUniverse() {
        }
 
        for _, s := range &unsafeFuncs {
-               s2 := ir.Pkgs.Unsafe.Lookup(s.name)
+               s2 := types.UnsafePkg.Lookup(s.name)
                def := NewName(s2)
                def.BuiltinOp = s.op
                s2.Def = def
        }
 
-       s = types.BuiltinPkg.Lookup("true")
+       s := types.BuiltinPkg.Lookup("true")
        s.Def = ir.NewConstAt(src.NoXPos, s, types.UntypedBool, constant.MakeBool(true))
 
        s = types.BuiltinPkg.Lookup("false")
@@ -199,7 +94,6 @@ func InitUniverse() {
        types.BlankSym = s
        s.Block = -100
        s.Def = NewName(s)
-       types.Types[types.TBLANK] = types.New(types.TBLANK)
        ir.AsNode(s.Def).SetType(types.Types[types.TBLANK])
        ir.BlankNode = ir.AsNode(s.Def)
        ir.BlankNode.SetTypecheck(1)
@@ -207,10 +101,8 @@ func InitUniverse() {
        s = types.BuiltinPkg.Lookup("_")
        s.Block = -100
        s.Def = NewName(s)
-       types.Types[types.TBLANK] = types.New(types.TBLANK)
        ir.AsNode(s.Def).SetType(types.Types[types.TBLANK])
 
-       types.Types[types.TNIL] = types.New(types.TNIL)
        s = types.BuiltinPkg.Lookup("nil")
        nnil := NodNil()
        nnil.(*ir.NilExpr).SetSym(s)
@@ -219,19 +111,6 @@ func InitUniverse() {
        s = types.BuiltinPkg.Lookup("iota")
        s.Def = ir.NewIota(base.Pos, s)
 
-       for et := types.TINT8; et <= types.TUINT64; et++ {
-               types.IsInt[et] = true
-       }
-       types.IsInt[types.TINT] = true
-       types.IsInt[types.TUINT] = true
-       types.IsInt[types.TUINTPTR] = true
-
-       types.IsFloat[types.TFLOAT32] = true
-       types.IsFloat[types.TFLOAT64] = true
-
-       types.IsComplex[types.TCOMPLEX64] = true
-       types.IsComplex[types.TCOMPLEX128] = true
-
        // initialize okfor
        for et := types.Kind(0); et < types.NTYPE; et++ {
                if types.IsInt[et] || et == types.TIDEAL {
@@ -329,28 +208,6 @@ func InitUniverse() {
        // special
        okfor[ir.OCAP] = okforcap[:]
        okfor[ir.OLEN] = okforlen[:]
-
-       // comparison
-       iscmp[ir.OLT] = true
-       iscmp[ir.OGT] = true
-       iscmp[ir.OGE] = true
-       iscmp[ir.OLE] = true
-       iscmp[ir.OEQ] = true
-       iscmp[ir.ONE] = true
-}
-
-func makeErrorInterface() *types.Type {
-       sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, []*types.Field{
-               types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
-       })
-       method := types.NewField(src.NoXPos, Lookup("Error"), sig)
-       return types.NewInterface(types.NoPkg, []*types.Field{method})
-}
-
-func makeComparableInterface() *types.Type {
-       sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, nil, nil)
-       method := types.NewField(src.NoXPos, Lookup("=="), sig)
-       return types.NewInterface(types.NoPkg, []*types.Field{method})
 }
 
 // DeclareUniverse makes the universe block visible within the current package.
index 2c2700f345730e2b0a99d472aedc5962953ca78a..f5675c66b4f4ec679e039fc3c26037fe652cad87 100644 (file)
@@ -165,7 +165,7 @@ func IsPaddedField(t *Type, i int) bool {
        if !t.IsStruct() {
                base.Fatalf("IsPaddedField called non-struct %v", t)
        }
-       end := t.Width
+       end := t.width
        if i+1 < t.NumFields() {
                end = t.Field(i + 1).Offset
        }
index 0824f6d0936161fdf126760284c613a1eb5f09fc..23fc4221e16c3e8589a7df53b0f92912a1e78f4e 100644 (file)
@@ -23,6 +23,9 @@ var BuiltinPkg *Pkg
 // LocalPkg is the package being compiled.
 var LocalPkg *Pkg
 
+// UnsafePkg is package unsafe.
+var UnsafePkg *Pkg
+
 // BlankSym is the blank (_) symbol.
 var BlankSym *Sym
 
@@ -61,7 +64,7 @@ var NumImport = make(map[string]int)
 // The default is regular Go syntax (fmtGo).
 // fmtDebug is like fmtGo but for debugging dumps and prints the type kind too.
 // fmtTypeID and fmtTypeIDName are for generating various unique representations
-// of types used in hashes and the linker.
+// of types used in hashes, the linker, and function/method instantiations.
 type fmtMode int
 
 const (
@@ -298,7 +301,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                return
        }
        if t.Kind() == TSSA {
-               b.WriteString(t.Extra.(string))
+               b.WriteString(t.extra.(string))
                return
        }
        if t.Kind() == TTUPLE {
@@ -309,7 +312,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
        }
 
        if t.Kind() == TRESULTS {
-               tys := t.Extra.(*Results).Types
+               tys := t.extra.(*Results).Types
                for i, et := range tys {
                        if i > 0 {
                                b.WriteByte(',')
@@ -361,8 +364,8 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                // output too. It seems like it should, but that mode is currently
                // used in string representation used by reflection, which is
                // user-visible and doesn't expect this.
-               if mode == fmtTypeID && t.Vargen != 0 {
-                       fmt.Fprintf(b, "·%d", t.Vargen)
+               if mode == fmtTypeID && t.vargen != 0 {
+                       fmt.Fprintf(b, "·%d", t.vargen)
                }
                return
        }
index 2e9e2f4fd849e1e1d338be8543eccf550a6e0383..dce7d29143a7dc608b890e3de8954c2143a8544b 100644 (file)
@@ -4,19 +4,30 @@
 
 package types
 
+const (
+       identIgnoreTags = 1 << iota
+       identStrict
+)
+
 // Identical reports whether t1 and t2 are identical types, following the spec rules.
 // Receiver parameter types are ignored. Named (defined) types are only equal if they
 // are pointer-equal - i.e. there must be a unique types.Type for each specific named
 // type. Also, a type containing a shape type is considered identical to another type
 // (shape or not) if their underlying types are the same, or they are both pointers.
 func Identical(t1, t2 *Type) bool {
-       return identical(t1, t2, true, nil)
+       return identical(t1, t2, 0, nil)
 }
 
 // IdenticalIgnoreTags is like Identical, but it ignores struct tags
 // for struct identity.
 func IdenticalIgnoreTags(t1, t2 *Type) bool {
-       return identical(t1, t2, false, nil)
+       return identical(t1, t2, identIgnoreTags, nil)
+}
+
+// IdenticalStrict is like Identical, but matches types exactly, without the
+// exception for shapes.
+func IdenticalStrict(t1, t2 *Type) bool {
+       return identical(t1, t2, identStrict, nil)
 }
 
 type typePair struct {
@@ -24,7 +35,7 @@ type typePair struct {
        t2 *Type
 }
 
-func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) bool {
+func identical(t1, t2 *Type, flags int, assumedEqual map[typePair]struct{}) bool {
        if t1 == t2 {
                return true
        }
@@ -32,7 +43,7 @@ func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) b
                return false
        }
        if t1.sym != nil || t2.sym != nil {
-               if t1.HasShape() || t2.HasShape() {
+               if flags&identStrict == 0 && (t1.HasShape() || t2.HasShape()) {
                        switch t1.kind {
                        case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64, TBOOL, TSTRING, TPTR, TUNSAFEPTR:
                                return true
@@ -78,7 +89,7 @@ cont:
                }
                for i, f1 := range t1.AllMethods().Slice() {
                        f2 := t2.AllMethods().Index(i)
-                       if f1.Sym != f2.Sym || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) {
+                       if f1.Sym != f2.Sym || !identical(f1.Type, f2.Type, flags, assumedEqual) {
                                return false
                        }
                }
@@ -90,10 +101,10 @@ cont:
                }
                for i, f1 := range t1.FieldSlice() {
                        f2 := t2.Field(i)
-                       if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) {
+                       if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !identical(f1.Type, f2.Type, flags, assumedEqual) {
                                return false
                        }
-                       if cmpTags && f1.Note != f2.Note {
+                       if (flags&identIgnoreTags) == 0 && f1.Note != f2.Note {
                                return false
                        }
                }
@@ -111,7 +122,7 @@ cont:
                        }
                        for i, f1 := range fs1 {
                                f2 := fs2[i]
-                               if f1.IsDDD() != f2.IsDDD() || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) {
+                               if f1.IsDDD() != f2.IsDDD() || !identical(f1.Type, f2.Type, flags, assumedEqual) {
                                        return false
                                }
                        }
@@ -129,10 +140,10 @@ cont:
                }
 
        case TMAP:
-               if !identical(t1.Key(), t2.Key(), cmpTags, assumedEqual) {
+               if !identical(t1.Key(), t2.Key(), flags, assumedEqual) {
                        return false
                }
        }
 
-       return identical(t1.Elem(), t2.Elem(), cmpTags, assumedEqual)
+       return identical(t1.Elem(), t2.Elem(), flags, assumedEqual)
 }
index f63a357f0d092921835d7b31896777780a0eabcd..fe42049ceedfbd462c36f9eef4be4a2fdb294304 100644 (file)
@@ -9,6 +9,7 @@ import (
        "cmd/internal/objabi"
        "fmt"
        "sort"
+       "strings"
        "sync"
 )
 
@@ -48,7 +49,13 @@ func NewPkg(path, name string) *Pkg {
        p := new(Pkg)
        p.Path = path
        p.Name = name
-       p.Prefix = objabi.PathToPrefix(path)
+       if strings.HasPrefix(path, "go.") {
+               // Special compiler-internal packages don't need to be escaped.
+               // This particularly helps with the go.shape package.
+               p.Prefix = path
+       } else {
+               p.Prefix = objabi.PathToPrefix(path)
+       }
        p.Syms = make(map[string]*Sym)
        pkgMap[path] = p
 
index 89391ade683af97f1faa2a547a40b3fc4feab83f..0f3db06c1decf32650f2bbd0949a720386414b05 100644 (file)
@@ -189,19 +189,19 @@ func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 {
                }
 
                CalcSize(f.Type)
-               if int32(f.Type.Align) > maxalign {
-                       maxalign = int32(f.Type.Align)
+               if int32(f.Type.align) > maxalign {
+                       maxalign = int32(f.Type.align)
                }
-               if f.Type.Align > 0 {
-                       o = Rnd(o, int64(f.Type.Align))
+               if f.Type.align > 0 {
+                       o = Rnd(o, int64(f.Type.align))
                }
                if isStruct { // For receiver/args/results, do not set, it depends on ABI
                        f.Offset = o
                }
 
-               w := f.Type.Width
+               w := f.Type.width
                if w < 0 {
-                       base.Fatalf("invalid width %d", f.Type.Width)
+                       base.Fatalf("invalid width %d", f.Type.width)
                }
                if w == 0 {
                        lastzero = o
@@ -231,10 +231,10 @@ func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 {
        if flag != 0 {
                o = Rnd(o, int64(maxalign))
        }
-       t.Align = uint8(maxalign)
+       t.align = uint8(maxalign)
 
        // type width only includes back to first field's offset
-       t.Width = o - starto
+       t.width = o - starto
 
        return o
 }
@@ -350,14 +350,14 @@ func CalcSize(t *Type) {
                return
        }
 
-       if t.Width == -2 {
+       if t.width == -2 {
                reportTypeLoop(t)
-               t.Width = 0
-               t.Align = 1
+               t.width = 0
+               t.align = 1
                return
        }
 
-       if t.WidthCalculated() {
+       if t.widthCalculated() {
                return
        }
 
@@ -372,7 +372,7 @@ func CalcSize(t *Type) {
 
        // break infinite recursion if the broken recursive type
        // is referenced again
-       if t.Broke() && t.Width == 0 {
+       if t.Broke() && t.width == 0 {
                return
        }
 
@@ -384,8 +384,8 @@ func CalcSize(t *Type) {
                base.Pos = pos
        }
 
-       t.Width = -2
-       t.Align = 0 // 0 means use t.Width, below
+       t.width = -2
+       t.align = 0 // 0 means use t.Width, below
 
        et := t.Kind()
        switch et {
@@ -417,15 +417,15 @@ func CalcSize(t *Type) {
 
        case TINT64, TUINT64, TFLOAT64:
                w = 8
-               t.Align = uint8(RegSize)
+               t.align = uint8(RegSize)
 
        case TCOMPLEX64:
                w = 8
-               t.Align = 4
+               t.align = 4
 
        case TCOMPLEX128:
                w = 16
-               t.Align = uint8(RegSize)
+               t.align = uint8(RegSize)
 
        case TPTR:
                w = int64(PtrSize)
@@ -436,14 +436,14 @@ func CalcSize(t *Type) {
 
        case TINTER: // implemented as 2 pointers
                w = 2 * int64(PtrSize)
-               t.Align = uint8(PtrSize)
+               t.align = uint8(PtrSize)
                expandiface(t)
 
        case TUNION:
                // Always part of an interface for now, so size/align don't matter.
                // Pretend a union is represented like an interface.
                w = 2 * int64(PtrSize)
-               t.Align = uint8(PtrSize)
+               t.align = uint8(PtrSize)
 
        case TCHAN: // implemented as pointer
                w = int64(PtrSize)
@@ -458,7 +458,7 @@ func CalcSize(t *Type) {
        case TCHANARGS:
                t1 := t.ChanArgs()
                CalcSize(t1) // just in case
-               if t1.Elem().Width >= 1<<16 {
+               if t1.Elem().width >= 1<<16 {
                        base.ErrorfAt(typePos(t1), "channel element type too large (>64kB)")
                }
                w = 1 // anything will do
@@ -481,7 +481,7 @@ func CalcSize(t *Type) {
                        base.Fatalf("early CalcSize string")
                }
                w = StringSize
-               t.Align = uint8(PtrSize)
+               t.align = uint8(PtrSize)
 
        case TARRAY:
                if t.Elem() == nil {
@@ -489,14 +489,14 @@ func CalcSize(t *Type) {
                }
 
                CalcSize(t.Elem())
-               if t.Elem().Width != 0 {
-                       cap := (uint64(MaxWidth) - 1) / uint64(t.Elem().Width)
+               if t.Elem().width != 0 {
+                       cap := (uint64(MaxWidth) - 1) / uint64(t.Elem().width)
                        if uint64(t.NumElem()) > cap {
                                base.ErrorfAt(typePos(t), "type %L larger than address space", t)
                        }
                }
-               w = t.NumElem() * t.Elem().Width
-               t.Align = t.Elem().Align
+               w = t.NumElem() * t.Elem().width
+               t.align = t.Elem().align
 
        case TSLICE:
                if t.Elem() == nil {
@@ -504,7 +504,7 @@ func CalcSize(t *Type) {
                }
                w = SliceSize
                CheckSize(t.Elem())
-               t.Align = uint8(PtrSize)
+               t.align = uint8(PtrSize)
 
        case TSTRUCT:
                if t.IsFuncArgStruct() {
@@ -526,11 +526,11 @@ func CalcSize(t *Type) {
                w = calcStructOffset(t1, t1.Recvs(), 0, 0)
                w = calcStructOffset(t1, t1.Params(), w, RegSize)
                w = calcStructOffset(t1, t1.Results(), w, RegSize)
-               t1.Extra.(*Func).Argwid = w
+               t1.extra.(*Func).Argwid = w
                if w%int64(RegSize) != 0 {
                        base.Warn("bad type %v %d\n", t1, w)
                }
-               t.Align = 1
+               t.align = 1
 
        case TTYPEPARAM:
                // TODO(danscales) - remove when we eliminate the need
@@ -542,12 +542,12 @@ func CalcSize(t *Type) {
                base.ErrorfAt(typePos(t), "type %v too large", t)
        }
 
-       t.Width = w
-       if t.Align == 0 {
+       t.width = w
+       if t.align == 0 {
                if w == 0 || w > 8 || w&(w-1) != 0 {
                        base.Fatalf("invalid alignment for %v", t)
                }
-               t.Align = uint8(w)
+               t.align = uint8(w)
        }
 
        base.Pos = lno
@@ -559,7 +559,19 @@ func CalcSize(t *Type) {
 // filling in s.Width and s.Align,
 // even if size calculation is otherwise disabled.
 func CalcStructSize(s *Type) {
-       s.Width = calcStructOffset(s, s, 0, 1) // sets align
+       s.width = calcStructOffset(s, s, 0, 1) // sets align
+}
+
+// RecalcSize is like CalcSize, but recalculates t's size even if it
+// has already been calculated before. It does not recalculate other
+// types.
+func RecalcSize(t *Type) {
+       t.align = 0
+       CalcSize(t)
+}
+
+func (t *Type) widthCalculated() bool {
+       return t.align > 0
 }
 
 // when a type's width should be known, we call CheckSize
@@ -622,17 +634,23 @@ func ResumeCheckSize() {
 
 // PtrDataSize returns the length in bytes of the prefix of t
 // containing pointer data. Anything after this offset is scalar data.
+//
+// PtrDataSize is only defined for actual Go types. It's an error to
+// use it on compiler-internal types (e.g., TSSA, TRESULTS).
 func PtrDataSize(t *Type) int64 {
-       if !t.HasPointers() {
+       switch t.Kind() {
+       case TBOOL, TINT8, TUINT8, TINT16, TUINT16, TINT32,
+               TUINT32, TINT64, TUINT64, TINT, TUINT,
+               TUINTPTR, TCOMPLEX64, TCOMPLEX128, TFLOAT32, TFLOAT64:
                return 0
-       }
 
-       switch t.Kind() {
-       case TPTR,
-               TUNSAFEPTR,
-               TFUNC,
-               TCHAN,
-               TMAP:
+       case TPTR:
+               if t.Elem().NotInHeap() {
+                       return 0
+               }
+               return int64(PtrSize)
+
+       case TUNSAFEPTR, TFUNC, TCHAN, TMAP:
                return int64(PtrSize)
 
        case TSTRING:
@@ -646,24 +664,32 @@ func PtrDataSize(t *Type) int64 {
                return 2 * int64(PtrSize)
 
        case TSLICE:
+               if t.Elem().NotInHeap() {
+                       return 0
+               }
                // struct { byte *array; uintgo len; uintgo cap; }
                return int64(PtrSize)
 
        case TARRAY:
-               // haspointers already eliminated t.NumElem() == 0.
-               return (t.NumElem()-1)*t.Elem().Width + PtrDataSize(t.Elem())
+               if t.NumElem() == 0 {
+                       return 0
+               }
+               // t.NumElem() > 0
+               size := PtrDataSize(t.Elem())
+               if size == 0 {
+                       return 0
+               }
+               return (t.NumElem()-1)*t.Elem().Size() + size
 
        case TSTRUCT:
-               // Find the last field that has pointers.
-               var lastPtrField *Field
+               // Find the last field that has pointers, if any.
                fs := t.Fields().Slice()
                for i := len(fs) - 1; i >= 0; i-- {
-                       if fs[i].Type.HasPointers() {
-                               lastPtrField = fs[i]
-                               break
+                       if size := PtrDataSize(fs[i].Type); size > 0 {
+                               return fs[i].Offset + size
                        }
                }
-               return lastPtrField.Offset + PtrDataSize(lastPtrField.Type)
+               return 0
 
        default:
                base.Fatalf("PtrDataSize: unexpected type, %v", t)
index 7349e52a73e8499e9cc5e0fa48fe48c6125aa3f5..d37c1730581c38be38a36d8e067d66deac34b94d 100644 (file)
@@ -26,7 +26,7 @@ func TestSizeof(t *testing.T) {
                {Forward{}, 20, 32},
                {Func{}, 28, 48},
                {Struct{}, 16, 32},
-               {Interface{}, 4, 8},
+               {Interface{}, 8, 16},
                {Chan{}, 8, 16},
                {Array{}, 12, 16},
                {FuncArgs{}, 4, 8},
index 875b0ba82f1ec5407d3b7fd82063a55b09412b08..6288df30d6ce18d7f90def271ebe5e9edfd9e9b3 100644 (file)
@@ -27,12 +27,6 @@ type TypeObject interface {
        TypeDefn() *Type // for "type T Defn", returns Defn
 }
 
-// A VarObject is an Object representing a function argument, variable, or struct field.
-type VarObject interface {
-       Object
-       RecordFrameOffset(int64) // save frame offset
-}
-
 //go:generate stringer -type Kind -trimprefix T type.go
 
 // Kind describes a kind of type.
@@ -125,21 +119,23 @@ var (
        ErrorType *Type
        // Predeclared comparable interface type.
        ComparableType *Type
+       // Predeclared any interface type.
+       AnyType *Type
 
        // Types to represent untyped string and boolean constants.
-       UntypedString = New(TSTRING)
-       UntypedBool   = New(TBOOL)
+       UntypedString = newType(TSTRING)
+       UntypedBool   = newType(TBOOL)
 
        // Types to represent untyped numeric constants.
-       UntypedInt     = New(TIDEAL)
-       UntypedRune    = New(TIDEAL)
-       UntypedFloat   = New(TIDEAL)
-       UntypedComplex = New(TIDEAL)
+       UntypedInt     = newType(TIDEAL)
+       UntypedRune    = newType(TIDEAL)
+       UntypedFloat   = newType(TIDEAL)
+       UntypedComplex = newType(TIDEAL)
 )
 
 // A Type represents a Go type.
 type Type struct {
-       // Extra contains extra etype-specific fields.
+       // extra contains extra etype-specific fields.
        // As an optimization, those etype-specific structs which contain exactly
        // one pointer-shaped field are stored as values rather than pointers when possible.
        //
@@ -156,10 +152,10 @@ type Type struct {
        // TSLICE: Slice
        // TSSA: string
        // TTYPEPARAM:  *Typeparam
-       Extra interface{}
+       extra interface{}
 
-       // Width is the width of this Type in bytes.
-       Width int64 // valid if Align > 0
+       // width is the width of this Type in bytes.
+       width int64 // valid if Align > 0
 
        // list of base methods (excluding embedding)
        methods Fields
@@ -178,10 +174,10 @@ type Type struct {
        }
 
        sym    *Sym  // symbol containing name, for named types
-       Vargen int32 // unique name for OTYPE/ONAME
+       vargen int32 // unique name for OTYPE/ONAME
 
        kind  Kind  // kind of type
-       Align uint8 // the required alignment of this type, in bytes (0 means Width and Align have not yet been computed)
+       align uint8 // the required alignment of this type, in bytes (0 means Width and Align have not yet been computed)
 
        flags bitset8
 
@@ -198,7 +194,7 @@ type Type struct {
        // For an instantiated generic type, the symbol for the base generic type.
        // This backpointer is useful, because the base type is the type that has
        // the method bodies.
-       OrigSym *Sym
+       origSym *Sym
 }
 
 func (*Type) CanBeAnSSAAux() {}
@@ -243,6 +239,11 @@ func (t *Type) Kind() Kind { return t.kind }
 func (t *Type) Sym() *Sym       { return t.sym }
 func (t *Type) SetSym(sym *Sym) { t.sym = sym }
 
+// OrigSym returns the name of the original generic type that t is an
+// instantiation of, if any.
+func (t *Type) OrigSym() *Sym       { return t.origSym }
+func (t *Type) SetOrigSym(sym *Sym) { t.origSym = sym }
+
 // Underlying returns the underlying type of type t.
 func (t *Type) Underlying() *Type { return t.underlying }
 
@@ -325,11 +326,11 @@ var NoPkg *Pkg = nil
 func (t *Type) Pkg() *Pkg {
        switch t.kind {
        case TFUNC:
-               return t.Extra.(*Func).pkg
+               return t.extra.(*Func).pkg
        case TSTRUCT:
-               return t.Extra.(*Struct).pkg
+               return t.extra.(*Struct).pkg
        case TINTER:
-               return t.Extra.(*Interface).pkg
+               return t.extra.(*Interface).pkg
        default:
                base.Fatalf("Pkg: unexpected kind: %v", t)
                return nil
@@ -349,7 +350,7 @@ type Map struct {
 // MapType returns t's extra map-specific fields.
 func (t *Type) MapType() *Map {
        t.wantEtype(TMAP)
-       return t.Extra.(*Map)
+       return t.extra.(*Map)
 }
 
 // Forward contains Type fields specific to forward types.
@@ -361,7 +362,7 @@ type Forward struct {
 // ForwardType returns t's extra forward-type-specific fields.
 func (t *Type) ForwardType() *Forward {
        t.wantEtype(TFORW)
-       return t.Extra.(*Forward)
+       return t.extra.(*Forward)
 }
 
 // Func contains Type fields specific to func types.
@@ -382,7 +383,7 @@ type Func struct {
 // FuncType returns t's extra func-specific fields.
 func (t *Type) FuncType() *Func {
        t.wantEtype(TFUNC)
-       return t.Extra.(*Func)
+       return t.extra.(*Func)
 }
 
 // StructType contains Type fields specific to struct types.
@@ -411,12 +412,13 @@ const (
 // StructType returns t's extra struct-specific fields.
 func (t *Type) StructType() *Struct {
        t.wantEtype(TSTRUCT)
-       return t.Extra.(*Struct)
+       return t.extra.(*Struct)
 }
 
 // Interface contains Type fields specific to interface types.
 type Interface struct {
-       pkg *Pkg
+       pkg      *Pkg
+       implicit bool
 }
 
 // Typeparam contains Type fields specific to typeparam types.
@@ -455,7 +457,7 @@ type Chan struct {
 // ChanType returns t's extra channel-specific fields.
 func (t *Type) ChanType() *Chan {
        t.wantEtype(TCHAN)
-       return t.Extra.(*Chan)
+       return t.extra.(*Chan)
 }
 
 type Tuple struct {
@@ -521,7 +523,7 @@ func (f *Field) SetNointerface(b bool) { f.flags.set(fieldNointerface, b) }
 
 // End returns the offset of the first byte immediately after this field.
 func (f *Field) End() int64 {
-       return f.Offset + f.Type.Width
+       return f.Offset + f.Type.width
 }
 
 // IsMethod reports whether f represents a method rather than a struct field.
@@ -581,40 +583,40 @@ func (f *Fields) Append(s ...*Field) {
 }
 
 // New returns a new Type of the specified kind.
-func New(et Kind) *Type {
+func newType(et Kind) *Type {
        t := &Type{
                kind:  et,
-               Width: BADWIDTH,
+               width: BADWIDTH,
        }
        t.underlying = t
        // TODO(josharian): lazily initialize some of these?
        switch t.kind {
        case TMAP:
-               t.Extra = new(Map)
+               t.extra = new(Map)
        case TFORW:
-               t.Extra = new(Forward)
+               t.extra = new(Forward)
        case TFUNC:
-               t.Extra = new(Func)
+               t.extra = new(Func)
        case TSTRUCT:
-               t.Extra = new(Struct)
+               t.extra = new(Struct)
        case TINTER:
-               t.Extra = new(Interface)
+               t.extra = new(Interface)
        case TPTR:
-               t.Extra = Ptr{}
+               t.extra = Ptr{}
        case TCHANARGS:
-               t.Extra = ChanArgs{}
+               t.extra = ChanArgs{}
        case TFUNCARGS:
-               t.Extra = FuncArgs{}
+               t.extra = FuncArgs{}
        case TCHAN:
-               t.Extra = new(Chan)
+               t.extra = new(Chan)
        case TTUPLE:
-               t.Extra = new(Tuple)
+               t.extra = new(Tuple)
        case TRESULTS:
-               t.Extra = new(Results)
+               t.extra = new(Results)
        case TTYPEPARAM:
-               t.Extra = new(Typeparam)
+               t.extra = new(Typeparam)
        case TUNION:
-               t.Extra = new(Union)
+               t.extra = new(Union)
        }
        return t
 }
@@ -624,8 +626,8 @@ func NewArray(elem *Type, bound int64) *Type {
        if bound < 0 {
                base.Fatalf("NewArray: invalid bound %v", bound)
        }
-       t := New(TARRAY)
-       t.Extra = &Array{Elem: elem, Bound: bound}
+       t := newType(TARRAY)
+       t.extra = &Array{Elem: elem, Bound: bound}
        t.SetNotInHeap(elem.NotInHeap())
        if elem.HasTParam() {
                t.SetHasTParam(true)
@@ -642,11 +644,14 @@ func NewSlice(elem *Type) *Type {
                if t.Elem() != elem {
                        base.Fatalf("elem mismatch")
                }
+               if elem.HasTParam() != t.HasTParam() || elem.HasShape() != t.HasShape() {
+                       base.Fatalf("Incorrect HasTParam/HasShape flag for cached slice type")
+               }
                return t
        }
 
-       t := New(TSLICE)
-       t.Extra = Slice{Elem: elem}
+       t := newType(TSLICE)
+       t.extra = Slice{Elem: elem}
        elem.cache.slice = t
        if elem.HasTParam() {
                t.SetHasTParam(true)
@@ -659,7 +664,7 @@ func NewSlice(elem *Type) *Type {
 
 // NewChan returns a new chan Type with direction dir.
 func NewChan(elem *Type, dir ChanDir) *Type {
-       t := New(TCHAN)
+       t := newType(TCHAN)
        ct := t.ChanType()
        ct.Elem = elem
        ct.Dir = dir
@@ -673,9 +678,9 @@ func NewChan(elem *Type, dir ChanDir) *Type {
 }
 
 func NewTuple(t1, t2 *Type) *Type {
-       t := New(TTUPLE)
-       t.Extra.(*Tuple).first = t1
-       t.Extra.(*Tuple).second = t2
+       t := newType(TTUPLE)
+       t.extra.(*Tuple).first = t1
+       t.extra.(*Tuple).second = t2
        if t1.HasTParam() || t2.HasTParam() {
                t.SetHasTParam(true)
        }
@@ -686,8 +691,8 @@ func NewTuple(t1, t2 *Type) *Type {
 }
 
 func newResults(types []*Type) *Type {
-       t := New(TRESULTS)
-       t.Extra.(*Results).Types = types
+       t := newType(TRESULTS)
+       t.extra.(*Results).Types = types
        return t
 }
 
@@ -699,14 +704,14 @@ func NewResults(types []*Type) *Type {
 }
 
 func newSSA(name string) *Type {
-       t := New(TSSA)
-       t.Extra = name
+       t := newType(TSSA)
+       t.extra = name
        return t
 }
 
 // NewMap returns a new map Type with key type k and element (aka value) type v.
 func NewMap(k, v *Type) *Type {
-       t := New(TMAP)
+       t := newType(TMAP)
        mt := t.MapType()
        mt.Key = k
        mt.Elem = v
@@ -734,22 +739,16 @@ func NewPtr(elem *Type) *Type {
                if t.Elem() != elem {
                        base.Fatalf("NewPtr: elem mismatch")
                }
-               if elem.HasTParam() {
-                       // Extra check when reusing the cache, since the elem
-                       // might have still been undetermined (i.e. a TFORW type)
-                       // when this entry was cached.
-                       t.SetHasTParam(true)
-               }
-               if elem.HasShape() {
-                       t.SetHasShape(true)
+               if elem.HasTParam() != t.HasTParam() || elem.HasShape() != t.HasShape() {
+                       base.Fatalf("Incorrect HasTParam/HasShape flag for cached pointer type")
                }
                return t
        }
 
-       t := New(TPTR)
-       t.Extra = Ptr{Elem: elem}
-       t.Width = int64(PtrSize)
-       t.Align = uint8(PtrSize)
+       t := newType(TPTR)
+       t.extra = Ptr{Elem: elem}
+       t.width = int64(PtrSize)
+       t.align = uint8(PtrSize)
        if NewPtrCacheEnabled {
                elem.cache.ptr = t
        }
@@ -764,15 +763,15 @@ func NewPtr(elem *Type) *Type {
 
 // NewChanArgs returns a new TCHANARGS type for channel type c.
 func NewChanArgs(c *Type) *Type {
-       t := New(TCHANARGS)
-       t.Extra = ChanArgs{T: c}
+       t := newType(TCHANARGS)
+       t.extra = ChanArgs{T: c}
        return t
 }
 
 // NewFuncArgs returns a new TFUNCARGS type for func type f.
 func NewFuncArgs(f *Type) *Type {
-       t := New(TFUNCARGS)
-       t.Extra = FuncArgs{T: f}
+       t := newType(TFUNCARGS)
+       t.extra = FuncArgs{T: f}
        return t
 }
 
@@ -811,28 +810,28 @@ func SubstAny(t *Type, types *[]*Type) *Type {
                elem := SubstAny(t.Elem(), types)
                if elem != t.Elem() {
                        t = t.copy()
-                       t.Extra = Ptr{Elem: elem}
+                       t.extra = Ptr{Elem: elem}
                }
 
        case TARRAY:
                elem := SubstAny(t.Elem(), types)
                if elem != t.Elem() {
                        t = t.copy()
-                       t.Extra.(*Array).Elem = elem
+                       t.extra.(*Array).Elem = elem
                }
 
        case TSLICE:
                elem := SubstAny(t.Elem(), types)
                if elem != t.Elem() {
                        t = t.copy()
-                       t.Extra = Slice{Elem: elem}
+                       t.extra = Slice{Elem: elem}
                }
 
        case TCHAN:
                elem := SubstAny(t.Elem(), types)
                if elem != t.Elem() {
                        t = t.copy()
-                       t.Extra.(*Chan).Elem = elem
+                       t.extra.(*Chan).Elem = elem
                }
 
        case TMAP:
@@ -840,8 +839,8 @@ func SubstAny(t *Type, types *[]*Type) *Type {
                elem := SubstAny(t.Elem(), types)
                if key != t.Key() || elem != t.Elem() {
                        t = t.copy()
-                       t.Extra.(*Map).Key = key
-                       t.Extra.(*Map).Elem = elem
+                       t.extra.(*Map).Key = key
+                       t.extra.(*Map).Elem = elem
                }
 
        case TFUNC:
@@ -882,26 +881,26 @@ func (t *Type) copy() *Type {
        // copy any *T Extra fields, to avoid aliasing
        switch t.kind {
        case TMAP:
-               x := *t.Extra.(*Map)
-               nt.Extra = &x
+               x := *t.extra.(*Map)
+               nt.extra = &x
        case TFORW:
-               x := *t.Extra.(*Forward)
-               nt.Extra = &x
+               x := *t.extra.(*Forward)
+               nt.extra = &x
        case TFUNC:
-               x := *t.Extra.(*Func)
-               nt.Extra = &x
+               x := *t.extra.(*Func)
+               nt.extra = &x
        case TSTRUCT:
-               x := *t.Extra.(*Struct)
-               nt.Extra = &x
+               x := *t.extra.(*Struct)
+               nt.extra = &x
        case TINTER:
-               x := *t.Extra.(*Interface)
-               nt.Extra = &x
+               x := *t.extra.(*Interface)
+               nt.extra = &x
        case TCHAN:
-               x := *t.Extra.(*Chan)
-               nt.Extra = &x
+               x := *t.extra.(*Chan)
+               nt.extra = &x
        case TARRAY:
-               x := *t.Extra.(*Array)
-               nt.Extra = &x
+               x := *t.extra.(*Array)
+               nt.extra = &x
        case TTYPEPARAM:
                base.Fatalf("typeparam types cannot be copied")
        case TTUPLE, TSSA, TRESULTS:
@@ -970,7 +969,7 @@ var ParamsResults = [2]func(*Type) *Type{
 // Key returns the key type of map type t.
 func (t *Type) Key() *Type {
        t.wantEtype(TMAP)
-       return t.Extra.(*Map).Key
+       return t.extra.(*Map).Key
 }
 
 // Elem returns the type of elements of t.
@@ -978,15 +977,15 @@ func (t *Type) Key() *Type {
 func (t *Type) Elem() *Type {
        switch t.kind {
        case TPTR:
-               return t.Extra.(Ptr).Elem
+               return t.extra.(Ptr).Elem
        case TARRAY:
-               return t.Extra.(*Array).Elem
+               return t.extra.(*Array).Elem
        case TSLICE:
-               return t.Extra.(Slice).Elem
+               return t.extra.(Slice).Elem
        case TCHAN:
-               return t.Extra.(*Chan).Elem
+               return t.extra.(*Chan).Elem
        case TMAP:
-               return t.Extra.(*Map).Elem
+               return t.extra.(*Map).Elem
        }
        base.Fatalf("Type.Elem %s", t.kind)
        return nil
@@ -995,18 +994,18 @@ func (t *Type) Elem() *Type {
 // ChanArgs returns the channel type for TCHANARGS type t.
 func (t *Type) ChanArgs() *Type {
        t.wantEtype(TCHANARGS)
-       return t.Extra.(ChanArgs).T
+       return t.extra.(ChanArgs).T
 }
 
 // FuncArgs returns the func type for TFUNCARGS type t.
 func (t *Type) FuncArgs() *Type {
        t.wantEtype(TFUNCARGS)
-       return t.Extra.(FuncArgs).T
+       return t.extra.(FuncArgs).T
 }
 
 // IsFuncArgStruct reports whether t is a struct representing function parameters or results.
 func (t *Type) IsFuncArgStruct() bool {
-       return t.kind == TSTRUCT && t.Extra.(*Struct).Funarg != FunargNone
+       return t.kind == TSTRUCT && t.extra.(*Struct).Funarg != FunargNone
 }
 
 // Methods returns a pointer to the base methods (excluding embedding) for type t.
@@ -1037,7 +1036,7 @@ func (t *Type) SetAllMethods(fs []*Field) {
 // Fields returns the fields of struct type t.
 func (t *Type) Fields() *Fields {
        t.wantEtype(TSTRUCT)
-       return &t.Extra.(*Struct).fields
+       return &t.extra.(*Struct).fields
 }
 
 // Field returns the i'th field of struct type t.
@@ -1059,7 +1058,7 @@ func (t *Type) SetFields(fields []*Field) {
        // Rather than try to track and invalidate those,
        // enforce that SetFields cannot be called once
        // t's width has been calculated.
-       if t.WidthCalculated() {
+       if t.widthCalculated() {
                base.Fatalf("SetFields of %v: width previously calculated", t)
        }
        t.wantEtype(TSTRUCT)
@@ -1083,15 +1082,11 @@ func (t *Type) SetInterface(methods []*Field) {
        t.Methods().Set(methods)
 }
 
-func (t *Type) WidthCalculated() bool {
-       return t.Align > 0
-}
-
 // ArgWidth returns the total aligned argument size for a function.
 // It includes the receiver, parameters, and results.
 func (t *Type) ArgWidth() int64 {
        t.wantEtype(TFUNC)
-       return t.Extra.(*Func).Argwid
+       return t.extra.(*Func).Argwid
 }
 
 func (t *Type) Size() int64 {
@@ -1102,12 +1097,12 @@ func (t *Type) Size() int64 {
                return 0
        }
        CalcSize(t)
-       return t.Width
+       return t.width
 }
 
 func (t *Type) Alignment() int64 {
        CalcSize(t)
-       return int64(t.Align)
+       return int64(t.align)
 }
 
 func (t *Type) SimpleString() string {
@@ -1221,8 +1216,8 @@ func (t *Type) cmp(x *Type) Cmp {
 
        if x.sym != nil {
                // Syms non-nil, if vargens match then equal.
-               if t.Vargen != x.Vargen {
-                       return cmpForNe(t.Vargen < x.Vargen)
+               if t.vargen != x.vargen {
+                       return cmpForNe(t.vargen < x.vargen)
                }
                return CMPeq
        }
@@ -1234,8 +1229,8 @@ func (t *Type) cmp(x *Type) Cmp {
                return CMPeq
 
        case TSSA:
-               tname := t.Extra.(string)
-               xname := x.Extra.(string)
+               tname := t.extra.(string)
+               xname := x.extra.(string)
                // desire fast sorting, not pretty sorting.
                if len(tname) == len(xname) {
                        if tname == xname {
@@ -1252,16 +1247,16 @@ func (t *Type) cmp(x *Type) Cmp {
                return CMPlt
 
        case TTUPLE:
-               xtup := x.Extra.(*Tuple)
-               ttup := t.Extra.(*Tuple)
+               xtup := x.extra.(*Tuple)
+               ttup := t.extra.(*Tuple)
                if c := ttup.first.Compare(xtup.first); c != CMPeq {
                        return c
                }
                return ttup.second.Compare(xtup.second)
 
        case TRESULTS:
-               xResults := x.Extra.(*Results)
-               tResults := t.Extra.(*Results)
+               xResults := x.extra.(*Results)
+               tResults := t.extra.(*Results)
                xl, tl := len(xResults.Types), len(tResults.Types)
                if tl != xl {
                        if tl < xl {
@@ -1548,7 +1543,7 @@ func (t *Type) PtrTo() *Type {
 
 func (t *Type) NumFields() int {
        if t.kind == TRESULTS {
-               return len(t.Extra.(*Results).Types)
+               return len(t.extra.(*Results).Types)
        }
        return t.Fields().Len()
 }
@@ -1556,15 +1551,15 @@ func (t *Type) FieldType(i int) *Type {
        if t.kind == TTUPLE {
                switch i {
                case 0:
-                       return t.Extra.(*Tuple).first
+                       return t.extra.(*Tuple).first
                case 1:
-                       return t.Extra.(*Tuple).second
+                       return t.extra.(*Tuple).second
                default:
                        panic("bad tuple index")
                }
        }
        if t.kind == TRESULTS {
-               return t.Extra.(*Results).Types[i]
+               return t.extra.(*Results).Types[i]
        }
        return t.Field(i).Type
 }
@@ -1577,7 +1572,7 @@ func (t *Type) FieldName(i int) string {
 
 func (t *Type) NumElem() int64 {
        t.wantEtype(TARRAY)
-       return t.Extra.(*Array).Bound
+       return t.extra.(*Array).Bound
 }
 
 type componentsIncludeBlankFields bool
@@ -1639,15 +1634,15 @@ func (t *Type) SoleComponent() *Type {
 // The direction will be one of Crecv, Csend, or Cboth.
 func (t *Type) ChanDir() ChanDir {
        t.wantEtype(TCHAN)
-       return t.Extra.(*Chan).Dir
+       return t.extra.(*Chan).Dir
 }
 
 func (t *Type) IsMemory() bool {
-       if t == TypeMem || t.kind == TTUPLE && t.Extra.(*Tuple).second == TypeMem {
+       if t == TypeMem || t.kind == TTUPLE && t.extra.(*Tuple).second == TypeMem {
                return true
        }
        if t.kind == TRESULTS {
-               if types := t.Extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
+               if types := t.extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
                        return true
                }
        }
@@ -1676,56 +1671,7 @@ func (t *Type) IsUntyped() bool {
 // HasPointers reports whether t contains a heap pointer.
 // Note that this function ignores pointers to go:notinheap types.
 func (t *Type) HasPointers() bool {
-       switch t.kind {
-       case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
-               TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL, TSSA:
-               return false
-
-       case TARRAY:
-               if t.NumElem() == 0 { // empty array has no pointers
-                       return false
-               }
-               return t.Elem().HasPointers()
-
-       case TSTRUCT:
-               for _, t1 := range t.Fields().Slice() {
-                       if t1.Type.HasPointers() {
-                               return true
-                       }
-               }
-               return false
-
-       case TPTR, TSLICE:
-               return !t.Elem().NotInHeap()
-
-       case TTUPLE:
-               ttup := t.Extra.(*Tuple)
-               return ttup.first.HasPointers() || ttup.second.HasPointers()
-
-       case TRESULTS:
-               types := t.Extra.(*Results).Types
-               for _, et := range types {
-                       if et.HasPointers() {
-                               return true
-                       }
-               }
-               return false
-       }
-
-       return true
-}
-
-// Tie returns 'T' if t is a concrete type,
-// 'I' if t is an interface type, and 'E' if t is an empty interface type.
-// It is used to build calls to the conv* and assert* runtime routines.
-func (t *Type) Tie() byte {
-       if t.IsEmptyInterface() {
-               return 'E'
-       }
-       if t.IsInterface() {
-               return 'I'
-       }
-       return 'T'
+       return PtrDataSize(t) > 0
 }
 
 var recvType *Type
@@ -1733,11 +1679,15 @@ var recvType *Type
 // FakeRecvType returns the singleton type used for interface method receivers.
 func FakeRecvType() *Type {
        if recvType == nil {
-               recvType = NewPtr(New(TSTRUCT))
+               recvType = NewPtr(newType(TSTRUCT))
        }
        return recvType
 }
 
+func FakeRecv() *Field {
+       return NewField(src.NoXPos, nil, FakeRecvType())
+}
+
 var (
        // TSSA types. HasPointers assumes these are pointer-free.
        TypeInvalid   = newSSA("invalid")
@@ -1753,10 +1703,14 @@ var (
 // type should be set later via SetUnderlying(). References to the type are
 // maintained until the type is filled in, so those references can be updated when
 // the type is complete.
-func NewNamed(obj Object) *Type {
-       t := New(TFORW)
+func NewNamed(obj TypeObject) *Type {
+       t := newType(TFORW)
        t.sym = obj.Sym()
        t.nod = obj
+       if t.sym.Pkg == ShapePkg {
+               t.SetIsShape(true)
+               t.SetHasShape(true)
+       }
        return t
 }
 
@@ -1768,6 +1722,25 @@ func (t *Type) Obj() Object {
        return nil
 }
 
+// typeGen tracks the number of function-scoped defined types that
+// have been declared. It's used to generate unique linker symbols for
+// their runtime type descriptors.
+var typeGen int32
+
+// SetVargen assigns a unique generation number to type t, which must
+// be a defined type declared within function scope. The generation
+// number is used to distinguish it from other similarly spelled
+// defined types from the same package.
+//
+// TODO(mdempsky): Come up with a better solution.
+func (t *Type) SetVargen() {
+       base.Assertf(t.Sym() != nil, "SetVargen on anonymous type %v", t)
+       base.Assertf(t.vargen == 0, "type %v already has Vargen %v", t, t.vargen)
+
+       typeGen++
+       t.vargen = typeGen
+}
+
 // SetUnderlying sets the underlying type. SetUnderlying automatically updates any
 // types that were waiting for this type to be completed.
 func (t *Type) SetUnderlying(underlying *Type) {
@@ -1781,9 +1754,9 @@ func (t *Type) SetUnderlying(underlying *Type) {
 
        // TODO(mdempsky): Fix Type rekinding.
        t.kind = underlying.kind
-       t.Extra = underlying.Extra
-       t.Width = underlying.Width
-       t.Align = underlying.Align
+       t.extra = underlying.extra
+       t.width = underlying.width
+       t.align = underlying.align
        t.underlying = underlying.underlying
 
        if underlying.NotInHeap() {
@@ -1839,8 +1812,8 @@ func fieldsHasShape(fields []*Field) bool {
 }
 
 // NewBasic returns a new basic type of the given kind.
-func NewBasic(kind Kind, obj Object) *Type {
-       t := New(kind)
+func newBasic(kind Kind, obj Object) *Type {
+       t := newType(kind)
        t.sym = obj.Sym()
        t.nod = obj
        return t
@@ -1848,8 +1821,8 @@ func NewBasic(kind Kind, obj Object) *Type {
 
 // NewInterface returns a new interface for the given methods and
 // embedded types. Embedded types are specified as fields with no Sym.
-func NewInterface(pkg *Pkg, methods []*Field) *Type {
-       t := New(TINTER)
+func NewInterface(pkg *Pkg, methods []*Field, implicit bool) *Type {
+       t := newType(TINTER)
        t.SetInterface(methods)
        for _, f := range methods {
                // f.Type could be nil for a broken interface declaration
@@ -1865,16 +1838,17 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type {
        if anyBroke(methods) {
                t.SetBroke(true)
        }
-       t.Extra.(*Interface).pkg = pkg
+       t.extra.(*Interface).pkg = pkg
+       t.extra.(*Interface).implicit = implicit
        return t
 }
 
 // NewTypeParam returns a new type param with the specified sym (package and name)
 // and specified index within the typeparam list.
 func NewTypeParam(sym *Sym, index int) *Type {
-       t := New(TTYPEPARAM)
+       t := newType(TTYPEPARAM)
        t.sym = sym
-       t.Extra.(*Typeparam).index = index
+       t.extra.(*Typeparam).index = index
        t.SetHasTParam(true)
        return t
 }
@@ -1882,36 +1856,49 @@ func NewTypeParam(sym *Sym, index int) *Type {
 // Index returns the index of the type param within its param list.
 func (t *Type) Index() int {
        t.wantEtype(TTYPEPARAM)
-       return t.Extra.(*Typeparam).index
+       return t.extra.(*Typeparam).index
 }
 
 // SetIndex sets the index of the type param within its param list.
 func (t *Type) SetIndex(i int) {
        t.wantEtype(TTYPEPARAM)
-       t.Extra.(*Typeparam).index = i
+       t.extra.(*Typeparam).index = i
 }
 
 // SetBound sets the bound of a typeparam.
 func (t *Type) SetBound(bound *Type) {
        t.wantEtype(TTYPEPARAM)
-       t.Extra.(*Typeparam).bound = bound
+       t.extra.(*Typeparam).bound = bound
 }
 
 // Bound returns the bound of a typeparam.
 func (t *Type) Bound() *Type {
        t.wantEtype(TTYPEPARAM)
-       return t.Extra.(*Typeparam).bound
+       return t.extra.(*Typeparam).bound
+}
+
+// IsImplicit reports whether an interface is implicit (i.e. elided from a type
+// parameter constraint).
+func (t *Type) IsImplicit() bool {
+       t.wantEtype(TINTER)
+       return t.extra.(*Interface).implicit
+}
+
+// MarkImplicit marks the interface as implicit.
+func (t *Type) MarkImplicit() {
+       t.wantEtype(TINTER)
+       t.extra.(*Interface).implicit = true
 }
 
 // NewUnion returns a new union with the specified set of terms (types). If
 // tildes[i] is true, then terms[i] represents ~T, rather than just T.
 func NewUnion(terms []*Type, tildes []bool) *Type {
-       t := New(TUNION)
+       t := newType(TUNION)
        if len(terms) != len(tildes) {
                base.Fatalf("Mismatched terms and tildes for NewUnion")
        }
-       t.Extra.(*Union).terms = terms
-       t.Extra.(*Union).tildes = tildes
+       t.extra.(*Union).terms = terms
+       t.extra.(*Union).tildes = tildes
        nt := len(terms)
        for i := 0; i < nt; i++ {
                if terms[i].HasTParam() {
@@ -1927,14 +1914,14 @@ func NewUnion(terms []*Type, tildes []bool) *Type {
 // NumTerms returns the number of terms in a union type.
 func (t *Type) NumTerms() int {
        t.wantEtype(TUNION)
-       return len(t.Extra.(*Union).terms)
+       return len(t.extra.(*Union).terms)
 }
 
 // Term returns ith term of a union type as (term, tilde). If tilde is true, term
 // represents ~T, rather than just T.
 func (t *Type) Term(i int) (*Type, bool) {
        t.wantEtype(TUNION)
-       u := t.Extra.(*Union)
+       u := t.extra.(*Union)
        return u.terms[i], u.tildes[i]
 }
 
@@ -1954,7 +1941,7 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ
                recvs = []*Field{recv}
        }
 
-       t := New(TFUNC)
+       t := newType(TFUNC)
        ft := t.FuncType()
 
        funargs := func(fields []*Field, funarg Funarg) *Type {
@@ -1990,12 +1977,12 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ
 
 // NewStruct returns a new struct with the given fields.
 func NewStruct(pkg *Pkg, fields []*Field) *Type {
-       t := New(TSTRUCT)
+       t := newType(TSTRUCT)
        t.SetFields(fields)
        if anyBroke(fields) {
                t.SetBroke(true)
        }
-       t.Extra.(*Struct).pkg = pkg
+       t.extra.(*Struct).pkg = pkg
        if fieldsHasTParam(fields) {
                t.SetHasTParam(true)
        }
@@ -2214,3 +2201,5 @@ var (
 )
 
 var SimType [NTYPE]Kind
+
+var ShapePkg = NewPkg("go.shape", "go.shape")
index fe3f380b21f2d994ec77cd2c1d7be471d202b28b..1fd05b3f5e8c7677beebde97c47b622f5ac0431c 100644 (file)
@@ -2,26 +2,25 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package types_test
+package types
 
 import (
-       "cmd/compile/internal/types"
        "testing"
 )
 
 func TestSSACompare(t *testing.T) {
-       a := []*types.Type{
-               types.TypeInvalid,
-               types.TypeMem,
-               types.TypeFlags,
-               types.TypeVoid,
-               types.TypeInt128,
+       a := []*Type{
+               TypeInvalid,
+               TypeMem,
+               TypeFlags,
+               TypeVoid,
+               TypeInt128,
        }
        for _, x := range a {
                for _, y := range a {
                        c := x.Compare(y)
-                       if x == y && c != types.CMPeq || x != y && c == types.CMPeq {
-                               t.Errorf("%s compare %s == %d\n", x.Extra, y.Extra, c)
+                       if x == y && c != CMPeq || x != y && c == CMPeq {
+                               t.Errorf("%s compare %s == %d\n", x.extra, y.extra, c)
                        }
                }
        }
diff --git a/src/cmd/compile/internal/types/universe.go b/src/cmd/compile/internal/types/universe.go
new file mode 100644 (file)
index 0000000..d5239eb
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+       "cmd/compile/internal/base"
+       "cmd/internal/src"
+)
+
+var basicTypes = [...]struct {
+       name  string
+       etype Kind
+}{
+       {"int8", TINT8},
+       {"int16", TINT16},
+       {"int32", TINT32},
+       {"int64", TINT64},
+       {"uint8", TUINT8},
+       {"uint16", TUINT16},
+       {"uint32", TUINT32},
+       {"uint64", TUINT64},
+       {"float32", TFLOAT32},
+       {"float64", TFLOAT64},
+       {"complex64", TCOMPLEX64},
+       {"complex128", TCOMPLEX128},
+       {"bool", TBOOL},
+       {"string", TSTRING},
+}
+
+var typedefs = [...]struct {
+       name     string
+       etype    Kind
+       sameas32 Kind
+       sameas64 Kind
+}{
+       {"int", TINT, TINT32, TINT64},
+       {"uint", TUINT, TUINT32, TUINT64},
+       {"uintptr", TUINTPTR, TUINT32, TUINT64},
+}
+
+func InitTypes(defTypeName func(sym *Sym, typ *Type) Object) {
+       if PtrSize == 0 {
+               base.Fatalf("typeinit before betypeinit")
+       }
+
+       SlicePtrOffset = 0
+       SliceLenOffset = Rnd(SlicePtrOffset+int64(PtrSize), int64(PtrSize))
+       SliceCapOffset = Rnd(SliceLenOffset+int64(PtrSize), int64(PtrSize))
+       SliceSize = Rnd(SliceCapOffset+int64(PtrSize), int64(PtrSize))
+
+       // string is same as slice wo the cap
+       StringSize = Rnd(SliceLenOffset+int64(PtrSize), int64(PtrSize))
+
+       for et := Kind(0); et < NTYPE; et++ {
+               SimType[et] = et
+       }
+
+       Types[TANY] = newType(TANY)
+       Types[TINTER] = NewInterface(LocalPkg, nil, false)
+
+       defBasic := func(kind Kind, pkg *Pkg, name string) *Type {
+               typ := newType(kind)
+               obj := defTypeName(pkg.Lookup(name), typ)
+               typ.sym = obj.Sym()
+               typ.nod = obj
+               if kind != TANY {
+                       CheckSize(typ)
+               }
+               return typ
+       }
+
+       for _, s := range &basicTypes {
+               Types[s.etype] = defBasic(s.etype, BuiltinPkg, s.name)
+       }
+
+       for _, s := range &typedefs {
+               sameas := s.sameas32
+               if PtrSize == 8 {
+                       sameas = s.sameas64
+               }
+               SimType[s.etype] = sameas
+
+               Types[s.etype] = defBasic(s.etype, BuiltinPkg, s.name)
+       }
+
+       // We create separate byte and rune types for better error messages
+       // rather than just creating type alias *Sym's for the uint8 and
+       // int32  Hence, (bytetype|runtype).Sym.isAlias() is false.
+       // TODO(gri) Should we get rid of this special case (at the cost
+       // of less informative error messages involving bytes and runes)?
+       // (Alternatively, we could introduce an OTALIAS node representing
+       // type aliases, albeit at the cost of having to deal with it everywhere).
+       ByteType = defBasic(TUINT8, BuiltinPkg, "byte")
+       RuneType = defBasic(TINT32, BuiltinPkg, "rune")
+
+       // error type
+       DeferCheckSize()
+       ErrorType = defBasic(TFORW, BuiltinPkg, "error")
+       ErrorType.SetUnderlying(makeErrorInterface())
+       ResumeCheckSize()
+
+       // comparable type (interface)
+       DeferCheckSize()
+       ComparableType = defBasic(TFORW, BuiltinPkg, "comparable")
+       ComparableType.SetUnderlying(makeComparableInterface())
+       ResumeCheckSize()
+
+       // any type (interface)
+       if base.Flag.G > 0 {
+               DeferCheckSize()
+               AnyType = defBasic(TFORW, BuiltinPkg, "any")
+               AnyType.SetUnderlying(NewInterface(NoPkg, []*Field{}, false))
+               ResumeCheckSize()
+       }
+
+       Types[TUNSAFEPTR] = defBasic(TUNSAFEPTR, UnsafePkg, "Pointer")
+
+       Types[TBLANK] = newType(TBLANK)
+       Types[TNIL] = newType(TNIL)
+
+       // simple aliases
+       SimType[TMAP] = TPTR
+       SimType[TCHAN] = TPTR
+       SimType[TFUNC] = TPTR
+       SimType[TUNSAFEPTR] = TPTR
+
+       for et := TINT8; et <= TUINT64; et++ {
+               IsInt[et] = true
+       }
+       IsInt[TINT] = true
+       IsInt[TUINT] = true
+       IsInt[TUINTPTR] = true
+
+       IsFloat[TFLOAT32] = true
+       IsFloat[TFLOAT64] = true
+
+       IsComplex[TCOMPLEX64] = true
+       IsComplex[TCOMPLEX128] = true
+}
+
+func makeErrorInterface() *Type {
+       sig := NewSignature(NoPkg, FakeRecv(), nil, nil, []*Field{
+               NewField(src.NoXPos, nil, Types[TSTRING]),
+       })
+       method := NewField(src.NoXPos, LocalPkg.Lookup("Error"), sig)
+       return NewInterface(NoPkg, []*Field{method}, false)
+}
+
+func makeComparableInterface() *Type {
+       sig := NewSignature(NoPkg, FakeRecv(), nil, nil, nil)
+       method := NewField(src.NoXPos, LocalPkg.Lookup("=="), sig)
+       return NewInterface(NoPkg, []*Field{method}, false)
+}
index ae4fb6ad109306112c119518489f283769014fd2..83c4b02abf46db0103922eb94b7cc0e107cda3f9 100644 (file)
@@ -55,6 +55,18 @@ func (err Error) FullError() string {
        return fmt.Sprintf("%s: %s", err.Pos, err.Full)
 }
 
+// An ArgumentError holds an error that is associated with an argument.
+type ArgumentError struct {
+       index int
+       error
+}
+
+// Index returns the positional index of the argument associated with the
+// error.
+func (e ArgumentError) Index() int {
+       return e.index
+}
+
 // An Importer resolves import paths to Packages.
 //
 // CAUTION: This interface does not support the import of locally
@@ -96,6 +108,10 @@ type ImporterFrom interface {
 // A Config specifies the configuration for type checking.
 // The zero value for Config is a ready-to-use default configuration.
 type Config struct {
+       // Context is the context used for resolving global identifiers. If nil, the
+       // type checker will initialize this field with a newly created context.
+       Context *Context
+
        // GoVersion describes the accepted Go language version. The string
        // must follow the format "go%d.%d" (e.g. "go1.12") or ist must be
        // empty; an empty string indicates the latest language version.
@@ -125,12 +141,6 @@ type Config struct {
        // TODO(gri) Consolidate error messages and remove this flag.
        CompilerErrorMessages bool
 
-       // If AllowTypeLists is set, the type list syntax is permitted
-       // in an interface in addition to the type set syntax.
-       // TODO(gri) Remove once type lists are no longer supported by
-       //           the parser.
-       AllowTypeLists bool
-
        // 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
@@ -197,11 +207,19 @@ type Info struct {
        // qualified identifiers are collected in the Uses map.
        Types map[syntax.Expr]TypeAndValue
 
-       // Inferred maps calls of parameterized functions that use
-       // type inference to the inferred type arguments and signature
-       // of the function called. The recorded "call" expression may be
-       // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
-       Inferred map[syntax.Expr]Inferred
+       // Instances maps identifiers denoting parameterized types or functions to
+       // their type arguments and instantiated type.
+       //
+       // For example, Instances will map the identifier for 'T' in the type
+       // instantiation T[int, string] to the type arguments [int, string] and
+       // resulting instantiated *Named type. Given a parameterized function
+       // func F[A any](A), Instances will map the identifier for 'F' in the call
+       // expression F(int(1)) to the inferred type arguments [int], and resulting
+       // instantiated *Signature.
+       //
+       // Invariant: Instantiating Uses[id].Type() with Instances[id].TypeArgs
+       // results in an equivalent of Instances[id].Type.
+       Instances map[*syntax.Name]Instance
 
        // Defs maps identifiers to the objects they define (including
        // package names, dots "." of dot-imports, and blank "_" identifiers).
@@ -358,11 +376,13 @@ func (tv TypeAndValue) HasOk() bool {
        return tv.mode == commaok || tv.mode == mapindex
 }
 
-// Inferred reports the inferred type arguments and signature
-// for a parameterized function call that uses type inference.
-type Inferred struct {
-       TArgs []Type
-       Sig   *Signature
+// Instance reports the type arguments and instantiated type for type and
+// function instantiations. For type instantiations, Type will be of dynamic
+// type *Named. For function instantiations, Type will be of dynamic type
+// *Signature.
+type Instance struct {
+       TypeArgs *TypeList
+       Type     Type
 }
 
 // An Initializer describes a package-level variable, or a list of variables in case
@@ -418,7 +438,7 @@ func AssignableTo(V, T Type) bool {
 // ConvertibleTo reports whether a value of type V is convertible to a value of type T.
 func ConvertibleTo(V, T Type) bool {
        x := operand{mode: value, typ: V}
-       return x.convertibleTo(nil, T) // check not needed for non-constant x
+       return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
 }
 
 // Implements reports whether type V implements interface T.
index be05d06fd0acec9ce58d9f5aec2469c87458e24b..30cfbe0ee403f171a9fa0e0bee44a70ce86001fd 100644 (file)
@@ -17,10 +17,6 @@ import (
        . "cmd/compile/internal/types2"
 )
 
-func unimplemented() {
-       panic("unimplemented")
-}
-
 // genericPkg is a source prefix for packages that contain generic code.
 const genericPkg = "package generic_"
 
@@ -149,6 +145,7 @@ func TestValuesInfo(t *testing.T) {
                {`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
 
                {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // issue #22341
+               {`package g1; var(j int32; s int; n = 1.0<<s == j)`, `1.0`, `int32`, `1`},        // issue #48422
        }
 
        for _, test := range tests {
@@ -329,23 +326,28 @@ func TestTypesInfo(t *testing.T) {
                {brokenPkg + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string]invalid type`},
 
                // parameterized functions
-               {genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`},
+               {genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[T interface{}](T)`},
                {genericPkg + `p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`},
-               {genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func[generic_p2.T₁ interface{}](generic_p2.T₁)`},
-               {genericPkg + `p3; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
+               {genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func(int)`},
+               {genericPkg + `p3; func f[T any](T) {}; func _() { f[int](42) }`, `f[int]`, `func(int)`},
+               {genericPkg + `p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[T interface{}](T)`},
+               {genericPkg + `p5; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
 
                // type parameters
                {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
-               {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[generic_t1.P₁ interface{}]`},
-               {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[generic_t2.P₁ interface{}]`},
-               {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[generic_t3.P₁, generic_t3.Q₂ interface{}]`},
-               {brokenPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[broken_t4.P₁, broken_t4.Q₂ interface{m()}]`},
+               {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P interface{}]`},
+               {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P interface{}]`},
+               {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P, Q interface{}]`},
+               {brokenPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P, Q interface{m()}]`},
 
                // instantiated types must be sanitized
                {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
 
                // issue 45096
-               {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`},
+               {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `T`},
+
+               // issue 47895
+               {`package p; import "unsafe"; type S struct { f int }; var s S; var _ = unsafe.Offsetof(s.f)`, `s.f`, `int`},
        }
 
        for _, test := range tests {
@@ -382,12 +384,12 @@ func TestTypesInfo(t *testing.T) {
        }
 }
 
-func TestInferredInfo(t *testing.T) {
+func TestInstanceInfo(t *testing.T) {
        var tests = []struct {
                src   string
-               fun   string
+               name  string
                targs []string
-               sig   string
+               typ   string
        }{
                {genericPkg + `p0; func f[T any](T) {}; func _() { f(42) }`,
                        `f`,
@@ -417,33 +419,33 @@ func TestInferredInfo(t *testing.T) {
 
                // we don't know how to translate these but we can type-check them
                {genericPkg + `q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(int)`,
                },
                {genericPkg + `q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(int) int`,
                },
                {genericPkg + `q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(...int) int`,
                },
                {genericPkg + `q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`,
-                       `x.m`,
+                       `m`,
                        []string{`float64`, `string`, `byte`},
                        `func(float64, *string, []byte)`,
                },
                {genericPkg + `q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`,
-                       `x.m`,
+                       `m`,
                        []string{`float64`, `byte`},
                        `func(float64, *byte, ...[]byte)`,
                },
 
                {genericPkg + `r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`,
-                       `x.m`,
+                       `m`,
                        []string{`int`},
                        `func(int)`,
                },
@@ -480,65 +482,130 @@ func TestInferredInfo(t *testing.T) {
                        []string{`string`, `*string`},
                        `func() string`,
                },
-               {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T { return nil }; func _() { _ = f[int] }`,
+               {genericPkg + `t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
                        `f`,
-                       []string{`int`, `chan<- int`},
-                       `func() []int`,
+                       []string{`string`, `*string`},
+                       `func() string`,
                },
                {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
                        `f`,
                        []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
                        `func() []int`,
                },
+               {genericPkg + `t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
+                       `f`,
+                       []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
+                       `func() []int`,
+               },
+               {genericPkg + `i0; import lib "generic_lib"; func _() { lib.F(42) }`,
+                       `F`,
+                       []string{`int`},
+                       `func(int)`,
+               },
+               {genericPkg + `type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {genericPkg + `type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {genericPkg + `type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {genericPkg + `type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
+                       `T`,
+                       []string{`[]int`, `int`},
+                       `struct{x []int; y int}`,
+               },
+               {genericPkg + `type4; import lib "generic_lib"; var _ lib.T[int]`,
+                       `T`,
+                       []string{`int`},
+                       `[]int`,
+               },
        }
 
        for _, test := range tests {
-               info := Info{Inferred: make(map[syntax.Expr]Inferred)}
-               name, err := mayTypecheck(t, "InferredInfo", test.src, &info)
-               if err != nil {
-                       t.Errorf("package %s: %v", name, err)
-                       continue
+               const lib = `package generic_lib
+
+func F[P any](P) {}
+
+type T[P any] []P
+`
+
+               imports := make(testImporter)
+               conf := Config{Importer: imports}
+               instances := make(map[*syntax.Name]Instance)
+               uses := make(map[*syntax.Name]Object)
+               makePkg := func(src string) *Package {
+                       f, err := parseSrc("p.go", src)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instances, Uses: uses})
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       imports[pkg.Name()] = pkg
+                       return pkg
                }
+               makePkg(lib)
+               pkg := makePkg(test.src)
 
-               // look for inferred type arguments and signature
+               // look for instance information
                var targs []Type
-               var sig *Signature
-               for call, inf := range info.Inferred {
-                       var fun syntax.Expr
-                       switch x := call.(type) {
-                       case *syntax.CallExpr:
-                               fun = x.Fun
-                       case *syntax.IndexExpr:
-                               fun = x.X
-                       default:
-                               panic(fmt.Sprintf("unexpected call expression type %T", call))
-                       }
-                       if syntax.String(fun) == test.fun {
-                               targs = inf.TArgs
-                               sig = inf.Sig
+               var typ Type
+               for ident, inst := range instances {
+                       if syntax.String(ident) == test.name {
+                               for i := 0; i < inst.TypeArgs.Len(); i++ {
+                                       targs = append(targs, inst.TypeArgs.At(i))
+                               }
+                               typ = inst.Type
+
+                               // Check that we can find the corresponding parameterized type.
+                               ptype := uses[ident].Type()
+                               lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
+                               if lister == nil || lister.TypeParams().Len() == 0 {
+                                       t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
+                                       continue
+                               }
+
+                               // Verify the invariant that re-instantiating the generic type with
+                               // TypeArgs results in an equivalent type.
+                               inst2, err := Instantiate(nil, ptype, targs, true)
+                               if err != nil {
+                                       t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
+                               }
+                               if !Identical(inst.Type, inst2) {
+                                       t.Errorf("%v and %v are not identical", inst.Type, inst2)
+                               }
                                break
                        }
                }
                if targs == nil {
-                       t.Errorf("package %s: no inferred information found for %s", name, test.fun)
+                       t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
                        continue
                }
 
                // check that type arguments are correct
                if len(targs) != len(test.targs) {
-                       t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs))
+                       t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
                        continue
                }
                for i, targ := range targs {
                        if got := targ.String(); got != test.targs[i] {
-                               t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i])
+                               t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
                                continue
                        }
                }
 
-               // check that signature is correct
-               if got := sig.String(); got != test.sig {
-                       t.Errorf("package %s: got %s; want %s", name, got, test.sig)
+               // check that the types match
+               if got := typ.Underlying().String(); got != test.typ {
+                       t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
                }
        }
 }
@@ -555,13 +622,6 @@ func TestDefsInfo(t *testing.T) {
                {`package p3; type x int`, `x`, `type p3.x int`},
                {`package p4; func f()`, `f`, `func p4.f()`},
                {`package p5; func f() int { x, _ := 1, 2; return x }`, `_`, `var _ int`},
-
-               // generic types must be sanitized
-               // (need to use sufficiently nested types to provoke unexpanded types)
-               {genericPkg + `g0; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
-               {genericPkg + `g1; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
-               {genericPkg + `g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
-               {genericPkg + `g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var generic_g3.g func(x struct{f generic_g3.t[string]})`},
        }
 
        for _, test := range tests {
@@ -600,13 +660,6 @@ func TestUsesInfo(t *testing.T) {
                {`package p2; func _() { _ = x }; var x int`, `x`, `var p2.x int`},
                {`package p3; func _() { type _ x }; type x int`, `x`, `type p3.x int`},
                {`package p4; func _() { _ = f }; func f()`, `f`, `func p4.f()`},
-
-               // generic types must be sanitized
-               // (need to use sufficiently nested types to provoke unexpanded types)
-               {genericPkg + `g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
-               {genericPkg + `g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
-               {genericPkg + `g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
-               {genericPkg + `g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func generic_g3.f(x struct{f generic_g3.t[string]})`},
        }
 
        for _, test := range tests {
@@ -1165,8 +1218,6 @@ func (m testImporter) Import(path string) (*Package, error) {
 }
 
 func TestSelection(t *testing.T) {
-       t.Skip("requires fixes around source positions")
-
        selections := make(map[*syntax.SelectorExpr]*Selection)
 
        imports := make(testImporter)
@@ -1290,11 +1341,9 @@ func main() {
        for e, sel := range selections {
                _ = sel.String() // assertion: must not panic
 
-               unimplemented()
-               _ = e
-               // start := fset.Position(e.Pos()).Offset
-               // end := fset.Position(e.End()).Offset
-               // syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
+               start := indexFor(mainSrc, syntax.StartPos(e))
+               end := indexFor(mainSrc, syntax.EndPos(e))
+               segment := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
 
                direct := "."
                if sel.Indirect() {
@@ -1304,13 +1353,11 @@ func main() {
                        sel.String(),
                        fmt.Sprintf("%s%v", direct, sel.Index()),
                }
-               unimplemented()
-               _ = got
-               // want := wantOut[syntax]
-               // if want != got {
-               //      t.Errorf("%s: got %q; want %q", syntax, got, want)
-               // }
-               // delete(wantOut, syntax)
+               want := wantOut[segment]
+               if want != got {
+                       t.Errorf("%s: got %q; want %q", segment, got, want)
+               }
+               delete(wantOut, segment)
 
                // We must explicitly assert properties of the
                // Signature's receiver since it doesn't participate
@@ -1320,19 +1367,31 @@ func main() {
                        got := sig.Recv().Type()
                        want := sel.Recv()
                        if !Identical(got, want) {
-                               unimplemented()
-                               // t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
+                               t.Errorf("%s: Recv() = %s, want %s", segment, got, want)
                        }
                } else if sig != nil && sig.Recv() != nil {
                        t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
                }
        }
        // Assert that all wantOut entries were used exactly once.
-       for syntax := range wantOut {
-               t.Errorf("no syntax.Selection found with syntax %q", syntax)
+       for segment := range wantOut {
+               t.Errorf("no syntax.Selection found with syntax %q", segment)
        }
 }
 
+// indexFor returns the index into s corresponding to the position pos.
+func indexFor(s string, pos syntax.Pos) int {
+       i, line := 0, 1 // string index and corresponding line
+       target := int(pos.Line())
+       for line < target && i < len(s) {
+               if s[i] == '\n' {
+                       line++
+               }
+               i++
+       }
+       return i + int(pos.Col()-1) // columns are 1-based
+}
+
 func TestIssue8518(t *testing.T) {
        imports := make(testImporter)
        conf := Config{
@@ -1582,6 +1641,7 @@ func TestConvertibleTo(t *testing.T) {
        }{
                {Typ[Int], Typ[Int], true},
                {Typ[Int], Typ[Float32], true},
+               {Typ[Int], Typ[String], true},
                {newDefined(Typ[Int]), Typ[Int], true},
                {newDefined(new(Struct)), new(Struct), true},
                {newDefined(Typ[Int]), new(Struct), false},
@@ -1589,8 +1649,7 @@ func TestConvertibleTo(t *testing.T) {
                {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
                {NewSlice(Typ[Int]), NewArray(Typ[Int], 10), false},
                {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
-               // Untyped string values are not permitted by the spec, so the below
-               // behavior is undefined.
+               // Untyped string values are not permitted by the spec, so the behavior below is undefined.
                {Typ[UntypedString], Typ[String], true},
        } {
                if got := ConvertibleTo(test.v, test.t); got != test.want {
@@ -1639,6 +1698,48 @@ func TestIdentical_issue15173(t *testing.T) {
        }
 }
 
+func TestIdenticalUnions(t *testing.T) {
+       tname := NewTypeName(nopos, nil, "myInt", nil)
+       myInt := NewNamed(tname, Typ[Int], nil)
+       tmap := map[string]*Term{
+               "int":     NewTerm(false, Typ[Int]),
+               "~int":    NewTerm(true, Typ[Int]),
+               "string":  NewTerm(false, Typ[String]),
+               "~string": NewTerm(true, Typ[String]),
+               "myInt":   NewTerm(false, myInt),
+       }
+       makeUnion := func(s string) *Union {
+               parts := strings.Split(s, "|")
+               var terms []*Term
+               for _, p := range parts {
+                       term := tmap[p]
+                       if term == nil {
+                               t.Fatalf("missing term %q", p)
+                       }
+                       terms = append(terms, term)
+               }
+               return NewUnion(terms)
+       }
+       for _, test := range []struct {
+               x, y string
+               want bool
+       }{
+               // These tests are just sanity checks. The tests for type sets and
+               // interfaces provide much more test coverage.
+               {"int|~int", "~int", true},
+               {"myInt|~int", "~int", true},
+               {"int|string", "string|int", true},
+               {"int|int|string", "string|int", true},
+               {"myInt|string", "int|string", false},
+       } {
+               x := makeUnion(test.x)
+               y := makeUnion(test.y)
+               if got := Identical(x, y); got != test.want {
+                       t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
+               }
+       }
+}
+
 func TestIssue15305(t *testing.T) {
        const src = "package p; func f() int16; var _ = f(undef)"
        f, err := parseSrc("issue15305.go", src)
@@ -1865,14 +1966,16 @@ func TestInstantiate(t *testing.T) {
 
        // type T should have one type parameter
        T := pkg.Scope().Lookup("T").Type().(*Named)
-       if n := T.TParams().Len(); n != 1 {
+       if n := T.TypeParams().Len(); n != 1 {
                t.Fatalf("expected 1 type parameter; found %d", n)
        }
 
        // instantiation should succeed (no endless recursion)
        // even with a nil *Checker
-       var check *Checker
-       res := check.Instantiate(nopos, T, []Type{Typ[Int]}, nil, false)
+       res, err := Instantiate(nil, T, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
 
        // instantiated type should point to itself
        if p := res.Underlying().(*Pointer).Elem(); p != res {
@@ -1880,6 +1983,39 @@ func TestInstantiate(t *testing.T) {
        }
 }
 
+func TestInstantiateErrors(t *testing.T) {
+       tests := []struct {
+               src    string // by convention, T must be the type being instantiated
+               targs  []Type
+               wantAt int // -1 indicates no error
+       }{
+               {"type T[P interface{~string}] int", []Type{Typ[Int]}, 0},
+               {"type T[P1 interface{int}, P2 interface{~string}] int", []Type{Typ[Int], Typ[Int]}, 1},
+               {"type T[P1 any, P2 interface{~[]P1}] int", []Type{Typ[Int], NewSlice(Typ[String])}, 1},
+               {"type T[P1 interface{~[]P2}, P2 any] int", []Type{NewSlice(Typ[String]), Typ[Int]}, 0},
+       }
+
+       for _, test := range tests {
+               src := genericPkg + "p; " + test.src
+               pkg, err := pkgFor(".", src, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               T := pkg.Scope().Lookup("T").Type().(*Named)
+
+               _, err = Instantiate(nil, T, test.targs, true)
+               if err == nil {
+                       t.Fatalf("Instantiate(%v, %v) returned nil error, want non-nil", T, test.targs)
+               }
+
+               gotAt := err.(ArgumentError).Index()
+               if gotAt != test.wantAt {
+                       t.Errorf("Instantate(%v, %v): error at index %d, want index %d", T, test.targs, gotAt, test.wantAt)
+               }
+       }
+}
+
 func TestInstanceIdentity(t *testing.T) {
        imports := make(testImporter)
        conf := Config{Importer: imports}
index 6184fc2ea506c1c4d29ec292211095e7177d3041..bfc55786830cb88dad7d2927820c10b0841802e9 100644 (file)
@@ -6,7 +6,10 @@
 
 package types2
 
-import "cmd/compile/internal/syntax"
+import (
+       "cmd/compile/internal/syntax"
+       "fmt"
+)
 
 // assignment reports whether x can be assigned to a variable of type T,
 // if necessary by attempting to convert untyped values to the appropriate
@@ -68,7 +71,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
        // x.typ is typed
 
        // A generic (non-instantiated) function value cannot be assigned to a variable.
-       if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
+       if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
                check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context)
        }
 
@@ -153,6 +156,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
 
        check.assignment(x, lhs.typ, context)
        if x.mode == invalid {
+               lhs.used = true // avoid follow-on "declared but not used" errors
                return nil
        }
 
@@ -161,7 +165,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
 
 func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type {
        if x.mode == invalid || x.typ == Typ[Invalid] {
-               check.useLHS(lhs)
+               check.use(lhs)
                return nil
        }
 
@@ -236,6 +240,28 @@ func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type {
        return x.typ
 }
 
+func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
+       measure := func(x int, unit string) string {
+               s := fmt.Sprintf("%d %s", x, unit)
+               if x != 1 {
+                       s += "s"
+               }
+               return s
+       }
+
+       vars := measure(nvars, "variable")
+       vals := measure(nvals, "value")
+       rhs0 := rhs[0]
+
+       if len(rhs) == 1 {
+               if call, _ := unparen(rhs0).(*syntax.CallExpr); call != nil {
+                       check.errorf(rhs0, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals)
+                       return
+               }
+       }
+       check.errorf(rhs0, "assignment mismatch: %s but %s", vars, vals)
+}
+
 // If returnPos is valid, initVars is called to type-check the assignment of
 // return expressions, and returnPos is the position of the return statement.
 func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syntax.Pos) {
@@ -244,6 +270,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syn
        if len(lhs) != len(rhs) {
                // invalidate lhs
                for _, obj := range lhs {
+                       obj.used = true // avoid declared but not used errors
                        if obj.typ == nil {
                                obj.typ = Typ[Invalid]
                        }
@@ -258,7 +285,11 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syn
                        check.errorf(returnPos, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
                        return
                }
-               check.errorf(rhs[0], "cannot initialize %d variables with %d values", len(lhs), len(rhs))
+               if check.conf.CompilerErrorMessages {
+                       check.assignError(orig_rhs, len(lhs), len(rhs))
+               } else {
+                       check.errorf(rhs[0], "cannot initialize %d variables with %d values", len(lhs), len(rhs))
+               }
                return
        }
 
@@ -276,8 +307,18 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syn
                return
        }
 
+       ok := true
        for i, lhs := range lhs {
-               check.initVar(lhs, rhs[i], context)
+               if check.initVar(lhs, rhs[i], context) == nil {
+                       ok = false
+               }
+       }
+
+       // avoid follow-on "declared but not used" errors if any initialization failed
+       if !ok {
+               for _, lhs := range lhs {
+                       lhs.used = true
+               }
        }
 }
 
@@ -285,14 +326,18 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
        rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2)
 
        if len(lhs) != len(rhs) {
-               check.useLHS(lhs...)
+               check.use(lhs...)
                // don't report an error if we already reported one
                for _, x := range rhs {
                        if x.mode == invalid {
                                return
                        }
                }
-               check.errorf(rhs[0], "cannot assign %d values to %d variables", len(rhs), len(lhs))
+               if check.conf.CompilerErrorMessages {
+                       check.assignError(orig_rhs, len(lhs), len(rhs))
+               } else {
+                       check.errorf(rhs[0], "cannot assign %d values to %d variables", len(rhs), len(lhs))
+               }
                return
        }
 
@@ -305,8 +350,26 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
                return
        }
 
+       ok := true
        for i, lhs := range lhs {
-               check.assignVar(lhs, rhs[i])
+               if check.assignVar(lhs, rhs[i]) == nil {
+                       ok = false
+               }
+       }
+
+       // avoid follow-on "declared but not used" errors if any assignment failed
+       if !ok {
+               // don't call check.use to avoid re-evaluation of the lhs expressions
+               for _, lhs := range lhs {
+                       if name, _ := unparen(lhs).(*syntax.Name); name != nil {
+                               if obj := check.lookup(name.Value); obj != nil {
+                                       // see comment in assignVar
+                                       if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg {
+                                               v.used = true
+                                       }
+                               }
+                       }
+               }
        }
 }
 
@@ -337,7 +400,7 @@ func (check *Checker) shortVarDecl(pos syntax.Pos, lhs, rhs []syntax.Expr) {
        for i, lhs := range lhs {
                ident, _ := lhs.(*syntax.Name)
                if ident == nil {
-                       check.useLHS(lhs)
+                       check.use(lhs)
                        check.errorf(lhs, "non-name %s on left side of :=", lhs)
                        hasErr = true
                        continue
index da2dcf54aa36537814f05015ea4db6f4f9a40949..548d55e10c564330e8601890ae7b397d483bd5ba 100644 (file)
@@ -82,7 +82,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                // of S and the respective parameter passing rules apply."
                S := x.typ
                var T Type
-               if s := asSlice(S); s != nil {
+               if s, _ := structure(S).(*Slice); s != nil {
                        T = s.elem
                } else {
                        check.errorf(x, invalidArg+"%s is not a slice", x)
@@ -101,7 +101,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                                if x.mode == invalid {
                                        return
                                }
-                               if isString(x.typ) {
+                               if allString(x.typ) {
                                        if check.Types != nil {
                                                sig := makeSig(S, S, x.typ)
                                                sig.variadic = true
@@ -291,8 +291,10 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                }
 
                // the argument types must be of floating-point type
-               f := func(x Type) Type {
-                       if t := asBasic(x); t != nil {
+               // (applyTypeFunc never calls f with a type parameter)
+               f := func(typ Type) Type {
+                       assert(asTypeParam(typ) == nil)
+                       if t := asBasic(typ); t != nil {
                                switch t.kind {
                                case Float32:
                                        return Typ[Complex64]
@@ -325,35 +327,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
 
        case _Copy:
                // copy(x, y []T) int
-               var dst Type
-               if t := asSlice(x.typ); t != nil {
-                       dst = t.elem
-               }
+               dst, _ := structure(x.typ).(*Slice)
 
                var y operand
                arg(&y, 1)
                if y.mode == invalid {
                        return
                }
-               var src Type
-               switch t := under(y.typ).(type) {
-               case *Basic:
-                       if isString(y.typ) {
-                               src = universeByte
-                       }
-               case *Slice:
-                       src = t.elem
-               case *TypeParam:
-                       check.error(x, "copy on generic operands not yet implemented")
-               }
+               src, _ := structureString(y.typ).(*Slice)
 
                if dst == nil || src == nil {
                        check.errorf(x, invalidArg+"copy expects slice arguments; found %s and %s", x, &y)
                        return
                }
 
-               if !Identical(dst, src) {
-                       check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+               if !Identical(dst.elem, src.elem) {
+                       check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)
                        return
                }
 
@@ -426,8 +415,10 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                }
 
                // the argument must be of complex type
-               f := func(x Type) Type {
-                       if t := asBasic(x); t != nil {
+               // (applyTypeFunc never calls f with a type parameter)
+               f := func(typ Type) Type {
+                       assert(asTypeParam(typ) == nil)
+                       if t := asBasic(typ); t != nil {
                                switch t.kind {
                                case Complex64:
                                        return Typ[Float32]
@@ -473,13 +464,13 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                }
 
                var min int // minimum number of arguments
-               switch optype(T).(type) {
+               switch structure(T).(type) {
                case *Slice:
                        min = 2
                case *Map, *Chan:
                        min = 1
-               case *top:
-                       check.errorf(arg0, invalidArg+"cannot make %s; type parameter has no structural type", arg0)
+               case nil:
+                       check.errorf(arg0, invalidArg+"cannot make %s; type set has no single underlying type", arg0)
                        return
                default:
                        check.errorf(arg0, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0)
@@ -662,6 +653,15 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)?
                check.recordSelection(selx, FieldVal, base, obj, index, false)
 
+               // record the selector expression (was bug - issue #47895)
+               {
+                       mode := value
+                       if x.mode == variable || indirect {
+                               mode = variable
+                       }
+                       check.record(&operand{mode, selx, obj.Type(), nil, 0})
+               }
+
                // The field offset is considered a variable even if the field is declared before
                // the part of the struct which is variable-sized. This makes both the rules
                // simpler and also permits (or at least doesn't prevent) a compiler from re-
@@ -754,7 +754,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                var t operand
                x1 := x
                for _, arg := range call.ArgList {
-                       check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+                       check.rawExpr(x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T))
                        check.dump("%v: %s", posFor(x1), x1)
                        x1 = &t // use incoming x only for first argument
                }
@@ -767,6 +767,56 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
        return true
 }
 
+// Structure is exported for the compiler.
+
+// If typ is a type parameter, Structure returns the single underlying
+// type of all types in the corresponding type constraint if it exists,
+// or nil otherwise. If typ is not a type parameter, Structure returns
+// the underlying type.
+func Structure(typ Type) Type {
+       return structure(typ)
+}
+
+// If typ is a type parameter, structure returns the single underlying
+// type of all types in the corresponding type constraint if it exists,
+// or nil otherwise. If typ is not a type parameter, structure returns
+// the underlying type.
+func structure(typ Type) Type {
+       var su Type
+       if underIs(typ, func(u Type) bool {
+               if su != nil && !Identical(su, u) {
+                       return false
+               }
+               // su == nil || Identical(su, u)
+               su = u
+               return true
+       }) {
+               return su
+       }
+       return nil
+}
+
+// structureString is like structure but also considers []byte and
+// string as "identical". In this case, if successful, the result
+// is always []byte.
+func structureString(typ Type) Type {
+       var su Type
+       if underIs(typ, func(u Type) bool {
+               if isString(u) {
+                       u = NewSlice(universeByte)
+               }
+               if su != nil && !Identical(su, u) {
+                       return false
+               }
+               // su == nil || Identical(su, u)
+               su = u
+               return true
+       }) {
+               return su
+       }
+       return nil
+}
+
 // hasVarSize reports if the size of type t is variable due to type parameters.
 func hasVarSize(t Type) bool {
        switch t := under(t).(type) {
@@ -780,7 +830,7 @@ func hasVarSize(t Type) bool {
                }
        case *TypeParam:
                return true
-       case *Named, *Union, *top:
+       case *Named, *Union:
                unreachable()
        }
        return false
@@ -798,7 +848,10 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
                // Test if t satisfies the requirements for the argument
                // type and collect possible result types at the same time.
                var terms []*Term
-               if !tp.iface().typeSet().is(func(t *term) bool {
+               if !tp.is(func(t *term) bool {
+                       if t == nil {
+                               return false
+                       }
                        if r := f(t.typ); r != nil {
                                terms = append(terms, NewTerm(t.tilde, r))
                                return true
@@ -808,16 +861,11 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
                        return nil
                }
 
-               // TODO(gri) Would it be ok to return just the one type
-               //           if len(rtypes) == 1? What about top-level
-               //           uses of real() where the result is used to
-               //           define type and initialize a variable?
-
-               // Construct a suitable new type parameter for the sum type. The
-               // type param is placed in the current package so export/import
+               // Construct a suitable new type parameter for the result type.
+               // The type parameter is placed in the current package so export/import
                // works as expected.
                tpar := NewTypeName(nopos, check.pkg, "<type parameter>", nil)
-               ptyp := check.NewTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
+               ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
                ptyp.index = tp.index
 
                return ptyp
index 52dbba1cb9810980fab197fee4e2b6d879085dc5..be5707cdfeac4dce2820226470cf2b1fc16608a4 100644 (file)
@@ -112,15 +112,15 @@ var builtinCalls = []struct {
 
        {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
        {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
-       {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(p.P₁) uintptr`},
+       {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(P) uintptr`},
 
        {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
        {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
-       {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(p.P₁) uintptr`},
+       {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(P) uintptr`},
 
        {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
        {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
-       {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(p.P₁) uintptr`},
+       {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(P) uintptr`},
 
        {"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
        {"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
index 94bcc4870bbbdcbca5f5e5a4b55c1bca5d2b09c7..49cae5a930d544debf09ef3252f43d0db88fc326 100644 (file)
@@ -15,6 +15,10 @@ import (
 // funcInst type-checks a function instantiation inst and returns the result in x.
 // The operand x must be the evaluation of inst.X and its type must be a signature.
 func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
+       if !check.allowVersion(check.pkg, 1, 18) {
+               check.softErrorf(inst.Pos(), "function instantiation requires go1.18 or later")
+       }
+
        xlist := unpackExpr(inst.Index)
        targs := check.typeList(xlist)
        if targs == nil {
@@ -26,7 +30,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
 
        // check number of type arguments (got) vs number of type parameters (want)
        sig := x.typ.(*Signature)
-       got, want := len(targs), sig.TParams().Len()
+       got, want := len(targs), sig.TypeParams().Len()
        if !useConstraintTypeInference && got != want || got > want {
                check.errorf(xlist[got-1], "got %d type arguments but want %d", got, want)
                x.mode = invalid
@@ -34,10 +38,8 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
                return
        }
 
-       // if we don't have enough type arguments, try type inference
-       inferred := false
        if got < want {
-               targs = check.infer(inst.Pos(), sig.TParams().list(), targs, nil, nil, true)
+               targs = check.infer(inst.Pos(), sig.TypeParams().list(), targs, nil, nil)
                if targs == nil {
                        // error was already reported
                        x.mode = invalid
@@ -45,7 +47,6 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
                        return
                }
                got = len(targs)
-               inferred = true
        }
        assert(got == want)
 
@@ -56,16 +57,44 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
        }
 
        // instantiate function signature
-       res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature)
-       assert(res.TParams().Len() == 0) // signature is not generic anymore
-       if inferred {
-               check.recordInferred(inst, targs, res)
-       }
+       res := check.instantiateSignature(x.Pos(), sig, targs, poslist)
+       assert(res.TypeParams().Len() == 0) // signature is not generic anymore
+       check.recordInstance(inst.X, targs, res)
        x.typ = res
        x.mode = value
        x.expr = inst
 }
 
+func (check *Checker) instantiateSignature(pos syntax.Pos, typ *Signature, targs []Type, posList []syntax.Pos) (res *Signature) {
+       assert(check != nil)
+       assert(len(targs) == typ.TypeParams().Len())
+
+       if check.conf.Trace {
+               check.trace(pos, "-- instantiating %s with %s", typ, targs)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(pos, "=> %s (under = %s)", res, res.Underlying())
+               }()
+       }
+
+       inst := check.instance(pos, typ, targs, check.conf.Context).(*Signature)
+       assert(len(posList) <= len(targs))
+       tparams := typ.TypeParams().list()
+       if i, err := check.verify(pos, tparams, targs); err != nil {
+               // best position for error reporting
+               pos := pos
+               if i < len(posList) {
+                       pos = posList[i]
+               }
+               check.softErrorf(pos, err.Error())
+       } else {
+               check.mono.recordInstance(check.pkg, pos, tparams, targs, posList)
+       }
+
+       return inst
+}
+
 func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
        var inst *syntax.IndexExpr // function instantiation, if any
        if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
@@ -79,8 +108,9 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
                x.expr = iexpr
                check.record(x)
        } else {
-               check.exprOrType(x, call.Fun)
+               check.exprOrType(x, call.Fun, true)
        }
+       // x.typ may be generic
 
        switch x.mode {
        case invalid:
@@ -90,6 +120,10 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
 
        case typexpr:
                // conversion
+               check.nonGeneric(x)
+               if x.mode == invalid {
+                       return conversion
+               }
                T := x.typ
                x.mode = invalid
                switch n := len(call.ArgList); n {
@@ -99,8 +133,8 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
                        check.expr(x, call.ArgList[0])
                        if x.mode != invalid {
                                if t := asInterface(T); t != nil {
-                                       if t.IsConstraint() {
-                                               check.errorf(call, "cannot use interface %s in conversion (contains type list or is comparable)", T)
+                                       if !t.IsMethodSet() {
+                                               check.errorf(call, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
                                                break
                                        }
                                }
@@ -118,6 +152,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
                return conversion
 
        case builtin:
+               // no need to check for non-genericity here
                id := x.id
                if !check.builtin(x, call, id) {
                        x.mode = invalid
@@ -131,9 +166,11 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
        }
 
        // ordinary function/method call
+       // signature may be generic
        cgocall := x.mode == cgofunc
 
-       sig := asSignature(x.typ)
+       // a type parameter may be "called" if all types have the same signature
+       sig, _ := structure(x.typ).(*Signature)
        if sig == nil {
                check.errorf(x, invalidOp+"cannot call non-function %s", x)
                x.mode = invalid
@@ -155,7 +192,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
                assert(len(targs) == len(xlist))
 
                // check number of type arguments (got) vs number of type parameters (want)
-               got, want := len(targs), sig.TParams().Len()
+               got, want := len(targs), sig.TypeParams().Len()
                if got > want {
                        check.errorf(xlist[want], "got %d type arguments but want %d", got, want)
                        check.use(call.ArgList...)
@@ -167,8 +204,14 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
 
        // evaluate arguments
        args, _ := check.exprList(call.ArgList, false)
+       isGeneric := sig.TypeParams().Len() > 0
        sig = check.arguments(call, sig, targs, args)
 
+       if isGeneric && sig.TypeParams().Len() == 0 {
+               // update the recorded type of call.Fun to its instantiated type
+               check.recordTypeAndValue(call.Fun, value, sig, nil)
+       }
+
        // determine result
        switch sig.results.Len() {
        case 0:
@@ -189,7 +232,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
 
        // if type inference failed, a parametrized result must be invalidated
        // (operands cannot have a parametrized type)
-       if x.mode == value && sig.TParams().Len() > 0 && isParameterized(sig.TParams().list(), x.typ) {
+       if x.mode == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ) {
                x.mode = invalid
        }
 
@@ -317,32 +360,42 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
        }
 
        // infer type arguments and instantiate signature if necessary
-       if sig.TParams().Len() > 0 {
+       if sig.TypeParams().Len() > 0 {
+               if !check.allowVersion(check.pkg, 1, 18) {
+                       if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
+                               check.softErrorf(iexpr.Pos(), "function instantiation requires go1.18 or later")
+                       } else {
+                               check.softErrorf(call.Pos(), "implicit function instantiation requires go1.18 or later")
+                       }
+               }
                // TODO(gri) provide position information for targs so we can feed
                //           it to the instantiate call for better error reporting
-               targs := check.infer(call.Pos(), sig.TParams().list(), targs, sigParams, args, true)
+               targs := check.infer(call.Pos(), sig.TypeParams().list(), targs, sigParams, args)
                if targs == nil {
                        return // error already reported
                }
 
                // compute result signature
-               rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature)
-               assert(rsig.TParams().Len() == 0) // signature is not generic anymore
-               check.recordInferred(call, targs, rsig)
+               rsig = check.instantiateSignature(call.Pos(), sig, targs, nil)
+               assert(rsig.TypeParams().Len() == 0) // signature is not generic anymore
+               check.recordInstance(call.Fun, targs, rsig)
 
                // Optimization: Only if the parameter list was adjusted do we
                // need to compute it from the adjusted list; otherwise we can
                // simply use the result signature's parameter list.
                if adjusted {
-                       sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs), nil).(*Tuple)
+                       sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TypeParams().list(), targs), nil).(*Tuple)
                } else {
                        sigParams = rsig.params
                }
        }
 
        // check arguments
-       for i, a := range args {
-               check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun))
+       if len(args) > 0 {
+               context := check.sprintf("argument to %s", call.Fun)
+               for i, a := range args {
+                       check.assignment(a, sigParams.vars[i].typ, context)
+               }
        }
 
        return
@@ -460,13 +513,11 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
                }
        }
 
-       check.exprOrType(x, e.X)
+       check.exprOrType(x, e.X, false)
        if x.mode == invalid {
                goto Error
        }
 
-       check.instantiatedOperand(x)
-
        obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
        if obj == nil {
                switch {
@@ -509,58 +560,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
 
        // methods may not have a fully set up signature yet
        if m, _ := obj.(*Func); m != nil {
-               // check.dump("### found method %s", m)
                check.objDecl(m, nil)
-               // If m has a parameterized receiver type, infer the type arguments from
-               // the actual receiver provided and then substitute the type parameters in
-               // the signature accordingly.
-               // TODO(gri) factor this code out
-               sig := m.typ.(*Signature)
-               if sig.RParams().Len() > 0 {
-                       // For inference to work, we must use the receiver type
-                       // matching the receiver in the actual method declaration.
-                       // If the method is embedded, the matching receiver is the
-                       // embedded struct or interface that declared the method.
-                       // Traverse the embedding to find that type (issue #44688).
-                       recv := x.typ
-                       for i := 0; i < len(index)-1; i++ {
-                               // The embedded type is either a struct or a pointer to
-                               // a struct except for the last one (which we don't need).
-                               recv = asStruct(derefStructPtr(recv)).Field(index[i]).typ
-                       }
-                       //check.dump("### recv = %s", recv)
-                       //check.dump("### method = %s rparams = %s tparams = %s", m, sig.rparams, sig.tparams)
-                       // The method may have a pointer receiver, but the actually provided receiver
-                       // may be a (hopefully addressable) non-pointer value, or vice versa. Here we
-                       // only care about inferring receiver type parameters; to make the inference
-                       // work, match up pointer-ness of receiver and argument.
-                       if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(recv) {
-                               if ptrRecv {
-                                       recv = NewPointer(recv)
-                               } else {
-                                       recv = recv.(*Pointer).base
-                               }
-                       }
-                       // Disable reporting of errors during inference below. If we're unable to infer
-                       // the receiver type arguments here, the receiver must be be otherwise invalid
-                       // and an error has been reported elsewhere.
-                       arg := operand{mode: variable, expr: x.expr, typ: recv}
-                       targs := check.infer(m.pos, sig.RParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */)
-                       //check.dump("### inferred targs = %s", targs)
-                       if targs == nil {
-                               // We may reach here if there were other errors (see issue #40056).
-                               goto Error
-                       }
-                       // Don't modify m. Instead - for now - make a copy of m and use that instead.
-                       // (If we modify m, some tests will fail; possibly because the m is in use.)
-                       // TODO(gri) investigate and provide a correct explanation here
-                       copy := *m
-                       copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs), nil)
-                       obj = &copy
-               }
-               // TODO(gri) we also need to do substitution for parameterized interface methods
-               //           (this breaks code in testdata/linalg.go2 at the moment)
-               //           12/20/2019: Is this TODO still correct?
        }
 
        if x.mode == typexpr {
@@ -659,56 +659,20 @@ Error:
 func (check *Checker) use(arg ...syntax.Expr) {
        var x operand
        for _, e := range arg {
-               // Certain AST fields may legally be nil (e.g., the ast.SliceExpr.High field).
-               if e == nil {
+               switch n := e.(type) {
+               case nil:
+                       // some AST fields may be nil (e.g., elements of syntax.SliceExpr.Index)
+                       // TODO(gri) can those fields really make it here?
                        continue
-               }
-               if l, _ := e.(*syntax.ListExpr); l != nil {
-                       check.use(l.ElemList...)
-                       continue
-               }
-               check.rawExpr(&x, e, nil)
-       }
-}
-
-// useLHS is like use, but doesn't "use" top-level identifiers.
-// It should be called instead of use if the arguments are
-// expressions on the lhs of an assignment.
-// The arguments must not be nil.
-func (check *Checker) useLHS(arg ...syntax.Expr) {
-       var x operand
-       for _, e := range arg {
-               // If the lhs is an identifier denoting a variable v, this assignment
-               // is not a 'use' of v. Remember current value of v.used and restore
-               // after evaluating the lhs via check.rawExpr.
-               var v *Var
-               var v_used bool
-               if ident, _ := unparen(e).(*syntax.Name); ident != nil {
-                       // never type-check the blank name on the lhs
-                       if ident.Value == "_" {
+               case *syntax.Name:
+                       // don't report an error evaluating blank
+                       if n.Value == "_" {
                                continue
                        }
-                       if _, obj := check.scope.LookupParent(ident.Value, nopos); obj != nil {
-                               // It's ok to mark non-local variables, but ignore variables
-                               // from other packages to avoid potential race conditions with
-                               // dot-imported variables.
-                               if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
-                                       v = w
-                                       v_used = v.used
-                               }
-                       }
-               }
-               check.rawExpr(&x, e, nil)
-               if v != nil {
-                       v.used = v_used // restore v.used
+               case *syntax.ListExpr:
+                       check.use(n.ElemList...)
+                       continue
                }
-       }
-}
-
-// instantiatedOperand reports an error of x is an uninstantiated (generic) type and sets x.typ to Typ[Invalid].
-func (check *Checker) instantiatedOperand(x *operand) {
-       if x.mode == typexpr && isGeneric(x.typ) {
-               check.errorf(x, "cannot use generic type %s without instantiation", x.typ)
-               x.typ = Typ[Invalid]
+               check.rawExpr(&x, e, nil, false)
        }
 }
index 6bc965c4978883448afb94093f381dc96bba9374..b9a76a8990058e921ce71154281a13357ef5b81f 100644 (file)
@@ -74,6 +74,28 @@ type dotImportKey struct {
        name  string
 }
 
+// An action describes a (delayed) action.
+type action struct {
+       f    func()      // action to be executed
+       desc *actionDesc // action description; may be nil, requires debug to be set
+}
+
+// If debug is set, describef sets a printf-formatted description for action a.
+// Otherwise, it is a no-op.
+func (a *action) describef(pos poser, format string, args ...interface{}) {
+       if debug {
+               a.desc = &actionDesc{pos, format, args}
+       }
+}
+
+// An actionDesc provides information on an action.
+// For debugging only.
+type actionDesc struct {
+       pos    poser
+       format string
+       args   []interface{}
+}
+
 // A Checker maintains the state of the type checker.
 // It must be created with NewChecker.
 type Checker struct {
@@ -86,7 +108,6 @@ type Checker struct {
        nextID  uint64                 // unique Id for type parameters (first valid Id is 1)
        objMap  map[Object]*declInfo   // maps package-level objects and (non-interface) methods to declaration info
        impMap  map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
-       typMap  map[string]*Named      // maps an instantiated named type hash to a *Named type
 
        // pkgPathMap maps package names to the set of distinct import paths we've
        // seen for that name, anywhere in the import graph. It is used for
@@ -101,15 +122,18 @@ type Checker struct {
        // information collected during type-checking of a set of package files
        // (initialized by Files, valid only for the duration of check.Files;
        // maps and lists are allocated on demand)
-       files        []*syntax.File            // list of package files
-       imports      []*PkgName                // list of imported packages
-       dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
+       files         []*syntax.File              // list of package files
+       imports       []*PkgName                  // list of imported packages
+       dotImportMap  map[dotImportKey]*PkgName   // maps dot-imported objects to the package they were dot-imported through
+       recvTParamMap map[*syntax.Name]*TypeParam // maps blank receiver type parameters to their type
+       mono          monoGraph                   // graph for detecting non-monomorphizable instantiation loops
 
        firstErr error                    // first error encountered
        methods  map[*TypeName][]*Func    // maps package scope type names to associated non-blank (non-interface) methods
        untyped  map[syntax.Expr]exprInfo // map of expressions without final type
-       delayed  []func()                 // stack of delayed action segments; segments are processed in FIFO order
+       delayed  []action                 // stack of delayed action segments; segments are processed in FIFO order
        objPath  []Object                 // path of object dependencies during type inference (for cycle reporting)
+       defTypes []*Named                 // defined types created during type checking, for final validation.
 
        // context within which the current object is type-checked
        // (valid only for the duration of type-checking a specific object)
@@ -144,8 +168,12 @@ func (check *Checker) rememberUntyped(e syntax.Expr, lhs bool, mode operandMode,
 // either at the end of the current statement, or in case of a local constant
 // or variable declaration, before the constant or variable is in scope
 // (so that f still sees the scope before any new declarations).
-func (check *Checker) later(f func()) {
-       check.delayed = append(check.delayed, f)
+// later returns the pushed action so one can provide a description
+// via action.describef for debugging, if desired.
+func (check *Checker) later(f func()) *action {
+       i := len(check.delayed)
+       check.delayed = append(check.delayed, action{f: f})
+       return &check.delayed[i]
 }
 
 // push pushes obj onto the object path and returns its index in the path.
@@ -171,6 +199,11 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
                conf = new(Config)
        }
 
+       // make sure we have a context
+       if conf.Context == nil {
+               conf.Context = NewContext()
+       }
+
        // make sure we have an info struct
        if info == nil {
                info = new(Info)
@@ -188,7 +221,6 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
                version: version,
                objMap:  make(map[Object]*declInfo),
                impMap:  make(map[importKey]*Package),
-               typMap:  make(map[string]*Named),
        }
 }
 
@@ -255,6 +287,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
 
        print := func(msg string) {
                if check.conf.Trace {
+                       fmt.Println()
                        fmt.Println(msg)
                }
        }
@@ -271,6 +304,9 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
        print("== processDelayed ==")
        check.processDelayed(0) // incl. all functions
 
+       print("== expandDefTypes ==")
+       check.expandDefTypes()
+
        print("== initOrder ==")
        check.initOrder()
 
@@ -282,6 +318,11 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
        print("== recordUntyped ==")
        check.recordUntyped()
 
+       if check.firstErr == nil {
+               // TODO(mdempsky): Ensure monomorph is safe when errors exist.
+               check.monomorph()
+       }
+
        check.pkg.complete = true
 
        // no longer needed - release memory
@@ -289,6 +330,8 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
        check.dotImportMap = nil
        check.pkgPathMap = nil
        check.seenPkgMap = nil
+       check.recvTParamMap = nil
+       check.defTypes = nil
 
        // TODO(gri) There's more memory we should release at this point.
 
@@ -304,12 +347,40 @@ func (check *Checker) processDelayed(top int) {
        // add more actions (such as nested functions), so
        // this is a sufficiently bounded process.
        for i := top; i < len(check.delayed); i++ {
-               check.delayed[i]() // may append to check.delayed
+               a := &check.delayed[i]
+               if check.conf.Trace && a.desc != nil {
+                       fmt.Println()
+                       check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
+               }
+               a.f() // may append to check.delayed
        }
        assert(top <= len(check.delayed)) // stack must not have shrunk
        check.delayed = check.delayed[:top]
 }
 
+func (check *Checker) expandDefTypes() {
+       // Ensure that every defined type created in the course of type-checking has
+       // either non-*Named underlying, or is unresolved.
+       //
+       // This guarantees that we don't leak any types whose underlying is *Named,
+       // because any unresolved instances will lazily compute their underlying by
+       // substituting in the underlying of their origin. The origin must have
+       // either been imported or type-checked and expanded here, and in either case
+       // its underlying will be fully expanded.
+       for i := 0; i < len(check.defTypes); i++ {
+               n := check.defTypes[i]
+               switch n.underlying.(type) {
+               case nil:
+                       if n.resolver == nil {
+                               panic("nil underlying")
+                       }
+               case *Named:
+                       n.under() // n.under may add entries to check.defTypes
+               }
+               n.check = nil
+       }
+}
+
 func (check *Checker) record(x *operand) {
        // convert x into a user-friendly set of values
        // TODO(gri) this code can be simplified
@@ -359,9 +430,9 @@ func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Ty
        }
        if mode == constant_ {
                assert(val != nil)
-               // We check is(typ, IsConstType) here as constant expressions may be
+               // We check allBasic(typ, IsConstType) here as constant expressions may be
                // recorded as type parameters.
-               assert(typ == Typ[Invalid] || is(typ, IsConstType))
+               assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
        }
        if m := check.Types; m != nil {
                m[x] = TypeAndValue{mode, typ, val}
@@ -412,12 +483,36 @@ func (check *Checker) recordCommaOkTypes(x syntax.Expr, a [2]Type) {
        }
 }
 
-func (check *Checker) recordInferred(call syntax.Expr, targs []Type, sig *Signature) {
-       assert(call != nil)
-       assert(sig != nil)
-       if m := check.Inferred; m != nil {
-               m[call] = Inferred{targs, sig}
+// recordInstance records instantiation information into check.Info, if the
+// Instances map is non-nil. The given expr must be an ident, selector, or
+// index (list) expr with ident or selector operand.
+//
+// TODO(rfindley): the expr parameter is fragile. See if we can access the
+// instantiated identifier in some other way.
+func (check *Checker) recordInstance(expr syntax.Expr, targs []Type, typ Type) {
+       ident := instantiatedIdent(expr)
+       assert(ident != nil)
+       assert(typ != nil)
+       if m := check.Instances; m != nil {
+               m[ident] = Instance{NewTypeList(targs), typ}
+       }
+}
+
+func instantiatedIdent(expr syntax.Expr) *syntax.Name {
+       var selOrIdent syntax.Expr
+       switch e := expr.(type) {
+       case *syntax.IndexExpr:
+               selOrIdent = e.X
+       case *syntax.SelectorExpr, *syntax.Name:
+               selOrIdent = e
+       }
+       switch x := selOrIdent.(type) {
+       case *syntax.Name:
+               return x
+       case *syntax.SelectorExpr:
+               return x.Sel
        }
+       panic("instantiated ident not found")
 }
 
 func (check *Checker) recordDef(id *syntax.Name, obj Object) {
index 41b0c54702d8d782ad42d4cf0c129f9540919253..d4c7b7b39b8df5edc0bc47dcbba6f6b976f9a397 100644 (file)
@@ -20,9 +20,6 @@
 //             _ = x /* ERROR "not declared" */ + 1
 //     }
 
-// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
-//           and test against strict mode.
-
 package types2_test
 
 import (
@@ -102,7 +99,7 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
        }
 
        var mode syntax.Mode
-       if strings.HasSuffix(filenames[0], ".go2") {
+       if strings.HasSuffix(filenames[0], ".go2") || manual {
                mode |= syntax.AllowGenerics
        }
        // parse files and collect parser errors
@@ -281,6 +278,7 @@ func TestManual(t *testing.T) {
 // TODO(gri) go/types has extra TestLongConstants and TestIndexRepresentability tests
 
 func TestCheck(t *testing.T)     { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", 75, false) } // TODO(gri) narrow column tolerance
+func TestSpec(t *testing.T)      { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/spec", 0, false) }
 func TestExamples(t *testing.T)  { testDirFiles(t, "testdata/examples", 0, false) }
 func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", 0, false) }
 
diff --git a/src/cmd/compile/internal/types2/context.go b/src/cmd/compile/internal/types2/context.go
new file mode 100644 (file)
index 0000000..a8f8591
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2021 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 types2
+
+import (
+       "bytes"
+       "strings"
+       "sync"
+)
+
+// An Context is an opaque type checking context. It may be used to share
+// identical type instances across type-checked packages or calls to
+// Instantiate.
+//
+// It is safe for concurrent use.
+type Context struct {
+       mu      sync.Mutex
+       typeMap map[string]*Named // type hash -> instance
+       nextID  int               // next unique ID
+       seen    map[*Named]int    // assigned unique IDs
+}
+
+// NewContext creates a new Context.
+func NewContext() *Context {
+       return &Context{
+               typeMap: make(map[string]*Named),
+               seen:    make(map[*Named]int),
+       }
+}
+
+// TypeHash returns a string representation of typ, which can be used as an exact
+// type hash: types that are identical produce identical string representations.
+// If typ is a *Named type and targs is not empty, typ is printed as if it were
+// instantiated with targs. The result is guaranteed to not contain blanks (" ").
+func (ctxt *Context) TypeHash(typ Type, targs []Type) string {
+       assert(ctxt != nil)
+       assert(typ != nil)
+       var buf bytes.Buffer
+
+       h := newTypeHasher(&buf, ctxt)
+       if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
+               // Don't use WriteType because we need to use the provided targs
+               // and not any targs that might already be with the *Named type.
+               h.typePrefix(named)
+               h.typeName(named.obj)
+               h.typeList(targs)
+       } else {
+               assert(targs == nil)
+               h.typ(typ)
+       }
+
+       return strings.Replace(buf.String(), " ", "#", -1) // ReplaceAll is not available in Go1.4
+}
+
+// typeForHash returns the recorded type for the type hash h, if it exists.
+// If no type exists for h and n is non-nil, n is recorded for h.
+func (ctxt *Context) typeForHash(h string, n *Named) *Named {
+       ctxt.mu.Lock()
+       defer ctxt.mu.Unlock()
+       if existing := ctxt.typeMap[h]; existing != nil {
+               return existing
+       }
+       if n != nil {
+               ctxt.typeMap[h] = n
+       }
+       return n
+}
+
+// idForType returns a unique ID for the pointer n.
+func (ctxt *Context) idForType(n *Named) int {
+       ctxt.mu.Lock()
+       defer ctxt.mu.Unlock()
+       id, ok := ctxt.seen[n]
+       if !ok {
+               id = ctxt.nextID
+               ctxt.seen[n] = id
+               ctxt.nextID++
+       }
+       return id
+}
index 6c26a4c4468d5688b9f7fc3ab1e106f38a461754..44e8aad84f065b4730d903489a1b34d4f01254b8 100644 (file)
@@ -16,32 +16,64 @@ import (
 func (check *Checker) conversion(x *operand, T Type) {
        constArg := x.mode == constant_
 
-       var ok bool
-       switch {
-       case constArg && isConstType(T):
-               // constant conversion
+       constConvertibleTo := func(T Type, val *constant.Value) bool {
                switch t := asBasic(T); {
-               case representableConst(x.val, check, t, &x.val):
-                       ok = true
+               case t == nil:
+                       // nothing to do
+               case representableConst(x.val, check, t, val):
+                       return true
                case isInteger(x.typ) && isString(t):
                        codepoint := unicode.ReplacementChar
                        if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
                                codepoint = rune(i)
                        }
-                       x.val = constant.MakeString(string(codepoint))
-                       ok = true
+                       if val != nil {
+                               *val = constant.MakeString(string(codepoint))
+                       }
+                       return true
                }
-       case x.convertibleTo(check, T):
+               return false
+       }
+
+       var ok bool
+       var cause string
+       switch {
+       case constArg && isConstType(T):
+               // constant conversion
+               ok = constConvertibleTo(T, &x.val)
+       case constArg && isTypeParam(T):
+               // x is convertible to T if it is convertible
+               // to each specific type in the type set of T.
+               // If T's type set is empty, or if it doesn't
+               // have specific types, constant x cannot be
+               // converted.
+               ok = under(T).(*TypeParam).underIs(func(u Type) bool {
+                       // t is nil if there are no specific type terms
+                       if u == nil {
+                               cause = check.sprintf("%s does not contain specific types", T)
+                               return false
+                       }
+                       if !constConvertibleTo(u, nil) {
+                               cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
+                               return false
+                       }
+                       return true
+               })
+               x.mode = value // type parameters are not constants
+       case x.convertibleTo(check, T, &cause):
                // non-constant conversion
-               x.mode = value
                ok = true
+               x.mode = value
        }
 
        if !ok {
-               if x.mode != invalid {
-                       check.errorf(x, "cannot convert %s to %s", x, T)
-                       x.mode = invalid
+               var err error_
+               err.errorf(x, "cannot convert %s to %s", x, T)
+               if cause != "" {
+                       err.errorf(nopos, cause)
                }
+               check.report(&err)
+               x.mode = invalid
                return
        }
 
@@ -61,7 +93,7 @@ func (check *Checker) conversion(x *operand, T Type) {
                        // ok
                } else if IsInterface(T) || constArg && !isConstType(T) {
                        final = Default(x.typ)
-               } else if isInteger(x.typ) && isString(T) {
+               } else if isInteger(x.typ) && allString(T) {
                        final = x.typ
                }
                check.updateExprType(x.expr, final, true)
@@ -80,16 +112,17 @@ func (check *Checker) conversion(x *operand, T Type) {
 // is tricky because we'd have to run updateExprType on the argument first.
 // (Issue #21982.)
 
-// convertibleTo reports whether T(x) is valid.
+// convertibleTo reports whether T(x) is valid. In the failure case, *cause
+// may be set to the cause for the failure.
 // The check parameter may be nil if convertibleTo is invoked through an
 // exported API call, i.e., when all methods have been type-checked.
-func (x *operand) convertibleTo(check *Checker, T Type) bool {
+func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
        // "x is assignable to T"
-       if ok, _ := x.assignableTo(check, T, nil); ok {
+       if ok, _ := x.assignableTo(check, T, cause); ok {
                return true
        }
 
-       // "x's type and T have identical underlying types if tags are ignored"
+       // "V and T have identical underlying types if tags are ignored"
        V := x.typ
        Vu := under(V)
        Tu := under(T)
@@ -97,7 +130,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
                return true
        }
 
-       // "x's type and T are unnamed pointer types and their pointer base types
+       // "V and T are unnamed pointer types and their pointer base types
        // have identical underlying types if tags are ignored"
        if V, ok := V.(*Pointer); ok {
                if T, ok := T.(*Pointer); ok {
@@ -107,22 +140,22 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
                }
        }
 
-       // "x's type and T are both integer or floating point types"
+       // "V and T are both integer or floating point types"
        if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
                return true
        }
 
-       // "x's type and T are both complex types"
+       // "V and T are both complex types"
        if isComplex(V) && isComplex(T) {
                return true
        }
 
-       // "x is an integer or a slice of bytes or runes and T is a string type"
+       // "V is an integer or a slice of bytes or runes and T is a string type"
        if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
                return true
        }
 
-       // "x is a string and T is a slice of bytes or runes"
+       // "V is a string and T is a slice of bytes or runes"
        if isString(V) && isBytesOrRunes(Tu) {
                return true
        }
@@ -137,7 +170,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
                return true
        }
 
-       // "x is a slice, T is a pointer-to-array type,
+       // "V a slice, T is a pointer-to-array type,
        // and the slice and array types have identical element types."
        if s := asSlice(V); s != nil {
                if p := asPointer(T); p != nil {
@@ -147,20 +180,88 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
                                                return true
                                        }
                                        // check != nil
-                                       if check.conf.CompilerErrorMessages {
-                                               check.error(x, "conversion of slices to array pointers only supported as of -lang=go1.17")
-                                       } else {
-                                               check.error(x, "conversion of slices to array pointers requires go1.17 or later")
+                                       if cause != nil {
+                                               if check.conf.CompilerErrorMessages {
+                                                       // compiler error message assumes a -lang flag
+                                                       *cause = "conversion of slices to array pointers only supported as of -lang=go1.17"
+                                               } else {
+                                                       *cause = "conversion of slices to array pointers requires go1.17 or later"
+                                               }
                                        }
-                                       x.mode = invalid // avoid follow-up error
+                                       return false
                                }
                        }
                }
        }
 
+       // optimization: if we don't have type parameters, we're done
+       Vp, _ := Vu.(*TypeParam)
+       Tp, _ := Tu.(*TypeParam)
+       if Vp == nil && Tp == nil {
+               return false
+       }
+
+       errorf := func(format string, args ...interface{}) {
+               if check != nil && cause != nil {
+                       msg := check.sprintf(format, args...)
+                       if *cause != "" {
+                               msg += "\n\t" + *cause
+                       }
+                       *cause = msg
+               }
+       }
+
+       // generic cases with specific type terms
+       // (generic operands cannot be constants, so we can ignore x.val)
+       switch {
+       case Vp != nil && Tp != nil:
+               x := *x // don't clobber outer x
+               return Vp.is(func(V *term) bool {
+                       if V == nil {
+                               return false // no specific types
+                       }
+                       x.typ = V.typ
+                       return Tp.is(func(T *term) bool {
+                               if !x.convertibleTo(check, T.typ, cause) {
+                                       errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
+                                       return false
+                               }
+                               return true
+                       })
+               })
+       case Vp != nil:
+               x := *x // don't clobber outer x
+               return Vp.is(func(V *term) bool {
+                       if V == nil {
+                               return false // no specific types
+                       }
+                       x.typ = V.typ
+                       if !x.convertibleTo(check, T, cause) {
+                               errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
+                               return false
+                       }
+                       return true
+               })
+       case Tp != nil:
+               return Tp.is(func(T *term) bool {
+                       if T == nil {
+                               return false // no specific types
+                       }
+                       if !x.convertibleTo(check, T.typ, cause) {
+                               errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
+                               return false
+                       }
+                       return true
+               })
+       }
+
        return false
 }
 
+// Helper predicates for convertibleToImpl. The types provided to convertibleToImpl
+// may be type parameters but they won't have specific type terms. Thus it is ok to
+// use the toT convenience converters in the predicates below.
+
 func isUintptr(typ Type) bool {
        t := asBasic(typ)
        return t != nil && t.kind == Uintptr
index aa9710788adef1f7cf01d53adc10b2a060b81f90..5d2a6c531b41ec5bdb7890faa39b04b5999dcb7d 100644 (file)
@@ -66,6 +66,12 @@ func (check *Checker) objDecl(obj Object, def *Named) {
                }()
        }
 
+       // Funcs with m.instRecv set have not yet be completed. Complete them now
+       // so that they have a type when objDecl exits.
+       if m, _ := obj.(*Func); m != nil && m.instRecv != nil {
+               check.completeMethod(check.conf.Context, m)
+       }
+
        // Checking the declaration of obj means inferring its type
        // (and possibly its value, for constants).
        // An object's type (and thus the object) may be in one of
@@ -309,6 +315,13 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                        }
                }
 
+       case *Union:
+               for _, t := range t.terms {
+                       if check.validType(t.typ, path) == invalid {
+                               return invalid
+                       }
+               }
+
        case *Interface:
                for _, etyp := range t.embeddeds {
                        if check.validType(etyp, path) == invalid {
@@ -317,7 +330,16 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                }
 
        case *Named:
-               t.expand(check.typMap)
+               // If t is parameterized, we should be considering the instantiated (expanded)
+               // form of t, but in general we can't with this algorithm: if t is an invalid
+               // type it may be so because it infinitely expands through a type parameter.
+               // Instantiating such a type would lead to an infinite sequence of instantiations.
+               // In general, we need "type flow analysis" to recognize those cases.
+               // Example: type A[T any] struct{ x A[*T] } (issue #48951)
+               // In this algorithm we always only consider the orginal, uninstantiated type.
+               // This won't recognize some invalid cases with parameterized types, but it
+               // will terminate.
+               t = t.orig
 
                // don't touch the type if it is from a different package or the Universe scope
                // (doing so would lead to a race condition - was issue #35049)
@@ -345,7 +367,8 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                                if tn == t.obj {
                                        check.cycleError(path[i:])
                                        t.info = invalid
-                                       return t.info
+                                       t.underlying = Typ[Invalid]
+                                       return invalid
                                }
                        }
                        panic("cycle start not found")
@@ -514,12 +537,27 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
        check.initVars(lhs, []syntax.Expr{init}, nopos)
 }
 
+// isImportedConstraint reports whether typ is an imported type constraint.
+func (check *Checker) isImportedConstraint(typ Type) bool {
+       named, _ := typ.(*Named)
+       if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
+               return false
+       }
+       u, _ := named.under().(*Interface)
+       return u != nil && !u.IsMethodSet()
+}
+
 func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
        assert(obj.typ == nil)
 
+       var rhs Type
        check.later(func() {
                check.validType(obj.typ, nil)
-       })
+               // If typ is local, an error was already reported where typ is specified/defined.
+               if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
+                       check.errorf(tdecl.Type.Pos(), "using type constraint %s requires go1.18 or later", rhs)
+               }
+       }).describef(obj, "validType(%s)", obj.Name())
 
        alias := tdecl.Alias
        if alias && tdecl.TParamList != nil {
@@ -540,7 +578,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
                }
 
                obj.typ = Typ[Invalid]
-               obj.typ = check.anyType(tdecl.Type)
+               rhs = check.varType(tdecl.Type)
+               obj.typ = rhs
                return
        }
 
@@ -551,38 +590,32 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
        if tdecl.TParamList != nil {
                check.openScope(tdecl, "type parameters")
                defer check.closeScope()
-               named.tparams = check.collectTypeParams(tdecl.TParamList)
+               check.collectTypeParams(&named.tparams, tdecl.TParamList)
        }
 
        // determine underlying type of named
-       named.fromRHS = check.definedType(tdecl.Type, named)
-       assert(named.fromRHS != nil)
-       // The underlying type of named may be itself a named type that is
-       // incomplete:
-       //
-       //      type (
-       //              A B
-       //              B *C
-       //              C A
-       //      )
-       //
-       // The type of C is the (named) type of A which is incomplete,
-       // and which has as its underlying type the named type B.
-       // Determine the (final, unnamed) underlying type by resolving
-       // any forward chain.
-       // TODO(gri) Investigate if we can just use named.fromRHS here
-       //           and rely on lazy computation of the underlying type.
-       named.underlying = under(named)
-
-       // If the RHS is a type parameter, it must be from this type declaration.
-       if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TParams().list(), tpar) < 0 {
-               check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar)
+       rhs = check.definedType(tdecl.Type, named)
+       assert(rhs != nil)
+       named.fromRHS = rhs
+
+       // If the underlying was not set while type-checking the right-hand side, it
+       // is invalid and an error should have been reported elsewhere.
+       if named.underlying == nil {
+               named.underlying = Typ[Invalid]
+       }
+
+       // Disallow a lone type parameter as the RHS of a type declaration (issue #45639).
+       // We can look directly at named.underlying because even if it is still a *Named
+       // type (underlying not fully resolved yet) it cannot become a type parameter due
+       // to this very restriction.
+       if tpar, _ := named.underlying.(*TypeParam); tpar != nil {
+               check.error(tdecl.Type, "cannot use a type parameter as RHS in type declaration")
                named.underlying = Typ[Invalid]
        }
 }
 
-func (check *Checker) collectTypeParams(list []*syntax.Field) *TParamList {
-       tparams := make([]*TypeName, len(list))
+func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Field) {
+       tparams := make([]*TypeParam, len(list))
 
        // Declare type parameters up-front.
        // The scope of type parameters starts at the beginning of the type parameter
@@ -591,44 +624,65 @@ func (check *Checker) collectTypeParams(list []*syntax.Field) *TParamList {
                tparams[i] = check.declareTypeParam(f.Name)
        }
 
+       // Set the type parameters before collecting the type constraints because
+       // the parameterized type may be used by the constraints (issue #47887).
+       // Example: type T[P T[P]] interface{}
+       *dst = bindTParams(tparams)
+
+       // Keep track of bounds for later validation.
        var bound Type
+       var bounds []Type
+       var posers []poser
        for i, f := range list {
                // Optimization: Re-use the previous type bound if it hasn't changed.
                // This also preserves the grouped output of type parameter lists
                // when printing type strings.
                if i == 0 || f.Type != list[i-1].Type {
-                       bound = check.boundType(f.Type)
+                       bound = check.bound(f.Type)
+                       bounds = append(bounds, bound)
+                       posers = append(posers, f.Type)
                }
-               tparams[i].typ.(*TypeParam).bound = bound
+               tparams[i].bound = bound
        }
 
-       return bindTParams(tparams)
-}
-
-func (check *Checker) declareTypeParam(name *syntax.Name) *TypeName {
-       tpar := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
-       check.NewTypeParam(tpar, nil)                           // assigns type to tpar as a side-effect
-       check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
-       return tpar
+       check.later(func() {
+               for i, bound := range bounds {
+                       if _, ok := under(bound).(*TypeParam); ok {
+                               check.error(posers[i], "cannot use a type parameter as constraint")
+                       }
+               }
+               for _, tpar := range tparams {
+                       tpar.iface() // compute type set
+               }
+       })
 }
 
-// boundType type-checks the type expression e and returns its type, or Typ[Invalid].
-// The type must be an interface, including the predeclared type "any".
-func (check *Checker) boundType(e syntax.Expr) Type {
-       // The predeclared identifier "any" is visible only as a type bound in a type parameter list.
-       // If we allow "any" for general use, this if-statement can be removed (issue #33232).
-       if name, _ := unparen(e).(*syntax.Name); name != nil && name.Value == "any" && check.lookup("any") == universeAny {
-               return universeAny.Type()
+func (check *Checker) bound(x syntax.Expr) Type {
+       // A type set literal of the form ~T and A|B may only appear as constraint;
+       // embed it in an implicit interface so that only interface type-checking
+       // needs to take care of such type expressions.
+       if op, _ := x.(*syntax.Operation); op != nil && (op.Op == syntax.Tilde || op.Op == syntax.Or) {
+               t := check.typ(&syntax.InterfaceType{MethodList: []*syntax.Field{{Type: x}}})
+               // mark t as implicit interface if all went well
+               if t, _ := t.(*Interface); t != nil {
+                       t.implicit = true
+               }
+               return t
        }
+       return check.typ(x)
+}
 
-       bound := check.typ(e)
-       check.later(func() {
-               u := under(bound)
-               if _, ok := u.(*Interface); !ok && u != Typ[Invalid] {
-                       check.errorf(e, "%s is not an interface", bound)
-               }
-       })
-       return bound
+func (check *Checker) declareTypeParam(name *syntax.Name) *TypeParam {
+       // Use Typ[Invalid] for the type constraint to ensure that a type
+       // is present even if the actual constraint has not been assigned
+       // yet.
+       // TODO(gri) Need to systematically review all uses of type parameter
+       //           constraints to make sure we don't rely on them if they
+       //           are not properly set yet.
+       tname := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
+       tpar := check.newTypeParam(tname, Typ[Invalid])          // assigns type to tname as a side-effect
+       check.declare(check.scope, name, tname, check.scope.pos) // TODO(gri) check scope position
+       return tpar
 }
 
 func (check *Checker) collectMethods(obj *TypeName) {
@@ -650,7 +704,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
        // and field names must be distinct."
        base := asNamed(obj.typ) // shouldn't fail but be conservative
        if base != nil {
-               u := safeUnderlying(base) // base should be expanded, but use safeUnderlying to be conservative
+               u := base.under()
                if t, _ := u.(*Struct); t != nil {
                        for _, fld := range t.fields {
                                if fld.name != "_" {
@@ -693,7 +747,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
                }
 
                if base != nil {
-                       base.load() // TODO(mdempsky): Probably unnecessary.
+                       base.resolve(nil) // TODO(mdempsky): Probably unnecessary.
                        base.methods = append(base.methods, m)
                }
        }
index a68273271b7434493f60ad45609e12b8f18b2070..b56d11a28bfdb007524f2e939d47d9adb4f1946b 100644 (file)
@@ -61,9 +61,12 @@ func (err *error_) msg(qf Qualifier) string {
        for i := range err.desc {
                p := &err.desc[i]
                if i > 0 {
-                       fmt.Fprintf(&buf, "\n\t%s: ", p.pos)
+                       fmt.Fprint(&buf, "\n\t")
+                       if p.pos.IsKnown() {
+                               fmt.Fprintf(&buf, "%s: ", p.pos)
+                       }
                }
-               buf.WriteString(sprintf(qf, p.format, p.args...))
+               buf.WriteString(sprintf(qf, false, p.format, p.args...))
        }
        return buf.String()
 }
@@ -82,7 +85,7 @@ func (err *error_) errorf(at poser, format string, args ...interface{}) {
        err.desc = append(err.desc, errorDesc{posFor(at), format, args})
 }
 
-func sprintf(qf Qualifier, format string, args ...interface{}) string {
+func sprintf(qf Qualifier, debug bool, format string, args ...interface{}) string {
        for i, arg := range args {
                switch a := arg.(type) {
                case nil:
@@ -98,7 +101,7 @@ func sprintf(qf Qualifier, format string, args ...interface{}) string {
                case Object:
                        arg = ObjectString(a, qf)
                case Type:
-                       arg = TypeString(a, qf)
+                       arg = typeString(a, qf, debug)
                }
                args[i] = arg
        }
@@ -143,7 +146,7 @@ func (check *Checker) markImports(pkg *Package) {
 }
 
 func (check *Checker) sprintf(format string, args ...interface{}) string {
-       return sprintf(check.qualifier, format, args...)
+       return sprintf(check.qualifier, false, format, args...)
 }
 
 func (check *Checker) report(err *error_) {
@@ -157,13 +160,13 @@ func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{})
        fmt.Printf("%s:\t%s%s\n",
                pos,
                strings.Repeat(".  ", check.indent),
-               check.sprintf(format, args...),
+               sprintf(check.qualifier, true, format, args...),
        )
 }
 
 // dump is only needed for debugging
 func (check *Checker) dump(format string, args ...interface{}) {
-       fmt.Println(check.sprintf(format, args...))
+       fmt.Println(sprintf(check.qualifier, true, format, args...))
 }
 
 func (check *Checker) err(at poser, msg string, soft bool) {
@@ -246,7 +249,7 @@ func stripAnnotations(s string) string {
        var b bytes.Buffer
        for _, r := range s {
                // strip #'s and subscript digits
-               if r != instanceMarker && !('₀' <= r && r < '₀'+10) { // '₀' == U+2080
+               if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
                        b.WriteRune(r)
                }
        }
index e1f0e83fc97d16f43be86cf4eb169d78e1bba284..ac73ca4650dc4a54852ad20092a7b6df99a4e4ce 100644 (file)
@@ -19,7 +19,7 @@ func TestError(t *testing.T) {
                t.Errorf("simple error: got %q, want %q", got, want)
        }
 
-       want = "<unknown position>: foo 42\n\t<unknown position>: bar 43"
+       want = "<unknown position>: foo 42\n\tbar 43"
        err.errorf(nopos, "bar %d", 43)
        if got := err.String(); got != want {
                t.Errorf("simple error: got %q, want %q", got, want)
@@ -35,7 +35,6 @@ func TestStripAnnotations(t *testing.T) {
                {"foo", "foo"},
                {"foo₀", "foo"},
                {"foo(T₀)", "foo(T)"},
-               {"#foo(T₀)", "foo(T)"},
        } {
                got := stripAnnotations(test.in)
                if got != test.want {
index 714bf77821399683925a986183c984869edc93b2..4edaad580e5fce5869181b35495307a508cc3f8e 100644 (file)
@@ -216,36 +216,36 @@ func fib(x int) int {
        // var x int:
        //   defined at fib.go:8:10
        //   used at 10:10, 12:13, 12:24, 9:5
-
-       // TODO(gri) Enable once positions are updated/verified
-       // Types and Values of each expression:
-       //  4: 8 | string              | type    : string
-       //  6:15 | len                 | builtin : func(string) int
-       //  6:15 | len(b)              | value   : int
-       //  6:19 | b                   | var     : fib.S
-       //  6:23 | S                   | type    : fib.S
-       //  6:23 | S(c)                | value   : fib.S
-       //  6:25 | c                   | var     : string
-       //  6:29 | "hello"             | value   : string = "hello"
-       //  8:12 | int                 | type    : int
-       //  8:17 | int                 | type    : int
-       //  9: 5 | x                   | var     : int
-       //  9: 5 | x < 2               | value   : untyped bool
-       //  9: 9 | 2                   | value   : int = 2
-       // 10:10 | x                   | var     : int
-       // 12: 9 | fib                 | value   : func(x int) int
-       // 12: 9 | fib(x - 1)          | value   : int
-       // 12: 9 | fib(x - 1) - fib(x - 2) | value   : int
-       // 12:13 | x                   | var     : int
-       // 12:13 | x - 1               | value   : int
-       // 12:15 | 1                   | value   : int = 1
-       // 12:20 | fib                 | value   : func(x int) int
-       // 12:20 | fib(x - 2)          | value   : int
-       // 12:24 | x                   | var     : int
-       // 12:24 | x - 2               | value   : int
-       // 12:26 | 2                   | value   : int = 2
 }
 
+// TODO(gri) Enable once positions are updated/verified
+// Types and Values of each expression:
+//  4: 8 | string              | type    : string
+//  6:15 | len                 | builtin : func(string) int
+//  6:15 | len(b)              | value   : int
+//  6:19 | b                   | var     : fib.S
+//  6:23 | S                   | type    : fib.S
+//  6:23 | S(c)                | value   : fib.S
+//  6:25 | c                   | var     : string
+//  6:29 | "hello"             | value   : string = "hello"
+//  8:12 | int                 | type    : int
+//  8:17 | int                 | type    : int
+//  9: 5 | x                   | var     : int
+//  9: 5 | x < 2               | value   : untyped bool
+//  9: 9 | 2                   | value   : int = 2
+// 10:10 | x                   | var     : int
+// 12: 9 | fib                 | value   : func(x int) int
+// 12: 9 | fib(x - 1)          | value   : int
+// 12: 9 | fib(x - 1) - fib(x - 2) | value   : int
+// 12:13 | x                   | var     : int
+// 12:13 | x - 1               | value   : int
+// 12:15 | 1                   | value   : int = 1
+// 12:20 | fib                 | value   : func(x int) int
+// 12:20 | fib(x - 2)          | value   : int
+// 12:24 | x                   | var     : int
+// 12:24 | x - 2               | value   : int
+// 12:26 | 2                   | value   : int = 2
+
 func mode(tv types2.TypeAndValue) string {
        switch {
        case tv.IsVoid():
index 6d8b423714c3fe992f81e7e91148dc12ad58034d..95b96f23345aa14f413d1ee9f23e32609d0c6b4d 100644 (file)
@@ -63,10 +63,10 @@ var unaryOpPredicates opPredicates
 func init() {
        // Setting unaryOpPredicates in init avoids declaration cycles.
        unaryOpPredicates = opPredicates{
-               syntax.Add: isNumeric,
-               syntax.Sub: isNumeric,
-               syntax.Xor: isInteger,
-               syntax.Not: isBoolean,
+               syntax.Add: allNumeric,
+               syntax.Sub: allNumeric,
+               syntax.Xor: allInteger,
+               syntax.Not: allBoolean,
        }
 }
 
@@ -113,6 +113,8 @@ func (check *Checker) overflow(x *operand) {
 
        // Typed constants must be representable in
        // their type after each constant operation.
+       // x.typ cannot be a type parameter (type
+       // parameters cannot be constant types).
        if isTyped(x.typ) {
                check.representable(x, asBasic(x.typ))
                return
@@ -127,9 +129,7 @@ func (check *Checker) overflow(x *operand) {
 }
 
 // opName returns the name of an operation, or the empty string.
-// For now, only operations that might overflow are handled.
-// TODO(gri) Expand this to a general mechanism giving names to
-//           nodes?
+// Only operations that might overflow are handled.
 func opName(e *syntax.Operation) string {
        op := int(e.Op)
        if e.Y == nil {
@@ -157,6 +157,8 @@ var op2str2 = [...]string{
        syntax.Shl: "shift",
 }
 
+// If typ is a type parameter, underIs returns the result of typ.underIs(f).
+// Otherwise, underIs returns the result of f(under(typ)).
 func underIs(typ Type, f func(Type) bool) bool {
        u := under(typ)
        if tpar, _ := u.(*TypeParam); tpar != nil {
@@ -708,10 +710,10 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
                return nil, nil, _InvalidUntypedConversion
        }
 
-       switch t := under(target).(type) {
+       switch u := under(target).(type) {
        case *Basic:
                if x.mode == constant_ {
-                       v, code := check.representation(x, t)
+                       v, code := check.representation(x, u)
                        if code != 0 {
                                return nil, nil, code
                        }
@@ -741,7 +743,8 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
                        return nil, nil, _InvalidUntypedConversion
                }
        case *TypeParam:
-               ok := t.underIs(func(t Type) bool {
+               // TODO(gri) review this code - doesn't look quite right
+               ok := u.underIs(func(t Type) bool {
                        target, _, _ := check.implicitTypeAndValue(x, t)
                        return target != nil
                })
@@ -752,7 +755,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
                // Update operand types to the default type rather than the target
                // (interface) type: values must have concrete dynamic types.
                // Untyped nil was handled upfront.
-               if !t.Empty() {
+               if !u.Empty() {
                        return nil, nil, _InvalidUntypedConversion // cannot assign untyped values to non-empty interfaces
                }
                return Default(x.typ), nil, 0 // default type for nil is nil
@@ -776,7 +779,7 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator) {
                        defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
                case syntax.Lss, syntax.Leq, syntax.Gtr, syntax.Geq:
                        // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
-                       defined = isOrdered(x.typ) && isOrdered(y.typ)
+                       defined = allOrdered(x.typ) && allOrdered(y.typ)
                default:
                        unreachable()
                }
@@ -830,7 +833,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) {
                xval = constant.ToInt(x.val)
        }
 
-       if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
+       if allInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
                // The lhs is of integer type or an untyped constant representable
                // as an integer. Nothing to do.
        } else {
@@ -861,11 +864,11 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) {
                        x.mode = invalid
                        return
                }
-       } else if !isInteger(y.typ) {
+       } else if !allInteger(y.typ) {
                check.errorf(y, invalidOp+"shift count %s must be integer", y)
                x.mode = invalid
                return
-       } else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
+       } else if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
                check.errorf(y, invalidOp+"signed shift count %s requires go1.13 or later", y)
                x.mode = invalid
                return
@@ -936,7 +939,7 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) {
        }
 
        // non-constant shift - lhs must be an integer
-       if !isInteger(x.typ) {
+       if !allInteger(x.typ) {
                check.errorf(x, invalidOp+"shifted operand %s must be integer", x)
                x.mode = invalid
                return
@@ -950,19 +953,19 @@ var binaryOpPredicates opPredicates
 func init() {
        // Setting binaryOpPredicates in init avoids declaration cycles.
        binaryOpPredicates = opPredicates{
-               syntax.Add: isNumericOrString,
-               syntax.Sub: isNumeric,
-               syntax.Mul: isNumeric,
-               syntax.Div: isNumeric,
-               syntax.Rem: isInteger,
-
-               syntax.And:    isInteger,
-               syntax.Or:     isInteger,
-               syntax.Xor:    isInteger,
-               syntax.AndNot: isInteger,
-
-               syntax.AndAnd: isBoolean,
-               syntax.OrOr:   isBoolean,
+               syntax.Add: allNumericOrString,
+               syntax.Sub: allNumeric,
+               syntax.Mul: allNumeric,
+               syntax.Div: allNumeric,
+               syntax.Rem: allInteger,
+
+               syntax.And:    allInteger,
+               syntax.Or:     allInteger,
+               syntax.Xor:    allInteger,
+               syntax.AndNot: allInteger,
+
+               syntax.AndAnd: allBoolean,
+               syntax.OrOr:   allBoolean,
        }
 }
 
@@ -992,10 +995,16 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
                if IsInterface(x.typ) || IsInterface(y.typ) {
                        return true
                }
-               if isBoolean(x.typ) != isBoolean(y.typ) {
+               if allBoolean(x.typ) != allBoolean(y.typ) {
+                       return false
+               }
+               if allString(x.typ) != allString(y.typ) {
                        return false
                }
-               if isString(x.typ) != isString(y.typ) {
+               if x.isNil() && !hasNil(y.typ) {
+                       return false
+               }
+               if y.isNil() && !hasNil(x.typ) {
                        return false
                }
                return true
@@ -1021,7 +1030,11 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
                // only report an error if we have valid types
                // (otherwise we had an error reported elsewhere already)
                if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
-                       check.errorf(x, invalidOp+"mismatched types %s and %s", x.typ, y.typ)
+                       if e != nil {
+                               check.errorf(x, invalidOp+"%s (mismatched types %s and %s)", e, x.typ, y.typ)
+                       } else {
+                               check.errorf(x, invalidOp+"%s %s= %s (mismatched types %s and %s)", lhs, op, rhs, x.typ, y.typ)
+                       }
                }
                x.mode = invalid
                return
@@ -1034,7 +1047,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
 
        if op == syntax.Div || op == syntax.Rem {
                // check for zero divisor
-               if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
+               if (x.mode == constant_ || allInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
                        check.error(&y, invalidOp+"division by zero")
                        x.mode = invalid
                        return
@@ -1087,8 +1100,10 @@ const (
 // rawExpr typechecks expression e and initializes x with the expression
 // value or type. If an error occurred, x.mode is set to invalid.
 // If hint != nil, it is the type of a composite literal element.
+// If allowGeneric is set, the operand type may be an uninstantiated
+// parameterized type or function value.
 //
-func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type) exprKind {
+func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type, allowGeneric bool) exprKind {
        if check.conf.Trace {
                check.trace(e.Pos(), "expr %s", e)
                check.indent++
@@ -1099,11 +1114,40 @@ func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type) exprKind {
        }
 
        kind := check.exprInternal(x, e, hint)
+
+       if !allowGeneric {
+               check.nonGeneric(x)
+       }
+
        check.record(x)
 
        return kind
 }
 
+// If x is a generic function or type, nonGeneric reports an error and invalidates x.mode and x.typ.
+// Otherwise it leaves x alone.
+func (check *Checker) nonGeneric(x *operand) {
+       if x.mode == invalid || x.mode == novalue {
+               return
+       }
+       var what string
+       switch t := x.typ.(type) {
+       case *Named:
+               if isGeneric(t) {
+                       what = "type"
+               }
+       case *Signature:
+               if t.tparams != nil {
+                       what = "function"
+               }
+       }
+       if what != "" {
+               check.errorf(x.expr, "cannot use generic %s %s without instantiation", what, x.expr)
+               x.mode = invalid
+               x.typ = Typ[Invalid]
+       }
+}
+
 // exprInternal contains the core of type checking of expressions.
 // Must only be called by rawExpr.
 //
@@ -1214,7 +1258,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                        goto Error
                }
 
-               switch utyp := under(base).(type) {
+               switch utyp := structure(base).(type) {
                case *Struct:
                        if len(e.ElemList) == 0 {
                                break
@@ -1388,7 +1432,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                x.typ = typ
 
        case *syntax.ParenExpr:
-               kind := check.rawExpr(x, e.X, nil)
+               kind := check.rawExpr(x, e.X, nil, false)
                x.expr = e
                return kind
 
@@ -1419,7 +1463,6 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                        check.errorf(x, "%s is not an interface type", x)
                        goto Error
                }
-               check.ordinaryType(x.Pos(), xtyp)
                // x.(type) expressions are encoded via TypeSwitchGuards
                if e.Type == nil {
                        check.error(e, invalidAST+"invalid use of AssertExpr")
@@ -1429,7 +1472,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                if T == Typ[Invalid] {
                        goto Error
                }
-               check.typeAssertion(posFor(x), x, xtyp, T)
+               check.typeAssertion(e, x, xtyp, T, false)
                x.mode = commaok
                x.typ = T
 
@@ -1471,7 +1514,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                        // unary expression
                        if e.Op == syntax.Mul {
                                // pointer indirection
-                               check.exprOrType(x, e.X)
+                               check.exprOrType(x, e.X, false)
                                switch x.mode {
                                case invalid:
                                        goto Error
@@ -1571,26 +1614,32 @@ func keyVal(x constant.Value) interface{} {
 }
 
 // typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
-func (check *Checker) typeAssertion(pos syntax.Pos, x *operand, xtyp *Interface, T Type) {
+func (check *Checker) typeAssertion(e syntax.Expr, x *operand, xtyp *Interface, T Type, typeSwitch bool) {
        method, wrongType := check.assertableTo(xtyp, T)
        if method == nil {
                return
        }
+
        var msg string
        if wrongType != nil {
                if Identical(method.typ, wrongType.typ) {
-                       msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name)
+                       msg = fmt.Sprintf("%s method has pointer receiver", method.name)
                } else {
-                       msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
+                       msg = fmt.Sprintf("wrong type for method %s: have %s, want %s", method.name, wrongType.typ, method.typ)
                }
        } else {
-               msg = "missing method " + method.name
+               msg = fmt.Sprintf("missing %s method", method.name)
        }
-       if check.conf.CompilerErrorMessages {
-               check.errorf(pos, "impossible type assertion: %s (%s)", x, msg)
+
+       var err error_
+       if typeSwitch {
+               err.errorf(e.Pos(), "impossible type switch case: %s", e)
+               err.errorf(nopos, "%s cannot have dynamic type %s (%s)", x, T, msg)
        } else {
-               check.errorf(pos, "%s cannot have dynamic type %s (%s)", x, T, msg)
+               err.errorf(e.Pos(), "impossible type assertion: %s", e)
+               err.errorf(nopos, "%s does not implement %s (%s)", T, x.typ, msg)
        }
+       check.report(&err)
 }
 
 // expr typechecks expression e and initializes x with the expression value.
@@ -1598,14 +1647,14 @@ func (check *Checker) typeAssertion(pos syntax.Pos, x *operand, xtyp *Interface,
 // If an error occurred, x.mode is set to invalid.
 //
 func (check *Checker) expr(x *operand, e syntax.Expr) {
-       check.rawExpr(x, e, nil)
+       check.rawExpr(x, e, nil, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
 }
 
 // multiExpr is like expr but the result may also be a multi-value.
 func (check *Checker) multiExpr(x *operand, e syntax.Expr) {
-       check.rawExpr(x, e, nil)
+       check.rawExpr(x, e, nil, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
 }
 
@@ -1615,16 +1664,18 @@ func (check *Checker) multiExpr(x *operand, e syntax.Expr) {
 //
 func (check *Checker) exprWithHint(x *operand, e syntax.Expr, hint Type) {
        assert(hint != nil)
-       check.rawExpr(x, e, hint)
+       check.rawExpr(x, e, hint, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
 }
 
 // exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If allowGeneric is set, the operand type may be an uninstantiated parameterized type or function
+// value.
 // If an error occurred, x.mode is set to invalid.
 //
-func (check *Checker) exprOrType(x *operand, e syntax.Expr) {
-       check.rawExpr(x, e, nil)
+func (check *Checker) exprOrType(x *operand, e syntax.Expr, allowGeneric bool) {
+       check.rawExpr(x, e, nil, allowGeneric)
        check.exclude(x, 1<<novalue)
        check.singleValue(x)
 }
@@ -1659,7 +1710,11 @@ func (check *Checker) singleValue(x *operand) {
                // tuple types are never named - no need for underlying type below
                if t, ok := x.typ.(*Tuple); ok {
                        assert(t.Len() != 1)
-                       check.errorf(x, "%d-valued %s where single value is expected", t.Len(), x)
+                       if check.conf.CompilerErrorMessages {
+                               check.errorf(x, "multiple-value %s in single-value context", x)
+                       } else {
+                               check.errorf(x, "%d-valued %s where single value is expected", t.Len(), x)
+                       }
                        x.mode = invalid
                }
        }
index 9f9dad6b64ee04d04ca3b9a59b7f82ad044709c1..03fea4fe7c6e19f9f1fe10839e56236c47628ac0 100644 (file)
@@ -29,8 +29,7 @@ func TestHilbert(t *testing.T) {
        }
 
        // parse source
-       // TODO(gri) get rid of []bytes to string conversion below
-       f, err := parseSrc("hilbert.go", string(src))
+       f, err := syntax.Parse(syntax.NewFileBase("hilbert.go"), bytes.NewReader(src), nil, nil, 0)
        if err != nil {
                t.Fatal(err)
        }
index e8755a1a68ea3872d1cf5e205eb50c21ca8f9d15..67110704e97f0d79d197b62f79ea3dd0181a9167 100644 (file)
@@ -15,7 +15,8 @@ import (
 // In that case x represents the uninstantiated function value and
 // it is the caller's responsibility to instantiate the function.
 func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst bool) {
-       check.exprOrType(x, e.X)
+       check.exprOrType(x, e.X, true)
+       // x may be generic
 
        switch x.mode {
        case invalid:
@@ -25,6 +26,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
        case typexpr:
                // type instantiation
                x.mode = invalid
+               // TODO(gri) here we re-evaluate e.X - try to avoid this
                x.typ = check.varType(e)
                if x.typ != Typ[Invalid] {
                        x.mode = typexpr
@@ -32,12 +34,18 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
                return false
 
        case value:
-               if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
+               if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
                        // function instantiation
                        return true
                }
        }
 
+       // x should not be generic at this point, but be safe and check
+       check.nonGeneric(x)
+       if x.mode == invalid {
+               return false
+       }
+
        // ordinary index expression
        valid := false
        length := int64(-1) // valid if >= 0
@@ -93,77 +101,80 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
 
        case *TypeParam:
                // TODO(gri) report detailed failure cause for better error messages
-               var tkey, telem Type // tkey != nil if we have maps
+               var key, elem Type // key != nil: we must have all maps
+               mode := variable   // non-maps result mode
+               // TODO(gri) factor out closure and use it for non-typeparam cases as well
                if typ.underIs(func(u Type) bool {
-                       var key, elem Type
-                       alen := int64(-1) // valid if >= 0
+                       l := int64(-1) // valid if >= 0
+                       var k, e Type  // k is only set for maps
                        switch t := u.(type) {
                        case *Basic:
-                               if !isString(t) {
-                                       return false
+                               if isString(t) {
+                                       e = universeByte
+                                       mode = value
                                }
-                               elem = universeByte
                        case *Array:
-                               elem = t.elem
-                               alen = t.len
+                               l = t.len
+                               e = t.elem
+                               if x.mode != variable {
+                                       mode = value
+                               }
                        case *Pointer:
-                               a, _ := under(t.base).(*Array)
-                               if a == nil {
-                                       return false
+                               if t := asArray(t.base); t != nil {
+                                       l = t.len
+                                       e = t.elem
                                }
-                               elem = a.elem
-                               alen = a.len
                        case *Slice:
-                               elem = t.elem
+                               e = t.elem
                        case *Map:
-                               key = t.key
-                               elem = t.elem
-                       default:
+                               k = t.key
+                               e = t.elem
+                       }
+                       if e == nil {
                                return false
                        }
-                       assert(elem != nil)
-                       if telem == nil {
+                       if elem == nil {
                                // first type
-                               tkey, telem = key, elem
-                               length = alen
-                       } else {
-                               // all map keys must be identical (incl. all nil)
-                               if !Identical(key, tkey) {
-                                       return false
-                               }
-                               // all element types must be identical
-                               if !Identical(elem, telem) {
-                                       return false
-                               }
-                               tkey, telem = key, elem
-                               // track the minimal length for arrays
-                               if alen >= 0 && alen < length {
-                                       length = alen
-                               }
+                               length = l
+                               key, elem = k, e
+                               return true
+                       }
+                       // all map keys must be identical (incl. all nil)
+                       // (that is, we cannot mix maps with other types)
+                       if !Identical(key, k) {
+                               return false
+                       }
+                       // all element types must be identical
+                       if !Identical(elem, e) {
+                               return false
+                       }
+                       // track the minimal length for arrays, if any
+                       if l >= 0 && l < length {
+                               length = l
                        }
                        return true
                }) {
                        // For maps, the index expression must be assignable to the map key type.
-                       if tkey != nil {
+                       if key != nil {
                                index := check.singleIndex(e)
                                if index == nil {
                                        x.mode = invalid
                                        return false
                                }
-                               var key operand
-                               check.expr(&key, index)
-                               check.assignment(&key, tkey, "map index")
+                               var k operand
+                               check.expr(&k, index)
+                               check.assignment(&kkey, "map index")
                                // ok to continue even if indexing failed - map element type is known
                                x.mode = mapindex
-                               x.typ = telem
+                               x.typ = elem
                                x.expr = e
                                return false
                        }
 
                        // no maps
                        valid = true
-                       x.mode = variable
-                       x.typ = telem
+                       x.mode = mode
+                       x.typ = elem
                }
        }
 
@@ -199,9 +210,14 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
 
        valid := false
        length := int64(-1) // valid if >= 0
-       switch typ := under(x.typ).(type) {
+       switch u := structure(x.typ).(type) {
+       case nil:
+               check.errorf(x, invalidOp+"cannot slice %s: type set has no single underlying type", x)
+               x.mode = invalid
+               return
+
        case *Basic:
-               if isString(typ) {
+               if isString(u) {
                        if e.Full {
                                check.error(x, invalidOp+"3-index slice of string")
                                x.mode = invalid
@@ -213,36 +229,31 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
                        }
                        // spec: "For untyped string operands the result
                        // is a non-constant value of type string."
-                       if typ.kind == UntypedString {
+                       if u.kind == UntypedString {
                                x.typ = Typ[String]
                        }
                }
 
        case *Array:
                valid = true
-               length = typ.len
+               length = u.len
                if x.mode != variable {
                        check.errorf(x, invalidOp+"%s (slice of unaddressable value)", x)
                        x.mode = invalid
                        return
                }
-               x.typ = &Slice{elem: typ.elem}
+               x.typ = &Slice{elem: u.elem}
 
        case *Pointer:
-               if typ := asArray(typ.base); typ != nil {
+               if u := asArray(u.base); u != nil {
                        valid = true
-                       length = typ.len
-                       x.typ = &Slice{elem: typ.elem}
+                       length = u.len
+                       x.typ = &Slice{elem: u.elem}
                }
 
        case *Slice:
                valid = true
                // x.typ doesn't change
-
-       case *TypeParam:
-               check.error(x, "generic slice expressions not yet implemented")
-               x.mode = invalid
-               return
        }
 
        if !valid {
@@ -375,7 +386,7 @@ func (check *Checker) isValidIndex(x *operand, what string, allowNegative bool)
        }
 
        // spec: "the index x must be of integer type or an untyped constant"
-       if !isInteger(x.typ) {
+       if !allInteger(x.typ) {
                check.errorf(x, invalidArg+"%s %s must be integer", what, x)
                return false
        }
index 7bf507471d337017dcf4d64c1935072b3e2bf25f..24c461f1c368af3bcb61aacdec9fed35f83d1902 100644 (file)
@@ -9,6 +9,7 @@ package types2
 import (
        "bytes"
        "cmd/compile/internal/syntax"
+       "fmt"
 )
 
 const useConstraintTypeInference = true
@@ -27,8 +28,7 @@ const useConstraintTypeInference = true
 //   3) Infer type arguments from untyped function arguments.
 //
 // Constraint type inference is used after each step to expand the set of type arguments.
-//
-func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, params *Tuple, args []*operand, report bool) (result []Type) {
+func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (result []Type) {
        if debug {
                defer func() {
                        assert(result == nil || len(result) == len(tparams))
@@ -60,7 +60,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
        // If we have type arguments, see how far we get with constraint type inference.
        if len(targs) > 0 && useConstraintTypeInference {
                var index int
-               targs, index = check.inferB(tparams, targs, report)
+               targs, index = check.inferB(tparams, targs)
                if targs == nil || index < 0 {
                        return targs
                }
@@ -105,9 +105,6 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
        }
 
        errorf := func(kind string, tpar, targ Type, arg *operand) {
-               if !report {
-                       return
-               }
                // provide a better error message if we can
                targs, index := u.x.types()
                if index == 0 {
@@ -122,7 +119,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
                                }
                        }
                        if allFailed {
-                               check.errorf(arg, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
+                               check.errorf(arg, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeParamsString(tparams))
                                return
                        }
                }
@@ -174,7 +171,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
        // Note that even if we don't have any type arguments, constraint type inference
        // may produce results for constraints that explicitly specify a type.
        if useConstraintTypeInference {
-               targs, index = check.inferB(tparams, targs, report)
+               targs, index = check.inferB(tparams, targs)
                if targs == nil || index < 0 {
                        return targs
                }
@@ -212,7 +209,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
 
        // Again, follow up with constraint type inference.
        if useConstraintTypeInference {
-               targs, index = check.inferB(tparams, targs, report)
+               targs, index = check.inferB(tparams, targs)
                if targs == nil || index < 0 {
                        return targs
                }
@@ -221,24 +218,22 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeName, targs []Type, p
        // At least one type argument couldn't be inferred.
        assert(targs != nil && index >= 0 && targs[index] == nil)
        tpar := tparams[index]
-       if report {
-               check.errorf(pos, "cannot infer %s (%s) (%s)", tpar.name, tpar.pos, targs)
-       }
+       check.errorf(pos, "cannot infer %s (%s)", tpar.obj.name, tpar.obj.pos)
        return nil
 }
 
-// typeNamesString produces a string containing all the
-// type names in list suitable for human consumption.
-func typeNamesString(list []*TypeName) string {
+// typeParamsString produces a string of the type parameter names
+// in list suitable for human consumption.
+func typeParamsString(list []*TypeParam) string {
        // common cases
        n := len(list)
        switch n {
        case 0:
                return ""
        case 1:
-               return list[0].name
+               return list[0].obj.name
        case 2:
-               return list[0].name + " and " + list[1].name
+               return list[0].obj.name + " and " + list[1].obj.name
        }
 
        // general case (n > 2)
@@ -248,15 +243,15 @@ func typeNamesString(list []*TypeName) string {
                if i > 0 {
                        b.WriteString(", ")
                }
-               b.WriteString(tname.name)
+               b.WriteString(tname.obj.name)
        }
        b.WriteString(", and ")
-       b.WriteString(list[n-1].name)
+       b.WriteString(list[n-1].obj.name)
        return b.String()
 }
 
 // IsParameterized reports whether typ contains any of the type parameters of tparams.
-func isParameterized(tparams []*TypeName, typ Type) bool {
+func isParameterized(tparams []*TypeParam, typ Type) bool {
        w := tpWalker{
                seen:    make(map[Type]bool),
                tparams: tparams,
@@ -266,7 +261,7 @@ func isParameterized(tparams []*TypeName, typ Type) bool {
 
 type tpWalker struct {
        seen    map[Type]bool
-       tparams []*TypeName
+       tparams []*TypeParam
 }
 
 func (w *tpWalker) isParameterized(typ Type) (res bool) {
@@ -280,7 +275,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
        }()
 
        switch t := typ.(type) {
-       case nil, *top, *Basic: // TODO(gri) should nil be handled here?
+       case nil, *Basic: // TODO(gri) should nil be handled here?
                break
 
        case *Array:
@@ -325,7 +320,7 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
                        }
                }
                return tset.is(func(t *term) bool {
-                       return w.isParameterized(t.typ)
+                       return t != nil && w.isParameterized(t.typ)
                })
 
        case *Map:
@@ -335,11 +330,11 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
                return w.isParameterized(t.elem)
 
        case *Named:
-               return w.isParameterizedTypeList(t.targs)
+               return w.isParameterizedTypeList(t.targs.list())
 
        case *TypeParam:
                // t must be one of w.tparams
-               return t.index < len(w.tparams) && w.tparams[t.index].typ == t
+               return tparamIndex(w.tparams, t) >= 0
 
        default:
                unreachable()
@@ -365,10 +360,10 @@ func (w *tpWalker) isParameterizedTypeList(list []Type) bool {
 // first type argument in that list that couldn't be inferred (and thus is nil). If all
 // type arguments were inferred successfully, index is < 0. The number of type arguments
 // provided may be less than the number of type parameters, but there must be at least one.
-func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (types []Type, index int) {
+func (check *Checker) inferB(tparams []*TypeParam, targs []Type) (types []Type, index int) {
        assert(len(tparams) >= len(targs) && len(targs) > 0)
 
-       // Setup bidirectional unification between those structural bounds
+       // Setup bidirectional unification between constraints
        // and the corresponding type arguments (which may be nil!).
        u := newUnifier(false)
        u.x.init(tparams)
@@ -381,22 +376,26 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
                }
        }
 
-       // Unify type parameters with their structural constraints, if any.
+       // If a constraint has a structural type, unify the corresponding type parameter with it.
        for _, tpar := range tparams {
-               typ := tpar.typ.(*TypeParam)
-               sbound := typ.structuralType()
+               sbound := structure(tpar)
                if sbound != nil {
-                       if !u.unify(typ, sbound) {
-                               if report {
-                                       check.errorf(tpar, "%s does not match %s", tpar, sbound)
-                               }
+                       // If the structural type is the underlying type of a single
+                       // defined type in the constraint, use that defined type instead.
+                       if named, _ := tpar.singleType().(*Named); named != nil {
+                               sbound = named
+                       }
+                       if !u.unify(tpar, sbound) {
+                               // TODO(gri) improve error message by providing the type arguments
+                               //           which we know already
+                               check.errorf(tpar.obj, "%s does not match %s", tpar, sbound)
                                return nil, 0
                        }
                }
        }
 
        // u.x.types() now contains the incoming type arguments plus any additional type
-       // arguments for which there were structural constraints. The newly inferred non-
+       // arguments which were inferred from structural types. The newly inferred non-
        // nil entries may still contain references to other type parameters.
        // For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
        // was given, unification produced the type list [int, []C, *A]. We eliminate the
@@ -409,6 +408,34 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
                }
        }
 
+       // The data structure of each (provided or inferred) type represents a graph, where
+       // each node corresponds to a type and each (directed) vertice points to a component
+       // type. The substitution process described above repeatedly replaces type parameter
+       // nodes in these graphs with the graphs of the types the type parameters stand for,
+       // which creates a new (possibly bigger) graph for each type.
+       // The substitution process will not stop if the replacement graph for a type parameter
+       // also contains that type parameter.
+       // For instance, for [A interface{ *A }], without any type argument provided for A,
+       // unification produces the type list [*A]. Substituting A in *A with the value for
+       // A will lead to infinite expansion by producing [**A], [****A], [********A], etc.,
+       // because the graph A -> *A has a cycle through A.
+       // Generally, cycles may occur across multiple type parameters and inferred types
+       // (for instance, consider [P interface{ *Q }, Q interface{ func(P) }]).
+       // We eliminate cycles by walking the graphs for all type parameters. If a cycle
+       // through a type parameter is detected, cycleFinder nils out the respectice type
+       // which kills the cycle; this also means that the respective type could not be
+       // inferred.
+       //
+       // TODO(gri) If useful, we could report the respective cycle as an error. We don't
+       //           do this now because type inference will fail anyway, and furthermore,
+       //           constraints with cycles of this kind cannot currently be satisfied by
+       //           any user-suplied type. But should that change, reporting an error
+       //           would be wrong.
+       w := cycleFinder{tparams, types, make(map[Type]bool)}
+       for _, t := range tparams {
+               w.typ(t) // t != nil
+       }
+
        // dirty tracks the indices of all types that may still contain type parameters.
        // We know that nil type entries and entries corresponding to provided (non-nil)
        // type arguments are clean, so exclude them from the start.
@@ -457,3 +484,98 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
 
        return
 }
+
+type cycleFinder struct {
+       tparams []*TypeParam
+       types   []Type
+       seen    map[Type]bool
+}
+
+func (w *cycleFinder) typ(typ Type) {
+       if w.seen[typ] {
+               // We have seen typ before. If it is one of the type parameters
+               // in tparams, iterative substitution will lead to infinite expansion.
+               // Nil out the corresponding type which effectively kills the cycle.
+               if tpar, _ := typ.(*TypeParam); tpar != nil {
+                       if i := tparamIndex(w.tparams, tpar); i >= 0 {
+                               // cycle through tpar
+                               w.types[i] = nil
+                       }
+               }
+               // If we don't have one of our type parameters, the cycle is due
+               // to an ordinary recursive type and we can just stop walking it.
+               return
+       }
+       w.seen[typ] = true
+       defer delete(w.seen, typ)
+
+       switch t := typ.(type) {
+       case *Basic:
+               // nothing to do
+
+       case *Array:
+               w.typ(t.elem)
+
+       case *Slice:
+               w.typ(t.elem)
+
+       case *Struct:
+               w.varList(t.fields)
+
+       case *Pointer:
+               w.typ(t.base)
+
+       // case *Tuple:
+       //      This case should not occur because tuples only appear
+       //      in signatures where they are handled explicitly.
+
+       case *Signature:
+               // There are no "method types" so we should never see a recv.
+               assert(t.recv == nil)
+               if t.params != nil {
+                       w.varList(t.params.vars)
+               }
+               if t.results != nil {
+                       w.varList(t.results.vars)
+               }
+
+       case *Union:
+               for _, t := range t.terms {
+                       w.typ(t.typ)
+               }
+
+       case *Interface:
+               for _, m := range t.methods {
+                       w.typ(m.typ)
+               }
+               for _, t := range t.embeddeds {
+                       w.typ(t)
+               }
+
+       case *Map:
+               w.typ(t.key)
+               w.typ(t.elem)
+
+       case *Chan:
+               w.typ(t.elem)
+
+       case *Named:
+               for _, tpar := range t.TypeArgs().list() {
+                       w.typ(tpar)
+               }
+
+       case *TypeParam:
+               if i := tparamIndex(w.tparams, t); i >= 0 && w.types[i] != nil {
+                       w.typ(w.types[i])
+               }
+
+       default:
+               panic(fmt.Sprintf("unexpected %T", typ))
+       }
+}
+
+func (w *cycleFinder) varList(list []*Var) {
+       for _, v := range list {
+               w.typ(v.typ)
+       }
+}
index fff263545600412727e7063abab69fbecd11f3f7..44cf593ffbf1fa5e69cacdce6a758c3ce7b64b51 100644 (file)
@@ -9,153 +9,158 @@ package types2
 
 import (
        "cmd/compile/internal/syntax"
+       "errors"
        "fmt"
 )
 
-// Instantiate instantiates the type typ with the given type arguments
-// targs. To check type constraint satisfaction, verify must be set.
-// pos and posList correspond to the instantiation and type argument
-// positions respectively; posList may be nil or shorter than the number
-// of type arguments provided.
-// typ must be a *Named or a *Signature type, and its number of type
-// parameters must match the number of provided type arguments.
-// The receiver (check) may be nil if and only if verify is not set.
-// The result is a new, instantiated (not generic) type of the same kind
-// (either a *Named or a *Signature).
-// Any methods attached to a *Named are simply copied; they are not
-// instantiated.
-func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) (res Type) {
-       // TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
-       var tparams []*TypeName
-       switch t := typ.(type) {
-       case *Named:
-               return check.instantiateLazy(pos, t, targs, posList, verify)
-       case *Signature:
-               tparams = t.TParams().list()
-               defer func() {
-                       // If we had an unexpected failure somewhere don't panic below when
-                       // asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
-                       // is returned.
-                       if _, ok := res.(*Signature); !ok {
-                               return
-                       }
-                       // If the signature doesn't use its type parameters, subst
-                       // will not make a copy. In that case, make a copy now (so
-                       // we can set tparams to nil w/o causing side-effects).
-                       if t == res {
-                               copy := *t
-                               res = &copy
-                       }
-                       // After instantiating a generic signature, it is not generic
-                       // anymore; we need to set tparams to nil.
-                       res.(*Signature).tparams = nil
-               }()
-       default:
-               // only types and functions can be generic
-               panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
+// Instantiate instantiates the type typ with the given type arguments targs.
+// typ must be a *Named or a *Signature type, and its number of type parameters
+// must match the number of provided type arguments. The result is a new,
+// instantiated (not parameterized) type of the same kind (either a *Named or a
+// *Signature). Any methods attached to a *Named are simply copied; they are
+// not instantiated.
+//
+// If ctxt is non-nil, it may be used to de-dupe the instance against previous
+// instances with the same identity.
+//
+// If verify is set and constraint satisfaction fails, the returned error may
+// be of dynamic type ArgumentError indicating which type argument did not
+// satisfy its corresponding type parameter constraint, and why.
+//
+// TODO(rfindley): change this function to also return an error if lengths of
+// tparams and targs do not match.
+func Instantiate(ctxt *Context, typ Type, targs []Type, validate bool) (Type, error) {
+       inst := (*Checker)(nil).instance(nopos, typ, targs, ctxt)
+
+       var err error
+       if validate {
+               var tparams []*TypeParam
+               switch t := typ.(type) {
+               case *Named:
+                       tparams = t.TypeParams().list()
+               case *Signature:
+                       tparams = t.TypeParams().list()
+               }
+               if i, err := (*Checker)(nil).verify(nopos, tparams, targs); err != nil {
+                       return inst, ArgumentError{i, err}
+               }
        }
 
-       inst := check.instantiate(pos, typ, tparams, targs, posList, nil)
-       if verify && len(tparams) == len(targs) {
-               check.verify(pos, tparams, targs, posList)
-       }
-       return inst
+       return inst, err
 }
 
-func (check *Checker) instantiate(pos syntax.Pos, typ Type, tparams []*TypeName, targs []Type, posList []syntax.Pos, typMap map[string]*Named) (res Type) {
-       // the number of supplied types must match the number of type parameters
-       if len(targs) != len(tparams) {
-               // TODO(gri) provide better error message
-               if check != nil {
-                       check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams))
-                       return Typ[Invalid]
-               }
-               panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
-       }
-
-       if check != nil && check.conf.Trace {
-               check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
-               check.indent++
-               defer func() {
-                       check.indent--
-                       var under Type
-                       if res != nil {
-                               // Calling under() here may lead to endless instantiations.
-                               // Test case: type T[P any] T[P]
-                               // TODO(gri) investigate if that's a bug or to be expected.
-                               under = safeUnderlying(res)
+// instance creates a type or function instance using the given original type
+// typ and arguments targs. For Named types the resulting instance will be
+// unexpanded.
+func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type, ctxt *Context) Type {
+       switch t := typ.(type) {
+       case *Named:
+               var h string
+               if ctxt != nil {
+                       h = ctxt.TypeHash(t, targs)
+                       // typ may already have been instantiated with identical type arguments. In
+                       // that case, re-use the existing instance.
+                       if named := ctxt.typeForHash(h, nil); named != nil {
+                               return named
                        }
-                       check.trace(pos, "=> %s (under = %s)", res, under)
-               }()
-       }
-
-       assert(len(posList) <= len(targs))
+               }
+               tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
+               named := check.newNamed(tname, t, nil, nil, nil) // underlying, tparams, and methods are set when named is resolved
+               named.targs = NewTypeList(targs)
+               named.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, []*Func) {
+                       return expandNamed(ctxt, n, pos)
+               }
+               if ctxt != nil {
+                       // It's possible that we've lost a race to add named to the context.
+                       // In this case, use whichever instance is recorded in the context.
+                       named = ctxt.typeForHash(h, named)
+               }
+               return named
 
-       if len(tparams) == 0 {
-               return typ // nothing to do (minor optimization)
+       case *Signature:
+               tparams := t.TypeParams()
+               if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
+                       return Typ[Invalid]
+               }
+               if tparams.Len() == 0 {
+                       return typ // nothing to do (minor optimization)
+               }
+               sig := check.subst(pos, typ, makeSubstMap(tparams.list(), targs), ctxt).(*Signature)
+               // If the signature doesn't use its type parameters, subst
+               // will not make a copy. In that case, make a copy now (so
+               // we can set tparams to nil w/o causing side-effects).
+               if sig == t {
+                       copy := *sig
+                       sig = &copy
+               }
+               // After instantiating a generic signature, it is not generic
+               // anymore; we need to set tparams to nil.
+               sig.tparams = nil
+               return sig
        }
 
-       return check.subst(pos, typ, makeSubstMap(tparams, targs), typMap)
+       // only types and functions can be generic
+       panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
 }
 
-// instantiateLazy avoids actually instantiating the type until needed. typ
-// must be a *Named type.
-func (check *Checker) instantiateLazy(pos syntax.Pos, base *Named, targs []Type, posList []syntax.Pos, verify bool) Type {
-       if verify && base.TParams().Len() == len(targs) {
-               // TODO: lift the nil check in verify to here.
-               check.later(func() {
-                       check.verify(pos, base.tparams.list(), targs, posList)
-               })
-       }
-
-       h := instantiatedHash(base, targs)
-       if check != nil {
-               // typ may already have been instantiated with identical type arguments. In
-               // that case, re-use the existing instance.
-               if named := check.typMap[h]; named != nil {
-                       return named
+// validateTArgLen verifies that the length of targs and tparams matches,
+// reporting an error if not. If validation fails and check is nil,
+// validateTArgLen panics.
+func (check *Checker) validateTArgLen(pos syntax.Pos, ntparams, ntargs int) bool {
+       if ntargs != ntparams {
+               // TODO(gri) provide better error message
+               if check != nil {
+                       check.errorf(pos, "got %d arguments but %d type parameters", ntargs, ntparams)
+                       return false
                }
+               panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
        }
-
-       tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil)
-       named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded
-       named.targs = targs
-       named.instance = &instance{pos, posList}
-       if check != nil {
-               check.typMap[h] = named
-       }
-
-       return named
+       return true
 }
 
-func (check *Checker) verify(pos syntax.Pos, tparams []*TypeName, targs []Type, posList []syntax.Pos) {
-       if check == nil {
-               panic("cannot have nil Checker if verifying constraints")
-       }
-
+func (check *Checker) verify(pos syntax.Pos, tparams []*TypeParam, targs []Type) (int, error) {
        smap := makeSubstMap(tparams, targs)
-       for i, tname := range tparams {
-               // best position for error reporting
-               pos := pos
-               if i < len(posList) {
-                       pos = posList[i]
-               }
-
+       for i, tpar := range tparams {
                // stop checking bounds after the first failure
-               if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) {
-                       break
+               if err := check.satisfies(pos, targs[i], tpar, smap); err != nil {
+                       return i, err
                }
        }
+       return -1, nil
 }
 
 // satisfies reports whether the type argument targ satisfies the constraint of type parameter
 // parameter tpar (after any of its type parameters have been substituted through smap).
 // A suitable error is reported if the result is false.
 // TODO(gri) This should be a method of interfaces or type sets.
-func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap substMap) bool {
+func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap substMap) error {
        iface := tpar.iface()
+
+       // Every type argument satisfies interface{}.
        if iface.Empty() {
-               return true // no type bound
+               return nil
+       }
+
+       // A type argument that is a type parameter with an empty type set satisfies any constraint.
+       // (The empty set is a subset of any set.)
+       if targ := asTypeParam(targ); targ != nil && targ.iface().typeSet().IsEmpty() {
+               return nil
+       }
+
+       // TODO(rfindley): it would be great if users could pass in a qualifier here,
+       // rather than falling back to verbose qualification. Maybe this can be part
+       // of the shared context.
+       var qf Qualifier
+       if check != nil {
+               qf = check.qualifier
+       }
+       errorf := func(format string, args ...interface{}) error {
+               return errors.New(sprintf(qf, false, format, args...))
+       }
+
+       // No type argument with non-empty type set satisfies the empty type set.
+       if iface.typeSet().IsEmpty() {
+               return errorf("%s does not satisfy %s (constraint type set is empty)", targ, tpar.bound)
        }
 
        // The type parameter bound is parameterized with the same type parameters
@@ -168,11 +173,9 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
        // TODO(gri) the error messages needs to be better, here
        if iface.IsComparable() && !Comparable(targ) {
                if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsAll() {
-                       check.softErrorf(pos, "%s has no constraints", targ)
-                       return false
+                       return errorf("%s has no constraints", targ)
                }
-               check.softErrorf(pos, "%s does not satisfy comparable", targ)
-               return false
+               return errorf("%s does not satisfy comparable", targ)
        }
 
        // targ must implement iface (methods)
@@ -182,8 +185,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
                // method set is empty.
                // TODO(gri) is this what we want? (spec question)
                if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
-                       check.errorf(pos, "%s has no methods", targ)
-                       return false
+                       return errorf("%s has no methods", targ)
                }
                if m, wrong := check.missingMethod(targ, iface, true); m != nil {
                        // TODO(gri) needs to print updated name to avoid major confusion in error message!
@@ -193,44 +195,37 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
                        if wrong != nil {
                                // TODO(gri) This can still report uninstantiated types which makes the error message
                                //           more difficult to read then necessary.
-                               check.softErrorf(pos,
-                                       "%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
+                               return errorf("%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
                                        targ, tpar.bound, wrong, m,
                                )
-                       } else {
-                               check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
                        }
-                       return false
+                       return errorf("%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
                }
        }
 
-       // targ's underlying type must also be one of the interface types listed, if any
+       // targ must also be in the set of types of iface, if any.
+       // Constraints with empty type sets were already excluded above.
        if !iface.typeSet().hasTerms() {
-               return true // nothing to do
+               return nil // nothing to do
        }
 
-       // If targ is itself a type parameter, each of its possible types, but at least one, must be in the
-       // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
+       // If targ is itself a type parameter, each of its possible types must be in the set
+       // of iface types (i.e., the targ type set must be a subset of the iface type set).
+       // Type arguments with empty type sets were already excluded above.
        if targ := asTypeParam(targ); targ != nil {
                targBound := targ.iface()
-               if !targBound.typeSet().hasTerms() {
-                       check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
-                       return false
-               }
                if !targBound.typeSet().subsetOf(iface.typeSet()) {
-                       // TODO(gri) need better error message
-                       check.softErrorf(pos, "%s does not satisfy %s", targ, tpar.bound)
-                       return false
+                       // TODO(gri) report which type is missing
+                       return errorf("%s does not satisfy %s", targ, tpar.bound)
                }
-               return true
+               return nil
        }
 
-       // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
+       // Otherwise, targ's type must be included in the iface type set.
        if !iface.typeSet().includes(targ) {
-               // TODO(gri) better error message
-               check.softErrorf(pos, "%s does not satisfy %s", targ, tpar.bound)
-               return false
+               // TODO(gri) report which type is missing
+               return errorf("%s does not satisfy %s", targ, tpar.bound)
        }
 
-       return true
+       return nil
 }
diff --git a/src/cmd/compile/internal/types2/instantiate_test.go b/src/cmd/compile/internal/types2/instantiate_test.go
new file mode 100644 (file)
index 0000000..a99fc5d
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2021 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 types2_test
+
+import (
+       . "cmd/compile/internal/types2"
+       "strings"
+       "testing"
+)
+
+func TestInstantiateEquality(t *testing.T) {
+       const src = genericPkg + "p; type T[P any] int"
+       pkg, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       T := pkg.Scope().Lookup("T").Type().(*Named)
+       // Instantiating the same type twice should result in pointer-equivalent
+       // instances.
+       ctxt := NewContext()
+       res1, err := Instantiate(ctxt, T, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res2, err := Instantiate(ctxt, T, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if res1 != res2 {
+               t.Errorf("first instance (%s) not pointer-equivalent to second instance (%s)", res1, res2)
+       }
+}
+func TestInstantiateNonEquality(t *testing.T) {
+       const src = genericPkg + "p; type T[P any] int"
+       pkg1, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       pkg2, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       // We consider T1 and T2 to be distinct types, so their instances should not
+       // be deduplicated by the context.
+       T1 := pkg1.Scope().Lookup("T").Type().(*Named)
+       T2 := pkg2.Scope().Lookup("T").Type().(*Named)
+       ctxt := NewContext()
+       res1, err := Instantiate(ctxt, T1, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res2, err := Instantiate(ctxt, T2, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if res1 == res2 {
+               t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
+       }
+       if Identical(res1, res2) {
+               t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
+       }
+}
+
+func TestMethodInstantiation(t *testing.T) {
+       const prefix = genericPkg + `p
+
+type T[P any] struct{}
+
+var X T[int]
+
+`
+       tests := []struct {
+               decl string
+               want string
+       }{
+               {"func (r T[P]) m() P", "func (T[int]).m() int"},
+               {"func (r T[P]) m(P)", "func (T[int]).m(int)"},
+               {"func (r *T[P]) m(P)", "func (*T[int]).m(int)"},
+               {"func (r T[P]) m() T[P]", "func (T[int]).m() T[int]"},
+               {"func (r T[P]) m(T[P])", "func (T[int]).m(T[int])"},
+               {"func (r T[P]) m(T[P], P, string)", "func (T[int]).m(T[int], int, string)"},
+               {"func (r T[P]) m(T[P], T[string], T[int])", "func (T[int]).m(T[int], T[string], T[int])"},
+       }
+
+       for _, test := range tests {
+               src := prefix + test.decl
+               pkg, err := pkgFor(".", src, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               typ := NewPointer(pkg.Scope().Lookup("X").Type())
+               obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
+               m, _ := obj.(*Func)
+               if m == nil {
+                       t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
+               }
+               if got := ObjectString(m, RelativeTo(pkg)); got != test.want {
+                       t.Errorf("instantiated %q, want %q", got, test.want)
+               }
+       }
+}
+
+func TestImmutableSignatures(t *testing.T) {
+       const src = genericPkg + `p
+
+type T[P any] struct{}
+
+func (T[P]) m() {}
+
+var _ T[int]
+`
+       pkg, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       typ := pkg.Scope().Lookup("T").Type().(*Named)
+       obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
+       if obj == nil {
+               t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
+       }
+
+       // Verify that the original method is not mutated by instantiating T (this
+       // bug manifested when subst did not return a new signature).
+       want := "func (T[P]).m()"
+       if got := stripAnnotations(ObjectString(obj, RelativeTo(pkg))); got != want {
+               t.Errorf("instantiated %q, want %q", got, want)
+       }
+}
+
+// Copied from errors.go.
+func stripAnnotations(s string) string {
+       var b strings.Builder
+       for _, r := range s {
+               // strip #'s and subscript digits
+               if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
+                       b.WriteRune(r)
+               }
+       }
+       if b.Len() < len(s) {
+               return b.String()
+       }
+       return s
+}
index 2617f748de6b6eefad5eca5dedfcba7609d97779..96c92ccaecd6b2f177338d22f6cd03635672a6c4 100644 (file)
@@ -11,34 +11,23 @@ import "cmd/compile/internal/syntax"
 
 // An Interface represents an interface type.
 type Interface struct {
+       check     *Checker      // for error reporting; nil once type set is computed
        obj       *TypeName     // corresponding declared object; or nil (for better error messages)
        methods   []*Func       // ordered list of explicitly declared methods
        embeddeds []Type        // ordered list of explicitly embedded elements
        embedPos  *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space
+       implicit  bool          // interface is wrapper for type set literal (non-interface T, ~T, or A|B)
        complete  bool          // indicates that all fields (except for tset) are set up
 
-       tset *TypeSet // type set described by this interface, computed lazily
+       tset *_TypeSet // type set described by this interface, computed lazily
 }
 
 // typeSet returns the type set for interface t.
-func (t *Interface) typeSet() *TypeSet { return computeInterfaceTypeSet(nil, nopos, t) }
+func (t *Interface) typeSet() *_TypeSet { return computeInterfaceTypeSet(t.check, nopos, t) }
 
 // emptyInterface represents the empty interface
 var emptyInterface = Interface{complete: true, tset: &topTypeSet}
 
-// NewInterface returns a new interface for the given methods and embedded types.
-// NewInterface takes ownership of the provided methods and may modify their types
-// by setting missing receivers.
-//
-// Deprecated: Use NewInterfaceType instead which allows arbitrary embedded types.
-func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
-       tnames := make([]Type, len(embeddeds))
-       for i, t := range embeddeds {
-               tnames[i] = t
-       }
-       return NewInterfaceType(methods, tnames)
-}
-
 // NewInterfaceType returns a new interface for the given methods and embedded types.
 // NewInterfaceType takes ownership of the provided methods and may modify their types
 // by setting missing receivers.
@@ -65,6 +54,14 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        return typ
 }
 
+// MarkImplicit marks the interface t as implicit, meaning this interface
+// corresponds to a constraint literal such as ~T or A|B without explicit
+// interface embedding. MarkImplicit should be called before any concurrent use
+// of implicit interfaces.
+func (t *Interface) MarkImplicit() {
+       t.implicit = true
+}
+
 // NumExplicitMethods returns the number of explicitly declared methods of interface t.
 func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
 
@@ -75,12 +72,6 @@ func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
 // NumEmbeddeds returns the number of embedded types in interface t.
 func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
 
-// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds().
-// The result is nil if the i'th embedded type is not a defined type.
-//
-// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types.
-func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname }
-
 // EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
 func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] }
 
@@ -97,8 +88,11 @@ func (t *Interface) Empty() bool { return t.typeSet().IsAll() }
 // IsComparable reports whether each type in interface t's type set is comparable.
 func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() }
 
-// IsConstraint reports whether interface t is not just a method set.
-func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() }
+// IsMethodSet reports whether the interface t is fully described by its method set.
+func (t *Interface) IsMethodSet() bool { return t.typeSet().IsMethodSet() }
+
+// IsImplicit reports whether the interface t is a wrapper for a type set literal.
+func (t *Interface) IsImplicit() bool { return t.implicit }
 
 func (t *Interface) Underlying() Type { return t }
 func (t *Interface) String() string   { return TypeString(t, nil) }
@@ -107,9 +101,6 @@ func (t *Interface) String() string   { return TypeString(t, nil) }
 // Implementation
 
 func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) {
-       var tlist []syntax.Expr // types collected from all type lists
-       var tname *syntax.Name  // most recent "type" name
-
        addEmbedded := func(pos syntax.Pos, typ Type) {
                ityp.embeddeds = append(ityp.embeddeds, typ)
                if ityp.embedPos == nil {
@@ -120,13 +111,12 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
 
        for _, f := range iface.MethodList {
                if f.Name == nil {
-                       // We have an embedded type; possibly a union of types.
                        addEmbedded(posFor(f.Type), parseUnion(check, flattenUnion(nil, f.Type)))
                        continue
                }
                // f.Name != nil
 
-               // We have a method with name f.Name, or a type of a type list (f.Name.Value == "type").
+               // We have a method with name f.Name.
                name := f.Name.Value
                if name == "_" {
                        if check.conf.CompilerErrorMessages {
@@ -137,31 +127,6 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
                        continue // ignore
                }
 
-               // TODO(gri) Remove type list handling once the parser doesn't accept type lists anymore.
-               if name == "type" {
-                       // Report an error for the first type list per interface
-                       // if we don't allow type lists, but continue.
-                       if !check.conf.AllowTypeLists && tlist == nil {
-                               check.softErrorf(f.Name, "use generalized embedding syntax instead of a type list")
-                       }
-                       // For now, collect all type list entries as if it
-                       // were a single union, where each union element is
-                       // of the form ~T.
-                       op := new(syntax.Operation)
-                       // We should also set the position (but there is no setter);
-                       // we don't care because this code will eventually go away.
-                       op.Op = syntax.Tilde
-                       op.X = f.Type
-                       tlist = append(tlist, op)
-                       // Report an error if we have multiple type lists in an
-                       // interface, but only if they are permitted in the first place.
-                       if check.conf.AllowTypeLists && tname != nil && tname != f.Name {
-                               check.error(f.Name, "cannot have multiple type lists in an interface")
-                       }
-                       tname = f.Name
-                       continue
-               }
-
                typ := check.typ(f.Type)
                sig, _ := typ.(*Signature)
                if sig == nil {
@@ -190,15 +155,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
                ityp.methods = append(ityp.methods, m)
        }
 
-       // If we saw a type list, add it like an embedded union.
-       if tlist != nil {
-               // Types T in a type list are added as ~T expressions but we don't
-               // have the position of the '~'. Use the first type position instead.
-               addEmbedded(tlist[0].(*syntax.Operation).X.Pos(), parseUnion(check, tlist))
-       }
-
        // All methods and embedded elements for this interface are collected;
-       // i.e., this interface is may be used in a type set computation.
+       // i.e., this interface may be used in a type set computation.
        ityp.complete = true
 
        if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
@@ -214,7 +172,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
        // Compute type set with a non-nil *Checker as soon as possible
        // to report any errors. Subsequent uses of type sets will use
        // this computed type set and won't need to pass in a *Checker.
-       check.later(func() { computeInterfaceTypeSet(check, iface.Pos(), ityp) })
+       //
+       // Pin the checker to the interface type in the interim, in case the type set
+       // must be used before delayed funcs are processed (see issue #48234).
+       // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
+       ityp.check = check
+       check.later(func() {
+               computeInterfaceTypeSet(check, iface.Pos(), ityp)
+               ityp.check = nil
+       }).describef(iface, "compute type set for %s", ityp)
 }
 
 func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr {
index 3779d17b3db033adcf44fff2206ef2127b80bf99..e0fd74482ab04307272fb20b972e6a1811cc8ac4 100644 (file)
@@ -74,9 +74,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
        typ, isPtr := deref(T)
 
        // *typ where typ is an interface or type parameter has no methods.
-       switch under(typ).(type) {
-       case *Interface, *TypeParam:
-               if isPtr {
+       if isPtr {
+               // don't look at under(typ) here - was bug (issue #47747)
+               if _, ok := typ.(*TypeParam); ok {
+                       return
+               }
+               if _, ok := under(typ).(*Interface); ok {
                        return
                }
        }
@@ -119,7 +122,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                                seen[named] = true
 
                                // look for a matching attached method
-                               named.load()
+                               named.resolve(nil)
                                if i, m := lookupMethod(named.methods, pkg, name); m != nil {
                                        // potential match
                                        // caution: method may not have a proper signature yet
@@ -213,7 +216,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                        //        is shorthand for (&x).m()".
                        if f, _ := obj.(*Func); f != nil {
                                // determine if method has a pointer receiver
-                               hasPtrRecv := tpar == nil && ptrRecv(f)
+                               hasPtrRecv := tpar == nil && f.hasPtrRecv()
                                if hasPtrRecv && !indirect && !addressable {
                                        return nil, nil, true // pointer/addressable receiver required
                                }
@@ -318,10 +321,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // both methods must have the same number of type parameters
                        ftyp := f.typ.(*Signature)
                        mtyp := m.typ.(*Signature)
-                       if ftyp.TParams().Len() != mtyp.TParams().Len() {
+                       if ftyp.TypeParams().Len() != mtyp.TypeParams().Len() {
                                return m, f
                        }
-                       if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 {
+                       if !acceptMethodTypeParams && ftyp.TypeParams().Len() > 0 {
                                panic("method with type parameters")
                        }
 
@@ -331,7 +334,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // TODO(gri) is this always correct? what about type bounds?
                        // (Alternative is to rename/subst type parameters and compare.)
                        u := newUnifier(true)
-                       u.x.init(ftyp.TParams().list())
+                       u.x.init(ftyp.TypeParams().list())
                        if !u.unify(ftyp, mtyp) {
                                return m, f
                        }
@@ -341,8 +344,6 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
        }
 
        // A concrete type implements T if it implements all methods of T.
-       Vd, _ := deref(V)
-       Vn := asNamed(Vd)
        for _, m := range T.typeSet().methods {
                // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
                obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
@@ -370,40 +371,20 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // both methods must have the same number of type parameters
                ftyp := f.typ.(*Signature)
                mtyp := m.typ.(*Signature)
-               if ftyp.TParams().Len() != mtyp.TParams().Len() {
+               if ftyp.TypeParams().Len() != mtyp.TypeParams().Len() {
                        return m, f
                }
-               if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 {
+               if !acceptMethodTypeParams && ftyp.TypeParams().Len() > 0 {
                        panic("method with type parameters")
                }
 
-               // If V is a (instantiated) generic type, its methods are still
-               // parameterized using the original (declaration) receiver type
-               // parameters (subst simply copies the existing method list, it
-               // does not instantiate the methods).
-               // In order to compare the signatures, substitute the receiver
-               // type parameters of ftyp with V's instantiation type arguments.
-               // This lazily instantiates the signature of method f.
-               if Vn != nil && Vn.TParams().Len() > 0 {
-                       // Be careful: The number of type arguments may not match
-                       // the number of receiver parameters. If so, an error was
-                       // reported earlier but the length discrepancy is still
-                       // here. Exit early in this case to prevent an assertion
-                       // failure in makeSubstMap.
-                       // TODO(gri) Can we avoid this check by fixing the lengths?
-                       if len(ftyp.RParams().list()) != len(Vn.targs) {
-                               return
-                       }
-                       ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs), nil).(*Signature)
-               }
-
                // If the methods have type parameters we don't care whether they
                // are the same or not, as long as they match up. Use unification
                // to see if they can be made to match.
                // TODO(gri) is this always correct? what about type bounds?
                // (Alternative is to rename/subst type parameters and compare.)
                u := newUnifier(true)
-               if ftyp.TParams().Len() > 0 {
+               if ftyp.TypeParams().Len() > 0 {
                        // We reach here only if we accept method type parameters.
                        // In this case, unification must consider any receiver
                        // and method type parameters as "free" type parameters.
@@ -413,9 +394,9 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // unimplemented call so that we test this code if we
                        // enable method type parameters.
                        unimplemented()
-                       u.x.init(append(ftyp.RParams().list(), ftyp.TParams().list()...))
+                       u.x.init(append(ftyp.RecvTypeParams().list(), ftyp.TypeParams().list()...))
                } else {
-                       u.x.init(ftyp.RParams().list())
+                       u.x.init(ftyp.RecvTypeParams().list())
                }
                if !u.unify(ftyp, mtyp) {
                        return m, f
@@ -493,22 +474,3 @@ func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
        }
        return -1, nil
 }
-
-// ptrRecv reports whether the receiver is of the form *T.
-func ptrRecv(f *Func) bool {
-       // If a method's receiver type is set, use that as the source of truth for the receiver.
-       // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
-       // signature. We may reach here before the signature is fully set up: we must explicitly
-       // check if the receiver is set (we cannot just look for non-nil f.typ).
-       if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
-               _, isPtr := deref(sig.recv.typ)
-               return isPtr
-       }
-
-       // If a method's type is not set it may be a method/function that is:
-       // 1) client-supplied (via NewFunc with no signature), or
-       // 2) internally created but not yet type-checked.
-       // For case 1) we can't do anything; the client must know what they are doing.
-       // For case 2) we can use the information gathered by the resolver.
-       return f.hasPtrRecv
-}
diff --git a/src/cmd/compile/internal/types2/mono.go b/src/cmd/compile/internal/types2/mono.go
new file mode 100644 (file)
index 0000000..39c4d4f
--- /dev/null
@@ -0,0 +1,337 @@
+// Copyright 2021 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 types2
+
+import (
+       "cmd/compile/internal/syntax"
+)
+
+// This file implements a check to validate that a Go package doesn't
+// have unbounded recursive instantiation, which is not compatible
+// with compilers using static instantiation (such as
+// monomorphization).
+//
+// It implements a sort of "type flow" analysis by detecting which
+// type parameters are instantiated with other type parameters (or
+// types derived thereof). A package cannot be statically instantiated
+// if the graph has any cycles involving at least one derived type.
+//
+// Concretely, we construct a directed, weighted graph. Vertices are
+// used to represent type parameters as well as some defined
+// types. Edges are used to represent how types depend on each other:
+//
+// * Everywhere a type-parameterized function or type is instantiated,
+//   we add edges to each type parameter from the vertices (if any)
+//   representing each type parameter or defined type referenced by
+//   the type argument. If the type argument is just the referenced
+//   type itself, then the edge has weight 0, otherwise 1.
+//
+// * For every defined type declared within a type-parameterized
+//   function or method, we add an edge of weight 1 to the defined
+//   type from each ambient type parameter.
+//
+// For example, given:
+//
+//     func f[A, B any]() {
+//             type T int
+//             f[T, map[A]B]()
+//     }
+//
+// we construct vertices representing types A, B, and T. Because of
+// declaration "type T int", we construct edges T<-A and T<-B with
+// weight 1; and because of instantiation "f[T, map[A]B]" we construct
+// edges A<-T with weight 0, and B<-A and B<-B with weight 1.
+//
+// Finally, we look for any positive-weight cycles. Zero-weight cycles
+// are allowed because static instantiation will reach a fixed point.
+
+type monoGraph struct {
+       vertices []monoVertex
+       edges    []monoEdge
+
+       // canon maps method receiver type parameters to their respective
+       // receiver type's type parameters.
+       canon map[*TypeParam]*TypeParam
+
+       // nameIdx maps a defined type or (canonical) type parameter to its
+       // vertex index.
+       nameIdx map[*TypeName]int
+}
+
+type monoVertex struct {
+       weight int // weight of heaviest known path to this vertex
+       pre    int // previous edge (if any) in the above path
+       len    int // length of the above path
+
+       // obj is the defined type or type parameter represented by this
+       // vertex.
+       obj *TypeName
+}
+
+type monoEdge struct {
+       dst, src int
+       weight   int
+
+       pos syntax.Pos
+       typ Type
+}
+
+func (check *Checker) monomorph() {
+       // We detect unbounded instantiation cycles using a variant of
+       // Bellman-Ford's algorithm. Namely, instead of always running |V|
+       // iterations, we run until we either reach a fixed point or we've
+       // found a path of length |V|. This allows us to terminate earlier
+       // when there are no cycles, which should be the common case.
+
+       again := true
+       for again {
+               again = false
+
+               for i, edge := range check.mono.edges {
+                       src := &check.mono.vertices[edge.src]
+                       dst := &check.mono.vertices[edge.dst]
+
+                       // N.B., we're looking for the greatest weight paths, unlike
+                       // typical Bellman-Ford.
+                       w := src.weight + edge.weight
+                       if w <= dst.weight {
+                               continue
+                       }
+
+                       dst.pre = i
+                       dst.len = src.len + 1
+                       if dst.len == len(check.mono.vertices) {
+                               check.reportInstanceLoop(edge.dst)
+                               return
+                       }
+
+                       dst.weight = w
+                       again = true
+               }
+       }
+}
+
+func (check *Checker) reportInstanceLoop(v int) {
+       var stack []int
+       seen := make([]bool, len(check.mono.vertices))
+
+       // We have a path that contains a cycle and ends at v, but v may
+       // only be reachable from the cycle, not on the cycle itself. We
+       // start by walking backwards along the path until we find a vertex
+       // that appears twice.
+       for !seen[v] {
+               stack = append(stack, v)
+               seen[v] = true
+               v = check.mono.edges[check.mono.vertices[v].pre].src
+       }
+
+       // Trim any vertices we visited before visiting v the first
+       // time. Since v is the first vertex we found within the cycle, any
+       // vertices we visited earlier cannot be part of the cycle.
+       for stack[0] != v {
+               stack = stack[1:]
+       }
+
+       // TODO(mdempsky): Pivot stack so we report the cycle from the top?
+
+       var err error_
+       obj0 := check.mono.vertices[v].obj
+       err.errorf(obj0, "instantiation cycle:")
+
+       qf := RelativeTo(check.pkg)
+       for _, v := range stack {
+               edge := check.mono.edges[check.mono.vertices[v].pre]
+               obj := check.mono.vertices[edge.dst].obj
+
+               switch obj.Type().(type) {
+               default:
+                       panic("unexpected type")
+               case *Named:
+                       err.errorf(edge.pos, "%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
+               case *TypeParam:
+                       err.errorf(edge.pos, "%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
+               }
+       }
+       check.report(&err)
+}
+
+// recordCanon records that tpar is the canonical type parameter
+// corresponding to method type parameter mpar.
+func (w *monoGraph) recordCanon(mpar, tpar *TypeParam) {
+       if w.canon == nil {
+               w.canon = make(map[*TypeParam]*TypeParam)
+       }
+       w.canon[mpar] = tpar
+}
+
+// recordInstance records that the given type parameters were
+// instantiated with the corresponding type arguments.
+func (w *monoGraph) recordInstance(pkg *Package, pos syntax.Pos, tparams []*TypeParam, targs []Type, posList []syntax.Pos) {
+       for i, tpar := range tparams {
+               pos := pos
+               if i < len(posList) {
+                       pos = posList[i]
+               }
+               w.assign(pkg, pos, tpar, targs[i])
+       }
+}
+
+// assign records that tpar was instantiated as targ at pos.
+func (w *monoGraph) assign(pkg *Package, pos syntax.Pos, tpar *TypeParam, targ Type) {
+       // Go generics do not have an analog to C++`s template-templates,
+       // where a template parameter can itself be an instantiable
+       // template. So any instantiation cycles must occur within a single
+       // package. Accordingly, we can ignore instantiations of imported
+       // type parameters.
+       //
+       // TODO(mdempsky): Push this check up into recordInstance? All type
+       // parameters in a list will appear in the same package.
+       if tpar.Obj().Pkg() != pkg {
+               return
+       }
+
+       // flow adds an edge from vertex src representing that typ flows to tpar.
+       flow := func(src int, typ Type) {
+               weight := 1
+               if typ == targ {
+                       weight = 0
+               }
+
+               w.addEdge(w.typeParamVertex(tpar), src, weight, pos, targ)
+       }
+
+       // Recursively walk the type argument to find any defined types or
+       // type parameters.
+       var do func(typ Type)
+       do = func(typ Type) {
+               switch typ := typ.(type) {
+               default:
+                       panic("unexpected type")
+
+               case *TypeParam:
+                       assert(typ.Obj().Pkg() == pkg)
+                       flow(w.typeParamVertex(typ), typ)
+
+               case *Named:
+                       if src := w.localNamedVertex(pkg, typ.Origin()); src >= 0 {
+                               flow(src, typ)
+                       }
+
+                       targs := typ.TypeArgs()
+                       for i := 0; i < targs.Len(); i++ {
+                               do(targs.At(i))
+                       }
+
+               case *Array:
+                       do(typ.Elem())
+               case *Basic:
+                       // ok
+               case *Chan:
+                       do(typ.Elem())
+               case *Map:
+                       do(typ.Key())
+                       do(typ.Elem())
+               case *Pointer:
+                       do(typ.Elem())
+               case *Slice:
+                       do(typ.Elem())
+
+               case *Interface:
+                       for i := 0; i < typ.NumMethods(); i++ {
+                               do(typ.Method(i).Type())
+                       }
+               case *Signature:
+                       tuple := func(tup *Tuple) {
+                               for i := 0; i < tup.Len(); i++ {
+                                       do(tup.At(i).Type())
+                               }
+                       }
+                       tuple(typ.Params())
+                       tuple(typ.Results())
+               case *Struct:
+                       for i := 0; i < typ.NumFields(); i++ {
+                               do(typ.Field(i).Type())
+                       }
+               }
+       }
+       do(targ)
+}
+
+// localNamedVertex returns the index of the vertex representing
+// named, or -1 if named doesn't need representation.
+func (w *monoGraph) localNamedVertex(pkg *Package, named *Named) int {
+       obj := named.Obj()
+       if obj.Pkg() != pkg {
+               return -1 // imported type
+       }
+
+       root := pkg.Scope()
+       if obj.Parent() == root {
+               return -1 // package scope, no ambient type parameters
+       }
+
+       if idx, ok := w.nameIdx[obj]; ok {
+               return idx
+       }
+
+       idx := -1
+
+       // Walk the type definition's scope to find any ambient type
+       // parameters that it's implicitly parameterized by.
+       for scope := obj.Parent(); scope != root; scope = scope.Parent() {
+               for _, elem := range scope.elems {
+                       if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && elem.Pos().Cmp(obj.Pos()) < 0 {
+                               if tpar, ok := elem.Type().(*TypeParam); ok {
+                                       if idx < 0 {
+                                               idx = len(w.vertices)
+                                               w.vertices = append(w.vertices, monoVertex{obj: obj})
+                                       }
+
+                                       w.addEdge(idx, w.typeParamVertex(tpar), 1, obj.Pos(), tpar)
+                               }
+                       }
+               }
+       }
+
+       if w.nameIdx == nil {
+               w.nameIdx = make(map[*TypeName]int)
+       }
+       w.nameIdx[obj] = idx
+       return idx
+}
+
+// typeParamVertex returns the index of the vertex representing tpar.
+func (w *monoGraph) typeParamVertex(tpar *TypeParam) int {
+       if x, ok := w.canon[tpar]; ok {
+               tpar = x
+       }
+
+       obj := tpar.Obj()
+
+       if idx, ok := w.nameIdx[obj]; ok {
+               return idx
+       }
+
+       if w.nameIdx == nil {
+               w.nameIdx = make(map[*TypeName]int)
+       }
+
+       idx := len(w.vertices)
+       w.vertices = append(w.vertices, monoVertex{obj: obj})
+       w.nameIdx[obj] = idx
+       return idx
+}
+
+func (w *monoGraph) addEdge(dst, src, weight int, pos syntax.Pos, typ Type) {
+       // TODO(mdempsky): Deduplicate redundant edges?
+       w.edges = append(w.edges, monoEdge{
+               dst:    dst,
+               src:    src,
+               weight: weight,
+
+               pos: pos,
+               typ: typ,
+       })
+}
diff --git a/src/cmd/compile/internal/types2/mono_test.go b/src/cmd/compile/internal/types2/mono_test.go
new file mode 100644 (file)
index 0000000..19d0e95
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2021 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 types2_test
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "cmd/compile/internal/types2"
+       "errors"
+       "fmt"
+       "strings"
+       "testing"
+)
+
+func checkMono(t *testing.T, body string) error {
+       src := "package x; import `unsafe`; var _ unsafe.Pointer;\n" + body
+       file, err := syntax.Parse(syntax.NewFileBase("x.go"), strings.NewReader(src), nil, nil, syntax.AllowGenerics)
+       if err != nil {
+               t.Fatal(err)
+       }
+       files := []*syntax.File{file}
+
+       var buf bytes.Buffer
+       conf := types2.Config{
+               Error:    func(err error) { fmt.Fprintln(&buf, err) },
+               Importer: defaultImporter(),
+       }
+       conf.Check("x", files, nil)
+       if buf.Len() == 0 {
+               return nil
+       }
+       return errors.New(strings.TrimRight(buf.String(), "\n"))
+}
+
+func TestMonoGood(t *testing.T) {
+       for i, good := range goods {
+               if err := checkMono(t, good); err != nil {
+                       t.Errorf("%d: unexpected failure: %v", i, err)
+               }
+       }
+}
+
+func TestMonoBad(t *testing.T) {
+       for i, bad := range bads {
+               if err := checkMono(t, bad); err == nil {
+                       t.Errorf("%d: unexpected success", i)
+               } else {
+                       t.Log(err)
+               }
+       }
+}
+
+var goods = []string{
+       "func F[T any](x T) { F(x) }",
+       "func F[T, U, V any]() { F[U, V, T](); F[V, T, U]() }",
+       "type Ring[A, B, C any] struct { L *Ring[B, C, A]; R *Ring[C, A, B] }",
+       "func F[T any]() { type U[T any] [unsafe.Sizeof(F[*T])]byte }",
+       "func F[T any]() { type U[T any] [unsafe.Sizeof(F[*T])]byte; var _ U[int] }",
+       "type U[T any] [unsafe.Sizeof(F[*T])]byte; func F[T any]() { var _ U[U[int]] }",
+       "func F[T any]() { type A = int; F[A]() }",
+}
+
+// TODO(mdempsky): Validate specific error messages and positioning.
+
+var bads = []string{
+       "func F[T any](x T) { F(&x) }",
+       "func F[T any]() { F[*T]() }",
+       "func F[T any]() { F[[]T]() }",
+       "func F[T any]() { F[[1]T]() }",
+       "func F[T any]() { F[chan T]() }",
+       "func F[T any]() { F[map[*T]int]() }",
+       "func F[T any]() { F[map[error]T]() }",
+       "func F[T any]() { F[func(T)]() }",
+       "func F[T any]() { F[func() T]() }",
+       "func F[T any]() { F[struct{ t T }]() }",
+       "func F[T any]() { F[interface{ t() T }]() }",
+       "type U[_ any] int; func F[T any]() { F[U[T]]() }",
+       "func F[T any]() { type U int; F[U]() }",
+       "func F[T any]() { type U int; F[*U]() }",
+       "type U[T any] int; func (U[T]) m() { var _ U[*T] }",
+       "type U[T any] int; func (*U[T]) m() { var _ U[*T] }",
+       "type U[T1 any] [unsafe.Sizeof(F[*T1])]byte; func F[T2 any]() { var _ U[T2] }",
+       "func F[A, B, C, D, E any]() { F[B, C, D, E, *A]() }",
+       "type U[_ any] int; const X = unsafe.Sizeof(func() { type A[T any] U[A[*T]] })",
+       "func F[T any]() { type A = *T; F[A]() }",
+       "type A[T any] struct { _ A[*T] }",
+}
index 3ce9c5b0c79c580e0b76eb841772326ab13724ef..6ebad8fbb5b8ee26f1338ae5349c05ee7911b880 100644 (file)
@@ -9,23 +9,21 @@ import (
        "sync"
 )
 
-// TODO(gri) Clean up Named struct below; specifically the fromRHS field (can we use underlying?).
-
 // A Named represents a named (defined) type.
 type Named struct {
        check      *Checker
-       info       typeInfo    // for cycle detection
-       obj        *TypeName   // corresponding declared object for declared types; placeholder for instantiated types
-       orig       *Named      // original, uninstantiated type
-       fromRHS    Type        // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)
-       underlying Type        // possibly a *Named during setup; never a *Named once set up completely
-       instance   *instance   // position information for lazy instantiation, or nil
-       tparams    *TParamList // type parameters, or nil
-       targs      []Type      // type arguments (after instantiation), or nil
-       methods    []*Func     // methods declared for this type (not the method set of this type); signatures are type-checked lazily
-
-       resolve func(*Named) ([]*TypeName, Type, []*Func)
-       once    sync.Once
+       info       typeInfo       // for cycle detection
+       obj        *TypeName      // corresponding declared object for declared types; placeholder for instantiated types
+       orig       *Named         // original, uninstantiated type
+       fromRHS    Type           // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)
+       underlying Type           // possibly a *Named during setup; never a *Named once set up completely
+       tparams    *TypeParamList // type parameters, or nil
+       targs      *TypeList      // type arguments (after instantiation), or nil
+       methods    []*Func        // methods declared for this type (not the method set of this type); signatures are type-checked lazily
+
+       // resolver may be provided to lazily resolve type parameters, underlying, and methods.
+       resolver func(*Context, *Named) (tparams *TypeParamList, underlying Type, methods []*Func)
+       once     sync.Once // ensures that tparams, underlying, and methods are resolved before accessing
 }
 
 // NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@ -38,49 +36,28 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
        return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
 }
 
-func (t *Named) load() *Named {
-       // If t is an instantiated type, it derives its methods and tparams from its
-       // base type. Since we expect type parameters and methods to be set after a
-       // call to load, we must load the base and copy here.
-       //
-       // underlying is set when t is expanded.
-       //
-       // By convention, a type instance is loaded iff its tparams are set.
-       if len(t.targs) > 0 && t.tparams == nil {
-               t.orig.load()
-               t.tparams = t.orig.tparams
-               t.methods = t.orig.methods
-       }
-       if t.resolve == nil {
+func (t *Named) resolve(ctxt *Context) *Named {
+       if t.resolver == nil {
                return t
        }
 
        t.once.Do(func() {
-               // TODO(mdempsky): Since we're passing t to resolve anyway
+               // TODO(mdempsky): Since we're passing t to the resolver anyway
                // (necessary because types2 expects the receiver type for methods
                // on defined interface types to be the Named rather than the
                // underlying Interface), maybe it should just handle calling
-               // SetTParams, SetUnderlying, and AddMethod instead?  Those
-               // methods would need to support reentrant calls though.  It would
+               // SetTypeParams, SetUnderlying, and AddMethod instead?  Those
+               // methods would need to support reentrant calls though. It would
                // also make the API more future-proof towards further extensions
-               // (like SetTParams).
-
-               tparams, underlying, methods := t.resolve(t)
-
-               switch underlying.(type) {
-               case nil, *Named:
-                       panic("invalid underlying type")
-               }
-
-               t.tparams = bindTParams(tparams)
-               t.underlying = underlying
-               t.methods = methods
+               // (like SetTypeParams).
+               t.tparams, t.underlying, t.methods = t.resolver(ctxt, t)
+               t.fromRHS = t.underlying // for cycle detection
        })
        return t
 }
 
 // newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
-func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TParamList, methods []*Func) *Named {
+func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParamList, methods []*Func) *Named {
        typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
        if typ.orig == nil {
                typ.orig = typ
@@ -88,54 +65,39 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
        if obj.typ == nil {
                obj.typ = typ
        }
-       // Ensure that typ is always expanded, at which point the check field can be
-       // nilled out.
-       //
-       // Note that currently we cannot nil out check inside typ.under(), because
-       // it's possible that typ is expanded multiple times.
-       //
-       // TODO(gri): clean this up so that under is the only function mutating
-       //            named types.
+       // Ensure that typ is always expanded and sanity-checked.
        if check != nil {
-               check.later(func() {
-                       switch typ.under().(type) {
-                       case *Named:
-                               panic("unexpanded underlying type")
-                       }
-                       typ.check = nil
-               })
+               check.defTypes = append(check.defTypes, typ)
        }
        return typ
 }
 
 // Obj returns the type name for the declaration defining the named type t. For
 // instantiated types, this is the type name of the base type.
-func (t *Named) Obj() *TypeName {
-       return t.orig.obj // for non-instances this is the same as t.obj
-}
+func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj
 
-// Orig returns the original generic type an instantiated type is derived from.
-// If t is not an instantiated type, the result is t.
-func (t *Named) Orig() *Named { return t.orig }
+// Origin returns the parameterized type from which the named type t is
+// instantiated. If t is not an instantiated type, the result is t.
+func (t *Named) Origin() *Named { return t.orig }
 
 // TODO(gri) Come up with a better representation and API to distinguish
 //           between parameterized instantiated and non-instantiated types.
 
-// TParams returns the type parameters of the named type t, or nil.
+// TypeParams returns the type parameters of the named type t, or nil.
 // The result is non-nil for an (originally) parameterized type even if it is instantiated.
-func (t *Named) TParams() *TParamList { return t.load().tparams }
+func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
 
-// SetTParams sets the type parameters of the named type t.
-func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams(tparams) }
+// SetTypeParams sets the type parameters of the named type t.
+func (t *Named) SetTypeParams(tparams []*TypeParam) { t.resolve(nil).tparams = bindTParams(tparams) }
 
-// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
-func (t *Named) TArgs() []Type { return t.targs }
+// TypeArgs returns the type arguments used to instantiate the named type t.
+func (t *Named) TypeArgs() *TypeList { return t.targs }
 
 // NumMethods returns the number of explicit methods whose receiver is named type t.
-func (t *Named) NumMethods() int { return len(t.load().methods) }
+func (t *Named) NumMethods() int { return len(t.resolve(nil).methods) }
 
 // Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
-func (t *Named) Method(i int) *Func { return t.load().methods[i] }
+func (t *Named) Method(i int) *Func { return t.resolve(nil).methods[i] }
 
 // SetUnderlying sets the underlying type and marks t as complete.
 func (t *Named) SetUnderlying(underlying Type) {
@@ -145,18 +107,18 @@ func (t *Named) SetUnderlying(underlying Type) {
        if _, ok := underlying.(*Named); ok {
                panic("underlying type must not be *Named")
        }
-       t.load().underlying = underlying
+       t.resolve(nil).underlying = underlying
 }
 
 // AddMethod adds method m unless it is already in the method list.
 func (t *Named) AddMethod(m *Func) {
-       t.load()
+       t.resolve(nil)
        if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
                t.methods = append(t.methods, m)
        }
 }
 
-func (t *Named) Underlying() Type { return t.load().expand(nil).underlying }
+func (t *Named) Underlying() Type { return t.resolve(nil).underlying }
 func (t *Named) String() string   { return TypeString(t, nil) }
 
 // ----------------------------------------------------------------------------
@@ -168,6 +130,18 @@ func (t *Named) String() string   { return TypeString(t, nil) }
 // chain before returning it. If no underlying type is found or a cycle
 // is detected, the result is Typ[Invalid]. If a cycle is detected and
 // n0.check != nil, the cycle is reported.
+//
+// This is necessary because the underlying type of named may be itself a
+// named type that is incomplete:
+//
+//     type (
+//             A B
+//             B *C
+//             C A
+//     )
+//
+// The type of C is the (named) type of A which is incomplete,
+// and which has as its underlying type the named type B.
 func (n0 *Named) under() Type {
        u := n0.Underlying()
 
@@ -177,7 +151,9 @@ func (n0 *Named) under() Type {
        var n1 *Named
        switch u1 := u.(type) {
        case nil:
-               return Typ[Invalid]
+               // After expansion via Underlying(), we should never encounter a nil
+               // underlying.
+               panic("nil underlying")
        default:
                // common case
                return u
@@ -242,42 +218,119 @@ func (n *Named) setUnderlying(typ Type) {
        }
 }
 
-// instance holds position information for use in lazy instantiation.
-//
-// TODO(rfindley): come up with a better name for this type, now that its usage
-// has changed.
-type instance struct {
-       pos     syntax.Pos   // position of type instantiation; for error reporting only
-       posList []syntax.Pos // position of each targ; for error reporting only
+// bestContext returns the best available context. In order of preference:
+// - the given ctxt, if non-nil
+// - check.Config.Context, if check is non-nil
+// - a new Context
+func (check *Checker) bestContext(ctxt *Context) *Context {
+       if ctxt != nil {
+               return ctxt
+       }
+       if check != nil {
+               assert(check.conf.Context != nil)
+               return check.conf.Context
+       }
+       return NewContext()
 }
 
-// expand ensures that the underlying type of n is instantiated.
+// expandNamed ensures that the underlying type of n is instantiated.
 // The underlying type will be Typ[Invalid] if there was an error.
-func (n *Named) expand(typMap map[string]*Named) *Named {
-       if n.instance != nil {
-               // n must be loaded before instantiation, in order to have accurate
-               // tparams. This is done implicitly by the call to n.TParams, but making it
-               // explicit is harmless: load is idempotent.
-               n.load()
-               if typMap == nil {
-                       if n.check != nil {
-                               typMap = n.check.typMap
-                       } else {
-                               // If we're instantiating lazily, we might be outside the scope of a
-                               // type-checking pass. In that case we won't have a pre-existing
-                               // typMap, but don't want to create a duplicate of the current instance
-                               // in the process of expansion.
-                               h := instantiatedHash(n.orig, n.targs)
-                               typMap = map[string]*Named{h: n}
+func expandNamed(ctxt *Context, n *Named, instPos syntax.Pos) (tparams *TypeParamList, underlying Type, methods []*Func) {
+       n.orig.resolve(ctxt)
+       assert(n.orig.underlying != nil)
+
+       check := n.check
+
+       if _, unexpanded := n.orig.underlying.(*Named); unexpanded {
+               // We should only get an unexpanded underlying here during type checking
+               // (for example, in recursive type declarations).
+               assert(check != nil)
+       }
+
+       // Mismatching arg and tparam length may be checked elsewhere.
+       if n.orig.tparams.Len() == n.targs.Len() {
+               // We must always have a context, to avoid infinite recursion.
+               ctxt = check.bestContext(ctxt)
+               h := ctxt.TypeHash(n.orig, n.targs.list())
+               // ensure that an instance is recorded for h to avoid infinite recursion.
+               ctxt.typeForHash(h, n)
+
+               smap := makeSubstMap(n.orig.tparams.list(), n.targs.list())
+               underlying = n.check.subst(instPos, n.orig.underlying, smap, ctxt)
+
+               for i := 0; i < n.orig.NumMethods(); i++ {
+                       origm := n.orig.Method(i)
+
+                       // During type checking origm may not have a fully set up type, so defer
+                       // instantiation of its signature until later.
+                       m := NewFunc(origm.pos, origm.pkg, origm.name, nil)
+                       m.hasPtrRecv_ = origm.hasPtrRecv()
+                       // Setting instRecv here allows us to complete later (we need the
+                       // instRecv to get targs and the original method).
+                       m.instRecv = n
+
+                       methods = append(methods, m)
+               }
+       } else {
+               underlying = Typ[Invalid]
+       }
+
+       // Methods should not escape the type checker API without being completed. If
+       // we're in the context of a type checking pass, we need to defer this until
+       // later (not all methods may have types).
+       completeMethods := func() {
+               for _, m := range methods {
+                       if m.instRecv != nil {
+                               check.completeMethod(ctxt, m)
                        }
                }
+       }
+       if check != nil {
+               check.later(completeMethods)
+       } else {
+               completeMethods()
+       }
+
+       return n.orig.tparams, underlying, methods
+}
 
-               inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList, typMap)
-               n.underlying = inst
-               n.fromRHS = inst
-               n.instance = nil
+func (check *Checker) completeMethod(ctxt *Context, m *Func) {
+       assert(m.instRecv != nil)
+       rbase := m.instRecv
+       m.instRecv = nil
+       m.setColor(black)
+
+       assert(rbase.TypeArgs().Len() > 0)
+
+       // Look up the original method.
+       _, orig := lookupMethod(rbase.orig.methods, rbase.obj.pkg, m.name)
+       assert(orig != nil)
+       if check != nil {
+               check.objDecl(orig, nil)
+       }
+       origSig := orig.typ.(*Signature)
+       if origSig.RecvTypeParams().Len() != rbase.targs.Len() {
+               m.typ = origSig // or new(Signature), but we can't use Typ[Invalid]: Funcs must have Signature type
+               return          // error reported elsewhere
        }
-       return n
+
+       smap := makeSubstMap(origSig.RecvTypeParams().list(), rbase.targs.list())
+       sig := check.subst(orig.pos, origSig, smap, ctxt).(*Signature)
+       if sig == origSig {
+               // No substitution occurred, but we still need to create a new signature to
+               // hold the instantiated receiver.
+               copy := *origSig
+               sig = &copy
+       }
+       var rtyp Type
+       if m.hasPtrRecv() {
+               rtyp = NewPointer(rbase)
+       } else {
+               rtyp = rbase
+       }
+       sig.recv = NewParam(origSig.recv.pos, origSig.recv.pkg, origSig.recv.name, rtyp)
+
+       m.typ = sig
 }
 
 // safeUnderlying returns the underlying of typ without expanding instances, to
@@ -286,7 +339,7 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
 // TODO(rfindley): eliminate this function or give it a better name.
 func safeUnderlying(typ Type) Type {
        if t, _ := typ.(*Named); t != nil {
-               return t.load().underlying
+               return t.underlying
        }
        return typ.Underlying()
 }
index 8263ccae0cb6923741a46a4abb7e337ced2a5c39..c7d6709c26769a5bcd11bf968bcc279f0cd1f588 100644 (file)
@@ -278,9 +278,21 @@ func NewTypeName(pos syntax.Pos, pkg *Package, name string, typ Type) *TypeName
 
 // NewTypeNameLazy returns a new defined type like NewTypeName, but it
 // lazily calls resolve to finish constructing the Named object.
-func NewTypeNameLazy(pos syntax.Pos, pkg *Package, name string, resolve func(named *Named) (tparams []*TypeName, underlying Type, methods []*Func)) *TypeName {
+func NewTypeNameLazy(pos syntax.Pos, pkg *Package, name string, load func(named *Named) (tparams []*TypeParam, underlying Type, methods []*Func)) *TypeName {
        obj := NewTypeName(pos, pkg, name, nil)
-       NewNamed(obj, nil, nil).resolve = resolve
+
+       resolve := func(_ *Context, t *Named) (*TypeParamList, Type, []*Func) {
+               tparams, underlying, methods := load(t)
+
+               switch underlying.(type) {
+               case nil, *Named:
+                       panic(fmt.Sprintf("invalid underlying type %T", t.underlying))
+               }
+
+               return bindTParams(tparams), underlying, methods
+       }
+
+       NewNamed(obj, nil, nil).resolver = resolve
        return obj
 }
 
@@ -303,6 +315,8 @@ func (obj *TypeName) IsAlias() bool {
                return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
        case *Named:
                return obj != t.obj
+       case *TypeParam:
+               return obj != t.obj
        default:
                return true
        }
@@ -351,7 +365,8 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
 // An abstract method may belong to many interfaces due to embedding.
 type Func struct {
        object
-       hasPtrRecv bool // only valid for methods that don't have a type yet
+       instRecv    *Named // if non-nil, the receiver type for an incomplete instance method
+       hasPtrRecv_ bool   // only valid for methods that don't have a type yet; use hasPtrRecv() to read
 }
 
 // NewFunc returns a new function with the given signature, representing
@@ -362,7 +377,7 @@ func NewFunc(pos syntax.Pos, pkg *Package, name string, sig *Signature) *Func {
        if sig != nil {
                typ = sig
        }
-       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false}
+       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, nil, false}
 }
 
 // FullName returns the package- or receiver-type-qualified name of
@@ -376,6 +391,25 @@ func (obj *Func) FullName() string {
 // Scope returns the scope of the function's body block.
 func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
 
+// hasPtrRecv reports whether the receiver is of the form *T for the given method obj.
+func (obj *Func) hasPtrRecv() bool {
+       // If a method's receiver type is set, use that as the source of truth for the receiver.
+       // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
+       // signature. We may reach here before the signature is fully set up: we must explicitly
+       // check if the receiver is set (we cannot just look for non-nil obj.typ).
+       if sig, _ := obj.typ.(*Signature); sig != nil && sig.recv != nil {
+               _, isPtr := deref(sig.recv.typ)
+               return isPtr
+       }
+
+       // If a method's type is not set it may be a method/function that is:
+       // 1) client-supplied (via NewFunc with no signature), or
+       // 2) internally created but not yet type-checked.
+       // For case 1) we can't do anything; the client must know what they are doing.
+       // For case 2) we can use the information gathered by the resolver.
+       return obj.hasPtrRecv_
+}
+
 func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
 
 // A Label represents a declared label.
@@ -475,8 +509,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                if _, ok := typ.(*Basic); ok {
                        return
                }
-               if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
-                       writeTParamList(buf, named.TParams().list(), qf, nil)
+               if named, _ := typ.(*Named); named != nil && named.TypeParams().Len() > 0 {
+                       newTypeWriter(buf, qf).tParamList(named.TypeParams().list())
                }
                if tname.IsAlias() {
                        buf.WriteString(" =")
index a86733a5c99a12824f36121d9a8f935910eb8599..ed3c123023da33943fd949e3605de043d03e3b83 100644 (file)
@@ -33,6 +33,8 @@ func TestIsAlias(t *testing.T) {
        pkg := NewPackage("p", "p")
        t1 := NewTypeName(nopos, pkg, "t1", nil)
        n1 := NewNamed(t1, new(Struct), nil)
+       t5 := NewTypeName(nopos, pkg, "t5", nil)
+       NewTypeParam(t5, nil)
        for _, test := range []struct {
                name  *TypeName
                alias bool
@@ -46,6 +48,7 @@ func TestIsAlias(t *testing.T) {
                {NewTypeName(nopos, nil, "int32", Typ[Int32]), false},  // type name refers to basic type with same name
                {NewTypeName(nopos, pkg, "int32", Typ[Int32]), true},   // type name is declared in user-defined package (outside Universe)
                {NewTypeName(nopos, nil, "rune", Typ[Rune]), true},     // type name refers to basic type rune which is an alias already
+               {t5, false}, // type name refers to type parameter and vice versa
        } {
                check(test.name, test.alias)
        }
index 8336451e9ce16cee7bd19fb49635a1c4038bc6c4..2f85802701dd970a47c300ec65ee3d1ec1741437 100644 (file)
@@ -176,17 +176,14 @@ func operandString(x *operand, qf Qualifier) string {
        if hasType {
                if x.typ != Typ[Invalid] {
                        var intro string
-                       var tpar *TypeParam
                        if isGeneric(x.typ) {
                                intro = " of parameterized type "
-                       } else if tpar = asTypeParam(x.typ); tpar != nil {
-                               intro = " of type parameter "
                        } else {
                                intro = " of type "
                        }
                        buf.WriteString(intro)
                        WriteType(&buf, x.typ, qf)
-                       if tpar != nil {
+                       if tpar := asTypeParam(x.typ); tpar != nil {
                                buf.WriteString(" constrained by ")
                                WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
                        }
@@ -252,53 +249,49 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
 
        V := x.typ
 
-       const debugAssignableTo = false
-       if debugAssignableTo && check != nil {
-               check.dump("V = %s", V)
-               check.dump("T = %s", T)
-       }
-
        // x's type is identical to T
        if Identical(V, T) {
                return true, 0
        }
 
-       Vu := optype(V)
-       Tu := optype(T)
-
-       if debugAssignableTo && check != nil {
-               check.dump("Vu = %s", Vu)
-               check.dump("Tu = %s", Tu)
-       }
+       Vu := under(V)
+       Tu := under(T)
+       Vp, _ := Vu.(*TypeParam)
+       Tp, _ := Tu.(*TypeParam)
 
        // x is an untyped value representable by a value of type T.
        if isUntyped(Vu) {
-               if t, ok := Tu.(*TypeParam); ok {
-                       return t.is(func(t *term) bool {
-                               // TODO(gri) this could probably be more efficient
-                               if t.tilde {
-                                       // TODO(gri) We need to check assignability
-                                       //           for the underlying type of x.
+               assert(Vp == nil)
+               if Tp != nil {
+                       // T is a type parameter: x is assignable to T if it is
+                       // representable by each specific type in the type set of T.
+                       return Tp.is(func(t *term) bool {
+                               if t == nil {
+                                       return false
                                }
-                               ok, _ := x.assignableTo(check, t.typ, reason)
-                               return ok
+                               // A term may be a tilde term but the underlying
+                               // type of an untyped value doesn't change so we
+                               // don't need to do anything special.
+                               newType, _, _ := check.implicitTypeAndValue(x, t.typ)
+                               return newType != nil
                        }), _IncompatibleAssign
                }
-               newType, _, _ := check.implicitTypeAndValue(x, Tu)
+               newType, _, _ := check.implicitTypeAndValue(x, T)
                return newType != nil, _IncompatibleAssign
        }
        // Vu is typed
 
        // x's type V and T have identical underlying types
-       // and at least one of V or T is not a named type
-       if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+       // and at least one of V or T is not a named type.
+       if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) {
                return true, 0
        }
 
-       // T is an interface type and x implements T
+       // T is an interface type and x implements T and T is not a type parameter
        if Ti, ok := Tu.(*Interface); ok {
                if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
                        if reason != nil {
+                               // TODO(gri) the error messages here should follow the style in Checker.typeAssertion (factor!)
                                if wrongType != nil {
                                        if Identical(m.typ, wrongType.typ) {
                                                *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
@@ -317,13 +310,69 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
 
        // x is a bidirectional channel value, T is a channel
        // type, x's type V and T have identical element types,
-       // and at least one of V or T is not a named type
+       // and at least one of V or T is not a named type.
        if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
                if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
-                       return !isNamed(V) || !isNamed(T), _InvalidChanAssign
+                       return !hasName(V) || !hasName(T), _InvalidChanAssign
+               }
+       }
+
+       // optimization: if we don't have type parameters, we're done
+       if Vp == nil && Tp == nil {
+               return false, _IncompatibleAssign
+       }
+
+       errorf := func(format string, args ...interface{}) {
+               if check != nil && reason != nil {
+                       msg := check.sprintf(format, args...)
+                       if *reason != "" {
+                               msg += "\n\t" + *reason
+                       }
+                       *reason = msg
                }
        }
 
+       // x's type V is not a named type and T is a type parameter, and
+       // x is assignable to each specific type in T's type set.
+       if !hasName(V) && Tp != nil {
+               ok := false
+               code := _IncompatibleAssign
+               Tp.is(func(T *term) bool {
+                       if T == nil {
+                               return false // no specific types
+                       }
+                       ok, code = x.assignableTo(check, T.typ, reason)
+                       if !ok {
+                               errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
+                               return false
+                       }
+                       return true
+               })
+               return ok, code
+       }
+
+       // x's type V is a type parameter and T is not a named type,
+       // and values x' of each specific type in V's type set are
+       // assignable to T.
+       if Vp != nil && !hasName(T) {
+               x := *x // don't clobber outer x
+               ok := false
+               code := _IncompatibleAssign
+               Vp.is(func(V *term) bool {
+                       if V == nil {
+                               return false // no specific types
+                       }
+                       x.typ = V.typ
+                       ok, code = x.assignableTo(check, T, reason)
+                       if !ok {
+                               errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T)
+                               return false
+                       }
+                       return true
+               })
+               return ok, code
+       }
+
        return false, _IncompatibleAssign
 }
 
index 3c883e1ab5c062d9488042b4068412dbd1646c74..7fbb91eb61256495fc20903937b41a4fb7c417fa 100644 (file)
 
 package types2
 
-// isNamed reports whether typ has a name.
-// isNamed may be called with types that are not fully set up.
-func isNamed(typ Type) bool {
-       switch typ.(type) {
-       case *Basic, *Named, *TypeParam:
-               return true
-       }
-       return false
+// The isX predicates below report whether t is an X.
+// If t is a type parameter the result is false; i.e.,
+// these predicates don't look inside a type parameter.
+
+func isBoolean(t Type) bool        { return isBasic(t, IsBoolean) }
+func isInteger(t Type) bool        { return isBasic(t, IsInteger) }
+func isUnsigned(t Type) bool       { return isBasic(t, IsUnsigned) }
+func isFloat(t Type) bool          { return isBasic(t, IsFloat) }
+func isComplex(t Type) bool        { return isBasic(t, IsComplex) }
+func isNumeric(t Type) bool        { return isBasic(t, IsNumeric) }
+func isString(t Type) bool         { return isBasic(t, IsString) }
+func isIntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
+func isConstType(t Type) bool      { return isBasic(t, IsConstType) }
+
+// isBasic reports whether under(t) is a basic type with the specified info.
+// If t is a type parameter the result is false; i.e.,
+// isBasic does not look inside a type parameter.
+func isBasic(t Type, info BasicInfo) bool {
+       u, _ := under(t).(*Basic)
+       return u != nil && u.info&info != 0
 }
 
-// isGeneric reports whether a type is a generic, uninstantiated type (generic
-// signatures are not included).
-func isGeneric(typ Type) bool {
-       // A parameterized type is only instantiated if it doesn't have an instantiation already.
-       named, _ := typ.(*Named)
-       return named != nil && named.obj != nil && named.targs == nil && named.TParams() != nil
-}
-
-func is(typ Type, what BasicInfo) bool {
-       switch t := under(typ).(type) {
+// The allX predicates below report whether t is an X.
+// If t is a type parameter the result is true if isX is true
+// for all specified types of the type parameter's type set.
+// allX is an optimized version of isX(structure(t)) (which
+// is the same as underIs(t, isX)).
+
+func allBoolean(t Type) bool         { return allBasic(t, IsBoolean) }
+func allInteger(t Type) bool         { return allBasic(t, IsInteger) }
+func allUnsigned(t Type) bool        { return allBasic(t, IsUnsigned) }
+func allNumeric(t Type) bool         { return allBasic(t, IsNumeric) }
+func allString(t Type) bool          { return allBasic(t, IsString) }
+func allOrdered(t Type) bool         { return allBasic(t, IsOrdered) }
+func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
+
+// allBasic reports whether under(t) is a basic type with the specified info.
+// If t is a type parameter, the result is true if isBasic(t, info) is true
+// for all specific types of the type parameter's type set.
+// allBasic(t, info) is an optimized version of isBasic(structure(t), info).
+func allBasic(t Type, info BasicInfo) bool {
+       switch u := under(t).(type) {
        case *Basic:
-               return t.info&what != 0
+               return u.info&info != 0
        case *TypeParam:
-               return t.underIs(func(t Type) bool { return is(t, what) })
+               return u.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
        }
        return false
 }
 
-func isBoolean(typ Type) bool  { return is(typ, IsBoolean) }
-func isInteger(typ Type) bool  { return is(typ, IsInteger) }
-func isUnsigned(typ Type) bool { return is(typ, IsUnsigned) }
-func isFloat(typ Type) bool    { return is(typ, IsFloat) }
-func isComplex(typ Type) bool  { return is(typ, IsComplex) }
-func isNumeric(typ Type) bool  { return is(typ, IsNumeric) }
-func isString(typ Type) bool   { return is(typ, IsString) }
-
-// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
-// produce the expected result because a type list that contains both an integer
-// and a floating-point type is neither (all) integers, nor (all) floats.
-// Use isIntegerOrFloat instead.
-func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
-
-// isNumericOrString is the equivalent of isIntegerOrFloat for isNumeric(typ) || isString(typ).
-func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
+// hasName reports whether t has a name. This includes
+// predeclared types, defined types, and type parameters.
+// hasName may be called with types that are not fully set up.
+func hasName(t Type) bool {
+       switch t.(type) {
+       case *Basic, *Named, *TypeParam:
+               return true
+       }
+       return false
+}
 
-// isTyped reports whether typ is typed; i.e., not an untyped
+// isTyped reports whether t is typed; i.e., not an untyped
 // constant or boolean. isTyped may be called with types that
 // are not fully set up.
-func isTyped(typ Type) bool {
+func isTyped(t Type) bool {
        // isTyped is called with types that are not fully
        // set up. Must not call asBasic()!
-       t, _ := typ.(*Basic)
-       return t == nil || t.info&IsUntyped == 0
+       b, _ := t.(*Basic)
+       return b == nil || b.info&IsUntyped == 0
 }
 
-// isUntyped(typ) is the same as !isTyped(typ).
-func isUntyped(typ Type) bool {
-       return !isTyped(typ)
+// isUntyped(t) is the same as !isTyped(t).
+func isUntyped(t Type) bool {
+       return !isTyped(t)
 }
 
-func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
+// IsInterface reports whether t is an interface type.
+func IsInterface(t Type) bool {
+       return asInterface(t) != nil
+}
 
-func isConstType(typ Type) bool {
-       // Type parameters are never const types.
-       t, _ := under(typ).(*Basic)
-       return t != nil && t.info&IsConstType != 0
+// isTypeParam reports whether t is a type parameter.
+func isTypeParam(t Type) bool {
+       _, ok := under(t).(*TypeParam)
+       return ok
 }
 
-// IsInterface reports whether typ is an interface type.
-func IsInterface(typ Type) bool {
-       return asInterface(typ) != nil
+// isGeneric reports whether a type is a generic, uninstantiated type
+// (generic signatures are not included).
+// TODO(gri) should we include signatures or assert that they are not present?
+func isGeneric(t Type) bool {
+       // A parameterized type is only generic if it doesn't have an instantiation already.
+       named, _ := t.(*Named)
+       return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
 }
 
 // Comparable reports whether values of type T are comparable.
@@ -115,15 +138,15 @@ func comparable(T Type, seen map[Type]bool) bool {
        return false
 }
 
-// hasNil reports whether a type includes the nil value.
-func hasNil(typ Type) bool {
-       switch t := under(typ).(type) {
+// hasNil reports whether type t includes the nil value.
+func hasNil(t Type) bool {
+       switch u := under(t).(type) {
        case *Basic:
-               return t.kind == UnsafePointer
+               return u.kind == UnsafePointer
        case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
                return true
        case *TypeParam:
-               return t.underIs(hasNil)
+               return u.underIs(hasNil)
        }
        return false
 }
@@ -220,11 +243,18 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                // parameter names.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
-                               identicalTParams(x.TParams().list(), y.TParams().list(), cmpTags, p) &&
+                               identicalTParams(x.TypeParams().list(), y.TypeParams().list(), cmpTags, p) &&
                                identical(x.params, y.params, cmpTags, p) &&
                                identical(x.results, y.results, cmpTags, p)
                }
 
+       case *Union:
+               if y, _ := y.(*Union); y != nil {
+                       xset := computeUnionTypeSet(nil, nopos, x)
+                       yset := computeUnionTypeSet(nil, nopos, y)
+                       return xset.terms.equal(yset.terms)
+               }
+
        case *Interface:
                // Two interface types are identical if they describe the same type sets.
                // With the existing implementation restriction, this simplifies to:
@@ -302,11 +332,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                // Two named types are identical if their type names originate
                // in the same type declaration.
                if y, ok := y.(*Named); ok {
-                       x.expand(nil)
-                       y.expand(nil)
-
-                       xargs := x.TArgs()
-                       yargs := y.TArgs()
+                       xargs := x.TypeArgs().list()
+                       yargs := y.TypeArgs().list()
 
                        if len(xargs) != len(yargs) {
                                return false
@@ -335,10 +362,6 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
        case *TypeParam:
                // nothing to do (x and y being equal is caught in the very beginning of this function)
 
-       case *top:
-               // Either both types are theTop in which case the initial x == y check
-               // will have caught them. Otherwise they are not identical.
-
        case nil:
                // avoid a crash in case of nil type
 
@@ -349,13 +372,13 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
        return false
 }
 
-func identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
+func identicalTParams(x, y []*TypeParam, cmpTags bool, p *ifacePair) bool {
        if len(x) != len(y) {
                return false
        }
        for i, x := range x {
                y := y[i]
-               if !identical(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
+               if !identical(x.bound, y.bound, cmpTags, p) {
                        return false
                }
        }
@@ -365,9 +388,8 @@ func identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
 // Default returns the default "typed" type for an "untyped" type;
 // it returns the incoming type for all other types. The default type
 // for untyped nil is untyped nil.
-//
-func Default(typ Type) Type {
-       if t, ok := typ.(*Basic); ok {
+func Default(t Type) Type {
+       if t, ok := t.(*Basic); ok {
                switch t.kind {
                case UntypedBool:
                        return Typ[Bool]
@@ -383,5 +405,5 @@ func Default(typ Type) Type {
                        return Typ[String]
                }
        }
-       return typ
+       return t
 }
index 018a20cfb2dc69722ce32b9e15aa3985d6538205..a8cb244c55e6095c31bbb68d5dee0d427e35a789 100644 (file)
@@ -412,52 +412,60 @@ func (check *Checker) collectObjects() {
                                }
 
                        case *syntax.TypeDecl:
+                               if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) {
+                                       check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
+                               }
                                obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
                                check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
 
                        case *syntax.FuncDecl:
-                               d := s // TODO(gri) get rid of this
-                               name := d.Name.Value
-                               obj := NewFunc(d.Name.Pos(), pkg, name, nil)
-                               if d.Recv == nil {
+                               name := s.Name.Value
+                               obj := NewFunc(s.Name.Pos(), pkg, name, nil)
+                               hasTParamError := false // avoid duplicate type parameter errors
+                               if s.Recv == nil {
                                        // regular function
                                        if name == "init" || name == "main" && pkg.name == "main" {
-                                               if d.TParamList != nil {
-                                                       check.softErrorf(d, "func %s must have no type parameters", name)
+                                               if len(s.TParamList) != 0 {
+                                                       check.softErrorf(s.TParamList[0], "func %s must have no type parameters", name)
+                                                       hasTParamError = true
                                                }
-                                               if t := d.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
-                                                       check.softErrorf(d, "func %s must have no arguments and no return values", name)
+                                               if t := s.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
+                                                       check.softErrorf(s, "func %s must have no arguments and no return values", name)
                                                }
                                        }
                                        // don't declare init functions in the package scope - they are invisible
                                        if name == "init" {
                                                obj.parent = pkg.scope
-                                               check.recordDef(d.Name, obj)
+                                               check.recordDef(s.Name, obj)
                                                // init functions must have a body
-                                               if d.Body == nil {
+                                               if s.Body == nil {
                                                        // TODO(gri) make this error message consistent with the others above
                                                        check.softErrorf(obj.pos, "missing function body")
                                                }
                                        } else {
-                                               check.declare(pkg.scope, d.Name, obj, nopos)
+                                               check.declare(pkg.scope, s.Name, obj, nopos)
                                        }
                                } else {
                                        // method
                                        // d.Recv != nil
-                                       if !acceptMethodTypeParams && len(d.TParamList) != 0 {
+                                       if !acceptMethodTypeParams && len(s.TParamList) != 0 {
                                                //check.error(d.TParamList.Pos(), invalidAST + "method must have no type parameters")
-                                               check.error(d, invalidAST+"method must have no type parameters")
+                                               check.error(s.TParamList[0], invalidAST+"method must have no type parameters")
+                                               hasTParamError = true
                                        }
-                                       ptr, recv, _ := check.unpackRecv(d.Recv.Type, false)
+                                       ptr, recv, _ := check.unpackRecv(s.Recv.Type, false)
                                        // (Methods with invalid receiver cannot be associated to a type, and
                                        // methods with blank _ names are never found; no need to collect any
                                        // of them. They will still be type-checked with all the other functions.)
                                        if recv != nil && name != "_" {
                                                methods = append(methods, methodInfo{obj, ptr, recv})
                                        }
-                                       check.recordDef(d.Name, obj)
+                                       check.recordDef(s.Name, obj)
+                               }
+                               if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
+                                       check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
                                }
-                               info := &declInfo{file: fileScope, fdecl: d}
+                               info := &declInfo{file: fileScope, fdecl: s}
                                // Methods are not package-level objects but we still track them in the
                                // object map so that we can handle them like regular functions (if the
                                // receiver is invalid); also we need their fdecl info when associating
@@ -501,7 +509,7 @@ func (check *Checker) collectObjects() {
                        // Determine the receiver base type and associate m with it.
                        ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
                        if base != nil {
-                               m.obj.hasPtrRecv = ptr
+                               m.obj.hasPtrRecv_ = ptr
                                check.methods[base] = append(check.methods[base], m.obj)
                        }
                }
index 204e456a916fb127e02b3fa9aee0f6c41cd5971b..6c3e1842ce7d715b93d350ff58cc1e3738e4cf0d 100644 (file)
@@ -62,6 +62,11 @@ func (check *Checker) isTerminating(s syntax.Stmt, label string) bool {
                return true
 
        case *syntax.ForStmt:
+               if _, ok := s.Init.(*syntax.RangeClause); ok {
+                       // Range clauses guarantee that the loop terminates,
+                       // so the loop is not a terminating statement. See issue 49003.
+                       break
+               }
                if s.Cond == nil && !hasBreak(s.Body, label, true) {
                        return true
                }
index 4722fec9889f0f53670daef90d75f537962f378e..e0d2e1b07a0bbef3a295b85738ad2ebc3bcae9bc 100644 (file)
@@ -24,12 +24,7 @@ func TestSelf(t *testing.T) {
        conf := Config{Importer: defaultImporter()}
        _, err = conf.Check("cmd/compile/internal/types2", files, nil)
        if err != nil {
-               // Importing go/constant doesn't work in the
-               // build dashboard environment. Don't report an error
-               // for now so that the build remains green.
-               // TODO(gri) fix this
-               t.Log(err) // replace w/ t.Fatal eventually
-               return
+               t.Fatal(err)
        }
 }
 
index e319e6521128b0ad3973c5ba8ceed9d4cded0030..45414355879b1e8c16b48b2cca40a70db9efc165 100644 (file)
@@ -4,10 +4,7 @@
 
 package types2
 
-import (
-       "cmd/compile/internal/syntax"
-       "fmt"
-)
+import "cmd/compile/internal/syntax"
 
 // ----------------------------------------------------------------------------
 // API
@@ -19,20 +16,21 @@ type Signature struct {
        // and store it in the Func Object) because when type-checking a function
        // literal we call the general type checker which returns a general Type.
        // We then unpack the *Signature and use the scope for the literal body.
-       rparams  *TParamList // receiver type parameters from left to right, or nil
-       tparams  *TParamList // type parameters from left to right, or nil
-       scope    *Scope      // function scope, present for package-local signatures
-       recv     *Var        // nil if not a method
-       params   *Tuple      // (incoming) parameters from left to right; or nil
-       results  *Tuple      // (outgoing) results from left to right; or nil
-       variadic bool        // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+       rparams  *TypeParamList // receiver type parameters from left to right, or nil
+       tparams  *TypeParamList // type parameters from left to right, or nil
+       scope    *Scope         // function scope, present for package-local signatures
+       recv     *Var           // nil if not a method
+       params   *Tuple         // (incoming) parameters from left to right; or nil
+       results  *Tuple         // (outgoing) results from left to right; or nil
+       variadic bool           // true if the last parameter's type is of the form ...T (or string, for append built-in only)
 }
 
-// NewSignature returns a new function type for the given receiver, parameters,
-// and results, either of which may be nil. If variadic is set, the function
-// is variadic, it must have at least one parameter, and the last parameter
-// must be of unnamed slice type.
-func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
+// NewSignatureType creates a new function type for the given receiver,
+// receiver type parameters, type parameters, parameters, and results. If
+// variadic is set, params must hold at least one parameter and the last
+// parameter must be of unnamed slice type. If recv is non-nil, typeParams must
+// be empty. If recvTypeParams is non-empty, recv must be non-nil.
+func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature {
        if variadic {
                n := params.Len()
                if n == 0 {
@@ -42,7 +40,20 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
                        panic("variadic parameter must be of unnamed slice type")
                }
        }
-       return &Signature{recv: recv, params: params, results: results, variadic: variadic}
+       sig := &Signature{recv: recv, params: params, results: results, variadic: variadic}
+       if len(recvTypeParams) != 0 {
+               if recv == nil {
+                       panic("function with receiver type parameters must have a receiver")
+               }
+               sig.rparams = bindTParams(recvTypeParams)
+       }
+       if len(typeParams) != 0 {
+               if recv != nil {
+                       panic("function with type parameters cannot have a receiver")
+               }
+               sig.tparams = bindTParams(typeParams)
+       }
+       return sig
 }
 
 // Recv returns the receiver of signature s (if a method), or nil if a
@@ -53,17 +64,17 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
 // contain methods whose receiver type is a different interface.
 func (s *Signature) Recv() *Var { return s.recv }
 
-// TParams returns the type parameters of signature s, or nil.
-func (s *Signature) TParams() *TParamList { return s.tparams }
+// TypeParams returns the type parameters of signature s, or nil.
+func (s *Signature) TypeParams() *TypeParamList { return s.tparams }
 
-// SetTParams sets the type parameters of signature s.
-func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) }
+// SetTypeParams sets the type parameters of signature s.
+func (s *Signature) SetTypeParams(tparams []*TypeParam) { s.tparams = bindTParams(tparams) }
 
-// RParams returns the receiver type parameters of signature s, or nil.
-func (s *Signature) RParams() *TParamList { return s.rparams }
+// RecvTypeParams returns the receiver type parameters of signature s, or nil.
+func (s *Signature) RecvTypeParams() *TypeParamList { return s.rparams }
 
-// SetRParams sets the receiver type params of signature s.
-func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) }
+// SetRecvTypeParams sets the receiver type params of signature s.
+func (s *Signature) SetRecvTypeParams(rparams []*TypeParam) { s.rparams = bindTParams(rparams) }
 
 // Params returns the parameters of signature s, or nil.
 func (s *Signature) Params() *Tuple { return s.params }
@@ -91,78 +102,68 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
        sig.scope = check.scope
        defer check.closeScope()
 
-       var recvTyp syntax.Expr // rewritten receiver type; valid if != nil
        if recvPar != nil {
                // collect generic receiver type parameters, if any
                // - a receiver type parameter is like any other type parameter, except that it is declared implicitly
                // - the receiver specification acts as local declaration for its type parameters, which may be blank
                _, rname, rparams := check.unpackRecv(recvPar.Type, true)
                if len(rparams) > 0 {
-                       // Blank identifiers don't get declared and regular type-checking of the instantiated
-                       // parameterized receiver type expression fails in Checker.collectParams of receiver.
-                       // Identify blank type parameters and substitute each with a unique new identifier named
-                       // "n_" (where n is the parameter index) and which cannot conflict with any user-defined
-                       // name.
-                       var smap map[*syntax.Name]*syntax.Name // substitution map from "_" to "!n" identifiers
+                       tparams := make([]*TypeParam, len(rparams))
+                       for i, rparam := range rparams {
+                               tparams[i] = check.declareTypeParam(rparam)
+                       }
+                       sig.rparams = bindTParams(tparams)
+                       // Blank identifiers don't get declared, so naive type-checking of the
+                       // receiver type expression would fail in Checker.collectParams below,
+                       // when Checker.ident cannot resolve the _ to a type.
+                       //
+                       // Checker.recvTParamMap maps these blank identifiers to their type parameter
+                       // types, so that they may be resolved in Checker.ident when they fail
+                       // lookup in the scope.
                        for i, p := range rparams {
                                if p.Value == "_" {
-                                       new := *p
-                                       new.Value = fmt.Sprintf("%d_", i)
-                                       rparams[i] = &new // use n_ identifier instead of _ so it can be looked up
-                                       if smap == nil {
-                                               smap = make(map[*syntax.Name]*syntax.Name)
+                                       tpar := sig.rparams.At(i)
+                                       if check.recvTParamMap == nil {
+                                               check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
                                        }
-                                       smap[p] = &new
+                                       check.recvTParamMap[p] = tpar
                                }
                        }
-                       if smap != nil {
-                               // blank identifiers were found => use rewritten receiver type
-                               recvTyp = isubst(recvPar.Type, smap)
-                       }
-                       rlist := make([]*TypeName, len(rparams))
-                       for i, rparam := range rparams {
-                               rlist[i] = check.declareTypeParam(rparam)
-                       }
-                       sig.rparams = bindTParams(rlist)
                        // determine receiver type to get its type parameters
                        // and the respective type parameter bounds
-                       var recvTParams []*TypeName
+                       var recvTParams []*TypeParam
                        if rname != nil {
                                // recv should be a Named type (otherwise an error is reported elsewhere)
                                // Also: Don't report an error via genericType since it will be reported
                                //       again when we type-check the signature.
                                // TODO(gri) maybe the receiver should be marked as invalid instead?
-                               if recv := asNamed(check.genericType(rname, false)); recv != nil {
-                                       recvTParams = recv.TParams().list()
+                               if recv, _ := check.genericType(rname, false).(*Named); recv != nil {
+                                       recvTParams = recv.TypeParams().list()
                                }
                        }
                        // provide type parameter bounds
                        // - only do this if we have the right number (otherwise an error is reported elsewhere)
-                       if sig.RParams().Len() == len(recvTParams) {
+                       if sig.RecvTypeParams().Len() == len(recvTParams) {
                                // We have a list of *TypeNames but we need a list of Types.
-                               list := make([]Type, sig.RParams().Len())
-                               for i, t := range sig.RParams().list() {
-                                       list[i] = t.typ
+                               list := make([]Type, sig.RecvTypeParams().Len())
+                               for i, t := range sig.RecvTypeParams().list() {
+                                       list[i] = t
+                                       check.mono.recordCanon(t, recvTParams[i])
                                }
                                smap := makeSubstMap(recvTParams, list)
-                               for i, tname := range sig.RParams().list() {
-                                       bound := recvTParams[i].typ.(*TypeParam).bound
+                               for i, tpar := range sig.RecvTypeParams().list() {
+                                       bound := recvTParams[i].bound
                                        // bound is (possibly) parameterized in the context of the
                                        // receiver type declaration. Substitute parameters for the
                                        // current context.
-                                       // TODO(gri) should we assume now that bounds always exist?
-                                       //           (no bound == empty interface)
-                                       if bound != nil {
-                                               bound = check.subst(tname.pos, bound, smap, nil)
-                                               tname.typ.(*TypeParam).bound = bound
-                                       }
+                                       tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
                                }
                        }
                }
        }
 
        if tparams != nil {
-               sig.tparams = check.collectTypeParams(tparams)
+               check.collectTypeParams(&sig.tparams, tparams)
                // Always type-check method type parameters but complain if they are not enabled.
                // (A separate check is needed when type-checking interface method signatures because
                // they don't have a receiver specification.)
@@ -177,10 +178,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
        scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
        var recvList []*Var // TODO(gri) remove the need for making a list here
        if recvPar != nil {
-               recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, recvTyp, false) // use rewritten receiver type, if any
+               recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, false) // use rewritten receiver type, if any
        }
-       params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true)
-       results, _ := check.collectParams(scope, ftyp.ResultList, nil, false)
+       params, variadic := check.collectParams(scope, ftyp.ParamList, true)
+       results, _ := check.collectParams(scope, ftyp.ResultList, false)
        scope.Squash(func(obj, alt Object) {
                var err error_
                err.errorf(obj, "%s redeclared in this block", obj.Name())
@@ -215,7 +216,13 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
                        var err string
                        switch T := rtyp.(type) {
                        case *Named:
-                               T.expand(nil)
+                               T.resolve(check.conf.Context)
+                               // The receiver type may be an instantiated type referred to
+                               // by an alias (which cannot have receiver parameters for now).
+                               if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
+                                       check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
+                                       break
+                               }
                                // spec: "The type denoted by T is called the receiver base type; it must not
                                // be a pointer or interface type and it must be declared in the same package
                                // as the method."
@@ -266,8 +273,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
 }
 
 // collectParams declares the parameters of list in scope and returns the corresponding
-// variable list. If type0 != nil, it is used instead of the first type in list.
-func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 syntax.Expr, variadicOk bool) (params []*Var, variadic bool) {
+// variable list.
+func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, variadicOk bool) (params []*Var, variadic bool) {
        if list == nil {
                return
        }
@@ -281,9 +288,6 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy
                // type-check type of grouped fields only once
                if ftype != prev {
                        prev = ftype
-                       if i == 0 && type0 != nil {
-                               ftype = type0
-                       }
                        if t, _ := ftype.(*syntax.DotsType); t != nil {
                                ftype = t.Elem
                                if variadicOk && i == len(list)-1 {
@@ -333,61 +337,3 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy
 
        return
 }
-
-// isubst returns an x with identifiers substituted per the substitution map smap.
-// isubst only handles the case of (valid) method receiver type expressions correctly.
-func isubst(x syntax.Expr, smap map[*syntax.Name]*syntax.Name) syntax.Expr {
-       switch n := x.(type) {
-       case *syntax.Name:
-               if alt := smap[n]; alt != nil {
-                       return alt
-               }
-       // case *syntax.StarExpr:
-       //      X := isubst(n.X, smap)
-       //      if X != n.X {
-       //              new := *n
-       //              new.X = X
-       //              return &new
-       //      }
-       case *syntax.Operation:
-               if n.Op == syntax.Mul && n.Y == nil {
-                       X := isubst(n.X, smap)
-                       if X != n.X {
-                               new := *n
-                               new.X = X
-                               return &new
-                       }
-               }
-       case *syntax.IndexExpr:
-               Index := isubst(n.Index, smap)
-               if Index != n.Index {
-                       new := *n
-                       new.Index = Index
-                       return &new
-               }
-       case *syntax.ListExpr:
-               var elems []syntax.Expr
-               for i, elem := range n.ElemList {
-                       new := isubst(elem, smap)
-                       if new != elem {
-                               if elems == nil {
-                                       elems = make([]syntax.Expr, len(n.ElemList))
-                                       copy(elems, n.ElemList)
-                               }
-                               elems[i] = new
-                       }
-               }
-               if elems != nil {
-                       new := *n
-                       new.ElemList = elems
-                       return &new
-               }
-       case *syntax.ParenExpr:
-               return isubst(n.X, smap) // no need to keep parentheses
-       default:
-               // Other receiver type expressions are invalid.
-               // It's fine to ignore those here as they will
-               // be checked elsewhere.
-       }
-       return x
-}
index d2f53258f03b6c9bd6579b2577853841ac90454b..99b846b80b91c1f355777331ca012ce54ee7f405 100644 (file)
@@ -28,20 +28,19 @@ func TestSizeof(t *testing.T) {
                {Tuple{}, 12, 24},
                {Signature{}, 28, 56},
                {Union{}, 16, 32},
-               {Interface{}, 40, 80},
+               {Interface{}, 44, 88},
                {Map{}, 16, 32},
                {Chan{}, 12, 24},
-               {Named{}, 80, 152},
+               {Named{}, 68, 128},
                {TypeParam{}, 28, 48},
                {term{}, 12, 24},
-               {top{}, 0, 0},
 
                // Objects
                {PkgName{}, 64, 104},
                {Const{}, 64, 104},
                {TypeName{}, 56, 88},
                {Var{}, 60, 96},
-               {Func{}, 60, 96},
+               {Func{}, 64, 104},
                {Label{}, 60, 96},
                {Builtin{}, 60, 96},
                {Nil{}, 56, 88},
@@ -49,7 +48,7 @@ func TestSizeof(t *testing.T) {
                // Misc
                {Scope{}, 60, 104},
                {Package{}, 40, 80},
-               {TypeSet{}, 28, 56},
+               {_TypeSet{}, 28, 56},
        }
 
        for _, test := range tests {
index cde35c17b6f717f97dd3781f914ee0fcfe0afc99..9c22f0167383df01e1d03708bd55180b3fc46332 100644 (file)
@@ -192,6 +192,8 @@ func TestStdFixed(t *testing.T) {
                "issue20780.go",  // types2 does not have constraints on stack size
                "issue42058a.go", // types2 does not have constraints on channel element size
                "issue42058b.go", // types2 does not have constraints on channel element size
+               "issue48097.go",  // go/types doesn't check validity of //go:xxx directives, and non-init bodyless function
+               "issue48230.go",  // go/types doesn't check validity of //go:xxx directives
        )
 }
 
@@ -215,7 +217,7 @@ func typecheck(t *testing.T, path string, filenames []string) {
        var files []*syntax.File
        for _, filename := range filenames {
                errh := func(err error) { t.Error(err) }
-               file, err := syntax.ParseFile(filename, errh, nil, 0)
+               file, err := syntax.ParseFile(filename, errh, nil, syntax.AllowGenerics)
                if err != nil {
                        return
                }
index 7865c2d4f45fe399ae96e77d0993f0585b5a026d..eaf420aca77ebeac4deec66786de82fb3e522b06 100644 (file)
@@ -52,11 +52,6 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
                check.error(body.Rbrace, "missing return")
        }
 
-       // TODO(gri) Should we make it an error to declare generic functions
-       //           where the type parameters are not used?
-       // 12/19/2018: Probably not - it can make sense to have an API with
-       //           all functions uniformly sharing the same type parameters.
-
        // spec: "Implementation restriction: A compiler may make it illegal to
        // declare a variable inside a function body if the variable is never used."
        check.usage(sig.scope)
@@ -175,7 +170,7 @@ func (check *Checker) closeScope() {
 func (check *Checker) suspendedCall(keyword string, call *syntax.CallExpr) {
        var x operand
        var msg string
-       switch check.rawExpr(&x, call, nil) {
+       switch check.rawExpr(&x, call, nil, false) {
        case conversion:
                msg = "requires function call, not conversion"
        case expression:
@@ -269,15 +264,29 @@ L:
        }
 }
 
+// isNil reports whether the expression e denotes the predeclared value nil.
+func (check *Checker) isNil(e syntax.Expr) bool {
+       // The only way to express the nil value is by literally writing nil (possibly in parentheses).
+       if name, _ := unparen(e).(*syntax.Name); name != nil {
+               _, ok := check.lookup(name.Value).(*Nil)
+               return ok
+       }
+       return false
+}
+
 func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []syntax.Expr, seen map[Type]syntax.Expr) (T Type) {
+       var dummy operand
 L:
        for _, e := range types {
-               T = check.typOrNil(e)
-               if T == Typ[Invalid] {
-                       continue L
-               }
-               if T != nil {
-                       check.ordinaryType(e.Pos(), T)
+               // The spec allows the value nil instead of a type.
+               if check.isNil(e) {
+                       T = nil
+                       check.expr(&dummy, e) // run e through expr so we get the usual Info recordings
+               } else {
+                       T = check.varType(e)
+                       if T == Typ[Invalid] {
+                               continue L
+                       }
                }
                // look for duplicate types
                // (quadratic algorithm, but type switches tend to be reasonably small)
@@ -286,7 +295,7 @@ L:
                                // talk about "case" rather than "type" because of nil case
                                Ts := "nil"
                                if T != nil {
-                                       Ts = T.String()
+                                       Ts = TypeString(T, check.qualifier)
                                }
                                var err error_
                                err.errorf(e, "duplicate case %s in type switch", Ts)
@@ -297,12 +306,53 @@ L:
                }
                seen[T] = e
                if T != nil {
-                       check.typeAssertion(e.Pos(), x, xtyp, T)
+                       check.typeAssertion(e, x, xtyp, T, true)
                }
        }
        return
 }
 
+// TODO(gri) Once we are certain that typeHash is correct in all situations, use this version of caseTypes instead.
+//           (Currently it may be possible that different types have identical names and import paths due to ImporterFrom.)
+//
+// func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []syntax.Expr, seen map[string]syntax.Expr) (T Type) {
+//     var dummy operand
+// L:
+//     for _, e := range types {
+//             // The spec allows the value nil instead of a type.
+//             var hash string
+//             if check.isNil(e) {
+//                     check.expr(&dummy, e) // run e through expr so we get the usual Info recordings
+//                     T = nil
+//                     hash = "<nil>" // avoid collision with a type named nil
+//             } else {
+//                     T = check.varType(e)
+//                     if T == Typ[Invalid] {
+//                             continue L
+//                     }
+//                     hash = typeHash(T, nil)
+//             }
+//             // look for duplicate types
+//             if other := seen[hash]; other != nil {
+//                     // talk about "case" rather than "type" because of nil case
+//                     Ts := "nil"
+//                     if T != nil {
+//                             Ts = TypeString(T, check.qualifier)
+//                     }
+//                     var err error_
+//                     err.errorf(e, "duplicate case %s in type switch", Ts)
+//                     err.errorf(other, "previous case")
+//                     check.report(&err)
+//                     continue L
+//             }
+//             seen[hash] = e
+//             if T != nil {
+//                     check.typeAssertion(e, x, xtyp, T, true)
+//             }
+//     }
+//     return
+// }
+
 // stmt typechecks statement s.
 func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
        // statements must end with the same top scope as they started with
@@ -336,7 +386,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                // function and method calls and receive operations can appear
                // in statement context. Such statements may be parenthesized."
                var x operand
-               kind := check.rawExpr(&x, s.X, nil)
+               kind := check.rawExpr(&x, s.X, nil, false)
                var msg string
                switch x.mode {
                default:
@@ -393,7 +443,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                        if x.mode == invalid {
                                return
                        }
-                       if !isNumeric(x.typ) {
+                       if !allNumeric(x.typ) {
                                check.errorf(lhs[0], invalidOp+"%s%s%s (non-numeric type %s)", lhs[0], s.Op, s.Op, x.typ)
                                return
                        }
@@ -422,7 +472,6 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                check.assignVar(lhs[0], &x)
 
        case *syntax.CallStmt:
-               // TODO(gri) get rid of this conversion to string
                kind := "go"
                if s.Tok == syntax.Defer {
                        kind = "defer"
@@ -507,7 +556,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                check.simpleStmt(s.Init)
                var x operand
                check.expr(&x, s.Cond)
-               if x.mode != invalid && !isBoolean(x.typ) {
+               if x.mode != invalid && !allBoolean(x.typ) {
                        check.error(s.Cond, "non-boolean condition in if statement")
                }
                check.stmt(inner, s.Then)
@@ -596,7 +645,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                if s.Cond != nil {
                        var x operand
                        check.expr(&x, s.Cond)
-                       if x.mode != invalid && !isBoolean(x.typ) {
+                       if x.mode != invalid && !allBoolean(x.typ) {
                                check.error(s.Cond, "non-boolean condition in for statement")
                        }
                }
@@ -605,9 +654,6 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                // declaration, but the post statement must not."
                if s, _ := s.Post.(*syntax.AssignStmt); s != nil && s.Op == syntax.Def {
                        // The parser already reported an error.
-                       // Don't call useLHS here because we want to use the lhs in
-                       // this erroneous statement so that we don't get errors about
-                       // these lhs variables being declared but not used.
                        check.use(s.Lhs) // avoid follow-up errors
                }
                check.stmt(inner, s.Body)
@@ -702,7 +748,6 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
                check.errorf(&x, "%s is not an interface type", &x)
                return
        }
-       check.ordinaryType(x.Pos(), xtyp)
 
        check.multipleSwitchDefaults(s.Body)
 
@@ -789,19 +834,28 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
        // determine key/value types
        var key, val Type
        if x.mode != invalid {
-               // Ranging over a type parameter is permitted if it has a structural type.
-               typ := optype(x.typ)
-               if _, ok := typ.(*Chan); ok && sValue != nil {
-                       check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
-                       // ok to continue
+               // Ranging over a type parameter is permitted if it has a single underlying type.
+               var cause string
+               u := structure(x.typ)
+               switch t := u.(type) {
+               case nil:
+                       cause = "type set has no single underlying type"
+               case *Chan:
+                       if sValue != nil {
+                               check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
+                               // ok to continue
+                       }
+                       if t.dir == SendOnly {
+                               cause = "receive from send-only channel"
+                       }
                }
-               var msg string
-               key, val, msg = rangeKeyVal(typ, isVarName(sKey), isVarName(sValue))
-               if key == nil || msg != "" {
-                       if msg != "" {
-                               msg = ": " + msg
+               key, val = rangeKeyVal(u)
+               if key == nil || cause != "" {
+                       if cause == "" {
+                               check.softErrorf(&x, "cannot range over %s", &x)
+                       } else {
+                               check.softErrorf(&x, "cannot range over %s (%s)", &x, cause)
                        }
-                       check.softErrorf(&x, "cannot range over %s%s", &x, msg)
                        // ok to continue
                }
        }
@@ -882,44 +936,23 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
        check.stmt(inner, s.Body)
 }
 
-// isVarName reports whether x is a non-nil, non-blank (_) expression.
-func isVarName(x syntax.Expr) bool {
-       if x == nil {
-               return false
-       }
-       ident, _ := unparen(x).(*syntax.Name)
-       return ident == nil || ident.Value != "_"
-}
-
 // rangeKeyVal returns the key and value type produced by a range clause
-// over an expression of type typ, and possibly an error message. If the
-// range clause is not permitted the returned key is nil or msg is not
-// empty (in that case we still may have a non-nil key type which can be
-// used to reduce the chance for follow-on errors).
-// The wantKey, wantVal, and hasVal flags indicate which of the iteration
-// variables are used or present; this matters if we range over a generic
-// type where not all keys or values are of the same type.
-func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
+// over an expression of type typ. If the range clause is not permitted
+// the results are nil.
+func rangeKeyVal(typ Type) (key, val Type) {
        switch typ := arrayPtrDeref(typ).(type) {
        case *Basic:
                if isString(typ) {
-                       return Typ[Int], universeRune, "" // use 'rune' name
+                       return Typ[Int], universeRune // use 'rune' name
                }
        case *Array:
-               return Typ[Int], typ.elem, ""
+               return Typ[Int], typ.elem
        case *Slice:
-               return Typ[Int], typ.elem, ""
+               return Typ[Int], typ.elem
        case *Map:
-               return typ.key, typ.elem, ""
+               return typ.key, typ.elem
        case *Chan:
-               var msg string
-               if typ.dir == SendOnly {
-                       msg = "receive from send-only channel"
-               }
-               return typ.elem, Typ[Invalid], msg
-       case *top:
-               // we have a type parameter with no structural type
-               return nil, nil, "no structural type"
+               return typ.elem, Typ[Invalid]
        }
-       return nil, nil, ""
+       return
 }
index f0c27c015043975601acf2c023575e6ac0b76ad9..933d7ef947d2b32025ac53019b7414c40b6bbdf5 100644 (file)
@@ -154,7 +154,7 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
                                                check.error(embeddedPos, "embedded field type cannot be a pointer to an interface")
                                        }
                                }
-                       })
+                       }).describef(embeddedPos, "check embedded type %s", embeddedTyp)
                }
        }
 
index ed3fd654a0e0e31ea8091437ed77ab99f0b05f02..269b284ac4566ad2602e5583a50e4b71d6b7696a 100644 (file)
@@ -6,20 +6,17 @@
 
 package types2
 
-import (
-       "bytes"
-       "cmd/compile/internal/syntax"
-)
+import "cmd/compile/internal/syntax"
 
 type substMap map[*TypeParam]Type
 
 // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
 // If targs[i] is nil, tpars[i] is not substituted.
-func makeSubstMap(tpars []*TypeName, targs []Type) substMap {
+func makeSubstMap(tpars []*TypeParam, targs []Type) substMap {
        assert(len(tpars) == len(targs))
        proj := make(substMap, len(tpars))
        for i, tpar := range tpars {
-               proj[tpar.typ.(*TypeParam)] = targs[i]
+               proj[tpar] = targs[i]
        }
        return proj
 }
@@ -35,14 +32,13 @@ func (m substMap) lookup(tpar *TypeParam) Type {
        return tpar
 }
 
-// subst returns the type typ with its type parameters tpars replaced by
-// the corresponding type arguments targs, recursively.
-// subst is functional in the sense that it doesn't modify the incoming
-// type. If a substitution took place, the result type is different from
+// subst returns the type typ with its type parameters tpars replaced by the
+// corresponding type arguments targs, recursively. subst doesn't modify the
+// incoming type. If a substitution took place, the result type is different
 // from the incoming type.
 //
-// If the given typMap is nil and check is non-nil, check.typMap is used.
-func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[string]*Named) Type {
+// If the given context is non-nil, it is used in lieu of check.Config.Context.
+func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, ctxt *Context) Type {
        if smap.empty() {
                return typ
        }
@@ -56,33 +52,20 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[
        }
 
        // general case
-       var subst subster
-       subst.pos = pos
-       subst.smap = smap
-
-       if check != nil {
-               subst.check = check
-               if typMap == nil {
-                       typMap = check.typMap
-               }
-       }
-       if typMap == nil {
-               // If we don't have a *Checker and its global type map,
-               // use a local version. Besides avoiding duplicate work,
-               // the type map prevents infinite recursive substitution
-               // for recursive types (example: type T[P any] *T[P]).
-               typMap = make(map[string]*Named)
+       subst := subster{
+               pos:   pos,
+               smap:  smap,
+               check: check,
+               ctxt:  check.bestContext(ctxt),
        }
-       subst.typMap = typMap
-
        return subst.typ(typ)
 }
 
 type subster struct {
-       pos    syntax.Pos
-       smap   substMap
-       check  *Checker // nil if called via Instantiate
-       typMap map[string]*Named
+       pos   syntax.Pos
+       smap  substMap
+       check *Checker // nil if called via Instantiate
+       ctxt  *Context
 }
 
 func (subst *subster) typ(typ Type) Type {
@@ -91,7 +74,7 @@ func (subst *subster) typ(typ Type) Type {
                // Call typOrNil if it's possible that typ is nil.
                panic("nil typ")
 
-       case *Basic, *top:
+       case *Basic:
                // nothing to do
 
        case *Array:
@@ -129,8 +112,7 @@ func (subst *subster) typ(typ Type) Type {
                if recv != t.recv || params != t.params || results != t.results {
                        return &Signature{
                                rparams: t.rparams,
-                               // TODO(gri) Why can't we nil out tparams here, rather than in
-                               //           instantiate above?
+                               // TODO(gri) why can't we nil out tparams here, rather than in instantiate?
                                tparams:  t.tparams,
                                scope:    t.scope,
                                recv:     recv,
@@ -183,27 +165,35 @@ func (subst *subster) typ(typ Type) Type {
                        }
                }
 
-               if t.TParams().Len() == 0 {
+               // subst is called by expandNamed, so in this function we need to be
+               // careful not to call any methods that would cause t to be expanded: doing
+               // so would result in deadlock.
+               //
+               // So we call t.orig.TypeParams() rather than t.TypeParams() here and
+               // below.
+               if t.orig.TypeParams().Len() == 0 {
                        dump(">>> %s is not parameterized", t)
                        return t // type is not parameterized
                }
 
                var newTArgs []Type
-               assert(len(t.targs) == t.TParams().Len())
+               if t.targs.Len() != t.orig.TypeParams().Len() {
+                       return Typ[Invalid] // error reported elsewhere
+               }
 
                // already instantiated
                dump(">>> %s already instantiated", t)
                // For each (existing) type argument targ, determine if it needs
                // to be substituted; i.e., if it is or contains a type parameter
                // that has a type argument for it.
-               for i, targ := range t.targs {
+               for i, targ := range t.targs.list() {
                        dump(">>> %d targ = %s", i, targ)
                        new_targ := subst.typ(targ)
                        if new_targ != targ {
                                dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
                                if newTArgs == nil {
-                                       newTArgs = make([]Type, t.TParams().Len())
-                                       copy(newTArgs, t.targs)
+                                       newTArgs = make([]Type, t.orig.TypeParams().Len())
+                                       copy(newTArgs, t.targs.list())
                                }
                                newTArgs[i] = new_targ
                        }
@@ -215,29 +205,25 @@ func (subst *subster) typ(typ Type) Type {
                }
 
                // before creating a new named type, check if we have this one already
-               h := instantiatedHash(t, newTArgs)
+               h := subst.ctxt.TypeHash(t.orig, newTArgs)
                dump(">>> new type hash: %s", h)
-               if named, found := subst.typMap[h]; found {
+               if named := subst.ctxt.typeForHash(h, nil); named != nil {
                        dump(">>> found %s", named)
                        return named
                }
 
-               // create a new named type and populate typMap to avoid endless recursion
-               tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
-               t.load()
-               named := subst.check.newNamed(tname, t.orig, t.underlying, t.TParams(), t.methods) // method signatures are updated lazily
-               named.targs = newTArgs
-               subst.typMap[h] = named
-               t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion
-
-               // do the substitution
-               dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTArgs)
-               named.underlying = subst.typOrNil(t.underlying)
-               dump(">>> underlying: %v", named.underlying)
-               assert(named.underlying != nil)
-               named.fromRHS = named.underlying // for cycle detection (Checker.validType)
+               // Create a new instance and populate the context to avoid endless
+               // recursion. The position used here is irrelevant because validation only
+               // occurs on t (we don't call validType on named), but we use subst.pos to
+               // help with debugging.
+               t.orig.resolve(subst.ctxt)
+               return subst.check.instance(subst.pos, t.orig, newTArgs, subst.ctxt)
 
-               return named
+               // Note that if we were to expose substitution more generally (not just in
+               // the context of a declaration), we'd have to substitute in
+               // named.underlying as well.
+               //
+               // But this is unnecessary for now.
 
        case *TypeParam:
                return subst.smap.lookup(t)
@@ -249,40 +235,6 @@ func (subst *subster) typ(typ Type) Type {
        return typ
 }
 
-var instanceHashing = 0
-
-func instantiatedHash(typ *Named, targs []Type) string {
-       assert(instanceHashing == 0)
-       instanceHashing++
-       var buf bytes.Buffer
-       writeTypeName(&buf, typ.obj, nil)
-       buf.WriteByte('[')
-       writeTypeList(&buf, targs, nil, nil)
-       buf.WriteByte(']')
-       instanceHashing--
-
-       // With respect to the represented type, whether a
-       // type is fully expanded or stored as instance
-       // does not matter - they are the same types.
-       // Remove the instanceMarkers printed for instances.
-       res := buf.Bytes()
-       i := 0
-       for _, b := range res {
-               if b != instanceMarker {
-                       res[i] = b
-                       i++
-               }
-       }
-
-       return string(res[:i])
-}
-
-func typeListString(list []Type) string {
-       var buf bytes.Buffer
-       writeTypeList(&buf, list, nil, nil)
-       return buf.String()
-}
-
 // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
 // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
 // where an array/slice element is accessed before it is set up.
index 378ba6b8f4c024d02f18f090526899e720017c9b..844e39e3bf4ae275c76cb98eef96fbff35cb17c1 100644 (file)
@@ -93,8 +93,8 @@ func (xl termlist) norm() termlist {
 }
 
 // If the type set represented by xl is specified by a single (non-𝓤) term,
-// structuralType returns that type. Otherwise it returns nil.
-func (xl termlist) structuralType() Type {
+// singleType returns that type. Otherwise it returns nil.
+func (xl termlist) singleType() Type {
        if nl := xl.norm(); len(nl) == 1 {
                return nl[0].typ // if nl.isAll() then typ is nil, which is ok
        }
index 2f3772ddeb80f9875f296c6d0df79f0f90b9befe..1bdf9e13860abc413aa7af9961449b4abe2e1643 100644 (file)
@@ -11,7 +11,7 @@ import (
 
 // maketl makes a term list from a string of the term list.
 func maketl(s string) termlist {
-       s = strings.Replace(s, " ", "", -1)
+       s = strings.ReplaceAll(s, " ", "")
        names := strings.Split(s, "∪")
        r := make(termlist, len(names))
        for i, n := range names {
@@ -20,7 +20,7 @@ func maketl(s string) termlist {
        return r
 }
 
-func TestTermlistTop(t *testing.T) {
+func TestTermlistAll(t *testing.T) {
        if !allTermlist.isAll() {
                t.Errorf("allTermlist is not the set of all types")
        }
@@ -106,7 +106,7 @@ func TestTermlistNorm(t *testing.T) {
        }
 }
 
-func TestTermlistStructuralType(t *testing.T) {
+func TestTermlistSingleType(t *testing.T) {
        // helper to deal with nil types
        tstring := func(typ Type) string {
                if typ == nil {
@@ -128,9 +128,9 @@ func TestTermlistStructuralType(t *testing.T) {
                "∅ ∪ ~int ∪ string": "nil",
        } {
                xl := maketl(test)
-               got := tstring(xl.structuralType())
+               got := tstring(xl.singleType())
                if got != want {
-                       t.Errorf("(%v).structuralType() == %v; want %v", test, got, want)
+                       t.Errorf("(%v).singleType() == %v; want %v", test, got, want)
                }
        }
 }
index 0cfea93bf6d500a9a7883ed3baffd04fc702e9e0..d1067a190f8cdc7ba56f07367c2c172b8a27d445 100644 (file)
@@ -45,6 +45,49 @@ func _[T C5[X], X any](ch T) {
        close(ch)
 }
 
+// copy
+
+func _[T any](x, y T) {
+       copy(x /* ERROR copy expects slice arguments */ , y)
+}
+
+func _[T ~[]byte](x, y T) {
+       copy(x, y)
+       copy(x, "foo")
+       copy("foo" /* ERROR expects slice arguments */ , y)
+
+       var x2 []byte
+       copy(x2, y) // element types are identical
+       copy(y, x2) // element types are identical
+
+       type myByte byte
+       var x3 []myByte
+       copy(x3 /* ERROR different element types */ , y)
+       copy(y, x3 /* ERROR different element types */ )
+}
+
+func _[T ~[]E, E any](x T, y []E) {
+       copy(x, y)
+       copy(x /* ERROR different element types */ , "foo")
+}
+
+func _[T ~string](x []byte, y T) {
+       copy(x, y)
+       copy(y /* ERROR expects slice arguments */ , x)
+}
+
+func _[T ~[]byte|~string](x T, y []byte) {
+       copy(x /* ERROR expects slice arguments */ , y)
+       copy(y, x)
+}
+
+type L0 []int
+type L1 []int
+
+func _[T L0 | L1](x, y T) {
+       copy(x, y)
+}
+
 // delete
 
 type M0 interface{ int }
@@ -84,15 +127,18 @@ func _[T M4[K, V], K comparable, V any](m T) {
 
 // make
 
+type myChan chan int
+
 func _[
-       S1 interface{ []int },
-       S2 interface{ []int | chan int },
+       S1 ~[]int,
+       S2 ~[]int | ~chan int,
 
-       M1 interface{ map[string]int },
-       M2 interface{ map[string]int | chan int },
+       M1 ~map[string]int,
+       M2 ~map[string]int | ~chan int,
 
-       C1 interface{ chan int },
-       C2 interface{ chan int | chan string },
+       C1 ~chan int,
+       C2 ~chan int | ~chan string,
+       C3 chan int | myChan, // single underlying type
 ]() {
        type S0 []int
        _ = make([]int, 10)
@@ -102,7 +148,7 @@ func _[
        _ = make /* ERROR expects 2 or 3 arguments */ (S1)
        _ = make(S1, 10, 20)
        _ = make /* ERROR expects 2 or 3 arguments */ (S1, 10, 20, 30)
-       _ = make(S2 /* ERROR cannot make .* no structural type */ , 10)
+       _ = make(S2 /* ERROR cannot make .* no single underlying type */ , 10)
 
        type M0 map[string]int
        _ = make(map[string]int)
@@ -110,7 +156,7 @@ func _[
        _ = make(M1)
        _ = make(M1, 10)
        _ = make/* ERROR expects 1 or 2 arguments */(M1, 10, 20)
-       _ = make(M2 /* ERROR cannot make .* no structural type */ )
+       _ = make(M2 /* ERROR cannot make .* no single underlying type */ )
 
        type C0 chan int
        _ = make(chan int)
@@ -118,7 +164,8 @@ func _[
        _ = make(C1)
        _ = make(C1, 10)
        _ = make/* ERROR expects 1 or 2 arguments */(C1, 10, 20)
-       _ = make(C2 /* ERROR cannot make .* no structural type */ )
+       _ = make(C2 /* ERROR cannot make .* no single underlying type */ )
+       _ = make(C3)
 }
 
 // unsafe.Alignof
diff --git a/src/cmd/compile/internal/types2/testdata/check/compliterals.go2 b/src/cmd/compile/internal/types2/testdata/check/compliterals.go2
new file mode 100644 (file)
index 0000000..60eac97
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// Composite literals with parameterized types
+
+package comp_literals
+
+type myStruct struct {
+       f int
+}
+
+type slice[E any] []E
+
+func struct_literals[S struct{f int}|myStruct]() {
+       _ = S{}
+       _ = S{0}
+       _ = S{f: 0}
+
+        _ = slice[int]{1, 2, 3}
+        _ = slice[S]{{}, {0}, {f:0}}
+}
index f051a4f2acb812bd511661ee35a90a4c0f8f69c9..09e5d5c5ad84355af0bdea8552b1de283b5cf256 100644 (file)
@@ -146,7 +146,7 @@ type (
                m1(I5)
        }
        I6 interface {
-               S0 /* ERROR "not an interface" */
+               S0 /* ERROR "non-interface type S0" */
        }
        I7 interface {
                I1
index f9726b5de53202c301757e36ea5bde812cd3db24..8e5862319e650b9dc3afbae66435516471bfaef1 100644 (file)
@@ -29,7 +29,7 @@ func arrays() {
        _ = a == b
        _ = a != b
        _ = a /* ERROR < not defined */ < b
-       _ = a == nil /* ERROR cannot convert */
+       _ = a == nil /* ERROR invalid operation.*mismatched types */
 
        type C [10]int
        var c C
@@ -53,7 +53,7 @@ func structs() {
        _ = s == t
        _ = s != t
        _ = s /* ERROR < not defined */ < t
-       _ = s == nil /* ERROR cannot convert */
+       _ = s == nil /* ERROR invalid operation.*mismatched types */
 
        type S struct {
                x int
index fd28421dc89bebb56bd26d3dbafeee77613ba768..df4cf6a840dff3879a22db9799e52cc1d06fcd3c 100644 (file)
@@ -459,9 +459,9 @@ func type_asserts() {
 
        var t I
        _ = t /* ERROR "use of .* outside type switch" */ .(type)
-       _ = t /* ERROR "missing method m" */ .(T)
+       _ = t /* ERROR "m method has pointer receiver" */ .(T)
        _ = t.(*T)
-       _ = t /* ERROR "missing method m" */ .(T1)
+       _ = t /* ERROR "missing m method" */ .(T1)
        _ = t /* ERROR "wrong type for method m" */ .(T2)
        _ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
 
similarity index 75%
rename from src/cmd/compile/internal/types2/testdata/check/tinference.go2
rename to src/cmd/compile/internal/types2/testdata/check/funcinference.go2
index 0afb77c1e41cfdbc5f6273fa8cf35cf4581a9823..7160e18b19c51cc717c287efbc98ed88cabf1df6 100644 (file)
@@ -2,26 +2,25 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package tinferenceB
+package funcInference
 
 import "strconv"
 
 type any interface{}
 
-// Embedding stand-alone type parameters is not permitted for now. Disabled.
-// func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D)
-// func _() {
-//     f := f0[string]
-//     f("a", "b", "c", "d")
-//     f0("a", "b", "c", "d")
-// }
-// 
-// func f1[A any, B interface{~A}](A, B)
-// func _() {
-//     f := f1[int]
-//     f(int(0), int(0))
-//     f1(int(0), int(0))
-// }
+func f0[A any, B interface{~*C}, C interface{~*D}, D interface{~*A}](A, B, C, D) {}
+func _() {
+       f := f0[string]
+       f("a", nil, nil, nil)
+       f0("a", nil, nil, nil)
+}
+
+func f1[A any, B interface{~*A}](A, B) {}
+func _() {
+       f := f1[int]
+       f(int(0), new(int))
+       f1(int(0), new(int))
+}
 
 func f2[A any, B interface{~[]A}](A, B) {}
 func _() {
@@ -60,9 +59,7 @@ func _() {
        var _ string = x
 }
 
-// TODO(gri) Need to flag invalid recursive constraints. At the
-// moment these cause infinite recursions and stack overflow.
-// func f7[A interface{type B}, B interface{~A}]()
+func f7[A interface{*B}, B interface{~*A}]() {}
 
 // More realistic examples
 
index effc2db7ae3d1e47e314b85969b24c23edef8bae..8608473135a937cb35394c9c5bc9b9a8e7016a30 100644 (file)
@@ -145,8 +145,8 @@ type List3[TElem any] struct {
 }
 
 // Infinite generic type declarations must lead to an error.
-type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] }
-type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] }
+type inf1 /* ERROR illegal cycle */ [T any] struct{ _ inf1[T] }
+type inf2 /* ERROR illegal cycle */ [T any] struct{ inf2[T] }
 
 // The implementation of conversions T(x) between integers and floating-point
 // numbers checks that both T and x have either integer or floating-point
@@ -223,6 +223,13 @@ func _[T interface{ ~func() }](f T) {
        go f()
 }
 
+type F1 func()
+type F2 func()
+func _[T interface{ func()|F1|F2 }](f T) {
+       f()
+       go f()
+}
+
 // We must compare against the underlying type of type list entries
 // when checking if a constraint is satisfied by a type. The under-
 // lying type of each type list entry must be computed after the
index 692ed37ef4b9e881f788155fbd1f030201952564..dfd51006b9ca0ce91d2e6ea92f4ea98af9bc554b 100644 (file)
@@ -79,11 +79,11 @@ func issue9473(a []int, b ...int) {
 // Check that embedding a non-interface type in an interface results in a good error message.
 func issue10979() {
        type _ interface {
-               int /* ERROR int is not an interface */
+               int /* ERROR non-interface type int */
        }
        type T struct{}
        type _ interface {
-               T /* ERROR T is not an interface */
+               T /* ERROR non-interface type T */
        }
        type _ interface {
                nosuchtype /* ERROR undeclared name: nosuchtype */
@@ -132,12 +132,12 @@ func issue10260() {
 
        var x I1
        x = T1 /* ERROR cannot use .*: missing method foo \(foo has pointer receiver\) */ {}
-       _ = x /* ERROR .* cannot have dynamic type T1 \(missing method foo \(foo has pointer receiver\)\) */ .(T1)
+       _ = x. /* ERROR impossible type assertion: x.\(T1\)\n\tT1 does not implement I1 \(foo method has pointer receiver\) */ (T1)
 
        T1{}.foo /* ERROR cannot call pointer method foo on T1 */ ()
        x.Foo /* ERROR "x.Foo undefined \(type I1 has no field or method Foo, but does have foo\)" */ ()
 
-       _ = i2 /* ERROR i2 .* cannot have dynamic type \*T1 \(wrong type for method foo \(have func\(\), want func\(x int\)\)\) */ .(*T1)
+       _ = i2. /* ERROR impossible type assertion: i2.\(\*T1\)\n\t\*T1 does not implement I2 \(wrong type for method foo: have func\(\), want func\(x int\)\) */ (*T1)
 
        i1 = i0 /* ERROR cannot use .* missing method foo */
        i1 = t0 /* ERROR cannot use .* missing method foo */
@@ -280,7 +280,7 @@ type issue25301b /* ERROR cycle */ = interface {
 }
 
 type issue25301c interface {
-       notE // ERROR struct\{\} is not an interface
+       notE // ERROR non-interface type struct\{\}
 }
 
 type notE = struct{}
index efc090a1d1f0b788dd8977cf551ed2d77a40a108..f02e773dbeeeebbafde08ab38ac4cef93f11897a 100644 (file)
@@ -4,8 +4,6 @@
 
 package linalg
 
-import "math"
-
 // Numeric is type bound that matches any numeric type.
 // It would likely be in a constraints package in the standard library.
 type Numeric interface {
@@ -52,32 +50,33 @@ type Complex interface {
        ~complex64 | ~complex128
 }
 
-// OrderedAbs is a helper type that defines an Abs method for
-// ordered numeric types.
-type OrderedAbs[T OrderedNumeric] T
-
-func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
-       if a < 0 {
-               return -a
-       }
-       return a
-}
-
-// ComplexAbs is a helper type that defines an Abs method for
-// complex types.
-type ComplexAbs[T Complex] T
-
-func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
-       r := float64(real(a))
-       i := float64(imag(a))
-       d := math.Sqrt(r * r + i * i)
-       return ComplexAbs[T](complex(d, 0))
-}
-
-func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
-       return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
-}
-
-func ComplexAbsDifference[T Complex](a, b T) T {
-       return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // OrderedAbs is a helper type that defines an Abs method for
+// // ordered numeric types.
+// type OrderedAbs[T OrderedNumeric] T
+// 
+// func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+//     if a < 0 {
+//             return -a
+//     }
+//     return a
+// }
+// 
+// // ComplexAbs is a helper type that defines an Abs method for
+// // complex types.
+// type ComplexAbs[T Complex] T
+// 
+// func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+//     r := float64(real(a))
+//     i := float64(imag(a))
+//     d := math.Sqrt(r * r + i * i)
+//     return ComplexAbs[T](complex(d, 0))
+// }
+// 
+// func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+//     return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+// }
+// 
+// func ComplexAbsDifference[T Complex](a, b T) T {
+//     return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+// }
index b7ddeaa1a881b0ec79ac318ff474819fd61ecf3e..395e3bfec8076e3eeaf09c7ddebb475d9b69dcc2 100644 (file)
@@ -4,4 +4,4 @@
 
 package main
 
-func /* ERROR "func main must have no type parameters" */ main[T any]() {}
+func main [T /* ERROR "func main must have no type parameters" */ any]() {}
index d744f2ba814d593f0df5fb200b069bef1ab45cae..5ec37b4ace1ea0f3360e3def73ed2a35d54c144f 100644 (file)
@@ -715,7 +715,7 @@ func typeswitches() {
        var t I
        switch t.(type) {
        case T:
-       case T1 /* ERROR "missing method m" */ :
+       case T1 /* ERROR "missing m method" */ :
        case T2 /* ERROR "wrong type for method m" */ :
        case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
        }
diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinference.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinference.go2
new file mode 100644 (file)
index 0000000..8876cca
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2021 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 typeInference
+
+// basic inference
+type Tb[P ~*Q, Q any] int
+func _() {
+       var x Tb[*int]
+       var y Tb[*int, int]
+       x = y
+       _ = x
+}
+
+// recursive inference
+type Tr[A any, B ~*C, C ~*D, D ~*A] int
+func _() {
+       var x Tr[string]
+       var y Tr[string, ***string, **string, *string]
+       var z Tr[int, ***int, **int, *int]
+       x = y
+       x = z // ERROR cannot use z .* as Tr
+       _ = x
+}
+
+// other patterns of inference
+type To0[A any, B ~[]A] int
+type To1[A any, B ~struct{a A}] int
+type To2[A any, B ~[][]A] int
+type To3[A any, B ~[3]*A] int
+type To4[A any, B any, C ~struct{a A; b B}] int
+func _() {
+       var _ To0[int]
+       var _ To1[int]
+       var _ To2[int]
+       var _ To3[int]
+       var _ To4[int, string]
+}
+
+// failed inference
+type Tf0[A, B any] int
+type Tf1[A any, B ~struct{a A; c C}, C any] int
+func _() {
+       var _ Tf0 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int]
+       var _ Tf1 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 3 type parameters */ [int]
+}
index 0d628cb9d06996e1dd35418e328829119508a72a..a3d1b5e28fb52945b455c6b9f3267b4557b04fb7 100644 (file)
@@ -8,7 +8,8 @@ type myInt int
 
 // Parameterized type declarations
 
-type T1[P any] P
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+type T1[P any] P // ERROR cannot use a type parameter as RHS in type declaration
 
 type T2[P any] struct {
         f P
@@ -17,13 +18,15 @@ type T2[P any] struct {
 
 type List[P any] []P
 
-// Alias type declarations cannot have type parameters. Syntax error.
-type A1[P any] = /* ERROR cannot be alias */ P
+// Alias type declarations cannot have type parameters.
+// Issue #46477 proposses to change that.
+type A1[P any] = /* ERROR cannot be alias */ struct{}
 
-// But an alias may refer to a generic, uninstantiated type.
-type A2 = List
+// Pending clarification of #46477 we disallow aliases
+// of generic types.
+type A2 = List // ERROR cannot use generic type
 var _ A2[int]
-var _ A2 /* ERROR without instantiation */
+var _ A2
 
 type A3 = List[int]
 var _ A3
@@ -55,5 +58,5 @@ var _ T3[int] = T3[int](List[int]{1, 2, 3})
 
 // Self-recursive generic types are not permitted
 
-type self1[P any] self1 /* ERROR illegal cycle */ [P]
+type self1 /* ERROR illegal cycle */ [P any] self1[P]
 type self2[P any] *self2[P] // this is ok
index d087c26a47e637836a8cc56308dfb53e7314bf1f..cd56c81bb93f6bcd4633050b0785b207b9a28c83 100644 (file)
@@ -87,25 +87,27 @@ type NumericAbs[T any] interface {
 
 func AbsDifference[T NumericAbs[T]](x T) { panic(0) }
 
-type OrderedAbs[T any] T
-
-func (a OrderedAbs[T]) Abs() OrderedAbs[T]
-
-func OrderedAbsDifference[T any](x T) {
-       AbsDifference(OrderedAbs[T](x))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type OrderedAbs[T any] T
+// 
+// func (a OrderedAbs[T]) Abs() OrderedAbs[T]
+// 
+// func OrderedAbsDifference[T any](x T) {
+//     AbsDifference(OrderedAbs[T](x))
+// }
 
 // same code, reduced to essence
 
 func g[P interface{ m() P }](x P) { panic(0) }
 
-type T4[P any] P
-
-func (_ T4[P]) m() T4[P]
-
-func _[Q any](x Q) {
-       g(T4[Q](x))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type T4[P any] P
+// 
+// func (_ T4[P]) m() T4[P]
+// 
+// func _[Q any](x Q) {
+//     g(T4[Q](x))
+// }
 
 // Another test case that caused  problems in the past
 
@@ -159,10 +161,7 @@ type _ interface {
        ~rune
 }
 
-// Interface type lists may contain each type at most once.
-// (If there are multiple lists, we assume the author intended
-// for them to be all in a single list, and we report the error
-// as well.)
+// Type sets may contain each type at most once.
 type _ interface {
        ~int|~int /* ERROR overlapping terms ~int */
        ~int|int /* ERROR overlapping terms int */
@@ -173,7 +172,7 @@ type _ interface {
        ~struct{f int} | ~struct{g int} | ~struct /* ERROR overlapping terms */ {f int}
 }
 
-// Interface type lists can contain any type, incl. *Named types.
+// Interface term lists can contain any type, incl. *Named types.
 // Verify that we use the underlying type to compute the operational type.
 type MyInt int
 func add1[T interface{MyInt}](x T) T {
@@ -185,9 +184,9 @@ func double[T interface{MyInt|MyString}](x T) T {
        return x + x
 }
 
-// Embedding of interfaces with type lists leads to interfaces
-// with type lists that are the intersection of the embedded
-// type lists.
+// Embedding of interfaces with term lists leads to interfaces
+// with term lists that are the intersection of the embedded
+// term lists.
 
 type E0 interface {
        ~int | ~bool | ~string
@@ -229,10 +228,10 @@ type I012 interface {
 }
 
 func f012[T I012]() {}
-var _ = f012[int /* ERROR does not satisfy I012 */ ]
-var _ = f012[bool /* ERROR does not satisfy I012 */ ]
-var _ = f012[string /* ERROR does not satisfy I012 */ ]
-var _ = f012[float64 /* ERROR does not satisfy I012 */ ]
+var _ = f012[int /* ERROR does not satisfy I012.*type set is empty */ ]
+var _ = f012[bool /* ERROR does not satisfy I012.*type set is empty */ ]
+var _ = f012[string /* ERROR does not satisfy I012.*type set is empty */ ]
+var _ = f012[float64 /* ERROR does not satisfy I012.*type set is empty */ ]
 
 type I12 interface {
        E1
@@ -255,3 +254,27 @@ var _ = f0_[int]
 var _ = f0_[bool /* ERROR does not satisfy I0_ */ ]
 var _ = f0_[string /* ERROR does not satisfy I0_ */ ]
 var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ]
+
+// Using a function instance as a type is an error.
+var _ f0 // ERROR not a type
+var _ f0 /* ERROR not a type */ [int]
+
+// Empty type sets can only be satisfied by empty type sets.
+type none interface {
+       // force an empty type set
+        int
+        string
+}
+
+func ff[T none]() {}
+func gg[T any]() {}
+func hh[T ~int]() {}
+
+func _[T none]() {
+        _ = ff[int /* ERROR int does not satisfy none \(constraint type set is empty\) */ ]
+        _ = ff[T]  // pathological but ok because T's type set is empty, too
+        _ = gg[int]
+        _ = gg[T]
+       _ = hh[int]
+       _ = hh[T]
+}
diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go2
new file mode 100644 (file)
index 0000000..74fe191
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "unsafe"
+
+func F1[T any](_ [unsafe.Sizeof(F1[int])]T) (res T)      { return }
+func F2[T any](_ T) (res [unsafe.Sizeof(F2[string])]int) { return }
+func F3[T any](_ [unsafe.Sizeof(F1[string])]int)         {}
index 1ad80b1e1b90fc98d343597771d7d8f9e0e30f3d..a1bf6c262f4ce105d36cd0172f96ec46558be14c 100644 (file)
@@ -6,11 +6,9 @@ package p
 
 // import "io" // for type assertion tests
 
-// The predeclared identifier "any" can only be used as a constraint
-// in a type parameter list.
-var _ any // ERROR cannot use any outside constraint position
-func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) {
-        var _ any /* ERROR constraint */
+var _ any // ok to use any anywhere
+func _[_ any, _ interface{any}](any) {
+        var _ any
 }
 
 func identity[T any](x T) T { return x }
@@ -116,10 +114,27 @@ func _[T interface{ [10]int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERR
 func _[T interface{ [10]byte | string }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
 func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
 
+// indexing with strings and non-variable arrays (assignment not permitted)
+func _[T string](x T) { _ = x[0]; x /* ERROR cannot assign */ [0] = 0 }
+func _[T []byte | string](x T) { x /* ERROR cannot assign */ [0] = 0 }
+func _[T [10]byte]() { f := func() (x T) { return }; f /* ERROR cannot assign */ ()[0] = 0 }
+func _[T [10]byte]() { f := func() (x *T) { return }; f /* ERROR cannot index */ ()[0] = 0 }
+func _[T [10]byte]() { f := func() (x *T) { return }; (*f())[0] = 0 }
+func _[T *[10]byte]() { f := func() (x T) { return }; f()[0] = 0 }
+
 // slicing
-// TODO(gri) implement this
 
-func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR generic slice expressions not yet implemented */ [i:j:k] }
+func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j] }
+func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j:k] }
+func _[T interface{ ~[]byte }] (x T, i, j, k int) { var _ T = x[i:j] }
+func _[T interface{ ~[]byte }] (x T, i, j, k int) { var _ T = x[i:j:k] }
+func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x[i:j] }
+func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x /* ERROR 3-index slice of string */ [i:j:k] }
+
+type myByte1 []byte
+type myByte2 []byte
+func _[T interface{ []byte | myByte1 | myByte2 }] (x T, i, j, k int) { var _ T = x[i:j:k] }
+func _[T interface{ []byte | myByte1 | []int }] (x T, i, j, k int) { var _ T = x[ /* ERROR no single underlying type */ i:j:k] }
 
 // len/cap built-ins
 
@@ -182,7 +197,7 @@ func _[
         for _, _ = range b1 {}
 
         var b2 B2
-        for range b2 /* ERROR cannot range over b2 .* no structural type */ {}
+        for range b2 {}
 
         var c0 chan int
         for range c0 {}
@@ -195,7 +210,7 @@ func _[
         for _, _ /* ERROR permits only one iteration variable */ = range c1 {}
 
         var c2 C2
-        for range c2 /* ERROR cannot range over c2 .* no structural type */ {}
+        for range c2 /* ERROR cannot range over c2.*no single underlying type */ {}
 
         var c3 C3
         for range c3 /* ERROR receive from send-only channel */ {}
@@ -211,7 +226,7 @@ func _[
         for _, _ = range s1 {}
 
         var s2 S2
-        for range s2 /* ERROR cannot range over s2 .* no structural type */ {}
+        for range s2 /* ERROR cannot range over s2.*no single underlying type */ {}
 
         var a0 []int
         for range a0 {}
@@ -224,7 +239,7 @@ func _[
         for _, _ = range a1 {}
 
         var a2 A2
-        for range a2 /* ERROR cannot range over a2 .* no structural type */ {}
+        for range a2 /* ERROR cannot range over a2.*no single underlying type */ {}
 
         var p0 *[10]int
         for range p0 {}
@@ -237,7 +252,7 @@ func _[
         for _, _ = range p1 {}
 
         var p2 P2
-        for range p2 /* ERROR cannot range over p2 .* no structural type */ {}
+        for range p2 /* ERROR cannot range over p2.*no single underlying type */ {}
 
         var m0 map[string]int
         for range m0 {}
@@ -250,7 +265,7 @@ func _[
         for _, _ = range m1 {}
 
         var m2 M2
-        for range m2 /* ERROR cannot range over m2 .* no structural type */ {}
+        for range m2 /* ERROR cannot range over m2.*no single underlying type */ {}
 }
 
 // type inference checks
@@ -304,8 +319,8 @@ var _ = f8[int, float64](0, 0, nil...) // test case for #18268
 // init functions cannot have type parameters
 
 func init() {}
-func init[/* ERROR func init must have no type parameters */ _ any]() {}
-func init[/* ERROR func init must have no type parameters */ P any]() {}
+func init[_ /* ERROR func init must have no type parameters */ any]() {}
+func init[P /* ERROR func init must have no type parameters */ any]() {}
 
 type T struct {}
 
@@ -346,15 +361,16 @@ func _() {
 
 // the previous example was extracted from
 
-func f12[T interface{m() T}]() {}
-
-type A[T any] T
-
-func (a A[T]) m() A[T]
-
-func _[T any]() {
-       f12[A[T]]()
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// func f12[T interface{m() T}]() {}
+// 
+// type A[T any] T
+// 
+// func (a A[T]) m() A[T]
+// 
+// func _[T any]() {
+//     f12[A[T]]()
+// }
 
 // method expressions
 
index f40d18c63e8786bf57e427c7d483868bfdb81c6d..4d7f70313a20ae48cf0afea39d9efe88c4f1f4dc 100644 (file)
@@ -6,18 +6,6 @@
 
 package p
 
-type (
-       // Type lists are processed as unions but an error is reported.
-       // TODO(gri) remove this once the parser doesn't accept type lists anymore.
-       _ interface{
-               type /* ERROR use generalized embedding syntax instead of a type list */ int
-       }
-       _ interface{
-               type /* ERROR use generalized embedding syntax instead of a type list */ int
-               type float32
-       }
-)
-
 type MyInt int
 
 type (
@@ -33,20 +21,20 @@ type (
        _ interface{int|~ /* ERROR overlapping terms ~int */ int }
        _ interface{~int|~ /* ERROR overlapping terms ~int */ int }
        _ interface{~int|MyInt /* ERROR overlapping terms p.MyInt and ~int */ }
-       _ interface{int|interface{}}
+       _ interface{int|any}
        _ interface{int|~string|union}
        _ interface{int|~string|interface{int}}
        _ interface{union|union /* ERROR overlapping terms p.union and p.union */ }
 
        // For now we do not permit interfaces with methods in unions.
-       _ interface{~ /* ERROR invalid use of ~ */ interface{}}
+       _ interface{~ /* ERROR invalid use of ~ */ any}
        _ interface{int|interface /* ERROR cannot use .* in union */ { m() }}
 )
 
 type (
        // Tilde is not permitted on defined types or interfaces.
        foo int
-       bar interface{}
+       bar any
        _ interface{foo}
        _ interface{~ /* ERROR invalid use of ~ */ foo }
        _ interface{~ /* ERROR invalid use of ~ */ bar }
index e169aec74660bad3c4c3719ac8d07d2fe37e0872..4eb18eb239ec0ad4be5895c95818d0f95111893e 100644 (file)
@@ -99,3 +99,26 @@ func _() {
        related2(1.0, []int{})
        related2( /* ERROR does not satisfy */ float64(1.0), []int{}) // TODO(gri) fix error position
 }
+
+type List[P any] []P
+
+func related3[Elem any, Slice []Elem | List[Elem]]() Slice { return nil }
+
+func _() {
+       // related3 can be instantiated explicitly
+       related3[int, []int]()
+       related3[byte, List[byte]]()
+
+       // Alternatively, the 2nd type argument can be inferred
+       // from the first one through constraint type inference.
+       related3[int]()
+
+       // The inferred type is the structural type of the Slice
+       // type parameter.
+       var _ []int = related3[int]()
+
+       // It is not the defined parameterized type List.
+       type anotherList []float32
+       var _ anotherList = related3[float32]() // valid
+       var _ anotherList = related3 /* ERROR cannot use .* \(value of type List\[float32\]\) as anotherList */ [float32, List[float32]]()
+}
index 4e87041e54771391056937e8b8e5424df025f5c5..1d76d553dcc44a1b57f2f983edefa404c39ab534 100644 (file)
@@ -6,8 +6,6 @@
 
 package p
 
-import "unsafe"
-
 // Parameterized types may have methods.
 type T1[A any] struct{ a A }
 
@@ -97,17 +95,18 @@ type T0 struct{}
 func (T0) _() {}
 func (T1[A]) _() {}
 
-// A generic receiver type may constrain its type parameter such
-// that it must be a pointer type. Such receiver types are not
-// permitted.
-type T3a[P interface{ ~int | ~string | ~float64 }] P
-
-func (T3a[_]) m() {} // this is ok
-
-type T3b[P interface{ ~unsafe.Pointer }] P
-
-func (T3b /* ERROR invalid receiver */ [_]) m() {}
-
-type T3c[P interface{ *int | *string }] P
-
-func (T3c /* ERROR invalid receiver */ [_]) m() {}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // A generic receiver type may constrain its type parameter such
+// // that it must be a pointer type. Such receiver types are not
+// // permitted.
+// type T3a[P interface{ ~int | ~string | ~float64 }] P
+// 
+// func (T3a[_]) m() {} // this is ok
+// 
+// type T3b[P interface{ ~unsafe.Pointer }] P
+// 
+// func (T3b /* ERROR invalid receiver */ [_]) m() {}
+// 
+// type T3c[P interface{ *int | *string }] P
+// 
+// func (T3c /* ERROR invalid receiver */ [_]) m() {}
index d662444ead817851e3500a16c0105393b0e58be9..077fcfdbb76119caf45f104d6751e648347512b7 100644 (file)
@@ -102,6 +102,7 @@ func _() {
 
 // Generic types cannot be used without instantiation.
 var _ T // ERROR cannot use generic type T
+var _ = T /* ERROR cannot use generic type T */ (0)
 
 // In type context, generic (parameterized) types cannot be parenthesized before
 // being instantiated. See also NOTES entry from 12/4/2019.
@@ -113,7 +114,7 @@ type I1[T any] interface{
 }
 
 // There is no such thing as a variadic generic type.
-type _[T ... /* ERROR invalid use of ... */ interface{}] struct{}
+type _[T ... /* ERROR invalid use of ... */ any] struct{}
 
 // Generic interfaces may be embedded as one would expect.
 type I2 interface {
@@ -184,12 +185,13 @@ type _ struct {
 //     _ = y < 0
 // }
 
-// It is not permitted to declare a local type whose underlying
-// type is a type parameters not declared by that type declaration.
-func _[T any]() {
-       type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
-       type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // It is not permitted to declare a local type whose underlying
+// // type is a type parameter not declared by that type declaration.
+// func _[T any]() {
+//     type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
+//     type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
+// }
 
 // As a special case, an explicit type argument may be omitted
 // from a type parameter bound if the type bound expects exactly
@@ -212,9 +214,9 @@ func Sum[T Adder[T]](list []T) T {
 }
 
 // Valid and invalid variations.
-type B0 interface {}
-type B1[_ any] interface{}
-type B2[_, _ any] interface{}
+type B0 any
+type B1[_ any] any
+type B2[_, _ any] any
 
 func _[T1 B0]() {}
 func _[T1 B1[T1]]() {}
@@ -274,8 +276,8 @@ func _() {
 
 // Type parameters are never const types, i.e., it's
 // not possible to declare a constant of type parameter type.
-// (If a type list contains just a single const type, we could
-// allow it, but such type lists don't make much sense in the
+// (If a type set contains just a single const type, we could
+// allow it, but such type sets don't make much sense in the
 // first place.)
 func _[T interface{~int|~float64}]() {
        // not valid
@@ -287,3 +289,27 @@ func _[T interface{~int|~float64}]() {
        var _ T = 1
        _ = T(0)
 }
+
+// It is possible to create composite literals of type parameter
+// type as long as it's possible to create a composite literal
+// of the structural type of the type parameter's constraint.
+func _[P interface{ ~[]int }]() P {
+       return P{}
+       return P{1, 2, 3}
+}
+
+func _[P interface{ ~[]E }, E interface{ map[string]P } ]() P {
+       x := P{}
+       return P{{}}
+       return P{E{}}
+       return P{E{"foo": x}}
+       return P{{"foo": x}, {}}
+}
+
+// This is a degenerate case with a singleton type set, but we can create
+// composite literals even if the structural type is a defined type.
+type MyInts []int
+
+func _[P MyInts]() P {
+       return P{}
+}
diff --git a/src/cmd/compile/internal/types2/testdata/examples/typesets.go2 b/src/cmd/compile/internal/types2/testdata/examples/typesets.go2
new file mode 100644 (file)
index 0000000..e19dcf8
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file shows some examples of constraint literals with elided interfaces.
+// These examples are permitted if proposal issue #48424 is accepted.
+
+package p
+
+// Constraint type sets of the form T, ~T, or A|B may omit the interface.
+type (
+       _[T int] struct{}
+       _[T ~int] struct{}
+       _[T int|string] struct{}
+       _[T ~int|~string] struct{}
+)
+
+func min[T int|string](x, y T) T {
+       if x < y {
+               return x
+       }
+       return y
+}
+
+func lookup[M ~map[K]V, K comparable, V any](m M, k K) V {
+       return m[k]
+}
+
+func deref[P ~*E, E any](p P) E {
+       return *p
+}
+
+func _() int {
+       p := new(int)
+       return deref(p)
+}
+
+func addrOfCopy[V any, P ~*V](v V) P {
+       return &v
+}
+
+func _() *int {
+       return addrOfCopy(0)
+}
+
+// A type parameter may not be embedded in an interface;
+// so it can also not be used as a constraint.
+func _[A any, B A /* ERROR cannot use a type parameter as constraint */ ]() {}
+func _[A any, B, C A /* ERROR cannot use a type parameter as constraint */ ]() {}
+
+
+// Error messages refer to the type constraint as it appears in the source.
+// (No implicit interface should be exposed.)
+func _[T string](x T) T {
+       return x /* ERROR constrained by string */ * x
+}
+
+func _[T int|string](x T) T {
+       return x /* ERROR constrained by int|string */ * x
+}
index 8d14f8acaf825937d8d77d59533978ddd87f58d9..9a98f7f955e8c24e3e2eaf4d0ead54099a96c51c 100644 (file)
@@ -37,8 +37,8 @@ func main7() { var _ foo7 = x7[int]{} }
 // func main8() {}
 
 // crash 9
-type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] }
-func _() { var _ = new(foo9 /* ERROR illegal cycle */ [int]) }
+type foo9 /* ERROR illegal cycle */ [A any] interface { foo9[A] }
+func _() { var _ = new(foo9[int]) }
 
 // crash 12
 var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len /* ERROR must be called */ /* ERROR must be called */ )]c /* ERROR undeclared */ /* ERROR undeclared */
@@ -74,9 +74,10 @@ func F20[t Z20]() { F20(t /* ERROR invalid composite literal type */ {}) }
 type Z21 /* ERROR illegal cycle */ interface{ Z21 }
 func F21[T Z21]() { ( /* ERROR not used */ F21[Z21]) }
 
-// crash 24
-type T24[P any] P
-func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // crash 24
+// type T24[P any] P
+// func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }
 
 // crash 25
 type T25[A any] int
@@ -85,7 +86,7 @@ var x T25 /* ERROR without instantiation */ .m1
 
 // crash 26
 type T26 = interface{ F26[ /* ERROR cannot have type parameters */ Z any]() }
-func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ }
+func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ [] /* ERROR operand */ }
 
 // crash 27
 func e27[T any]() interface{ x27 /* ERROR not a type */ } { panic(0) }
index 85eb0a78fe284a21b464b612bc7efafa8820b3ed..8f3101235410c091910641c928113718e66d2bc4 100644 (file)
@@ -4,10 +4,10 @@
 
 package p
 
-// Do not report a duplicate type error for this type list.
+// Do not report a duplicate type error for this term list.
 // (Check types after interfaces have been completed.)
 type _ interface {
        // TODO(gri) Once we have full type sets we can enable this again.
-       // Fow now we don't permit interfaces in type lists.
+       // Fow now we don't permit interfaces in term lists.
        // type interface{ Error() string }, interface{ String() string }
 }
index d5311ed3e7538e9350a0df3dc23b137a88503ae4..00885238e69c9a26ce5ef6f44539c0cba86152b1 100644 (file)
@@ -6,4 +6,4 @@ package p
 
 // A constraint must be an interface; it cannot
 // be a type parameter, for instance.
-func _[A interface{ ~int }, B A /* ERROR not an interface */ ]() {}
+func _[A interface{ ~int }, B A /* ERROR cannot use a type parameter as constraint */ ]() {}
index abac141d7f08dd359a26ba18c36b696d7970d40a..696d9d9beef9d2f9961456e1ddf3ed6f31c51889 100644 (file)
@@ -4,17 +4,18 @@
 
 package p
 
-type T[P any] P
-type A = T
-var x A[int]
-var _ A /* ERROR cannot use generic type */
-
-type B = T[int]
-var y B = x
-var _ B /* ERROR not a generic type */ [int]
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type T[P any] P
+// type A = T  // ERROR cannot use generic type
+// var x A[int]
+// var _ A
+//
+// type B = T[int]
+// var y B = x
+// var _ B /* ERROR not a generic type */ [int]
 
 // test case from issue
 
 type Vector[T any] []T
-type VectorAlias = Vector
+type VectorAlias = Vector // ERROR cannot use generic type
 var v Vector[int]
index 0da6e103fd1139b48d6d26e6d9b9ec9cee7ac5db..114646786d5b74324413b74cbbca0c211f3c6cb2 100644 (file)
@@ -3,19 +3,21 @@
 // license that can be found in the LICENSE file.
 
 // Check "infinite expansion" cycle errors across instantiated types.
+// We can't detect these errors anymore at the moment. See #48962 for
+// details.
 
 package p
 
-type E0[P any] P
+type E0[P any] []P
 type E1[P any] *P
 type E2[P any] struct{ _ P }
 type E3[P any] struct{ _ *P }
 
-type T0 /* ERROR illegal cycle */ struct {
+type T0 /* illegal cycle */ struct {
         _ E0[T0]
 }
 
-type T0_ /* ERROR illegal cycle */ struct {
+type T0_ /* illegal cycle */ struct {
         E0[T0_]
 }
 
@@ -23,7 +25,7 @@ type T1 struct {
         _ E1[T1]
 }
 
-type T2 /* ERROR illegal cycle */ struct {
+type T2 /* illegal cycle */ struct {
         _ E2[T2]
 }
 
@@ -33,7 +35,7 @@ type T3 struct {
 
 // some more complex cases
 
-type T4 /* ERROR illegal cycle */ struct {
+type T4 /* illegal cycle */ struct {
        _ E0[E2[T4]]
 }
 
@@ -41,7 +43,7 @@ type T5 struct {
        _ E0[E2[E0[E1[E2[[10]T5]]]]]
 }
 
-type T6 /* ERROR illegal cycle */ struct {
+type T6 /* illegal cycle */ struct {
        _ E0[[10]E2[E0[E2[E2[T6]]]]]
 }
 
index 4642ab60fc8edaf7f78c709459f29b549258e33f..7f55ba85a6b42d4580a030337e5bba3e1da71713 100644 (file)
@@ -6,13 +6,13 @@ package p
 
 // Test case from issue.
 
-type Nat interface {
+type Nat /* ERROR cycle */ interface {
        Zero|Succ
 }
 
 type Zero struct{}
 type Succ struct{
-       Nat // ERROR interface contains type constraints
+       Nat // Nat contains type constraints but is invalid, so no error
 }
 
 // Struct tests.
index bf0031f5d244305720afb8c8d2f2710c5b8bbaf9..dd66e9648b56326f364b4ade15b459a506a5bb9d 100644 (file)
@@ -28,6 +28,6 @@ func _[T constraint](x interface{}){
 }
 
 func _(x constraint /* ERROR contains type constraints */ ) {
-       switch x /* ERROR contains type constraints */ .(type) {
+       switch x.(type) { // no need to report another error
        }
 }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2
new file mode 100644 (file)
index 0000000..e4bcee5
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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
+
+const L = 10
+
+type (
+       _        [L]struct{}
+       _        [A /* ERROR undeclared name A for array length */ ]struct{}
+       _        [B /* ERROR not an expression */ ]struct{}
+       _[A any] struct{}
+
+       B int
+)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go2
new file mode 100644 (file)
index 0000000..c3e9e34
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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 Builder[T interface{ struct{ Builder[T] } }] struct{}
+type myBuilder struct {
+       Builder[myBuilder /* ERROR myBuilder does not satisfy */]
+}
index 441fb4cb346211c684e0a9e51247102b89ed7048..80148fe4819862f4761eb439da062e735204aa20 100644 (file)
@@ -4,9 +4,10 @@
 
 package P
 
-// It is not permitted to declare a local type whose underlying
-// type is a type parameters not declared by that type declaration.
-func _[T any]() {
-       type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
-       type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // It is not permitted to declare a local type whose underlying
+// // type is a type parameters not declared by that type declaration.
+// func _[T any]() {
+//     type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
+//     type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
+// }
index f25b9d2b266c45010da8e8d857ad4e4427bc64d8..9963d2ee003c165774539cca29614f05147908e9 100644 (file)
@@ -5,7 +5,7 @@
 package issue45985
 
 // TODO(gri): this error should be on app[int] below.
-func app[S /* ERROR "type S = S does not match" */ interface{ ~[]T }, T any](s S, e T) S {
+func app[S /* ERROR "S does not match" */ interface{ ~[]T }, T any](s S, e T) S {
     return append(s, e)
 }
 
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2
new file mode 100644 (file)
index 0000000..8bf3109
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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
+
+// test case 1
+type T[U interface{ M() T[U] }] int
+
+type X int
+
+func (X) M() T[X] { return 0 }
+
+// test case 2
+type A[T interface{ A[T] }] interface{}
+
+// test case 3
+type A2[U interface{ A2[U] }] interface{ M() A2[U] }
+
+type I interface{ A2[I]; M() A2[I] }
index 77281a19a2032cf3ac8a250f8a3280fbbca342ef..ccf4bcf782afb93b0e04a313780747ca63ad8fb0 100644 (file)
@@ -19,7 +19,7 @@ func _[P comparable,
         _ = f[R /* ERROR R has no constraints */ ]
 
         _ = g[int]
-        _ = g[P /* ERROR P has no type constraints */ ]
+        _ = g[P /* ERROR P does not satisfy interface{interface{comparable; ~int\|~string} */ ]
         _ = g[Q]
         _ = g[func( /* ERROR does not satisfy comparable */ )]
         _ = g[R /* ERROR R has no constraints */ ]
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2
new file mode 100644 (file)
index 0000000..6a2e787
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2021 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
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type T1[P any] P
+// 
+// func (T1[_]) m() {}
+// 
+// func _[P any](x *T1[P]) {
+//         // x.m exists because x is of type *T1 where T1 is a defined type
+//         // (even though under(T1) is a type parameter)
+//         x.m()
+// }
+
+
+func _[P interface{ m() }](x P) {
+        x.m()
+        // (&x).m doesn't exist because &x is of type *P
+        // and pointers to type parameters don't have methods
+        (&x).m /* ERROR \*P has no field or method m */ ()
+}
+
+
+type T2 interface{ m() }
+
+func _(x *T2) {
+        // x.m doesn't exists because x is of type *T2
+        // and pointers to interfaces don't have methods
+        x.m /* ERROR \*T2 has no field or method m */()
+}
+
+// Test case 1 from issue
+
+type Fooer1[t any] interface {
+       Foo(Barer[t])
+}
+type Barer[t any] interface {
+       Bar(t)
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Foo1[t any] t
+// type Bar[t any] t
+// 
+// func (l Foo1[t]) Foo(v Barer[t]) { v.Bar(t(l)) }
+// func (b *Bar[t]) Bar(l t)        { *b = Bar[t](l) }
+// 
+// func _[t any](f Fooer1[t]) t {
+//     var b Bar[t]
+//     f.Foo(&b)
+//     return t(b)
+// }
+
+// Test case 2 from issue
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Fooer2[t any] interface {
+//     Foo()
+// }
+// 
+// type Foo2[t any] t
+// 
+// func (f *Foo2[t]) Foo() {}
+// 
+// func _[t any](v t) {
+//     var f = Foo2[t](v)
+//     _ = Fooer2[t](&f)
+// }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go2
new file mode 100644 (file)
index 0000000..9c10683
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2021 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
+
+// parameterized types with self-recursive constraints
+type (
+       T1[P T1[P]]                            interface{}
+       T2[P, Q T2[P, Q]]                      interface{}
+       T3[P T2[P, Q], Q interface{ ~string }] interface{}
+
+       T4a[P T4a[P]]                                                        interface{ ~int }
+       T4b[P T4b[int]]                                                      interface{ ~int }
+       T4c[P T4c[string /* ERROR string does not satisfy T4c\[string\] */]] interface{ ~int }
+
+       // mutually recursive constraints
+       T5[P T6[P]] interface{ int }
+       T6[P T5[P]] interface{ int }
+)
+
+// verify that constraints are checked as expected
+var (
+       _ T1[int]
+       _ T2[int, string]
+       _ T3[int, string]
+)
+
+// test case from issue
+
+type Eq[a Eq[a]] interface {
+       Equal(that a) bool
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2
new file mode 100644 (file)
index 0000000..166cc68
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2021 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.
+
+// Parser accepts type parameters but the type checker
+// needs to report any operations that are not permitted
+// before Go 1.18.
+
+package go1_17
+
+type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}
+
+// for init (and main, but we're not in package main) we should only get one error
+func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]()   {}
+func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
+
+func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
+       var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
+       var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
+       _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
+       _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int](struct{}{})
+}
+
+func (T[ /* ERROR type instantiation requires go1\.18 or later */ P]) g(x int) {
+       f[ /* ERROR function instantiation requires go1\.18 or later */ int](0)     // explicit instantiation
+       (f[ /* ERROR function instantiation requires go1\.18 or later */ int])(0)   // parentheses (different code path)
+       f( /* ERROR implicit function instantiation requires go1\.18 or later */ x) // implicit instantiation
+}
+
+type C1 interface {
+       comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+}
+
+type C2 interface {
+       comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+       int        // ERROR embedding non-interface type int requires go1\.18 or later
+       ~ /* ERROR embedding interface element ~int requires go1\.18 or later */ int
+       int /* ERROR embedding interface element int\|~string requires go1\.18 or later */ | ~string
+}
+
+type _ interface {
+       // errors for these were reported with their declaration
+       C1
+       C2
+}
+
+type (
+       _ comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+       // errors for these were reported with their declaration
+       _ C1
+       _ C2
+
+       _ = comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+       // errors for these were reported with their declaration
+       _ = C1
+       _ = C2
+)
+
+// TODO(gri) need test cases for imported constraint types (see also issue #47967)
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2
new file mode 100644 (file)
index 0000000..4c4fc2f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2021 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 Fooer[t any] interface {
+       foo(Barer[t])
+}
+type Barer[t any] interface {
+       bar(Bazer[t])
+}
+type Bazer[t any] interface {
+       Fooer[t]
+       baz(t)
+}
+
+type Int int
+
+func (n Int) baz(int) {}
+func (n Int) foo(b Barer[int]) { b.bar(n) }
+
+type F[t any] interface { f(G[t]) }
+type G[t any] interface { g(H[t]) }
+type H[t any] interface { F[t] }
+
+type T struct{}
+func (n T) f(b G[T]) { b.g(n) }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2
new file mode 100644 (file)
index 0000000..711e50a
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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[P any] struct{}
+
+func (T[P]) m1()
+
+type A1 = T // ERROR cannot use generic type
+
+func (A1[P]) m2() {}
+
+type A2 = T[int]
+
+func (A2 /* ERROR cannot define methods on instantiated type T\[int\] */) m3()   {}
+func (_ /* ERROR cannot define methods on instantiated type T\[int\] */ A2) m4() {}
+
+func (T[int]) m5()                                     {} // int is the type parameter name, not an instantiation
+func (T[* /* ERROR must be an identifier */ int]) m6() {} // syntax error
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
new file mode 100644 (file)
index 0000000..2c4b661
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2021 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
+
+// don't crash
+func T /* ERROR missing */ [P] /* ERROR missing */ m /* ERROR unexpected */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go2
new file mode 100644 (file)
index 0000000..5c97268
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2021 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[P any] struct{}
+
+func _(x interface{}) {
+       switch x.(type) {
+       case nil:
+       case int:
+
+       case T[int]:
+       case []T[int]:
+       case [10]T[int]:
+       case struct{T[int]}:
+       case *T[int]:
+       case func(T[int]):
+       case interface{m(T[int])}:
+       case map[T[int]] string:
+       case chan T[int]:
+
+       case T /* ERROR cannot use generic type T\[P interface{}\] without instantiation */ :
+       case []T /* ERROR cannot use generic type */ :
+       case [10]T /* ERROR cannot use generic type */ :
+       case struct{T /* ERROR cannot use generic type */ }:
+       case *T /* ERROR cannot use generic type */ :
+       case func(T /* ERROR cannot use generic type */ ):
+       case interface{m(T /* ERROR cannot use generic type */ )}:
+       case map[T /* ERROR cannot use generic type */ ] string:
+       case chan T /* ERROR cannot use generic type */ :
+
+       case T /* ERROR cannot use generic type */ , *T /* ERROR cannot use generic type */ :
+       }
+}
+
+// Make sure a parenthesized nil is ok.
+
+func _(x interface{}) {
+       switch x.(type) {
+       case ((nil)), int:
+       }
+}
+
+// Make sure we look for the predeclared nil.
+
+func _(x interface{}) {
+       type nil int
+       switch x.(type) {
+       case nil: // ok - this is the type nil
+       }
+}
+
+func _(x interface{}) {
+       var nil int
+       switch x.(type) {
+       case nil /* ERROR not a type */ : // not ok - this is the variable nil
+       }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go2
new file mode 100644 (file)
index 0000000..e6ccc6b
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Box[A any] struct {
+       value A
+}
+
+func Nest[A /* ERROR instantiation cycle */ any](b Box[A], n int) interface{} {
+       if n == 0 {
+               return b
+       }
+       return Nest(Box[Box[A]]{b}, n-1)
+}
+
+func main() {
+       Nest(Box[int]{0}, 10)
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go2
new file mode 100644 (file)
index 0000000..f401330
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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[P any] struct{}
+
+func (T[_]) A() {}
+
+var _ = (T[int]).A
+var _ = (*T[int]).A
+
+var _ = (T /* ERROR cannot use generic type */).A
+var _ = (*T /* ERROR cannot use generic type */).A
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.src
new file mode 100644 (file)
index 0000000..5395154
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2021 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 issue48082
+
+import "init" /* ERROR init must be a func */ /* ERROR could not import init */
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go2
new file mode 100644 (file)
index 0000000..3dae514
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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[P any] struct{}
+
+type _ interface{ int | T /* ERROR cannot use generic type */ }
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go2
new file mode 100644 (file)
index 0000000..0ab92df
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2021 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 f1[P interface{ *P }]() {}
+func f2[P interface{ func(P) }]() {}
+func f3[P, Q interface{ func(Q) P }]() {}
+func f4[P interface{ *Q }, Q interface{ func(P) }]() {}
+func f5[P interface{ func(P) }]() {}
+func f6[P interface { *Tree[P] }, Q any ]() {}
+
+func _() {
+        f1( /* ERROR cannot infer P */ )
+        f2( /* ERROR cannot infer P */ )
+        f3( /* ERROR cannot infer P */ )
+        f4( /* ERROR cannot infer P */ )
+        f5( /* ERROR cannot infer P */ )
+        f6( /* ERROR cannot infer P */ )
+}
+
+type Tree[P any] struct {
+        left, right *Tree[P]
+        data P
+}
+
+// test case from issue
+
+func foo[Src interface { func() Src }]() Src {
+        return foo[Src]
+}
+
+func _() {
+        foo( /* ERROR cannot infer Src */ )
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2
new file mode 100644 (file)
index 0000000..e069930
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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
+
+var _ = interface{
+       m()
+       m /* ERROR "duplicate method" */ ()
+}(nil)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go2
new file mode 100644 (file)
index 0000000..2d908f4
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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 g() {
+       var s string
+       var i int
+       _ = s /* ERROR invalid operation: s \+ i \(mismatched types string and int\) */ + i
+}
+
+func f(i int) int {
+        i /* ERROR invalid operation: i \+= "1" \(mismatched types int and untyped string\) */ += "1"
+        return i
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go2
new file mode 100644 (file)
index 0000000..4f92dec
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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[U interface{ M() T /* ERROR "got 2 arguments but 1 type parameters" */ [U, int] }] int
+
+type X int
+
+func (X) M() T[X] { return 0 }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go2
new file mode 100644 (file)
index 0000000..c12091b
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 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 N /* ERROR cycle */ interface {
+       int | N
+}
+
+type A /* ERROR cycle */ interface {
+       int | B
+}
+
+type B interface {
+       int | A
+}
+
+type S /* ERROR cycle */ struct {
+       I // ERROR interface contains type constraints
+}
+
+type I interface {
+       int | S
+}
+
+type P interface {
+       *P // ERROR interface contains type constraints
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go2
new file mode 100644 (file)
index 0000000..870bacd
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This issue has been re-opened.
+
+package p
+
+func f[P any](a, _ P) {
+       // var x int
+       // f(a, x /* ERROR type int of x does not match P */)
+       // f(x, a /* ERROR type P of a does not match inferred type int for P */)
+}
+
+func g[P any](a, b P) {
+       // g(a, b)
+       // g(&a, &b)
+       // g([]P{}, []P{})
+}
+
+func h[P any](a, b P) {
+       // h(&a, &b)
+       // h([]P{a}, []P{b})
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go2
new file mode 100644 (file)
index 0000000..652f8ce
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This issue is still open.
+
+package p
+
+func f[P *Q, Q any](p P, q Q) {
+       // _ = f[P]
+        // _ = f[/* ERROR cannot infer P */ *P]
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go2
new file mode 100644 (file)
index 0000000..9f4a768
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2021 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 g[P ~func(T) P, T any](P) {}
+
+func _() {
+       type F func(int) F
+       var f F
+       g(f)
+       _ = g[F]
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go2
new file mode 100644 (file)
index 0000000..8a32c1e
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2021 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 "unsafe"
+
+// The actual example from the issue.
+type List[P any] struct{}
+
+func (_ List[P]) m() (_ List[List[P]]) { return }
+
+// Other types of recursion through methods.
+type R[P any] int
+
+func (*R[R /* ERROR must be an identifier */ [int]]) m0() {}
+func (R[P]) m1(R[R[P]])                                   {}
+func (R[P]) m2(R[*P])                                     {}
+func (R[P]) m3([unsafe.Sizeof(new(R[P]))]int)             {}
+func (R[P]) m4([unsafe.Sizeof(new(R[R[P]]))]int)          {}
+
+// Mutual recursion
+type M[P any] int
+
+func (R[P]) m5(M[M[P]]) {}
+func (M[P]) m(R[R[P]])  {}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.src
new file mode 100644 (file)
index 0000000..9262110
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 "unsafe"
+
+type T /* ERROR illegal cycle in declaration of T */ struct {
+       T
+}
+
+func _(t T) {
+       _ = unsafe.Sizeof(t) // should not go into infinite recursion here
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go2
new file mode 100644 (file)
index 0000000..cf02cc1
--- /dev/null
@@ -0,0 +1,21 @@
+// 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 (
+        A1 /* ERROR illegal cycle */ [P any] [10]A1[P]
+        A2 /* ERROR illegal cycle */ [P any] [10]A2[*P]
+        A3[P any] [10]*A3[P]
+
+        L1[P any] []L1[P]
+
+        S1 /* ERROR illegal cycle */ [P any] struct{ f S1[P] }
+        S2 /* ERROR illegal cycle */ [P any] struct{ f S2[*P] } // like example in issue
+        S3[P any] struct{ f *S3[P] }
+
+        I1 /* ERROR illegal cycle */ [P any] interface{ I1[P] }
+        I2 /* ERROR illegal cycle */ [P any] interface{ I2[*P] }
+        I3[P any] interface{ *I3 /* ERROR interface contains type constraints */ [P] }
+)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go2
new file mode 100644 (file)
index 0000000..d8ff7c8
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 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 Fooer interface {
+       Foo()
+}
+
+type Fooable[F /* ERROR instantiation cycle */ Fooer] struct {
+       ptr F
+}
+
+func (f *Fooable[F]) Adapter() *Fooable[*FooerImpl[F]] {
+       return &Fooable[*FooerImpl[F]]{&FooerImpl[F]{}}
+}
+
+type FooerImpl[F Fooer] struct {
+}
+
+func (fi *FooerImpl[F]) Foo() {}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49003.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49003.go
new file mode 100644 (file)
index 0000000..ece1a27
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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(s string) int {
+       for range s {
+       }
+} // ERROR missing return
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49005.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49005.go
new file mode 100644 (file)
index 0000000..6225e68
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is tested when running "go test -run Manual"
+// without source arguments. Use for one-off debugging.
+
+package p
+
+type T1 interface{ M() }
+
+func F1() T1
+
+var _ = F1().(*X1 /* ERROR undeclared name: X1 */)
+
+func _() {
+       switch F1().(type) {
+       case *X1 /* ERROR undeclared name: X1 */ :
+       }
+}
+
+type T2 interface{ M() }
+
+func F2() T2
+
+var _ = F2(). /* ERROR impossible type assertion: F2\(\).\(\*X2\)\n\t\*X2 does not implement T2 \(missing M method\) */ (*X2)
+
+type X2 struct{}
+
+func _() {
+       switch F2().(type) {
+       case * /* ERROR impossible type switch case: \*X2\n\tF2\(\) \(value of type T2\) cannot have dynamic type \*X2 \(missing M method\) */ X2:
+       }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2
new file mode 100644 (file)
index 0000000..c37b0f1
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2021 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
+
+// The example from the issue.
+type (
+       N /* ERROR illegal cycle */ [P any] M[P]
+       M[P any] N[P]
+)
+
+// A slightly more complicated case.
+type (
+       A /* ERROR illegal cycle */ [P any] B[P]
+       B[P any] C[P]
+       C[P any] A[P]
+)
+
+// Confusing but valid (note that `type T *T` is valid).
+type (
+       N1[P any] *M1[P]
+       M1[P any] *N1[P]
+)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go2
new file mode 100644 (file)
index 0000000..524a0cb
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2021 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 _[P int](x P) int {
+       return x // ERROR cannot use x .* as int value in return statement
+}
+
+func _[P int]() int {
+       return P /* ERROR cannot use P\(1\) .* as int value in return statement */ (1)
+}
+
+func _[P int](x int) P {
+        return x // ERROR cannot use x .* as P value in return statement
+}
+
+func _[P, Q any](x P) Q {
+        return x // ERROR cannot use x .* as Q value in return statement
+}
+
+// test case from issue
+func F[G interface{ uint }]() int {
+       f := func(uint) int { return 0 }
+       return f(G /* ERROR cannot use G\(1\) .* as uint value in argument to f */ (1))
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go2
new file mode 100644 (file)
index 0000000..3f25e0e
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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 integer interface {
+       ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+               ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+func Add1024[T integer](s []T) {
+       for i, v := range s {
+               s[i] = v + 1024 // ERROR cannot convert 1024 \(untyped int constant\) to T
+       }
+}
+
+func f[T interface{ int8 }]() {
+       println(T(1024 /* ERROR cannot convert 1024 \(untyped int value\) to T */))
+}
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go2
new file mode 100644 (file)
index 0000000..8f52acc
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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 _[
+        T0 any,
+        T1 []int,
+        T2 ~float64 | ~complex128 | chan int,
+]() {
+        _ = T0(nil /* ERROR cannot convert untyped nil to T0 */ )
+        _ = T1(1 /* ERROR cannot convert 1 .* to T1 */ )
+        _ = T2(2 /* ERROR cannot convert 2 .* to T2 */ )
+}
+
+// test case from issue
+func f[T interface{[]int}]() {
+       _ = T(1 /* ERROR cannot convert */ )
+}
diff --git a/src/cmd/compile/internal/types2/testdata/spec/assignability.go2 b/src/cmd/compile/internal/types2/testdata/spec/assignability.go2
new file mode 100644 (file)
index 0000000..fb28358
--- /dev/null
@@ -0,0 +1,264 @@
+// Copyright 2021 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 assignability
+
+// See the end of this package for the declarations
+// of the types and variables used in these tests.
+
+// "x's type is identical to T"
+func _[TP any](X TP) {
+       b = b
+       a = a
+       l = l
+       s = s
+       p = p
+       f = f
+       i = i
+       m = m
+       c = c
+       d = d
+
+       B = B
+       A = A
+       L = L
+       S = S
+       P = P
+       F = F
+       I = I
+       M = M
+       C = C
+       D = D
+       X = X
+}
+
+// "x's type V and T have identical underlying types
+// and at least one of V or T is not a named type."
+// (here a named type is a type with a name)
+func _[TP1, TP2 Interface](X1 TP1, X2 TP2) {
+       b = B // ERROR cannot use B .* as int value
+       a = A
+       l = L
+       s = S
+       p = P
+       f = F
+       i = I
+       m = M
+       c = C
+       d = D
+
+       B = b // ERROR cannot use b .* as Basic value
+       A = a
+       L = l
+       S = s
+       P = p
+       F = f
+       I = i
+       M = m
+       C = c
+       D = d
+       X1 = i  // ERROR cannot use i .* as TP1 value
+       X1 = X2 // ERROR cannot use X2 .* as TP1 value
+}
+
+// "T is an interface type and x implements T and T is not a type parameter"
+func _[TP Interface](X TP) {
+       i = d // ERROR missing method m
+       i = D
+       i = X
+       X = i // ERROR cannot use i .* as TP value
+}
+
+// "x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type"
+// (here a named type is a type with a name)
+type (
+       _SendChan = chan<- int
+       _RecvChan = <-chan int
+
+       SendChan _SendChan
+       RecvChan _RecvChan
+)
+
+func _[
+       _CC ~_Chan,
+       _SC ~_SendChan,
+       _RC ~_RecvChan,
+
+       CC Chan,
+       SC SendChan,
+       RC RecvChan,
+]() {
+       var (
+               _ _SendChan = c
+               _ _RecvChan = c
+               _ _Chan = c
+
+               _ _SendChan = C
+               _ _RecvChan = C
+               _ _Chan = C
+
+               _ SendChan = c
+               _ RecvChan = c
+               _ Chan = c
+
+               _ SendChan = C // ERROR cannot use C .* as SendChan value
+               _ RecvChan = C // ERROR cannot use C .* as RecvChan value
+               _ Chan = C
+               _ Chan = make /* ERROR cannot use make\(chan Basic\) .* as Chan value */ (chan Basic)
+       )
+
+       var (
+               _ _CC = C // ERROR cannot use C .* as _CC value
+               _ _SC = C // ERROR cannot use C .* as _SC value
+               _ _RC = C // ERROR cannot use C .* as _RC value
+
+               _ CC = _CC /* ERROR cannot use _CC\(nil\) .* as CC value */ (nil)
+               _ SC = _CC /* ERROR cannot use _CC\(nil\) .* as SC value */ (nil)
+               _ RC = _CC /* ERROR cannot use _CC\(nil\) .* as RC value */ (nil)
+
+               _ CC = C // ERROR cannot use C .* as CC value
+               _ SC = C // ERROR cannot use C .* as SC value
+               _ RC = C // ERROR cannot use C .* as RC value
+       )
+}
+
+// "x's type V is not a named type and T is a type parameter, and x is assignable to each specific type in T's type set."
+func _[
+       TP0 any,
+       TP1 ~_Chan,
+       TP2 ~chan int | ~chan byte,
+]() {
+       var (
+               _ TP0 = c // ERROR cannot use c .* as TP0 value
+               _ TP0 = C // ERROR cannot use C .* as TP0 value
+               _ TP1 = c
+               _ TP1 = C // ERROR cannot use C .* as TP1 value
+               _ TP2 = c // ERROR .* cannot assign chan int to chan byte
+       )
+}
+
+// "x's type V is a type parameter and T is not a named type, and values x' of each specific type in V's type set are assignable to T."
+func _[
+       TP0 Interface,
+       TP1 ~_Chan,
+       TP2 ~chan int | ~chan byte,
+](X0 TP0, X1 TP1, X2 TP2) {
+       i = X0
+       I = X0
+       c = X1
+       C = X1 // ERROR cannot use X1 .* as Chan value
+       c = X2 // ERROR .* cannot assign chan byte \(in TP2\) to chan int
+}
+
+// "x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type"
+func _[TP Interface](X TP) {
+       b = nil // ERROR cannot use untyped nil
+       a = nil // ERROR cannot use untyped nil
+       l = nil
+       s = nil // ERROR cannot use untyped nil
+       p = nil
+       f = nil
+       i = nil
+       m = nil
+       c = nil
+       d = nil // ERROR cannot use untyped nil
+
+       B = nil // ERROR cannot use untyped nil
+       A = nil // ERROR cannot use untyped nil
+       L = nil
+       S = nil // ERROR cannot use untyped nil
+       P = nil
+       F = nil
+       I = nil
+       M = nil
+       C = nil
+       D = nil // ERROR cannot use untyped nil
+       X = nil // ERROR cannot use untyped nil
+}
+
+// "x is an untyped constant representable by a value of type T"
+func _[
+       Int8 ~int8,
+       Int16 ~int16,
+       Int32 ~int32,
+       Int64 ~int64,
+        Int8_16 ~int8 | ~int16,
+](
+       i8 Int8,
+       i16 Int16,
+       i32 Int32,
+       i64 Int64,
+        i8_16 Int8_16,
+) {
+       b = 42
+       b = 42.0
+       // etc.
+
+       i8 = -1 << 7
+       i8 = 1<<7 - 1
+       i16 = -1 << 15
+       i16 = 1<<15 - 1
+       i32 = -1 << 31
+       i32 = 1<<31 - 1
+       i64 = -1 << 63
+       i64 = 1<<63 - 1
+
+       i8_16 = -1 << 7
+       i8_16 = 1<<7 - 1
+       i8_16 = - /* ERROR cannot use .* as Int8_16 */ 1 << 15
+       i8_16 = 1 /* ERROR cannot use .* as Int8_16 */ <<15 - 1
+}
+
+// proto-types for tests
+
+type (
+       _Basic     = int
+       _Array     = [10]int
+       _Slice     = []int
+       _Struct    = struct{ f int }
+       _Pointer   = *int
+       _Func      = func(x int) string
+       _Interface = interface{ m() int }
+       _Map       = map[string]int
+       _Chan      = chan int
+
+       Basic     _Basic
+       Array     _Array
+       Slice     _Slice
+       Struct    _Struct
+       Pointer   _Pointer
+       Func      _Func
+       Interface _Interface
+       Map       _Map
+       Chan      _Chan
+       Defined   _Struct
+)
+
+func (Defined) m() int
+
+// proto-variables for tests
+
+var (
+       b _Basic
+       a _Array
+       l _Slice
+       s _Struct
+       p _Pointer
+       f _Func
+       i _Interface
+       m _Map
+       c _Chan
+       d _Struct
+
+       B Basic
+       A Array
+       L Slice
+       S Struct
+       P Pointer
+       F Func
+       I Interface
+       M Map
+       C Chan
+       D Defined
+)
diff --git a/src/cmd/compile/internal/types2/testdata/spec/conversions.go2 b/src/cmd/compile/internal/types2/testdata/spec/conversions.go2
new file mode 100644 (file)
index 0000000..fde332f
--- /dev/null
@@ -0,0 +1,178 @@
+// Copyright 2021 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 conversions
+
+import "unsafe"
+
+// constant conversions
+
+func _[T ~byte]() T { return 255 }
+func _[T ~byte]() T { return 256 /* ERROR cannot use 256 .* as T value */ }
+
+func _[T ~byte]() {
+       const _ = T /* ERROR T\(0\) .* is not constant */ (0)
+       var _ T = 255
+       var _ T = 256 // ERROR cannot use 256 .* as T value
+}
+
+func _[T ~string]() T { return T('a') }
+func _[T ~int | ~string]() T { return T('a') }
+func _[T ~byte | ~int | ~string]() T { return T(256 /* ERROR cannot convert 256 .* to T */ ) }
+
+// implicit conversions never convert to string
+func _[T ~string]() {
+       var _ string = 0 // ERROR cannot use .* as string value
+       var _ T = 0 // ERROR cannot use .* as T value
+}
+
+// failing const conversions of constants to type parameters report a cause
+func _[
+       T1 any,
+       T2 interface{ m() },
+       T3 ~int | ~float64 | ~bool,
+       T4 ~int | ~string,
+]() {
+       _ = T1(0 /* ERROR cannot convert 0 .* to T1\n\tT1 does not contain specific types */ )
+       _ = T2(1 /* ERROR cannot convert 1 .* to T2\n\tT2 does not contain specific types */ )
+       _ = T3(2 /* ERROR cannot convert 2 .* to T3\n\tcannot convert 2 .* to bool \(in T3\) */ )
+       _ = T4(3.14 /* ERROR cannot convert 3.14 .* to T4\n\tcannot convert 3.14 .* to int \(in T4\) */ )
+}
+
+// "x is assignable to T"
+// - tested via assignability tests
+
+// "x's type and T have identical underlying types if tags are ignored"
+
+func _[X ~int, T ~int](x X) T { return T(x) }
+func _[X struct{f int "foo"}, T struct{f int "bar"}](x X) T { return T(x) }
+
+type Foo struct{f int "foo"}
+type Bar struct{f int "bar"}
+type Far struct{f float64 }
+
+func _[X Foo, T Bar](x X) T { return T(x) }
+func _[X Foo|Bar, T Bar](x X) T { return T(x) }
+func _[X Foo, T Foo|Bar](x X) T { return T(x) }
+func _[X Foo, T Far](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Foo\) to T\n\tcannot convert Foo \(in X\) to Far \(in T\) */ ) }
+
+// "x's type and T are unnamed pointer types and their pointer base types
+// have identical underlying types if tags are ignored"
+
+func _[X ~*Foo, T ~*Bar](x X) T { return T(x) }
+func _[X ~*Foo|~*Bar, T ~*Bar](x X) T { return T(x) }
+func _[X ~*Foo, T ~*Foo|~*Bar](x X) T { return T(x) }
+func _[X ~*Foo, T ~*Far](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\*Foo\) to T\n\tcannot convert \*Foo \(in X\) to \*Far \(in T\) */ ) }
+
+// Verify that the defined types in constraints are considered for the rule above.
+
+type (
+       B int
+       C int
+       X0 *B
+       T0 *C
+)
+
+func _(x X0) T0 { return T0(x /* ERROR cannot convert */ ) } // non-generic reference
+func _[X X0, T T0](x X) T { return T(x /* ERROR cannot convert */ ) }
+func _[T T0](x X0) T { return T(x /* ERROR cannot convert */ ) }
+func _[X X0](x X) T0 { return T0(x /* ERROR cannot convert */ ) }
+
+// "x's type and T are both integer or floating point types"
+
+func _[X Integer, T Integer](x X) T { return T(x) }
+func _[X Unsigned, T Integer](x X) T { return T(x) }
+func _[X Float, T Integer](x X) T { return T(x) }
+
+func _[X Integer, T Unsigned](x X) T { return T(x) }
+func _[X Unsigned, T Unsigned](x X) T { return T(x) }
+func _[X Float, T Unsigned](x X) T { return T(x) }
+
+func _[X Integer, T Float](x X) T { return T(x) }
+func _[X Unsigned, T Float](x X) T { return T(x) }
+func _[X Float, T Float](x X) T { return T(x) }
+
+func _[X, T Integer|Unsigned|Float](x X) T { return T(x) }
+func _[X, T Integer|~string](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Integer\|~string\) to T\n\tcannot convert string \(in X\) to int \(in T\) */ ) }
+
+// "x's type and T are both complex types"
+
+func _[X, T Complex](x X) T { return T(x) }
+func _[X, T Float|Complex](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Float\|Complex\) to T\n\tcannot convert float32 \(in X\) to complex64 \(in T\) */ ) }
+
+// "x is an integer or a slice of bytes or runes and T is a string type"
+
+type myInt int
+type myString string
+
+func _[T ~string](x int) T { return T(x) }
+func _[T ~string](x myInt) T { return T(x) }
+func _[X Integer](x X) string { return string(x) }
+func _[X Integer](x X) myString { return myString(x) }
+func _[X Integer](x X) *string { return (*string)(x /* ERROR cannot convert x \(variable of type X constrained by Integer\) to \*string\n\tcannot convert int \(in X\) to \*string */ ) }
+
+func _[T ~string](x []byte) T { return T(x) }
+func _[T ~string](x []rune) T { return T(x) }
+func _[X ~[]byte, T ~string](x X) T { return T(x) }
+func _[X ~[]rune, T ~string](x X) T { return T(x) }
+func _[X Integer|~[]byte|~[]rune, T ~string](x X) T { return T(x) }
+func _[X Integer|~[]byte|~[]rune, T ~*string](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Integer\|~\[\]byte\|~\[\]rune\) to T\n\tcannot convert int \(in X\) to \*string \(in T\) */ ) }
+
+// "x is a string and T is a slice of bytes or runes"
+
+func _[T ~[]byte](x string) T { return T(x) }
+func _[T ~[]rune](x string) T { return T(x) }
+func _[T ~[]rune](x *string) T { return T(x /* ERROR cannot convert x \(variable of type \*string\) to T\n\tcannot convert \*string to \[\]rune \(in T\) */ ) }
+
+func _[X ~string, T ~[]byte](x X) T { return T(x) }
+func _[X ~string, T ~[]rune](x X) T { return T(x) }
+func _[X ~string, T ~[]byte|~[]rune](x X) T { return T(x) }
+func _[X ~*string, T ~[]byte|~[]rune](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\*string\) to T\n\tcannot convert \*string \(in X\) to \[\]byte \(in T\) */ ) }
+
+// package unsafe:
+// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+
+type myUintptr uintptr
+
+func _[X ~uintptr](x X) unsafe.Pointer { return unsafe.Pointer(x) }
+func _[T unsafe.Pointer](x myUintptr) T { return T(x) }
+func _[T unsafe.Pointer](x int64) T { return T(x /* ERROR cannot convert x \(variable of type int64\) to T\n\tcannot convert int64 to unsafe\.Pointer \(in T\) */ ) }
+
+// "and vice versa"
+
+func _[T ~uintptr](x unsafe.Pointer) T { return T(x) }
+func _[X unsafe.Pointer](x X) uintptr { return uintptr(x) }
+func _[X unsafe.Pointer](x X) myUintptr { return myUintptr(x) }
+func _[X unsafe.Pointer](x X) int64 { return int64(x /* ERROR cannot convert x \(variable of type X constrained by unsafe\.Pointer\) to int64\n\tcannot convert unsafe\.Pointer \(in X\) to int64 */ ) }
+
+// "x is a slice, T is a pointer-to-array type,
+// and the slice and array types have identical element types."
+
+func _[X ~[]E, T ~*[10]E, E any](x X) T { return T(x) }
+func _[X ~[]E, T ~[10]E, E any](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\[\]E\) to T\n\tcannot convert \[\]E \(in X\) to \[10\]E \(in T\) */ ) }
+
+// ----------------------------------------------------------------------------
+// The following declarations can be replaced by the exported types of the
+// constraints package once all builders support importing interfaces with
+// type constraints.
+
+type Signed interface {
+       ~int | ~int8 | ~int16 | ~int32 | ~int64
+}
+
+type Unsigned interface {
+       ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+type Integer interface {
+       Signed | Unsigned
+}
+
+type Float interface {
+       ~float32 | ~float64
+}
+
+type Complex interface {
+       ~complex64 | ~complex128
+}
index a3946beab573412b102946ab04e6c5eb78ca8b1c..1356aae0b018a464ef6c9deed88138e5d7115d7c 100644 (file)
@@ -16,8 +16,6 @@ func NewTuple(x ...*Var) *Tuple {
        if len(x) > 0 {
                return &Tuple{vars: x}
        }
-       // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
-       //           it's too subtle and causes problems.
        return nil
 }
 
index 4b8642aa9629df7b22af72ae22dd71c08b28e05d..300c81f5fac84a6afd4004bbdb51329e160e966f 100644 (file)
@@ -9,114 +9,69 @@ package types2
 type Type interface {
        // Underlying returns the underlying type of a type
        // w/o following forwarding chains. Only used by
-       // client packages (here for backward-compatibility).
+       // client packages.
        Underlying() Type
 
        // String returns a string representation of a type.
        String() string
 }
 
-// top represents the top of the type lattice.
-// It is the underlying type of a type parameter that
-// can be satisfied by any type (ignoring methods),
-// because its type constraint contains no restrictions
-// besides methods.
-type top struct{}
-
-// theTop is the singleton top type.
-var theTop = &top{}
-
-func (t *top) Underlying() Type { return t }
-func (t *top) String() string   { return TypeString(t, nil) }
-
 // under returns the true expanded underlying type.
 // If it doesn't exist, the result is Typ[Invalid].
 // under must only be called when a type is known
 // to be fully set up.
 func under(t Type) Type {
-       // TODO(gri) is this correct for *Union?
        if n := asNamed(t); n != nil {
                return n.under()
        }
        return t
 }
 
-// optype returns a type's operational type. Except for
-// type parameters, the operational type is the same
-// as the underlying type (as returned by under). For
-// Type parameters, the operational type is the structural
-// type, if any; otherwise it's the top type.
-// The result is never the incoming type parameter.
-func optype(typ Type) Type {
-       if t := asTypeParam(typ); t != nil {
-               // TODO(gri) review accuracy of this comment
-               // If the optype is typ, return the top type as we have
-               // no information. It also prevents infinite recursion
-               // via the asTypeParam converter function. This can happen
-               // for a type parameter list of the form:
-               // (type T interface { type T }).
-               // See also issue #39680.
-               if u := t.structuralType(); u != nil {
-                       assert(u != typ) // "naked" type parameters cannot be embedded
-                       return u
-               }
-               return theTop
-       }
-       return under(typ)
-}
-
-// Converters
-//
-// A converter must only be called when a type is
-// known to be fully set up. A converter returns
-// a type's operational type (see comment for optype)
-// or nil if the type argument is not of the
-// respective type.
+// Convenience converters
 
 func asBasic(t Type) *Basic {
-       op, _ := optype(t).(*Basic)
-       return op
+       u, _ := under(t).(*Basic)
+       return u
 }
 
 func asArray(t Type) *Array {
-       op, _ := optype(t).(*Array)
-       return op
+       u, _ := under(t).(*Array)
+       return u
 }
 
 func asSlice(t Type) *Slice {
-       op, _ := optype(t).(*Slice)
-       return op
+       u, _ := under(t).(*Slice)
+       return u
 }
 
 func asStruct(t Type) *Struct {
-       op, _ := optype(t).(*Struct)
-       return op
+       u, _ := under(t).(*Struct)
+       return u
 }
 
 func asPointer(t Type) *Pointer {
-       op, _ := optype(t).(*Pointer)
-       return op
+       u, _ := under(t).(*Pointer)
+       return u
 }
 
 func asSignature(t Type) *Signature {
-       op, _ := optype(t).(*Signature)
-       return op
+       u, _ := under(t).(*Signature)
+       return u
 }
 
-// If the argument to asInterface, asNamed, or asTypeParam is of the respective type
-// (possibly after expanding an instance type), these methods return that type.
-// Otherwise the result is nil.
-
-// asInterface does not need to look at optype (type sets don't contain interfaces)
 func asInterface(t Type) *Interface {
        u, _ := under(t).(*Interface)
        return u
 }
 
+// If the argument to asNamed, or asTypeParam is of the respective type
+// (possibly after expanding resolving a *Named type), these methods return that type.
+// Otherwise the result is nil.
+
 func asNamed(t Type) *Named {
        e, _ := t.(*Named)
        if e != nil {
-               e.expand(nil)
+               e.resolve(nil)
        }
        return e
 }
@@ -126,10 +81,32 @@ func asTypeParam(t Type) *TypeParam {
        return u
 }
 
-// Exported for the compiler.
+// Helper functions exported for the compiler.
+// These functions assume type checking has completed
+// and Type.Underlying() is returning the fully set up
+// underlying type. Do not use internally.
+
+func AsPointer(t Type) *Pointer {
+       u, _ := t.Underlying().(*Pointer)
+       return u
+}
+
+func AsNamed(t Type) *Named {
+       u, _ := t.(*Named)
+       return u
+}
 
-func AsPointer(t Type) *Pointer     { return asPointer(t) }
-func AsNamed(t Type) *Named         { return asNamed(t) }
-func AsSignature(t Type) *Signature { return asSignature(t) }
-func AsInterface(t Type) *Interface { return asInterface(t) }
-func AsTypeParam(t Type) *TypeParam { return asTypeParam(t) }
+func AsSignature(t Type) *Signature {
+       u, _ := t.Underlying().(*Signature)
+       return u
+}
+
+func AsInterface(t Type) *Interface {
+       u, _ := t.Underlying().(*Interface)
+       return u
+}
+
+func AsTypeParam(t Type) *TypeParam {
+       u, _ := t.Underlying().(*TypeParam)
+       return u
+}
diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go
new file mode 100644 (file)
index 0000000..ababe85
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2021 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 types2
+
+import "bytes"
+
+// TypeParamList holds a list of type parameters.
+type TypeParamList struct{ tparams []*TypeParam }
+
+// Len returns the number of type parameters in the list.
+// It is safe to call on a nil receiver.
+func (l *TypeParamList) Len() int { return len(l.list()) }
+
+// At returns the i'th type parameter in the list.
+func (l *TypeParamList) At(i int) *TypeParam { return l.tparams[i] }
+
+// list is for internal use where we expect a []*TypeParam.
+// TODO(rfindley): list should probably be eliminated: we can pass around a
+// TypeParamList instead.
+func (l *TypeParamList) list() []*TypeParam {
+       if l == nil {
+               return nil
+       }
+       return l.tparams
+}
+
+// TypeList holds a list of types.
+type TypeList struct{ types []Type }
+
+// NewTypeList returns a new TypeList with the types in list.
+func NewTypeList(list []Type) *TypeList {
+       if len(list) == 0 {
+               return nil
+       }
+       return &TypeList{list}
+}
+
+// Len returns the number of types in the list.
+// It is safe to call on a nil receiver.
+func (l *TypeList) Len() int { return len(l.list()) }
+
+// At returns the i'th type in the list.
+func (l *TypeList) At(i int) Type { return l.types[i] }
+
+// list is for internal use where we expect a []Type.
+// TODO(rfindley): list should probably be eliminated: we can pass around a
+// TypeList instead.
+func (l *TypeList) list() []Type {
+       if l == nil {
+               return nil
+       }
+       return l.types
+}
+
+func (l *TypeList) String() string {
+       if l == nil || len(l.types) == 0 {
+               return "[]"
+       }
+       var buf bytes.Buffer
+       newTypeWriter(&buf, nil).typeList(l.types)
+       return buf.String()
+}
+
+// ----------------------------------------------------------------------------
+// Implementation
+
+func bindTParams(list []*TypeParam) *TypeParamList {
+       if len(list) == 0 {
+               return nil
+       }
+       for i, typ := range list {
+               if typ.index >= 0 {
+                       panic("type parameter bound more than once")
+               }
+               typ.index = i
+       }
+       return &TypeParamList{tparams: list}
+}
index f666fae7ede630269cc14d10258b7ad7eb06785d..099bc429c30a302093b27c1a1c9ddb4a6cab33ac 100644 (file)
@@ -21,54 +21,43 @@ type TypeParam struct {
        id    uint64    // unique id, for debugging only
        obj   *TypeName // corresponding type name
        index int       // type parameter index in source order, starting at 0
-       // TODO(rfindley): this could also be Typ[Invalid]. Verify that this is handled correctly.
-       bound Type // *Named or *Interface; underlying type is always *Interface
+       bound Type      // any type, but eventually an *Interface for correct programs (see TypeParam.iface)
 }
 
 // Obj returns the type name for the type parameter t.
 func (t *TypeParam) Obj() *TypeName { return t.obj }
 
 // NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
-// or Signature type by calling SetTParams. Setting a type parameter on more
+// or Signature type by calling SetTypeParams. Setting a type parameter on more
 // than one type will result in a panic.
 //
-// The bound argument can be nil, and set later via SetBound.
-func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam {
+// The constraint argument can be nil, and set later via SetConstraint.
+func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
+       return (*Checker)(nil).newTypeParam(obj, constraint)
+}
+
+func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
        // Always increment lastID, even if it is not used.
        id := nextID()
        if check != nil {
                check.nextID++
                id = check.nextID
        }
-       typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound}
+       typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: constraint}
        if obj.typ == nil {
                obj.typ = typ
        }
        return typ
 }
 
-// Index returns the index of the type param within its param list.
+// Index returns the index of the type param within its param list, or -1 if
+// the type parameter has not yet been bound to a type.
 func (t *TypeParam) Index() int {
        return t.index
 }
 
-// SetId sets the unique id of a type param. Should only be used for type params
-// in imported generic types.
-func (t *TypeParam) SetId(id uint64) {
-       t.id = id
-}
-
 // Constraint returns the type constraint specified for t.
 func (t *TypeParam) Constraint() Type {
-       // compute the type set if possible (we may not have an interface)
-       if iface, _ := under(t.bound).(*Interface); iface != nil {
-               // use the type bound position if we have one
-               pos := nopos
-               if n, _ := t.bound.(*Named); n != nil {
-                       pos = n.obj.pos
-               }
-               computeInterfaceTypeSet(t.check, pos, iface)
-       }
        return t.bound
 }
 
@@ -83,61 +72,68 @@ func (t *TypeParam) SetConstraint(bound Type) {
 func (t *TypeParam) Underlying() Type { return t }
 func (t *TypeParam) String() string   { return TypeString(t, nil) }
 
-// TParamList holds a list of type parameters bound to a type.
-type TParamList struct{ tparams []*TypeName }
-
-// Len returns the number of type parameters in the list.
-// It is safe to call on a nil receiver.
-func (tps *TParamList) Len() int {
-       return len(tps.list())
-}
-
-// At returns the i'th type parameter in the list.
-func (tps *TParamList) At(i int) *TypeName {
-       return tps.list()[i]
-}
+// ----------------------------------------------------------------------------
+// Implementation
 
-func (tps *TParamList) list() []*TypeName {
-       if tps == nil {
-               return nil
+// iface returns the constraint interface of t.
+func (t *TypeParam) iface() *Interface {
+       bound := t.bound
+
+       // determine constraint interface
+       var ityp *Interface
+       switch u := under(bound).(type) {
+       case *Basic:
+               if u == Typ[Invalid] {
+                       // error is reported elsewhere
+                       return &emptyInterface
+               }
+       case *Interface:
+               ityp = u
+       case *TypeParam:
+               // error is reported in Checker.collectTypeParams
+               return &emptyInterface
        }
-       return tps.tparams
-}
 
-func bindTParams(list []*TypeName) *TParamList {
-       if len(list) == 0 {
-               return nil
+       // If we don't have an interface, wrap constraint into an implicit interface.
+       if ityp == nil {
+               ityp = NewInterfaceType(nil, []Type{bound})
+               ityp.implicit = true
+               t.bound = ityp // update t.bound for next time (optimization)
        }
-       for i, tp := range list {
-               typ := tp.Type().(*TypeParam)
-               if typ.index >= 0 {
-                       panic("type parameter bound more than once")
+
+       // compute type set if necessary
+       if ityp.tset == nil {
+               // use the (original) type bound position if we have one
+               pos := nopos
+               if n, _ := bound.(*Named); n != nil {
+                       pos = n.obj.pos
                }
-               typ.index = i
+               computeInterfaceTypeSet(t.check, pos, ityp)
        }
-       return &TParamList{tparams: list}
-}
 
-// ----------------------------------------------------------------------------
-// Implementation
+       return ityp
+}
 
-// iface returns the constraint interface of t.
-func (t *TypeParam) iface() *Interface {
-       if iface, _ := under(t.Constraint()).(*Interface); iface != nil {
-               return iface
-       }
-       return &emptyInterface
+// singleType returns the single type of the type parameter constraint; or nil.
+func (t *TypeParam) singleType() Type {
+       return t.iface().typeSet().singleType()
 }
 
-// structuralType returns the structural type of the type parameter's constraint; or nil.
-func (t *TypeParam) structuralType() Type {
-       return t.iface().typeSet().structuralType()
+// hasTerms reports whether the type parameter constraint has specific type terms.
+func (t *TypeParam) hasTerms() bool {
+       return t.iface().typeSet().hasTerms()
 }
 
+// is calls f with the specific type terms of t's constraint and reports whether
+// all calls to f returned true. If there are no specific terms, is
+// returns the result of f(nil).
 func (t *TypeParam) is(f func(*term) bool) bool {
        return t.iface().typeSet().is(f)
 }
 
+// underIs calls f with the underlying types of the specific type terms
+// of t's constraint and reports whether all calls to f returned true.
+// If there are no specific terms, underIs returns the result of f(nil).
 func (t *TypeParam) underIs(f func(Type) bool) bool {
        return t.iface().typeSet().underIs(f)
 }
index 5955bbe805467dc333732bca17c6306afaf4ea00..445a62f9e06280d5d34cfb047996e4369511f92d 100644 (file)
@@ -14,8 +14,8 @@ import (
 // ----------------------------------------------------------------------------
 // API
 
-// A TypeSet represents the type set of an interface.
-type TypeSet struct {
+// A _TypeSet represents the type set of an interface.
+type _TypeSet struct {
        comparable bool // if set, the interface is or embeds comparable
        // TODO(gri) consider using a set for the methods for faster lookup
        methods []*Func  // all methods of the interface; sorted by unique ID
@@ -23,49 +23,47 @@ type TypeSet struct {
 }
 
 // IsEmpty reports whether type set s is the empty set.
-func (s *TypeSet) IsEmpty() bool { return s.terms.isEmpty() }
+func (s *_TypeSet) IsEmpty() bool { return s.terms.isEmpty() }
 
 // IsAll reports whether type set s is the set of all types (corresponding to the empty interface).
-func (s *TypeSet) IsAll() bool {
+func (s *_TypeSet) IsAll() bool {
        return !s.comparable && len(s.methods) == 0 && s.terms.isAll()
 }
 
-// TODO(gri) IsMethodSet is not a great name for this predicate. Find a better one.
-
-// IsMethodSet reports whether the type set s is described by a single set of methods.
-func (s *TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() }
+// IsMethodSet reports whether the interface t is fully described by its method set.
+func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() }
 
 // IsComparable reports whether each type in the set is comparable.
-func (s *TypeSet) IsComparable() bool {
+func (s *_TypeSet) IsComparable() bool {
        if s.terms.isAll() {
                return s.comparable
        }
        return s.is(func(t *term) bool {
-               return Comparable(t.typ)
+               return t != nil && Comparable(t.typ)
        })
 }
 
 // TODO(gri) IsTypeSet is not a great name for this predicate. Find a better one.
 
 // IsTypeSet reports whether the type set s is represented by a finite set of underlying types.
-func (s *TypeSet) IsTypeSet() bool {
+func (s *_TypeSet) IsTypeSet() bool {
        return !s.comparable && len(s.methods) == 0
 }
 
 // NumMethods returns the number of methods available.
-func (s *TypeSet) NumMethods() int { return len(s.methods) }
+func (s *_TypeSet) NumMethods() int { return len(s.methods) }
 
 // Method returns the i'th method of type set s for 0 <= i < s.NumMethods().
 // The methods are ordered by their unique ID.
-func (s *TypeSet) Method(i int) *Func { return s.methods[i] }
+func (s *_TypeSet) Method(i int) *Func { return s.methods[i] }
 
 // LookupMethod returns the index of and method with matching package and name, or (-1, nil).
-func (s *TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) {
+func (s *_TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) {
        // TODO(gri) s.methods is sorted - consider binary search
        return lookupMethod(s.methods, pkg, name)
 }
 
-func (s *TypeSet) String() string {
+func (s *_TypeSet) String() string {
        switch {
        case s.IsEmpty():
                return "∅"
@@ -79,53 +77,53 @@ func (s *TypeSet) String() string {
        var buf bytes.Buffer
        buf.WriteByte('{')
        if s.comparable {
-               buf.WriteString(" comparable")
+               buf.WriteString("comparable")
                if hasMethods || hasTerms {
-                       buf.WriteByte(';')
+                       buf.WriteString("; ")
                }
        }
        for i, m := range s.methods {
                if i > 0 {
-                       buf.WriteByte(';')
+                       buf.WriteString("; ")
                }
-               buf.WriteByte(' ')
                buf.WriteString(m.String())
        }
        if hasMethods && hasTerms {
-               buf.WriteByte(';')
+               buf.WriteString("; ")
        }
        if hasTerms {
                buf.WriteString(s.terms.String())
        }
-       buf.WriteString(" }") // there was at least one method or term
-
+       buf.WriteString("}")
        return buf.String()
 }
 
 // ----------------------------------------------------------------------------
 // Implementation
 
-func (s *TypeSet) hasTerms() bool             { return !s.terms.isAll() }
-func (s *TypeSet) structuralType() Type       { return s.terms.structuralType() }
-func (s *TypeSet) includes(t Type) bool       { return s.terms.includes(t) }
-func (s1 *TypeSet) subsetOf(s2 *TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
+// hasTerms reports whether the type set has specific type terms.
+func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
 
-// TODO(gri) TypeSet.is and TypeSet.underIs should probably also go into termlist.go
+// singleType returns the single type in s if there is exactly one; otherwise the result is nil.
+func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
+
+// includes reports whether t ∈ s.
+func (s *_TypeSet) includes(t Type) bool { return s.terms.includes(t) }
 
-var topTerm = term{false, theTop}
+// subsetOf reports whether s1 ⊆ s2.
+func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
 
-func (s *TypeSet) is(f func(*term) bool) bool {
-       if len(s.terms) == 0 {
-               return false
+// TODO(gri) TypeSet.is and TypeSet.underIs should probably also go into termlist.go
+
+// is calls f with the specific type terms of s and reports whether
+// all calls to f returned true. If there are no specific terms, is
+// returns the result of f(nil).
+func (s *_TypeSet) is(f func(*term) bool) bool {
+       if !s.hasTerms() {
+               return f(nil)
        }
        for _, t := range s.terms {
-               // Terms represent the top term with a nil type.
-               // The rest of the type checker uses the top type
-               // instead. Convert.
-               // TODO(gri) investigate if we can do without this
-               if t.typ == nil {
-                       t = &topTerm
-               }
+               assert(t.typ != nil)
                if !f(t) {
                        return false
                }
@@ -133,17 +131,17 @@ func (s *TypeSet) is(f func(*term) bool) bool {
        return true
 }
 
-func (s *TypeSet) underIs(f func(Type) bool) bool {
-       if len(s.terms) == 0 {
-               return false
+// underIs calls f with the underlying types of the specific type terms
+// of s and reports whether all calls to f returned true. If there are
+// no specific terms, is returns the result of f(nil).
+func (s *_TypeSet) underIs(f func(Type) bool) bool {
+       if !s.hasTerms() {
+               return f(nil)
        }
        for _, t := range s.terms {
-               // see corresponding comment in TypeSet.is
+               assert(t.typ != nil)
+               // x == under(x) for ~x terms
                u := t.typ
-               if u == nil {
-                       u = theTop
-               }
-               // t == under(t) for ~t terms
                if !t.tilde {
                        u = under(u)
                }
@@ -158,10 +156,10 @@ func (s *TypeSet) underIs(f func(Type) bool) bool {
 }
 
 // topTypeSet may be used as type set for the empty interface.
-var topTypeSet = TypeSet{terms: allTermlist}
+var topTypeSet = _TypeSet{terms: allTermlist}
 
 // computeInterfaceTypeSet may be called with check == nil.
-func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet {
+func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_TypeSet {
        if ityp.tset != nil {
                return ityp.tset
        }
@@ -197,7 +195,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T
        // have valid interfaces. Mark the interface as complete to avoid
        // infinite recursion if the validType check occurs later for some
        // reason.
-       ityp.tset = &TypeSet{terms: allTermlist} // TODO(gri) is this sufficient?
+       ityp.tset = &_TypeSet{terms: allTermlist} // TODO(gri) is this sufficient?
 
        // Methods of embedded interfaces are collected unchanged; i.e., the identity
        // of a method I.m's Func Object of an interface I is the same as that of
@@ -271,6 +269,11 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T
                switch u := under(typ).(type) {
                case *Interface:
                        tset := computeInterfaceTypeSet(check, pos, u)
+                       // If typ is local, an error was already reported where typ is specified/defined.
+                       if check != nil && check.isImportedConstraint(typ) && !check.allowVersion(check.pkg, 1, 18) {
+                               check.errorf(pos, "embedding constraint interface %s requires go1.18 or later", typ)
+                               continue
+                       }
                        if tset.comparable {
                                ityp.tset.comparable = true
                        }
@@ -279,6 +282,10 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T
                        }
                        terms = tset.terms
                case *Union:
+                       if check != nil && !check.allowVersion(check.pkg, 1, 18) {
+                               check.errorf(pos, "embedding interface element %s requires go1.18 or later", u)
+                               continue
+                       }
                        tset := computeUnionTypeSet(check, pos, u)
                        if tset == &invalidTypeSet {
                                continue // ignore invalid unions
@@ -286,14 +293,14 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *T
                        terms = tset.terms
                case *TypeParam:
                        // Embedding stand-alone type parameters is not permitted.
-                       // This case is handled during union parsing.
-                       unreachable()
+                       // Union parsing reports a (delayed) error, so we can ignore this entry.
+                       continue
                default:
-                       if typ == Typ[Invalid] {
+                       if u == Typ[Invalid] {
                                continue
                        }
                        if check != nil && !check.allowVersion(check.pkg, 1, 18) {
-                               check.errorf(pos, "%s is not an interface", typ)
+                               check.errorf(pos, "embedding non-interface type %s requires go1.18 or later", typ)
                                continue
                        }
                        terms = termlist{{false, typ}}
@@ -347,17 +354,17 @@ func (a byUniqueMethodName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
 // invalidTypeSet is a singleton type set to signal an invalid type set
 // due to an error. It's also a valid empty type set, so consumers of
 // type sets may choose to ignore it.
-var invalidTypeSet TypeSet
+var invalidTypeSet _TypeSet
 
 // computeUnionTypeSet may be called with check == nil.
 // The result is &invalidTypeSet if the union overflows.
-func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *TypeSet {
+func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *_TypeSet {
        if utyp.tset != nil {
                return utyp.tset
        }
 
        // avoid infinite recursion (see also computeInterfaceTypeSet)
-       utyp.tset = new(TypeSet)
+       utyp.tset = new(_TypeSet)
 
        var allTerms termlist
        for _, t := range utyp.terms {
@@ -367,8 +374,8 @@ func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *TypeSet {
                        terms = computeInterfaceTypeSet(check, pos, u).terms
                case *TypeParam:
                        // A stand-alone type parameters is not permitted as union term.
-                       // This case is handled during union parsing.
-                       unreachable()
+                       // Union parsing reports a (delayed) error, so we can ignore this entry.
+                       continue
                default:
                        if t.typ == Typ[Invalid] {
                                continue
index 0e14d523c8be46dc148603b244f5d544a2206939..7f7cc06db9773c7f09cef849888de81c5bd18499 100644 (file)
@@ -4,7 +4,11 @@
 
 package types2
 
-import "testing"
+import (
+       "cmd/compile/internal/syntax"
+       "strings"
+       "testing"
+)
 
 func TestInvalidTypeSet(t *testing.T) {
        if !invalidTypeSet.IsEmpty() {
@@ -12,4 +16,65 @@ func TestInvalidTypeSet(t *testing.T) {
        }
 }
 
+func TestTypeSetString(t *testing.T) {
+       for body, want := range map[string]string{
+               "{}":            "𝓤",
+               "{int}":         "{int}",
+               "{~int}":        "{~int}",
+               "{int|string}":  "{int ∪ string}",
+               "{int; string}": "∅",
+
+               "{comparable}":              "{comparable}",
+               "{comparable; int}":         "{comparable; int}",
+               "{~int; comparable}":        "{comparable; ~int}",
+               "{int|string; comparable}":  "{comparable; int ∪ string}",
+               "{comparable; int; string}": "∅",
+
+               "{m()}":                         "{func (p.T).m()}",
+               "{m1(); m2() int }":             "{func (p.T).m1(); func (p.T).m2() int}",
+               "{error}":                       "{func (error).Error() string}",
+               "{m(); comparable}":             "{comparable; func (p.T).m()}",
+               "{m1(); comparable; m2() int }": "{comparable; func (p.T).m1(); func (p.T).m2() int}",
+               "{comparable; error}":           "{comparable; func (error).Error() string}",
+
+               "{m(); comparable; int|float32|string}": "{comparable; func (p.T).m(); int ∪ float32 ∪ string}",
+               "{m1(); int; m2(); comparable }":        "{comparable; func (p.T).m1(); func (p.T).m2(); int}",
+
+               "{E}; type E interface{}":           "𝓤",
+               "{E}; type E interface{int;string}": "∅",
+               "{E}; type E interface{comparable}": "{comparable}",
+       } {
+               // parse
+               errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
+               src := "package p; type T interface" + body
+               file, err := syntax.Parse(nil, strings.NewReader(src), errh, nil, syntax.AllowGenerics)
+               if err != nil {
+                       t.Fatalf("%s: %v (invalid test case)", body, err)
+               }
+
+               // type check
+               var conf Config
+               pkg, err := conf.Check(file.PkgName.Value, []*syntax.File{file}, nil)
+               if err != nil {
+                       t.Fatalf("%s: %v (invalid test case)", body, err)
+               }
+
+               // lookup T
+               obj := pkg.scope.Lookup("T")
+               if obj == nil {
+                       t.Fatalf("%s: T not found (invalid test case)", body)
+               }
+               T, ok := under(obj.Type()).(*Interface)
+               if !ok {
+                       t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
+               }
+
+               // verify test case
+               got := T.typeSet().String()
+               if got != want {
+                       t.Errorf("%s: got %s; want %s", body, got, want)
+               }
+       }
+}
+
 // TODO(gri) add more tests
index cb7cf73a62938fb00b30039e3220edd61478fdd0..f18a32016f77fa028374bb2cd30cd151411e28c8 100644 (file)
@@ -8,7 +8,7 @@ package types2
 
 import (
        "bytes"
-       "fmt"
+       "strconv"
        "unicode/utf8"
 )
 
@@ -43,8 +43,14 @@ func RelativeTo(pkg *Package) Qualifier {
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 func TypeString(typ Type, qf Qualifier) string {
+       return typeString(typ, qf, false)
+}
+
+func typeString(typ Type, qf Qualifier, debug bool) string {
        var buf bytes.Buffer
-       WriteType(&buf, typ, qf)
+       w := newTypeWriter(&buf, qf)
+       w.debug = debug
+       w.typ(typ)
        return buf.String()
 }
 
@@ -52,121 +58,178 @@ func TypeString(typ Type, qf Qualifier) string {
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
-       writeType(buf, typ, qf, make([]Type, 0, 8))
+       newTypeWriter(buf, qf).typ(typ)
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
+       newTypeWriter(buf, qf).signature(sig)
+}
+
+type typeWriter struct {
+       buf   *bytes.Buffer
+       seen  map[Type]bool
+       qf    Qualifier
+       ctxt  *Context // if non-nil, we are type hashing
+       debug bool     // if true, write debug annotations
+}
+
+func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
+       return &typeWriter{buf, make(map[Type]bool), qf, nil, false}
+}
+
+func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
+       assert(ctxt != nil)
+       return &typeWriter{buf, make(map[Type]bool), nil, ctxt, false}
 }
 
-// instanceMarker is the prefix for an instantiated type
-// in "non-evaluated" instance form.
-const instanceMarker = '#'
-
-func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
-       // Theoretically, this is a quadratic lookup algorithm, but in
-       // practice deeply nested composite types with unnamed component
-       // types are uncommon. This code is likely more efficient than
-       // using a map.
-       for _, t := range visited {
-               if t == typ {
-                       fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
-                       return
+func (w *typeWriter) byte(b byte) {
+       if w.ctxt != nil {
+               if b == ' ' {
+                       b = '#'
                }
+               w.buf.WriteByte(b)
+               return
+       }
+       w.buf.WriteByte(b)
+       if b == ',' || b == ';' {
+               w.buf.WriteByte(' ')
+       }
+}
+
+func (w *typeWriter) string(s string) {
+       w.buf.WriteString(s)
+}
+
+func (w *typeWriter) error(msg string) {
+       if w.ctxt != nil {
+               panic(msg)
        }
-       visited = append(visited, typ)
+       w.buf.WriteString("<" + msg + ">")
+}
+
+func (w *typeWriter) typ(typ Type) {
+       if w.seen[typ] {
+               w.error("cycle to " + goTypeName(typ))
+               return
+       }
+       w.seen[typ] = true
+       defer delete(w.seen, typ)
 
        switch t := typ.(type) {
        case nil:
-               buf.WriteString("<nil>")
+               w.error("nil")
 
        case *Basic:
                // exported basic types go into package unsafe
                // (currently this is just unsafe.Pointer)
                if isExported(t.name) {
                        if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
-                               writeTypeName(buf, obj, qf)
+                               w.typeName(obj)
                                break
                        }
                }
-               buf.WriteString(t.name)
+               w.string(t.name)
 
        case *Array:
-               fmt.Fprintf(buf, "[%d]", t.len)
-               writeType(buf, t.elem, qf, visited)
+               w.byte('[')
+               w.string(strconv.FormatInt(t.len, 10))
+               w.byte(']')
+               w.typ(t.elem)
 
        case *Slice:
-               buf.WriteString("[]")
-               writeType(buf, t.elem, qf, visited)
+               w.string("[]")
+               w.typ(t.elem)
 
        case *Struct:
-               buf.WriteString("struct{")
+               w.string("struct{")
                for i, f := range t.fields {
                        if i > 0 {
-                               buf.WriteString("; ")
+                               w.byte(';')
                        }
                        // This doesn't do the right thing for embedded type
                        // aliases where we should print the alias name, not
                        // the aliased type (see issue #44410).
                        if !f.embedded {
-                               buf.WriteString(f.name)
-                               buf.WriteByte(' ')
+                               w.string(f.name)
+                               w.byte(' ')
                        }
-                       writeType(buf, f.typ, qf, visited)
+                       w.typ(f.typ)
                        if tag := t.Tag(i); tag != "" {
-                               fmt.Fprintf(buf, " %q", tag)
+                               w.byte(' ')
+                               // TODO(gri) If tag contains blanks, replacing them with '#'
+                               //           in Context.TypeHash may produce another tag
+                               //           accidentally.
+                               w.string(strconv.Quote(tag))
                        }
                }
-               buf.WriteByte('}')
+               w.byte('}')
 
        case *Pointer:
-               buf.WriteByte('*')
-               writeType(buf, t.base, qf, visited)
+               w.byte('*')
+               w.typ(t.base)
 
        case *Tuple:
-               writeTuple(buf, t, false, qf, visited)
+               w.tuple(t, false)
 
        case *Signature:
-               buf.WriteString("func")
-               writeSignature(buf, t, qf, visited)
+               w.string("func")
+               w.signature(t)
 
        case *Union:
                // Unions only appear as (syntactic) embedded elements
                // in interfaces and syntactically cannot be empty.
                if t.Len() == 0 {
-                       panic("empty union")
+                       w.error("empty union")
+                       break
                }
                for i, t := range t.terms {
                        if i > 0 {
-                               buf.WriteByte('|')
+                               w.byte('|')
                        }
                        if t.tilde {
-                               buf.WriteByte('~')
+                               w.byte('~')
                        }
-                       writeType(buf, t.typ, qf, visited)
+                       w.typ(t.typ)
                }
 
        case *Interface:
-               buf.WriteString("interface{")
+               if t.implicit {
+                       if len(t.methods) == 0 && len(t.embeddeds) == 1 {
+                               w.typ(t.embeddeds[0])
+                               break
+                       }
+                       // Something's wrong with the implicit interface.
+                       // Print it as such and continue.
+                       w.string("/* implicit */ ")
+               }
+               w.string("interface{")
                first := true
                for _, m := range t.methods {
                        if !first {
-                               buf.WriteString("; ")
+                               w.byte(';')
                        }
                        first = false
-                       buf.WriteString(m.name)
-                       writeSignature(buf, m.typ.(*Signature), qf, visited)
+                       w.string(m.name)
+                       w.signature(m.typ.(*Signature))
                }
                for _, typ := range t.embeddeds {
                        if !first {
-                               buf.WriteString("; ")
+                               w.byte(';')
                        }
                        first = false
-                       writeType(buf, typ, qf, visited)
+                       w.typ(typ)
                }
-               buf.WriteByte('}')
+               w.byte('}')
 
        case *Map:
-               buf.WriteString("map[")
-               writeType(buf, t.key, qf, visited)
-               buf.WriteByte(']')
-               writeType(buf, t.elem, qf, visited)
+               w.string("map[")
+               w.typ(t.key)
+               w.byte(']')
+               w.typ(t.elem)
 
        case *Chan:
                var s string
@@ -183,183 +246,142 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                case RecvOnly:
                        s = "<-chan "
                default:
-                       unreachable()
+                       w.error("unknown channel direction")
                }
-               buf.WriteString(s)
+               w.string(s)
                if parens {
-                       buf.WriteByte('(')
+                       w.byte('(')
                }
-               writeType(buf, t.elem, qf, visited)
+               w.typ(t.elem)
                if parens {
-                       buf.WriteByte(')')
+                       w.byte(')')
                }
 
        case *Named:
-               if t.instance != nil {
-                       buf.WriteByte(instanceMarker)
-               }
-               writeTypeName(buf, t.obj, qf)
+               w.typePrefix(t)
+               w.typeName(t.obj)
                if t.targs != nil {
                        // instantiated type
-                       buf.WriteByte('[')
-                       writeTypeList(buf, t.targs, qf, visited)
-                       buf.WriteByte(']')
-               } else if t.TParams().Len() != 0 {
+                       w.typeList(t.targs.list())
+               } else if w.ctxt == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TParams
                        // parameterized type
-                       writeTParamList(buf, t.TParams().list(), qf, visited)
+                       w.tParamList(t.TypeParams().list())
                }
 
        case *TypeParam:
-               s := "?"
-               if t.obj != nil {
-                       // Optionally write out package for typeparams (like Named).
-                       // TODO(danscales): this is required for import/export, so
-                       // we maybe need a separate function that won't be changed
-                       // for debugging purposes.
-                       if t.obj.pkg != nil {
-                               writePackage(buf, t.obj.pkg, qf)
-                       }
-                       s = t.obj.name
+               if t.obj == nil {
+                       w.error("unnamed type parameter")
+                       break
+               }
+               w.string(t.obj.name)
+               if w.debug || w.ctxt != nil {
+                       w.string(subscript(t.id))
                }
-               buf.WriteString(s + subscript(t.id))
-
-       case *top:
-               buf.WriteString("⊤")
 
        default:
                // For externally defined implementations of Type.
                // Note: In this case cycles won't be caught.
-               buf.WriteString(t.String())
+               w.string(t.String())
        }
 }
 
-func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
+// If w.ctxt is non-nil, typePrefix writes a unique prefix for the named type t
+// based on the types already observed by w.ctxt. If w.ctxt is nil, it does
+// nothing.
+func (w *typeWriter) typePrefix(t *Named) {
+       if w.ctxt != nil {
+               w.string(strconv.Itoa(w.ctxt.idForType(t)))
+       }
+}
+
+func (w *typeWriter) typeList(list []Type) {
+       w.byte('[')
        for i, typ := range list {
                if i > 0 {
-                       buf.WriteString(", ")
+                       w.byte(',')
                }
-               writeType(buf, typ, qf, visited)
+               w.typ(typ)
        }
+       w.byte(']')
 }
 
-func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
-       buf.WriteString("[")
+func (w *typeWriter) tParamList(list []*TypeParam) {
+       w.byte('[')
        var prev Type
-       for i, p := range list {
+       for i, tpar := range list {
                // Determine the type parameter and its constraint.
                // list is expected to hold type parameter names,
                // but don't crash if that's not the case.
-               tpar, _ := p.typ.(*TypeParam)
-               var bound Type
-               if tpar != nil {
-                       bound = tpar.bound // should not be nil but we want to see it if it is
+               if tpar == nil {
+                       w.error("nil type parameter")
+                       continue
                }
-
                if i > 0 {
-                       if bound != prev {
+                       if tpar.bound != prev {
                                // bound changed - write previous one before advancing
-                               buf.WriteByte(' ')
-                               writeType(buf, prev, qf, visited)
+                               w.byte(' ')
+                               w.typ(prev)
                        }
-                       buf.WriteString(", ")
-               }
-               prev = bound
-
-               if tpar != nil {
-                       writeType(buf, tpar, qf, visited)
-               } else {
-                       buf.WriteString(p.name)
+                       w.byte(',')
                }
+               prev = tpar.bound
+               w.typ(tpar)
        }
        if prev != nil {
-               buf.WriteByte(' ')
-               writeType(buf, prev, qf, visited)
+               w.byte(' ')
+               w.typ(prev)
        }
-       buf.WriteByte(']')
+       w.byte(']')
 }
 
-func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
-       if obj == nil {
-               buf.WriteString("<Named w/o object>")
-               return
-       }
+func (w *typeWriter) typeName(obj *TypeName) {
        if obj.pkg != nil {
-               writePackage(buf, obj.pkg, qf)
-       }
-       buf.WriteString(obj.name)
-
-       if instanceHashing != 0 {
-               // For local defined types, use the (original!) TypeName's scope
-               // numbers to disambiguate.
-               typ := obj.typ.(*Named)
-               // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
-               //           and whether the loop can iterate more than twice.
-               //           (It seems somehow connected to instance types.)
-               for typ.orig != typ {
-                       typ = typ.orig
-               }
-               writeScopeNumbers(buf, typ.obj.parent)
+               writePackage(w.buf, obj.pkg, w.qf)
        }
+       w.string(obj.name)
 }
 
-// writeScopeNumbers writes the number sequence for this scope to buf
-// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
-// If a scope is nil or has no parent (such as a package scope), nothing
-// is written.
-func writeScopeNumbers(buf *bytes.Buffer, s *Scope) {
-       if s != nil && s.number > 0 {
-               writeScopeNumbers(buf, s.parent)
-               fmt.Fprintf(buf, ".%d", s.number)
-       }
-}
-
-func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
-       buf.WriteByte('(')
+func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
+       w.byte('(')
        if tup != nil {
                for i, v := range tup.vars {
                        if i > 0 {
-                               buf.WriteString(", ")
+                               w.byte(',')
                        }
-                       if v.name != "" {
-                               buf.WriteString(v.name)
-                               buf.WriteByte(' ')
+                       // parameter names are ignored for type identity and thus type hashes
+                       if w.ctxt == nil && v.name != "" {
+                               w.string(v.name)
+                               w.byte(' ')
                        }
                        typ := v.typ
                        if variadic && i == len(tup.vars)-1 {
                                if s, ok := typ.(*Slice); ok {
-                                       buf.WriteString("...")
+                                       w.string("...")
                                        typ = s.elem
                                } else {
                                        // special case:
                                        // append(s, "foo"...) leads to signature func([]byte, string...)
                                        if t := asBasic(typ); t == nil || t.kind != String {
-                                               panic("expected string type")
+                                               w.error("expected string type")
+                                               continue
                                        }
-                                       writeType(buf, typ, qf, visited)
-                                       buf.WriteString("...")
+                                       w.typ(typ)
+                                       w.string("...")
                                        continue
                                }
                        }
-                       writeType(buf, typ, qf, visited)
+                       w.typ(typ)
                }
        }
-       buf.WriteByte(')')
-}
-
-// WriteSignature writes the representation of the signature sig to buf,
-// without a leading "func" keyword.
-// The Qualifier controls the printing of
-// package-level objects, and may be nil.
-func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
-       writeSignature(buf, sig, qf, make([]Type, 0, 8))
+       w.byte(')')
 }
 
-func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
-       if sig.TParams().Len() != 0 {
-               writeTParamList(buf, sig.TParams().list(), qf, visited)
+func (w *typeWriter) signature(sig *Signature) {
+       if sig.TypeParams().Len() != 0 {
+               w.tParamList(sig.TypeParams().list())
        }
 
-       writeTuple(buf, sig.params, sig.variadic, qf, visited)
+       w.tuple(sig.params, sig.variadic)
 
        n := sig.results.Len()
        if n == 0 {
@@ -367,15 +389,15 @@ func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []T
                return
        }
 
-       buf.WriteByte(' ')
-       if n == 1 && sig.results.vars[0].name == "" {
-               // single unnamed result
-               writeType(buf, sig.results.vars[0].typ, qf, visited)
+       w.byte(' ')
+       if n == 1 && (w.ctxt != nil || sig.results.vars[0].name == "") {
+               // single unnamed result (if type hashing, name must be ignored)
+               w.typ(sig.results.vars[0].typ)
                return
        }
 
        // multiple or named result(s)
-       writeTuple(buf, sig.results, false, qf, visited)
+       w.tuple(sig.results, false)
 }
 
 // subscript returns the decimal (utf8) representation of x using subscript digits.
index a53319c153932eb3525fc1272365961789a0dad9..95893fd1e1d50afb8ac9f5c453c87fd9e7096d08 100644 (file)
@@ -28,7 +28,15 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
        switch obj {
        case nil:
                if e.Value == "_" {
-                       check.error(e, "cannot use _ as value or type")
+                       // Blank identifiers are never declared, but the current identifier may
+                       // be a placeholder for a receiver type parameter. In this case we can
+                       // resolve its type and object from Checker.recvTParamMap.
+                       if tpar := check.recvTParamMap[e]; tpar != nil {
+                               x.mode = typexpr
+                               x.typ = tpar
+                       } else {
+                               check.error(e, "cannot use _ as value or type")
+                       }
                } else {
                        if check.conf.CompilerErrorMessages {
                                check.errorf(e, "undefined: %s", e.Value)
@@ -40,12 +48,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
        case universeAny, universeComparable:
                if !check.allowVersion(check.pkg, 1, 18) {
                        check.errorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
-                       return
-               }
-               // If we allow "any" for general use, this if-statement can be removed (issue #33232).
-               if obj == universeAny {
-                       check.error(e, "cannot use any outside constraint position")
-                       return
+                       return // avoid follow-on errors
                }
        }
        check.recordUse(e, obj)
@@ -136,22 +139,17 @@ func (check *Checker) typ(e syntax.Expr) Type {
 }
 
 // varType type-checks the type expression e and returns its type, or Typ[Invalid].
-// The type must not be an (uninstantiated) generic type and it must be ordinary
-// (see ordinaryType).
+// The type must not be an (uninstantiated) generic type and it must not be a
+// constraint interface.
 func (check *Checker) varType(e syntax.Expr) Type {
        typ := check.definedType(e, nil)
-       check.ordinaryType(syntax.StartPos(e), typ)
-       return typ
-}
 
-// ordinaryType reports an error if typ is an interface type containing
-// type lists or is (or embeds) the predeclared type comparable.
-func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
-       // We don't want to call under() (via asInterface) or complete interfaces while we
+       // We don't want to call under() (via toInterface) or complete interfaces while we
        // are in the middle of type-checking parameter declarations that might belong to
        // interface methods. Delay this check to the end of type-checking.
        check.later(func() {
                if t := asInterface(typ); t != nil {
+                       pos := syntax.StartPos(e)
                        tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position?
                        if !tset.IsMethodSet() {
                                if tset.comparable {
@@ -162,14 +160,7 @@ func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
                        }
                }
        })
-}
 
-// anyType type-checks the type expression e and returns its type, or Typ[Invalid].
-// The type may be generic or instantiated.
-func (check *Checker) anyType(e syntax.Expr) Type {
-       typ := check.typInternal(e, nil)
-       assert(isTyped(typ))
-       check.recordTypeAndValue(e, typexpr, typ, nil)
        return typ
 }
 
@@ -223,8 +214,6 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
                        if T != nil {
                                // Calling under() here may lead to endless instantiations.
                                // Test case: type T[P any] *T[P]
-                               // TODO(gri) investigate if that's a bug or to be expected
-                               // (see also analogous comment in Checker.instantiate).
                                under = safeUnderlying(T)
                        }
                        if T == under {
@@ -274,6 +263,9 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
                }
 
        case *syntax.IndexExpr:
+               if !check.allowVersion(check.pkg, 1, 18) {
+                       check.softErrorf(e.Pos(), "type instantiation requires go1.18 or later")
+               }
                return check.instantiatedType(e.X, unpackExpr(e.Index), def)
 
        case *syntax.ParenExpr:
@@ -320,6 +312,13 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
                        typ := new(Pointer)
                        def.setUnderlying(typ)
                        typ.base = check.varType(e.X)
+                       // If typ.base is invalid, it's unlikely that *base is particularly
+                       // useful - even a valid dereferenciation will lead to an invalid
+                       // type again, and in some cases we get unexpected follow-on errors
+                       // (e.g., see #49005). Return an invalid type instead.
+                       if typ.base == Typ[Invalid] {
+                               return Typ[Invalid]
+                       }
                        return typ
                }
 
@@ -397,37 +396,24 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
        return typ
 }
 
-// typeOrNil type-checks the type expression (or nil value) e
-// and returns the type of e, or nil. If e is a type, it must
-// not be an (uninstantiated) generic type.
-// If e is neither a type nor nil, typeOrNil returns Typ[Invalid].
-// TODO(gri) should we also disallow non-var types?
-func (check *Checker) typOrNil(e syntax.Expr) Type {
-       var x operand
-       check.rawExpr(&x, e, nil)
-       switch x.mode {
-       case invalid:
-               // ignore - error reported before
-       case novalue:
-               check.errorf(&x, "%s used as type", &x)
-       case typexpr:
-               check.instantiatedOperand(&x)
-               return x.typ
-       case nilvalue:
-               return nil
-       default:
-               check.errorf(&x, "%s is not a type", &x)
+func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def *Named) (res Type) {
+       if check.conf.Trace {
+               check.trace(x.Pos(), "-- instantiating %s with %s", x, targsx)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       // Don't format the underlying here. It will always be nil.
+                       check.trace(x.Pos(), "=> %s", res)
+               }()
        }
-       return Typ[Invalid]
-}
 
-func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def *Named) Type {
        gtyp := check.genericType(x, true)
        if gtyp == Typ[Invalid] {
                return gtyp // error already reported
        }
-       base, _ := gtyp.(*Named)
-       if base == nil {
+
+       origin, _ := gtyp.(*Named)
+       if origin == nil {
                panic(fmt.Sprintf("%v: cannot instantiate %v", x.Pos(), gtyp))
        }
 
@@ -441,25 +427,83 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def
        // determine argument positions
        posList := make([]syntax.Pos, len(targs))
        for i, arg := range targsx {
-               posList[i] = syntax.StartPos(arg)
+               posList[i] = arg.Pos()
        }
 
-       typ := check.instantiateLazy(x.Pos(), base, targs, posList, true)
-       def.setUnderlying(typ)
+       // create the instance
+       h := check.conf.Context.TypeHash(origin, targs)
+       // targs may be incomplete, and require inference. In any case we should de-duplicate.
+       inst := check.conf.Context.typeForHash(h, nil)
+       // If inst is non-nil, we can't just return here. Inst may have been
+       // constructed via recursive substitution, in which case we wouldn't do the
+       // validation below. Ensure that the validation (and resulting errors) runs
+       // for each instantiated type in the source.
+       if inst == nil {
+               tname := NewTypeName(x.Pos(), origin.obj.pkg, origin.obj.name, nil)
+               inst = check.newNamed(tname, origin, nil, nil, nil) // underlying, methods and tparams are set when named is resolved
+               inst.targs = NewTypeList(targs)
+               inst = check.conf.Context.typeForHash(h, inst)
+       }
+       def.setUnderlying(inst)
+
+       inst.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, []*Func) {
+               tparams := origin.TypeParams().list()
+
+               inferred := targs
+               if len(targs) < len(tparams) {
+                       // If inference fails, len(inferred) will be 0, and inst.underlying will
+                       // be set to Typ[Invalid] in expandNamed.
+                       inferred = check.infer(x.Pos(), tparams, targs, nil, nil)
+                       if len(inferred) > len(targs) {
+                               inst.targs = NewTypeList(inferred)
+                       }
+               }
 
-       // make sure we check instantiation works at least once
-       // and that the resulting type is valid
+               check.recordInstance(x, inferred, inst)
+               return expandNamed(ctxt, n, x.Pos())
+       }
+
+       // origin.tparams may not be set up, so we need to do expansion later.
        check.later(func() {
-               check.validType(typ, nil)
+               // This is an instance from the source, not from recursive substitution,
+               // and so it must be resolved during type-checking so that we can report
+               // errors.
+               inst.resolve(check.conf.Context)
+               // Since check is non-nil, we can still mutate inst. Unpinning the resolver
+               // frees some memory.
+               inst.resolver = nil
+
+               if check.validateTArgLen(x.Pos(), inst.tparams.Len(), inst.targs.Len()) {
+                       if i, err := check.verify(x.Pos(), inst.tparams.list(), inst.targs.list()); err != nil {
+                               // best position for error reporting
+                               pos := x.Pos()
+                               if i < len(posList) {
+                                       pos = posList[i]
+                               }
+                               check.softErrorf(pos, err.Error())
+                       } else {
+                               check.mono.recordInstance(check.pkg, x.Pos(), inst.tparams.list(), inst.targs.list(), posList)
+                       }
+               }
+
+               check.validType(inst, nil)
        })
 
-       return typ
+       return inst
 }
 
 // arrayLength type-checks the array length expression e
 // and returns the constant length >= 0, or a value < 0
 // to indicate an error (and thus an unknown length).
 func (check *Checker) arrayLength(e syntax.Expr) int64 {
+       // If e is an undeclared identifier, the array declaration might be an
+       // attempt at a parameterized type declaration with missing constraint.
+       // Provide a better error message than just "undeclared name: X".
+       if name, _ := e.(*syntax.Name); name != nil && check.lookup(name.Value) == nil {
+               check.errorf(name, "undeclared name %s for array length", name.Value)
+               return -1
+       }
+
        var x operand
        check.expr(&x, e)
        if x.mode != constant_ {
@@ -468,6 +512,7 @@ func (check *Checker) arrayLength(e syntax.Expr) int64 {
                }
                return -1
        }
+
        if isUntyped(x.typ) || isInteger(x.typ) {
                if val := constant.ToInt(x.val); val.Kind() == constant.Int {
                        if representableConst(val, check, Typ[Int], nil) {
@@ -479,6 +524,7 @@ func (check *Checker) arrayLength(e syntax.Expr) int64 {
                        }
                }
        }
+
        check.errorf(&x, "array length %s must be integer", &x)
        return -1
 }
index 710fc51b53fe3bfbd0a3a165ba7bc800f4237648..7f636c30d3f9a5c598075865a058721bbfa9ae75 100644 (file)
@@ -62,7 +62,7 @@ func (u *unifier) unify(x, y Type) bool {
 // A tparamsList describes a list of type parameters and the types inferred for them.
 type tparamsList struct {
        unifier *unifier
-       tparams []*TypeName
+       tparams []*TypeParam
        // For each tparams element, there is a corresponding type slot index in indices.
        // index  < 0: unifier.types[-index-1] == nil
        // index == 0: no type slot allocated yet
@@ -76,29 +76,30 @@ type tparamsList struct {
 // String returns a string representation for a tparamsList. For debugging.
 func (d *tparamsList) String() string {
        var buf bytes.Buffer
-       buf.WriteByte('[')
-       for i, tname := range d.tparams {
+       w := newTypeWriter(&buf, nil)
+       w.byte('[')
+       for i, tpar := range d.tparams {
                if i > 0 {
-                       buf.WriteString(", ")
+                       w.string(", ")
                }
-               writeType(&buf, tname.typ, nil, nil)
-               buf.WriteString(": ")
-               writeType(&buf, d.at(i), nil, nil)
+               w.typ(tpar)
+               w.string(": ")
+               w.typ(d.at(i))
        }
-       buf.WriteByte(']')
+       w.byte(']')
        return buf.String()
 }
 
 // init initializes d with the given type parameters.
 // The type parameters must be in the order in which they appear in their declaration
 // (this ensures that the tparams indices match the respective type parameter index).
-func (d *tparamsList) init(tparams []*TypeName) {
+func (d *tparamsList) init(tparams []*TypeParam) {
        if len(tparams) == 0 {
                return
        }
        if debug {
                for i, tpar := range tparams {
-                       assert(i == tpar.typ.(*TypeParam).index)
+                       assert(i == tpar.index)
                }
        }
        d.tparams = tparams
@@ -107,7 +108,7 @@ func (d *tparamsList) init(tparams []*TypeName) {
 
 // join unifies the i'th type parameter of x with the j'th type parameter of y.
 // If both type parameters already have a type associated with them and they are
-// not joined, join fails and return false.
+// not joined, join fails and returns false.
 func (u *unifier) join(i, j int) bool {
        ti := u.x.indices[i]
        tj := u.y.indices[j]
@@ -131,6 +132,7 @@ func (u *unifier) join(i, j int) bool {
                break
        case ti > 0 && tj > 0:
                // Both type parameters have (possibly different) inferred types. Cannot join.
+               // TODO(gri) Should we check if types are identical? Investigate.
                return false
        case ti > 0:
                // Only the type parameter for x has an inferred type. Use x slot for y.
@@ -158,8 +160,8 @@ func (d *tparamsList) index(typ Type) int {
 
 // If tpar is a type parameter in list, tparamIndex returns the type parameter index.
 // Otherwise, the result is < 0. tpar must not be nil.
-func tparamIndex(list []*TypeName, tpar *TypeParam) int {
-       if i := tpar.index; i < len(list) && list[i].typ == tpar {
+func tparamIndex(list []*TypeParam, tpar *TypeParam) int {
+       if i := tpar.index; i < len(list) && list[i] == tpar {
                return i
        }
        return -1
@@ -225,7 +227,7 @@ func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
 }
 
 // nify implements the core unification algorithm which is an
-// adapted version of Checker.identical0. For changes to that
+// adapted version of Checker.identical. For changes to that
 // code the corresponding changes should be made here.
 // Must not be called directly from outside the unifier.
 func (u *unifier) nify(x, y Type, p *ifacePair) bool {
@@ -233,13 +235,13 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                // If exact unification is known to fail because we attempt to
                // match a type name against an unnamed type literal, consider
                // the underlying type of the named type.
-               // (Subtle: We use isNamed to include any type with a name (incl.
+               // (Subtle: We use hasName to include any type with a name (incl.
                // basic types and type parameters. We use asNamed because we only
                // want *Named types.)
                switch {
-               case !isNamed(x) && y != nil && asNamed(y) != nil:
+               case !hasName(x) && y != nil && asNamed(y) != nil:
                        return u.nify(x, under(y), p)
-               case x != nil && asNamed(x) != nil && !isNamed(y):
+               case x != nil && asNamed(x) != nil && !hasName(y):
                        return u.nify(under(x), y, p)
                }
        }
@@ -426,16 +428,18 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                }
 
        case *Named:
+               // TODO(gri) This code differs now from the parallel code in Checker.identical. Investigate.
                if y, ok := y.(*Named); ok {
-                       x.expand(nil)
-                       y.expand(nil)
+                       xargs := x.targs.list()
+                       yargs := y.targs.list()
+
                        // TODO(gri) This is not always correct: two types may have the same names
                        //           in the same package if one of them is nested in a function.
                        //           Extremely unlikely but we need an always correct solution.
                        if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
-                               assert(len(x.targs) == len(y.targs))
-                               for i, x := range x.targs {
-                                       if !u.nify(x, y.targs[i], p) {
+                               assert(len(xargs) == len(yargs))
+                               for i, x := range xargs {
+                                       if !u.nify(x, yargs[i], p) {
                                                return false
                                        }
                                }
index f61c37a6afd97f760ad950c155284eb8f36da812..5379bde02c5db0d448cca75cfb1ad9427ba76277 100644 (file)
@@ -11,8 +11,8 @@ import "cmd/compile/internal/syntax"
 
 // A Union represents a union of terms embedded in an interface.
 type Union struct {
-       terms []*Term  // list of syntactical terms (not a canonicalized termlist)
-       tset  *TypeSet // type set described by this union, computed lazily
+       terms []*Term   // list of syntactical terms (not a canonicalized termlist)
+       tset  *_TypeSet // type set described by this union, computed lazily
 }
 
 // NewUnion returns a new Union type with the given terms.
@@ -54,7 +54,10 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type {
        for _, x := range tlist {
                tilde, typ := parseTilde(check, x)
                if len(tlist) == 1 && !tilde {
-                       return typ // single type (optimization)
+                       // Single type. Ok to return early because all relevant
+                       // checks have been performed in parseTilde (no need to
+                       // run through term validity check below).
+                       return typ
                }
                if len(terms) >= maxTermCount {
                        check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
@@ -72,28 +75,16 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type {
                                continue
                        }
 
-                       x := tlist[i]
-                       pos := syntax.StartPos(x)
-                       // We may not know the position of x if it was a typechecker-
-                       // introduced ~T term for a type list entry T. Use the position
-                       // of T instead.
-                       // TODO(gri) remove this test once we don't support type lists anymore
-                       if !pos.IsKnown() {
-                               if op, _ := x.(*syntax.Operation); op != nil {
-                                       pos = syntax.StartPos(op.X)
-                               }
-                       }
-
                        u := under(t.typ)
                        f, _ := u.(*Interface)
                        if t.tilde {
                                if f != nil {
-                                       check.errorf(x, "invalid use of ~ (%s is an interface)", t.typ)
+                                       check.errorf(tlist[i], "invalid use of ~ (%s is an interface)", t.typ)
                                        continue // don't report another error for t
                                }
 
                                if !Identical(u, t.typ) {
-                                       check.errorf(x, "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
+                                       check.errorf(tlist[i], "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
                                        continue // don't report another error for t
                                }
                        }
@@ -102,14 +93,14 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type {
                        // in the beginning. Embedded interfaces with tilde are excluded above. If we reach
                        // here, we must have at least two terms in the union.
                        if f != nil && !f.typeSet().IsTypeSet() {
-                               check.errorf(pos, "cannot use %s in union (interface contains methods)", t)
+                               check.errorf(tlist[i], "cannot use %s in union (interface contains methods)", t)
                                continue // don't report another error for t
                        }
 
                        // Report overlapping (non-disjoint) terms such as
                        // a|a, a|~a, ~a|~a, and ~a|A (where under(A) == a).
                        if j := overlappingTerm(terms[:i], t); j >= 0 {
-                               check.softErrorf(pos, "overlapping terms %s and %s", t, terms[j])
+                               check.softErrorf(tlist[i], "overlapping terms %s and %s", t, terms[j])
                        }
                }
        })
@@ -122,12 +113,17 @@ func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) {
                x = op.X
                tilde = true
        }
-       typ = check.anyType(x)
-       // embedding stand-alone type parameters is not permitted (issue #47127).
-       if _, ok := under(typ).(*TypeParam); ok {
-               check.error(x, "cannot embed a type parameter")
-               typ = Typ[Invalid]
-       }
+       typ = check.typ(x)
+       // Embedding stand-alone type parameters is not permitted (issue #47127).
+       // Do this check later because it requires computation of the underlying type (see also issue #46461).
+       // Note: If an underlying type cannot be a type parameter, the call to
+       //       under() will not be needed and then we don't need to delay this
+       //       check to later and could return Typ[Invalid] instead.
+       check.later(func() {
+               if _, ok := under(typ).(*TypeParam); ok {
+                       check.error(x, "cannot embed a type parameter")
+               }
+       })
        return
 }
 
index f14c0792229ce56417ef326819de51d65f27962c..92fa32524c03d158681d465d28a6cb929406c00f 100644 (file)
@@ -86,9 +86,9 @@ func defPredeclaredTypes() {
                obj := NewTypeName(nopos, nil, "error", nil)
                obj.setColor(black)
                res := NewVar(nopos, nil, "", Typ[String])
-               sig := NewSignature(nil, nil, NewTuple(res), false)
+               sig := NewSignatureType(nil, nil, nil, nil, NewTuple(res), false)
                err := NewFunc(nopos, nil, "Error", sig)
-               ityp := &Interface{obj, []*Func{err}, nil, nil, true, nil}
+               ityp := &Interface{nil, obj, []*Func{err}, nil, nil, false, true, nil}
                computeInterfaceTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset
                typ := NewNamed(obj, ityp, nil)
                sig.recv = NewVar(nopos, nil, "", typ)
@@ -99,7 +99,7 @@ func defPredeclaredTypes() {
        {
                obj := NewTypeName(nopos, nil, "comparable", nil)
                obj.setColor(black)
-               ityp := &Interface{obj, nil, nil, nil, true, &TypeSet{true, nil, allTermlist}}
+               ityp := &Interface{nil, obj, nil, nil, nil, false, true, &_TypeSet{true, nil, allTermlist}}
                NewNamed(obj, ityp, nil)
                def(obj)
        }
index d4c1aafdc121dcbb9226341618e94c0f1c6bc67f..9350c389c162d6f3bbccee60d84014c9e4442b83 100644 (file)
@@ -167,7 +167,7 @@ func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
        a := n.Lhs[0]
 
        var call *ir.CallExpr
-       if w := t.Elem().Width; w <= zeroValSize {
+       if w := t.Elem().Size(); w <= zeroValSize {
                fn := mapfn(mapaccess2[fast], t, false)
                call = mkcall1(fn, fn.Type().Results(), init, reflectdata.TypePtr(t), r.X, key)
        } else {
@@ -533,7 +533,7 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
 
                fn := typecheck.LookupRuntime("slicecopy")
                fn = typecheck.SubstArgTypes(fn, ptr1.Type().Elem(), ptr2.Type().Elem())
-               ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(elemtype.Width))
+               ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(elemtype.Size()))
        } else {
                // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
                ix := ir.NewIndexExpr(base.Pos, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1))
@@ -543,7 +543,7 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
                sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, l2)
 
                nwid := cheapExpr(typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, l2), types.Types[types.TUINTPTR]), &nodes)
-               nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(elemtype.Width))
+               nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(elemtype.Size()))
 
                // instantiate func memmove(to *any, frm *any, length uintptr)
                fn := typecheck.LookupRuntime("memmove")
@@ -690,7 +690,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
        hp := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
 
        // hn := l2 * sizeof(elem(s))
-       hn := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(elemtype.Width)), types.Types[types.TUINTPTR])
+       hn := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(elemtype.Size())), types.Types[types.TUINTPTR])
 
        clrname := "memclrNoHeapPointers"
        hasPointers := elemtype.HasPointers()
index af4f8f482286629dd6df9f0b6d8ac6e0d41604f8..d0aaee03d59d07b4bd39ef861f1ea62ccc5fae30 100644 (file)
@@ -158,7 +158,7 @@ func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
                fn := typecheck.LookupRuntime("slicecopy")
                fn = typecheck.SubstArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
 
-               return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(n.X.Type().Elem().Width))
+               return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(n.X.Type().Elem().Size()))
        }
 
        n.X = walkExpr(n.X, init)
@@ -194,7 +194,7 @@ func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
        nwid := ir.Node(typecheck.Temp(types.Types[types.TUINTPTR]))
        setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
        ne.Body.Append(setwid)
-       nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(nl.Type().Elem().Width))
+       nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(nl.Type().Elem().Size()))
        call := mkcall1(fn, nil, init, nto, nfrm, nwid)
        ne.Body.Append(call)
 
@@ -452,7 +452,7 @@ func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
                // 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 := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(t.Elem().Width), types.Types[types.TUINTPTR]))
+               size := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(t.Elem().Size()), types.Types[types.TUINTPTR]))
 
                // instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
                fn := typecheck.LookupRuntime("mallocgc")
@@ -622,10 +622,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
                r := ir.NewCallExpr(base.Pos, ir.OCALL, on, nil)
                if params := on.Type().Params().FieldSlice(); len(params) > 0 {
                        t := params[0].Type
-                       if !types.Identical(t, n.Type()) {
-                               n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
-                               n.SetType(t)
-                       }
+                       n = typecheck.Conv(n, t)
                        r.Args.Append(n)
                }
                calls = append(calls, r)
index 902e01ef388ee39ee5046905c1edd024cd27921d..4d1c5621fec857fe3a9487bf9da3c422367e08d5 100644 (file)
@@ -107,7 +107,16 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
        // The closure is not trivial or directly called, so it's going to stay a closure.
        ir.ClosureDebugRuntimeCheck(clo)
        clofn.SetNeedctxt(true)
-       ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
+
+       // The closure expression may be walked more than once if it appeared in composite
+       // literal initialization (e.g, see issue #49029).
+       //
+       // Don't add the closure function to compilation queue more than once, since when
+       // compiling a function twice would lead to an ICE.
+       if !clofn.Walked() {
+               clofn.SetWalked(true)
+               ir.CurFunc.Closures = append(ir.CurFunc.Closures, clofn)
+       }
 
        typ := typecheck.ClosureType(clo)
 
@@ -218,6 +227,10 @@ func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name {
        }
        sym.SetUniq(true)
 
+       if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
+               base.FatalfAt(dot.Pos(), "missing wrapper for %v", meth)
+       }
+
        savecurfn := ir.CurFunc
        saveLineNo := base.Pos
        ir.CurFunc = nil
index b18615f61a3e3b4d0ca988193c1114d3b6d1fb86..625e2160503754b6c2beb0452e0ecddf0b2b280d 100644 (file)
@@ -5,7 +5,6 @@
 package walk
 
 import (
-       "encoding/binary"
        "go/constant"
 
        "cmd/compile/internal/base"
@@ -14,7 +13,6 @@ import (
        "cmd/compile/internal/ssagen"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
-       "cmd/internal/sys"
 )
 
 // The result of walkCompare MUST be assigned back to n, e.g.
@@ -81,7 +79,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
        var inline bool
 
        maxcmpsize := int64(4)
-       unalignedLoad := canMergeLoads()
+       unalignedLoad := ssagen.Arch.LinkArch.CanMergeLoads
        if unalignedLoad {
                // Keep this low enough to generate less code than a function call.
                maxcmpsize = 2 * int64(ssagen.Arch.LinkArch.RegSize)
@@ -138,7 +136,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                return n
        case types.TARRAY:
                // We can compare several elements at once with 2/4/8 byte integer compares
-               inline = t.NumElem() <= 1 || (types.IsSimple[t.Elem().Kind()] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize))
+               inline = t.NumElem() <= 1 || (types.IsSimple[t.Elem().Kind()] && (t.NumElem() <= 4 || t.Elem().Size()*t.NumElem() <= maxcmpsize))
        case types.TSTRUCT:
                inline = t.NumComponents(types.IgnoreBlankFields) <= 4
        }
@@ -164,7 +162,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                call.Args.Append(typecheck.NodAddr(cmpl))
                call.Args.Append(typecheck.NodAddr(cmpr))
                if needsize {
-                       call.Args.Append(ir.NewInt(t.Width))
+                       call.Args.Append(ir.NewInt(t.Size()))
                }
                res := ir.Node(call)
                if n.Op() != ir.OEQ {
@@ -202,22 +200,22 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                }
        } else {
                step := int64(1)
-               remains := t.NumElem() * t.Elem().Width
-               combine64bit := unalignedLoad && types.RegSize == 8 && t.Elem().Width <= 4 && t.Elem().IsInteger()
-               combine32bit := unalignedLoad && t.Elem().Width <= 2 && t.Elem().IsInteger()
-               combine16bit := unalignedLoad && t.Elem().Width == 1 && t.Elem().IsInteger()
+               remains := t.NumElem() * t.Elem().Size()
+               combine64bit := unalignedLoad && types.RegSize == 8 && t.Elem().Size() <= 4 && t.Elem().IsInteger()
+               combine32bit := unalignedLoad && t.Elem().Size() <= 2 && t.Elem().IsInteger()
+               combine16bit := unalignedLoad && t.Elem().Size() == 1 && t.Elem().IsInteger()
                for i := int64(0); remains > 0; {
                        var convType *types.Type
                        switch {
                        case remains >= 8 && combine64bit:
                                convType = types.Types[types.TINT64]
-                               step = 8 / t.Elem().Width
+                               step = 8 / t.Elem().Size()
                        case remains >= 4 && combine32bit:
                                convType = types.Types[types.TUINT32]
-                               step = 4 / t.Elem().Width
+                               step = 4 / t.Elem().Size()
                        case remains >= 2 && combine16bit:
                                convType = types.Types[types.TUINT16]
-                               step = 2 / t.Elem().Width
+                               step = 2 / t.Elem().Size()
                        default:
                                step = 1
                        }
@@ -227,7 +225,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                                        ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i)),
                                )
                                i++
-                               remains -= t.Elem().Width
+                               remains -= t.Elem().Size()
                        } else {
                                elemType := t.Elem().ToUnsigned()
                                cmplw := ir.Node(ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i)))
@@ -242,17 +240,17 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                                        lb := ir.Node(ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i+offset)))
                                        lb = typecheck.Conv(lb, elemType)
                                        lb = typecheck.Conv(lb, convType)
-                                       lb = ir.NewBinaryExpr(base.Pos, ir.OLSH, lb, ir.NewInt(8*t.Elem().Width*offset))
+                                       lb = ir.NewBinaryExpr(base.Pos, ir.OLSH, lb, ir.NewInt(8*t.Elem().Size()*offset))
                                        cmplw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmplw, lb)
                                        rb := ir.Node(ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i+offset)))
                                        rb = typecheck.Conv(rb, elemType)
                                        rb = typecheck.Conv(rb, convType)
-                                       rb = ir.NewBinaryExpr(base.Pos, ir.OLSH, rb, ir.NewInt(8*t.Elem().Width*offset))
+                                       rb = ir.NewBinaryExpr(base.Pos, ir.OLSH, rb, ir.NewInt(8*t.Elem().Size()*offset))
                                        cmprw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmprw, rb)
                                }
                                compare(cmplw, cmprw)
                                i += step
-                               remains -= step * t.Elem().Width
+                               remains -= step * t.Elem().Size()
                        }
                }
        }
@@ -311,7 +309,7 @@ func walkCompareString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
                maxRewriteLen := 6
                // Some architectures can load unaligned byte sequence as 1 word.
                // So we can cover longer strings with the same amount of code.
-               canCombineLoads := canMergeLoads()
+               canCombineLoads := ssagen.Arch.LinkArch.CanMergeLoads
                combine64bit := false
                if canCombineLoads {
                        // Keep this low enough to generate less code than a function call.
@@ -491,18 +489,3 @@ func tracecmpArg(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
 
        return typecheck.Conv(n, t)
 }
-
-// canMergeLoads reports whether the backend optimization passes for
-// the current architecture can combine adjacent loads into a single
-// larger, possibly unaligned, load. Note that currently the
-// optimizations must be able to handle little endian byte order.
-func canMergeLoads() bool {
-       switch ssagen.Arch.LinkArch.Family {
-       case sys.ARM64, sys.AMD64, sys.I386, sys.S390X:
-               return true
-       case sys.PPC64:
-               // Load combining only supported on ppc64le.
-               return ssagen.Arch.LinkArch.ByteOrder == binary.LittleEndian
-       }
-       return false
-}
index 6c6b4982a059714faa7ab4545ccab6cfc970a12d..b985b4caeb8597ec7387cb7ca24eb4cde01e5c0d 100644 (file)
@@ -277,7 +277,7 @@ func isSmallSliceLit(n *ir.CompLitExpr) bool {
                return false
        }
 
-       return n.Type().Elem().Width == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Width
+       return n.Type().Elem().Size() == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Size()
 }
 
 func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
@@ -440,8 +440,8 @@ func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
                tk := types.NewArray(n.Type().Key(), int64(len(entries)))
                te := types.NewArray(n.Type().Elem(), int64(len(entries)))
 
-               tk.SetNoalg(true)
-               te.SetNoalg(true)
+               // TODO(#47904): mark tk and te NoAlg here once the
+               // compiler/linker can handle NoAlg types correctly.
 
                types.CalcSize(tk)
                types.CalcSize(te)
@@ -482,7 +482,7 @@ func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
 
                loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil)
                loop.Body = []ir.Node{body}
-               *loop.PtrInit() = []ir.Node{zero}
+               loop.SetInit([]ir.Node{zero})
 
                appendWalkStmt(init, loop)
                return
@@ -650,7 +650,7 @@ func genAsStatic(as *ir.AssignStmt) {
 
        switch r := as.Y; r.Op() {
        case ir.OLITERAL:
-               staticdata.InitConst(name, offset, r, int(r.Type().Width))
+               staticdata.InitConst(name, offset, r, int(r.Type().Size()))
                return
        case ir.OMETHEXPR:
                r := r.(*ir.SelectorExpr)
index 27a07ce4b6085031262d6e8590703fcceaa0114b..ffc5fd19e801dcfbc2bdd046bc43eb3fda9104c7 100644 (file)
@@ -14,6 +14,7 @@ import (
        "cmd/compile/internal/ssagen"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
+       "cmd/internal/src"
        "cmd/internal/sys"
 )
 
@@ -24,9 +25,6 @@ func walkConv(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
                return n.X
        }
        if n.Op() == ir.OCONVNOP && ir.ShouldCheckPtr(ir.CurFunc, 1) {
-               if n.Type().IsPtr() && n.X.Type().IsUnsafePtr() { // unsafe.Pointer to *T
-                       return walkCheckPtrAlignment(n, init, nil)
-               }
                if n.Type().IsUnsafePtr() && n.X.Type().IsUintptr() { // uintptr to unsafe.Pointer
                        return walkCheckPtrArithmetic(n, init)
                }
@@ -58,7 +56,7 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
                } else {
                        typeWord = reflectdata.ITabAddr(fromType, toType)
                }
-               l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, dataWord(n.X, init, n.Esc() != ir.EscNone))
+               l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, dataWord(n.Pos(), n.X, init, n.Esc() != ir.EscNone))
                l.SetType(toType)
                l.SetTypecheck(n.Typecheck())
                return l
@@ -75,7 +73,7 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
        itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
        itab.SetType(types.Types[types.TUINTPTR].PtrTo())
        itab.SetTypecheck(1)
-       data := ir.NewUnaryExpr(base.Pos, ir.OIDATA, c)
+       data := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, c)
        data.SetType(types.Types[types.TUINT8].PtrTo()) // Type is generic pointer - we're just passing it through.
        data.SetTypecheck(1)
 
@@ -112,7 +110,7 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
 // Returns the data word (the second word) used to represent n in an interface.
 // n must not be of interface type.
 // esc describes whether the result escapes.
-func dataWord(n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
+func dataWord(pos src.XPos, n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
        fromType := n.Type()
 
        // If it's a pointer, it is its own representation.
@@ -145,7 +143,7 @@ func dataWord(n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
        case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
                // n is a readonly global; use it directly.
                value = n
-       case !escapes && fromType.Width <= 1024:
+       case !escapes && fromType.Size() <= 1024:
                // n does not escape. Use a stack temporary initialized to n.
                value = typecheck.Temp(fromType)
                init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n)))
@@ -184,16 +182,16 @@ func dataWord(n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
                        fromType.IsPtrShaped() && argType.IsPtrShaped():
                        // can directly convert (e.g. named type to underlying type, or one pointer to another)
                        // TODO: never happens because pointers are directIface?
-                       arg = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType, n)
+                       arg = ir.NewConvExpr(pos, ir.OCONVNOP, argType, n)
                case fromType.IsInteger() && argType.IsInteger():
                        // can directly convert (e.g. int32 to uint32)
-                       arg = ir.NewConvExpr(n.Pos(), ir.OCONV, argType, n)
+                       arg = ir.NewConvExpr(pos, ir.OCONV, argType, n)
                default:
                        // unsafe cast through memory
                        arg = copyExpr(n, fromType, init)
                        var addr ir.Node = typecheck.NodAddr(arg)
-                       addr = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType.PtrTo(), addr)
-                       arg = ir.NewStarExpr(n.Pos(), addr)
+                       addr = ir.NewConvExpr(pos, ir.OCONVNOP, argType.PtrTo(), addr)
+                       arg = ir.NewStarExpr(pos, addr)
                        arg.SetType(argType)
                }
                args = []ir.Node{arg}
@@ -206,7 +204,7 @@ func dataWord(n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
 // walkConvIData walks an OCONVIDATA node.
 func walkConvIData(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
        n.X = walkExpr(n.X, init)
-       return dataWord(n.X, init, n.Esc() != ir.EscNone)
+       return dataWord(n.Pos(), n.X, init, n.Esc() != ir.EscNone)
 }
 
 // walkBytesRunesToString walks an OBYTES2STR or ORUNES2STR node.
@@ -326,11 +324,11 @@ func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, nee
                base.Fatalf("can only handle non-interfaces")
        }
        switch {
-       case from.Size() == 2 && from.Align == 2:
+       case from.Size() == 2 && uint8(from.Alignment()) == 2:
                return "convT16", types.Types[types.TUINT16], false
-       case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
+       case from.Size() == 4 && uint8(from.Alignment()) == 4 && !from.HasPointers():
                return "convT32", types.Types[types.TUINT32], false
-       case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
+       case from.Size() == 8 && uint8(from.Alignment()) == uint8(types.Types[types.TUINT64].Alignment()) && !from.HasPointers():
                return "convT64", types.Types[types.TUINT64], false
        }
        if sc := from.SoleComponent(); sc != nil {
@@ -369,7 +367,7 @@ func rtconvfn(src, dst *types.Type) (param, result types.Kind) {
                if dst.IsFloat() {
                        switch src.Kind() {
                        case types.TINT64, types.TUINT64:
-                               return src.Kind(), types.TFLOAT64
+                               return src.Kind(), dst.Kind()
                        }
                }
 
@@ -385,7 +383,7 @@ func rtconvfn(src, dst *types.Type) (param, result types.Kind) {
                if dst.IsFloat() {
                        switch src.Kind() {
                        case types.TINT64, types.TUINT64:
-                               return src.Kind(), types.TFLOAT64
+                               return src.Kind(), dst.Kind()
                        case types.TUINT32, types.TUINT, types.TUINTPTR:
                                return types.TUINT32, types.TFLOAT64
                        }
@@ -413,32 +411,6 @@ func byteindex(n ir.Node) ir.Node {
        return n
 }
 
-func walkCheckPtrAlignment(n *ir.ConvExpr, init *ir.Nodes, count ir.Node) ir.Node {
-       if !n.Type().IsPtr() {
-               base.Fatalf("expected pointer type: %v", n.Type())
-       }
-       elem := n.Type().Elem()
-       if count != nil {
-               if !elem.IsArray() {
-                       base.Fatalf("expected array type: %v", elem)
-               }
-               elem = elem.Elem()
-       }
-
-       size := elem.Size()
-       if elem.Alignment() == 1 && (size == 0 || size == 1 && count == nil) {
-               return n
-       }
-
-       if count == nil {
-               count = ir.NewInt(1)
-       }
-
-       n.X = cheapExpr(n.X, init)
-       init.Append(mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), reflectdata.TypePtr(elem), typecheck.Conv(count, types.Types[types.TUINTPTR])))
-       return n
-}
-
 func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
        // Calling cheapExpr(n, init) below leads to a recursive call to
        // walkExpr, which leads us back here again. Use n.Checkptr to
index 26e225440a73d5ed2d35c282d4d879222e828944..e5bf6cf0b5e3670a8df0c827f1385ff40251f54d 100644 (file)
@@ -767,7 +767,7 @@ func walkIndexMap(n *ir.IndexExpr, init *ir.Nodes) ir.Node {
                // m[k] is not the target of an assignment.
                fast := mapfast(t)
                key = mapKeyArg(fast, n, key)
-               if w := t.Elem().Width; w <= zeroValSize {
+               if w := t.Elem().Size(); w <= zeroValSize {
                        call = mkcall1(mapfn(mapaccess1[fast], t, false), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key)
                } else {
                        z := reflectdata.ZeroAddr(w)
@@ -807,15 +807,7 @@ func walkSend(n *ir.SendStmt, init *ir.Nodes) ir.Node {
 
 // walkSlice walks an OSLICE, OSLICEARR, OSLICESTR, OSLICE3, or OSLICE3ARR node.
 func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
-
-       checkSlice := ir.ShouldCheckPtr(ir.CurFunc, 1) && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
-       if checkSlice {
-               conv := n.X.(*ir.ConvExpr)
-               conv.X = walkExpr(conv.X, init)
-       } else {
-               n.X = walkExpr(n.X, init)
-       }
-
+       n.X = walkExpr(n.X, init)
        n.Low = walkExpr(n.Low, init)
        if n.Low != nil && ir.IsZero(n.Low) {
                // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
@@ -823,9 +815,6 @@ func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
        }
        n.High = walkExpr(n.High, init)
        n.Max = walkExpr(n.Max, init)
-       if checkSlice {
-               n.X = walkCheckPtrAlignment(n.X.(*ir.ConvExpr), init, n.Max)
-       }
 
        if n.Op().IsSlice3() {
                if n.Max != nil && n.Max.Op() == ir.OCAP && ir.SameSafeExpr(n.X, n.Max.(*ir.UnaryExpr).X) {
@@ -873,7 +862,7 @@ func bounded(n ir.Node, max int64) bool {
        }
 
        sign := n.Type().IsSigned()
-       bits := int32(8 * n.Type().Width)
+       bits := int32(8 * n.Type().Size())
 
        if ir.IsSmallIntConst(n) {
                v := ir.Int64Val(n)
index 6e336f565cf73735c0b46a24eba826aca932d859..861c122456d7648f2fc319beecb77f23004e2ae1 100644 (file)
@@ -14,6 +14,7 @@ import (
        "cmd/compile/internal/staticinit"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
+       "cmd/internal/objabi"
        "cmd/internal/src"
 )
 
@@ -297,7 +298,7 @@ func (o *orderState) mapKeyTemp(t *types.Type, n ir.Node) ir.Node {
                // Unsafe cast through memory.
                // We'll need to do a load with type kt. Create a temporary of type kt to
                // ensure sufficient alignment. nt may be under-aligned.
-               if kt.Align < nt.Align {
+               if uint8(kt.Alignment()) < uint8(nt.Alignment()) {
                        base.Fatalf("mapKeyTemp: key type is not sufficiently aligned, kt=%v nt=%v", kt, nt)
                }
                tmp := o.newTemp(kt, true)
@@ -443,6 +444,13 @@ func (o *orderState) edge() {
        // __libfuzzer_extra_counters.
        counter := staticinit.StaticName(types.Types[types.TUINT8])
        counter.SetLibfuzzerExtraCounter(true)
+       // As well as setting SetLibfuzzerExtraCounter, we preemptively set the
+       // symbol type to SLIBFUZZER_EXTRA_COUNTER so that the race detector
+       // instrumentation pass (which does not have access to the flags set by
+       // SetLibfuzzerExtraCounter) knows to ignore them. This information is
+       // lost by the time it reaches the compile step, so SetLibfuzzerExtraCounter
+       // is still necessary.
+       counter.Linksym().Type = objabi.SLIBFUZZER_EXTRA_COUNTER
 
        // counter += 1
        incr := ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(1))
@@ -941,6 +949,12 @@ func (o *orderState) stmt(n ir.Node) {
                                        if colas {
                                                if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).X == n {
                                                        init = init[1:]
+
+                                                       // iimport may have added a default initialization assignment,
+                                                       // due to how it handles ODCL statements.
+                                                       if len(init) > 0 && init[0].Op() == ir.OAS && init[0].(*ir.AssignStmt).X == n {
+                                                               init = init[1:]
+                                                       }
                                                }
                                                dcl := typecheck.Stmt(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
                                                ncas.PtrInit().Append(dcl)
index b1169fdae8a1aba973a7e3023d56b882634e721b..aa8c5489630829ec8781cd56cd2e694a259e37fe 100644 (file)
@@ -112,7 +112,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
                }
 
                // for v1, v2 := range ha { body }
-               if cheapComputableIndex(t.Elem().Width) {
+               if cheapComputableIndex(t.Elem().Size()) {
                        // v1, v2 = hv1, ha[hv1]
                        tmp := ir.NewIndexExpr(base.Pos, ha, hv1)
                        tmp.SetBounded(true)
@@ -154,7 +154,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
                // This runs *after* the condition check, so we know
                // advancing the pointer is safe and won't go past the
                // end of the allocation.
-               as := ir.NewAssignStmt(base.Pos, hp, addptr(hp, t.Elem().Width))
+               as := ir.NewAssignStmt(base.Pos, hp, addptr(hp, t.Elem().Size()))
                nfor.Late = []ir.Node{typecheck.Stmt(as)}
 
        case types.TMAP:
@@ -408,7 +408,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
                return nil
        }
 
-       elemsize := typecheck.RangeExprType(loop.X.Type()).Elem().Width
+       elemsize := typecheck.RangeExprType(loop.X.Type()).Elem().Size()
        if elemsize <= 0 || !ir.IsZero(stmt.Y) {
                return nil
        }
index d2b67ddf55a7abc8d5ccba5dc9d991aa7cd7fd2e..fde8f5089590fbc2984a6fb2c98d2d1e0e0412f0 100644 (file)
@@ -105,7 +105,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
                n := cas.Comm
                ir.SetPos(n)
                r := ir.NewIfStmt(base.Pos, nil, nil, nil)
-               *r.PtrInit() = cas.Init()
+               r.SetInit(cas.Init())
                var cond ir.Node
                switch n.Op() {
                default:
index 4581bca3dfe42da847008085e9d62f9944305171..f09e9165464bcf9e31979752111a881c5091c84c 100644 (file)
@@ -136,6 +136,14 @@ func walkStmt(n ir.Node) ir.Node {
 
        case ir.OTAILCALL:
                n := n.(*ir.TailCallStmt)
+
+               var init ir.Nodes
+               n.Call.X = walkExpr(n.Call.X, &init)
+
+               if len(init) > 0 {
+                       init.Append(n)
+                       return ir.NewBlockStmt(n.Pos(), init)
+               }
                return n
 
        case ir.OINLMARK:
index 6551fe7a645310ac09df4147eaff07c3f1bb5f41..78cc2e69da091b1acf00109c036980bd69dd665f 100644 (file)
@@ -205,7 +205,7 @@ var mapdelete = mkmapnames("mapdelete", "")
 
 func mapfast(t *types.Type) int {
        // Check runtime/map.go:maxElemSize before changing.
-       if t.Elem().Width > 128 {
+       if t.Elem().Size() > 128 {
                return mapslow
        }
        switch reflectdata.AlgType(t.Key()) {
@@ -312,7 +312,7 @@ func mayCall(n ir.Node) bool {
                        return true
 
                case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR,
-                       ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD, ir.OSLICE2ARRPTR:
+                       ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODYNAMICDOTTYPE, ir.ODIV, ir.OMOD, ir.OSLICE2ARRPTR:
                        // These ops might panic, make sure they are done
                        // before we start marshaling args for a call. See issue 16760.
                        return true
index 0b2ca3fdbb83af3573a2af995d795ffd7bd80718..765051c9445b293e84f372fcd890598c048f3ba3 100644 (file)
@@ -88,13 +88,7 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
        case ssa.BlockRet:
                s.Prog(obj.ARET)
 
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.ARET)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
-
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
 
        case ssa.BlockDefer:
                p := s.Prog(wasm.AGet)
@@ -122,7 +116,7 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
 
 func ssaGenValue(s *ssagen.State, v *ssa.Value) {
        switch v.Op {
-       case ssa.OpWasmLoweredStaticCall, ssa.OpWasmLoweredClosureCall, ssa.OpWasmLoweredInterCall:
+       case ssa.OpWasmLoweredStaticCall, ssa.OpWasmLoweredClosureCall, ssa.OpWasmLoweredInterCall, ssa.OpWasmLoweredTailCall:
                s.PrepareCall(v)
                if call, ok := v.Aux.(*ssa.AuxCall); ok && call.Fn == ir.Syms.Deferreturn {
                        // The runtime needs to inject jumps to
@@ -141,6 +135,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                        p := s.Prog(obj.ACALL)
                        p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: sym}
                        p.Pos = v.Pos
+                       if v.Op == ssa.OpWasmLoweredTailCall {
+                               p.As = obj.ARET
+                       }
                } else {
                        getValue64(s, v.Args[0])
                        p := s.Prog(obj.ACALL)
index a06fdbcb71770ebce782dcbba69fdc673b236ac7..32e29f347b9c7f675414ee46c037aa62ea682b00 100644 (file)
@@ -752,6 +752,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
 
        case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
                s.Call(v)
+       case ssa.Op386CALLtail:
+               s.TailCall(v)
        case ssa.Op386NEGL,
                ssa.Op386BSWAPL,
                ssa.Op386NOTL:
@@ -892,14 +894,9 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
                        p.To.Type = obj.TYPE_BRANCH
                        s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
                }
-       case ssa.BlockExit:
+       case ssa.BlockExit, ssa.BlockRetJmp:
        case ssa.BlockRet:
                s.Prog(obj.ARET)
-       case ssa.BlockRetJmp:
-               p := s.Prog(obj.AJMP)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = b.Aux.(*obj.LSym)
 
        case ssa.Block386EQF:
                s.CombJump(b, next, &eqfJumps)
index 7ee000861bcc2ad073e68a38c227a6a401343ea8..9c8529f7eb600ab5e0457595343a3464aae44004 100644 (file)
@@ -40,8 +40,8 @@ Finally, to generate modified source code with coverage annotations
 `
 
 func usage() {
-       fmt.Fprintln(os.Stderr, usageMessage)
-       fmt.Fprintln(os.Stderr, "Flags:")
+       fmt.Fprint(os.Stderr, usageMessage)
+       fmt.Fprintln(os.Stderr, "\nFlags:")
        flag.PrintDefaults()
        fmt.Fprintln(os.Stderr, "\n  Only one of -html, -func, or -mode may be set.")
        os.Exit(2)
index b794962205d3da7f8cdf9c37c43fecdc0473e81e..703fba57a45b414bb4cf5de7341ef5dd1f468406 100644 (file)
@@ -13,6 +13,7 @@ package main
 import _ "unsafe" // for go:linkname
 
 //go:linkname some_name some_name
+var some_name int
 
 const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
 
index bec17696f3040acd6f78750f3306c1d3bbeba102..d37c3f83efb4d474175a46062956222c450ad906 100644 (file)
@@ -32,6 +32,7 @@ var (
        goos             string
        goarm            string
        go386            string
+       goamd64          string
        gomips           string
        gomips64         string
        goppc64          string
@@ -48,8 +49,6 @@ var (
        exe              string
        defaultcc        map[string]string
        defaultcxx       map[string]string
-       defaultcflags    string
-       defaultldflags   string
        defaultpkgconfig string
        defaultldso      string
 
@@ -147,6 +146,12 @@ func xinit() {
        }
        go386 = b
 
+       b = os.Getenv("GOAMD64")
+       if b == "" {
+               b = "v1"
+       }
+       goamd64 = b
+
        b = os.Getenv("GOMIPS")
        if b == "" {
                b = "hardfloat"
@@ -209,9 +214,6 @@ func xinit() {
        defaultcc = compilerEnv("CC", cc)
        defaultcxx = compilerEnv("CXX", cxx)
 
-       defaultcflags = os.Getenv("CFLAGS")
-       defaultldflags = os.Getenv("LDFLAGS")
-
        b = os.Getenv("PKG_CONFIG")
        if b == "" {
                b = "pkg-config"
@@ -222,6 +224,7 @@ 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)
@@ -809,6 +812,9 @@ func runInstall(pkg string, ch chan struct{}) {
        importMap := make(map[string]string)
        for _, p := range gofiles {
                for _, imp := range readimports(p) {
+                       if imp == "C" {
+                               fatalf("%s imports C", p)
+                       }
                        importMap[imp] = resolveVendor(imp, dir)
                }
        }
@@ -819,6 +825,9 @@ func runInstall(pkg string, ch chan struct{}) {
        sort.Strings(sortedImports)
 
        for _, dep := range importMap {
+               if dep == "C" {
+                       fatalf("%s imports C", pkg)
+               }
                startInstall(dep)
        }
        for _, dep := range importMap {
@@ -967,28 +976,8 @@ func packagefile(pkg string) string {
        return pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, pkg)
 }
 
-// matchfield reports whether the field (x,y,z) matches this build.
-// all the elements in the field must be satisfied.
-func matchfield(f string) bool {
-       for _, tag := range strings.Split(f, ",") {
-               if !matchtag(tag) {
-                       return false
-               }
-       }
-       return true
-}
-
-// matchtag reports whether the tag (x or !x) matches this build.
+// matchtag reports whether the tag matches this build.
 func matchtag(tag string) bool {
-       if tag == "" {
-               return false
-       }
-       if tag[0] == '!' {
-               if len(tag) == 1 || tag[1] == '!' {
-                       return false
-               }
-               return !matchtag(tag[1:])
-       }
        return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" ||
                (goos == "android" && tag == "linux") ||
                (goos == "illumos" && tag == "solaris") ||
@@ -1029,7 +1018,7 @@ func shouldbuild(file, pkg string) bool {
                return false
        }
 
-       // Check file contents for // +build lines.
+       // Check file contents for //go:build lines.
        for _, p := range strings.Split(readfile(file), "\n") {
                p = strings.TrimSpace(p)
                if p == "" {
@@ -1049,20 +1038,13 @@ func shouldbuild(file, pkg string) bool {
                if !strings.HasPrefix(p, "//") {
                        break
                }
-               if !strings.Contains(p, "+build") {
-                       continue
-               }
-               fields := strings.Fields(p[2:])
-               if len(fields) < 1 || fields[0] != "+build" {
-                       continue
-               }
-               for _, p := range fields[1:] {
-                       if matchfield(p) {
-                               goto fieldmatch
+               if strings.HasPrefix(p, "//go:build ") {
+                       matched, err := matchexpr(p[len("//go:build "):])
+                       if err != nil {
+                               errprintf("%s: %v", file, err)
                        }
+                       return matched
                }
-               return false
-       fieldmatch:
        }
 
        return true
@@ -1186,6 +1168,9 @@ 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)
        }
index 54e935ad3bec1d35c5bf37732ed1bb659965792c..fdc1d257744fcdba092d5db466acdcf4e321ac13 100644 (file)
@@ -60,6 +60,7 @@ func mkbuildcfg(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/buildtag.go b/src/cmd/dist/buildtag.go
new file mode 100644 (file)
index 0000000..24776a0
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2021 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 (
+       "fmt"
+       "strings"
+)
+
+// exprParser is a //go:build expression parser and evaluator.
+// The parser is a trivial precedence-based parser which is still
+// almost overkill for these very simple expressions.
+type exprParser struct {
+       x string
+       t exprToken // upcoming token
+}
+
+// val is the value type result of parsing.
+// We don't keep a parse tree, just the value of the expression.
+type val bool
+
+// exprToken describes a single token in the input.
+// Prefix operators define a prefix func that parses the
+// upcoming value. Binary operators define an infix func
+// that combines two values according to the operator.
+// In that case, the parsing loop parses the two values.
+type exprToken struct {
+       tok    string
+       prec   int
+       prefix func(*exprParser) val
+       infix  func(val, val) val
+}
+
+var exprTokens []exprToken
+
+func init() { // init to break init cycle
+       exprTokens = []exprToken{
+               {tok: "&&", prec: 1, infix: func(x, y val) val { return x && y }},
+               {tok: "||", prec: 2, infix: func(x, y val) val { return x || y }},
+               {tok: "!", prec: 3, prefix: (*exprParser).not},
+               {tok: "(", prec: 3, prefix: (*exprParser).paren},
+               {tok: ")"},
+       }
+}
+
+// matchexpr parses and evaluates the //go:build expression x.
+func matchexpr(x string) (matched bool, err error) {
+       defer func() {
+               if e := recover(); e != nil {
+                       matched = false
+                       err = fmt.Errorf("parsing //go:build line: %v", e)
+               }
+       }()
+
+       p := &exprParser{x: x}
+       p.next()
+       v := p.parse(0)
+       if p.t.tok != "end of expression" {
+               panic("unexpected " + p.t.tok)
+       }
+       return bool(v), nil
+}
+
+// parse parses an expression, including binary operators at precedence >= prec.
+func (p *exprParser) parse(prec int) val {
+       if p.t.prefix == nil {
+               panic("unexpected " + p.t.tok)
+       }
+       v := p.t.prefix(p)
+       for p.t.prec >= prec && p.t.infix != nil {
+               t := p.t
+               p.next()
+               v = t.infix(v, p.parse(t.prec+1))
+       }
+       return v
+}
+
+// not is the prefix parser for a ! token.
+func (p *exprParser) not() val {
+       p.next()
+       return !p.parse(100)
+}
+
+// paren is the prefix parser for a ( token.
+func (p *exprParser) paren() val {
+       p.next()
+       v := p.parse(0)
+       if p.t.tok != ")" {
+               panic("missing )")
+       }
+       p.next()
+       return v
+}
+
+// next advances the parser to the next token,
+// leaving the token in p.t.
+func (p *exprParser) next() {
+       p.x = strings.TrimSpace(p.x)
+       if p.x == "" {
+               p.t = exprToken{tok: "end of expression"}
+               return
+       }
+       for _, t := range exprTokens {
+               if strings.HasPrefix(p.x, t.tok) {
+                       p.x = p.x[len(t.tok):]
+                       p.t = t
+                       return
+               }
+       }
+
+       i := 0
+       for i < len(p.x) && validtag(p.x[i]) {
+               i++
+       }
+       if i == 0 {
+               panic(fmt.Sprintf("syntax error near %#q", rune(p.x[i])))
+       }
+       tag := p.x[:i]
+       p.x = p.x[i:]
+       p.t = exprToken{
+               tok: "tag",
+               prefix: func(p *exprParser) val {
+                       p.next()
+                       return val(matchtag(tag))
+               },
+       }
+}
+
+func validtag(c byte) bool {
+       return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '.' || c == '_'
+}
index 26b33e389fe9283aabd5c0c8f44fba88fa44ea8c..75f04a975c92d492ef46591d10bef65ba2520b53 100644 (file)
@@ -46,6 +46,7 @@ var bootstrapDirs = []string{
        "cmd/internal/obj/...",
        "cmd/internal/objabi",
        "cmd/internal/pkgpath",
+       "cmd/internal/quoted",
        "cmd/internal/src",
        "cmd/internal/sys",
        "cmd/link",
diff --git a/src/cmd/dist/exec.go b/src/cmd/dist/exec.go
new file mode 100644 (file)
index 0000000..6730553
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2021 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 (
+       "os"
+       "os/exec"
+       "strings"
+)
+
+// setDir sets cmd.Dir to dir, and also adds PWD=dir to cmd's environment.
+func setDir(cmd *exec.Cmd, dir string) {
+       cmd.Dir = dir
+       setEnv(cmd, "PWD", dir)
+}
+
+// setEnv sets cmd.Env so that key = value.
+//
+// It first removes any existing values for key, so it is safe to call
+// even from within cmdbootstrap.
+func setEnv(cmd *exec.Cmd, key, value string) {
+       kv := key + "=" + value
+       if cmd.Env == nil {
+               cmd.Env = os.Environ()
+       }
+
+       prefix := kv[:len(key)+1]
+       for i, entry := range cmd.Env {
+               if strings.HasPrefix(entry, prefix) {
+                       cmd.Env[i] = kv
+                       return
+               }
+       }
+
+       cmd.Env = append(cmd.Env, kv)
+}
+
+// unsetEnv sets cmd.Env so that key is not present in the environment.
+func unsetEnv(cmd *exec.Cmd, key string) {
+       if cmd.Env == nil {
+               cmd.Env = os.Environ()
+       }
+
+       prefix := key + "="
+       for i, entry := range cmd.Env {
+               if strings.HasPrefix(entry, prefix) {
+                       cmd.Env = append(cmd.Env[:i], cmd.Env[i+1:]...)
+                       return
+               }
+       }
+}
index a104b5c8f3185ff1214f8f96562b16254ca8f5ba..14b48351db1070f7a88f869ad623cb6955dddb0d 100644 (file)
@@ -139,27 +139,35 @@ func (t *tester) run() {
                goInstall("go", append([]string{"-a", "-i"}, toolchain...)...)
        }
 
-       // Complete rebuild bootstrap, even with -no-rebuild.
-       // If everything is up-to-date, this is a no-op.
-       // If everything is not up-to-date, the first checkNotStale
-       // during the test process will kill the tests, so we might
-       // as well install the world.
-       // Now that for example "go install cmd/compile" does not
-       // also install runtime (you need "go install -i cmd/compile"
-       // for that), it's easy for previous workflows like
-       // "rebuild the compiler and then run run.bash"
-       // to break if we don't automatically refresh things here.
-       // Rebuilding is a shortened bootstrap.
-       // See cmdbootstrap for a description of the overall process.
-       //
-       // But don't do this if we're running in the Go build system,
-       // where cmd/dist is invoked many times. This just slows that
-       // down (Issue 24300).
-       if !t.listMode && os.Getenv("GO_BUILDER_NAME") == "" {
-               goInstall("go", append([]string{"-i"}, toolchain...)...)
-               goInstall("go", append([]string{"-i"}, toolchain...)...)
-               goInstall("go", "std", "cmd")
-               checkNotStale("go", "std", "cmd")
+       if !t.listMode {
+               if os.Getenv("GO_BUILDER_NAME") == "" {
+                       // Complete rebuild bootstrap, even with -no-rebuild.
+                       // If everything is up-to-date, this is a no-op.
+                       // If everything is not up-to-date, the first checkNotStale
+                       // during the test process will kill the tests, so we might
+                       // as well install the world.
+                       // Now that for example "go install cmd/compile" does not
+                       // also install runtime (you need "go install -i cmd/compile"
+                       // for that), it's easy for previous workflows like
+                       // "rebuild the compiler and then run run.bash"
+                       // to break if we don't automatically refresh things here.
+                       // Rebuilding is a shortened bootstrap.
+                       // See cmdbootstrap for a description of the overall process.
+                       goInstall("go", append([]string{"-i"}, toolchain...)...)
+                       goInstall("go", append([]string{"-i"}, toolchain...)...)
+                       goInstall("go", "std", "cmd")
+               } else {
+                       // The Go builder infrastructure should always begin running tests from a
+                       // clean, non-stale state, so there is no need to rebuild the world.
+                       // Instead, we can just check that it is not stale, which may be less
+                       // expensive (and is also more likely to catch bugs in the builder
+                       // implementation).
+                       willTest := []string{"std"}
+                       if t.shouldTestCmd() {
+                               willTest = append(willTest, "cmd")
+                       }
+                       checkNotStale("go", willTest...)
+               }
        }
 
        t.timeoutScale = 1
@@ -509,7 +517,8 @@ func (t *tester) registerTests() {
                        heading: "GOOS=ios on darwin/amd64",
                        fn: func(dt *distTest) error {
                                cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
-                               cmd.Env = append(os.Environ(), "GOOS=ios", "CGO_ENABLED=1")
+                               setEnv(cmd, "GOOS", "ios")
+                               setEnv(cmd, "CGO_ENABLED", "1")
                                return nil
                        },
                })
@@ -529,7 +538,7 @@ func (t *tester) registerTests() {
                                cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
                                // We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
                                // creation of first goroutines and first garbage collections in the parallel setting.
-                               cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
+                               setEnv(cmd, "GOMAXPROCS", "2")
                                return nil
                        },
                })
@@ -550,7 +559,7 @@ func (t *tester) registerTests() {
                                        return nil
                                }
                                cmd := exec.Command("go", "test")
-                               cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
+                               setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153"))
                                cmd.Stdout = os.Stdout
                                cmd.Stderr = os.Stderr
                                return cmd.Run()
@@ -587,16 +596,13 @@ func (t *tester) registerTests() {
                                        return err
                                }
 
-                               // Run `go test fmt` in the moved GOROOT.
+                               // Run `go test fmt` in the moved GOROOT, without explicitly setting
+                               // GOROOT in the environment. The 'go' command should find itself.
                                cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
                                cmd.Stdout = os.Stdout
                                cmd.Stderr = os.Stderr
-                               // Don't set GOROOT in the environment.
-                               for _, e := range os.Environ() {
-                                       if !strings.HasPrefix(e, "GOROOT=") && !strings.HasPrefix(e, "GOCACHE=") {
-                                               cmd.Env = append(cmd.Env, e)
-                                       }
-                               }
+                               unsetEnv(cmd, "GOROOT")
+                               unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽
                                err := cmd.Run()
 
                                if rerr := os.Rename(moved, goroot); rerr != nil {
@@ -723,11 +729,9 @@ func (t *tester) registerTests() {
                                                heading: "../misc/swig/callback",
                                                fn: func(dt *distTest) error {
                                                        cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
-                                                       cmd.Env = append(os.Environ(),
-                                                               "CGO_CFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
-                                                               "CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
-                                                               "CGO_LDFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
-                                                       )
+                                                       setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
+                                                       setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
+                                                       setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
                                                        return nil
                                                },
                                        },
@@ -879,9 +883,9 @@ func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{})
 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
        cmd := exec.Command(bin, args...)
        if filepath.IsAbs(dir) {
-               cmd.Dir = dir
+               setDir(cmd, dir)
        } else {
-               cmd.Dir = filepath.Join(goroot, dir)
+               setDir(cmd, filepath.Join(goroot, dir))
        }
        return cmd
 }
@@ -984,11 +988,6 @@ func (t *tester) internalLink() bool {
                // linkmode=internal fails on dragonfly since errno is a TLS relocation.
                return false
        }
-       if gohostarch == "ppc64le" {
-               // linkmode=internal fails on ppc64le because cmd/link doesn't
-               // handle the TOC correctly (issue 15409).
-               return false
-       }
        if goos == "android" {
                return false
        }
@@ -1032,7 +1031,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
                switch pair {
                case "aix-ppc64",
                        "darwin-amd64", "darwin-arm64", "ios-arm64",
-                       "linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x",
+                       "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
                        "freebsd-amd64",
                        "windows-amd64", "windows-386":
                        return true
@@ -1040,7 +1039,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
                return false
        case "c-shared":
                switch pair {
-               case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
+               case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
                        "darwin-amd64", "darwin-arm64",
                        "freebsd-amd64",
                        "android-arm", "android-arm64", "android-386",
@@ -1119,7 +1118,8 @@ func (t *tester) runHostTest(dir, pkg string) error {
        defer os.Remove(f.Name())
 
        cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
-       cmd.Env = append(os.Environ(), "GOARCH="+gohostarch, "GOOS="+gohostos)
+       setEnv(cmd, "GOARCH", gohostarch)
+       setEnv(cmd, "GOOS", gohostos)
        if err := cmd.Run(); err != nil {
                return err
        }
@@ -1128,7 +1128,7 @@ func (t *tester) runHostTest(dir, pkg string) error {
 
 func (t *tester) cgoTest(dt *distTest) error {
        cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
-       cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=auto")
+       setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto")
 
        // Skip internal linking cases on linux/arm64 to support GCC-9.4 and above.
        // See issue #39466.
@@ -1136,7 +1136,7 @@ func (t *tester) cgoTest(dt *distTest) error {
 
        if t.internalLink() && !skipInternalLink {
                cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal")
-               cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=internal")
+               setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal")
        }
 
        pair := gohostos + "-" + goarch
@@ -1148,9 +1148,9 @@ func (t *tester) cgoTest(dt *distTest) error {
                        break
                }
                cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
-               cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
+               setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
 
-               cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
+               t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
 
                if t.supportedBuildmode("pie") {
                        t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
@@ -1168,10 +1168,10 @@ func (t *tester) cgoTest(dt *distTest) error {
                "openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64":
 
                cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
-               cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
+               setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
                // cgo should be able to cope with both -g arguments and colored
                // diagnostics.
-               cmd.Env = append(cmd.Env, "CGO_CFLAGS=-g0 -fdiagnostics-color")
+               setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color")
 
                t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
                t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
@@ -1204,7 +1204,7 @@ func (t *tester) cgoTest(dt *distTest) error {
                                        // than -static in -extldflags, so test both.
                                        // See issue #16651.
                                        cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static")
-                                       cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread")
+                                       setEnv(cmd, "CGO_LDFLAGS", "-static -pthread")
                                }
                        }
 
@@ -1443,7 +1443,7 @@ func (t *tester) raceTest(dt *distTest) error {
                // We shouldn't need to redo all of misc/cgo/test too.
                // The race buildler will take care of this.
                // cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
-               // cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
+               // setEnv(cmd, "GOTRACEBACK", "2")
        }
        if t.extLink() {
                // Test with external linking; see issue 9133.
@@ -1473,7 +1473,8 @@ func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
                })
 
                cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go")
-               cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch)
+               setEnv(cmd, "GOOS", gohostos)
+               setEnv(cmd, "GOARCH", gohostarch)
                runtest.err = cmd.Run()
        })
        if runtest.err != nil {
@@ -1637,7 +1638,7 @@ func (t *tester) runPrecompiledStdTest(timeout time.Duration) error {
        bin := t.prebuiltGoPackageTestBinary()
        fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin)
        cmd := exec.Command(bin, "-test.short="+short(), "-test.timeout="+timeout.String())
-       cmd.Dir = filepath.Dir(bin)
+       setDir(cmd, filepath.Dir(bin))
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        if err := cmd.Start(); err != nil {
index df60145d1e21e8f2a9a4fc421e56c2f20d305c6b..28fe5e1d8d20d5f02ba573bef5ae633a02e47759 100644 (file)
@@ -72,7 +72,7 @@ func run(dir string, mode int, cmd ...string) string {
        }
 
        xcmd := exec.Command(cmd[0], cmd[1:]...)
-       xcmd.Dir = dir
+       setDir(xcmd, dir)
        var data []byte
        var err error
 
index 661624cfe4c168c793d582203de163f3169634e6..f27af1d27befbe10f4fcf61fc21eed960f6e9867 100644 (file)
@@ -221,11 +221,7 @@ func findCodeRoots() []Dir {
        cmd.Stderr = os.Stderr
        out, _ := cmd.Output()
        for _, line := range strings.Split(string(out), "\n") {
-               i := strings.Index(line, "\t")
-               if i < 0 {
-                       continue
-               }
-               path, dir := line[:i], line[i+1:]
+               path, dir, _ := strings.Cut(line, "\t")
                if dir != "" {
                        list = append(list, Dir{importPath: path, dir: dir, inModule: true})
                }
index 587f0bdc1468f2fd23a2f15d8a097a89137f4fef..2257c5c0eb6ee2402efec602a127cc182f953031 100644 (file)
@@ -315,9 +315,7 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
                        recv = "(" + recv + ") "
                }
                fnc := pkg.oneLineNodeDepth(n.Type, depth)
-               if strings.Index(fnc, "func") == 0 {
-                       fnc = fnc[4:]
-               }
+               fnc = strings.TrimPrefix(fnc, "func")
                return fmt.Sprintf("func %s%s%s", recv, name, fnc)
 
        case *ast.TypeSpec:
@@ -325,7 +323,8 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
                if n.Assign.IsValid() {
                        sep = " = "
                }
-               return fmt.Sprintf("type %s%s%s", n.Name.Name, sep, pkg.oneLineNodeDepth(n.Type, depth))
+               tparams := pkg.formatTypeParams(n.TypeParams, depth)
+               return fmt.Sprintf("type %s%s%s%s", n.Name.Name, tparams, sep, pkg.oneLineNodeDepth(n.Type, depth))
 
        case *ast.FuncType:
                var params []string
@@ -344,15 +343,16 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
                        }
                }
 
+               tparam := pkg.formatTypeParams(n.TypeParams, depth)
                param := joinStrings(params)
                if len(results) == 0 {
-                       return fmt.Sprintf("func(%s)", param)
+                       return fmt.Sprintf("func%s(%s)", tparam, param)
                }
                result := joinStrings(results)
                if !needParens {
-                       return fmt.Sprintf("func(%s) %s", param, result)
+                       return fmt.Sprintf("func%s(%s) %s", tparam, param, result)
                }
-               return fmt.Sprintf("func(%s) (%s)", param, result)
+               return fmt.Sprintf("func%s(%s) (%s)", tparam, param, result)
 
        case *ast.StructType:
                if n.Fields == nil || len(n.Fields.List) == 0 {
@@ -421,6 +421,17 @@ func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
        }
 }
 
+func (pkg *Package) formatTypeParams(list *ast.FieldList, depth int) string {
+       if list.NumFields() == 0 {
+               return ""
+       }
+       var tparams []string
+       for _, field := range list.List {
+               tparams = append(tparams, pkg.oneLineField(field, depth))
+       }
+       return "[" + joinStrings(tparams) + "]"
+}
+
 // oneLineField returns a one-line summary of the field.
 func (pkg *Package) oneLineField(field *ast.Field, depth int) string {
        var names []string
diff --git a/src/cmd/fix/buildtag.go b/src/cmd/fix/buildtag.go
new file mode 100644 (file)
index 0000000..5f4fbfe
--- /dev/null
@@ -0,0 +1,51 @@
+// 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 (
+       "go/ast"
+       "strings"
+)
+
+func init() {
+       register(buildtagFix)
+}
+
+const buildtagGoVersionCutoff = 1_18
+
+var buildtagFix = fix{
+       name: "buildtag",
+       date: "2021-08-25",
+       f:    buildtag,
+       desc: `Remove +build comments from modules using Go 1.18 or later`,
+}
+
+func buildtag(f *ast.File) bool {
+       if goVersion < buildtagGoVersionCutoff {
+               return false
+       }
+
+       // File is already gofmt-ed, so we know that if there are +build lines,
+       // they are in a comment group that starts with a //go:build line followed
+       // by a blank line. While we cannot delete comments from an AST and
+       // expect consistent output in general, this specific case - deleting only
+       // some lines from a comment block - does format correctly.
+       fixed := false
+       for _, g := range f.Comments {
+               sawGoBuild := false
+               for i, c := range g.List {
+                       if strings.HasPrefix(c.Text, "//go:build ") {
+                               sawGoBuild = true
+                       }
+                       if sawGoBuild && strings.HasPrefix(c.Text, "// +build ") {
+                               g.List = g.List[:i]
+                               fixed = true
+                               break
+                       }
+               }
+       }
+
+       return fixed
+}
diff --git a/src/cmd/fix/buildtag_test.go b/src/cmd/fix/buildtag_test.go
new file mode 100644 (file)
index 0000000..1c6efbe
--- /dev/null
@@ -0,0 +1,34 @@
+// 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 init() {
+       addTestCases(buildtagTests, buildtag)
+}
+
+var buildtagTests = []testCase{
+       {
+               Name:    "buildtag.oldGo",
+               Version: 1_10,
+               In: `//go:build yes
+// +build yes
+
+package main
+`,
+       },
+       {
+               Name:    "buildtag.new",
+               Version: 1_99,
+               In: `//go:build yes
+// +build yes
+
+package main
+`,
+               Out: `//go:build yes
+
+package main
+`,
+       },
+}
index b47b06682add8040c98fa9480e73bf3788d6e062..3d292bdeba933f18c09a2e775e055bd02089c868 100644 (file)
@@ -63,7 +63,7 @@ func typefix(f *ast.File, badType func(string) bool) bool {
                                return
                        }
                        v := reflect.ValueOf(n)
-                       if v.Type().Kind() != reflect.Ptr {
+                       if v.Type().Kind() != reflect.Pointer {
                                return
                        }
                        if v.IsNil() {
index b49db375710c3c511ca26a3fa55fa406b19d19ff..b9980c17b9ae4594f7a78af46ba83b8ffd66ac2d 100644 (file)
@@ -125,6 +125,9 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
        case *ast.IndexExpr:
                walkBeforeAfter(&n.X, before, after)
                walkBeforeAfter(&n.Index, before, after)
+       case *ast.IndexListExpr:
+               walkBeforeAfter(&n.X, before, after)
+               walkBeforeAfter(&n.Indices, before, after)
        case *ast.SliceExpr:
                walkBeforeAfter(&n.X, before, after)
                if n.Low != nil {
@@ -156,6 +159,9 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
        case *ast.StructType:
                walkBeforeAfter(&n.Fields, before, after)
        case *ast.FuncType:
+               if n.TypeParams != nil {
+                       walkBeforeAfter(&n.TypeParams, before, after)
+               }
                walkBeforeAfter(&n.Params, before, after)
                if n.Results != nil {
                        walkBeforeAfter(&n.Results, before, after)
@@ -231,6 +237,9 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
                walkBeforeAfter(&n.Values, before, after)
                walkBeforeAfter(&n.Names, before, after)
        case *ast.TypeSpec:
+               if n.TypeParams != nil {
+                       walkBeforeAfter(&n.TypeParams, before, after)
+               }
                walkBeforeAfter(&n.Type, before, after)
 
        case *ast.BadDecl:
index d055929aac0767bcd6b0be7ff6550b239c55af34..b5f7b901d66cc52cd130418dc32399b20f575e3f 100644 (file)
@@ -18,6 +18,7 @@ import (
        "os"
        "path/filepath"
        "sort"
+       "strconv"
        "strings"
 
        "cmd/internal/diff"
@@ -36,7 +37,12 @@ var forceRewrites = flag.String("force", "",
 
 var allowed, force map[string]bool
 
-var doDiff = flag.Bool("diff", false, "display diffs instead of rewriting files")
+var (
+       doDiff       = flag.Bool("diff", false, "display diffs instead of rewriting files")
+       goVersionStr = flag.String("go", "", "go language version for files")
+
+       goVersion int // 115 for go1.15
+)
 
 // enable for debugging fix failures
 const debug = false // display incorrectly reformatted source and exit
@@ -63,6 +69,26 @@ func main() {
        flag.Usage = usage
        flag.Parse()
 
+       if *goVersionStr != "" {
+               if !strings.HasPrefix(*goVersionStr, "go") {
+                       report(fmt.Errorf("invalid -go=%s", *goVersionStr))
+                       os.Exit(exitCode)
+               }
+               majorStr := (*goVersionStr)[len("go"):]
+               minorStr := "0"
+               if i := strings.Index(majorStr, "."); i >= 0 {
+                       majorStr, minorStr = majorStr[:i], majorStr[i+len("."):]
+               }
+               major, err1 := strconv.Atoi(majorStr)
+               minor, err2 := strconv.Atoi(minorStr)
+               if err1 != nil || err2 != nil || major < 0 || major >= 100 || minor < 0 || minor >= 100 {
+                       report(fmt.Errorf("invalid -go=%s", *goVersionStr))
+                       os.Exit(exitCode)
+               }
+
+               goVersion = major*100 + minor
+       }
+
        sort.Sort(byDate(fixes))
 
        if *allowedRewrites != "" {
index af16bcaa31ed94ca6e1f611c847cbae3e0f41786..1baa95c5456bcc85d7158902f9c2afa382363fdf 100644 (file)
@@ -14,10 +14,11 @@ import (
 )
 
 type testCase struct {
-       Name string
-       Fn   func(*ast.File) bool
-       In   string
-       Out  string
+       Name    string
+       Fn      func(*ast.File) bool
+       Version int
+       In      string
+       Out     string
 }
 
 var testCases []testCase
@@ -78,7 +79,16 @@ func TestRewrite(t *testing.T) {
        for _, tt := range testCases {
                tt := tt
                t.Run(tt.Name, func(t *testing.T) {
-                       t.Parallel()
+                       if tt.Version == 0 {
+                               t.Parallel()
+                       } else {
+                               old := goVersion
+                               goVersion = tt.Version
+                               defer func() {
+                                       goVersion = old
+                               }()
+                       }
+
                        // Apply fix: should get tt.Out.
                        out, fixed, ok := parseFixPrint(t, tt.Fn, tt.Name, tt.In, true)
                        if !ok {
@@ -91,6 +101,9 @@ func TestRewrite(t *testing.T) {
                                return
                        }
 
+                       if tt.Out == "" {
+                               tt.Out = tt.In
+                       }
                        if out != tt.Out {
                                t.Errorf("incorrect output.\n")
                                if !strings.HasPrefix(tt.Name, "testdata/") {
index 39a53785b724d4105ccfd6d7bdd320a7f3428005..b7ec72e1167362571b5d5ce7889714abb3abdbd9 100644 (file)
@@ -383,7 +383,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
                if n == nil {
                        return
                }
-               if false && reflect.TypeOf(n).Kind() == reflect.Ptr { // debugging trace
+               if false && reflect.TypeOf(n).Kind() == reflect.Pointer { // debugging trace
                        defer func() {
                                if t := typeof[n]; t != "" {
                                        pos := fset.Position(n.(ast.Node).Pos())
@@ -544,8 +544,8 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
                        if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
                                // Lazy: assume there are no nested [] in the array
                                // length or map key type.
-                               if i := strings.Index(t, "]"); i >= 0 {
-                                       typeof[n] = t[i+1:]
+                               if _, elem, ok := strings.Cut(t, "]"); ok {
+                                       typeof[n] = elem
                                }
                        }
 
@@ -575,8 +575,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
                        t := expand(typeof[n])
                        if strings.HasPrefix(t, "[") { // array or slice
                                // Lazy: assume there are no nested [] in the array length.
-                               if i := strings.Index(t, "]"); i >= 0 {
-                                       et := t[i+1:]
+                               if _, et, ok := strings.Cut(t, "]"); ok {
                                        for _, e := range n.Elts {
                                                if kv, ok := e.(*ast.KeyValueExpr); ok {
                                                        e = kv.Value
@@ -589,8 +588,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
                        }
                        if strings.HasPrefix(t, "map[") { // map
                                // Lazy: assume there are no nested [] in the map key type.
-                               if i := strings.Index(t, "]"); i >= 0 {
-                                       kt, vt := t[4:i], t[i+1:]
+                               if kt, vt, ok := strings.Cut(t[len("map["):], "]"); ok {
                                        for _, e := range n.Elts {
                                                if kv, ok := e.(*ast.KeyValueExpr); ok {
                                                        if typeof[kv.Key] == "" {
@@ -629,12 +627,10 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
                                key, value = "int", "rune"
                        } else if strings.HasPrefix(t, "[") {
                                key = "int"
-                               if i := strings.Index(t, "]"); i >= 0 {
-                                       value = t[i+1:]
-                               }
+                               _, value, _ = strings.Cut(t, "]")
                        } else if strings.HasPrefix(t, "map[") {
-                               if i := strings.Index(t, "]"); i >= 0 {
-                                       key, value = t[4:i], t[i+1:]
+                               if k, v, ok := strings.Cut(t[len("map["):], "]"); ok {
+                                       key, value = k, v
                                }
                        }
                        changed := false
index ccfff098857da7bcac7792025172c70849206381..f7802a167566dfcd3d31895608f35b577ad54c50 100644 (file)
@@ -3,13 +3,17 @@ module cmd
 go 1.18
 
 require (
-       github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
-       github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
-       golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
-       golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
-       golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
-       golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
-       golang.org/x/term v0.0.0-20210503060354-a79de5458b56
-       golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151
+       github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31
+       golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1
+       golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a
+       golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+       golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
+       golang.org/x/tools v0.1.8-0.20211025211149-f916b54a1784
+)
+
+require (
+       github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d // indirect
+       golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
+       golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
        golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 )
index f4d41f0d1025d02354fb1db12f6864efb0640fd3..25c25d81bdff950e1d7433e34b8bfd426de6d87c 100644 (file)
@@ -1,22 +1,23 @@
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a h1:jmAp/2PZAScNd62lTD3Mcb0Ey9FvIIJtLohPhtxZJ+Q=
-github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI=
-github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjcLS7UN4m4Gq+V+uSecqM=
-golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
-golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY=
-golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
-golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
-golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
-golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151 h1:jHjT6WuVKEMzjJgrS1+r1wk54oxwqumUnvtn0QZXyXE=
-golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31 h1:YvpxjnjGhf/vDEeYOysNbsrtB///PKS8lqkFNSDm1p8=
+github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
+github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d h1:uGg2frlt3IcT7kbV6LEp5ONv4vmoO2FW4qSO+my/aoM=
+github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1 h1:MwxAfiDvuwX8Nnnc6iRDhzyMyyc2tz5tYyCP/pZcPCg=
+golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a h1:55PVa91KndtPGH2lus5l2gDZqoO/x+Oa5CV0lVf8Ij8=
+golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/tools v0.1.8-0.20211025211149-f916b54a1784 h1:+xP+QoP2SEPgbn+07I/yJTzP+gavj0XKGS6+JU5tlck=
+golang.org/x/tools v0.1.8-0.20211025211149-f916b54a1784/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
index 7f88d3216cf080a9573026997231cc608a801589..c9426801c51070b7ea28f3a25cdd02cf5ecf2f3e 100644 (file)
 //             The default is GOMAXPROCS, normally the number of CPUs available.
 //     -race
 //             enable data race detection.
-//             Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64,
+//             Supported only on linux/amd64, freebsd/amd64, darwin/amd64, darwin/arm64, windows/amd64,
 //             linux/ppc64le and linux/arm64 (only for 48-bit VMA).
 //     -msan
 //             enable interoperation with memory sanitizer.
 //             Supported only on linux/amd64, linux/arm64
 //             and only with Clang/LLVM as the host C compiler.
 //             On linux/arm64, pie build mode will be used.
+//     -asan
+//             enable interoperation with address sanitizer.
+//             Supported only on linux/arm64, linux/amd64.
 //     -v
 //             print the names of packages as they are compiled.
 //     -work
 //
 //     -asmflags '[pattern=]arg list'
 //             arguments to pass on each go tool asm invocation.
+//     -buildinfo
+//             Whether to stamp binaries with build flags. By default, the compiler name
+//             (gc or gccgo), toolchain flags (like -gcflags), and environment variables
+//             containing flags (like CGO_CFLAGS) are stamped into binaries. Use
+//             -buildinfo=false to omit build information. See also -buildvcs.
 //     -buildmode mode
 //             build mode to use. See 'go help buildmode' for more.
+//     -buildvcs
+//             Whether to stamp binaries with version control information. By default,
+//             version control information is stamped into a binary if the main package
+//             and the main module containing it are in the repository containing the
+//             current directory (if there is a repository). Use -buildvcs=false to
+//             omit version control information. See also -buildinfo.
 //     -compiler name
 //             name of compiler to use, as in runtime.Compiler (gccgo or gc).
 //     -gccgoflags '[pattern=]arg list'
 //             in order to keep output separate from default builds.
 //             If using the -race flag, the install suffix is automatically set to race
 //             or, if set explicitly, has _race appended to it. Likewise for the -msan
-//             flag. Using a -buildmode option that requires non-default compile flags
-//             has a similar effect.
+//             and -asan flags. Using a -buildmode option that requires non-default compile
+//             flags has a similar effect.
 //     -ldflags '[pattern=]arg list'
 //             arguments to pass on each go tool link invocation.
 //     -linkshared
 //             directory, but it is not accessed. When -modfile is specified, an
 //             alternate go.sum file is also used: its path is derived from the
 //             -modfile flag by trimming the ".mod" extension and appending ".sum".
+//     -workfile file
+//             in module aware mode, use the given go.work file as a workspace file.
+//             By default or when -workfile is "auto", the go command searches for a
+//             file named go.work in the current directory and then containing directories
+//             until one is found. If a valid go.work file is found, the modules
+//             specified will collectively be used as the main modules. If -workfile
+//             is "off", or a go.work file is not found in "auto" mode, workspace
+//             mode is disabled.
 //     -overlay file
 //             read a JSON config file that provides an overlay for build operations.
 //             The file is a JSON struct with a single field, named 'Replace', that
 // download cache, including unpacked source code of versioned
 // dependencies.
 //
+// The -fuzzcache flag causes clean to remove files stored in the Go build
+// cache for fuzz testing. The fuzzing engine caches files that expand
+// code coverage, so removing them may make fuzzing less effective until
+// new inputs are found that provide the same coverage. These files are
+// distinct from those stored in testdata directory; clean does not remove
+// those files.
+//
 // For more about build flags, see 'go help build'.
 //
 // For more about specifying packages, see 'go help packages'.
 //
 // Usage:
 //
-//     go fix [packages]
+//     go fix [-fix list] [packages]
 //
 // Fix runs the Go fix command on the packages named by the import paths.
 //
+// The -fix flag sets a comma-separated list of fixes to run.
+// The default is all known fixes.
+// (Its value is passed to 'go tool fix -r'.)
+//
 // For more about fix, see 'go doc cmd/fix'.
 // For more about specifying packages, see 'go help packages'.
 //
-// To run fix with specific options, run 'go tool fix'.
+// To run fix with other options, run 'go tool fix'.
 //
 // See also: go fmt, go vet.
 //
 // files. Those commands can run any process but the intent is to
 // create or update Go source files.
 //
-// Go generate is never run automatically by go build, go get, go test,
+// Go generate is never run automatically by go build, go test,
 // and so on. It must be run explicitly.
 //
 // Go generate scans the file for directives, which are lines of
 //
 // Usage:
 //
-//     go get [-d] [-t] [-u] [-v] [build flags] [packages]
+//     go get [-t] [-u] [-v] [build flags] [packages]
 //
 // Get resolves its command-line arguments to packages at specific module versions,
-// updates go.mod to require those versions, downloads source code into the
-// module cache, then builds and installs the named packages.
+// updates go.mod to require those versions, and downloads source code into the
+// module cache.
 //
 // To add a dependency for a package or upgrade it to its latest version:
 //
 //
 // See https://golang.org/ref/mod#go-get for details.
 //
-// The 'go install' command may be used to build and install packages. When a
-// version is specified, 'go install' runs in module-aware mode and ignores
-// the go.mod file in the current directory. For example:
+// In earlier versions of Go, 'go get' was used to build and install packages.
+// Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
+// may be used to build and install commands instead. When a version is specified,
+// 'go install' runs in module-aware mode and ignores the go.mod file in the
+// current directory. For example:
 //
 //     go install example.com/pkg@v1.2.3
 //     go install example.com/pkg@latest
 //
 // See 'go help install' or https://golang.org/ref/mod#go-install for details.
 //
-// In addition to build flags (listed in 'go help build') 'go get' accepts the
-// following flags.
+// 'go get' accepts the following flags.
 //
 // The -t flag instructs get to consider modules needed to build tests of
 // packages specified on the command line.
 // When the -t and -u flags are used together, get will update
 // test dependencies as well.
 //
-// The -d flag instructs get not to build or install packages. get will only
-// update go.mod and download source code needed to build packages.
-//
-// Building and installing packages with get is deprecated. In a future release,
-// the -d flag will be enabled by default, and 'go get' will be only be used to
-// adjust dependencies of the current module. To install a package using
-// dependencies from the current module, use 'go install'. To install a package
-// ignoring the current module, use 'go install' with an @version suffix like
-// "@latest" after each argument.
+// The -x flag prints commands as they are executed. This is useful for
+// debugging version control commands when a module is downloaded directly
+// from a repository.
 //
 // For more about modules, see https://golang.org/ref/mod.
 //
 //
 // - All arguments must refer to packages in the same module at the same version.
 //
+// - Package path arguments must refer to main packages. Pattern arguments
+// will only match main packages.
+//
 // - No module is considered the "main" module. If the module containing
 // packages named on the command line has a go.mod file, it must not contain
 // directives (replace and exclude) that would cause it to be interpreted
 // differently than if it were the main module. The module must not require
 // a higher version of itself.
 //
-// - Package path arguments must refer to main packages. Pattern arguments
-// will only match main packages.
+// - Vendor directories are not used in any module. (Vendor directories are not
+// included in the module zip files downloaded by 'go install'.)
 //
 // If the arguments don't have version suffixes, "go install" may run in
 // module-aware mode or GOPATH mode, depending on the GO111MODULE environment
 //
 //     download    download modules to local cache
 //     edit        edit go.mod from tools or scripts
+//     editwork    edit go.work from tools or scripts
 //     graph       print module requirement graph
 //     init        initialize new module in current directory
+//     initwork    initialize workspace file
 //     tidy        add missing and remove unused modules
 //     vendor      make vendored copy of dependencies
 //     verify      verify dependencies have expected content
 //
 // Download downloads the named modules, which can be module patterns selecting
 // dependencies of the main module or module queries of the form path@version.
-// With no arguments, download applies to all dependencies of the main module
-// (equivalent to 'go mod download all').
+//
+// With no arguments, download applies to the modules needed to build and test
+// the packages in the main module: the modules explicitly required by the main
+// module if it is at 'go 1.17' or higher, or all transitively-required modules
+// if at 'go 1.16' or lower.
 //
 // The go command will automatically download modules as needed during ordinary
 // execution. The "go mod download" command is useful mainly for pre-filling
 // See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
 //
 //
+// Edit go.work from tools or scripts
+//
+// Usage:
+//
+//     go mod editwork [editing flags] [go.work]
+//
+// Editwork provides a command-line interface for editing go.work,
+// for use primarily by tools or scripts. It only reads go.work;
+// it does not look up information about the modules involved.
+// If no file is specified, editwork looks for a go.work file in the current
+// directory and its parent directories
+//
+// The editing flags specify a sequence of editing operations.
+//
+// The -fmt flag reformats the go.work file without making other changes.
+// This reformatting is also implied by any other modifications that use or
+// rewrite the go.mod file. The only time this flag is needed is if no other
+// flags are specified, as in 'go mod editwork -fmt'.
+//
+// The -directory=path and -dropdirectory=path flags
+// add and drop a directory from the go.work files set of module directories.
+//
+// The -replace=old[@v]=new[@v] flag adds a replacement of the given
+// module path and version pair. If the @v in old@v is omitted, a
+// replacement without a version on the left side is added, which applies
+// to all versions of the old module path. If the @v in new@v is omitted,
+// the new path should be a local module root directory, not a module
+// path. Note that -replace overrides any redundant replacements for old[@v],
+// so omitting @v will drop existing replacements for specific versions.
+//
+// The -dropreplace=old[@v] flag drops a replacement of the given
+// module path and version pair. If the @v is omitted, a replacement without
+// a version on the left side is dropped.
+//
+// The -directory, -dropdirectory, -replace, and -dropreplace,
+// editing flags may be repeated, and the changes are applied in the order given.
+//
+// The -go=version flag sets the expected Go language version.
+//
+// The -print flag prints the final go.work in its text format instead of
+// writing it back to go.mod.
+//
+// The -json flag prints the final go.work file in JSON format instead of
+// writing it back to go.mod. The JSON output corresponds to these Go types:
+//
+//     type Module struct {
+//             Path    string
+//             Version string
+//     }
+//
+//     type GoWork struct {
+//             Go        string
+//             Directory []Directory
+//             Replace   []Replace
+//     }
+//
+//     type Directory struct {
+//             Path       string
+//             ModulePath string
+//     }
+//
+//     type Replace struct {
+//             Old Module
+//             New Module
+//     }
+//
+// See the workspaces design proposal at
+// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
+// more information.
+//
+//
 // Print module requirement graph
 //
 // Usage:
 // See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
 //
 //
+// Initialize workspace file
+//
+// Usage:
+//
+//     go mod initwork [moddirs]
+//
+// go mod initwork initializes and writes a new go.work file in the current
+// directory, in effect creating a new workspace at the current directory.
+//
+// go mod initwork optionally accepts paths to the workspace modules as arguments.
+// If the argument is omitted, an empty workspace with no modules will be created.
+//
+// See the workspaces design proposal at
+// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
+// more information.
+//
+//
 // Add missing and remove unused modules
 //
 // Usage:
 //
 // 'Go test' recompiles each package along with any files with names matching
 // the file pattern "*_test.go".
-// These additional files can contain test functions, benchmark functions, and
-// example functions. See 'go help testfunc' for more.
+// These additional files can contain test functions, benchmark functions, fuzz
+// targets and example functions. See 'go help testfunc' for more.
 // Each listed package causes the execution of a separate test binary.
 // Files whose names begin with "_" (including "_test.go") or "." are ignored.
 //
 // 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.
+// To disable the running of go vet, use the -vet=off flag. To run all
+// checks, use the -vet=all 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
 // The rule for a match in the cache is that the run involves the same
 // test binary and the flags on the command line come entirely from a
 // restricted set of 'cacheable' test flags, defined as -benchtime, -cpu,
-// -list, -parallel, -run, -short, and -v. If a run of go test has any test
-// or non-test flags outside this set, the result is not cached. To
-// disable test caching, use any test flag or argument other than the
-// cacheable flags. The idiomatic way to disable test caching explicitly
-// is to use -count=1. Tests that open files within the package's source
-// root (usually $GOPATH) or that consult environment variables only
-// match future runs in which the files and environment variables are unchanged.
-// A cached test result is treated as executing in no time at all,
-// so a successful package test result will be cached and reused
-// regardless of -timeout setting.
+// -list, -parallel, -run, -short, -timeout, -failfast, and -v.
+// If a run of go test has any test or non-test flags outside this set,
+// the result is not cached. To disable test caching, use any test flag
+// or argument other than the cacheable flags. The idiomatic way to disable
+// test caching explicitly is to use -count=1. Tests that open files within
+// the package's source root (usually $GOPATH) or that consult environment
+// variables only match future runs in which the files and environment
+// variables are unchanged. A cached test result is treated as executing
+// in no time at all,so a successful package test result will be cached and
+// reused regardless of -timeout setting.
 //
 // In addition to the build flags, the flags handled by 'go test' itself are:
 //
 // See 'go help test' for details. Running 'go clean -testcache' removes
 // all cached test results (but not cached build results).
 //
+// The go command also caches values used in fuzzing with 'go test -fuzz',
+// specifically, values that expanded code coverage when passed to a
+// fuzz function. These values are not used for regular building and
+// testing, but they're stored in a subdirectory of the build cache.
+// Running 'go clean -fuzzcache' removes all cached fuzzing values.
+// This may make fuzzing less effective, temporarily.
+//
 // The GODEBUG environment variable can enable printing of debugging
 // information about the state of the cache:
 //
 //     GO386
 //             For GOARCH=386, how to implement floating point instructions.
 //             Valid values are sse2 (default), softfloat.
+//     GOAMD64
+//             For GOARCH=amd64, the microarchitecture level for which to compile.
+//             Valid values are v1 (default), v2, v3, v4.
+//             See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels.
 //     GOMIPS
 //             For GOARCH=mips{,le}, whether to use floating point instructions.
 //             Valid values are hardfloat (default), softfloat.
 //         (for example, -benchtime 100x).
 //
 //     -count n
-//         Run each test and benchmark n times (default 1).
+//         Run each test, benchmark, and fuzz seed n times (default 1).
 //         If -cpu is set, run n times for each GOMAXPROCS value.
-//         Examples are always run once.
+//         Examples are always run once. -count does not apply to
+//         fuzz targets matched by -fuzz.
 //
 //     -cover
 //         Enable coverage analysis.
 //         Sets -cover.
 //
 //     -cpu 1,2,4
-//         Specify a list of GOMAXPROCS values for which the tests or
-//         benchmarks should be executed. The default is the current value
-//         of GOMAXPROCS.
+//         Specify a list of GOMAXPROCS values for which the tests, benchmarks or
+//         fuzz targets should be executed. The default is the current value
+//         of GOMAXPROCS. -cpu does not apply to fuzz targets matched by -fuzz.
 //
 //     -failfast
 //         Do not start new tests after the first test failure.
 //
+//     -fuzz regexp
+//         Run the fuzz target matching the regular expression. When specified,
+//         the command line argument must match exactly one package within the
+//         main module, and regexp must match exactly one fuzz target within
+//         that package. After tests, benchmarks, seed corpora of other fuzz
+//         targets, and examples have completed, the matching target will be
+//         fuzzed. See the Fuzzing section of the testing package documentation
+//         for details.
+//
+//     -fuzztime t
+//         Run enough iterations of the fuzz test to take t, specified as a
+//         time.Duration (for example, -fuzztime 1h30s). The default is to run
+//         forever.
+//         The special syntax Nx means to run the fuzz test N times
+//         (for example, -fuzztime 100x).
+//
+//     -json
+//         Log verbose output and test results in JSON. This presents the
+//         same information as the -v flag in a machine-readable format.
+//
 //     -list regexp
-//         List tests, benchmarks, or examples matching the regular expression.
-//         No tests, benchmarks or examples will be run. This will only
-//         list top-level tests. No subtest or subbenchmarks will be shown.
+//         List tests, benchmarks, fuzz targets, or examples matching the regular
+//         expression. No tests, benchmarks, fuzz targets, or examples will be run.
+//         This will only list top-level tests. No subtest or subbenchmarks will be
+//         shown.
 //
 //     -parallel n
-//         Allow parallel execution of test functions that call t.Parallel.
+//         Allow parallel execution of test functions that call t.Parallel, and
+//         f.Fuzz functions that call t.Parallel when running the seed corpus.
 //         The value of this flag is the maximum number of tests to run
-//         simultaneously; by default, it is set to the value of GOMAXPROCS.
+//         simultaneously.
+//         While fuzzing, the value of this flag is the maximum number of
+//         subprocesses that may call the fuzz function simultaneously, regardless of
+//         whether T.Parallel is called.
+//         By default, -parallel is set to the value of GOMAXPROCS.
+//         Setting -parallel to values higher than GOMAXPROCS may cause degraded
+//         performance due to CPU contention, especially when fuzzing.
 //         Note that -parallel only applies within a single test binary.
 //         The 'go test' command may run tests for different packages
 //         in parallel as well, according to the setting of the -p flag
 //         (see 'go help build').
 //
 //     -run regexp
-//         Run only those tests and examples matching the regular expression.
-//         For tests, the regular expression is split by unbracketed slash (/)
-//         characters into a sequence of regular expressions, and each part
-//         of a test's identifier must match the corresponding element in
+//         Run only those tests, examples, and fuzz targets matching the regular
+//         expression. For tests, the regular expression is split by unbracketed
+//         slash (/) characters into a sequence of regular expressions, and each
+//         part of a test's identifier must match the corresponding element in
 //         the sequence, if any. Note that possible parents of matches are
 //         run too, so that -run=X/Y matches and runs and reports the result
 //         of all tests matching X, even those without sub-tests matching Y,
 //         exhaustive tests.
 //
 //     -shuffle off,on,N
-//             Randomize the execution order of tests and benchmarks.
-//             It is off by default. If -shuffle is set to on, then it will seed
-//             the randomizer using the system clock. If -shuffle is set to an
-//             integer N, then N will be used as the seed value. In both cases,
-//             the seed will be reported for reproducibility.
+//         Randomize the execution order of tests and benchmarks.
+//         It is off by default. If -shuffle is set to on, then it will seed
+//         the randomizer using the system clock. If -shuffle is set to an
+//         integer N, then N will be used as the seed value. In both cases,
+//         the seed will be reported for reproducibility.
 //
 //     -timeout d
 //         If a test binary runs longer than duration d, panic.
 // When 'go test' runs a test binary, it does so from within the
 // corresponding package's source code directory. Depending on the test,
 // it may be necessary to do the same when invoking a generated test
-// binary directly.
+// binary directly. Because that directory may be located within the
+// module cache, which may be read-only and is verified by checksums, the
+// test must not write to it or any other directory within the module
+// unless explicitly requested by the user (such as with the -fuzz flag,
+// which writes failures to testdata/fuzz).
 //
 // The command-line package list, if present, must appear before any
 // flag not known to the go test command. Continuing the example above,
 //
 //     func BenchmarkXxx(b *testing.B) { ... }
 //
+// A fuzz target is one named FuzzXxx and should have the signature,
+//
+//     func FuzzXxx(f *testing.F) { ... }
+//
 // An example function is similar to a test function but, instead of using
 // *testing.T to report success or failure, prints output to os.Stdout.
 // If the last comment in the function starts with "Output:" then the output
 //
 // The entire test file is presented as the example when it contains a single
 // example function, at least one other function, type, variable, or constant
-// declaration, and no test or benchmark functions.
+// declaration, and no fuzz targets or test or benchmark functions.
 //
 // See the documentation of the testing package for more information.
 //
index a1f2727825ede1f1ead32d3e240311206a186ed5..9faa7cba42e097b094ca17d41c47dbbb5f54ba62 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build go1.1
-// +build go1.1
 
 package main
 
index 8a091c5dbef488168b66a643e4b705c5628a6e0e..4a81c826a5f542ff4e9378498239ffd97e018896 100644 (file)
@@ -13,6 +13,7 @@ import (
        "flag"
        "fmt"
        "go/format"
+       "internal/godebug"
        "internal/race"
        "internal/testenv"
        "io"
@@ -31,7 +32,6 @@ import (
        "cmd/go/internal/cache"
        "cmd/go/internal/cfg"
        "cmd/go/internal/robustio"
-       "cmd/go/internal/work"
        "cmd/internal/sys"
 )
 
@@ -44,9 +44,12 @@ func init() {
 }
 
 var (
-       canRace = false // whether we can run the race detector
-       canCgo  = false // whether we can use cgo
-       canMSan = false // whether we can run the memory sanitizer
+       canRace          = false // whether we can run the race detector
+       canCgo           = false // whether we can use cgo
+       canMSan          = false // whether we can run the memory sanitizer
+       canASan          = false // whether we can run the address sanitizer
+       canFuzz          = false // whether we can search for new fuzz failures
+       fuzzInstrumented = false // whether fuzzing uses instrumentation
 )
 
 var exeSuffix string = func() string {
@@ -198,6 +201,7 @@ func TestMain(m *testing.M) {
                testGOCACHE = strings.TrimSpace(string(out))
 
                canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH)
+               canASan = canCgo && sys.ASanSupported(runtime.GOOS, runtime.GOARCH)
                canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
                // The race detector doesn't work on Alpine Linux:
                // golang.org/issue/14481
@@ -205,6 +209,8 @@ func TestMain(m *testing.M) {
                if isAlpineLinux() || runtime.Compiler == "gccgo" {
                        canRace = false
                }
+               canFuzz = sys.FuzzSupported(runtime.GOOS, runtime.GOARCH)
+               fuzzInstrumented = sys.FuzzInstrumented(runtime.GOOS, runtime.GOARCH)
        }
        // Don't let these environment variables confuse the test.
        os.Setenv("GOENV", "off")
@@ -1378,10 +1384,10 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
                }`)
        testStr := "test test test test test \n\\ "
        var buf bytes.Buffer
-       for buf.Len() < work.ArgLengthForResponseFile+1 {
+       for buf.Len() < sys.ExecArgLengthLimit+1 {
                buf.WriteString(testStr)
        }
-       tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
+       tg.run("run", "-buildinfo=false", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
        if tg.stderr.String() != buf.String() {
                t.Errorf("strings differ")
        }
@@ -2284,7 +2290,7 @@ func TestUpxCompression(t *testing.T) {
 
 func TestCacheListStale(t *testing.T) {
        tooSlow(t)
-       if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
+       if godebug.Get("gocacheverify") == "1" {
                t.Skip("GODEBUG gocacheverify")
        }
        tg := testgo(t)
@@ -2307,7 +2313,7 @@ func TestCacheListStale(t *testing.T) {
 func TestCacheCoverage(t *testing.T) {
        tooSlow(t)
 
-       if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
+       if godebug.Get("gocacheverify") == "1" {
                t.Skip("GODEBUG gocacheverify")
        }
 
@@ -2339,7 +2345,7 @@ func TestIssue22588(t *testing.T) {
 
 func TestIssue22531(t *testing.T) {
        tooSlow(t)
-       if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
+       if godebug.Get("gocacheverify") == "1" {
                t.Skip("GODEBUG gocacheverify")
        }
        tg := testgo(t)
@@ -2368,7 +2374,7 @@ func TestIssue22531(t *testing.T) {
 
 func TestIssue22596(t *testing.T) {
        tooSlow(t)
-       if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
+       if godebug.Get("gocacheverify") == "1" {
                t.Skip("GODEBUG gocacheverify")
        }
        tg := testgo(t)
@@ -2398,7 +2404,7 @@ func TestIssue22596(t *testing.T) {
 func TestTestCache(t *testing.T) {
        tooSlow(t)
 
-       if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
+       if godebug.Get("gocacheverify") == "1" {
                t.Skip("GODEBUG gocacheverify")
        }
        tg := testgo(t)
index 7d5ff9bbb748391dac7cc2f2be0c7fc032977bac..bab94944014afa330431c328ca22edce9d80ba31 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package main_test
 
index 0144525e307b0565b002c25b103dd9bc8108e8c0..954ce47a9899325014b4e99b5b6a1875a4120f30 100644 (file)
@@ -17,7 +17,7 @@ import (
        "sync"
 
        "cmd/go/internal/cfg"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 // A Command is an implementation of a go command
index 6914efa0e6ff15ae883e61d44a8ee3aba3c1f907..2c72c7e562b7333be43813553321469a555b44a0 100644 (file)
@@ -9,7 +9,7 @@ import (
 
        "cmd/go/internal/cfg"
        "cmd/go/internal/fsys"
-       "cmd/internal/str"
+       "cmd/internal/quoted"
 )
 
 // A StringsFlag is a command-line flag that interprets its argument
@@ -18,7 +18,7 @@ type StringsFlag []string
 
 func (v *StringsFlag) Set(s string) error {
        var err error
-       *v, err = str.SplitQuotedFields(s)
+       *v, err = quoted.Split(s)
        if *v == nil {
                *v = []string{}
        }
@@ -62,6 +62,13 @@ func AddModFlag(flags *flag.FlagSet) {
        flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
 }
 
+// AddWorkfileFlag adds the workfile flag to the flag set. It enables workspace
+// mode for commands that support it by resetting the cfg.WorkFile variable
+// to "" (equivalent to auto) rather than off.
+func AddWorkfileFlag(flags *flag.FlagSet) {
+       flags.Var(explicitStringFlag{value: &cfg.WorkFile, explicit: &cfg.WorkFileExplicit}, "workfile", "")
+}
+
 // AddModCommonFlags adds the module-related flags common to build commands
 // and 'go mod' subcommands.
 func AddModCommonFlags(flags *flag.FlagSet) {
index 5cc0b0f1011e5a1a0c2ff3a0eb256960d90deb7c..682705f9b2cb41e3a6fc81fd74536a3aa4e42104 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9 || windows
-// +build plan9 windows
 
 package base
 
index cdc2658372e429930170b5a25b6a8ee7948e0c9f..657ff38584104201de727e67d74f50ce798df8b1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || js || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js linux netbsd openbsd solaris
 
 package base
 
index d0da65e03ced64a930867913843e534dd5701bd9..f927016965051e7d2d8f46c4d2af9b5123c92fe7 100644 (file)
@@ -36,7 +36,7 @@ func Tool(toolName string) string {
        }
        // Give a nice message if there is no tool with that name.
        if _, err := os.Stat(toolPath); err != nil {
-               fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
+               fmt.Fprintf(os.Stderr, "go: no such tool %q\n", toolName)
                SetExitStatus(2)
                Exit()
        }
index 307527c695cbededab0ae1dfa4447e2fc3161c4b..a81ca7d8c39799b998302f3d5a7f632a27511449 100644 (file)
@@ -40,7 +40,7 @@ func init() {
 
 func runBug(ctx context.Context, cmd *base.Command, args []string) {
        if len(args) > 0 {
-               base.Fatalf("go bug: bug takes no arguments")
+               base.Fatalf("go: bug takes no arguments")
        }
        var buf bytes.Buffer
        buf.WriteString(bugHeader)
index d592d7049786ce9d3fd5d15a67f2884327f149a0..93d7c25658fa07eef33d282ff3e61e90cf63d616 100644 (file)
@@ -533,3 +533,15 @@ func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
 
        return nil
 }
+
+// FuzzDir returns a subdirectory within the cache for storing fuzzing data.
+// The subdirectory may not exist.
+//
+// This directory is managed by the internal/fuzz package. Files in this
+// directory aren't removed by the 'go clean -cache' command or by Trim.
+// They may be removed with 'go clean -fuzzcache'.
+//
+// TODO(#48526): make Trim remove unused files from this directory.
+func (c *Cache) FuzzDir() string {
+       return filepath.Join(c.dir, "fuzz")
+}
index 57a3c1ff6fbdc1f9f29a10a4580e8d40e4f8c908..351c3ee6a508747554940aec7534c1f53a00cd8d 100644 (file)
@@ -25,7 +25,9 @@ import (
 // These are general "build flags" used by build and other commands.
 var (
        BuildA                 bool   // -a flag
+       BuildBuildinfo         bool   // -buildinfo flag
        BuildBuildmode         string // -buildmode flag
+       BuildBuildvcs          bool   // -buildvcs flag
        BuildContext           = defaultContext()
        BuildMod               string                  // -mod flag
        BuildModExplicit       bool                    // whether -mod was set explicitly
@@ -33,6 +35,7 @@ var (
        BuildI                 bool                    // -i flag
        BuildLinkshared        bool                    // -linkshared flag
        BuildMSan              bool                    // -msan flag
+       BuildASan              bool                    // -asan flag
        BuildN                 bool                    // -n flag
        BuildO                 string                  // -o flag
        BuildP                 = runtime.GOMAXPROCS(0) // -p flag
@@ -47,17 +50,24 @@ var (
        BuildWork              bool // -work flag
        BuildX                 bool // -x flag
 
-       ModCacheRW bool   // -modcacherw flag
-       ModFile    string // -modfile flag
+       ModCacheRW       bool   // -modcacherw flag
+       ModFile          string // -modfile flag
+       WorkFile         string // -workfile flag
+       WorkFileExplicit bool   // whether -workfile was set explicitly
 
        CmdName string // "build", "install", "list", "mod tidy", etc.
 
        DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
        DebugTrace       string // -debug-trace flag
+
+       // GoPathError is set when GOPATH is not set. it contains an
+       // explanation why GOPATH is unset.
+       GoPathError string
 )
 
 func defaultContext() build.Context {
        ctxt := build.Default
+
        ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
 
        ctxt.GOROOT = findGOROOT()
@@ -70,7 +80,7 @@ func defaultContext() build.Context {
                build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
        }
 
-       ctxt.GOPATH = envOr("GOPATH", ctxt.GOPATH)
+       ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
 
        // Override defaults computed in go/build with defaults
        // from go environment configuration file, if known.
@@ -261,6 +271,7 @@ var (
        // Used in envcmd.MkEnv and build ID computations.
        GOARM    = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
        GO386    = envOr("GO386", buildcfg.GO386)
+       GOAMD64  = envOr("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
        GOMIPS   = envOr("GOMIPS", buildcfg.GOMIPS)
        GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
        GOPPC64  = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
@@ -287,6 +298,8 @@ 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":
@@ -396,3 +409,24 @@ func gopathDir(rel string) string {
        }
        return filepath.Join(list[0], rel)
 }
+
+func gopath(ctxt build.Context) string {
+       if len(ctxt.GOPATH) > 0 {
+               return ctxt.GOPATH
+       }
+       env := "HOME"
+       if runtime.GOOS == "windows" {
+               env = "USERPROFILE"
+       } else if runtime.GOOS == "plan9" {
+               env = "home"
+       }
+       if home := os.Getenv(env); home != "" {
+               def := filepath.Join(home, "go")
+               if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
+                       GoPathError = "cannot set GOROOT as GOPATH"
+               }
+               return ""
+       }
+       GoPathError = fmt.Sprintf("%s is not set", env)
+       return ""
+}
index fd4cb205591105d0ad527e25e811cd62dfadf5a8..dc93cdf5983126c42adeddb2504276a8a41f834f 100644 (file)
@@ -75,6 +75,13 @@ The -modcache flag causes clean to remove the entire module
 download cache, including unpacked source code of versioned
 dependencies.
 
+The -fuzzcache flag causes clean to remove files stored in the Go build
+cache for fuzz testing. The fuzzing engine caches files that expand
+code coverage, so removing them may make fuzzing less effective until
+new inputs are found that provide the same coverage. These files are
+distinct from those stored in testdata directory; clean does not remove
+those files.
+
 For more about build flags, see 'go help build'.
 
 For more about specifying packages, see 'go help packages'.
@@ -85,6 +92,7 @@ var (
        cleanI         bool // clean -i flag
        cleanR         bool // clean -r flag
        cleanCache     bool // clean -cache flag
+       cleanFuzzcache bool // clean -fuzzcache flag
        cleanModcache  bool // clean -modcache flag
        cleanTestcache bool // clean -testcache flag
 )
@@ -96,6 +104,7 @@ func init() {
        CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
        CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
        CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "")
+       CmdClean.Flag.BoolVar(&cleanFuzzcache, "fuzzcache", false, "")
        CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "")
        CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", false, "")
 
@@ -112,7 +121,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
        // or no other target (such as a cache) was requested to be cleaned.
        cleanPkg := len(args) > 0 || cleanI || cleanR
        if (!modload.Enabled() || modload.HasModRoot()) &&
-               !cleanCache && !cleanModcache && !cleanTestcache {
+               !cleanCache && !cleanModcache && !cleanTestcache && !cleanFuzzcache {
                cleanPkg = true
        }
 
@@ -144,7 +153,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
                                                // 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)
+                                                       base.Errorf("go: %v", err)
                                                }
                                        }
                                }
@@ -157,7 +166,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
                        if !cfg.BuildN {
                                if err := os.RemoveAll(logFile); err != nil && !printedErrors {
                                        printedErrors = true
-                                       base.Errorf("go clean -cache: %v", err)
+                                       base.Errorf("go: %v", err)
                                }
                        }
                }
@@ -187,7 +196,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
                        }
                        if err != nil {
                                if _, statErr := os.Stat(dir); !os.IsNotExist(statErr) {
-                                       base.Errorf("go clean -testcache: %v", err)
+                                       base.Errorf("go: %v", err)
                                }
                        }
                }
@@ -195,14 +204,26 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
 
        if cleanModcache {
                if cfg.GOMODCACHE == "" {
-                       base.Fatalf("go clean -modcache: no module cache")
+                       base.Fatalf("go: cannot clean -modcache without a module cache")
                }
                if cfg.BuildN || cfg.BuildX {
                        b.Showcmd("", "rm -rf %s", cfg.GOMODCACHE)
                }
                if !cfg.BuildN {
                        if err := modfetch.RemoveAll(cfg.GOMODCACHE); err != nil {
-                               base.Errorf("go clean -modcache: %v", err)
+                               base.Errorf("go: %v", err)
+                       }
+               }
+       }
+
+       if cleanFuzzcache {
+               fuzzDir := cache.Default().FuzzDir()
+               if cfg.BuildN || cfg.BuildX {
+                       b.Showcmd("", "rm -rf %s", fuzzDir)
+               }
+               if !cfg.BuildN {
+                       if err := os.RemoveAll(fuzzDir); err != nil {
+                               base.Errorf("go: %v", err)
                        }
                }
        }
@@ -245,7 +266,7 @@ func clean(p *load.Package) {
        }
        dirs, err := os.ReadDir(p.Dir)
        if err != nil {
-               base.Errorf("go clean %s: %v", p.Dir, err)
+               base.Errorf("go: %s: %v", p.Dir, err)
                return
        }
 
@@ -334,7 +355,7 @@ func clean(p *load.Package) {
                                        }
                                }
                                if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
-                                       base.Errorf("go clean: %v", err)
+                                       base.Errorf("go: %v", err)
                                }
                        }
                        continue
@@ -386,5 +407,5 @@ func removeFile(f string) {
                        return
                }
        }
-       base.Errorf("go clean: %v", err)
+       base.Errorf("go: %v", err)
 }
index 1553d263914541f05a639e03b8041969ba244301..e56dd8223f0519e90e9c89cd8e576d5f227becc5 100644 (file)
@@ -26,6 +26,7 @@ import (
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
        "cmd/go/internal/work"
+       "cmd/internal/quoted"
 )
 
 var CmdEnv = &base.Command{
@@ -104,13 +105,13 @@ func MkEnv() []cfg.EnvVar {
                env = append(env, cfg.EnvVar{Name: key, Value: val})
        }
 
-       cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch)
-       if env := strings.Fields(cfg.Getenv("CC")); len(env) > 0 {
-               cc = env[0]
+       cc := cfg.Getenv("CC")
+       if cc == "" {
+               cc = cfg.DefaultCC(cfg.Goos, cfg.Goarch)
        }
-       cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
-       if env := strings.Fields(cfg.Getenv("CXX")); len(env) > 0 {
-               cxx = env[0]
+       cxx := cfg.Getenv("CXX")
+       if cxx == "" {
+               cxx = cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
        }
        env = append(env, cfg.EnvVar{Name: "AR", Value: envOr("AR", "ar")})
        env = append(env, cfg.EnvVar{Name: "CC", Value: cc})
@@ -145,13 +146,17 @@ func findEnv(env []cfg.EnvVar, name string) string {
 // ExtraEnvVars returns environment variables that should not leak into child processes.
 func ExtraEnvVars() []cfg.EnvVar {
        gomod := ""
+       modload.Init()
        if modload.HasModRoot() {
-               gomod = filepath.Join(modload.ModRoot(), "go.mod")
+               gomod = modload.ModFilePath()
        } else if modload.Enabled() {
                gomod = os.DevNull
        }
+       modload.InitWorkfile()
+       gowork := modload.WorkFilePath()
        return []cfg.EnvVar{
                {Name: "GOMOD", Value: gomod},
+               {Name: "GOWORK", Value: gowork},
        }
 }
 
@@ -191,13 +196,13 @@ func argKey(arg string) string {
 
 func runEnv(ctx context.Context, cmd *base.Command, args []string) {
        if *envJson && *envU {
-               base.Fatalf("go env: cannot use -json with -u")
+               base.Fatalf("go: cannot use -json with -u")
        }
        if *envJson && *envW {
-               base.Fatalf("go env: cannot use -json with -w")
+               base.Fatalf("go: cannot use -json with -w")
        }
        if *envU && *envW {
-               base.Fatalf("go env: cannot use -u with -w")
+               base.Fatalf("go: cannot use -u with -w")
        }
 
        // Handle 'go env -w' and 'go env -u' before calling buildcfg.Check,
@@ -275,7 +280,7 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
 func runEnvW(args []string) {
        // Process and sanity-check command line.
        if len(args) == 0 {
-               base.Fatalf("go env -w: no KEY=VALUE arguments given")
+               base.Fatalf("go: no KEY=VALUE arguments given")
        }
        osEnv := make(map[string]string)
        for _, e := range cfg.OrigEnv {
@@ -287,14 +292,14 @@ func runEnvW(args []string) {
        for _, arg := range args {
                i := strings.Index(arg, "=")
                if i < 0 {
-                       base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
+                       base.Fatalf("go: arguments must be KEY=VALUE: invalid argument: %s", arg)
                }
                key, val := arg[:i], arg[i+1:]
                if err := checkEnvWrite(key, val); err != nil {
-                       base.Fatalf("go env -w: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                if _, ok := add[key]; ok {
-                       base.Fatalf("go env -w: multiple values for key: %s", key)
+                       base.Fatalf("go: multiple values for key: %s", key)
                }
                add[key] = val
                if osVal := osEnv[key]; osVal != "" && osVal != val {
@@ -303,13 +308,13 @@ func runEnvW(args []string) {
        }
 
        if err := checkBuildConfig(add, nil); err != nil {
-               base.Fatalf("go env -w: %v", err)
+               base.Fatalf("go: %v", err)
        }
 
        gotmp, okGOTMP := add["GOTMPDIR"]
        if okGOTMP {
                if !filepath.IsAbs(gotmp) && gotmp != "" {
-                       base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
+                       base.Fatalf("go: GOTMPDIR must be an absolute path")
                }
        }
 
@@ -319,18 +324,18 @@ func runEnvW(args []string) {
 func runEnvU(args []string) {
        // Process and sanity-check command line.
        if len(args) == 0 {
-               base.Fatalf("go env -u: no arguments given")
+               base.Fatalf("go: 'go env -u' requires an argument")
        }
        del := make(map[string]bool)
        for _, arg := range args {
                if err := checkEnvWrite(arg, ""); err != nil {
-                       base.Fatalf("go env -u: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                del[arg] = true
        }
 
        if err := checkBuildConfig(nil, del); err != nil {
-               base.Fatalf("go env -u: %v", err)
+               base.Fatalf("go: %v", err)
        }
 
        updateEnvFile(nil, del)
@@ -414,7 +419,7 @@ func printEnvAsJSON(env []cfg.EnvVar) {
        enc := json.NewEncoder(os.Stdout)
        enc.SetIndent("", "\t")
        if err := enc.Encode(m); err != nil {
-               base.Fatalf("go env -json: %s", err)
+               base.Fatalf("go: %s", err)
        }
 }
 
@@ -429,7 +434,7 @@ func getOrigEnv(key string) string {
 
 func checkEnvWrite(key, val string) error {
        switch key {
-       case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOTOOLDIR", "GOVERSION":
+       case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOWORK", "GOTOOLDIR", "GOVERSION":
                return fmt.Errorf("%s cannot be modified", key)
        case "GOENV":
                return fmt.Errorf("%s can only be set using the OS environment", key)
@@ -457,10 +462,23 @@ func checkEnvWrite(key, val string) error {
                if !filepath.IsAbs(val) && val != "" {
                        return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val)
                }
-       // Make sure CC and CXX are absolute paths
-       case "CC", "CXX", "GOMODCACHE":
-               if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) {
-                       return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, val)
+       case "GOMODCACHE":
+               if !filepath.IsAbs(val) && val != "" {
+                       return fmt.Errorf("GOMODCACHE entry is relative; must be absolute path: %q", val)
+               }
+       case "CC", "CXX":
+               if val == "" {
+                       break
+               }
+               args, err := quoted.Split(val)
+               if err != nil {
+                       return fmt.Errorf("invalid %s: %v", key, err)
+               }
+               if len(args) == 0 {
+                       return fmt.Errorf("%s entry cannot contain only space", key)
+               }
+               if !filepath.IsAbs(args[0]) && args[0] != filepath.Base(args[0]) {
+                       return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, args[0])
                }
        }
 
@@ -479,11 +497,11 @@ func checkEnvWrite(key, val string) error {
 func updateEnvFile(add map[string]string, del map[string]bool) {
        file, err := cfg.EnvFile()
        if file == "" {
-               base.Fatalf("go env: cannot find go env config: %v", err)
+               base.Fatalf("go: cannot find go env config: %v", err)
        }
        data, err := os.ReadFile(file)
        if err != nil && (!os.IsNotExist(err) || len(add) == 0) {
-               base.Fatalf("go env: reading go env config: %v", err)
+               base.Fatalf("go: reading go env config: %v", err)
        }
 
        lines := strings.SplitAfter(string(data), "\n")
@@ -541,7 +559,7 @@ func updateEnvFile(add map[string]string, del map[string]bool) {
                os.MkdirAll(filepath.Dir(file), 0777)
                err = os.WriteFile(file, data, 0666)
                if err != nil {
-                       base.Fatalf("go env: writing go env config: %v", err)
+                       base.Fatalf("go: writing go env config: %v", err)
                }
        }
 }
index cc5940fccd8f27672a3c202b2b06a322a40b820d..d8ba353de6595091f10b693bcb3aed1fde9d2e0d 100644 (file)
@@ -10,28 +10,40 @@ import (
        "cmd/go/internal/cfg"
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
+       "cmd/go/internal/work"
        "context"
        "fmt"
+       "go/build"
        "os"
 )
 
 var CmdFix = &base.Command{
-       Run:       runFix,
-       UsageLine: "go fix [packages]",
+       UsageLine: "go fix [-fix list] [packages]",
        Short:     "update packages to use new APIs",
        Long: `
 Fix runs the Go fix command on the packages named by the import paths.
 
+The -fix flag sets a comma-separated list of fixes to run.
+The default is all known fixes.
+(Its value is passed to 'go tool fix -r'.)
+
 For more about fix, see 'go doc cmd/fix'.
 For more about specifying packages, see 'go help packages'.
 
-To run fix with specific options, run 'go tool fix'.
+To run fix with other options, run 'go tool fix'.
 
 See also: go fmt, go vet.
        `,
 }
 
+var fixes = CmdFix.Flag.String("fix", "", "comma-separated list of fixes to apply")
+
+func init() {
+       work.AddBuildFlags(CmdFix, work.DefaultBuildFlags)
+       CmdFix.Run = runFix // fix cycle
+}
+
 func runFix(ctx context.Context, cmd *base.Command, args []string) {
        pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args)
        w := 0
@@ -58,6 +70,16 @@ func runFix(ctx context.Context, cmd *base.Command, args []string) {
                // the command only applies to this package,
                // not to packages in subdirectories.
                files := base.RelPaths(pkg.InternalAllGoFiles())
-               base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), files))
+               goVersion := ""
+               if pkg.Module != nil {
+                       goVersion = "go" + pkg.Module.GoVersion
+               } else if pkg.Standard {
+                       goVersion = build.Default.ReleaseTags[len(build.Default.ReleaseTags)-1]
+               }
+               var fixArg []string
+               if *fixes != "" {
+                       fixArg = []string{"-r=" + *fixes}
+               }
+               base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), "-go="+goVersion, fixArg, files))
        }
 }
index 2b89a078acce4a3d7e7c94db8b99f614faadaece..19656eab7fc661c4cea1fabf55630f38ab2b3c98 100644 (file)
@@ -11,14 +11,12 @@ import (
        "fmt"
        "os"
        "path/filepath"
-       "runtime"
-       "sync"
 
        "cmd/go/internal/base"
        "cmd/go/internal/cfg"
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
-       "cmd/internal/str"
+       "cmd/internal/sys"
 )
 
 func init() {
@@ -53,18 +51,13 @@ See also: go fix, go vet.
 func runFmt(ctx context.Context, cmd *base.Command, args []string) {
        printed := false
        gofmt := gofmtPath()
-       procs := runtime.GOMAXPROCS(0)
-       var wg sync.WaitGroup
-       wg.Add(procs)
-       fileC := make(chan string, 2*procs)
-       for i := 0; i < procs; i++ {
-               go func() {
-                       defer wg.Done()
-                       for file := range fileC {
-                               base.Run(str.StringList(gofmt, "-l", "-w", file))
-                       }
-               }()
-       }
+
+       gofmtArgs := []string{gofmt, "-l", "-w"}
+       gofmtArgLen := len(gofmt) + len(" -l -w")
+
+       baseGofmtArgs := len(gofmtArgs)
+       baseGofmtArgLen := gofmtArgLen
+
        for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) {
                if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
                        if !printed {
@@ -89,11 +82,18 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
                // not to packages in subdirectories.
                files := base.RelPaths(pkg.InternalAllGoFiles())
                for _, file := range files {
-                       fileC <- file
+                       gofmtArgs = append(gofmtArgs, file)
+                       gofmtArgLen += 1 + len(file) // plus separator
+                       if gofmtArgLen >= sys.ExecArgLengthLimit {
+                               base.Run(gofmtArgs)
+                               gofmtArgs = gofmtArgs[:baseGofmtArgs]
+                               gofmtArgLen = baseGofmtArgLen
+                       }
                }
        }
-       close(fileC)
-       wg.Wait()
+       if len(gofmtArgs) > baseGofmtArgs {
+               base.Run(gofmtArgs)
+       }
 }
 
 func gofmtPath() string {
index 7f175c7031169dded7b720e9899f7d38909f8d74..c080c14987c37cad5928771d49bb0a4b1b602953 100644 (file)
@@ -1,7 +1,6 @@
 package fsys
 
 import (
-       "cmd/go/internal/txtar"
        "encoding/json"
        "errors"
        "fmt"
@@ -12,6 +11,8 @@ import (
        "path/filepath"
        "reflect"
        "testing"
+
+       "golang.org/x/tools/txtar"
 )
 
 // initOverlay resets the overlay state to reflect the config.
index d7f2eb46107cf568259be59c59f93a773ac8ccb7..a3873d11387c8195f0de88a887f1c4ead93ce3ed 100644 (file)
@@ -26,7 +26,7 @@ import (
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
        "cmd/go/internal/work"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 var CmdGenerate = &base.Command{
@@ -38,7 +38,7 @@ Generate runs commands described by directives within existing
 files. Those commands can run any process but the intent is to
 create or update Go source files.
 
-Go generate is never run automatically by go build, go get, go test,
+Go generate is never run automatically by go build, go test,
 and so on. It must be run explicitly.
 
 Go generate scans the file for directives, which are lines of
index 836364e39b6e0358d0c641982090a14d87bc53d9..f46313dcff605434dfc4902e8fe91a59f1acf587 100644 (file)
@@ -20,7 +20,7 @@ import (
        "cmd/go/internal/vcs"
        "cmd/go/internal/web"
        "cmd/go/internal/work"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/module"
 )
@@ -114,16 +114,16 @@ func init() {
 func runGet(ctx context.Context, cmd *base.Command, args []string) {
        if cfg.ModulesEnabled {
                // Should not happen: main.go should install the separate module-enabled get code.
-               base.Fatalf("go get: modules not implemented")
+               base.Fatalf("go: modules not implemented")
        }
 
        work.BuildInit()
 
        if *getF && !*getU {
-               base.Fatalf("go get: cannot use -f flag without -u")
+               base.Fatalf("go: cannot use -f flag without -u")
        }
        if *getInsecure {
-               base.Fatalf("go get: -insecure flag is no longer supported; use GOINSECURE instead")
+               base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead")
        }
 
        // Disable any prompting for passwords by Git itself.
@@ -214,18 +214,19 @@ func downloadPaths(patterns []string) []string {
                // if the argument has no slash or refers to an existing file.
                if strings.HasSuffix(arg, ".go") {
                        if !strings.Contains(arg, "/") {
-                               base.Errorf("go get %s: arguments must be package or module paths", arg)
+                               base.Errorf("go: %s: arguments must be package or module paths", arg)
                                continue
                        }
                        if fi, err := os.Stat(arg); err == nil && !fi.IsDir() {
-                               base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", arg)
+                               base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", arg)
                        }
                }
        }
        base.ExitIfErrors()
 
        var pkgs []string
-       for _, m := range search.ImportPathsQuiet(patterns) {
+       noModRoots := []string{}
+       for _, m := range search.ImportPathsQuiet(patterns, noModRoots) {
                if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
                        pkgs = append(pkgs, m.Pattern())
                } else {
@@ -315,7 +316,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
                if wildcardOkay && strings.Contains(arg, "...") {
                        match := search.NewMatch(arg)
                        if match.IsLocal() {
-                               match.MatchDirs()
+                               noModRoots := []string{} // We're in gopath mode, so there are no modroots.
+                               match.MatchDirs(noModRoots)
                                args = match.Dirs
                        } else {
                                match.MatchPackages()
@@ -415,10 +417,10 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
 // to make the first copy of or update a copy of the given package.
 func downloadPackage(p *load.Package) error {
        var (
-               vcsCmd         *vcs.Cmd
-               repo, rootPath string
-               err            error
-               blindRepo      bool // set if the repo has unusual configuration
+               vcsCmd                  *vcs.Cmd
+               repo, rootPath, repoDir string
+               err                     error
+               blindRepo               bool // set if the repo has unusual configuration
        )
 
        // p can be either a real package, or a pseudo-package whose “import path” is
@@ -444,10 +446,19 @@ func downloadPackage(p *load.Package) error {
 
        if p.Internal.Build.SrcRoot != "" {
                // Directory exists. Look for checkout along path to src.
-               vcsCmd, rootPath, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot)
+               const allowNesting = false
+               repoDir, vcsCmd, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot, allowNesting)
                if err != nil {
                        return err
                }
+               if !str.HasFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) {
+                       panic(fmt.Sprintf("repository %q not in source root %q", repo, p.Internal.Build.SrcRoot))
+               }
+               rootPath = str.TrimFilePathPrefix(repoDir, p.Internal.Build.SrcRoot)
+               if err := vcs.CheckGOVCS(vcsCmd, rootPath); err != nil {
+                       return err
+               }
+
                repo = "<local>" // should be unused; make distinctive
 
                // Double-check where it came from.
index 490ff1fb7cf05bd5a7e107c1ea40bb44174cc0db..035235fe1b5a1d39a3e8228daa20362fee8af86c 100644 (file)
@@ -592,6 +592,10 @@ Architecture-specific environment variables:
        GO386
                For GOARCH=386, how to implement floating point instructions.
                Valid values are sse2 (default), softfloat.
+       GOAMD64
+               For GOARCH=amd64, the microarchitecture level for which to compile.
+               Valid values are v1 (default), v2, v3, v4.
+               See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels.
        GOMIPS
                For GOARCH=mips{,le}, whether to use floating point instructions.
                Valid values are hardfloat (default), softfloat.
@@ -771,6 +775,13 @@ The go command also caches successful package test results.
 See 'go help test' for details. Running 'go clean -testcache' removes
 all cached test results (but not cached build results).
 
+The go command also caches values used in fuzzing with 'go test -fuzz',
+specifically, values that expanded code coverage when passed to a
+fuzz function. These values are not used for regular building and
+testing, but they're stored in a subdirectory of the build cache.
+Running 'go clean -fuzzcache' removes all cached fuzzing values.
+This may make fuzzing less effective, temporarily.
+
 The GODEBUG environment variable can enable printing of debugging
 information about the state of the cache:
 
index 50aeabc578c93094ce776e99d25d0612e7397bbc..ff6bea6777dce89c81385f1e38182e43de12f821 100644 (file)
@@ -2,17 +2,51 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Copied from Go distribution src/go/build/build.go, syslist.go
+// Copied from Go distribution src/go/build/build.go, syslist.go.
+// That package does not export the ability to process raw file data,
+// although we could fake it with an appropriate build.Context
+// and a lot of unwrapping.
+// More importantly, that package does not implement the tags["*"]
+// special case, in which both tag and !tag are considered to be true
+// for essentially all tags (except "ignore").
+//
+// If we added this API to go/build directly, we wouldn't need this
+// file anymore, but this API is not terribly general-purpose and we
+// don't really want to commit to any public form of it, nor do we
+// want to move the core parts of go/build into a top-level internal package.
+// These details change very infrequently, so the copy is fine.
 
 package imports
 
 import (
        "bytes"
+       "errors"
+       "fmt"
+       "go/build/constraint"
        "strings"
        "unicode"
 )
 
-var slashslash = []byte("//")
+var (
+       bSlashSlash = []byte("//")
+       bStarSlash  = []byte("*/")
+       bSlashStar  = []byte("/*")
+       bPlusBuild  = []byte("+build")
+
+       goBuildComment = []byte("//go:build")
+
+       errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
+       errMultipleGoBuild     = errors.New("multiple //go:build comments")
+)
+
+func isGoBuildComment(line []byte) bool {
+       if !bytes.HasPrefix(line, goBuildComment) {
+               return false
+       }
+       line = bytes.TrimSpace(line)
+       rest := line[len(goBuildComment):]
+       return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
+}
 
 // ShouldBuild reports whether it is okay to use this file,
 // The rule is that in the file's leading run of // comments
@@ -34,10 +68,61 @@ var slashslash = []byte("//")
 // in any build.
 //
 func ShouldBuild(content []byte, tags map[string]bool) bool {
-       // Pass 1. Identify leading run of // comments and blank lines,
+       // Identify leading run of // comments and blank lines,
        // which must be followed by a blank line.
+       // Also identify any //go:build comments.
+       content, goBuild, _, err := parseFileHeader(content)
+       if err != nil {
+               return false
+       }
+
+       // If //go:build line is present, it controls.
+       // Otherwise fall back to +build processing.
+       var shouldBuild bool
+       switch {
+       case goBuild != nil:
+               x, err := constraint.Parse(string(goBuild))
+               if err != nil {
+                       return false
+               }
+               shouldBuild = eval(x, tags, true)
+
+       default:
+               shouldBuild = true
+               p := content
+               for len(p) > 0 {
+                       line := p
+                       if i := bytes.IndexByte(line, '\n'); i >= 0 {
+                               line, p = line[:i], p[i+1:]
+                       } else {
+                               p = p[len(p):]
+                       }
+                       line = bytes.TrimSpace(line)
+                       if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
+                               continue
+                       }
+                       text := string(line)
+                       if !constraint.IsPlusBuild(text) {
+                               continue
+                       }
+                       if x, err := constraint.Parse(text); err == nil {
+                               if !eval(x, tags, true) {
+                                       shouldBuild = false
+                               }
+                       }
+               }
+       }
+
+       return shouldBuild
+}
+
+func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
        end := 0
        p := content
+       ended := false       // found non-blank, non-// line, so stopped accepting // +build lines
+       inSlashStar := false // in /* */ comment
+
+Lines:
        for len(p) > 0 {
                line := p
                if i := bytes.IndexByte(line, '\n'); i >= 0 {
@@ -46,78 +131,61 @@ func ShouldBuild(content []byte, tags map[string]bool) bool {
                        p = p[len(p):]
                }
                line = bytes.TrimSpace(line)
-               if len(line) == 0 { // Blank line
+               if len(line) == 0 && !ended { // Blank line
+                       // Remember position of most recent blank line.
+                       // When we find the first non-blank, non-// line,
+                       // this "end" position marks the latest file position
+                       // where a // +build line can appear.
+                       // (It must appear _before_ a blank line before the non-blank, non-// line.
+                       // Yes, that's confusing, which is part of why we moved to //go:build lines.)
+                       // Note that ended==false here means that inSlashStar==false,
+                       // since seeing a /* would have set ended==true.
                        end = len(content) - len(p)
-                       continue
+                       continue Lines
                }
-               if !bytes.HasPrefix(line, slashslash) { // Not comment line
-                       break
+               if !bytes.HasPrefix(line, bSlashSlash) { // Not comment line
+                       ended = true
                }
-       }
-       content = content[:end]
 
-       // Pass 2.  Process each line in the run.
-       p = content
-       allok := true
-       for len(p) > 0 {
-               line := p
-               if i := bytes.IndexByte(line, '\n'); i >= 0 {
-                       line, p = line[:i], p[i+1:]
-               } else {
-                       p = p[len(p):]
-               }
-               line = bytes.TrimSpace(line)
-               if !bytes.HasPrefix(line, slashslash) {
-                       continue
+               if !inSlashStar && isGoBuildComment(line) {
+                       if goBuild != nil {
+                               return nil, nil, false, errMultipleGoBuild
+                       }
+                       goBuild = line
                }
-               line = bytes.TrimSpace(line[len(slashslash):])
-               if len(line) > 0 && line[0] == '+' {
-                       // Looks like a comment +line.
-                       f := strings.Fields(string(line))
-                       if f[0] == "+build" {
-                               ok := false
-                               for _, tok := range f[1:] {
-                                       if matchTags(tok, tags) {
-                                               ok = true
-                                       }
-                               }
-                               if !ok {
-                                       allok = false
+
+       Comments:
+               for len(line) > 0 {
+                       if inSlashStar {
+                               if i := bytes.Index(line, bStarSlash); i >= 0 {
+                                       inSlashStar = false
+                                       line = bytes.TrimSpace(line[i+len(bStarSlash):])
+                                       continue Comments
                                }
+                               continue Lines
                        }
+                       if bytes.HasPrefix(line, bSlashSlash) {
+                               continue Lines
+                       }
+                       if bytes.HasPrefix(line, bSlashStar) {
+                               inSlashStar = true
+                               line = bytes.TrimSpace(line[len(bSlashStar):])
+                               continue Comments
+                       }
+                       // Found non-comment text.
+                       break Lines
                }
        }
 
-       return allok
-}
-
-// matchTags reports whether the name is one of:
-//
-//     tag (if tags[tag] is true)
-//     !tag (if tags[tag] is false)
-//     a comma-separated list of any of these
-//
-func matchTags(name string, tags map[string]bool) bool {
-       if name == "" {
-               return false
-       }
-       if i := strings.Index(name, ","); i >= 0 {
-               // comma-separated list
-               ok1 := matchTags(name[:i], tags)
-               ok2 := matchTags(name[i+1:], tags)
-               return ok1 && ok2
-       }
-       if strings.HasPrefix(name, "!!") { // bad syntax, reject always
-               return false
-       }
-       if strings.HasPrefix(name, "!") { // negation
-               return len(name) > 1 && matchTag(name[1:], tags, false)
-       }
-       return matchTag(name, tags, true)
+       return content[:end], goBuild, sawBinaryOnly, nil
 }
 
-// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
-func matchTag(name string, tags map[string]bool, want bool) bool {
+// matchTag reports whether the tag name is valid and tags[name] is true.
+// As a special case, if tags["*"] is true and name is not empty or ignore,
+// then matchTag will return prefer instead of the actual answer,
+// which allows the caller to pretend in that case that most tags are
+// both true and false.
+func matchTag(name string, tags map[string]bool, prefer bool) bool {
        // Tags must be letters, digits, underscores or dots.
        // Unlike in Go identifiers, all digits are fine (e.g., "386").
        for _, c := range name {
@@ -131,7 +199,7 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
                // if we put * in the tags map then all tags
                // except "ignore" are considered both present and not
                // (so we return true no matter how 'want' is set).
-               return true
+               return prefer
        }
 
        have := tags[name]
@@ -144,7 +212,25 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
        if name == "darwin" {
                have = have || tags["ios"]
        }
-       return have == want
+       return have
+}
+
+// eval is like
+//     x.Eval(func(tag string) bool { return matchTag(tag, tags) })
+// except that it implements the special case for tags["*"] meaning
+// all tags are both true and false at the same time.
+func eval(x constraint.Expr, tags map[string]bool, prefer bool) bool {
+       switch x := x.(type) {
+       case *constraint.TagExpr:
+               return matchTag(x.Tag, tags, prefer)
+       case *constraint.NotExpr:
+               return !eval(x.X, tags, !prefer)
+       case *constraint.AndExpr:
+               return eval(x.X, tags, prefer) && eval(x.Y, tags, prefer)
+       case *constraint.OrExpr:
+               return eval(x.X, tags, prefer) || eval(x.Y, tags, prefer)
+       }
+       panic(fmt.Sprintf("unexpected constraint expression %T", x))
 }
 
 // MatchFile returns false if the name contains a $GOOS or $GOARCH
index 2d245ee7872e73c706b15dcf6b2e1f9559248412..7e69c56513ac01a2acf0d5cd5d4372597abd96f0 100644 (file)
@@ -33,7 +33,7 @@ func TestScan(t *testing.T) {
                }
                if p == "net/http" {
                        // A test import but not an import
-                       t.Errorf("json reported as importing encoding/binary but does not")
+                       t.Errorf("json reported as importing net/http but does not")
                }
        }
        if !foundBase64 {
index 4b8c0e9f48259bf6c24d4b6fcc6669127e75d15d..8c85ddcf21163e94b0dad71b61801f492195080c 100644 (file)
@@ -24,7 +24,7 @@ import (
        "cmd/go/internal/modinfo"
        "cmd/go/internal/modload"
        "cmd/go/internal/work"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 var CmdList = &base.Command{
@@ -316,6 +316,7 @@ For more about modules, see https://golang.org/ref/mod.
 func init() {
        CmdList.Run = runList // break init cycle
        work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
+       base.AddWorkfileFlag(&CmdList.Flag)
 }
 
 var (
@@ -336,6 +337,8 @@ var (
 var nl = []byte{'\n'}
 
 func runList(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
+
        if *listFmt != "" && *listJson == true {
                base.Fatalf("go list -f cannot be used with -json")
        }
@@ -424,12 +427,12 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
                }
 
                if modload.Init(); !modload.Enabled() {
-                       base.Fatalf("go list -m: not using modules")
+                       base.Fatalf("go: list -m cannot be used with GO111MODULE=off")
                }
 
                modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect.
                if cfg.BuildMod == "vendor" {
-                       const actionDisabledFormat = "go list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
+                       const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
 
                        if *listVersions {
                                base.Fatalf(actionDisabledFormat, "determine available versions")
@@ -468,11 +471,11 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
                if !*listE {
                        for _, m := range mods {
                                if m.Error != nil {
-                                       base.Errorf("go list -m: %v", m.Error.Err)
+                                       base.Errorf("go: %v", m.Error.Err)
                                }
                        }
                        if err != nil {
-                               base.Errorf("go list -m: %v", err)
+                               base.Errorf("go: %v", err)
                        }
                        base.ExitIfErrors()
                }
@@ -708,7 +711,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
                        }
                        rmods, err := modload.ListModules(ctx, args, mode)
                        if err != nil && !*listE {
-                               base.Errorf("go list -retracted: %v", err)
+                               base.Errorf("go: %v", err)
                        }
                        for i, arg := range args {
                                rmod := rmods[i]
index 4e0cb5bc19ef76bd43899380599854ccc73ca5f5..de079decdf2541c6f7ac312e002aec761427bfbc 100644 (file)
@@ -6,7 +6,7 @@ package load
 
 import (
        "cmd/go/internal/base"
-       "cmd/internal/str"
+       "cmd/internal/quoted"
        "fmt"
        "strings"
 )
@@ -22,6 +22,7 @@ var (
 // that allows specifying different effective flags for different packages.
 // See 'go help build' for more details about per-package flags.
 type PerPackageFlag struct {
+       raw     string
        present bool
        values  []ppfValue
 }
@@ -39,6 +40,7 @@ func (f *PerPackageFlag) Set(v string) error {
 
 // set is the implementation of Set, taking a cwd (current working directory) for easier testing.
 func (f *PerPackageFlag) set(v, cwd string) error {
+       f.raw = v
        f.present = true
        match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern
        // For backwards compatibility with earlier flag splitting, ignore spaces around flags.
@@ -61,7 +63,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
                match = MatchPackage(pattern, cwd)
                v = v[i+1:]
        }
-       flags, err := str.SplitQuotedFields(v)
+       flags, err := quoted.Split(v)
        if err != nil {
                return err
        }
@@ -72,9 +74,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
        return nil
 }
 
-// String is required to implement flag.Value.
-// It is not used, because cmd/go never calls flag.PrintDefaults.
-func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }
+func (f *PerPackageFlag) String() string { return f.raw }
 
 // Present reports whether the flag appeared on the command line.
 func (f *PerPackageFlag) Present() bool {
index f5f0f3539318af4b0d6ac7eb32cd7eac2702aabf..f9051cce3dd0bc902f9178bc42a71c093fc68e96 100644 (file)
@@ -21,9 +21,11 @@ import (
        pathpkg "path"
        "path/filepath"
        "runtime"
+       "runtime/debug"
        "sort"
        "strconv"
        "strings"
+       "time"
        "unicode"
        "unicode/utf8"
 
@@ -36,8 +38,9 @@ import (
        "cmd/go/internal/modload"
        "cmd/go/internal/par"
        "cmd/go/internal/search"
+       "cmd/go/internal/str"
        "cmd/go/internal/trace"
-       "cmd/internal/str"
+       "cmd/go/internal/vcs"
        "cmd/internal/sys"
 
        "golang.org/x/mod/modfile"
@@ -203,6 +206,7 @@ type PackageInternal struct {
        Local             bool                 // imported via local path (./ or ../)
        LocalPrefix       string               // interpret ./ and ../ imports relative to this prefix
        ExeName           string               // desired name for temporary executable
+       FuzzInstrument    bool                 // package should be instrumented for fuzzing
        CoverMode         string               // preprocess Go source files with the coverage tool in this mode
        CoverVars         map[string]*CoverVar // variables created by coverage analysis
        OmitDebug         bool                 // tell linker not to write debug information
@@ -1456,9 +1460,9 @@ func disallowInternal(ctx context.Context, srcDir string, importer *Package, imp
                        // The importer is a list of command-line files.
                        // Pretend that the import path is the import path of the
                        // directory containing them.
-                       // If the directory is outside the main module, this will resolve to ".",
+                       // If the directory is outside the main modules, this will resolve to ".",
                        // which is not a prefix of any valid module.
-                       importerPath = modload.DirImportPath(ctx, importer.Dir)
+                       importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
                }
                parentOfInternal := p.ImportPath[:i]
                if str.HasPathPrefix(importerPath, parentOfInternal) {
@@ -1628,6 +1632,7 @@ var cgoSyscallExclude = map[string]bool{
        "runtime/cgo":  true,
        "runtime/race": true,
        "runtime/msan": true,
+       "runtime/asan": true,
 }
 
 var foldPath = make(map[string]string)
@@ -1683,9 +1688,10 @@ func (p *Package) DefaultExecName() string {
 func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
        p.copyBuild(opts, bp)
 
-       // The localPrefix is the path we interpret ./ imports relative to.
+       // The localPrefix is the path we interpret ./ imports relative to,
+       // if we support them at all (not in module mode!).
        // Synthesized main packages sometimes override this.
-       if p.Internal.Local {
+       if p.Internal.Local && !cfg.ModulesEnabled {
                p.Internal.LocalPrefix = dirToImportPath(p.Dir)
        }
 
@@ -1925,9 +1931,8 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
        }
        p.Internal.Imports = imports
        p.collectDeps()
-
-       if cfg.ModulesEnabled && p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
-               p.Internal.BuildInfo = modload.PackageBuildInfo(pkgPath, p.Deps)
+       if p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
+               p.setBuildInfo()
        }
 
        // unsafe is a fake package.
@@ -2199,6 +2204,191 @@ func (p *Package) collectDeps() {
        }
 }
 
+// setBuildInfo gathers build information, formats it as a string to be
+// embedded in the binary, then sets p.Internal.BuildInfo to that string.
+// setBuildInfo should only be called on a main package with no errors.
+//
+// This information can be retrieved using debug.ReadBuildInfo.
+//
+// Note that the GoVersion field is not set here to avoid encoding it twice.
+// It is stored separately in the binary, mostly for historical reasons.
+func (p *Package) setBuildInfo() {
+       // TODO: build and vcs information is not embedded for executables in GOROOT.
+       // cmd/dist uses -gcflags=all= -ldflags=all= by default, which means these
+       // executables always appear stale unless the user sets the same flags.
+       // Perhaps it's safe to omit those flags when GO_GCFLAGS and GO_LDFLAGS
+       // are not set?
+       setPkgErrorf := func(format string, args ...interface{}) {
+               if p.Error == nil {
+                       p.Error = &PackageError{Err: fmt.Errorf(format, args...)}
+               }
+       }
+
+       var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module
+       debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module {
+               dm := &debug.Module{
+                       Path:    mi.Path,
+                       Version: mi.Version,
+               }
+               if mi.Replace != nil {
+                       dm.Replace = debugModFromModinfo(mi.Replace)
+               } else {
+                       dm.Sum = modfetch.Sum(module.Version{Path: mi.Path, Version: mi.Version})
+               }
+               return dm
+       }
+
+       var main debug.Module
+       if p.Module != nil {
+               main = *debugModFromModinfo(p.Module)
+       }
+
+       visited := make(map[*Package]bool)
+       mdeps := make(map[module.Version]*debug.Module)
+       var q []*Package
+       q = append(q, p.Internal.Imports...)
+       for len(q) > 0 {
+               p1 := q[0]
+               q = q[1:]
+               if visited[p1] {
+                       continue
+               }
+               visited[p1] = true
+               if p1.Module != nil {
+                       m := module.Version{Path: p1.Module.Path, Version: p1.Module.Version}
+                       if p1.Module.Path != main.Path && mdeps[m] == nil {
+                               mdeps[m] = debugModFromModinfo(p1.Module)
+                       }
+               }
+               q = append(q, p1.Internal.Imports...)
+       }
+       sortedMods := make([]module.Version, 0, len(mdeps))
+       for mod := range mdeps {
+               sortedMods = append(sortedMods, mod)
+       }
+       module.Sort(sortedMods)
+       deps := make([]*debug.Module, len(sortedMods))
+       for i, mod := range sortedMods {
+               deps[i] = mdeps[mod]
+       }
+
+       pkgPath := p.ImportPath
+       if p.Internal.CmdlineFiles {
+               pkgPath = "command-line-arguments"
+       }
+       info := &debug.BuildInfo{
+               Path: pkgPath,
+               Main: main,
+               Deps: deps,
+       }
+       appendSetting := func(key, value string) {
+               info.Settings = append(info.Settings, debug.BuildSetting{Key: key, Value: value})
+       }
+
+       // Add command-line flags relevant to the build.
+       // This is informational, not an exhaustive list.
+       if cfg.BuildBuildinfo && !p.Standard {
+               appendSetting("compiler", cfg.BuildContext.Compiler)
+               if BuildAsmflags.present {
+                       appendSetting("asmflags", BuildAsmflags.String())
+               }
+               if BuildGcflags.present && cfg.BuildContext.Compiler == "gc" {
+                       appendSetting("gcflags", BuildGcflags.String())
+               }
+               if BuildGccgoflags.present && cfg.BuildContext.Compiler == "gccgo" {
+                       appendSetting("gccgoflags", BuildGccgoflags.String())
+               }
+               if BuildLdflags.present {
+                       appendSetting("ldflags", BuildLdflags.String())
+               }
+               tags := append(cfg.BuildContext.BuildTags, cfg.BuildContext.ToolTags...)
+               appendSetting("tags", strings.Join(tags, ","))
+               appendSetting("CGO_ENABLED", strconv.FormatBool(cfg.BuildContext.CgoEnabled))
+               if cfg.BuildContext.CgoEnabled {
+                       for _, name := range []string{"CGO_CPPFLAGS", "CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} {
+                               appendSetting(name, cfg.Getenv(name))
+                       }
+               }
+       }
+
+       // Add VCS status if all conditions are true:
+       //
+       // - -buildvcs is enabled.
+       // - p is contained within a main module (there may be multiple main modules
+       //   in a workspace, but local replacements don't count).
+       // - Both the current directory and p's module's root directory are contained
+       //   in the same local repository.
+       // - We know the VCS commands needed to get the status.
+       setVCSError := func(err error) {
+               setPkgErrorf("error obtaining VCS status: %v\n\tUse -buildvcs=false to disable VCS stamping.", err)
+       }
+
+       var repoDir string
+       var vcsCmd *vcs.Cmd
+       var err error
+       const allowNesting = true
+       if cfg.BuildBuildvcs && p.Module != nil && p.Module.Version == "" && !p.Standard {
+               repoDir, vcsCmd, err = vcs.FromDir(base.Cwd(), "", allowNesting)
+               if err != nil && !errors.Is(err, os.ErrNotExist) {
+                       setVCSError(err)
+                       return
+               }
+               if !str.HasFilePathPrefix(p.Module.Dir, repoDir) &&
+                       !str.HasFilePathPrefix(repoDir, p.Module.Dir) {
+                       // The module containing the main package does not overlap with the
+                       // repository containing the working directory. Don't include VCS info.
+                       // If the repo contains the module or vice versa, but they are not
+                       // the same directory, it's likely an error (see below).
+                       repoDir, vcsCmd = "", nil
+               }
+       }
+       if repoDir != "" && vcsCmd.Status != nil {
+               // Check that the current directory, package, and module are in the same
+               // repository. vcs.FromDir allows nested Git repositories, but nesting
+               // is not allowed for other VCS tools. The current directory may be outside
+               // p.Module.Dir when a workspace is used.
+               pkgRepoDir, _, err := vcs.FromDir(p.Dir, "", allowNesting)
+               if err != nil {
+                       setVCSError(err)
+                       return
+               }
+               if pkgRepoDir != repoDir {
+                       setVCSError(fmt.Errorf("main package is in repository %q but current directory is in repository %q", pkgRepoDir, repoDir))
+                       return
+               }
+               modRepoDir, _, err := vcs.FromDir(p.Module.Dir, "", allowNesting)
+               if err != nil {
+                       setVCSError(err)
+                       return
+               }
+               if modRepoDir != repoDir {
+                       setVCSError(fmt.Errorf("main module is in repository %q but current directory is in repository %q", modRepoDir, repoDir))
+                       return
+               }
+
+               st, err := vcsCmd.Status(vcsCmd, repoDir)
+               if err != nil {
+                       setVCSError(err)
+                       return
+               }
+               if st.Revision != "" {
+                       appendSetting(vcsCmd.Cmd+"revision", st.Revision)
+               }
+               if !st.CommitTime.IsZero() {
+                       stamp := st.CommitTime.UTC().Format(time.RFC3339Nano)
+                       appendSetting(vcsCmd.Cmd+"committime", stamp)
+               }
+               appendSetting(vcsCmd.Cmd+"uncommitted", strconv.FormatBool(st.Uncommitted))
+       }
+
+       text, err := info.MarshalText()
+       if err != nil {
+               setPkgErrorf("error formatting build info: %v", err)
+               return
+       }
+       p.Internal.BuildInfo = string(text)
+}
+
 // SafeArg reports whether arg is a "safe" command-line argument,
 // meaning that when it appears in a command-line, it probably
 // doesn't have some special meaning other than its own name.
@@ -2237,6 +2427,10 @@ func LinkerDeps(p *Package) []string {
        if cfg.BuildMSan {
                deps = append(deps, "runtime/msan")
        }
+       // Using address sanitizer forces an import of runtime/asan.
+       if cfg.BuildASan {
+               deps = append(deps, "runtime/asan")
+       }
 
        return deps
 }
@@ -2453,7 +2647,8 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
                }
                matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
        } else {
-               matches = search.ImportPaths(patterns)
+               noModRoots := []string{}
+               matches = search.ImportPaths(patterns, noModRoots)
        }
 
        var (
@@ -2679,10 +2874,7 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
                if fi.IsDir() {
                        base.Fatalf("%s is a directory, should be a Go file", file)
                }
-               dir1, _ := filepath.Split(file)
-               if dir1 == "" {
-                       dir1 = "./"
-               }
+               dir1 := filepath.Dir(file)
                if dir == "" {
                        dir = dir1
                } else if dir != dir1 {
@@ -2710,7 +2902,9 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
        pkg.Internal.Local = true
        pkg.Internal.CmdlineFiles = true
        pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err)
-       pkg.Internal.LocalPrefix = dirToImportPath(dir)
+       if !cfg.ModulesEnabled {
+               pkg.Internal.LocalPrefix = dirToImportPath(dir)
+       }
        pkg.ImportPath = "command-line-arguments"
        pkg.Target = ""
        pkg.Match = gofiles
index 42eefe37ba54870883c3729da892e24880dabe56..8a18dfbe931c9b2416ee142fbc8793859d9d9d1b 100644 (file)
@@ -23,7 +23,7 @@ import (
 
        "cmd/go/internal/fsys"
        "cmd/go/internal/trace"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 var TestMainDeps = []string{
@@ -555,6 +555,7 @@ func formatTestmain(t *testFuncs) ([]byte, error) {
 type testFuncs struct {
        Tests       []testFunc
        Benchmarks  []testFunc
+       FuzzTargets []testFunc
        Examples    []testFunc
        TestMain    *testFunc
        Package     *Package
@@ -653,6 +654,13 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
                        }
                        t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
                        *doImport, *seen = true, true
+               case isTest(name, "Fuzz"):
+                       err := checkTestFunc(n, "F")
+                       if err != nil {
+                               return err
+                       }
+                       t.FuzzTargets = append(t.FuzzTargets, testFunc{pkg, name, "", false})
+                       *doImport, *seen = true, true
                }
        }
        ex := doc.Examples(f)
@@ -670,10 +678,16 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
 }
 
 func checkTestFunc(fn *ast.FuncDecl, arg string) error {
+       var why string
        if !isTestFunc(fn, arg) {
-               name := fn.Name.String()
+               why = fmt.Sprintf("must be: func %s(%s *testing.%s)", fn.Name.String(), strings.ToLower(arg), arg)
+       }
+       if fn.Type.TypeParams.NumFields() > 0 {
+               why = "test functions cannot have type parameters"
+       }
+       if why != "" {
                pos := testFileSet.Position(fn.Pos())
-               return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
+               return fmt.Errorf("%s: wrong signature for %s, %s", pos, fn.Name.String(), why)
        }
        return nil
 }
@@ -716,6 +730,12 @@ var benchmarks = []testing.InternalBenchmark{
 {{end}}
 }
 
+var fuzzTargets = []testing.InternalFuzzTarget{
+{{range .FuzzTargets}}
+       {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
 var examples = []testing.InternalExample{
 {{range .Examples}}
        {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
@@ -774,7 +794,7 @@ func main() {
                CoveredPackages: {{printf "%q" .Covered}},
        })
 {{end}}
-       m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
+       m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
 {{with .TestMain}}
        {{.Package}}.{{.Name}}(m)
        os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
index a37b2ad6d184b0f89169e4e0e1d8ff5e396b8370..09354d23061ec78452c36398c6775bbfbfec7c9f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || (solaris && !illumos)
-// +build aix solaris,!illumos
 
 // This code implements the filelock API using POSIX 'fcntl' locks, which attach
 // to an (inode, process) pair rather than a file descriptor. To avoid unlocking
index 70f5d7a688a070e5381c7da252fcd153cda80fb6..491bec39af935468b0fb7541e5faeb3c1c4dcfae 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !plan9 && !solaris && !windows
-// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!plan9,!solaris,!windows
 
 package filelock
 
index 908afb6c8cb7687d4d34545038b831e27434c2d8..54b2c946e0d6b2272e5758ac638e0bef49aa3e8e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package filelock
 
index 640d4406f4200cd1e44c426421955678feb66f91..7bd7bd28f55ab7830fe9bb0e86327272877de5d5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9
-// +build !js,!plan9
 
 package filelock_test
 
index 878a1e770d4d42a754950bc86f21221446c20262..d7778d05de1884f88bcbdbbc13e30a26c86d43ba 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd illumos linux netbsd openbsd
 
 package filelock
 
index dd27ce92bd8d617449952f0c792f7966d10d2b84..e2ca5383046bbe13bd3dd5bb7d3c43bcab190d22 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package filelock
 
index e4923f68764dad89a06539bbffccbe112e645996..1a677a7fe4a60d3a98866a846bbd6e39b057cbe9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9
-// +build !plan9
 
 package lockedfile
 
index 979118b10ae83d13d01064ca3eb896f5b6a38d48..35669388e0531318a8d3cdb65f2c992bccbe9e7d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package lockedfile
 
index 3acc6695a748003e6f0fc7107bc49ffcf5995162..c9907db46cecb36e043a1ff8105ac386bcec9e95 100644 (file)
@@ -4,7 +4,6 @@
 
 // js does not support inter-process file locking.
 //go:build !js
-// +build !js
 
 package lockedfile_test
 
index b753346e7da50bccbb6d904a3f59c30648093153..3c1caa334eb4df6bbaec7f1dae4228286df11067 100644 (file)
@@ -4,7 +4,6 @@
 
 // js does not support inter-process file locking.
 //go:build !js
-// +build !js
 
 package lockedfile_test
 
index 0e5af852376e76c5363d595d15c55f18d4acd8f6..f252133762cdb7c560a87aeed1e60703c2ddfc1e 100644 (file)
@@ -16,6 +16,7 @@ import (
        "cmd/go/internal/modload"
 
        "golang.org/x/mod/module"
+       "golang.org/x/mod/semver"
 )
 
 var cmdDownload = &base.Command{
@@ -24,8 +25,11 @@ var cmdDownload = &base.Command{
        Long: `
 Download downloads the named modules, which can be module patterns selecting
 dependencies of the main module or module queries of the form path@version.
-With no arguments, download applies to all dependencies of the main module
-(equivalent to 'go mod download all').
+
+With no arguments, download applies to the modules needed to build and test
+the packages in the main module: the modules explicitly required by the main
+module if it is at 'go 1.17' or higher, or all transitively-required modules
+if at 'go 1.16' or lower.
 
 The go command will automatically download modules as needed during ordinary
 execution. The "go mod download" command is useful mainly for pre-filling
@@ -66,6 +70,7 @@ func init() {
        // TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
        cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
        base.AddModCommonFlags(&cmdDownload.Flag)
+       base.AddWorkfileFlag(&cmdDownload.Flag)
 }
 
 type moduleJSON struct {
@@ -81,27 +86,65 @@ type moduleJSON struct {
 }
 
 func runDownload(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
+
        // Check whether modules are enabled and whether we're in a module.
        modload.ForceUseModules = true
-       if !modload.HasModRoot() && len(args) == 0 {
-               base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
-       }
+       modload.ExplicitWriteGoMod = true
        haveExplicitArgs := len(args) > 0
-       if !haveExplicitArgs {
-               args = []string{"all"}
-       }
+
        if modload.HasModRoot() {
-               modload.LoadModFile(ctx) // to fill Target
-               targetAtUpgrade := modload.Target.Path + "@upgrade"
-               targetAtPatch := modload.Target.Path + "@patch"
-               for _, arg := range args {
-                       switch arg {
-                       case modload.Target.Path, targetAtUpgrade, targetAtPatch:
-                               os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
+               modload.LoadModFile(ctx) // to fill MainModules
+
+               if len(modload.MainModules.Versions()) != 1 {
+                       panic(modload.TODOWorkspaces("Support workspace mode in go mod download"))
+               }
+               mainModule := modload.MainModules.Versions()[0]
+
+               if haveExplicitArgs {
+                       targetAtUpgrade := mainModule.Path + "@upgrade"
+                       targetAtPatch := mainModule.Path + "@patch"
+                       for _, arg := range args {
+                               switch arg {
+                               case mainModule.Path, targetAtUpgrade, targetAtPatch:
+                                       os.Stderr.WriteString("go: skipping download of " + arg + " that resolves to the main module\n")
+                               }
+                       }
+               } else {
+                       modFile := modload.MainModules.ModFile(mainModule)
+                       if modFile.Go == nil || semver.Compare("v"+modFile.Go.Version, modload.ExplicitIndirectVersionV) < 0 {
+                               if len(modFile.Require) > 0 {
+                                       args = []string{"all"}
+                               }
+                       } else {
+                               // As of Go 1.17, the go.mod file explicitly requires every module
+                               // that provides any package imported by the main module.
+                               // 'go mod download' is typically run before testing packages in the
+                               // main module, so by default we shouldn't download the others
+                               // (which are presumed irrelevant to the packages in the main module).
+                               // See https://golang.org/issue/44435.
+                               //
+                               // However, we also need to load the full module graph, to ensure that
+                               // we have downloaded enough of the module graph to run 'go list all',
+                               // 'go mod graph', and similar commands.
+                               _ = modload.LoadModGraph(ctx, "")
+
+                               for _, m := range modFile.Require {
+                                       args = append(args, m.Mod.Path)
+                               }
                        }
                }
        }
 
+       if len(args) == 0 {
+               if modload.HasModRoot() {
+                       os.Stderr.WriteString("go: no module dependencies to download\n")
+               } else {
+                       base.Errorf("go: no modules specified (see 'go help mod download')")
+               }
+               base.Exit()
+       }
+
        downloadModule := func(m *moduleJSON) {
                var err error
                m.Info, err = modfetch.InfoFile(m.Path, m.Version)
@@ -140,13 +183,16 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
        if !haveExplicitArgs {
                // 'go mod download' is sometimes run without arguments to pre-populate the
                // module cache. It may fetch modules that aren't needed to build packages
-               // in the main mdoule. This is usually not intended, so don't save sums for
-               // downloaded modules (golang.org/issue/45332).
-               // TODO(golang.org/issue/45551): For now, in ListModules, save sums needed
-               // to load the build list (same as 1.15 behavior). In the future, report an
-               // error if go.mod or go.sum need to be updated after loading the build
-               // list.
-               modload.DisallowWriteGoMod()
+               // in the main module. This is usually not intended, so don't save sums for
+               // downloaded modules (golang.org/issue/45332). We do still fix
+               // inconsistencies in go.mod though.
+               //
+               // TODO(#45551): In the future, report an error if go.mod or go.sum need to
+               // be updated after loading the build list. This may require setting
+               // the mode to "mod" or "readonly" depending on haveExplicitArgs.
+               if err := modload.WriteGoMod(ctx); err != nil {
+                       base.Fatalf("go: %v", err)
+               }
        }
 
        for _, info := range infos {
@@ -183,7 +229,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
                for _, m := range mods {
                        b, err := json.MarshalIndent(m, "", "\t")
                        if err != nil {
-                               base.Fatalf("go mod download: %v", err)
+                               base.Fatalf("go: %v", err)
                        }
                        os.Stdout.Write(append(b, '\n'))
                        if m.Error != "" {
@@ -193,7 +239,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
        } else {
                for _, m := range mods {
                        if m.Error != "" {
-                               base.Errorf("go mod download: %v", m.Error)
+                               base.Errorf("go: %v", m.Error)
                        }
                }
                base.ExitIfErrors()
@@ -206,13 +252,15 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
        //
        // Don't save sums for 'go mod download' without arguments; see comment above.
        if haveExplicitArgs {
-               modload.WriteGoMod(ctx)
+               if err := modload.WriteGoMod(ctx); err != nil {
+                       base.Errorf("go: %v", err)
+               }
        }
 
        // If there was an error matching some of the requested packages, emit it now
        // (after we've written the checksums for the modules that were downloaded
        // successfully).
        if infosErr != nil {
-               base.Errorf("go mod download: %v", infosErr)
+               base.Errorf("go: %v", infosErr)
        }
 }
index bb3d5210926aef7993e93a8beb0fbd189859e399..e5182a9590adc866532d0dfde80130808706faad 100644 (file)
@@ -171,15 +171,15 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
                        len(edits) > 0
 
        if !anyFlags {
-               base.Fatalf("go mod edit: no flags specified (see 'go help mod edit').")
+               base.Fatalf("go: no flags specified (see 'go help mod edit').")
        }
 
        if *editJSON && *editPrint {
-               base.Fatalf("go mod edit: cannot use both -json and -print")
+               base.Fatalf("go: cannot use both -json and -print")
        }
 
        if len(args) > 1 {
-               base.Fatalf("go mod edit: too many arguments")
+               base.Fatalf("go: too many arguments")
        }
        var gomod string
        if len(args) == 1 {
@@ -190,7 +190,7 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
 
        if *editModule != "" {
                if err := module.CheckImportPath(*editModule); err != nil {
-                       base.Fatalf("go mod: invalid -module: %v", err)
+                       base.Fatalf("go: invalid -module: %v", err)
                }
        }
 
@@ -264,15 +264,15 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
 func parsePathVersion(flag, arg string) (path, version string) {
        i := strings.Index(arg, "@")
        if i < 0 {
-               base.Fatalf("go mod: -%s=%s: need path@version", flag, arg)
+               base.Fatalf("go: -%s=%s: need path@version", flag, arg)
        }
        path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
        if err := module.CheckImportPath(path); err != nil {
-               base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
+               base.Fatalf("go: -%s=%s: invalid path: %v", flag, arg, err)
        }
 
        if !allowedVersionArg(version) {
-               base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version)
+               base.Fatalf("go: -%s=%s: invalid version %q", flag, arg, version)
        }
 
        return path, version
@@ -281,11 +281,11 @@ func parsePathVersion(flag, arg string) (path, version string) {
 // parsePath parses -flag=arg expecting arg to be path (not path@version).
 func parsePath(flag, arg string) (path string) {
        if strings.Contains(arg, "@") {
-               base.Fatalf("go mod: -%s=%s: need just path, not path@version", flag, arg)
+               base.Fatalf("go: -%s=%s: need just path, not path@version", flag, arg)
        }
        path = arg
        if err := module.CheckImportPath(path); err != nil {
-               base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
+               base.Fatalf("go: -%s=%s: invalid path: %v", flag, arg, err)
        }
        return path
 }
@@ -350,7 +350,7 @@ func flagRequire(arg string) {
        path, version := parsePathVersion("require", arg)
        edits = append(edits, func(f *modfile.File) {
                if err := f.AddRequire(path, version); err != nil {
-                       base.Fatalf("go mod: -require=%s: %v", arg, err)
+                       base.Fatalf("go: -require=%s: %v", arg, err)
                }
        })
 }
@@ -360,7 +360,7 @@ func flagDropRequire(arg string) {
        path := parsePath("droprequire", arg)
        edits = append(edits, func(f *modfile.File) {
                if err := f.DropRequire(path); err != nil {
-                       base.Fatalf("go mod: -droprequire=%s: %v", arg, err)
+                       base.Fatalf("go: -droprequire=%s: %v", arg, err)
                }
        })
 }
@@ -370,7 +370,7 @@ func flagExclude(arg string) {
        path, version := parsePathVersion("exclude", arg)
        edits = append(edits, func(f *modfile.File) {
                if err := f.AddExclude(path, version); err != nil {
-                       base.Fatalf("go mod: -exclude=%s: %v", arg, err)
+                       base.Fatalf("go: -exclude=%s: %v", arg, err)
                }
        })
 }
@@ -380,7 +380,7 @@ func flagDropExclude(arg string) {
        path, version := parsePathVersion("dropexclude", arg)
        edits = append(edits, func(f *modfile.File) {
                if err := f.DropExclude(path, version); err != nil {
-                       base.Fatalf("go mod: -dropexclude=%s: %v", arg, err)
+                       base.Fatalf("go: -dropexclude=%s: %v", arg, err)
                }
        })
 }
@@ -389,27 +389,27 @@ func flagDropExclude(arg string) {
 func flagReplace(arg string) {
        var i int
        if i = strings.Index(arg, "="); i < 0 {
-               base.Fatalf("go mod: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
+               base.Fatalf("go: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
        }
        old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
        if strings.HasPrefix(new, ">") {
-               base.Fatalf("go mod: -replace=%s: separator between old and new is =, not =>", arg)
+               base.Fatalf("go: -replace=%s: separator between old and new is =, not =>", arg)
        }
        oldPath, oldVersion, err := parsePathVersionOptional("old", old, false)
        if err != nil {
-               base.Fatalf("go mod: -replace=%s: %v", arg, err)
+               base.Fatalf("go: -replace=%s: %v", arg, err)
        }
        newPath, newVersion, err := parsePathVersionOptional("new", new, true)
        if err != nil {
-               base.Fatalf("go mod: -replace=%s: %v", arg, err)
+               base.Fatalf("go: -replace=%s: %v", arg, err)
        }
        if newPath == new && !modfile.IsDirectoryPath(new) {
-               base.Fatalf("go mod: -replace=%s: unversioned new path must be local directory", arg)
+               base.Fatalf("go: -replace=%s: unversioned new path must be local directory", arg)
        }
 
        edits = append(edits, func(f *modfile.File) {
                if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil {
-                       base.Fatalf("go mod: -replace=%s: %v", arg, err)
+                       base.Fatalf("go: -replace=%s: %v", arg, err)
                }
        })
 }
@@ -418,11 +418,11 @@ func flagReplace(arg string) {
 func flagDropReplace(arg string) {
        path, version, err := parsePathVersionOptional("old", arg, true)
        if err != nil {
-               base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
+               base.Fatalf("go: -dropreplace=%s: %v", arg, err)
        }
        edits = append(edits, func(f *modfile.File) {
                if err := f.DropReplace(path, version); err != nil {
-                       base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
+                       base.Fatalf("go: -dropreplace=%s: %v", arg, err)
                }
        })
 }
@@ -431,11 +431,11 @@ func flagDropReplace(arg string) {
 func flagRetract(arg string) {
        vi, err := parseVersionInterval(arg)
        if err != nil {
-               base.Fatalf("go mod: -retract=%s: %v", arg, err)
+               base.Fatalf("go: -retract=%s: %v", arg, err)
        }
        edits = append(edits, func(f *modfile.File) {
                if err := f.AddRetract(vi, ""); err != nil {
-                       base.Fatalf("go mod: -retract=%s: %v", arg, err)
+                       base.Fatalf("go: -retract=%s: %v", arg, err)
                }
        })
 }
@@ -444,11 +444,11 @@ func flagRetract(arg string) {
 func flagDropRetract(arg string) {
        vi, err := parseVersionInterval(arg)
        if err != nil {
-               base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
+               base.Fatalf("go: -dropretract=%s: %v", arg, err)
        }
        edits = append(edits, func(f *modfile.File) {
                if err := f.DropRetract(vi); err != nil {
-                       base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
+                       base.Fatalf("go: -dropretract=%s: %v", arg, err)
                }
        })
 }
diff --git a/src/cmd/go/internal/modcmd/editwork.go b/src/cmd/go/internal/modcmd/editwork.go
new file mode 100644 (file)
index 0000000..50f8636
--- /dev/null
@@ -0,0 +1,289 @@
+// Copyright 2021 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 mod editwork
+
+package modcmd
+
+import (
+       "bytes"
+       "cmd/go/internal/base"
+       "cmd/go/internal/lockedfile"
+       "cmd/go/internal/modload"
+       "context"
+       "encoding/json"
+       "errors"
+       "os"
+       "path/filepath"
+       "strings"
+
+       "golang.org/x/mod/modfile"
+)
+
+var cmdEditwork = &base.Command{
+       UsageLine: "go mod editwork [editing flags] [go.work]",
+       Short:     "edit go.work from tools or scripts",
+       Long: `Editwork provides a command-line interface for editing go.work,
+for use primarily by tools or scripts. It only reads go.work;
+it does not look up information about the modules involved.
+If no file is specified, editwork looks for a go.work file in the current
+directory and its parent directories
+
+The editing flags specify a sequence of editing operations.
+
+The -fmt flag reformats the go.work file without making other changes.
+This reformatting is also implied by any other modifications that use or
+rewrite the go.mod file. The only time this flag is needed is if no other
+flags are specified, as in 'go mod editwork -fmt'.
+
+The -directory=path and -dropdirectory=path flags
+add and drop a directory from the go.work files set of module directories.
+
+The -replace=old[@v]=new[@v] flag adds a replacement of the given
+module path and version pair. If the @v in old@v is omitted, a
+replacement without a version on the left side is added, which applies
+to all versions of the old module path. If the @v in new@v is omitted,
+the new path should be a local module root directory, not a module
+path. Note that -replace overrides any redundant replacements for old[@v],
+so omitting @v will drop existing replacements for specific versions.
+
+The -dropreplace=old[@v] flag drops a replacement of the given
+module path and version pair. If the @v is omitted, a replacement without
+a version on the left side is dropped.
+
+The -directory, -dropdirectory, -replace, and -dropreplace,
+editing flags may be repeated, and the changes are applied in the order given.
+
+The -go=version flag sets the expected Go language version.
+
+The -print flag prints the final go.work in its text format instead of
+writing it back to go.mod.
+
+The -json flag prints the final go.work file in JSON format instead of
+writing it back to go.mod. The JSON output corresponds to these Go types:
+
+       type Module struct {
+               Path    string
+               Version string
+       }
+
+       type GoWork struct {
+               Go        string
+               Directory []Directory
+               Replace   []Replace
+       }
+
+       type Directory struct {
+               Path       string
+               ModulePath string
+       }
+
+       type Replace struct {
+               Old Module
+               New Module
+       }
+
+See the workspaces design proposal at
+https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
+more information.
+`,
+}
+
+var (
+       editworkFmt   = cmdEditwork.Flag.Bool("fmt", false, "")
+       editworkGo    = cmdEditwork.Flag.String("go", "", "")
+       editworkJSON  = cmdEditwork.Flag.Bool("json", false, "")
+       editworkPrint = cmdEditwork.Flag.Bool("print", false, "")
+       workedits     []func(file *modfile.WorkFile) // edits specified in flags
+)
+
+func init() {
+       cmdEditwork.Run = runEditwork // break init cycle
+
+       cmdEditwork.Flag.Var(flagFunc(flagEditworkDirectory), "directory", "")
+       cmdEditwork.Flag.Var(flagFunc(flagEditworkDropDirectory), "dropdirectory", "")
+       cmdEditwork.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
+       cmdEditwork.Flag.Var(flagFunc(flagEditworkDropReplace), "dropreplace", "")
+
+       base.AddWorkfileFlag(&cmdEditwork.Flag)
+}
+
+func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
+       anyFlags :=
+               *editworkGo != "" ||
+                       *editworkJSON ||
+                       *editworkPrint ||
+                       *editworkFmt ||
+                       len(workedits) > 0
+
+       if !anyFlags {
+               base.Fatalf("go: no flags specified (see 'go help mod editwork').")
+       }
+
+       if *editworkJSON && *editworkPrint {
+               base.Fatalf("go: cannot use both -json and -print")
+       }
+
+       if len(args) > 1 {
+               base.Fatalf("go: 'go mod editwork' accepts at most one argument")
+       }
+       var gowork string
+       if len(args) == 1 {
+               gowork = args[0]
+       } else {
+               modload.InitWorkfile()
+               gowork = modload.WorkFilePath()
+       }
+
+       if *editworkGo != "" {
+               if !modfile.GoVersionRE.MatchString(*editworkGo) {
+                       base.Fatalf(`go mod: invalid -go option; expecting something like "-go %s"`, modload.LatestGoVersion())
+               }
+       }
+
+       data, err := lockedfile.Read(gowork)
+       if err != nil {
+               base.Fatalf("go: %v", err)
+       }
+
+       workFile, err := modfile.ParseWork(gowork, data, nil)
+       if err != nil {
+               base.Fatalf("go: errors parsing %s:\n%s", base.ShortPath(gowork), err)
+       }
+
+       if *editworkGo != "" {
+               if err := workFile.AddGoStmt(*editworkGo); err != nil {
+                       base.Fatalf("go: internal error: %v", err)
+               }
+       }
+
+       if len(workedits) > 0 {
+               for _, edit := range workedits {
+                       edit(workFile)
+               }
+       }
+       workFile.SortBlocks()
+       workFile.Cleanup() // clean file after edits
+
+       if *editworkJSON {
+               editworkPrintJSON(workFile)
+               return
+       }
+
+       out := modfile.Format(workFile.Syntax)
+
+       if *editworkPrint {
+               os.Stdout.Write(out)
+               return
+       }
+
+       err = lockedfile.Transform(gowork, func(lockedData []byte) ([]byte, error) {
+               if !bytes.Equal(lockedData, data) {
+                       return nil, errors.New("go.work changed during editing; not overwriting")
+               }
+               return out, nil
+       })
+       if err != nil {
+               base.Fatalf("go: %v", err)
+       }
+}
+
+// flagEditworkDirectory implements the -directory flag.
+func flagEditworkDirectory(arg string) {
+       workedits = append(workedits, func(f *modfile.WorkFile) {
+               _, mf, err := modload.ReadModFile(filepath.Join(arg, "go.mod"), nil)
+               modulePath := ""
+               if err == nil {
+                       modulePath = mf.Module.Mod.Path
+               }
+               f.AddDirectory(modload.ToDirectoryPath(arg), modulePath)
+               if err := f.AddDirectory(modload.ToDirectoryPath(arg), ""); err != nil {
+                       base.Fatalf("go: -directory=%s: %v", arg, err)
+               }
+       })
+}
+
+// flagEditworkDropDirectory implements the -dropdirectory flag.
+func flagEditworkDropDirectory(arg string) {
+       workedits = append(workedits, func(f *modfile.WorkFile) {
+               if err := f.DropDirectory(modload.ToDirectoryPath(arg)); err != nil {
+                       base.Fatalf("go: -dropdirectory=%s: %v", arg, err)
+               }
+       })
+}
+
+// flagReplace implements the -replace flag.
+func flagEditworkReplace(arg string) {
+       var i int
+       if i = strings.Index(arg, "="); i < 0 {
+               base.Fatalf("go: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
+       }
+       old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
+       if strings.HasPrefix(new, ">") {
+               base.Fatalf("go: -replace=%s: separator between old and new is =, not =>", arg)
+       }
+       oldPath, oldVersion, err := parsePathVersionOptional("old", old, false)
+       if err != nil {
+               base.Fatalf("go: -replace=%s: %v", arg, err)
+       }
+       newPath, newVersion, err := parsePathVersionOptional("new", new, true)
+       if err != nil {
+               base.Fatalf("go: -replace=%s: %v", arg, err)
+       }
+       if newPath == new && !modfile.IsDirectoryPath(new) {
+               base.Fatalf("go: -replace=%s: unversioned new path must be local directory", arg)
+       }
+
+       workedits = append(workedits, func(f *modfile.WorkFile) {
+               if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil {
+                       base.Fatalf("go: -replace=%s: %v", arg, err)
+               }
+       })
+}
+
+// flagDropReplace implements the -dropreplace flag.
+func flagEditworkDropReplace(arg string) {
+       path, version, err := parsePathVersionOptional("old", arg, true)
+       if err != nil {
+               base.Fatalf("go: -dropreplace=%s: %v", arg, err)
+       }
+       workedits = append(workedits, func(f *modfile.WorkFile) {
+               if err := f.DropReplace(path, version); err != nil {
+                       base.Fatalf("go: -dropreplace=%s: %v", arg, err)
+               }
+       })
+}
+
+// editPrintJSON prints the -json output.
+func editworkPrintJSON(workFile *modfile.WorkFile) {
+       var f workfileJSON
+       if workFile.Go != nil {
+               f.Go = workFile.Go.Version
+       }
+       for _, d := range workFile.Directory {
+               f.Directory = append(f.Directory, directoryJSON{DiskPath: d.Path, ModPath: d.ModulePath})
+       }
+
+       for _, r := range workFile.Replace {
+               f.Replace = append(f.Replace, replaceJSON{r.Old, r.New})
+       }
+       data, err := json.MarshalIndent(&f, "", "\t")
+       if err != nil {
+               base.Fatalf("go: internal error: %v", err)
+       }
+       data = append(data, '\n')
+       os.Stdout.Write(data)
+}
+
+// workfileJSON is the -json output data structure.
+type workfileJSON struct {
+       Go        string `json:",omitempty"`
+       Directory []directoryJSON
+       Replace   []replaceJSON
+}
+
+type directoryJSON struct {
+       DiskPath string
+       ModPath  string `json:",omitempty"`
+}
index ac81f26dadea69dd3f58d7491caaa39aba7cfcad..9b6aa1fb14dddc5ade58f888a5bf01f2ba7ed140 100644 (file)
@@ -42,11 +42,14 @@ var (
 func init() {
        cmdGraph.Flag.Var(&graphGo, "go", "")
        base.AddModCommonFlags(&cmdGraph.Flag)
+       base.AddWorkfileFlag(&cmdGraph.Flag)
 }
 
 func runGraph(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
+
        if len(args) > 0 {
-               base.Fatalf("go mod graph: graph takes no arguments")
+               base.Fatalf("go: 'go mod graph' accepts no arguments")
        }
        modload.ForceUseModules = true
        modload.RootMode = modload.NeedRoot
index 958c3066ac11082dee31fe8b0cc4f3f049124e5e..bc4620a2a8d3f2121145ee64038ba0329fda599d 100644 (file)
@@ -39,7 +39,7 @@ func init() {
 
 func runInit(ctx context.Context, cmd *base.Command, args []string) {
        if len(args) > 1 {
-               base.Fatalf("go mod init: too many arguments")
+               base.Fatalf("go: 'go mod init' accepts at most one argument")
        }
        var modPath string
        if len(args) == 1 {
diff --git a/src/cmd/go/internal/modcmd/initwork.go b/src/cmd/go/internal/modcmd/initwork.go
new file mode 100644 (file)
index 0000000..4182aa0
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2021 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 mod initwork
+
+package modcmd
+
+import (
+       "cmd/go/internal/base"
+       "cmd/go/internal/modload"
+       "context"
+       "path/filepath"
+)
+
+var _ = modload.TODOWorkspaces("Add more documentation below. Though this is" +
+       "enough for those trying workspaces out, there should be more through" +
+       "documentation if the proposal is accepted and released.")
+
+var cmdInitwork = &base.Command{
+       UsageLine: "go mod initwork [moddirs]",
+       Short:     "initialize workspace file",
+       Long: `go mod initwork initializes and writes a new go.work file in the current
+directory, in effect creating a new workspace at the current directory.
+
+go mod initwork optionally accepts paths to the workspace modules as arguments.
+If the argument is omitted, an empty workspace with no modules will be created.
+
+See the workspaces design proposal at
+https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
+more information.
+`,
+       Run: runInitwork,
+}
+
+func init() {
+       base.AddModCommonFlags(&cmdInitwork.Flag)
+       base.AddWorkfileFlag(&cmdInitwork.Flag)
+}
+
+func runInitwork(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
+
+       modload.ForceUseModules = true
+
+       // TODO(matloob): support using the -workfile path
+       // To do that properly, we'll have to make the module directories
+       // make dirs relative to workFile path before adding the paths to
+       // the directory entries
+
+       workFile := filepath.Join(base.Cwd(), "go.work")
+
+       modload.CreateWorkFile(ctx, workFile, args)
+}
index d72d0cacd68ddafdc2723c00ca3d7f04a7aa62bc..29aad5832407b05637aefb15281da953ecea6ac2 100644 (file)
@@ -23,8 +23,10 @@ See 'go help modules' for an overview of module functionality.
        Commands: []*base.Command{
                cmdDownload,
                cmdEdit,
+               cmdEditwork,
                cmdGraph,
                cmdInit,
+               cmdInitwork,
                cmdTidy,
                cmdVendor,
                cmdVerify,
index fe25507e94f4fe365ec17d48b09e91be1109d702..57d303a13c7642cb4499bfe97ee18fd01996c2f7 100644 (file)
@@ -95,7 +95,7 @@ func (f *goVersionFlag) Set(s string) error {
 
 func runTidy(ctx context.Context, cmd *base.Command, args []string) {
        if len(args) > 0 {
-               base.Fatalf("go mod tidy: no arguments allowed")
+               base.Fatalf("go: 'go mod tidy' accepts no arguments")
        }
 
        // Tidy aims to make 'go test' reproducible for any package in 'all', so we
index b133ba7ea936fec4f359ccec91194f7123f4d928..484e095cc764c2d4955b02b625280733882e74d2 100644 (file)
@@ -24,7 +24,7 @@ import (
        "cmd/go/internal/imports"
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/module"
        "golang.org/x/mod/semver"
@@ -59,7 +59,7 @@ func init() {
 
 func runVendor(ctx context.Context, cmd *base.Command, args []string) {
        if len(args) != 0 {
-               base.Fatalf("go mod vendor: vendor takes no arguments")
+               base.Fatalf("go: 'go mod vendor' accepts no arguments")
        }
        modload.ForceUseModules = true
        modload.RootMode = modload.NeedRoot
@@ -74,15 +74,15 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
        }
        _, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
 
-       vdir := filepath.Join(modload.ModRoot(), "vendor")
+       vdir := filepath.Join(modload.VendorDir())
        if err := os.RemoveAll(vdir); err != nil {
-               base.Fatalf("go mod vendor: %v", err)
+               base.Fatalf("go: %v", err)
        }
 
        modpkgs := make(map[module.Version][]string)
        for _, pkg := range pkgs {
                m := modload.PackageModule(pkg)
-               if m.Path == "" || m == modload.Target {
+               if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
                        continue
                }
                modpkgs[m] = append(modpkgs[m], pkg)
@@ -128,7 +128,8 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
        }
 
        for _, m := range vendorMods {
-               line := moduleLine(m, modload.Replacement(m))
+               replacement := modload.Replacement(m)
+               line := moduleLine(m, replacement)
                io.WriteString(w, line)
 
                goVersion := ""
@@ -177,11 +178,11 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
        }
 
        if err := os.MkdirAll(vdir, 0777); err != nil {
-               base.Fatalf("go mod vendor: %v", err)
+               base.Fatalf("go: %v", err)
        }
 
        if err := os.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
-               base.Fatalf("go mod vendor: %v", err)
+               base.Fatalf("go: %v", err)
        }
 }
 
@@ -242,14 +243,14 @@ func vendorPkg(vdir, pkg string) {
        if err != nil {
                if errors.As(err, &noGoError) {
                        return // No source files in this package are built. Skip embeds in ignored files.
-               } else if !errors.As(err, &multiplePackageError) { // multiplePackgeErrors are okay, but others are not.
+               } else if !errors.As(err, &multiplePackageError) { // multiplePackageErrors are OK, but others are not.
                        base.Fatalf("internal error: failed to find embedded files of %s: %v\n", pkg, err)
                }
        }
        embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns)
        embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
        if err != nil {
-               base.Fatalf("go mod vendor: %v", err)
+               base.Fatalf("go: %v", err)
        }
        for _, embed := range embeds {
                embedDst := filepath.Join(dst, embed)
@@ -260,21 +261,21 @@ func vendorPkg(vdir, pkg string) {
                // Copy the file as is done by copyDir below.
                r, err := os.Open(filepath.Join(src, embed))
                if err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                w, err := os.Create(embedDst)
                if err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                if _, err := io.Copy(w, r); err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                r.Close()
                if err := w.Close(); err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
        }
 }
@@ -353,7 +354,7 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
        if strings.HasSuffix(info.Name(), ".go") {
                f, err := fsys.Open(filepath.Join(dir, info.Name()))
                if err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                defer f.Close()
 
@@ -375,10 +376,10 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
 func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, copiedFiles map[string]bool) {
        files, err := os.ReadDir(src)
        if err != nil {
-               base.Fatalf("go mod vendor: %v", err)
+               base.Fatalf("go: %v", err)
        }
        if err := os.MkdirAll(dst, 0777); err != nil {
-               base.Fatalf("go mod vendor: %v", err)
+               base.Fatalf("go: %v", err)
        }
        for _, file := range files {
                if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
@@ -387,20 +388,20 @@ func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, cop
                copiedFiles[file.Name()] = true
                r, err := os.Open(filepath.Join(src, file.Name()))
                if err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                dstPath := filepath.Join(dst, file.Name())
                copiedFiles[dstPath] = true
                w, err := os.Create(dstPath)
                if err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                if _, err := io.Copy(w, r); err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
                r.Close()
                if err := w.Close(); err != nil {
-                       base.Fatalf("go mod vendor: %v", err)
+                       base.Fatalf("go: %v", err)
                }
        }
 }
index 5a6eca32cfb706bfcd50906937d9eec70e4fc4c4..3f0c005d5d91482c87d764f155168ed3a579151c 100644 (file)
@@ -39,12 +39,15 @@ See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
 
 func init() {
        base.AddModCommonFlags(&cmdVerify.Flag)
+       base.AddWorkfileFlag(&cmdVerify.Flag)
 }
 
 func runVerify(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
+
        if len(args) != 0 {
                // NOTE(rsc): Could take a module pattern.
-               base.Fatalf("go mod verify: verify takes no arguments")
+               base.Fatalf("go: verify takes no arguments")
        }
        modload.ForceUseModules = true
        modload.RootMode = modload.NeedRoot
index 3b14b27c8c780d954a133cd46dc4bee2f875e442..d8355cca957a460788b1f7f146679c79bdfe169c 100644 (file)
@@ -12,8 +12,6 @@ import (
        "cmd/go/internal/base"
        "cmd/go/internal/imports"
        "cmd/go/internal/modload"
-
-       "golang.org/x/mod/module"
 )
 
 var cmdWhy = &base.Command{
@@ -61,11 +59,14 @@ var (
 func init() {
        cmdWhy.Run = runWhy // break init cycle
        base.AddModCommonFlags(&cmdWhy.Flag)
+       base.AddWorkfileFlag(&cmdWhy.Flag)
 }
 
 func runWhy(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
        modload.ForceUseModules = true
        modload.RootMode = modload.NeedRoot
+       modload.ExplicitWriteGoMod = true // don't write go.mod in ListModules
 
        loadOpts := modload.PackageOpts{
                Tags:                     imports.AnyTags(),
@@ -78,28 +79,28 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
        if *whyM {
                for _, arg := range args {
                        if strings.Contains(arg, "@") {
-                               base.Fatalf("go mod why: module query not allowed")
+                               base.Fatalf("go: %s: 'go mod why' requires a module path, not a version query", arg)
                        }
                }
 
                mods, err := modload.ListModules(ctx, args, 0)
                if err != nil {
-                       base.Fatalf("go mod why: %v", err)
+                       base.Fatalf("go: %v", err)
                }
 
-               byModule := make(map[module.Version][]string)
+               byModule := make(map[string][]string)
                _, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
                for _, path := range pkgs {
                        m := modload.PackageModule(path)
                        if m.Path != "" {
-                               byModule[m] = append(byModule[m], path)
+                               byModule[m.Path] = append(byModule[m.Path], path)
                        }
                }
                sep := ""
                for _, m := range mods {
                        best := ""
                        bestDepth := 1000000000
-                       for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] {
+                       for _, path := range byModule[m.Path] {
                                d := modload.WhyDepth(path)
                                if d > 0 && d < bestDepth {
                                        best = path
index ed694581a7c6af47ba12c789ece904fb15c1099c..e23669fb00c76b7bb5d6a1f20523051354f2f3f5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cmd_go_bootstrap
-// +build cmd_go_bootstrap
 
 package modfetch
 
index b01b4674131e7af76436c5b5513b6dbc1c155cbe..8d299e931af8b126b4cbdb18d725e5f4f7852eef 100644 (file)
@@ -720,7 +720,7 @@ func checkCacheDir() error {
        if cfg.GOMODCACHE == "" {
                // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE
                // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen.
-               return fmt.Errorf("internal error: cfg.GOMODCACHE not set")
+               return fmt.Errorf("module cache not found: neither GOMODCACHE nor GOPATH is set")
        }
        if !filepath.IsAbs(cfg.GOMODCACHE) {
                return fmt.Errorf("GOMODCACHE entry is relative; must be absolute path: %q.\n", cfg.GOMODCACHE)
index efb4b1516a2ef48874a19c4fc240119bc1a84ec1..378fbae34f9530378ced67a8298f797891af9e72 100644 (file)
@@ -21,7 +21,7 @@ import (
 
        "cmd/go/internal/cfg"
        "cmd/go/internal/lockedfile"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 // Downloaded size limits.
index 4d4964edf447ebb7e963acd2c0defb74bb5957f6..a782de56ff95a9caa8a07d9076042e7dc2238b36 100644 (file)
@@ -170,59 +170,63 @@ func (r *gitRepo) loadLocalTags() {
 }
 
 // loadRefs loads heads and tags references from the remote into the map r.refs.
-// Should only be called as r.refsOnce.Do(r.loadRefs).
-func (r *gitRepo) loadRefs() {
-       // The git protocol sends all known refs and ls-remote filters them on the client side,
-       // so we might as well record both heads and tags in one shot.
-       // Most of the time we only care about tags but sometimes we care about heads too.
-       out, gitErr := Run(r.dir, "git", "ls-remote", "-q", r.remote)
-       if gitErr != nil {
-               if rerr, ok := gitErr.(*RunError); ok {
-                       if bytes.Contains(rerr.Stderr, []byte("fatal: could not read Username")) {
-                               rerr.HelpText = "Confirm the import path was entered correctly.\nIf this is a private repository, see https://golang.org/doc/faq#git_https for additional information."
+// The result is cached in memory.
+func (r *gitRepo) loadRefs() (map[string]string, error) {
+       r.refsOnce.Do(func() {
+               // The git protocol sends all known refs and ls-remote filters them on the client side,
+               // so we might as well record both heads and tags in one shot.
+               // Most of the time we only care about tags but sometimes we care about heads too.
+               out, gitErr := Run(r.dir, "git", "ls-remote", "-q", r.remote)
+               if gitErr != nil {
+                       if rerr, ok := gitErr.(*RunError); ok {
+                               if bytes.Contains(rerr.Stderr, []byte("fatal: could not read Username")) {
+                                       rerr.HelpText = "Confirm the import path was entered correctly.\nIf this is a private repository, see https://golang.org/doc/faq#git_https for additional information."
+                               }
                        }
-               }
 
-               // If the remote URL doesn't exist at all, ideally we should treat the whole
-               // repository as nonexistent by wrapping the error in a notExistError.
-               // For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL
-               // ourselves and see what code it serves.
-               if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
-                       if _, err := web.GetBytes(u); errors.Is(err, fs.ErrNotExist) {
-                               gitErr = notExistError{gitErr}
+                       // If the remote URL doesn't exist at all, ideally we should treat the whole
+                       // repository as nonexistent by wrapping the error in a notExistError.
+                       // For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL
+                       // ourselves and see what code it serves.
+                       if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
+                               if _, err := web.GetBytes(u); errors.Is(err, fs.ErrNotExist) {
+                                       gitErr = notExistError{gitErr}
+                               }
                        }
-               }
 
-               r.refsErr = gitErr
-               return
-       }
-
-       r.refs = make(map[string]string)
-       for _, line := range strings.Split(string(out), "\n") {
-               f := strings.Fields(line)
-               if len(f) != 2 {
-                       continue
+                       r.refsErr = gitErr
+                       return
                }
-               if f[1] == "HEAD" || strings.HasPrefix(f[1], "refs/heads/") || strings.HasPrefix(f[1], "refs/tags/") {
-                       r.refs[f[1]] = f[0]
+
+               refs := make(map[string]string)
+               for _, line := range strings.Split(string(out), "\n") {
+                       f := strings.Fields(line)
+                       if len(f) != 2 {
+                               continue
+                       }
+                       if f[1] == "HEAD" || strings.HasPrefix(f[1], "refs/heads/") || strings.HasPrefix(f[1], "refs/tags/") {
+                               refs[f[1]] = f[0]
+                       }
                }
-       }
-       for ref, hash := range r.refs {
-               if strings.HasSuffix(ref, "^{}") { // record unwrapped annotated tag as value of tag
-                       r.refs[strings.TrimSuffix(ref, "^{}")] = hash
-                       delete(r.refs, ref)
+               for ref, hash := range refs {
+                       if strings.HasSuffix(ref, "^{}") { // record unwrapped annotated tag as value of tag
+                               refs[strings.TrimSuffix(ref, "^{}")] = hash
+                               delete(refs, ref)
+                       }
                }
-       }
+               r.refs = refs
+       })
+       return r.refs, r.refsErr
 }
 
 func (r *gitRepo) Tags(prefix string) ([]string, error) {
-       r.refsOnce.Do(r.loadRefs)
-       if r.refsErr != nil {
-               return nil, r.refsErr
+       refs, err := r.loadRefs()
+       if err != nil {
+               return nil, err
        }
 
        tags := []string{}
-       for ref := range r.refs {
+       for ref := range refs {
                if !strings.HasPrefix(ref, "refs/tags/") {
                        continue
                }
@@ -237,14 +241,14 @@ func (r *gitRepo) Tags(prefix string) ([]string, error) {
 }
 
 func (r *gitRepo) Latest() (*RevInfo, error) {
-       r.refsOnce.Do(r.loadRefs)
-       if r.refsErr != nil {
-               return nil, r.refsErr
+       refs, err := r.loadRefs()
+       if err != nil {
+               return nil, err
        }
-       if r.refs["HEAD"] == "" {
+       if refs["HEAD"] == "" {
                return nil, ErrNoCommits
        }
-       return r.Stat(r.refs["HEAD"])
+       return r.Stat(refs["HEAD"])
 }
 
 // findRef finds some ref name for the given hash,
@@ -252,8 +256,11 @@ func (r *gitRepo) Latest() (*RevInfo, error) {
 // There may be multiple ref names for a given hash,
 // in which case this returns some name - it doesn't matter which.
 func (r *gitRepo) findRef(hash string) (ref string, ok bool) {
-       r.refsOnce.Do(r.loadRefs)
-       for ref, h := range r.refs {
+       refs, err := r.loadRefs()
+       if err != nil {
+               return "", false
+       }
+       for ref, h := range refs {
                if h == hash {
                        return ref, true
                }
@@ -295,29 +302,32 @@ func (r *gitRepo) stat(rev string) (*RevInfo, error) {
        // Maybe rev is the name of a tag or branch on the remote server.
        // Or maybe it's the prefix of a hash of a named ref.
        // Try to resolve to both a ref (git name) and full (40-hex-digit) commit hash.
-       r.refsOnce.Do(r.loadRefs)
+       refs, err := r.loadRefs()
+       if err != nil {
+               return nil, err
+       }
        // loadRefs may return an error if git fails, for example segfaults, or
        // could not load a private repo, but defer checking to the else block
        // below, in case we already have the rev in question in the local cache.
        var ref, hash string
-       if r.refs["refs/tags/"+rev] != "" {
+       if refs["refs/tags/"+rev] != "" {
                ref = "refs/tags/" + rev
-               hash = r.refs[ref]
+               hash = refs[ref]
                // Keep rev as is: tags are assumed not to change meaning.
-       } else if r.refs["refs/heads/"+rev] != "" {
+       } else if refs["refs/heads/"+rev] != "" {
                ref = "refs/heads/" + rev
-               hash = r.refs[ref]
+               hash = refs[ref]
                rev = hash // Replace rev, because meaning of refs/heads/foo can change.
-       } else if rev == "HEAD" && r.refs["HEAD"] != "" {
+       } else if rev == "HEAD" && refs["HEAD"] != "" {
                ref = "HEAD"
-               hash = r.refs[ref]
+               hash = refs[ref]
                rev = hash // Replace rev, because meaning of HEAD can change.
        } else if len(rev) >= minHashDigits && len(rev) <= 40 && AllHex(rev) {
                // At the least, we have a hash prefix we can look up after the fetch below.
                // Maybe we can map it to a full hash using the known refs.
                prefix := rev
                // Check whether rev is prefix of known ref hash.
-               for k, h := range r.refs {
+               for k, h := range refs {
                        if strings.HasPrefix(h, prefix) {
                                if hash != "" && hash != h {
                                        // Hash is an ambiguous hash prefix.
@@ -335,9 +345,6 @@ func (r *gitRepo) stat(rev string) (*RevInfo, error) {
                        hash = rev
                }
        } else {
-               if r.refsErr != nil {
-                       return nil, r.refsErr
-               }
                return nil, &UnknownRevisionError{Rev: rev}
        }
 
@@ -535,12 +542,12 @@ func (r *gitRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[s
 
        // Build list of known remote refs that might help.
        var redo []string
-       r.refsOnce.Do(r.loadRefs)
-       if r.refsErr != nil {
-               return nil, r.refsErr
+       refs, err := r.loadRefs()
+       if err != nil {
+               return nil, err
        }
        for _, tag := range need {
-               if r.refs["refs/tags/"+tag] != "" {
+               if refs["refs/tags/"+tag] != "" {
                        redo = append(redo, tag)
                }
        }
index 0e9f38196676b108a28c77e9c2d5b591ecb0ae02..eaa01950b95ef395e57ac6f8d85036c44b6ff911 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Interactive debugging shell for codehost.Repo implementations.
 
index 5d810d2621c907614df4d02da47a015b0f937e6c..c2cca084e3077a8b3f9627e8b212491c1baf06dd 100644 (file)
@@ -20,7 +20,7 @@ import (
 
        "cmd/go/internal/lockedfile"
        "cmd/go/internal/par"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 // A VCSError indicates an error using a version control system.
index dfef9f73c27aefa1bd3073706280a62f5cd8173e..df835c3d7e4e0d9cec61755dec2aab32e615a85d 100644 (file)
@@ -567,11 +567,11 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string)
        if rev != info.Short {
                switch {
                case strings.HasPrefix(rev, info.Short):
-                       return fmt.Errorf("revision is longer than canonical (%s)", info.Short)
+                       return fmt.Errorf("revision is longer than canonical (expected %s)", info.Short)
                case strings.HasPrefix(info.Short, rev):
-                       return fmt.Errorf("revision is shorter than canonical (%s)", info.Short)
+                       return fmt.Errorf("revision is shorter than canonical (expected %s)", info.Short)
                default:
-                       return fmt.Errorf("does not match short name of revision (%s)", info.Short)
+                       return fmt.Errorf("does not match short name of revision (expected %s)", info.Short)
                }
        }
 
index d3d30d970b3b979b14741ce2a2da38c8812a422c..408b2860adfcac5fd42bb62708f572582753df81 100644 (file)
@@ -693,19 +693,21 @@ func isValidSum(data []byte) bool {
        return true
 }
 
+var ErrGoSumDirty = errors.New("updates to go.sum needed, disabled by -mod=readonly")
+
 // WriteGoSum writes the go.sum file if it needs to be updated.
 //
 // keep is used to check whether a newly added sum should be saved in go.sum.
 // It should have entries for both module content sums and go.mod sums
 // (version ends with "/go.mod"). Existing sums will be preserved unless they
 // have been marked for deletion with TrimGoSum.
-func WriteGoSum(keep map[module.Version]bool) {
+func WriteGoSum(keep map[module.Version]bool, readonly bool) error {
        goSum.mu.Lock()
        defer goSum.mu.Unlock()
 
        // If we haven't read the go.sum file yet, don't bother writing it.
        if !goSum.enabled {
-               return
+               return nil
        }
 
        // Check whether we need to add sums for which keep[m] is true or remove
@@ -723,10 +725,10 @@ Outer:
                }
        }
        if !dirty {
-               return
+               return nil
        }
-       if cfg.BuildMod == "readonly" {
-               base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
+       if readonly {
+               return ErrGoSumDirty
        }
        if _, ok := fsys.OverlayPath(GoSumFile); ok {
                base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
@@ -774,11 +776,12 @@ Outer:
        })
 
        if err != nil {
-               base.Fatalf("go: updating go.sum: %v", err)
+               return fmt.Errorf("updating go.sum: %w", err)
        }
 
        goSum.status = make(map[modSum]modSumStatus)
        goSum.overwrite = false
+       return nil
 }
 
 // TrimGoSum trims go.sum to contain only the modules needed for reproducible
index f233cba6df1bb7e996735147834e9c40960158f4..492b03bd84ac8b6e0d3758accb79e614dd567fe2 100644 (file)
@@ -5,7 +5,6 @@
 // Go checksum database lookup
 
 //go:build !cmd_go_bootstrap
-// +build !cmd_go_bootstrap
 
 package modfetch
 
@@ -201,7 +200,8 @@ func (c *dbClient) ReadConfig(file string) (data []byte, err error) {
        }
 
        if cfg.SumdbDir == "" {
-               return nil, errors.New("could not locate sumdb file: missing $GOPATH")
+               return nil, fmt.Errorf("could not locate sumdb file: missing $GOPATH: %s",
+                       cfg.GoPathError)
        }
        targ := filepath.Join(cfg.SumdbDir, file)
        data, err = lockedfile.Read(targ)
@@ -220,7 +220,8 @@ func (*dbClient) WriteConfig(file string, old, new []byte) error {
                return fmt.Errorf("cannot write key")
        }
        if cfg.SumdbDir == "" {
-               return errors.New("could not locate sumdb file: missing $GOPATH")
+               return fmt.Errorf("could not locate sumdb file: missing $GOPATH: %s",
+                       cfg.GoPathError)
        }
        targ := filepath.Join(cfg.SumdbDir, file)
        os.MkdirAll(filepath.Dir(targ), 0777)
index 9672e5598e0d3a980570899a4770925effaee087..2c48c3c44473f485450b1fa681eac5c1cab6633f 100644 (file)
@@ -37,7 +37,6 @@ import (
 
        "cmd/go/internal/base"
        "cmd/go/internal/imports"
-       "cmd/go/internal/load"
        "cmd/go/internal/modfetch"
        "cmd/go/internal/modload"
        "cmd/go/internal/par"
@@ -50,14 +49,14 @@ import (
 )
 
 var CmdGet = &base.Command{
-       // Note: -d -u are listed explicitly because they are the most common get flags.
+       // Note: flags below are listed explicitly because they're the most common.
        // Do not send CLs removing them because they're covered by [get flags].
-       UsageLine: "go get [-d] [-t] [-u] [-v] [build flags] [packages]",
+       UsageLine: "go get [-t] [-u] [-v] [build flags] [packages]",
        Short:     "add dependencies to current module and install them",
        Long: `
 Get resolves its command-line arguments to packages at specific module versions,
-updates go.mod to require those versions, downloads source code into the
-module cache, then builds and installs the named packages.
+updates go.mod to require those versions, and downloads source code into the
+module cache.
 
 To add a dependency for a package or upgrade it to its latest version:
 
@@ -73,17 +72,18 @@ To remove a dependency on a module and downgrade modules that require it:
 
 See https://golang.org/ref/mod#go-get for details.
 
-The 'go install' command may be used to build and install packages. When a
-version is specified, 'go install' runs in module-aware mode and ignores
-the go.mod file in the current directory. For example:
+In earlier versions of Go, 'go get' was used to build and install packages.
+Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
+may be used to build and install commands instead. When a version is specified,
+'go install' runs in module-aware mode and ignores the go.mod file in the
+current directory. For example:
 
        go install example.com/pkg@v1.2.3
        go install example.com/pkg@latest
 
 See 'go help install' or https://golang.org/ref/mod#go-install for details.
 
-In addition to build flags (listed in 'go help build') 'go get' accepts the
-following flags.
+'go get' accepts the following flags.
 
 The -t flag instructs get to consider modules needed to build tests of
 packages specified on the command line.
@@ -98,15 +98,9 @@ but changes the default to select patch releases.
 When the -t and -u flags are used together, get will update
 test dependencies as well.
 
-The -d flag instructs get not to build or install packages. get will only
-update go.mod and download source code needed to build packages.
-
-Building and installing packages with get is deprecated. In a future release,
-the -d flag will be enabled by default, and 'go get' will be only be used to
-adjust dependencies of the current module. To install a package using
-dependencies from the current module, use 'go install'. To install a package
-ignoring the current module, use 'go install' with an @version suffix like
-"@latest" after each argument.
+The -x flag prints commands as they are executed. This is useful for
+debugging version control commands when a module is downloaded directly
+from a repository.
 
 For more about modules, see https://golang.org/ref/mod.
 
@@ -218,7 +212,7 @@ variable for future go command invocations.
 }
 
 var (
-       getD        = CmdGet.Flag.Bool("d", false, "")
+       getD        = CmdGet.Flag.Bool("d", true, "")
        getF        = CmdGet.Flag.Bool("f", false, "")
        getFix      = CmdGet.Flag.Bool("fix", false, "")
        getM        = CmdGet.Flag.Bool("m", false, "")
@@ -263,30 +257,50 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
        case "", "upgrade", "patch":
                // ok
        default:
-               base.Fatalf("go get: unknown upgrade flag -u=%s", getU.rawVersion)
+               base.Fatalf("go: unknown upgrade flag -u=%s", getU.rawVersion)
+       }
+       // TODO(#43684): in the future (Go 1.20), warn that -d is a no-op.
+       if !*getD {
+               base.Fatalf("go: -d flag may not be disabled")
        }
        if *getF {
-               fmt.Fprintf(os.Stderr, "go get: -f flag is a no-op when using modules\n")
+               fmt.Fprintf(os.Stderr, "go: -f flag is a no-op when using modules\n")
        }
        if *getFix {
-               fmt.Fprintf(os.Stderr, "go get: -fix flag is a no-op when using modules\n")
+               fmt.Fprintf(os.Stderr, "go: -fix flag is a no-op when using modules\n")
        }
        if *getM {
-               base.Fatalf("go get: -m flag is no longer supported; consider -d to skip building packages")
+               base.Fatalf("go: -m flag is no longer supported")
        }
        if *getInsecure {
-               base.Fatalf("go get: -insecure flag is no longer supported; use GOINSECURE instead")
+               base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead")
        }
 
+       modload.ForceUseModules = true
+
        // Do not allow any updating of go.mod until we've applied
        // all the requested changes and checked that the result matches
        // what was requested.
-       modload.DisallowWriteGoMod()
+       modload.ExplicitWriteGoMod = true
 
        // Allow looking up modules for import paths when outside of a module.
        // 'go get' is expected to do this, unlike other commands.
        modload.AllowMissingModuleImports()
 
+       // 'go get' no longer builds or installs packages, so there's nothing to do
+       // if there's no go.mod file.
+       // TODO(#40775): make modload.Init return ErrNoModRoot instead of exiting.
+       // We could handle that here by printing a different message.
+       modload.Init()
+       if !modload.HasModRoot() {
+               base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" +
+                       "\t'go get' is no longer supported outside a module.\n" +
+                       "\tTo build and install a command, use 'go install' with a version,\n" +
+                       "\tlike 'go install example.com/cmd@latest'\n" +
+                       "\tFor more information, see https://golang.org/doc/go-get-install-deprecation\n" +
+                       "\tor run 'go help get' or 'go help install'.")
+       }
+
        queries := parseArgs(ctx, args)
 
        r := newResolver(ctx, queries)
@@ -356,74 +370,12 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
        }
        r.checkPackageProblems(ctx, pkgPatterns)
 
-       // We've already downloaded modules (and identified direct and indirect
-       // dependencies) by loading packages in findAndUpgradeImports.
-       // So if -d is set, we're done after the module work.
-       //
-       // Otherwise, we need to build and install the packages matched by
-       // command line arguments.
-       // Note that 'go get -u' without arguments is equivalent to
-       // 'go get -u .', so we'll typically build the package in the current
-       // directory.
-       if !*getD && len(pkgPatterns) > 0 {
-               work.BuildInit()
-
-               pkgOpts := load.PackageOpts{ModResolveTests: *getT}
-               var pkgs []*load.Package
-               for _, pkg := range load.PackagesAndErrors(ctx, pkgOpts, pkgPatterns) {
-                       if pkg.Error != nil {
-                               var noGo *load.NoGoError
-                               if errors.As(pkg.Error.Err, &noGo) {
-                                       if m := modload.PackageModule(pkg.ImportPath); m.Path == pkg.ImportPath {
-                                               // pkg is at the root of a module, and doesn't exist with the current
-                                               // build tags. Probably the user just wanted to change the version of
-                                               // that module — not also build the package — so suppress the error.
-                                               // (See https://golang.org/issue/33526.)
-                                               continue
-                                       }
-                               }
-                       }
-                       pkgs = append(pkgs, pkg)
-               }
-               load.CheckPackageErrors(pkgs)
-
-               haveExternalExe := false
-               for _, pkg := range pkgs {
-                       if pkg.Name == "main" && pkg.Module != nil && pkg.Module.Path != modload.Target.Path {
-                               haveExternalExe = true
-                               break
-                       }
-               }
-               if haveExternalExe {
-                       fmt.Fprint(os.Stderr, "go get: installing executables with 'go get' in module mode is deprecated.")
-                       var altMsg string
-                       if modload.HasModRoot() {
-                               altMsg = `
-       To adjust and download dependencies of the current module, use 'go get -d'.
-       To install using requirements of the current module, use 'go install'.
-       To install ignoring the current module, use 'go install' with a version,
-       like 'go install example.com/cmd@latest'.
-`
-                       } else {
-                               altMsg = "\n\tUse 'go install pkg@version' instead.\n"
-                       }
-                       fmt.Fprint(os.Stderr, altMsg)
-                       fmt.Fprintf(os.Stderr, "\tFor more information, see https://golang.org/doc/go-get-install-deprecation\n\tor run 'go help get' or 'go help install'.\n")
-               }
-
-               work.InstallPackages(ctx, pkgPatterns, pkgs)
-       }
-
-       if !modload.HasModRoot() {
-               return
-       }
-
        // Everything succeeded. Update go.mod.
        oldReqs := reqsFromGoMod(modload.ModFile())
 
-       modload.AllowWriteGoMod()
-       modload.WriteGoMod(ctx)
-       modload.DisallowWriteGoMod()
+       if err := modload.WriteGoMod(ctx); err != nil {
+               base.Fatalf("go: %v", err)
+       }
 
        newReqs := reqsFromGoMod(modload.ModFile())
        r.reportChanges(oldReqs, newReqs)
@@ -440,7 +392,7 @@ func parseArgs(ctx context.Context, rawArgs []string) []*query {
        for _, arg := range search.CleanPatterns(rawArgs) {
                q, err := newQuery(arg)
                if err != nil {
-                       base.Errorf("go get: %v", err)
+                       base.Errorf("go: %v", err)
                        continue
                }
 
@@ -455,11 +407,11 @@ func parseArgs(ctx context.Context, rawArgs []string) []*query {
                // if the argument has no version and either has no slash or refers to an existing file.
                if strings.HasSuffix(q.raw, ".go") && q.rawVersion == "" {
                        if !strings.Contains(q.raw, "/") {
-                               base.Errorf("go get %s: arguments must be package or module paths", q.raw)
+                               base.Errorf("go: %s: arguments must be package or module paths", q.raw)
                                continue
                        }
                        if fi, err := os.Stat(q.raw); err == nil && !fi.IsDir() {
-                               base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", q.raw)
+                               base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", q.raw)
                                continue
                        }
                }
@@ -675,7 +627,9 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
 
        if !q.isWildcard() {
                q.pathOnce(q.pattern, func() pathSet {
-                       if modload.HasModRoot() && q.pattern == modload.Target.Path {
+                       hasModRoot := modload.HasModRoot()
+                       if hasModRoot && modload.MainModules.Contains(q.pattern) {
+                               v := module.Version{Path: q.pattern}
                                // The user has explicitly requested to downgrade their own module to
                                // version "none". This is not an entirely unreasonable request: it
                                // could plausibly mean “downgrade away everything that depends on any
@@ -686,7 +640,7 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
                                // However, neither of those behaviors would be consistent with the
                                // plain meaning of the query. To try to reduce confusion, reject the
                                // query explicitly.
-                               return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
+                               return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version})
                        }
 
                        return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
@@ -698,8 +652,8 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
                        continue
                }
                q.pathOnce(curM.Path, func() pathSet {
-                       if modload.HasModRoot() && curM == modload.Target {
-                               return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
+                       if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) {
+                               return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version})
                        }
                        return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
                })
@@ -718,28 +672,38 @@ func (r *resolver) performLocalQueries(ctx context.Context) {
 
                        // Absolute paths like C:\foo and relative paths like ../foo... are
                        // restricted to matching packages in the main module.
-                       pkgPattern := modload.DirImportPath(ctx, q.pattern)
+                       pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern)
                        if pkgPattern == "." {
-                               return errSet(fmt.Errorf("%s%s is not within module rooted at %s", q.pattern, absDetail, modload.ModRoot()))
+                               modload.MustHaveModRoot()
+                               var modRoots []string
+                               for _, m := range modload.MainModules.Versions() {
+                                       modRoots = append(modRoots, modload.MainModules.ModRoot(m))
+                               }
+                               var plural string
+                               if len(modRoots) != 1 {
+                                       plural = "s"
+                               }
+                               return errSet(fmt.Errorf("%s%s is not within module%s rooted at %s", q.pattern, absDetail, plural, strings.Join(modRoots, ", ")))
                        }
 
-                       match := modload.MatchInModule(ctx, pkgPattern, modload.Target, imports.AnyTags())
+                       match := modload.MatchInModule(ctx, pkgPattern, mainModule, imports.AnyTags())
                        if len(match.Errs) > 0 {
                                return pathSet{err: match.Errs[0]}
                        }
 
                        if len(match.Pkgs) == 0 {
                                if q.raw == "" || q.raw == "." {
-                                       return errSet(fmt.Errorf("no package in current directory"))
+                                       return errSet(fmt.Errorf("no package to get in current directory"))
                                }
                                if !q.isWildcard() {
-                                       return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.ModRoot()))
+                                       modload.MustHaveModRoot()
+                                       return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.MainModules.ModRoot(mainModule)))
                                }
                                search.WarnUnmatched([]*search.Match{match})
                                return pathSet{}
                        }
 
-                       return pathSet{pkgMods: []module.Version{modload.Target}}
+                       return pathSet{pkgMods: []module.Version{mainModule}}
                })
        }
 }
@@ -789,11 +753,12 @@ func (r *resolver) queryWildcard(ctx context.Context, q *query) {
                                return pathSet{}
                        }
 
-                       if curM.Path == modload.Target.Path && !versionOkForMainModule(q.version) {
+                       if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
                                if q.matchesPath(curM.Path) {
-                                       return errSet(&modload.QueryMatchesMainModuleError{
-                                               Pattern: q.pattern,
-                                               Query:   q.version,
+                                       return errSet(&modload.QueryMatchesMainModulesError{
+                                               MainModules: []module.Version{curM},
+                                               Pattern:     q.pattern,
+                                               Query:       q.version,
                                        })
                                }
 
@@ -1159,8 +1124,8 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack
        }
 
        opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
-               if m.Path == "" || m == modload.Target {
-                       // Packages in the standard library and main module are already at their
+               if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
+                       // Packages in the standard library and main modules are already at their
                        // latest (and only) available versions.
                        return nil
                }
@@ -1327,7 +1292,7 @@ func (r *resolver) applyUpgrades(ctx context.Context, upgrades []pathSet) (chang
        var tentative []module.Version
        for _, cs := range upgrades {
                if cs.err != nil {
-                       base.Errorf("go get: %v", cs.err)
+                       base.Errorf("go: %v", cs.err)
                        continue
                }
 
@@ -1370,11 +1335,11 @@ func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m
                        continue
                }
 
-               if m.Path == modload.Target.Path {
-                       if m.Version == modload.Target.Version {
+               if modload.MainModules.Contains(m.Path) {
+                       if m.Version == "" {
                                return pathSet{}, true, m, true
                        }
-                       // The main module can only be set to its own version.
+                       // A main module can only be set to its own version.
                        continue
                }
 
@@ -1720,13 +1685,13 @@ func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) {
        })
        for _, c := range sortedChanges {
                if c.old == "" {
-                       fmt.Fprintf(os.Stderr, "go get: added %s %s\n", c.path, c.new)
+                       fmt.Fprintf(os.Stderr, "go: added %s %s\n", c.path, c.new)
                } else if c.new == "none" || c.new == "" {
-                       fmt.Fprintf(os.Stderr, "go get: removed %s %s\n", c.path, c.old)
+                       fmt.Fprintf(os.Stderr, "go: removed %s %s\n", c.path, c.old)
                } else if semver.Compare(c.new, c.old) > 0 {
-                       fmt.Fprintf(os.Stderr, "go get: upgraded %s %s => %s\n", c.path, c.old, c.new)
+                       fmt.Fprintf(os.Stderr, "go: upgraded %s %s => %s\n", c.path, c.old, c.new)
                } else {
-                       fmt.Fprintf(os.Stderr, "go get: downgraded %s %s => %s\n", c.path, c.old, c.new)
+                       fmt.Fprintf(os.Stderr, "go: downgraded %s %s => %s\n", c.path, c.old, c.new)
                }
        }
 
@@ -1744,10 +1709,11 @@ func (r *resolver) resolve(q *query, m module.Version) {
                panic("internal error: resolving a module.Version with an empty path")
        }
 
-       if m.Path == modload.Target.Path && m.Version != modload.Target.Version {
-               reportError(q, &modload.QueryMatchesMainModuleError{
-                       Pattern: q.pattern,
-                       Query:   q.version,
+       if modload.MainModules.Contains(m.Path) && m.Version != "" {
+               reportError(q, &modload.QueryMatchesMainModulesError{
+                       MainModules: []module.Version{{Path: m.Path}},
+                       Pattern:     q.pattern,
+                       Query:       q.version,
                })
                return
        }
@@ -1775,7 +1741,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
 
        resolved := make([]module.Version, 0, len(r.resolvedVersion))
        for mPath, rv := range r.resolvedVersion {
-               if mPath != modload.Target.Path {
+               if !modload.MainModules.Contains(mPath) {
                        resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
                }
        }
@@ -1784,7 +1750,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
        if err != nil {
                var constraint *modload.ConstraintError
                if !errors.As(err, &constraint) {
-                       base.Errorf("go get: %v", err)
+                       base.Errorf("go: %v", err)
                        return false
                }
 
@@ -1796,7 +1762,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
                        return rv.reason.ResolvedString(module.Version{Path: m.Path, Version: rv.version})
                }
                for _, c := range constraint.Conflicts {
-                       base.Errorf("go get: %v requires %v, not %v", reason(c.Source), c.Dep, reason(c.Constraint))
+                       base.Errorf("go: %v requires %v, not %v", reason(c.Source), c.Dep, reason(c.Constraint))
                }
                return false
        }
index 0a66517a4998f381fccf8ef809205a8833e034aa..887cb51b317f7f3c46db33192452197571467a09 100644 (file)
@@ -14,7 +14,7 @@ import (
        "cmd/go/internal/base"
        "cmd/go/internal/modload"
        "cmd/go/internal/search"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/module"
 )
@@ -192,9 +192,9 @@ func (q *query) validate() error {
                        // TODO(bcmills): "all@none" seems like a totally reasonable way to
                        // request that we remove all module requirements, leaving only the main
                        // module and standard library. Perhaps we should implement that someday.
-                       return &modload.QueryMatchesMainModuleError{
-                               Pattern: q.pattern,
-                               Query:   q.version,
+                       return &modload.QueryUpgradesAllError{
+                               MainModules: modload.MainModules.Versions(),
+                               Query:       q.version,
                        }
                }
        }
@@ -284,21 +284,21 @@ func reportError(q *query, err error) {
        patternRE := regexp.MustCompile("(?m)(?:[ \t(\"`]|^)" + regexp.QuoteMeta(q.pattern) + "(?:[ @:;)\"`]|$)")
        if patternRE.MatchString(errStr) {
                if q.rawVersion == "" {
-                       base.Errorf("go get: %s", errStr)
+                       base.Errorf("go: %s", errStr)
                        return
                }
 
                versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :;)\"`]|$)")
                if versionRE.MatchString(errStr) {
-                       base.Errorf("go get: %s", errStr)
+                       base.Errorf("go: %s", errStr)
                        return
                }
        }
 
        if qs := q.String(); qs != "" {
-               base.Errorf("go get %s: %s", qs, errStr)
+               base.Errorf("go: %s: %s", qs, errStr)
        } else {
-               base.Errorf("go get: %s", errStr)
+               base.Errorf("go: %s", errStr)
        }
 }
 
index 76e1ad589f43c1c6c12fed6faa038186a19453d7..0e0292ec15c8222270207f8ad99454203b08cd9e 100644 (file)
@@ -5,7 +5,6 @@
 package modload
 
 import (
-       "bytes"
        "context"
        "encoding/hex"
        "errors"
@@ -80,7 +79,7 @@ func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
                v  string
                ok bool
        )
-       if rs.depth == lazy {
+       if rs.pruning == pruned {
                v, ok = rs.rootSelected(path)
        }
        if !ok {
@@ -212,20 +211,20 @@ func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) {
 // in rs (which may be nil to indicate that m was not loaded from a requirement
 // graph).
 func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode) *modinfo.ModulePublic {
-       if m == Target {
+       if m.Version == "" && MainModules.Contains(m.Path) {
                info := &modinfo.ModulePublic{
                        Path:    m.Path,
                        Version: m.Version,
                        Main:    true,
                }
-               if v, ok := rawGoVersion.Load(Target); ok {
+               if v, ok := rawGoVersion.Load(m); ok {
                        info.GoVersion = v.(string)
                } else {
                        panic("internal error: GoVersion not set for main module")
                }
-               if HasModRoot() {
-                       info.Dir = ModRoot()
-                       info.GoMod = ModFilePath()
+               if modRoot := MainModules.ModRoot(m); modRoot != "" {
+                       info.Dir = modRoot
+                       info.GoMod = modFilePath(modRoot)
                }
                return info
        }
@@ -322,7 +321,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
                if filepath.IsAbs(r.Path) {
                        info.Replace.Dir = r.Path
                } else {
-                       info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
+                       info.Replace.Dir = filepath.Join(replaceRelativeTo(), r.Path)
                }
                info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
        }
@@ -336,84 +335,13 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
        return info
 }
 
-// PackageBuildInfo returns a string containing module version information
-// for modules providing packages named by path and deps. path and deps must
-// name packages that were resolved successfully with LoadPackages.
-func PackageBuildInfo(path string, deps []string) string {
-       if isStandardImportPath(path) || !Enabled() {
-               return ""
-       }
-
-       target := mustFindModule(loaded, path, path)
-       mdeps := make(map[module.Version]bool)
-       for _, dep := range deps {
-               if !isStandardImportPath(dep) {
-                       mdeps[mustFindModule(loaded, path, dep)] = true
-               }
-       }
-       var mods []module.Version
-       delete(mdeps, target)
-       for mod := range mdeps {
-               mods = append(mods, mod)
-       }
-       module.Sort(mods)
-
-       var buf bytes.Buffer
-       fmt.Fprintf(&buf, "path\t%s\n", path)
-
-       writeEntry := func(token string, m module.Version) {
-               mv := m.Version
-               if mv == "" {
-                       mv = "(devel)"
-               }
-               fmt.Fprintf(&buf, "%s\t%s\t%s", token, m.Path, mv)
-               if r := Replacement(m); r.Path == "" {
-                       fmt.Fprintf(&buf, "\t%s\n", modfetch.Sum(m))
-               } else {
-                       fmt.Fprintf(&buf, "\n=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
-               }
-       }
-
-       writeEntry("mod", target)
-       for _, mod := range mods {
-               writeEntry("dep", mod)
-       }
-
-       return buf.String()
-}
-
-// mustFindModule is like findModule, but it calls base.Fatalf if the
-// module can't be found.
-//
-// TODO(jayconrod): remove this. Callers should use findModule and return
-// errors instead of relying on base.Fatalf.
-func mustFindModule(ld *loader, target, path string) module.Version {
-       pkg, ok := ld.pkgCache.Get(path).(*loadPkg)
-       if ok {
-               if pkg.err != nil {
-                       base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
-               }
-               return pkg.mod
-       }
-
-       if path == "command-line-arguments" {
-               return Target
-       }
-
-       base.Fatalf("build %v: cannot find module for path %v", target, path)
-       panic("unreachable")
-}
-
 // findModule searches for the module that contains the package at path.
 // If the package was loaded, its containing module and true are returned.
-// Otherwise, module.Version{} and false are returend.
+// Otherwise, module.Version{} and false are returned.
 func findModule(ld *loader, path string) (module.Version, bool) {
        if pkg, ok := ld.pkgCache.Get(path).(*loadPkg); ok {
                return pkg.mod, pkg.mod != module.Version{}
        }
-       if path == "command-line-arguments" {
-               return Target, true
-       }
        return module.Version{}, false
 }
 
index bf6956731676d39e66e74642f6a43b40607d619a..27cab0b9c8060470f7fe3215fc4dca2884887fde 100644 (file)
@@ -30,17 +30,18 @@ func capVersionSlice(s []module.Version) []module.Version {
 
 // A Requirements represents a logically-immutable set of root module requirements.
 type Requirements struct {
-       // depth is the depth at which the requirement graph is computed.
+       // pruning is the pruning at which the requirement graph is computed.
        //
-       // If eager, the graph includes all transitive requirements regardless of depth.
+       // If unpruned, the graph includes all transitive requirements regardless
+       // of whether the requiring module supports pruning.
        //
-       // If lazy, the graph includes only the root modules, the explicit
+       // If pruned, the graph includes only the root modules, the explicit
        // requirements of those root modules, and the transitive requirements of only
-       // the *non-lazy* root modules.
-       depth modDepth
+       // the root modules that do not support pruning.
+       pruning modPruning
 
        // rootModules is the set of module versions explicitly required by the main
-       // module, sorted and capped to length. It may contain duplicates, and may
+       // modules, sorted and capped to length. It may contain duplicates, and may
        // contain multiple versions for a given module path.
        rootModules    []module.Version
        maxRootVersion map[string]string
@@ -97,10 +98,10 @@ var requirements *Requirements
 //
 // If vendoring is in effect, the caller must invoke initVendor on the returned
 // *Requirements before any other method.
-func newRequirements(depth modDepth, rootModules []module.Version, direct map[string]bool) *Requirements {
+func newRequirements(pruning modPruning, rootModules []module.Version, direct map[string]bool) *Requirements {
        for i, m := range rootModules {
-               if m == Target {
-                       panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is Target", i))
+               if m.Version == "" && MainModules.Contains(m.Path) {
+                       panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is a main module", i))
                }
                if m.Path == "" || m.Version == "" {
                        panic(fmt.Sprintf("bad requirement: rootModules[%v] = %v", i, m))
@@ -114,7 +115,7 @@ func newRequirements(depth modDepth, rootModules []module.Version, direct map[st
        }
 
        rs := &Requirements{
-               depth:          depth,
+               pruning:        pruning,
                rootModules:    capVersionSlice(rootModules),
                maxRootVersion: make(map[string]string, len(rootModules)),
                direct:         direct,
@@ -135,13 +136,18 @@ func newRequirements(depth modDepth, rootModules []module.Version, direct map[st
 func (rs *Requirements) initVendor(vendorList []module.Version) {
        rs.graphOnce.Do(func() {
                mg := &ModuleGraph{
-                       g: mvs.NewGraph(cmpVersion, []module.Version{Target}),
+                       g: mvs.NewGraph(cmpVersion, MainModules.Versions()),
                }
 
-               if rs.depth == lazy {
-                       // The roots of a lazy module should already include every module in the
-                       // vendor list, because the vendored modules are the same as those
-                       // maintained as roots by the lazy loading “import invariant”.
+               if MainModules.Len() != 1 {
+                       panic("There should be exactly one main module in Vendor mode.")
+               }
+               mainModule := MainModules.Versions()[0]
+
+               if rs.pruning == pruned {
+                       // The roots of a pruned module should already include every module in the
+                       // vendor list, because the vendored modules are the same as those needed
+                       // for graph pruning.
                        //
                        // Just to be sure, we'll double-check that here.
                        inconsistent := false
@@ -156,9 +162,9 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
                        }
 
                        // Now we can treat the rest of the module graph as effectively “pruned
-                       // out”, like a more aggressive version of lazy loading: in vendor mode,
-                       // the root requirements *are* the complete module graph.
-                       mg.g.Require(Target, rs.rootModules)
+                       // out”, as though we are viewing the main module from outside: in vendor
+                       // mode, the root requirements *are* the complete module graph.
+                       mg.g.Require(mainModule, rs.rootModules)
                } else {
                        // The transitive requirements of the main module are not in general available
                        // from the vendor directory, and we don't actually know how we got from
@@ -170,7 +176,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
                        // graph, but still distinguishes between direct and indirect
                        // dependencies.
                        vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""}
-                       mg.g.Require(Target, append(rs.rootModules, vendorMod))
+                       mg.g.Require(mainModule, append(rs.rootModules, vendorMod))
                        mg.g.Require(vendorMod, vendorList)
                }
 
@@ -182,8 +188,8 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
 // path, or the zero module.Version and ok=false if the module is not a root
 // dependency.
 func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
-       if path == Target.Path {
-               return Target.Version, true
+       if MainModules.Contains(path) {
+               return "", true
        }
        if v, ok := rs.maxRootVersion[path]; ok {
                return v, true
@@ -197,7 +203,7 @@ func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
 // selection.
 func (rs *Requirements) hasRedundantRoot() bool {
        for i, m := range rs.rootModules {
-               if m.Path == Target.Path || (i > 0 && m.Path == rs.rootModules[i-1].Path) {
+               if MainModules.Contains(m.Path) || (i > 0 && m.Path == rs.rootModules[i-1].Path) {
                        return true
                }
        }
@@ -214,7 +220,7 @@ func (rs *Requirements) hasRedundantRoot() bool {
 // returns a non-nil error of type *mvs.BuildListError.
 func (rs *Requirements) Graph(ctx context.Context) (*ModuleGraph, error) {
        rs.graphOnce.Do(func() {
-               mg, mgErr := readModGraph(ctx, rs.depth, rs.rootModules)
+               mg, mgErr := readModGraph(ctx, rs.pruning, rs.rootModules)
                rs.graph.Store(cachedGraph{mg, mgErr})
        })
        cached := rs.graph.Load().(cachedGraph)
@@ -230,7 +236,7 @@ func (rs *Requirements) IsDirect(path string) bool {
 // A ModuleGraph represents the complete graph of module dependencies
 // of a main module.
 //
-// If the main module is lazily loaded, the graph does not include
+// If the main module supports module graph pruning, the graph does not include
 // transitive dependencies of non-root (implicit) dependencies.
 type ModuleGraph struct {
        g         *mvs.Graph
@@ -254,8 +260,16 @@ var readModGraphDebugOnce sync.Once
 //
 // Unlike LoadModGraph, readModGraph does not attempt to diagnose or update
 // inconsistent roots.
-func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (*ModuleGraph, error) {
-       if depth == lazy {
+func readModGraph(ctx context.Context, pruning modPruning, roots []module.Version) (*ModuleGraph, error) {
+       if pruning == pruned {
+               // Enable diagnostics for lazy module loading
+               // (https://golang.org/ref/mod#lazy-loading) only if the module graph is
+               // pruned.
+               //
+               // In unpruned modules,we load the module graph much more aggressively (in
+               // order to detect inconsistencies that wouldn't be feasible to spot-check),
+               // so it wouldn't be useful to log when that occurs (because it happens in
+               // normal operation all the time).
                readModGraphDebugOnce.Do(func() {
                        for _, f := range strings.Split(os.Getenv("GODEBUG"), ",") {
                                switch f {
@@ -274,19 +288,26 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
                mu       sync.Mutex // guards mg.g and hasError during loading
                hasError bool
                mg       = &ModuleGraph{
-                       g: mvs.NewGraph(cmpVersion, []module.Version{Target}),
+                       g: mvs.NewGraph(cmpVersion, MainModules.Versions()),
                }
        )
-       mg.g.Require(Target, roots)
+       for _, m := range MainModules.Versions() {
+               // Require all roots from all main modules.
+               _ = TODOWorkspaces("This flattens a level of the module graph, adding the dependencies " +
+                       "of all main modules to a single requirements struct, and losing the information of which " +
+                       "main module required which requirement. Rework the requirements struct and change this" +
+                       "to reflect the structure of the main modules.")
+               mg.g.Require(m, roots)
+       }
 
        var (
-               loadQueue    = par.NewQueue(runtime.GOMAXPROCS(0))
-               loadingEager sync.Map // module.Version → nil; the set of modules that have been or are being loaded via eager roots
+               loadQueue       = par.NewQueue(runtime.GOMAXPROCS(0))
+               loadingUnpruned sync.Map // module.Version → nil; the set of modules that have been or are being loaded via roots that do not support pruning
        )
 
        // loadOne synchronously loads the explicit requirements for module m.
        // It does not load the transitive requirements of m even if the go version in
-       // m's go.mod file indicates eager loading.
+       // m's go.mod file indicates that it supports graph pruning.
        loadOne := func(m module.Version) (*modFileSummary, error) {
                cached := mg.loadCache.Do(m, func() interface{} {
                        summary, err := goModSummary(m)
@@ -305,15 +326,15 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
                return cached.summary, cached.err
        }
 
-       var enqueue func(m module.Version, depth modDepth)
-       enqueue = func(m module.Version, depth modDepth) {
+       var enqueue func(m module.Version, pruning modPruning)
+       enqueue = func(m module.Version, pruning modPruning) {
                if m.Version == "none" {
                        return
                }
 
-               if depth == eager {
-                       if _, dup := loadingEager.LoadOrStore(m, nil); dup {
-                               // m has already been enqueued for loading. Since eager loading may
+               if pruning == unpruned {
+                       if _, dup := loadingUnpruned.LoadOrStore(m, nil); dup {
+                               // m has already been enqueued for loading. Since unpruned loading may
                                // follow cycles in the the requirement graph, we need to return early
                                // to avoid making the load queue infinitely long.
                                return
@@ -326,21 +347,21 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
                                return // findError will report the error later.
                        }
 
-                       // If the version in m's go.mod file implies eager loading, then we cannot
-                       // assume that the explicit requirements of m (added by loadOne) are
-                       // sufficient to build the packages it contains. We must load its full
+                       // If the version in m's go.mod file does not support pruning, then we
+                       // cannot assume that the explicit requirements of m (added by loadOne)
+                       // are sufficient to build the packages it contains. We must load its full
                        // transitive dependency graph to be sure that we see all relevant
                        // dependencies.
-                       if depth == eager || summary.depth == eager {
+                       if pruning == unpruned || summary.pruning == unpruned {
                                for _, r := range summary.require {
-                                       enqueue(r, eager)
+                                       enqueue(r, unpruned)
                                }
                        }
                })
        }
 
        for _, m := range roots {
-               enqueue(m, depth)
+               enqueue(m, pruning)
        }
        <-loadQueue.Idle()
 
@@ -351,8 +372,7 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
 }
 
 // RequiredBy returns the dependencies required by module m in the graph,
-// or ok=false if module m's dependencies are not relevant (such as if they
-// are pruned out by lazy loading).
+// or ok=false if module m's dependencies are pruned out.
 //
 // The caller must not modify the returned slice, but may safely append to it
 // and may rely on it not to be modified.
@@ -404,10 +424,12 @@ func (mg *ModuleGraph) findError() error {
 }
 
 func (mg *ModuleGraph) allRootsSelected() bool {
-       roots, _ := mg.g.RequiredBy(Target)
-       for _, m := range roots {
-               if mg.Selected(m.Path) != m.Version {
-                       return false
+       for _, mm := range MainModules.Versions() {
+               roots, _ := mg.g.RequiredBy(mm)
+               for _, m := range roots {
+                       if mg.Selected(m.Path) != m.Version {
+                               return false
+                       }
                }
        }
        return true
@@ -427,12 +449,12 @@ func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph {
        rs := LoadModFile(ctx)
 
        if goVersion != "" {
-               depth := modDepthFromGoVersion(goVersion)
-               if depth == eager && rs.depth != eager {
+               pruning := pruningForGoVersion(goVersion)
+               if pruning == unpruned && rs.pruning != unpruned {
                        // Use newRequirements instead of convertDepth because convertDepth
                        // also updates roots; here, we want to report the unmodified roots
                        // even though they may seem inconsistent.
-                       rs = newRequirements(eager, rs.rootModules, rs.direct)
+                       rs = newRequirements(unpruned, rs.rootModules, rs.direct)
                }
 
                mg, err := rs.Graph(ctx)
@@ -447,7 +469,8 @@ func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph {
                base.Fatalf("go: %v", err)
        }
 
-       commitRequirements(ctx, modFileGoVersion(), rs)
+       requirements = rs
+
        return mg
 }
 
@@ -455,9 +478,8 @@ func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph {
 //
 // If the complete graph reveals that some root of rs is not actually the
 // selected version of its path, expandGraph computes a new set of roots that
-// are consistent. (When lazy loading is implemented, this may result in
-// upgrades to other modules due to requirements that were previously pruned
-// out.)
+// are consistent. (With a pruned module graph, this may result in upgrades to
+// other modules due to requirements that were previously pruned out.)
 //
 // expandGraph returns the updated roots, along with the module graph loaded
 // from those roots and any error encountered while loading that graph.
@@ -473,9 +495,9 @@ func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleG
 
        if !mg.allRootsSelected() {
                // The roots of rs are not consistent with the rest of the graph. Update
-               // them. In an eager module this is a no-op for the build list as a whole —
+               // them. In an unpruned module this is a no-op for the build list as a whole —
                // it just promotes what were previously transitive requirements to be
-               // roots — but in a lazy module it may pull in previously-irrelevant
+               // roots — but in a pruned module it may pull in previously-irrelevant
                // transitive dependencies.
 
                newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil, false)
@@ -513,7 +535,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) (chang
        if err != nil {
                return false, err
        }
-       commitRequirements(ctx, modFileGoVersion(), rs)
+       requirements = rs
        return changed, err
 }
 
@@ -544,23 +566,25 @@ type Conflict struct {
 
 // tidyRoots trims the root dependencies to the minimal requirements needed to
 // both retain the same versions of all packages in pkgs and satisfy the
-// lazy loading invariants (if applicable).
+// graph-pruning invariants (if applicable).
 func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
-       if rs.depth == eager {
-               return tidyEagerRoots(ctx, rs.direct, pkgs)
+       mainModule := MainModules.mustGetSingleMainModule()
+       if rs.pruning == unpruned {
+               return tidyUnprunedRoots(ctx, mainModule, rs.direct, pkgs)
        }
-       return tidyLazyRoots(ctx, rs.direct, pkgs)
+       return tidyPrunedRoots(ctx, mainModule, rs.direct, pkgs)
 }
 
 func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
-       if rs.depth == eager {
-               return updateEagerRoots(ctx, direct, rs, add)
+       if rs.pruning == unpruned {
+               return updateUnprunedRoots(ctx, direct, rs, add)
        }
-       return updateLazyRoots(ctx, direct, rs, pkgs, add, rootsImported)
+       return updatePrunedRoots(ctx, direct, rs, pkgs, add, rootsImported)
 }
 
-// tidyLazyRoots returns a minimal set of root requirements that maintains the
-// "lazy loading" invariants of the go.mod file for the given packages:
+// tidyPrunedRoots returns a minimal set of root requirements that maintains the
+// invariants of the go.mod file needed to support graph pruning for the given
+// packages:
 //
 //     1. For each package marked with pkgInAll, the module path that provided that
 //        package is included as a root.
@@ -568,16 +592,16 @@ func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements,
 //        selected at the same version or is upgraded by the dependencies of a
 //        root.
 //
-// If any module that provided a package has been upgraded above its previous,
+// If any module that provided a package has been upgraded above its previous
 // version, the caller may need to reload and recompute the package graph.
 //
 // To ensure that the loading process eventually converges, the caller should
 // add any needed roots from the tidy root set (without removing existing untidy
 // roots) until the set of roots has converged.
-func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
+func tidyPrunedRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
        var (
                roots        []module.Version
-               pathIncluded = map[string]bool{Target.Path: true}
+               pathIncluded = map[string]bool{mainModule.Path: true}
        )
        // We start by adding roots for every package in "all".
        //
@@ -605,7 +629,7 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
                queued[pkg] = true
        }
        module.Sort(roots)
-       tidy := newRequirements(lazy, roots, direct)
+       tidy := newRequirements(pruned, roots, direct)
 
        for len(queue) > 0 {
                roots = tidy.rootModules
@@ -641,7 +665,7 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
 
                if len(roots) > len(tidy.rootModules) {
                        module.Sort(roots)
-                       tidy = newRequirements(lazy, roots, tidy.direct)
+                       tidy = newRequirements(pruned, roots, tidy.direct)
                }
        }
 
@@ -652,8 +676,8 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
        return tidy, nil
 }
 
-// updateLazyRoots returns a set of root requirements that maintains the “lazy
-// loading” invariants of the go.mod file:
+// updatePrunedRoots returns a set of root requirements that maintains the
+// invariants of the go.mod file needed to support graph pruning:
 //
 //     1. The selected version of the module providing each package marked with
 //        either pkgInAll or pkgIsRoot is included as a root.
@@ -670,7 +694,7 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
 // The packages in pkgs are assumed to have been loaded from either the roots of
 // rs or the modules selected in the graph of rs.
 //
-// The above invariants together imply the “lazy loading” invariants for the
+// The above invariants together imply the graph-pruning invariants for the
 // go.mod file:
 //
 //     1. (The import invariant.) Every module that provides a package transitively
@@ -690,13 +714,13 @@ func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg)
 //        it requires explicitly. This invariant is left up to the caller, who must
 //        not load packages from outside the module graph but may add roots to the
 //        graph, but is facilited by (3). If the caller adds roots to the graph in
-//        order to resolve missing packages, then updateLazyRoots will retain them,
+//        order to resolve missing packages, then updatePrunedRoots will retain them,
 //        the selected versions of those roots cannot regress, and they will
 //        eventually be written back to the main module's go.mod file.
 //
 // (See https://golang.org/design/36460-lazy-module-loading#invariants for more
 // detail.)
-func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
+func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
        roots := rs.rootModules
        rootsUpgraded := false
 
@@ -717,11 +741,11 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
                        // pkg is transitively imported by a package or test in the main module.
                        // We need to promote the module that maintains it to a root: if some
                        // other module depends on the main module, and that other module also
-                       // uses lazy loading, it will expect to find all of our transitive
-                       // dependencies by reading just our go.mod file, not the go.mod files of
-                       // everything we depend on.
+                       // uses a pruned module graph, it will expect to find all of our
+                       // transitive dependencies by reading just our go.mod file, not the go.mod
+                       // files of everything we depend on.
                        //
-                       // (This is the “import invariant” that makes lazy loading possible.)
+                       // (This is the “import invariant” that makes graph pruning possible.)
 
                case rootsImported && pkg.flags.has(pkgFromRoot):
                        // pkg is a transitive dependency of some root, and we are treating the
@@ -732,17 +756,18 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
                        // it matches a command-line argument.) We want future invocations of the
                        // 'go' command — such as 'go test' on the same package — to continue to
                        // use the same versions of its dependencies that we are using right now.
-                       // So we need to bring this package's dependencies inside the lazy-loading
-                       // horizon.
+                       // So we need to bring this package's dependencies inside the pruned
+                       // module graph.
                        //
                        // Making the module containing this package a root of the module graph
-                       // does exactly that: if the module containing the package is lazy it
-                       // should satisfy the import invariant itself, so all of its dependencies
-                       // should be in its go.mod file, and if the module containing the package
-                       // is eager then if we make it a root we will load all of its transitive
-                       // dependencies into the module graph.
+                       // does exactly that: if the module containing the package supports graph
+                       // pruning then it should satisfy the import invariant itself, so all of
+                       // its dependencies should be in its go.mod file, and if the module
+                       // containing the package does not support pruning then if we make it a
+                       // root we will load all of its (unpruned) transitive dependencies into
+                       // the module graph.
                        //
-                       // (This is the “argument invariant” of lazy loading, and is important for
+                       // (This is the “argument invariant”, and is important for
                        // reproducibility.)
 
                default:
@@ -807,16 +832,15 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
                        // We've added or upgraded one or more roots, so load the full module
                        // graph so that we can update those roots to be consistent with other
                        // requirements.
-                       if cfg.BuildMod != "mod" {
+                       if mustHaveCompleteRequirements() {
                                // Our changes to the roots may have moved dependencies into or out of
-                               // the lazy-loading horizon, which could in turn change the selected
-                               // versions of other modules. (Unlike for eager modules, for lazy
-                               // modules adding or removing an explicit root is a semantic change, not
-                               // just a cosmetic one.)
+                               // the graph-pruning horizon, which could in turn change the selected
+                               // versions of other modules. (For pruned modules adding or removing an
+                               // explicit root is a semantic change, not just a cosmetic one.)
                                return rs, errGoModDirty
                        }
 
-                       rs = newRequirements(lazy, roots, direct)
+                       rs = newRequirements(pruned, roots, direct)
                        var err error
                        mg, err = rs.Graph(ctx)
                        if err != nil {
@@ -831,7 +855,7 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
                        if rs.graph.Load() != nil {
                                // We've already loaded the full module graph, which includes the
                                // requirements of all of the root modules — even the transitive
-                               // requirements, if they are eager!
+                               // requirements, if they are unpruned!
                                mg, _ = rs.Graph(ctx)
                        } else if cfg.BuildMod == "vendor" {
                                // We can't spot-check the requirements of other modules because we
@@ -855,7 +879,9 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
                roots = make([]module.Version, 0, len(rs.rootModules))
                rootsUpgraded = false
                inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
-               inRootPaths[Target.Path] = true
+               for _, mm := range MainModules.Versions() {
+                       inRootPaths[mm.Path] = true
+               }
                for _, m := range rs.rootModules {
                        if inRootPaths[m.Path] {
                                // This root specifies a redundant path. We already retained the
@@ -908,12 +934,12 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
                }
        }
 
-       if rs.depth == lazy && reflect.DeepEqual(roots, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
-               // The root set is unchanged and rs was already lazy, so keep rs to
+       if rs.pruning == pruned && reflect.DeepEqual(roots, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
+               // The root set is unchanged and rs was already pruned, so keep rs to
                // preserve its cached ModuleGraph (if any).
                return rs, nil
        }
-       return newRequirements(lazy, roots, direct), nil
+       return newRequirements(pruned, roots, direct), nil
 }
 
 // spotCheckRoots reports whether the versions of the roots in rs satisfy the
@@ -955,17 +981,37 @@ func spotCheckRoots(ctx context.Context, rs *Requirements, mods map[module.Versi
        return true
 }
 
-// tidyEagerRoots returns a minimal set of root requirements that maintains the
-// selected version of every module that provided a package in pkgs, and
-// includes the selected version of every such module in direct as a root.
-func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
+// tidyUnprunedRoots returns a minimal set of root requirements that maintains
+// the selected version of every module that provided or lexically could have
+// provided a package in pkgs, and includes the selected version of every such
+// module in direct as a root.
+func tidyUnprunedRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
        var (
+               // keep is a set of of modules that provide packages or are needed to
+               // disambiguate imports.
                keep     []module.Version
                keptPath = map[string]bool{}
-       )
-       var (
-               rootPaths   []string // module paths that should be included as roots
+
+               // rootPaths is a list of module paths that provide packages directly
+               // imported from the main module. They should be included as roots.
+               rootPaths   []string
                inRootPaths = map[string]bool{}
+
+               // altMods is a set of paths of modules that lexically could have provided
+               // imported packages. It may be okay to remove these from the list of
+               // explicit requirements if that removes them from the module graph. If they
+               // are present in the module graph reachable from rootPaths, they must not
+               // be at a lower version. That could cause a missing sum error or a new
+               // import ambiguity.
+               //
+               // For example, suppose a developer rewrites imports from example.com/m to
+               // example.com/m/v2, then runs 'go mod tidy'. Tidy may delete the
+               // requirement on example.com/m if there is no other transitive requirement
+               // on it. However, if example.com/m were downgraded to a version not in
+               // go.sum, when package example.com/m/v2/p is loaded, we'd get an error
+               // trying to disambiguate the import, since we can't check example.com/m
+               // without its sum. See #47738.
+               altMods = map[string]string{}
        )
        for _, pkg := range pkgs {
                if !pkg.fromExternalModule() {
@@ -979,16 +1025,48 @@ func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg
                                inRootPaths[m.Path] = true
                        }
                }
+               for _, m := range pkg.altMods {
+                       altMods[m.Path] = m.Version
+               }
        }
 
-       min, err := mvs.Req(Target, rootPaths, &mvsReqs{roots: keep})
+       // Construct a build list with a minimal set of roots.
+       // This may remove or downgrade modules in altMods.
+       reqs := &mvsReqs{roots: keep}
+       min, err := mvs.Req(mainModule, rootPaths, reqs)
+       if err != nil {
+               return nil, err
+       }
+       buildList, err := mvs.BuildList([]module.Version{mainModule}, reqs)
        if err != nil {
                return nil, err
        }
-       return newRequirements(eager, min, direct), nil
+
+       // Check if modules in altMods were downgraded but not removed.
+       // If so, add them to roots, which will retain an "// indirect" requirement
+       // in go.mod. See comment on altMods above.
+       keptAltMod := false
+       for _, m := range buildList {
+               if v, ok := altMods[m.Path]; ok && semver.Compare(m.Version, v) < 0 {
+                       keep = append(keep, module.Version{Path: m.Path, Version: v})
+                       keptAltMod = true
+               }
+       }
+       if keptAltMod {
+               // We must run mvs.Req again instead of simply adding altMods to min.
+               // It's possible that a requirement in altMods makes some other
+               // explicit indirect requirement unnecessary.
+               reqs.roots = keep
+               min, err = mvs.Req(mainModule, rootPaths, reqs)
+               if err != nil {
+                       return nil, err
+               }
+       }
+
+       return newRequirements(unpruned, min, direct), nil
 }
 
-// updateEagerRoots returns a set of root requirements that includes the selected
+// updateUnprunedRoots returns a set of root requirements that includes the selected
 // version of every module path in direct as a root, and maintains the selected
 // version of every module selected in the graph of rs.
 //
@@ -1002,7 +1080,7 @@ func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg
 //        by a dependency in add.
 //     4. Every version in add is selected at its given version unless upgraded by
 //        (the dependencies of) an existing root or another module in add.
-func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) {
+func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) {
        mg, err := rs.Graph(ctx)
        if err != nil {
                // We can't ignore errors in the module graph even if the user passed the -e
@@ -1011,7 +1089,7 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
                return rs, err
        }
 
-       if cfg.BuildMod != "mod" {
+       if mustHaveCompleteRequirements() {
                // Instead of actually updating the requirements, just check that no updates
                // are needed.
                if rs == nil {
@@ -1067,10 +1145,10 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
 
        // “The selected version of every module path in direct is included as a root.”
        //
-       // This is only for convenience and clarity for end users: in an eager module,
+       // This is only for convenience and clarity for end users: in an unpruned module,
        // the choice of explicit vs. implicit dependency has no impact on MVS
        // selection (for itself or any other module).
-       keep := append(mg.BuildList()[1:], add...)
+       keep := append(mg.BuildList()[MainModules.Len():], add...)
        for _, m := range keep {
                if direct[m.Path] && !inRootPaths[m.Path] {
                        rootPaths = append(rootPaths, m.Path)
@@ -1078,44 +1156,52 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
                }
        }
 
-       min, err := mvs.Req(Target, rootPaths, &mvsReqs{roots: keep})
-       if err != nil {
-               return rs, err
+       // TODO(matloob): Make roots into a map.
+       var roots []module.Version
+       for _, mainModule := range MainModules.Versions() {
+               min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep})
+               if err != nil {
+                       return rs, err
+               }
+               roots = append(roots, min...)
+       }
+       if MainModules.Len() > 1 {
+               module.Sort(roots)
        }
-       if rs.depth == eager && reflect.DeepEqual(min, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
-               // The root set is unchanged and rs was already eager, so keep rs to
+       if rs.pruning == unpruned && reflect.DeepEqual(roots, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
+               // The root set is unchanged and rs was already unpruned, so keep rs to
                // preserve its cached ModuleGraph (if any).
                return rs, nil
        }
-       return newRequirements(eager, min, direct), nil
+
+       return newRequirements(unpruned, roots, direct), nil
 }
 
-// convertDepth returns a version of rs with the given depth.
-// If rs already has the given depth, convertDepth returns rs unmodified.
-func convertDepth(ctx context.Context, rs *Requirements, depth modDepth) (*Requirements, error) {
-       if rs.depth == depth {
+// convertPruning returns a version of rs with the given pruning behavior.
+// If rs already has the given pruning, convertPruning returns rs unmodified.
+func convertPruning(ctx context.Context, rs *Requirements, pruning modPruning) (*Requirements, error) {
+       if rs.pruning == pruning {
                return rs, nil
        }
 
-       if depth == eager {
-               // We are converting a lazy module to an eager one. The roots of an eager
-               // module graph are a superset of the roots of a lazy graph, so we don't
-               // need to add any new roots — we just need to prune away the ones that are
-               // redundant given eager loading, which is exactly what updateEagerRoots
-               // does.
-               return updateEagerRoots(ctx, rs.direct, rs, nil)
+       if pruning == unpruned {
+               // We are converting a pruned module to an unpruned one. The roots of a
+               // ppruned module graph are a superset of the roots of an unpruned one, so
+               // we don't need to add any new roots — we just need to drop the ones that
+               // are redundant, which is exactly what updateUnprunedRoots does.
+               return updateUnprunedRoots(ctx, rs.direct, rs, nil)
        }
 
-       // We are converting an eager module to a lazy one. The module graph of an
-       // eager module includes the transitive dependencies of every module in the
-       // build list.
+       // We are converting an unpruned module to a pruned one.
        //
-       // Hey, we can express that as a lazy root set! “Include the transitive
-       // dependencies of every module in the build list” is exactly what happens in
-       // a lazy module if we promote every module in the build list to a root!
+       // An unpruned module graph includes the transitive dependencies of every
+       // module in the build list. As it turns out, we can express that as a pruned
+       // root set! “Include the transitive dependencies of every module in the build
+       // list” is exactly what happens in a pruned module if we promote every module
+       // in the build list to a root.
        mg, err := rs.Graph(ctx)
        if err != nil {
                return rs, err
        }
-       return newRequirements(lazy, mg.BuildList()[1:], rs.direct), nil
+       return newRequirements(pruned, mg.BuildList()[MainModules.Len():], rs.direct), nil
 }
index c350b9d1b5c571ed0e0754a07ad58fa3c9b26fe9..023983caed47d1de9a2339373c72fb4a5f254192 100644 (file)
@@ -21,7 +21,7 @@ import (
 //     2. Each module version in tryUpgrade is upgraded toward the indicated
 //        version as far as can be done without violating (1).
 //
-//     3. Each module version in rs.rootModules (or rs.graph, if rs.depth is eager)
+//     3. Each module version in rs.rootModules (or rs.graph, if rs is unpruned)
 //        is downgraded from its original version only to the extent needed to
 //        satisfy (1), or upgraded only to the extent needed to satisfy (1) and
 //        (2).
@@ -69,13 +69,14 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
        }
 
        var roots []module.Version
-       if rs.depth == eager {
-               // In an eager module, modules that provide packages imported by the main
-               // module may either be explicit roots or implicit transitive dependencies.
-               // We promote the modules in mustSelect to be explicit requirements.
+       if rs.pruning == unpruned {
+               // In a module without graph pruning, modules that provide packages imported
+               // by the main module may either be explicit roots or implicit transitive
+               // dependencies. We promote the modules in mustSelect to be explicit
+               // requirements.
                var rootPaths []string
                for _, m := range mustSelect {
-                       if m.Version != "none" && m.Path != Target.Path {
+                       if !MainModules.Contains(m.Path) && m.Version != "none" {
                                rootPaths = append(rootPaths, m.Path)
                        }
                }
@@ -97,13 +98,13 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
                        }
                }
 
-               roots, err = mvs.Req(Target, rootPaths, &mvsReqs{roots: mods})
+               roots, err = mvs.Req(MainModules.mustGetSingleMainModule(), rootPaths, &mvsReqs{roots: mods})
                if err != nil {
                        return nil, false, err
                }
        } else {
-               // In a lazy module, every module that provides a package imported by the
-               // main module must be retained as a root.
+               // In a module with a pruned graph, every module that provides a package
+               // imported by the main module must be retained as a root.
                roots = mods
                if !changed {
                        // Because the roots we just computed are unchanged, the entire graph must
@@ -126,7 +127,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
                        direct[m.Path] = true
                }
        }
-       return newRequirements(rs.depth, roots, direct), changed, nil
+       return newRequirements(rs.pruning, roots, direct), changed, nil
 }
 
 // limiterForEdit returns a versionLimiter with its max versions set such that
@@ -149,11 +150,12 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
                }
        }
 
-       if rs.depth == eager {
-               // Eager go.mod files don't indicate which transitive dependencies are
-               // actually relevant to the main module, so we have to assume that any module
-               // that could have provided any package — that is, any module whose selected
-               // version was not "none" — may be relevant.
+       if rs.pruning == unpruned {
+               // go.mod files that do not support graph pruning don't indicate which
+               // transitive dependencies are actually relevant to the main module, so we
+               // have to assume that any module that could have provided any package —
+               // that is, any module whose selected version was not "none" — may be
+               // relevant.
                for _, m := range mg.BuildList() {
                        restrictTo(m)
                }
@@ -175,7 +177,7 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
                }
        }
 
-       if err := raiseLimitsForUpgrades(ctx, maxVersion, rs.depth, tryUpgrade, mustSelect); err != nil {
+       if err := raiseLimitsForUpgrades(ctx, maxVersion, rs.pruning, tryUpgrade, mustSelect); err != nil {
                return nil, err
        }
 
@@ -185,22 +187,22 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
                restrictTo(m)
        }
 
-       return newVersionLimiter(rs.depth, maxVersion), nil
+       return newVersionLimiter(rs.pruning, maxVersion), nil
 }
 
 // raiseLimitsForUpgrades increases the module versions in maxVersions to the
 // versions that would be needed to allow each of the modules in tryUpgrade
-// (individually) and all of the modules in mustSelect (simultaneously) to be
-// added as roots.
+// (individually or in any combination) and all of the modules in mustSelect
+// (simultaneously) to be added as roots.
 //
 // Versions not present in maxVersion are unrestricted, and it is assumed that
 // they will not be promoted to root requirements (and thus will not contribute
-// their own dependencies if the main module is lazy).
+// their own dependencies if the main module supports graph pruning).
 //
 // These limits provide an upper bound on how far a module may be upgraded as
 // part of an incidental downgrade, if downgrades are needed in order to select
 // the versions in mustSelect.
-func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, depth modDepth, tryUpgrade []module.Version, mustSelect []module.Version) error {
+func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, pruning modPruning, tryUpgrade []module.Version, mustSelect []module.Version) error {
        // allow raises the limit for m.Path to at least m.Version.
        // If m.Path was already unrestricted, it remains unrestricted.
        allow := func(m module.Version) {
@@ -213,51 +215,88 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
                }
        }
 
-       var eagerUpgrades []module.Version
-       if depth == eager {
-               eagerUpgrades = tryUpgrade
+       var (
+               unprunedUpgrades []module.Version
+               isPrunedRootPath map[string]bool
+       )
+       if pruning == unpruned {
+               unprunedUpgrades = tryUpgrade
        } else {
+               isPrunedRootPath = make(map[string]bool, len(maxVersion))
+               for p := range maxVersion {
+                       isPrunedRootPath[p] = true
+               }
                for _, m := range tryUpgrade {
-                       if m.Path == Target.Path {
-                               // Target is already considered to be higher than any possible m, so we
-                               // won't be upgrading to it anyway and there is no point scanning its
-                               // dependencies.
-                               continue
+                       isPrunedRootPath[m.Path] = true
+               }
+               for _, m := range mustSelect {
+                       isPrunedRootPath[m.Path] = true
+               }
+
+               allowedRoot := map[module.Version]bool{}
+
+               var allowRoot func(m module.Version) error
+               allowRoot = func(m module.Version) error {
+                       if allowedRoot[m] {
+                               return nil
+                       }
+                       allowedRoot[m] = true
+
+                       if MainModules.Contains(m.Path) {
+                               // The main module versions are already considered to be higher than any
+                               // possible m, so m cannot be selected as a root and there is no point
+                               // scanning its dependencies.
+                               return nil
                        }
 
+                       allow(m)
+
                        summary, err := goModSummary(m)
                        if err != nil {
                                return err
                        }
-                       if summary.depth == eager {
-                               // For efficiency, we'll load all of the eager upgrades as one big
+                       if summary.pruning == unpruned {
+                               // For efficiency, we'll load all of the unpruned upgrades as one big
                                // graph, rather than loading the (potentially-overlapping) subgraph for
                                // each upgrade individually.
-                               eagerUpgrades = append(eagerUpgrades, m)
-                               continue
+                               unprunedUpgrades = append(unprunedUpgrades, m)
+                               return nil
                        }
-
                        for _, r := range summary.require {
-                               allow(r)
+                               if isPrunedRootPath[r.Path] {
+                                       // r could become a root as the result of an upgrade or downgrade,
+                                       // in which case its dependencies will not be pruned out.
+                                       // We need to allow those dependencies to be upgraded too.
+                                       if err := allowRoot(r); err != nil {
+                                               return err
+                                       }
+                               } else {
+                                       // r will not become a root, so its dependencies don't matter.
+                                       // Allow only r itself.
+                                       allow(r)
+                               }
                        }
+                       return nil
+               }
+
+               for _, m := range tryUpgrade {
+                       allowRoot(m)
                }
        }
 
-       if len(eagerUpgrades) > 0 {
-               // Compute the max versions for eager upgrades all together.
-               // Since these modules are eager, we'll end up scanning all of their
+       if len(unprunedUpgrades) > 0 {
+               // Compute the max versions for unpruned upgrades all together.
+               // Since these modules are unpruned, we'll end up scanning all of their
                // transitive dependencies no matter which versions end up selected,
                // and since we have a large dependency graph to scan we might get
                // a significant benefit from not revisiting dependencies that are at
                // common versions among multiple upgrades.
-               upgradeGraph, err := readModGraph(ctx, eager, eagerUpgrades)
+               upgradeGraph, err := readModGraph(ctx, unpruned, unprunedUpgrades)
                if err != nil {
-                       if go117LazyTODO {
-                               // Compute the requirement path from a module path in tryUpgrade to the
-                               // error, and the requirement path (if any) from rs.rootModules to the
-                               // tryUpgrade module path. Return a *mvs.BuildListError showing the
-                               // concatenation of the paths (with an upgrade in the middle).
-                       }
+                       // Compute the requirement path from a module path in tryUpgrade to the
+                       // error, and the requirement path (if any) from rs.rootModules to the
+                       // tryUpgrade module path. Return a *mvs.BuildListError showing the
+                       // concatenation of the paths (with an upgrade in the middle).
                        return err
                }
 
@@ -268,16 +307,41 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
                }
        }
 
-       if len(mustSelect) > 0 {
-               mustGraph, err := readModGraph(ctx, depth, mustSelect)
+       // Explicitly allow any (transitive) upgrades implied by mustSelect.
+       nextRoots := append([]module.Version(nil), mustSelect...)
+       for nextRoots != nil {
+               module.Sort(nextRoots)
+               rs := newRequirements(pruning, nextRoots, nil)
+               nextRoots = nil
+
+               rs, mustGraph, err := expandGraph(ctx, rs)
                if err != nil {
                        return err
                }
 
                for _, r := range mustGraph.BuildList() {
-                       // Some module in mustSelect requires r, so we must allow at least r.Version
-                       // unless it conflicts with an entry in mustSelect.
+                       // Some module in mustSelect requires r, so we must allow at least
+                       // r.Version (unless it conflicts with another entry in mustSelect, in
+                       // which case we will error out either way).
                        allow(r)
+
+                       if isPrunedRootPath[r.Path] {
+                               if v, ok := rs.rootSelected(r.Path); ok && r.Version == v {
+                                       // r is already a root, so its requirements are already included in
+                                       // the build list.
+                                       continue
+                               }
+
+                               // The dependencies in mustSelect may upgrade (or downgrade) an existing
+                               // root to match r, which will remain as a root. However, since r is not
+                               // a root of rs, its dependencies have been pruned out of this build
+                               // list. We need to add it back explicitly so that we allow any
+                               // transitive upgrades that r will pull in.
+                               if nextRoots == nil {
+                                       nextRoots = rs.rootModules // already capped
+                               }
+                               nextRoots = append(nextRoots, r)
+                       }
                }
        }
 
@@ -301,7 +365,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
        }
 
        var initial []module.Version
-       if rs.depth == eager {
+       if rs.pruning == unpruned {
                mg, err := rs.Graph(ctx)
                if err != nil {
                        return nil, false, err
@@ -318,7 +382,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
 
        mods = make([]module.Version, 0, len(limiter.selected))
        for path, v := range limiter.selected {
-               if v != "none" && path != Target.Path {
+               if v != "none" && !MainModules.Contains(path) {
                        mods = append(mods, module.Version{Path: path, Version: v})
                }
        }
@@ -328,13 +392,13 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
        // downgraded module may require a higher (but still allowed) version of
        // another. The lower version may require extraneous dependencies that aren't
        // actually relevant, so we need to compute the actual selected versions.
-       mg, err := readModGraph(ctx, rs.depth, mods)
+       mg, err := readModGraph(ctx, rs.pruning, mods)
        if err != nil {
                return nil, false, err
        }
        mods = make([]module.Version, 0, len(limiter.selected))
        for path, _ := range limiter.selected {
-               if path != Target.Path {
+               if !MainModules.Contains(path) {
                        if v := mg.Selected(path); v != "none" {
                                mods = append(mods, module.Version{Path: path, Version: v})
                        }
@@ -350,16 +414,16 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
 // A versionLimiter tracks the versions that may be selected for each module
 // subject to constraints on the maximum versions of transitive dependencies.
 type versionLimiter struct {
-       // depth is the depth at which the dependencies of the modules passed to
+       // pruning is the pruning at which the dependencies of the modules passed to
        // Select and UpgradeToward are loaded.
-       depth modDepth
+       pruning modPruning
 
        // max maps each module path to the maximum version that may be selected for
        // that path.
        //
        // Paths with no entry are unrestricted, and we assume that they will not be
        // promoted to root dependencies (so will not contribute dependencies if the
-       // main module is lazy).
+       // main module supports graph pruning).
        max map[string]string
 
        // selected maps each module path to a version of that path (if known) whose
@@ -411,14 +475,18 @@ func (dq dqState) isDisqualified() bool {
 // in the map are unrestricted. The limiter assumes that unrestricted paths will
 // not be promoted to root dependencies.
 //
-// If depth is lazy, then if a module passed to UpgradeToward or Select is
-// itself lazy, its unrestricted dependencies are skipped when scanning
-// requirements.
-func newVersionLimiter(depth modDepth, max map[string]string) *versionLimiter {
+// If module graph pruning is in effect, then if a module passed to
+// UpgradeToward or Select supports pruning, its unrestricted dependencies are
+// skipped when scanning requirements.
+func newVersionLimiter(pruning modPruning, max map[string]string) *versionLimiter {
+       selected := make(map[string]string)
+       for _, m := range MainModules.Versions() {
+               selected[m.Path] = m.Version
+       }
        return &versionLimiter{
-               depth:     depth,
+               pruning:   pruning,
                max:       max,
-               selected:  map[string]string{Target.Path: Target.Version},
+               selected:  selected,
                dqReason:  map[module.Version]dqState{},
                requiring: map[module.Version][]module.Version{},
        }
@@ -427,8 +495,8 @@ func newVersionLimiter(depth modDepth, max map[string]string) *versionLimiter {
 // UpgradeToward attempts to upgrade the selected version of m.Path as close as
 // possible to m.Version without violating l's maximum version limits.
 //
-// If depth is lazy and m itself is lazy, the the dependencies of unrestricted
-// dependencies of m will not be followed.
+// If module graph pruning is in effect and m itself supports pruning, the
+// dependencies of unrestricted dependencies of m will not be followed.
 func (l *versionLimiter) UpgradeToward(ctx context.Context, m module.Version) error {
        selected, ok := l.selected[m.Path]
        if ok {
@@ -440,7 +508,7 @@ func (l *versionLimiter) UpgradeToward(ctx context.Context, m module.Version) er
                selected = "none"
        }
 
-       if l.check(m, l.depth).isDisqualified() {
+       if l.check(m, l.pruning).isDisqualified() {
                candidates, err := versions(ctx, m.Path, CheckAllowed)
                if err != nil {
                        // This is likely a transient error reaching the repository,
@@ -457,7 +525,7 @@ func (l *versionLimiter) UpgradeToward(ctx context.Context, m module.Version) er
                })
                candidates = candidates[:i]
 
-               for l.check(m, l.depth).isDisqualified() {
+               for l.check(m, l.pruning).isDisqualified() {
                        n := len(candidates)
                        if n == 0 || cmpVersion(selected, candidates[n-1]) >= 0 {
                                // We couldn't find a suitable candidate above the already-selected version.
@@ -474,7 +542,7 @@ func (l *versionLimiter) UpgradeToward(ctx context.Context, m module.Version) er
 
 // Select attempts to set the selected version of m.Path to exactly m.Version.
 func (l *versionLimiter) Select(m module.Version) (conflict module.Version, err error) {
-       dq := l.check(m, l.depth)
+       dq := l.check(m, l.pruning)
        if !dq.isDisqualified() {
                l.selected[m.Path] = m.Version
        }
@@ -484,15 +552,15 @@ func (l *versionLimiter) Select(m module.Version) (conflict module.Version, err
 // check determines whether m (or its transitive dependencies) would violate l's
 // maximum version limits if added to the module requirement graph.
 //
-// If depth is lazy and m itself is lazy, then the dependencies of unrestricted
-// dependencies of m will not be followed. If the lazy loading invariants hold
-// for the main module up to this point, the packages in those modules are at
-// best only imported by tests of dependencies that are themselves loaded from
-// outside modules. Although we would like to keep 'go test all' as reproducible
-// as is feasible, we don't want to retain test dependencies that are only
-// marginally relevant at best.
-func (l *versionLimiter) check(m module.Version, depth modDepth) dqState {
-       if m.Version == "none" || m == Target {
+// If pruning is in effect and m itself supports graph pruning, the dependencies
+// of unrestricted dependencies of m will not be followed. If the graph-pruning
+// invariants hold for the main module up to this point, the packages in those
+// modules are at best only imported by tests of dependencies that are
+// themselves loaded from outside modules. Although we would like to keep
+// 'go test all' as reproducible as is feasible, we don't want to retain test
+// dependencies that are only marginally relevant at best.
+func (l *versionLimiter) check(m module.Version, pruning modPruning) dqState {
+       if m.Version == "none" || m == MainModules.mustGetSingleMainModule() {
                // version "none" has no requirements, and the dependencies of Target are
                // tautological.
                return dqState{}
@@ -522,20 +590,20 @@ func (l *versionLimiter) check(m module.Version, depth modDepth) dqState {
                return l.disqualify(m, dqState{err: err})
        }
 
-       if summary.depth == eager {
-               depth = eager
+       if summary.pruning == unpruned {
+               pruning = unpruned
        }
        for _, r := range summary.require {
-               if depth == lazy {
+               if pruning == pruned {
                        if _, restricted := l.max[r.Path]; !restricted {
                                // r.Path is unrestricted, so we don't care at what version it is
                                // selected. We assume that r.Path will not become a root dependency, so
-                               // since m is lazy, r's dependencies won't be followed.
+                               // since m supports pruning, r's dependencies won't be followed.
                                continue
                        }
                }
 
-               if dq := l.check(r, depth); dq.isDisqualified() {
+               if dq := l.check(r, pruning); dq.isDisqualified() {
                        return l.disqualify(m, dq)
                }
 
index d2bbe5cbe0b1eae58ac5a041792d0b4d0e8a3c85..bc2b0a02305826fbfa53d79bacf7ca76a5372bc0 100644 (file)
@@ -32,6 +32,8 @@ type ImportMissingError struct {
        Module   module.Version
        QueryErr error
 
+       ImportingMainModule module.Version
+
        // isStd indicates whether we would expect to find the package in the standard
        // library. This is normally true for all dotless import paths, but replace
        // directives can cause us to treat the replaced paths as also being in
@@ -71,6 +73,9 @@ func (e *ImportMissingError) Error() string {
                if e.QueryErr != nil {
                        return fmt.Sprintf("%s: %v", message, e.QueryErr)
                }
+               if e.ImportingMainModule.Path != "" && e.ImportingMainModule != MainModules.ModContainingCWD() {
+                       return fmt.Sprintf("%s; to add it:\n\tcd %s\n\tgo get %s", message, MainModules.ModRoot(e.ImportingMainModule), e.Path)
+               }
                return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
        }
 
@@ -238,55 +243,63 @@ func (e *invalidImportError) Unwrap() error {
 //
 // If the package is not present in any module selected from the requirement
 // graph, importFromModules returns an *ImportMissingError.
-func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, dir string, err error) {
+//
+// If the package is present in exactly one module, importFromModules will
+// return the module, its root directory, and a list of other modules that
+// lexically could have provided the package but did not.
+func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, dir string, altMods []module.Version, err error) {
        if strings.Contains(path, "@") {
-               return module.Version{}, "", fmt.Errorf("import path should not have @version")
+               return module.Version{}, "", nil, fmt.Errorf("import path should not have @version")
        }
        if build.IsLocalImport(path) {
-               return module.Version{}, "", fmt.Errorf("relative import not supported")
+               return module.Version{}, "", nil, fmt.Errorf("relative import not supported")
        }
        if path == "C" {
                // There's no directory for import "C".
-               return module.Version{}, "", nil
+               return module.Version{}, "", nil, nil
        }
        // Before any further lookup, check that the path is valid.
        if err := module.CheckImportPath(path); err != nil {
-               return module.Version{}, "", &invalidImportError{importPath: path, err: err}
+               return module.Version{}, "", nil, &invalidImportError{importPath: path, err: err}
        }
 
        // Is the package in the standard library?
        pathIsStd := search.IsStandardImportPath(path)
        if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
-               if targetInGorootSrc {
-                       if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil {
-                               return module.Version{}, dir, err
-                       } else if ok {
-                               return Target, dir, nil
+               for _, mainModule := range MainModules.Versions() {
+                       if MainModules.InGorootSrc(mainModule) {
+                               if dir, ok, err := dirInModule(path, MainModules.PathPrefix(mainModule), MainModules.ModRoot(mainModule), true); err != nil {
+                                       return module.Version{}, dir, nil, err
+                               } else if ok {
+                                       return mainModule, dir, nil, nil
+                               }
                        }
                }
                dir := filepath.Join(cfg.GOROOT, "src", path)
-               return module.Version{}, dir, nil
+               return module.Version{}, dir, nil, nil
        }
 
        // -mod=vendor is special.
        // Everything must be in the main module or the main module's vendor directory.
        if cfg.BuildMod == "vendor" {
-               mainDir, mainOK, mainErr := dirInModule(path, targetPrefix, ModRoot(), true)
-               vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
+               mainModule := MainModules.mustGetSingleMainModule()
+               modRoot := MainModules.ModRoot(mainModule)
+               mainDir, mainOK, mainErr := dirInModule(path, MainModules.PathPrefix(mainModule), modRoot, true)
+               vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(modRoot, "vendor"), false)
                if mainOK && vendorOK {
-                       return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
+                       return module.Version{}, "", nil, &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
                }
                // Prefer to return main directory if there is one,
                // Note that we're not checking that the package exists.
                // We'll leave that for load.
                if !vendorOK && mainDir != "" {
-                       return Target, mainDir, nil
+                       return mainModule, mainDir, nil, nil
                }
                if mainErr != nil {
-                       return module.Version{}, "", mainErr
+                       return module.Version{}, "", nil, mainErr
                }
-               readVendorList()
-               return vendorPkgModule[path], vendorDir, nil
+               readVendorList(mainModule)
+               return vendorPkgModule[path], vendorDir, nil, nil
        }
 
        // Check each module on the build list.
@@ -307,7 +320,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
        // already non-nil, then we attempt to load the package using the full
        // requirements in mg.
        for {
-               var sumErrMods []module.Version
+               var sumErrMods, altMods []module.Version
                for prefix := path; prefix != "."; prefix = pathpkg.Dir(prefix) {
                        var (
                                v  string
@@ -341,13 +354,15 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
                                // continue the loop and find the package in some other module,
                                // we need to look at this module to make sure the import is
                                // not ambiguous.
-                               return module.Version{}, "", err
+                               return module.Version{}, "", nil, err
                        }
                        if dir, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
-                               return module.Version{}, "", err
+                               return module.Version{}, "", nil, err
                        } else if ok {
                                mods = append(mods, m)
                                dirs = append(dirs, dir)
+                       } else {
+                               altMods = append(altMods, m)
                        }
                }
 
@@ -360,7 +375,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
                                mods[i], mods[j] = mods[j], mods[i]
                                dirs[i], dirs[j] = dirs[j], dirs[i]
                        }
-                       return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
+                       return module.Version{}, "", nil, &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
                }
 
                if len(sumErrMods) > 0 {
@@ -368,7 +383,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
                                j := len(sumErrMods) - 1 - i
                                sumErrMods[i], sumErrMods[j] = sumErrMods[j], sumErrMods[i]
                        }
-                       return module.Version{}, "", &ImportMissingSumError{
+                       return module.Version{}, "", nil, &ImportMissingSumError{
                                importPath: path,
                                mods:       sumErrMods,
                                found:      len(mods) > 0,
@@ -376,7 +391,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
                }
 
                if len(mods) == 1 {
-                       return mods[0], dirs[0], nil
+                       return mods[0], dirs[0], altMods, nil
                }
 
                if mg != nil {
@@ -386,7 +401,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
                        if !HasModRoot() {
                                queryErr = ErrNoModRoot
                        }
-                       return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
+                       return module.Version{}, "", nil, &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
                }
 
                // So far we've checked the root dependencies.
@@ -397,7 +412,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
                        // the module graph, so we can't return an ImportMissingError here — one
                        // of the missing modules might actually contain the package in question,
                        // in which case we shouldn't go looking for it in some new dependency.
-                       return module.Version{}, "", err
+                       return module.Version{}, "", nil, err
                }
        }
 }
@@ -410,9 +425,9 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
 func queryImport(ctx context.Context, path string, rs *Requirements) (module.Version, error) {
        // To avoid spurious remote fetches, try the latest replacement for each
        // module (golang.org/issue/26241).
-       if index != nil {
-               var mods []module.Version
-               for mp, mv := range index.highestReplaced {
+       var mods []module.Version
+       if MainModules != nil { // TODO(#48912): Ensure MainModules exists at this point, and remove the check.
+               for mp, mv := range MainModules.HighestReplaced() {
                        if !maybeInModule(path, mp) {
                                continue
                        }
@@ -439,40 +454,41 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
                        }
                        mods = append(mods, module.Version{Path: mp, Version: mv})
                }
+       }
 
-               // Every module path in mods is a prefix of the import path.
-               // As in QueryPattern, prefer the longest prefix that satisfies the import.
-               sort.Slice(mods, func(i, j int) bool {
-                       return len(mods[i].Path) > len(mods[j].Path)
-               })
-               for _, m := range mods {
-                       needSum := true
-                       root, isLocal, err := fetch(ctx, m, needSum)
-                       if err != nil {
-                               if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
-                                       return module.Version{}, &ImportMissingSumError{importPath: path}
-                               }
-                               return module.Version{}, err
-                       }
-                       if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
-                               return m, err
-                       } else if ok {
-                               if cfg.BuildMod == "readonly" {
-                                       return module.Version{}, &ImportMissingError{Path: path, replaced: m}
-                               }
-                               return m, nil
+       // Every module path in mods is a prefix of the import path.
+       // As in QueryPattern, prefer the longest prefix that satisfies the import.
+       sort.Slice(mods, func(i, j int) bool {
+               return len(mods[i].Path) > len(mods[j].Path)
+       })
+       for _, m := range mods {
+               needSum := true
+               root, isLocal, err := fetch(ctx, m, needSum)
+               if err != nil {
+                       if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
+                               return module.Version{}, &ImportMissingSumError{importPath: path}
                        }
+                       return module.Version{}, err
                }
-               if len(mods) > 0 && module.CheckPath(path) != nil {
-                       // The package path is not valid to fetch remotely,
-                       // so it can only exist in a replaced module,
-                       // and we know from the above loop that it is not.
-                       return module.Version{}, &PackageNotInModuleError{
-                               Mod:         mods[0],
-                               Query:       "latest",
-                               Pattern:     path,
-                               Replacement: Replacement(mods[0]),
+               if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
+                       return m, err
+               } else if ok {
+                       if cfg.BuildMod == "readonly" {
+                               return module.Version{}, &ImportMissingError{Path: path, replaced: m}
                        }
+                       return m, nil
+               }
+       }
+       if len(mods) > 0 && module.CheckPath(path) != nil {
+               // The package path is not valid to fetch remotely,
+               // so it can only exist in a replaced module,
+               // and we know from the above loop that it is not.
+               replacement := Replacement(mods[0])
+               return module.Version{}, &PackageNotInModuleError{
+                       Mod:         mods[0],
+                       Query:       "latest",
+                       Pattern:     path,
+                       Replacement: replacement,
                }
        }
 
@@ -638,14 +654,14 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
 // The isLocal return value reports whether the replacement,
 // if any, is local to the filesystem.
 func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
-       if mod == Target {
-               return ModRoot(), true, nil
+       if modRoot := MainModules.ModRoot(mod); modRoot != "" {
+               return modRoot, true, nil
        }
        if r := Replacement(mod); r.Path != "" {
                if r.Version == "" {
                        dir = r.Path
                        if !filepath.IsAbs(dir) {
-                               dir = filepath.Join(ModRoot(), dir)
+                               dir = filepath.Join(replaceRelativeTo(), dir)
                        }
                        // Ensure that the replacement directory actually exists:
                        // dirInModule does not report errors for missing modules,
@@ -667,7 +683,7 @@ func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, i
                mod = r
        }
 
-       if HasModRoot() && cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) {
+       if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && needSum && !modfetch.HaveSum(mod) {
                return "", false, module.VersionError(mod, &sumMissingError{})
        }
 
index 98145887e9dcc5c6b18aa071f08c27ce7c4681ca..11310489addbecccf79c848ee4933635957b58cb 100644 (file)
@@ -69,7 +69,7 @@ func TestQueryImport(t *testing.T) {
        RootMode = NoRoot
 
        ctx := context.Background()
-       rs := newRequirements(eager, nil, nil)
+       rs := newRequirements(unpruned, nil, nil)
 
        for _, tt := range importTests {
                t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
index d5f9d1042233816b3563978895cdf5b71fcdcaa3..0602aee0cccd63300d90d92256fda9bcf2912af4 100644 (file)
@@ -17,6 +17,7 @@ import (
        "path/filepath"
        "strconv"
        "strings"
+       "sync"
 
        "cmd/go/internal/base"
        "cmd/go/internal/cfg"
@@ -43,28 +44,191 @@ var (
        ForceUseModules bool
 
        allowMissingModuleImports bool
+
+       // ExplicitWriteGoMod prevents LoadPackages, ListModules, and other functions
+       // from updating go.mod and go.sum or reporting errors when updates are
+       // needed. A package should set this if it would cause go.mod to be written
+       // multiple times (for example, 'go get' calls LoadPackages multiple times) or
+       // if it needs some other operation to be successful before go.mod and go.sum
+       // can be written (for example, 'go mod download' must download modules before
+       // adding sums to go.sum). Packages that set this are responsible for calling
+       // WriteGoMod explicitly.
+       ExplicitWriteGoMod bool
 )
 
+func TODOWorkspaces(s string) error {
+       return fmt.Errorf("need to support this for workspaces: %s", s)
+}
+
 // Variables set in Init.
 var (
        initialized bool
-       modRoot     string
-       gopath      string
+
+       // These are primarily used to initialize the MainModules, and should be
+       // eventually superceded by them but are still used in cases where the module
+       // roots are required but MainModules hasn't been initialized yet. Set to
+       // the modRoots of the main modules.
+       // modRoots != nil implies len(modRoots) > 0
+       modRoots []string
+       gopath   string
 )
 
-// Variables set in initTarget (during {Load,Create}ModFile).
+// Variable set in InitWorkfile
 var (
-       Target module.Version
+       // Set to the path to the go.work file, or "" if workspace mode is disabled.
+       workFilePath string
+)
 
-       // targetPrefix is the path prefix for packages in Target, without a trailing
-       // slash. For most modules, targetPrefix is just Target.Path, but the
+type MainModuleSet struct {
+       // versions are the module.Version values of each of the main modules.
+       // For each of them, the Path fields are ordinary module paths and the Version
+       // fields are empty strings.
+       versions []module.Version
+
+       // modRoot maps each module in versions to its absolute filesystem path.
+       modRoot map[module.Version]string
+
+       // pathPrefix is the path prefix for packages in the module, without a trailing
+       // slash. For most modules, pathPrefix is just version.Path, but the
        // standard-library module "std" has an empty prefix.
-       targetPrefix string
+       pathPrefix map[module.Version]string
 
-       // targetInGorootSrc caches whether modRoot is within GOROOT/src.
+       // inGorootSrc caches whether modRoot is within GOROOT/src.
        // The "std" module is special within GOROOT/src, but not otherwise.
-       targetInGorootSrc bool
-)
+       inGorootSrc map[module.Version]bool
+
+       modFiles map[module.Version]*modfile.File
+
+       modContainingCWD module.Version
+
+       workFileGoVersion string
+
+       workFileReplaceMap map[module.Version]module.Version
+       // highest replaced version of each module path; empty string for wildcard-only replacements
+       highestReplaced map[string]string
+
+       indexMu sync.Mutex
+       indices map[module.Version]*modFileIndex
+}
+
+func (mms *MainModuleSet) PathPrefix(m module.Version) string {
+       return mms.pathPrefix[m]
+}
+
+// Versions returns the module.Version values of each of the main modules.
+// For each of them, the Path fields are ordinary module paths and the Version
+// fields are empty strings.
+// Callers should not modify the returned slice.
+func (mms *MainModuleSet) Versions() []module.Version {
+       if mms == nil {
+               return nil
+       }
+       return mms.versions
+}
+
+func (mms *MainModuleSet) Contains(path string) bool {
+       if mms == nil {
+               return false
+       }
+       for _, v := range mms.versions {
+               if v.Path == path {
+                       return true
+               }
+       }
+       return false
+}
+
+func (mms *MainModuleSet) ModRoot(m module.Version) string {
+       if mms == nil {
+               return ""
+       }
+       return mms.modRoot[m]
+}
+
+func (mms *MainModuleSet) InGorootSrc(m module.Version) bool {
+       if mms == nil {
+               return false
+       }
+       return mms.inGorootSrc[m]
+}
+
+func (mms *MainModuleSet) mustGetSingleMainModule() module.Version {
+       if mms == nil || len(mms.versions) == 0 {
+               panic("internal error: mustGetSingleMainModule called in context with no main modules")
+       }
+       if len(mms.versions) != 1 {
+               if inWorkspaceMode() {
+                       panic("internal error: mustGetSingleMainModule called in workspace mode")
+               } else {
+                       panic("internal error: multiple main modules present outside of workspace mode")
+               }
+       }
+       return mms.versions[0]
+}
+
+func (mms *MainModuleSet) GetSingleIndexOrNil() *modFileIndex {
+       if mms == nil {
+               return nil
+       }
+       if len(mms.versions) == 0 {
+               return nil
+       }
+       return mms.indices[mms.mustGetSingleMainModule()]
+}
+
+func (mms *MainModuleSet) Index(m module.Version) *modFileIndex {
+       mms.indexMu.Lock()
+       defer mms.indexMu.Unlock()
+       return mms.indices[m]
+}
+
+func (mms *MainModuleSet) SetIndex(m module.Version, index *modFileIndex) {
+       mms.indexMu.Lock()
+       defer mms.indexMu.Unlock()
+       mms.indices[m] = index
+}
+
+func (mms *MainModuleSet) ModFile(m module.Version) *modfile.File {
+       return mms.modFiles[m]
+}
+
+func (mms *MainModuleSet) Len() int {
+       if mms == nil {
+               return 0
+       }
+       return len(mms.versions)
+}
+
+// ModContainingCWD returns the main module containing the working directory,
+// or module.Version{} if none of the main modules contain the working
+// directory.
+func (mms *MainModuleSet) ModContainingCWD() module.Version {
+       return mms.modContainingCWD
+}
+
+func (mms *MainModuleSet) HighestReplaced() map[string]string {
+       return mms.highestReplaced
+}
+
+// GoVersion returns the go version set on the single module, in module mode,
+// or the go.work file in workspace mode.
+func (mms *MainModuleSet) GoVersion() string {
+       if !inWorkspaceMode() {
+               return modFileGoVersion(mms.ModFile(mms.mustGetSingleMainModule()))
+       }
+       v := mms.workFileGoVersion
+       if v == "" {
+               // Fall back to 1.18 for go.work files.
+               v = "1.18"
+       }
+       return v
+}
+
+func (mms *MainModuleSet) WorkFileReplaceMap() map[module.Version]module.Version {
+       return mms.workFileReplaceMap
+}
+
+var MainModules *MainModuleSet
 
 type Root int
 
@@ -94,6 +258,7 @@ const (
 // in go.mod, edit it before loading.
 func ModFile() *modfile.File {
        Init()
+       modFile := MainModules.ModFile(MainModules.mustGetSingleMainModule())
        if modFile == nil {
                die()
        }
@@ -102,9 +267,38 @@ func ModFile() *modfile.File {
 
 func BinDir() string {
        Init()
+       if cfg.GOBIN != "" {
+               return cfg.GOBIN
+       }
+       if gopath == "" {
+               return ""
+       }
        return filepath.Join(gopath, "bin")
 }
 
+// InitWorkfile initializes the workFilePath variable for commands that
+// operate in workspace mode. It should not be called by other commands,
+// for example 'go mod tidy', that don't operate in workspace mode.
+func InitWorkfile() {
+       switch cfg.WorkFile {
+       case "off":
+               workFilePath = ""
+       case "", "auto":
+               workFilePath = findWorkspaceFile(base.Cwd())
+       default:
+               if !filepath.IsAbs(cfg.WorkFile) {
+                       base.Errorf("the path provided to -workfile must be an absolute path")
+               }
+               workFilePath = cfg.WorkFile
+       }
+}
+
+// WorkFilePath returns the path of the go.work file, or "" if not in
+// workspace mode. WorkFilePath must be called after InitWorkfile.
+func WorkFilePath() string {
+       return workFilePath
+}
+
 // Init determines whether module mode is enabled, locates the root of the
 // current module (if any), sets environment variables for Git subprocesses, and
 // configures the cfg, codehost, load, modfetch, and search packages for use
@@ -169,18 +363,18 @@ func Init() {
        if os.Getenv("GCM_INTERACTIVE") == "" {
                os.Setenv("GCM_INTERACTIVE", "never")
        }
-
-       if modRoot != "" {
+       if modRoots != nil {
                // modRoot set before Init was called ("go mod init" does this).
                // No need to search for go.mod.
        } else if RootMode == NoRoot {
                if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") {
                        base.Fatalf("go: -modfile cannot be used with commands that ignore the current module")
                }
-               modRoot = ""
+               modRoots = nil
+       } else if inWorkspaceMode() {
+               // We're in workspace mode.
        } else {
-               modRoot = findModuleRoot(base.Cwd())
-               if modRoot == "" {
+               if modRoot := findModuleRoot(base.Cwd()); modRoot == "" {
                        if cfg.ModFile != "" {
                                base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
                        }
@@ -198,11 +392,12 @@ func Init() {
                        // will find it and get modules when they're not expecting them.
                        // It's a bit of a peculiar thing to disallow but quite mysterious
                        // when it happens. See golang.org/issue/26708.
-                       modRoot = ""
                        fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
                        if !mustUseModules {
                                return
                        }
+               } else {
+                       modRoots = []string{modRoot}
                }
        }
        if cfg.ModFile != "" && !strings.HasSuffix(cfg.ModFile, ".mod") {
@@ -212,36 +407,15 @@ func Init() {
        // We're in module mode. Set any global variables that need to be set.
        cfg.ModulesEnabled = true
        setDefaultBuildMod()
+       _ = TODOWorkspaces("In workspace mode, mod will not be readonly for go mod download," +
+               "verify, graph, and why. Implement support for go mod download and add test cases" +
+               "to ensure verify, graph, and why work properly.")
        list := filepath.SplitList(cfg.BuildContext.GOPATH)
-       if len(list) == 0 || list[0] == "" {
-               base.Fatalf("missing $GOPATH")
-       }
-       gopath = list[0]
-       if _, err := fsys.Stat(filepath.Join(gopath, "go.mod")); err == nil {
-               base.Fatalf("$GOPATH/go.mod exists but should not")
-       }
-
-       if modRoot == "" {
-               // We're in module mode, but not inside a module.
-               //
-               // Commands like 'go build', 'go run', 'go list' have no go.mod file to
-               // read or write. They would need to find and download the latest versions
-               // of a potentially large number of modules with no way to save version
-               // information. We can succeed slowly (but not reproducibly), but that's
-               // not usually a good experience.
-               //
-               // Instead, we forbid resolving import paths to modules other than std and
-               // cmd. Users may still build packages specified with .go files on the
-               // command line, but they'll see an error if those files import anything
-               // outside std.
-               //
-               // This can be overridden by calling AllowMissingModuleImports.
-               // For example, 'go get' does this, since it is expected to resolve paths.
-               //
-               // See golang.org/issue/32027.
-       } else {
-               modfetch.GoSumFile = strings.TrimSuffix(ModFilePath(), ".mod") + ".sum"
-               search.SetModRoot(modRoot)
+       if len(list) > 0 && list[0] != "" {
+               gopath = list[0]
+               if _, err := fsys.Stat(filepath.Join(gopath, "go.mod")); err == nil {
+                       base.Fatalf("$GOPATH/go.mod exists but should not")
+               }
        }
 }
 
@@ -255,7 +429,7 @@ func Init() {
 // be called until the command is installed and flags are parsed. Instead of
 // calling Init and Enabled, the main package can call this function.
 func WillBeEnabled() bool {
-       if modRoot != "" || cfg.ModulesEnabled {
+       if modRoots != nil || cfg.ModulesEnabled {
                // Already enabled.
                return true
        }
@@ -297,16 +471,18 @@ func WillBeEnabled() bool {
 // (usually through MustModRoot).
 func Enabled() bool {
        Init()
-       return modRoot != "" || cfg.ModulesEnabled
+       return modRoots != nil || cfg.ModulesEnabled
 }
 
-// ModRoot returns the root of the main module.
-// It calls base.Fatalf if there is no main module.
-func ModRoot() string {
-       if !HasModRoot() {
-               die()
+func VendorDir() string {
+       return filepath.Join(MainModules.ModRoot(MainModules.mustGetSingleMainModule()), "vendor")
+}
+
+func inWorkspaceMode() bool {
+       if !initialized {
+               panic("inWorkspaceMode called before modload.Init called")
        }
-       return modRoot
+       return workFilePath != ""
 }
 
 // HasModRoot reports whether a main module is present.
@@ -314,17 +490,27 @@ func ModRoot() string {
 // does not require a main module.
 func HasModRoot() bool {
        Init()
-       return modRoot != ""
+       return modRoots != nil
 }
 
-// ModFilePath returns the effective path of the go.mod file. Normally, this
-// "go.mod" in the directory returned by ModRoot, but the -modfile flag may
-// change its location. ModFilePath calls base.Fatalf if there is no main
-// module, even if -modfile is set.
-func ModFilePath() string {
+// MustHaveModRoot checks that a main module or main modules are present,
+// and calls base.Fatalf if there are no main modules.
+func MustHaveModRoot() {
+       Init()
        if !HasModRoot() {
                die()
        }
+}
+
+// ModFilePath returns the path that would be used for the go.mod
+// file, if in module mode. ModFilePath calls base.Fatalf if there is no main
+// module, even if -modfile is set.
+func ModFilePath() string {
+       MustHaveModRoot()
+       return modFilePath(findModuleRoot(base.Cwd()))
+}
+
+func modFilePath(modRoot string) string {
        if cfg.ModFile != "" {
                return cfg.ModFile
        }
@@ -365,12 +551,42 @@ func (goModDirtyError) Error() string {
 
 var errGoModDirty error = goModDirtyError{}
 
+func loadWorkFile(path string) (goVersion string, modRoots []string, replaces []*modfile.Replace, err error) {
+       _ = TODOWorkspaces("Clean up and write back the go.work file: add module paths for workspace modules.")
+       workDir := filepath.Dir(path)
+       workData, err := lockedfile.Read(path)
+       if err != nil {
+               return "", nil, nil, err
+       }
+       wf, err := modfile.ParseWork(path, workData, nil)
+       if err != nil {
+               return "", nil, nil, err
+       }
+       if wf.Go != nil {
+               goVersion = wf.Go.Version
+       }
+       seen := map[string]bool{}
+       for _, d := range wf.Directory {
+               modRoot := d.Path
+               if !filepath.IsAbs(modRoot) {
+                       modRoot = filepath.Join(workDir, modRoot)
+               }
+               if seen[modRoot] {
+                       return "", nil, nil, fmt.Errorf("path %s appears multiple times in workspace", modRoot)
+               }
+               seen[modRoot] = true
+               modRoots = append(modRoots, modRoot)
+       }
+       return goVersion, modRoots, wf.Replace, nil
+}
+
 // LoadModFile sets Target and, if there is a main module, parses the initial
 // build list from its go.mod file.
 //
 // LoadModFile may make changes in memory, like adding a go directive and
-// ensuring requirements are consistent, and will write those changes back to
-// disk unless DisallowWriteGoMod is in effect.
+// ensuring requirements are consistent. The caller is responsible for ensuring
+// those changes are written to disk by calling LoadPackages or ListModules
+// (unless ExplicitWriteGoMod is set) or by calling WriteGoMod directly.
 //
 // As a side-effect, LoadModFile may change cfg.BuildMod to "vendor" if
 // -mod wasn't set explicitly and automatic vendoring should be enabled.
@@ -383,111 +599,134 @@ var errGoModDirty error = goModDirtyError{}
 // it for global consistency. Most callers outside of the modload package should
 // use LoadModGraph instead.
 func LoadModFile(ctx context.Context) *Requirements {
-       rs, needCommit := loadModFile(ctx)
-       if needCommit {
-               commitRequirements(ctx, modFileGoVersion(), rs)
-       }
-       return rs
-}
-
-// loadModFile is like LoadModFile, but does not implicitly commit the
-// requirements back to disk after fixing inconsistencies.
-//
-// If needCommit is true, after the caller makes any other needed changes to the
-// returned requirements they should invoke commitRequirements to fix any
-// inconsistencies that may be present in the on-disk go.mod file.
-func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
        if requirements != nil {
-               return requirements, false
+               return requirements
        }
 
        Init()
-       if modRoot == "" {
-               Target = module.Version{Path: "command-line-arguments"}
-               targetPrefix = "command-line-arguments"
-               goVersion := LatestGoVersion()
-               rawGoVersion.Store(Target, goVersion)
-               requirements = newRequirements(modDepthFromGoVersion(goVersion), nil, nil)
-               return requirements, false
-       }
-
-       gomod := ModFilePath()
-       var data []byte
-       var err error
-       if gomodActual, ok := fsys.OverlayPath(gomod); ok {
-               // Don't lock go.mod if it's part of the overlay.
-               // On Plan 9, locking requires chmod, and we don't want to modify any file
-               // in the overlay. See #44700.
-               data, err = os.ReadFile(gomodActual)
+       var (
+               workFileGoVersion string
+               workFileReplaces  []*modfile.Replace
+       )
+       if inWorkspaceMode() {
+               var err error
+               workFileGoVersion, modRoots, workFileReplaces, err = loadWorkFile(workFilePath)
+               if err != nil {
+                       base.Fatalf("reading go.work: %v", err)
+               }
+               _ = TODOWorkspaces("Support falling back to individual module go.sum " +
+                       "files for sums not in the workspace sum file.")
+               modfetch.GoSumFile = workFilePath + ".sum"
+       } else if modRoots == nil {
+               // We're in module mode, but not inside a module.
+               //
+               // Commands like 'go build', 'go run', 'go list' have no go.mod file to
+               // read or write. They would need to find and download the latest versions
+               // of a potentially large number of modules with no way to save version
+               // information. We can succeed slowly (but not reproducibly), but that's
+               // not usually a good experience.
+               //
+               // Instead, we forbid resolving import paths to modules other than std and
+               // cmd. Users may still build packages specified with .go files on the
+               // command line, but they'll see an error if those files import anything
+               // outside std.
+               //
+               // This can be overridden by calling AllowMissingModuleImports.
+               // For example, 'go get' does this, since it is expected to resolve paths.
+               //
+               // See golang.org/issue/32027.
        } else {
-               data, err = lockedfile.Read(gomodActual)
-       }
-       if err != nil {
-               base.Fatalf("go: %v", err)
-       }
-
-       var fixed bool
-       f, err := modfile.Parse(gomod, data, fixVersion(ctx, &fixed))
-       if err != nil {
-               // Errors returned by modfile.Parse begin with file:line.
-               base.Fatalf("go: errors parsing go.mod:\n%s\n", err)
-       }
-       if f.Module == nil {
-               // No module declaration. Must add module path.
-               base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
+               modfetch.GoSumFile = strings.TrimSuffix(modFilePath(modRoots[0]), ".mod") + ".sum"
        }
+       if len(modRoots) == 0 {
+               _ = TODOWorkspaces("Instead of creating a fake module with an empty modroot, make MainModules.Len() == 0 mean that we're in module mode but not inside any module.")
+               mainModule := module.Version{Path: "command-line-arguments"}
+               MainModules = makeMainModules([]module.Version{mainModule}, []string{""}, []*modfile.File{nil}, []*modFileIndex{nil}, "", nil)
+               goVersion := LatestGoVersion()
+               rawGoVersion.Store(mainModule, goVersion)
+               requirements = newRequirements(pruningForGoVersion(goVersion), nil, nil)
+               return requirements
+       }
+
+       var modFiles []*modfile.File
+       var mainModules []module.Version
+       var indices []*modFileIndex
+       for _, modroot := range modRoots {
+               gomod := modFilePath(modroot)
+               var fixed bool
+               data, f, err := ReadModFile(gomod, fixVersion(ctx, &fixed))
+               if err != nil {
+                       base.Fatalf("go: %v", err)
+               }
 
-       modFile = f
-       initTarget(f.Module.Mod)
-       index = indexModFile(data, f, fixed)
+               modFiles = append(modFiles, f)
+               mainModule := f.Module.Mod
+               mainModules = append(mainModules, mainModule)
+               indices = append(indices, indexModFile(data, f, mainModule, fixed))
 
-       if err := module.CheckImportPath(f.Module.Mod.Path); err != nil {
-               if pathErr, ok := err.(*module.InvalidPathError); ok {
-                       pathErr.Kind = "module"
+               if err := module.CheckImportPath(f.Module.Mod.Path); err != nil {
+                       if pathErr, ok := err.(*module.InvalidPathError); ok {
+                               pathErr.Kind = "module"
+                       }
+                       base.Fatalf("go: %v", err)
                }
-               base.Fatalf("go: %v", err)
        }
 
+       MainModules = makeMainModules(mainModules, modRoots, modFiles, indices, workFileGoVersion, workFileReplaces)
        setDefaultBuildMod() // possibly enable automatic vendoring
-       rs = requirementsFromModFile()
+       rs := requirementsFromModFiles(ctx, modFiles)
+
+       if inWorkspaceMode() {
+               // We don't need to do anything for vendor or update the mod file so
+               // return early.
+               requirements = rs
+               return rs
+       }
+
+       mainModule := MainModules.mustGetSingleMainModule()
+
        if cfg.BuildMod == "vendor" {
-               readVendorList()
-               checkVendorConsistency()
+               readVendorList(mainModule)
+               index := MainModules.Index(mainModule)
+               modFile := MainModules.ModFile(mainModule)
+               checkVendorConsistency(index, modFile)
                rs.initVendor(vendorList)
        }
+
        if rs.hasRedundantRoot() {
                // If any module path appears more than once in the roots, we know that the
                // go.mod file needs to be updated even though we have not yet loaded any
                // transitive dependencies.
+               var err error
                rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
                if err != nil {
                        base.Fatalf("go: %v", err)
                }
        }
 
-       if index.goVersionV == "" {
+       if MainModules.Index(mainModule).goVersionV == "" {
                // TODO(#45551): Do something more principled instead of checking
                // cfg.CmdName directly here.
                if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" {
-                       addGoStmt(LatestGoVersion())
-                       if go117EnableLazyLoading {
-                               // We need to add a 'go' version to the go.mod file, but we must assume
-                               // that its existing contents match something between Go 1.11 and 1.16.
-                               // Go 1.11 through 1.16 have eager requirements, but the latest Go
-                               // version uses lazy requirements instead — so we need to cnvert the
-                               // requirements to be lazy.
-                               rs, err = convertDepth(ctx, rs, lazy)
-                               if err != nil {
-                                       base.Fatalf("go: %v", err)
-                               }
+                       addGoStmt(MainModules.ModFile(mainModule), mainModule, LatestGoVersion())
+
+                       // We need to add a 'go' version to the go.mod file, but we must assume
+                       // that its existing contents match something between Go 1.11 and 1.16.
+                       // Go 1.11 through 1.16 do not support graph pruning, but the latest Go
+                       // version uses a pruned module graph — so we need to convert the
+                       // requirements to support pruning.
+                       var err error
+                       rs, err = convertPruning(ctx, rs, pruned)
+                       if err != nil {
+                               base.Fatalf("go: %v", err)
                        }
                } else {
-                       rawGoVersion.Store(Target, modFileGoVersion())
+                       rawGoVersion.Store(mainModule, modFileGoVersion(MainModules.ModFile(mainModule)))
                }
        }
 
        requirements = rs
-       return requirements, true
+       return requirements
 }
 
 // CreateModFile initializes a new module by creating a go.mod file.
@@ -500,9 +739,10 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
 // exactly the same as in the legacy configuration (for example, we can't get
 // packages at multiple versions from the same module).
 func CreateModFile(ctx context.Context, modPath string) {
-       modRoot = base.Cwd()
+       modRoot := base.Cwd()
+       modRoots = []string{modRoot}
        Init()
-       modFilePath := ModFilePath()
+       modFilePath := modFilePath(modRoot)
        if _, err := fsys.Stat(modFilePath); err == nil {
                base.Fatalf("go: %s already exists", modFilePath)
        }
@@ -523,15 +763,22 @@ func CreateModFile(ctx context.Context, modPath string) {
                        }
                }
                base.Fatalf("go: %v", err)
+       } else if _, _, ok := module.SplitPathVersion(modPath); !ok {
+               if strings.HasPrefix(modPath, "gopkg.in/") {
+                       invalidMajorVersionMsg := fmt.Errorf("module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN:\n\tgo mod init %s", suggestGopkgIn(modPath))
+                       base.Fatalf(`go: invalid module path "%v": %v`, modPath, invalidMajorVersionMsg)
+               }
+               invalidMajorVersionMsg := fmt.Errorf("major version suffixes must be in the form of /vN and are only allowed for v2 or later:\n\tgo mod init %s", suggestModulePath(modPath))
+               base.Fatalf(`go: invalid module path "%v": %v`, modPath, invalidMajorVersionMsg)
        }
 
        fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
-       modFile = new(modfile.File)
+       modFile := new(modfile.File)
        modFile.AddModuleStmt(modPath)
-       initTarget(modFile.Module.Mod)
-       addGoStmt(LatestGoVersion()) // Add the go directive before converted module requirements.
+       MainModules = makeMainModules([]module.Version{modFile.Module.Mod}, []string{modRoot}, []*modfile.File{modFile}, []*modFileIndex{nil}, "", nil)
+       addGoStmt(modFile, modFile.Module.Mod, LatestGoVersion()) // Add the go directive before converted module requirements.
 
-       convertedFrom, err := convertLegacyConfig(modPath)
+       convertedFrom, err := convertLegacyConfig(modFile, modRoot)
        if convertedFrom != "" {
                fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(convertedFrom))
        }
@@ -539,12 +786,15 @@ func CreateModFile(ctx context.Context, modPath string) {
                base.Fatalf("go: %v", err)
        }
 
-       rs := requirementsFromModFile()
+       rs := requirementsFromModFiles(ctx, []*modfile.File{modFile})
        rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false)
        if err != nil {
                base.Fatalf("go: %v", err)
        }
-       commitRequirements(ctx, modFileGoVersion(), rs)
+       requirements = rs
+       if err := commitRequirements(ctx); err != nil {
+               base.Fatalf("go: %v", err)
+       }
 
        // Suggest running 'go mod tidy' unless the project is empty. Even if we
        // imported all the correct requirements above, we're probably missing
@@ -570,6 +820,32 @@ func CreateModFile(ctx context.Context, modPath string) {
        }
 }
 
+// CreateWorkFile initializes a new workspace by creating a go.work file.
+func CreateWorkFile(ctx context.Context, workFile string, modDirs []string) {
+       if _, err := fsys.Stat(workFile); err == nil {
+               base.Fatalf("go: %s already exists", workFile)
+       }
+
+       goV := LatestGoVersion() // Use current Go version by default
+       workF := new(modfile.WorkFile)
+       workF.Syntax = new(modfile.FileSyntax)
+       workF.AddGoStmt(goV)
+
+       for _, dir := range modDirs {
+               _, f, err := ReadModFile(filepath.Join(dir, "go.mod"), nil)
+               if err != nil {
+                       if os.IsNotExist(err) {
+                               base.Fatalf("go: creating workspace file: no go.mod file exists in directory %v", dir)
+                       }
+                       base.Fatalf("go: error parsing go.mod in directory %s: %v", dir, err)
+               }
+               workF.AddDirectory(ToDirectoryPath(dir), f.Module.Mod.Path)
+       }
+
+       data := modfile.Format(workF.Syntax)
+       lockedfile.Write(workFile, bytes.NewReader(data), 0666)
+}
+
 // fixVersion returns a modfile.VersionFixer implemented using the Query function.
 //
 // It resolves commit hashes and branch names to versions,
@@ -632,49 +908,118 @@ func AllowMissingModuleImports() {
        allowMissingModuleImports = true
 }
 
-// initTarget sets Target and associated variables according to modFile,
-func initTarget(m module.Version) {
-       Target = m
-       targetPrefix = m.Path
-
-       if rel := search.InDir(base.Cwd(), cfg.GOROOTsrc); rel != "" {
-               targetInGorootSrc = true
-               if m.Path == "std" {
-                       // The "std" module in GOROOT/src is the Go standard library. Unlike other
-                       // modules, the packages in the "std" module have no import-path prefix.
-                       //
-                       // Modules named "std" outside of GOROOT/src do not receive this special
-                       // treatment, so it is possible to run 'go test .' in other GOROOTs to
-                       // test individual packages using a combination of the modified package
-                       // and the ordinary standard library.
-                       // (See https://golang.org/issue/30756.)
-                       targetPrefix = ""
+// makeMainModules creates a MainModuleSet and associated variables according to
+// the given main modules.
+func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile.File, indices []*modFileIndex, workFileGoVersion string, workFileReplaces []*modfile.Replace) *MainModuleSet {
+       for _, m := range ms {
+               if m.Version != "" {
+                       panic("mainModulesCalled with module.Version with non empty Version field: " + fmt.Sprintf("%#v", m))
+               }
+       }
+       modRootContainingCWD := findModuleRoot(base.Cwd())
+       mainModules := &MainModuleSet{
+               versions:           ms[:len(ms):len(ms)],
+               inGorootSrc:        map[module.Version]bool{},
+               pathPrefix:         map[module.Version]string{},
+               modRoot:            map[module.Version]string{},
+               modFiles:           map[module.Version]*modfile.File{},
+               indices:            map[module.Version]*modFileIndex{},
+               workFileGoVersion:  workFileGoVersion,
+               workFileReplaceMap: toReplaceMap(workFileReplaces),
+               highestReplaced:    map[string]string{},
+       }
+       replacedByWorkFile := make(map[string]bool)
+       replacements := make(map[module.Version]module.Version)
+       for _, r := range workFileReplaces {
+               replacedByWorkFile[r.Old.Path] = true
+               v, ok := mainModules.highestReplaced[r.Old.Path]
+               if !ok || semver.Compare(r.Old.Version, v) > 0 {
+                       mainModules.highestReplaced[r.Old.Path] = r.Old.Version
+               }
+               replacements[r.Old] = r.New
+       }
+       for i, m := range ms {
+               mainModules.pathPrefix[m] = m.Path
+               mainModules.modRoot[m] = rootDirs[i]
+               mainModules.modFiles[m] = modFiles[i]
+               mainModules.indices[m] = indices[i]
+
+               if mainModules.modRoot[m] == modRootContainingCWD {
+                       mainModules.modContainingCWD = m
+               }
+
+               if rel := search.InDir(rootDirs[i], cfg.GOROOTsrc); rel != "" {
+                       mainModules.inGorootSrc[m] = true
+                       if m.Path == "std" {
+                               // The "std" module in GOROOT/src is the Go standard library. Unlike other
+                               // modules, the packages in the "std" module have no import-path prefix.
+                               //
+                               // Modules named "std" outside of GOROOT/src do not receive this special
+                               // treatment, so it is possible to run 'go test .' in other GOROOTs to
+                               // test individual packages using a combination of the modified package
+                               // and the ordinary standard library.
+                               // (See https://golang.org/issue/30756.)
+                               mainModules.pathPrefix[m] = ""
+                       }
+               }
+
+               if modFiles[i] != nil {
+                       curModuleReplaces := make(map[module.Version]bool)
+                       for _, r := range modFiles[i].Replace {
+                               if replacedByWorkFile[r.Old.Path] {
+                                       continue
+                               } else if prev, ok := replacements[r.Old]; ok && !curModuleReplaces[r.Old] {
+                                       base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v\nuse \"go mod editwork -replace %v=[override]\" to resolve", r.Old, prev, r.New, r.Old)
+                               }
+                               curModuleReplaces[r.Old] = true
+                               replacements[r.Old] = r.New
+
+                               v, ok := mainModules.highestReplaced[r.Old.Path]
+                               if !ok || semver.Compare(r.Old.Version, v) > 0 {
+                                       mainModules.highestReplaced[r.Old.Path] = r.Old.Version
+                               }
+                       }
                }
        }
+       return mainModules
 }
 
-// requirementsFromModFile returns the set of non-excluded requirements from
+// requirementsFromModFiles returns the set of non-excluded requirements from
 // the global modFile.
-func requirementsFromModFile() *Requirements {
-       roots := make([]module.Version, 0, len(modFile.Require))
+func requirementsFromModFiles(ctx context.Context, modFiles []*modfile.File) *Requirements {
+       rootCap := 0
+       for i := range modFiles {
+               rootCap += len(modFiles[i].Require)
+       }
+       roots := make([]module.Version, 0, rootCap)
+       mPathCount := make(map[string]int)
+       for _, m := range MainModules.Versions() {
+               mPathCount[m.Path] = 1
+       }
        direct := map[string]bool{}
-       for _, r := range modFile.Require {
-               if index != nil && index.exclude[r.Mod] {
-                       if cfg.BuildMod == "mod" {
-                               fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
-                       } else {
-                               fmt.Fprintf(os.Stderr, "go: ignoring requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
+       for _, modFile := range modFiles {
+       requirement:
+               for _, r := range modFile.Require {
+                       // TODO(#45713): Maybe join
+                       for _, mainModule := range MainModules.Versions() {
+                               if index := MainModules.Index(mainModule); index != nil && index.exclude[r.Mod] {
+                                       if cfg.BuildMod == "mod" {
+                                               fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
+                                       } else {
+                                               fmt.Fprintf(os.Stderr, "go: ignoring requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
+                                       }
+                                       continue requirement
+                               }
                        }
-                       continue
-               }
 
-               roots = append(roots, r.Mod)
-               if !r.Indirect {
-                       direct[r.Mod.Path] = true
+                       roots = append(roots, r.Mod)
+                       if !r.Indirect {
+                               direct[r.Mod.Path] = true
+                       }
                }
        }
        module.Sort(roots)
-       rs := newRequirements(modDepthFromGoVersion(modFileGoVersion()), roots, direct)
+       rs := newRequirements(pruningForGoVersion(MainModules.GoVersion()), roots, direct)
        return rs
 }
 
@@ -682,6 +1027,11 @@ func requirementsFromModFile() *Requirements {
 // wasn't provided. setDefaultBuildMod may be called multiple times.
 func setDefaultBuildMod() {
        if cfg.BuildModExplicit {
+               if inWorkspaceMode() && cfg.BuildMod != "readonly" {
+                       base.Fatalf("go: -mod may only be set to readonly when in workspace mode, but it is set to %q"+
+                               "\n\tRemove the -mod flag to use the default readonly value,"+
+                               "\n\tor set -workfile=off to disable workspace mode.", cfg.BuildMod)
+               }
                // Don't override an explicit '-mod=' argument.
                return
        }
@@ -700,13 +1050,12 @@ func setDefaultBuildMod() {
                // go.mod is inconsistent. They're useful for debugging, and they need
                // to work in buggy situations.
                cfg.BuildMod = "mod"
-               allowWriteGoMod = false
                return
        case "mod vendor":
                cfg.BuildMod = "readonly"
                return
        }
-       if modRoot == "" {
+       if modRoots == nil {
                if allowMissingModuleImports {
                        cfg.BuildMod = "mod"
                } else {
@@ -715,31 +1064,38 @@ func setDefaultBuildMod() {
                return
        }
 
-       if fi, err := fsys.Stat(filepath.Join(modRoot, "vendor")); err == nil && fi.IsDir() {
-               modGo := "unspecified"
-               if index != nil && index.goVersionV != "" {
-                       if semver.Compare(index.goVersionV, "v1.14") >= 0 {
-                               // The Go version is at least 1.14, and a vendor directory exists.
-                               // Set -mod=vendor by default.
-                               cfg.BuildMod = "vendor"
-                               cfg.BuildModReason = "Go version in go.mod is at least 1.14 and vendor directory exists."
-                               return
-                       } else {
-                               modGo = index.goVersionV[1:]
+       if len(modRoots) == 1 {
+               index := MainModules.GetSingleIndexOrNil()
+               if fi, err := fsys.Stat(filepath.Join(modRoots[0], "vendor")); err == nil && fi.IsDir() {
+                       modGo := "unspecified"
+                       if index != nil && index.goVersionV != "" {
+                               if semver.Compare(index.goVersionV, "v1.14") >= 0 {
+                                       // The Go version is at least 1.14, and a vendor directory exists.
+                                       // Set -mod=vendor by default.
+                                       cfg.BuildMod = "vendor"
+                                       cfg.BuildModReason = "Go version in go.mod is at least 1.14 and vendor directory exists."
+                                       return
+                               } else {
+                                       modGo = index.goVersionV[1:]
+                               }
                        }
-               }
 
-               // Since a vendor directory exists, we should record why we didn't use it.
-               // This message won't normally be shown, but it may appear with import errors.
-               cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo)
+                       // Since a vendor directory exists, we should record why we didn't use it.
+                       // This message won't normally be shown, but it may appear with import errors.
+                       cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo)
+               }
        }
 
        cfg.BuildMod = "readonly"
 }
 
+func mustHaveCompleteRequirements() bool {
+       return cfg.BuildMod != "mod" && !inWorkspaceMode()
+}
+
 // convertLegacyConfig imports module requirements from a legacy vendoring
 // configuration file, if one is present.
-func convertLegacyConfig(modPath string) (from string, err error) {
+func convertLegacyConfig(modFile *modfile.File, modRoot string) (from string, err error) {
        noneSelected := func(path string) (version string) { return "none" }
        queryPackage := func(path, rev string) (module.Version, error) {
                pkgMods, modOnly, err := QueryPattern(context.Background(), path, rev, noneSelected, nil)
@@ -770,14 +1126,14 @@ func convertLegacyConfig(modPath string) (from string, err error) {
 // addGoStmt adds a go directive to the go.mod file if it does not already
 // include one. The 'go' version added, if any, is the latest version supported
 // by this toolchain.
-func addGoStmt(v string) {
+func addGoStmt(modFile *modfile.File, mod module.Version, v string) {
        if modFile.Go != nil && modFile.Go.Version != "" {
                return
        }
        if err := modFile.AddGoStmt(v); err != nil {
                base.Fatalf("go: internal error: %v", err)
        }
-       rawGoVersion.Store(Target, v)
+       rawGoVersion.Store(mod, v)
 }
 
 // LatestGoVersion returns the latest version of the Go language supported by
@@ -828,7 +1184,7 @@ var altConfigs = []string{
        ".git/config",
 }
 
-func findModuleRoot(dir string) (root string) {
+func findModuleRoot(dir string) (roots string) {
        if dir == "" {
                panic("dir not set")
        }
@@ -848,6 +1204,32 @@ func findModuleRoot(dir string) (root string) {
        return ""
 }
 
+func findWorkspaceFile(dir string) (root string) {
+       if dir == "" {
+               panic("dir not set")
+       }
+       dir = filepath.Clean(dir)
+
+       // Look for enclosing go.mod.
+       for {
+               f := filepath.Join(dir, "go.work")
+               if fi, err := fsys.Stat(f); err == nil && !fi.IsDir() {
+                       return f
+               }
+               d := filepath.Dir(dir)
+               if d == dir {
+                       break
+               }
+               if d == cfg.GOROOT {
+                       _ = TODOWorkspaces("If we end up checking in a go.work file to GOROOT/src," +
+                               "remove this case.")
+                       return "" // As a special case, don't cross GOROOT to find a go.work file.
+               }
+               dir = d
+       }
+       return ""
+}
+
 func findAltConfig(dir string) (root, name string) {
        if dir == "" {
                panic("dir not set")
@@ -973,66 +1355,62 @@ func findImportComment(file string) string {
        return path
 }
 
-var allowWriteGoMod = true
-
-// DisallowWriteGoMod causes future calls to WriteGoMod to do nothing at all.
-func DisallowWriteGoMod() {
-       allowWriteGoMod = false
-}
-
-// AllowWriteGoMod undoes the effect of DisallowWriteGoMod:
-// future calls to WriteGoMod will update go.mod if needed.
-// Note that any past calls have been discarded, so typically
-// a call to AlowWriteGoMod should be followed by a call to WriteGoMod.
-func AllowWriteGoMod() {
-       allowWriteGoMod = true
-}
-
 // WriteGoMod writes the current build list back to go.mod.
-func WriteGoMod(ctx context.Context) {
-       if !allowWriteGoMod {
-               panic("WriteGoMod called while disallowed")
-       }
-       commitRequirements(ctx, modFileGoVersion(), LoadModFile(ctx))
+func WriteGoMod(ctx context.Context) error {
+       requirements = LoadModFile(ctx)
+       return commitRequirements(ctx)
 }
 
-// commitRequirements writes sets the global requirements variable to rs and
-// writes its contents back to the go.mod file on disk.
-func commitRequirements(ctx context.Context, goVersion string, rs *Requirements) {
-       requirements = rs
-
-       if !allowWriteGoMod {
-               // Some package outside of modload promised to update the go.mod file later.
-               return
-       }
-
-       if modRoot == "" {
+// commitRequirements ensures go.mod and go.sum are up to date with the current
+// requirements.
+//
+// In "mod" mode, commitRequirements writes changes to go.mod and go.sum.
+//
+// In "readonly" and "vendor" modes, commitRequirements returns an error if
+// go.mod or go.sum are out of date in a semantically significant way.
+//
+// In workspace mode, commitRequirements only writes changes to go.work.sum.
+func commitRequirements(ctx context.Context) (err error) {
+       if inWorkspaceMode() {
+               // go.mod files aren't updated in workspace mode, but we still want to
+               // update the go.work.sum file.
+               return modfetch.WriteGoSum(keepSums(ctx, loaded, requirements, addBuildListZipSums), mustHaveCompleteRequirements())
+       }
+       if MainModules.Len() != 1 || MainModules.ModRoot(MainModules.Versions()[0]) == "" {
                // We aren't in a module, so we don't have anywhere to write a go.mod file.
-               return
+               return nil
        }
+       mainModule := MainModules.mustGetSingleMainModule()
+       modFile := MainModules.ModFile(mainModule)
+       if modFile == nil {
+               // command-line-arguments has no .mod file to write.
+               return nil
+       }
+       modFilePath := modFilePath(MainModules.ModRoot(mainModule))
 
        var list []*modfile.Require
-       for _, m := range rs.rootModules {
+       for _, m := range requirements.rootModules {
                list = append(list, &modfile.Require{
                        Mod:      m,
-                       Indirect: !rs.direct[m.Path],
+                       Indirect: !requirements.direct[m.Path],
                })
        }
-       if goVersion != "" {
-               modFile.AddGoStmt(goVersion)
+       if modFile.Go == nil || modFile.Go.Version == "" {
+               modFile.AddGoStmt(modFileGoVersion(modFile))
        }
-       if semver.Compare("v"+modFileGoVersion(), separateIndirectVersionV) < 0 {
+       if semver.Compare("v"+modFileGoVersion(modFile), separateIndirectVersionV) < 0 {
                modFile.SetRequire(list)
        } else {
                modFile.SetRequireSeparateIndirect(list)
        }
        modFile.Cleanup()
 
+       index := MainModules.GetSingleIndexOrNil()
        dirty := index.modFileIsDirty(modFile)
        if dirty && cfg.BuildMod != "mod" {
                // If we're about to fail due to -mod=readonly,
                // prefer to report a dirty go.mod over a dirty go.sum
-               base.Fatalf("go: %v", errGoModDirty)
+               return errGoModDirty
        }
 
        if !dirty && cfg.CmdName != "mod tidy" {
@@ -1041,30 +1419,33 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
                // Don't write go.mod, but write go.sum in case we added or trimmed sums.
                // 'go mod init' shouldn't write go.sum, since it will be incomplete.
                if cfg.CmdName != "mod init" {
-                       modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums))
+                       if err := modfetch.WriteGoSum(keepSums(ctx, loaded, requirements, addBuildListZipSums), mustHaveCompleteRequirements()); err != nil {
+                               return err
+                       }
                }
-               return
+               return nil
        }
-       gomod := ModFilePath()
-       if _, ok := fsys.OverlayPath(gomod); ok {
+       if _, ok := fsys.OverlayPath(modFilePath); ok {
                if dirty {
-                       base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay")
+                       return errors.New("updates to go.mod needed, but go.mod is part of the overlay specified with -overlay")
                }
-               return
+               return nil
        }
 
        new, err := modFile.Format()
        if err != nil {
-               base.Fatalf("go: %v", err)
+               return err
        }
        defer func() {
                // At this point we have determined to make the go.mod file on disk equal to new.
-               index = indexModFile(new, modFile, false)
+               MainModules.SetIndex(mainModule, indexModFile(new, modFile, mainModule, false))
 
                // Update go.sum after releasing the side lock and refreshing the index.
                // 'go mod init' shouldn't write go.sum, since it will be incomplete.
                if cfg.CmdName != "mod init" {
-                       modfetch.WriteGoSum(keepSums(ctx, loaded, rs, addBuildListZipSums))
+                       if err == nil {
+                               err = modfetch.WriteGoSum(keepSums(ctx, loaded, requirements, addBuildListZipSums), mustHaveCompleteRequirements())
+                       }
                }
        }()
 
@@ -1076,7 +1457,7 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
 
        errNoChange := errors.New("no update needed")
 
-       err = lockedfile.Transform(ModFilePath(), func(old []byte) ([]byte, error) {
+       err = lockedfile.Transform(modFilePath, func(old []byte) ([]byte, error) {
                if bytes.Equal(old, new) {
                        // The go.mod file is already equal to new, possibly as the result of some
                        // other process.
@@ -1097,8 +1478,9 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
        })
 
        if err != nil && err != errNoChange {
-               base.Fatalf("go: updating go.mod: %v", err)
+               return fmt.Errorf("updating go.mod: %w", err)
        }
+       return nil
 }
 
 // keepSums returns the set of modules (and go.mod file entries) for which
@@ -1126,16 +1508,18 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
                                continue
                        }
 
-                       if rs.depth == lazy && pkg.mod.Path != "" {
+                       if rs.pruning == pruned && pkg.mod.Path != "" {
                                if v, ok := rs.rootSelected(pkg.mod.Path); ok && v == pkg.mod.Version {
-                                       // pkg was loaded from a root module, and because the main module is
-                                       // lazy we do not check non-root modules for conflicts for packages
-                                       // that can be found in roots. So we only need the checksums for the
-                                       // root modules that may contain pkg, not all possible modules.
+                                       // pkg was loaded from a root module, and because the main module has
+                                       // a pruned module graph we do not check non-root modules for
+                                       // conflicts for packages that can be found in roots. So we only need
+                                       // the checksums for the root modules that may contain pkg, not all
+                                       // possible modules.
                                        for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
                                                if v, ok := rs.rootSelected(prefix); ok && v != "none" {
                                                        m := module.Version{Path: prefix, Version: v}
-                                                       keep[resolveReplacement(m)] = true
+                                                       r := resolveReplacement(m)
+                                                       keep[r] = true
                                                }
                                        }
                                        continue
@@ -1146,15 +1530,15 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
                        for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
                                if v := mg.Selected(prefix); v != "none" {
                                        m := module.Version{Path: prefix, Version: v}
-                                       keep[resolveReplacement(m)] = true
+                                       r := resolveReplacement(m)
+                                       keep[r] = true
                                }
                        }
                }
        }
 
        if rs.graph.Load() == nil {
-               // The module graph was not loaded, possibly because the main module is lazy
-               // or possibly because we haven't needed to load the graph yet.
+               // We haven't needed to load the module graph so far.
                // Save sums for the root modules (or their replacements), but don't
                // incur the cost of loading the graph just to find and retain the sums.
                for _, m := range rs.rootModules {
@@ -1171,13 +1555,15 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
                                // The requirements from m's go.mod file are present in the module graph,
                                // so they are relevant to the MVS result regardless of whether m was
                                // actually selected.
-                               keep[modkey(resolveReplacement(m))] = true
+                               r := resolveReplacement(m)
+                               keep[modkey(r)] = true
                        }
                })
 
                if which == addBuildListZipSums {
                        for _, m := range mg.BuildList() {
-                               keep[resolveReplacement(m)] = true
+                               r := resolveReplacement(m)
+                               keep[r] = true
                        }
                }
        }
@@ -1197,3 +1583,56 @@ const (
 func modkey(m module.Version) module.Version {
        return module.Version{Path: m.Path, Version: m.Version + "/go.mod"}
 }
+
+func suggestModulePath(path string) string {
+       var m string
+
+       i := len(path)
+       for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') {
+               i--
+       }
+       url := path[:i]
+       url = strings.TrimSuffix(url, "/v")
+       url = strings.TrimSuffix(url, "/")
+
+       f := func(c rune) bool {
+               return c > '9' || c < '0'
+       }
+       s := strings.FieldsFunc(path[i:], f)
+       if len(s) > 0 {
+               m = s[0]
+       }
+       m = strings.TrimLeft(m, "0")
+       if m == "" || m == "1" {
+               return url + "/v2"
+       }
+
+       return url + "/v" + m
+}
+
+func suggestGopkgIn(path string) string {
+       var m string
+       i := len(path)
+       for i > 0 && (('0' <= path[i-1] && path[i-1] <= '9') || (path[i-1] == '.')) {
+               i--
+       }
+       url := path[:i]
+       url = strings.TrimSuffix(url, ".v")
+       url = strings.TrimSuffix(url, "/v")
+       url = strings.TrimSuffix(url, "/")
+
+       f := func(c rune) bool {
+               return c > '9' || c < '0'
+       }
+       s := strings.FieldsFunc(path, f)
+       if len(s) > 0 {
+               m = s[0]
+       }
+
+       m = strings.TrimLeft(m, "0")
+
+       if m == "" {
+               return url + ".v1"
+       }
+       return url + ".v" + m
+}
index ccdeb9b1d11e8650ec420169723ba7d1aae4c2ba..f782cd93db3d25d2258303fc22239c09156ff1c8 100644 (file)
@@ -72,14 +72,21 @@ func ListModules(ctx context.Context, args []string, mode ListMode) ([]*modinfo.
        }
 
        if err == nil {
-               commitRequirements(ctx, modFileGoVersion(), rs)
+               requirements = rs
+               if !ExplicitWriteGoMod {
+                       err = commitRequirements(ctx)
+               }
        }
        return mods, err
 }
 
 func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
        if len(args) == 0 {
-               return rs, []*modinfo.ModulePublic{moduleInfo(ctx, rs, Target, mode)}, nil
+               var ms []*modinfo.ModulePublic
+               for _, m := range MainModules.Versions() {
+                       ms = append(ms, moduleInfo(ctx, rs, m, mode))
+               }
+               return rs, ms, nil
        }
 
        needFullGraph := false
@@ -101,7 +108,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
                        path := arg[:i]
                        vers := arg[i+1:]
                        if vers == "upgrade" || vers == "patch" {
-                               if _, ok := rs.rootSelected(path); !ok || rs.depth == eager {
+                               if _, ok := rs.rootSelected(path); !ok || rs.pruning == unpruned {
                                        needFullGraph = true
                                        if !HasModRoot() {
                                                base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
@@ -110,7 +117,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
                        }
                        continue
                }
-               if _, ok := rs.rootSelected(arg); !ok || rs.depth == eager {
+               if _, ok := rs.rootSelected(arg); !ok || rs.pruning == unpruned {
                        needFullGraph = true
                        if mode&ListVersions == 0 && !HasModRoot() {
                                base.Fatalf("go: cannot match %q without -versions or an explicit version: %v", arg, ErrNoModRoot)
index b54f670812fbd2660d62360ee01316ce9d1a5aa1..845bf2f8a2323ac1beff39fc2adcb4acfb52e7fd 100644 (file)
@@ -40,9 +40,10 @@ package modload
 //     - the main module specifies a go version ≤ 1.15, and the package is imported
 //       by a *test of* another package in "all".
 //
-// When we implement lazy loading, we will record the modules providing packages
-// in "all" even when we are only loading individual packages, so we set the
-// pkgInAll flag regardless of the whether the "all" pattern is a root.
+// When graph pruning is in effect, we want to spot-check the graph-pruning
+// invariants — which depend on which packages are known to be in "all" — even
+// when we are only loading individual packages, so we set the pkgInAll flag
+// regardless of the whether the "all" pattern is a root.
 // (This is necessary to maintain the “import invariant” described in
 // https://golang.org/design/36460-lazy-module-loading.)
 //
@@ -118,7 +119,7 @@ import (
        "cmd/go/internal/mvs"
        "cmd/go/internal/par"
        "cmd/go/internal/search"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/module"
        "golang.org/x/mod/semver"
@@ -274,7 +275,9 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
 
                                                // If we're outside of a module, ensure that the failure mode
                                                // indicates that.
-                                               ModRoot()
+                                               if !HasModRoot() {
+                                                       die()
+                                               }
 
                                                if ld != nil {
                                                        m.AddError(err)
@@ -306,7 +309,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
                                        // The initial roots are the packages in the main module.
                                        // loadFromRoots will expand that to "all".
                                        m.Errs = m.Errs[:0]
-                                       matchPackages(ctx, m, opts.Tags, omitStd, []module.Version{Target})
+                                       matchPackages(ctx, m, opts.Tags, omitStd, MainModules.Versions())
                                } else {
                                        // Starting with the packages in the main module,
                                        // enumerate the full list of "all".
@@ -324,7 +327,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
                }
        }
 
-       initialRS, _ := loadModFile(ctx) // Ignore needCommit — we're going to commit at the end regardless.
+       initialRS := LoadModFile(ctx)
 
        ld := loadFromRoots(ctx, loaderParams{
                PackageOpts:  opts,
@@ -365,7 +368,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
 
                        for _, m := range initialRS.rootModules {
                                var unused bool
-                               if ld.requirements.depth == eager {
+                               if ld.requirements.pruning == unpruned {
                                        // m is unused if it was dropped from the module graph entirely. If it
                                        // was only demoted from direct to indirect, it may still be in use via
                                        // a transitive import.
@@ -384,7 +387,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
                }
 
                keep := keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly)
-               if compatDepth := modDepthFromGoVersion(ld.TidyCompatibleVersion); compatDepth != ld.requirements.depth {
+               if compatDepth := pruningForGoVersion(ld.TidyCompatibleVersion); compatDepth != ld.requirements.pruning {
                        compatRS := newRequirements(compatDepth, ld.requirements.rootModules, ld.requirements.direct)
                        ld.checkTidyCompatibility(ctx, compatRS)
 
@@ -393,7 +396,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
                        }
                }
 
-               if allowWriteGoMod {
+               if !ExplicitWriteGoMod {
                        modfetch.TrimGoSum(keep)
 
                        // commitRequirements below will also call WriteGoSum, but the "keep" map
@@ -401,13 +404,24 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
                        // loaded.requirements, but here we may have also loaded (and want to
                        // preserve checksums for) additional entities from compatRS, which are
                        // only needed for compatibility with ld.TidyCompatibleVersion.
-                       modfetch.WriteGoSum(keep)
+                       if err := modfetch.WriteGoSum(keep, mustHaveCompleteRequirements()); err != nil {
+                               base.Fatalf("go: %v", err)
+                       }
+               }
+
+               // Update the go.mod file's Go version if necessary.
+               modFile := MainModules.ModFile(MainModules.mustGetSingleMainModule())
+               if ld.GoVersion != "" {
+                       modFile.AddGoStmt(ld.GoVersion)
                }
        }
 
        // Success! Update go.mod and go.sum (if needed) and return the results.
+       // We'll skip updating if ExplicitWriteGoMod is true (the caller has opted
+       // to call WriteGoMod itself) or if ResolveMissingImports is false (the
+       // command wants to examine the package graph as-is).
        loaded = ld
-       commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
+       requirements = loaded.requirements
 
        for _, pkg := range ld.pkgs {
                if !pkg.isTest() {
@@ -415,6 +429,13 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
                }
        }
        sort.Strings(loadedPackages)
+
+       if !ExplicitWriteGoMod && opts.ResolveMissingImports {
+               if err := commitRequirements(ctx); err != nil {
+                       base.Fatalf("go: %v", err)
+               }
+       }
+
        return matches, loadedPackages
 }
 
@@ -436,14 +457,23 @@ func matchLocalDirs(ctx context.Context, m *search.Match, rs *Requirements) {
                if !filepath.IsAbs(dir) {
                        absDir = filepath.Join(base.Cwd(), dir)
                }
-               if search.InDir(absDir, cfg.GOROOTsrc) == "" && search.InDir(absDir, ModRoot()) == "" && pathInModuleCache(ctx, absDir, rs) == "" {
+
+               modRoot := findModuleRoot(absDir)
+               found := false
+               for _, mod := range MainModules.Versions() {
+                       if MainModules.ModRoot(mod) == modRoot {
+                               found = true
+                               break
+                       }
+               }
+               if !found && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(ctx, absDir, rs) == "" {
                        m.Dirs = []string{}
                        m.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir)))
                        return
                }
        }
 
-       m.MatchDirs()
+       m.MatchDirs(modRoots)
 }
 
 // resolveLocalPackage resolves a filesystem path to a package path.
@@ -485,49 +515,69 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
                }
        }
 
-       if modRoot != "" && absDir == modRoot {
-               if absDir == cfg.GOROOTsrc {
-                       return "", errPkgIsGorootSrc
+       for _, mod := range MainModules.Versions() {
+               modRoot := MainModules.ModRoot(mod)
+               if modRoot != "" && absDir == modRoot {
+                       if absDir == cfg.GOROOTsrc {
+                               return "", errPkgIsGorootSrc
+                       }
+                       return MainModules.PathPrefix(mod), nil
                }
-               return targetPrefix, nil
        }
 
        // Note: The checks for @ here are just to avoid misinterpreting
        // the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
        // It's not strictly necessary but helpful to keep the checks.
-       if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
-               suffix := filepath.ToSlash(absDir[len(modRoot):])
-               if strings.HasPrefix(suffix, "/vendor/") {
-                       if cfg.BuildMod != "vendor" {
-                               return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
+       var pkgNotFoundErr error
+       pkgNotFoundLongestPrefix := ""
+       for _, mainModule := range MainModules.Versions() {
+               modRoot := MainModules.ModRoot(mainModule)
+               if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
+                       suffix := filepath.ToSlash(absDir[len(modRoot):])
+                       if strings.HasPrefix(suffix, "/vendor/") {
+                               if cfg.BuildMod != "vendor" {
+                                       return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
+                               }
+
+                               readVendorList(mainModule)
+                               pkg := strings.TrimPrefix(suffix, "/vendor/")
+                               if _, ok := vendorPkgModule[pkg]; !ok {
+                                       return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
+                               }
+                               return pkg, nil
                        }
 
-                       readVendorList()
-                       pkg := strings.TrimPrefix(suffix, "/vendor/")
-                       if _, ok := vendorPkgModule[pkg]; !ok {
-                               return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
+                       mainModulePrefix := MainModules.PathPrefix(mainModule)
+                       if mainModulePrefix == "" {
+                               pkg := strings.TrimPrefix(suffix, "/")
+                               if pkg == "builtin" {
+                                       // "builtin" is a pseudo-package with a real source file.
+                                       // It's not included in "std", so it shouldn't resolve from "."
+                                       // within module "std" either.
+                                       return "", errPkgIsBuiltin
+                               }
+                               return pkg, nil
                        }
-                       return pkg, nil
-               }
 
-               if targetPrefix == "" {
-                       pkg := strings.TrimPrefix(suffix, "/")
-                       if pkg == "builtin" {
-                               // "builtin" is a pseudo-package with a real source file.
-                               // It's not included in "std", so it shouldn't resolve from "."
-                               // within module "std" either.
-                               return "", errPkgIsBuiltin
+                       pkg := mainModulePrefix + suffix
+                       if _, ok, err := dirInModule(pkg, mainModulePrefix, modRoot, true); err != nil {
+                               return "", err
+                       } else if !ok {
+                               // This main module could contain the directory but doesn't. Other main
+                               // modules might contain the directory, so wait till we finish the loop
+                               // to see if another main module contains directory. But if not,
+                               // return an error.
+                               if len(mainModulePrefix) > len(pkgNotFoundLongestPrefix) {
+                                       pkgNotFoundLongestPrefix = mainModulePrefix
+                                       pkgNotFoundErr = &PackageNotInModuleError{MainModules: []module.Version{mainModule}, Pattern: pkg}
+                               }
+                               continue
                        }
                        return pkg, nil
                }
-
-               pkg := targetPrefix + suffix
-               if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil {
-                       return "", err
-               } else if !ok {
-                       return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg}
-               }
-               return pkg, nil
+       }
+       if pkgNotFoundErr != nil {
+               return "", pkgNotFoundErr
        }
 
        if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
@@ -560,7 +610,7 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
                if repl := Replacement(m); repl.Path != "" && repl.Version == "" {
                        root = repl.Path
                        if !filepath.IsAbs(root) {
-                               root = filepath.Join(ModRoot(), root)
+                               root = filepath.Join(replaceRelativeTo(), root)
                        }
                } else if repl.Path != "" {
                        root, err = modfetch.DownloadDir(repl)
@@ -583,7 +633,7 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
                return path.Join(m.Path, filepath.ToSlash(sub)), true
        }
 
-       if rs.depth == lazy {
+       if rs.pruning == pruned {
                for _, m := range rs.rootModules {
                        if v, _ := rs.rootSelected(m.Path); v != m.Version {
                                continue // m is a root, but we have a higher root for the same path.
@@ -596,9 +646,9 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
                }
        }
 
-       // None of the roots contained dir, or we're in eager mode and want to load
-       // the full module graph more aggressively. Either way, check the full graph
-       // to see if the directory is a non-root dependency.
+       // None of the roots contained dir, or the graph is unpruned (so we don't want
+       // to distinguish between roots and transitive dependencies). Either way,
+       // check the full graph to see if the directory is a non-root dependency.
        //
        // If the roots are not consistent with the full module graph, the selected
        // versions of root modules may differ from what we already checked above.
@@ -645,14 +695,14 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
                        return roots
                },
        })
-       commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
+       requirements = loaded.requirements
 }
 
 // DirImportPath returns the effective import path for dir,
-// provided it is within the main module, or else returns ".".
-func DirImportPath(ctx context.Context, dir string) string {
+// provided it is within a main module, or else returns ".".
+func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path string, m module.Version) {
        if !HasModRoot() {
-               return "."
+               return ".", module.Version{}
        }
        LoadModFile(ctx) // Sets targetPrefix.
 
@@ -662,17 +712,32 @@ func DirImportPath(ctx context.Context, dir string) string {
                dir = filepath.Clean(dir)
        }
 
-       if dir == modRoot {
-               return targetPrefix
-       }
-       if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
-               suffix := filepath.ToSlash(dir[len(modRoot):])
-               if strings.HasPrefix(suffix, "/vendor/") {
-                       return strings.TrimPrefix(suffix, "/vendor/")
+       var longestPrefix string
+       var longestPrefixPath string
+       var longestPrefixVersion module.Version
+       for _, v := range mms.Versions() {
+               modRoot := mms.ModRoot(v)
+               if dir == modRoot {
+                       return mms.PathPrefix(v), v
+               }
+               if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
+                       pathPrefix := MainModules.PathPrefix(v)
+                       if pathPrefix > longestPrefix {
+                               longestPrefix = pathPrefix
+                               longestPrefixVersion = v
+                               suffix := filepath.ToSlash(dir[len(modRoot):])
+                               if strings.HasPrefix(suffix, "/vendor/") {
+                                       longestPrefixPath = strings.TrimPrefix(suffix, "/vendor/")
+                               }
+                               longestPrefixPath = mms.PathPrefix(v) + suffix
+                       }
                }
-               return targetPrefix + suffix
        }
-       return "."
+       if len(longestPrefix) > 0 {
+               return longestPrefixPath, longestPrefixVersion
+       }
+
+       return ".", module.Version{}
 }
 
 // ImportMap returns the actual package import path
@@ -807,6 +872,7 @@ type loadPkg struct {
        imports     []*loadPkg     // packages imported by this one
        testImports []string       // test-only imports, saved for use by pkg.test.
        inStd       bool
+       altMods     []module.Version // modules that could have contained the package but did not
 
        // Populated by (*loader).pkgTest:
        testOnce sync.Once
@@ -894,10 +960,7 @@ func (pkg *loadPkg) fromExternalModule() bool {
        if pkg.mod.Path == "" {
                return false // loaded from the standard library, not a module
        }
-       if pkg.mod.Path == Target.Path {
-               return false // loaded from the main module.
-       }
-       return true
+       return !MainModules.Contains(pkg.mod.Path)
 }
 
 var errMissing = errors.New("cannot find package")
@@ -915,10 +978,10 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
        }
 
        if ld.GoVersion == "" {
-               ld.GoVersion = modFileGoVersion()
+               ld.GoVersion = MainModules.GoVersion()
 
                if ld.Tidy && semver.Compare("v"+ld.GoVersion, "v"+LatestGoVersion()) > 0 {
-                       ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", ld.GoVersion, LatestGoVersion())
+                       ld.errorf("go: go.mod file indicates go %s, but maximum version supported by tidy is %s\n", ld.GoVersion, LatestGoVersion())
                        base.ExitIfErrors()
                }
        }
@@ -935,18 +998,26 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
        }
 
        if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll {
-               // The module's go version explicitly predates the change in "all" for lazy
-               // loading, so continue to use the older interpretation.
+               // The module's go version explicitly predates the change in "all" for graph
+               // pruning, so continue to use the older interpretation.
                ld.allClosesOverTests = true
        }
 
        var err error
-       ld.requirements, err = convertDepth(ctx, ld.requirements, modDepthFromGoVersion(ld.GoVersion))
+       ld.requirements, err = convertPruning(ctx, ld.requirements, pruningForGoVersion(ld.GoVersion))
        if err != nil {
                ld.errorf("go: %v\n", err)
        }
 
-       if ld.requirements.depth == eager {
+       if ld.requirements.pruning == unpruned {
+               // If the module graph does not support pruning, we assume that we will need
+               // the full module graph in order to load package dependencies.
+               //
+               // This might not be strictly necessary, but it matches the historical
+               // behavior of the 'go' command and keeps the go.mod file more consistent in
+               // case of erroneous hand-edits — which are less likely to be detected by
+               // spot-checks in modules that do not maintain the expanded go.mod
+               // requirements needed for graph pruning.
                var err error
                ld.requirements, _, err = expandGraph(ctx, ld.requirements)
                if err != nil {
@@ -963,7 +1034,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
                // build list we're using.
                rootPkgs := ld.listRoots(ld.requirements)
 
-               if ld.requirements.depth == lazy && cfg.BuildMod == "mod" {
+               if ld.requirements.pruning == pruned && cfg.BuildMod == "mod" {
                        // Before we start loading transitive imports of packages, locate all of
                        // the root packages and promote their containing modules to root modules
                        // dependencies. If their go.mod files are tidy (the common case) and the
@@ -1074,15 +1145,15 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
                        ld.errorf("go: %v\n", err)
                }
 
-               if ld.requirements.depth == lazy {
+               if ld.requirements.pruning == pruned {
                        // We continuously add tidy roots to ld.requirements during loading, so at
                        // this point the tidy roots should be a subset of the roots of
                        // ld.requirements, ensuring that no new dependencies are brought inside
-                       // the lazy-loading horizon.
+                       // the graph-pruning horizon.
                        // If that is not the case, there is a bug in the loading loop above.
                        for _, m := range rs.rootModules {
                                if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version {
-                                       ld.errorf("go mod tidy: internal error: a requirement on %v is needed but was not added during package loading\n", m)
+                                       ld.errorf("go: internal error: a requirement on %v is needed but was not added during package loading\n", m)
                                        base.ExitIfErrors()
                                }
                        }
@@ -1124,8 +1195,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
 }
 
 // updateRequirements ensures that ld.requirements is consistent with the
-// information gained from ld.pkgs and includes the modules in add as roots at
-// at least the given versions.
+// information gained from ld.pkgs.
 //
 // In particular:
 //
@@ -1168,7 +1238,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
        }
 
        for _, pkg := range ld.pkgs {
-               if pkg.mod != Target {
+               if pkg.mod.Version != "" || !MainModules.Contains(pkg.mod.Path) {
                        continue
                }
                for _, dep := range pkg.imports {
@@ -1206,14 +1276,14 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
 
        var addRoots []module.Version
        if ld.Tidy {
-               // When we are tidying a lazy module, we may need to add roots to preserve
-               // the versions of indirect, test-only dependencies that are upgraded
-               // above or otherwise missing from the go.mod files of direct
-               // dependencies. (For example, the direct dependency might be a very
+               // When we are tidying a module with a pruned dependency graph, we may need
+               // to add roots to preserve the versions of indirect, test-only dependencies
+               // that are upgraded above or otherwise missing from the go.mod files of
+               // direct dependencies. (For example, the direct dependency might be a very
                // stable codebase that predates modules and thus lacks a go.mod file, or
-               // the author of the direct dependency may have forgotten to commit a
-               // change to the go.mod file, or may have made an erroneous hand-edit that
-               // causes it to be untidy.)
+               // the author of the direct dependency may have forgotten to commit a change
+               // to the go.mod file, or may have made an erroneous hand-edit that causes
+               // it to be untidy.)
                //
                // Promoting an indirect dependency to a root adds the next layer of its
                // dependencies to the module graph, which may increase the selected
@@ -1283,7 +1353,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
                                //
                                // In some sense, we can think of this as ‘upgraded the module providing
                                // pkg.path from "none" to a version higher than "none"’.
-                               if _, _, err = importFromModules(ctx, pkg.path, rs, nil); err == nil {
+                               if _, _, _, err = importFromModules(ctx, pkg.path, rs, nil); err == nil {
                                        changed = true
                                        break
                                }
@@ -1327,6 +1397,15 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod
                        var err error
                        mod, err = queryImport(ctx, pkg.path, ld.requirements)
                        if err != nil {
+                               var ime *ImportMissingError
+                               if errors.As(err, &ime) {
+                                       for curstack := pkg.stack; curstack != nil; curstack = curstack.stack {
+                                               if MainModules.Contains(curstack.mod.Path) {
+                                                       ime.ImportingMainModule = curstack.mod
+                                                       break
+                                               }
+                                       }
+                               }
                                // pkg.err was already non-nil, so we can reasonably attribute the error
                                // for pkg to either the original error or the one returned by
                                // queryImport. The existing error indicates only that we couldn't find
@@ -1425,7 +1504,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
                // so it's ok if we call it more than is strictly necessary.
                wantTest := false
                switch {
-               case ld.allPatternIsRoot && pkg.mod == Target:
+               case ld.allPatternIsRoot && MainModules.Contains(pkg.mod.Path):
                        // We are loading the "all" pattern, which includes packages imported by
                        // tests in the main module. This package is in the main module, so we
                        // need to identify the imports of its test even if LoadTests is not set.
@@ -1446,7 +1525,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
 
                if wantTest {
                        var testFlags loadPkgFlags
-                       if pkg.mod == Target || (ld.allClosesOverTests && new.has(pkgInAll)) {
+                       if MainModules.Contains(pkg.mod.Path) || (ld.allClosesOverTests && new.has(pkgInAll)) {
                                // Tests of packages in the main module are in "all", in the sense that
                                // they cause the packages they import to also be in "all". So are tests
                                // of packages in "all" if "all" closes over test dependencies.
@@ -1485,7 +1564,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
                        // If the main module is tidy and the package is in "all" — or if we're
                        // lucky — we can identify all of its imports without actually loading the
                        // full module graph.
-                       m, _, err := importFromModules(ctx, path, ld.requirements, nil)
+                       m, _, _, err := importFromModules(ctx, path, ld.requirements, nil)
                        if err != nil {
                                var missing *ImportMissingError
                                if errors.As(err, &missing) && ld.ResolveMissingImports {
@@ -1511,7 +1590,8 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
                                // module to a root to ensure that any other packages this package
                                // imports are resolved from correct dependency versions.
                                //
-                               // (This is the “argument invariant” from the lazy loading design.)
+                               // (This is the “argument invariant” from
+                               // https://golang.org/design/36460-lazy-module-loading.)
                                need := <-needc
                                need[m] = true
                                needc <- need
@@ -1573,7 +1653,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
        }
 
        var mg *ModuleGraph
-       if ld.requirements.depth == eager {
+       if ld.requirements.pruning == unpruned {
                var err error
                mg, err = ld.requirements.Graph(ctx)
                if err != nil {
@@ -1589,11 +1669,11 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
                }
        }
 
-       pkg.mod, pkg.dir, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg)
+       pkg.mod, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg)
        if pkg.dir == "" {
                return
        }
-       if pkg.mod == Target {
+       if MainModules.Contains(pkg.mod.Path) {
                // Go ahead and mark pkg as in "all". This provides the invariant that a
                // package that is *only* imported by other packages in "all" is always
                // marked as such before loading its imports.
@@ -1698,13 +1778,14 @@ func (ld *loader) stdVendor(parentPath, path string) string {
        }
 
        if str.HasPathPrefix(parentPath, "cmd") {
-               if !ld.VendorModulesInGOROOTSrc || Target.Path != "cmd" {
+               if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("cmd") {
                        vendorPath := pathpkg.Join("cmd", "vendor", path)
+
                        if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
                                return vendorPath
                        }
                }
-       } else if !ld.VendorModulesInGOROOTSrc || Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") {
+       } else if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("std") || str.HasPathPrefix(parentPath, "vendor") {
                // If we are outside of the 'std' module, resolve imports from within 'std'
                // to the vendor directory.
                //
@@ -1781,7 +1862,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
                fmt.Fprintln(os.Stderr)
 
                goFlag := ""
-               if ld.GoVersion != modFileGoVersion() {
+               if ld.GoVersion != MainModules.GoVersion() {
                        goFlag = " -go=" + ld.GoVersion
                }
 
@@ -1813,7 +1894,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
 
        mg, err := rs.Graph(ctx)
        if err != nil {
-               ld.errorf("go mod tidy: error loading go %s module graph: %v\n", ld.TidyCompatibleVersion, err)
+               ld.errorf("go: error loading go %s module graph: %v\n", ld.TidyCompatibleVersion, err)
                suggestFixes()
                return
        }
@@ -1847,7 +1928,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
 
                pkg := pkg
                ld.work.Add(func() {
-                       mod, _, err := importFromModules(ctx, pkg.path, rs, mg)
+                       mod, _, _, err := importFromModules(ctx, pkg.path, rs, mg)
                        if mod != pkg.mod {
                                mismatches := <-mismatchMu
                                mismatches[pkg] = mismatch{mod: mod, err: err}
@@ -1900,9 +1981,10 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
                case mismatch.err != nil:
                        // pkg resolved successfully, but errors out using the requirements in rs.
                        //
-                       // This could occur because the import is provided by a single lazy root
-                       // (and is thus unambiguous in lazy mode) and also one or more
-                       // transitive dependencies (and is ambiguous in eager mode).
+                       // This could occur because the import is provided by a single root (and
+                       // is thus unambiguous in a main module with a pruned module graph) and
+                       // also one or more transitive dependencies (and is ambiguous with an
+                       // unpruned graph).
                        //
                        // It could also occur because some transitive dependency upgrades the
                        // module that previously provided the package to a version that no
@@ -1940,18 +2022,18 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
                        }
 
                case pkg.err != nil:
-                       // pkg had an error in lazy mode (presumably suppressed with the -e flag),
-                       // but not in eager mode.
+                       // pkg had an error in with a pruned module graph (presumably suppressed
+                       // with the -e flag), but the error went away using an unpruned graph.
                        //
-                       // This is possible, if, say, the import is unresolved in lazy mode
+                       // This is possible, if, say, the import is unresolved in the pruned graph
                        // (because the "latest" version of each candidate module either is
-                       // unavailable or does not contain the package), but is resolved in
-                       // eager mode due to a newer-than-latest dependency that is normally
-                       // runed out of the module graph.
+                       // unavailable or does not contain the package), but is resolved in the
+                       // unpruned graph due to a newer-than-latest dependency that is normally
+                       // pruned out.
                        //
                        // This could also occur if the source code for the module providing the
-                       // package in lazy mode has a checksum error, but eager mode upgrades
-                       // that module to a version with a correct checksum.
+                       // package in the pruned graph has a checksum error, but the unpruned
+                       // graph upgrades that module to a version with a correct checksum.
                        //
                        // pkg.err should have already been logged elsewhere — along with a
                        // stack trace — so log only the import path and non-error info here.
index 03e02e73b63f659f0ec6e3eff89299f691763c6d..1672d563b794bf844665bff28965c7e4930826c4 100644 (file)
@@ -33,10 +33,13 @@ const (
        // tests outside of the main module.
        narrowAllVersionV = "v1.16"
 
-       // lazyLoadingVersionV is the Go version (plus leading "v") at which a
+       // ExplicitIndirectVersionV is the Go version (plus leading "v") at which a
        // module's go.mod file is expected to list explicit requirements on every
        // module that provides any package transitively imported by that module.
-       lazyLoadingVersionV = "v1.17"
+       //
+       // Other indirect dependencies of such a module can be safely pruned out of
+       // the module graph; see https://golang.org/ref/mod#graph-pruning.
+       ExplicitIndirectVersionV = "v1.17"
 
        // separateIndirectVersionV is the Go version (plus leading "v") at which
        // "// indirect" dependencies are added in a block separate from the direct
@@ -44,23 +47,37 @@ const (
        separateIndirectVersionV = "v1.17"
 )
 
-const (
-       // go117EnableLazyLoading toggles whether lazy-loading code paths should be
-       // active. It will be removed once the lazy loading implementation is stable
-       // and well-tested.
-       go117EnableLazyLoading = true
-
-       // go1117LazyTODO is a constant that exists only until lazy loading is
-       // implemented. Its use indicates a condition that will need to change if the
-       // main module is lazy.
-       go117LazyTODO = false
-)
+// ReadModFile reads and parses the mod file at gomod. ReadModFile properly applies the
+// overlay, locks the file while reading, and applies fix, if applicable.
+func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfile.File, err error) {
+       if gomodActual, ok := fsys.OverlayPath(gomod); ok {
+               // Don't lock go.mod if it's part of the overlay.
+               // On Plan 9, locking requires chmod, and we don't want to modify any file
+               // in the overlay. See #44700.
+               data, err = os.ReadFile(gomodActual)
+       } else {
+               data, err = lockedfile.Read(gomodActual)
+       }
+       if err != nil {
+               return nil, nil, err
+       }
 
-var modFile *modfile.File
+       f, err = modfile.Parse(gomod, data, fix)
+       if err != nil {
+               // Errors returned by modfile.Parse begin with file:line.
+               return nil, nil, fmt.Errorf("errors parsing go.mod:\n%s\n", err)
+       }
+       if f.Module == nil {
+               // No module declaration. Must add module path.
+               return nil, nil, errors.New("no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
+       }
+
+       return data, f, err
+}
 
 // modFileGoVersion returns the (non-empty) Go version at which the requirements
-// in modFile are intepreted, or the latest Go version if modFile is nil.
-func modFileGoVersion() string {
+// in modFile are interpreted, or the latest Go version if modFile is nil.
+func modFileGoVersion(modFile *modfile.File) string {
        if modFile == nil {
                return LatestGoVersion()
        }
@@ -71,9 +88,9 @@ func modFileGoVersion() string {
                // has been erroneously hand-edited.
                //
                // The semantics of the go.mod file are more-or-less the same from Go 1.11
-               // through Go 1.16, changing at 1.17 for lazy loading. So even though a
-               // go.mod file without a 'go' directive is theoretically a Go 1.11 file,
-               // scripts may assume that it ends up as a Go 1.16 module.
+               // through Go 1.16, changing at 1.17 to support module graph pruning.
+               // So even though a go.mod file without a 'go' directive is theoretically a
+               // Go 1.11 file, scripts may assume that it ends up as a Go 1.16 module.
                return "1.16"
        }
        return modFile.Go.Version
@@ -82,39 +99,36 @@ func modFileGoVersion() string {
 // A modFileIndex is an index of data corresponding to a modFile
 // at a specific point in time.
 type modFileIndex struct {
-       data            []byte
-       dataNeedsFix    bool // true if fixVersion applied a change while parsing data
-       module          module.Version
-       goVersionV      string // GoVersion with "v" prefix
-       require         map[module.Version]requireMeta
-       replace         map[module.Version]module.Version
-       highestReplaced map[string]string // highest replaced version of each module path; empty string for wildcard-only replacements
-       exclude         map[module.Version]bool
+       data         []byte
+       dataNeedsFix bool // true if fixVersion applied a change while parsing data
+       module       module.Version
+       goVersionV   string // GoVersion with "v" prefix
+       require      map[module.Version]requireMeta
+       replace      map[module.Version]module.Version
+       exclude      map[module.Version]bool
 }
 
-// index is the index of the go.mod file as of when it was last read or written.
-var index *modFileIndex
-
 type requireMeta struct {
        indirect bool
 }
 
-// A modDepth indicates which dependencies should be loaded for a go.mod file.
-type modDepth uint8
+// A modPruning indicates whether transitive dependencies of Go 1.17 dependencies
+// are pruned out of the module subgraph rooted at a given module.
+// (See https://golang.org/ref/mod#graph-pruning.)
+type modPruning uint8
 
 const (
-       lazy  modDepth = iota // load dependencies only as needed
-       eager                 // load all transitive dependencies eagerly
+       pruned   modPruning = iota // transitive dependencies of modules at go 1.17 and higher are pruned out
+       unpruned                   // no transitive dependencies are pruned out
 )
 
-func modDepthFromGoVersion(goVersion string) modDepth {
-       if !go117EnableLazyLoading {
-               return eager
-       }
-       if semver.Compare("v"+goVersion, lazyLoadingVersionV) < 0 {
-               return eager
+func pruningForGoVersion(goVersion string) modPruning {
+       if semver.Compare("v"+goVersion, ExplicitIndirectVersionV) < 0 {
+               // The go.mod file does not duplicate relevant information about transitive
+               // dependencies, so they cannot be pruned out.
+               return unpruned
        }
-       return lazy
+       return pruned
 }
 
 // CheckAllowed returns an error equivalent to ErrDisallowed if m is excluded by
@@ -137,8 +151,10 @@ var ErrDisallowed = errors.New("disallowed module version")
 // CheckExclusions returns an error equivalent to ErrDisallowed if module m is
 // excluded by the main module's go.mod file.
 func CheckExclusions(ctx context.Context, m module.Version) error {
-       if index != nil && index.exclude[m] {
-               return module.VersionError(m, errExcluded)
+       for _, mainModule := range MainModules.Versions() {
+               if index := MainModules.Index(mainModule); index != nil && index.exclude[m] {
+                       return module.VersionError(m, errExcluded)
+               }
        }
        return nil
 }
@@ -306,23 +322,74 @@ func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string
        return summary.deprecated, nil
 }
 
-// Replacement returns the replacement for mod, if any, from go.mod.
-// If there is no replacement for mod, Replacement returns
-// a module.Version with Path == "".
+func replacement(mod module.Version, replace map[module.Version]module.Version) (fromVersion string, to module.Version, ok bool) {
+       if r, ok := replace[mod]; ok {
+               return mod.Version, r, true
+       }
+       if r, ok := replace[module.Version{Path: mod.Path}]; ok {
+               return "", r, true
+       }
+       return "", module.Version{}, false
+}
+
+// Replacement returns the replacement for mod, if any. If the path in the
+// module.Version is relative it's relative to the single main module outside
+// workspace mode, or the workspace's directory in workspace mode.
 func Replacement(mod module.Version) module.Version {
-       if index != nil {
-               if r, ok := index.replace[mod]; ok {
-                       return r
-               }
-               if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
-                       return r
+       foundFrom, found, foundModRoot := "", module.Version{}, ""
+       if MainModules == nil {
+               return module.Version{}
+       }
+       if _, r, ok := replacement(mod, MainModules.WorkFileReplaceMap()); ok {
+               return r
+       }
+       for _, v := range MainModules.Versions() {
+               if index := MainModules.Index(v); index != nil {
+                       if from, r, ok := replacement(mod, index.replace); ok {
+                               modRoot := MainModules.ModRoot(v)
+                               if foundModRoot != "" && foundFrom != from && found != r {
+                                       base.Errorf("conflicting replacements found for %v in workspace modules defined by %v and %v",
+                                               mod, modFilePath(foundModRoot), modFilePath(modRoot))
+                                       return canonicalizeReplacePath(found, foundModRoot)
+                               }
+                               found, foundModRoot = r, modRoot
+                       }
                }
        }
-       return module.Version{}
+       return canonicalizeReplacePath(found, foundModRoot)
+}
+
+func replaceRelativeTo() string {
+       if workFilePath := WorkFilePath(); workFilePath != "" {
+               return filepath.Dir(workFilePath)
+       }
+       return MainModules.ModRoot(MainModules.mustGetSingleMainModule())
+}
+
+// canonicalizeReplacePath ensures that relative, on-disk, replaced module paths
+// are relative to the workspace directory (in workspace mode) or to the module's
+// directory (in module mode, as they already are).
+func canonicalizeReplacePath(r module.Version, modRoot string) module.Version {
+       if filepath.IsAbs(r.Path) || r.Version != "" {
+               return r
+       }
+       workFilePath := WorkFilePath()
+       if workFilePath == "" {
+               return r
+       }
+       abs := filepath.Join(modRoot, r.Path)
+       if rel, err := filepath.Rel(workFilePath, abs); err == nil {
+               return module.Version{Path: rel, Version: r.Version}
+       }
+       // We couldn't make the version's path relative to the workspace's path,
+       // so just return the absolute path. It's the best we can do.
+       return module.Version{Path: abs, Version: r.Version}
 }
 
 // resolveReplacement returns the module actually used to load the source code
 // for m: either m itself, or the replacement for m (iff m is replaced).
+// It also returns the modroot of the module providing the replacement if
+// one was found.
 func resolveReplacement(m module.Version) module.Version {
        if r := Replacement(m); r.Path != "" {
                return r
@@ -330,10 +397,21 @@ func resolveReplacement(m module.Version) module.Version {
        return m
 }
 
+func toReplaceMap(replacements []*modfile.Replace) map[module.Version]module.Version {
+       replaceMap := make(map[module.Version]module.Version, len(replacements))
+       for _, r := range replacements {
+               if prev, dup := replaceMap[r.Old]; dup && prev != r.New {
+                       base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New)
+               }
+               replaceMap[r.Old] = r.New
+       }
+       return replaceMap
+}
+
 // indexModFile rebuilds the index of modFile.
 // If modFile has been changed since it was first read,
 // modFile.Cleanup must be called before indexModFile.
-func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex {
+func indexModFile(data []byte, modFile *modfile.File, mod module.Version, needsFix bool) *modFileIndex {
        i := new(modFileIndex)
        i.data = data
        i.dataNeedsFix = needsFix
@@ -345,12 +423,12 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
 
        i.goVersionV = ""
        if modFile.Go == nil {
-               rawGoVersion.Store(Target, "")
+               rawGoVersion.Store(mod, "")
        } else {
                // We're going to use the semver package to compare Go versions, so go ahead
                // and add the "v" prefix it expects once instead of every time.
                i.goVersionV = "v" + modFile.Go.Version
-               rawGoVersion.Store(Target, modFile.Go.Version)
+               rawGoVersion.Store(mod, modFile.Go.Version)
        }
 
        i.require = make(map[module.Version]requireMeta, len(modFile.Require))
@@ -358,21 +436,7 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
                i.require[r.Mod] = requireMeta{indirect: r.Indirect}
        }
 
-       i.replace = make(map[module.Version]module.Version, len(modFile.Replace))
-       for _, r := range modFile.Replace {
-               if prev, dup := i.replace[r.Old]; dup && prev != r.New {
-                       base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New)
-               }
-               i.replace[r.Old] = r.New
-       }
-
-       i.highestReplaced = make(map[string]string)
-       for _, r := range modFile.Replace {
-               v, ok := i.highestReplaced[r.Old.Path]
-               if !ok || semver.Compare(r.Old.Version, v) > 0 {
-                       i.highestReplaced[r.Old.Path] = r.Old.Version
-               }
-       }
+       i.replace = toReplaceMap(modFile.Replace)
 
        i.exclude = make(map[module.Version]bool, len(modFile.Exclude))
        for _, x := range modFile.Exclude {
@@ -465,7 +529,7 @@ var rawGoVersion sync.Map // map[module.Version]string
 type modFileSummary struct {
        module     module.Version
        goVersion  string
-       depth      modDepth
+       pruning    modPruning
        require    []module.Version
        retract    []retraction
        deprecated string
@@ -490,8 +554,8 @@ type retraction struct {
 //
 // The caller must not modify the returned summary.
 func goModSummary(m module.Version) (*modFileSummary, error) {
-       if m == Target {
-               panic("internal error: goModSummary called on the Target module")
+       if m.Version == "" && MainModules.Contains(m.Path) {
+               panic("internal error: goModSummary called on a main module")
        }
 
        if cfg.BuildMod == "vendor" {
@@ -506,7 +570,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
 
                // For every module other than the target,
                // return the full list of modules from modules.txt.
-               readVendorList()
+               readVendorList(MainModules.mustGetSingleMainModule())
 
                // We don't know what versions the vendored module actually relies on,
                // so assume that it requires everything.
@@ -515,7 +579,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
        }
 
        actual := resolveReplacement(m)
-       if HasModRoot() && cfg.BuildMod == "readonly" && actual.Version != "" {
+       if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
                key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
                if !modfetch.HaveSum(key) {
                        suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
@@ -553,27 +617,29 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
                }
        }
 
-       if index != nil && len(index.exclude) > 0 {
-               // Drop any requirements on excluded versions.
-               // Don't modify the cached summary though, since we might need the raw
-               // summary separately.
-               haveExcludedReqs := false
-               for _, r := range summary.require {
-                       if index.exclude[r] {
-                               haveExcludedReqs = true
-                               break
-                       }
-               }
-               if haveExcludedReqs {
-                       s := new(modFileSummary)
-                       *s = *summary
-                       s.require = make([]module.Version, 0, len(summary.require))
+       for _, mainModule := range MainModules.Versions() {
+               if index := MainModules.Index(mainModule); index != nil && len(index.exclude) > 0 {
+                       // Drop any requirements on excluded versions.
+                       // Don't modify the cached summary though, since we might need the raw
+                       // summary separately.
+                       haveExcludedReqs := false
                        for _, r := range summary.require {
-                               if !index.exclude[r] {
-                                       s.require = append(s.require, r)
+                               if index.exclude[r] {
+                                       haveExcludedReqs = true
+                                       break
                                }
                        }
-                       summary = s
+                       if haveExcludedReqs {
+                               s := new(modFileSummary)
+                               *s = *summary
+                               s.require = make([]module.Version, 0, len(summary.require))
+                               for _, r := range summary.require {
+                                       if !index.exclude[r] {
+                                               s.require = append(s.require, r)
+                                       }
+                               }
+                               summary = s
+                       }
                }
        }
        return summary, nil
@@ -584,16 +650,20 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
 // its dependencies.
 //
 // rawGoModSummary cannot be used on the Target module.
+
 func rawGoModSummary(m module.Version) (*modFileSummary, error) {
-       if m == Target {
+       if m.Path == "" && MainModules.Contains(m.Path) {
                panic("internal error: rawGoModSummary called on the Target module")
        }
 
+       type key struct {
+               m module.Version
+       }
        type cached struct {
                summary *modFileSummary
                err     error
        }
-       c := rawGoModSummaryCache.Do(m, func() interface{} {
+       c := rawGoModSummaryCache.Do(key{m}, func() interface{} {
                summary := new(modFileSummary)
                name, data, err := rawGoModData(m)
                if err != nil {
@@ -610,9 +680,9 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
                if f.Go != nil && f.Go.Version != "" {
                        rawGoVersion.LoadOrStore(m, f.Go.Version)
                        summary.goVersion = f.Go.Version
-                       summary.depth = modDepthFromGoVersion(f.Go.Version)
+                       summary.pruning = pruningForGoVersion(f.Go.Version)
                } else {
-                       summary.depth = eager
+                       summary.pruning = unpruned
                }
                if len(f.Require) > 0 {
                        summary.require = make([]module.Version, 0, len(f.Require))
@@ -650,7 +720,7 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) {
                // m is a replacement module with only a file path.
                dir := m.Path
                if !filepath.IsAbs(dir) {
-                       dir = filepath.Join(ModRoot(), dir)
+                       dir = filepath.Join(replaceRelativeTo(), dir)
                }
                name = filepath.Join(dir, "go.mod")
                if gomodActual, ok := fsys.OverlayPath(name); ok {
@@ -718,3 +788,15 @@ func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (la
 }
 
 var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersionIgnoringRetractions result
+
+// ToDirectoryPath adds a prefix if necessary so that path in unambiguously
+// an absolute path or a relative path starting with a '.' or '..'
+// path component.
+func ToDirectoryPath(path string) string {
+       if modfile.IsDirectoryPath(path) {
+               return path
+       }
+       // The path is not a relative path or an absolute path, so make it relative
+       // to the current directory.
+       return "./" + filepath.ToSlash(filepath.Clean(path))
+}
index 87619b4ace68e28d40621054ab4d437a4b97cf83..40224d534b1b129c3990ef9155aa9400c028c22d 100644 (file)
@@ -42,7 +42,7 @@ type mvsReqs struct {
 }
 
 func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
-       if mod == Target {
+       if MainModules.Contains(mod.Path) {
                // Use the build list as it existed when r was constructed, not the current
                // global build list.
                return r.roots, nil
@@ -113,7 +113,7 @@ func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string,
 func previousVersion(m module.Version) (module.Version, error) {
        // TODO(golang.org/issue/38714): thread tracing context through MVS.
 
-       if m == Target {
+       if MainModules.Contains(m.Path) {
                return module.Version{Path: m.Path, Version: "none"}, nil
        }
 
index d4c906a873972ac1c8b44c7adb42c1b9ccb1ced3..1eb484de9d0b8796e4bbe9a6ecf37340399b1dfd 100644 (file)
@@ -22,7 +22,7 @@ import (
        "cmd/go/internal/modfetch"
        "cmd/go/internal/search"
        "cmd/go/internal/trace"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/module"
        "golang.org/x/mod/semver"
@@ -110,11 +110,12 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
                allowed = func(context.Context, module.Version) error { return nil }
        }
 
-       if path == Target.Path && (query == "upgrade" || query == "patch") {
-               if err := allowed(ctx, Target); err != nil {
+       if MainModules.Contains(path) && (query == "upgrade" || query == "patch") {
+               m := module.Version{Path: path}
+               if err := allowed(ctx, m); err != nil {
                        return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
                }
-               return &modfetch.RevInfo{Version: Target.Version}, nil
+               return &modfetch.RevInfo{Version: m.Version}, nil
        }
 
        if path == "std" || path == "cmd" {
@@ -512,9 +513,10 @@ func QueryPackages(ctx context.Context, pattern, query string, current func(stri
        pkgMods, modOnly, err := QueryPattern(ctx, pattern, query, current, allowed)
 
        if len(pkgMods) == 0 && err == nil {
+               replacement := Replacement(modOnly.Mod)
                return nil, &PackageNotInModuleError{
                        Mod:         modOnly.Mod,
-                       Replacement: Replacement(modOnly.Mod),
+                       Replacement: replacement,
                        Query:       query,
                        Pattern:     pattern,
                }
@@ -551,7 +553,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
                return m.Errs[0]
        }
 
-       var match func(mod module.Version, root string, isLocal bool) *search.Match
+       var match func(mod module.Version, roots []string, isLocal bool) *search.Match
        matchPattern := search.MatchPattern(pattern)
 
        if i := strings.Index(pattern, "..."); i >= 0 {
@@ -559,30 +561,32 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
                if base == "." {
                        return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query}
                }
-               match = func(mod module.Version, root string, isLocal bool) *search.Match {
+               match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
                        m := search.NewMatch(pattern)
                        matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
                        return m
                }
        } else {
-               match = func(mod module.Version, root string, isLocal bool) *search.Match {
+               match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
                        m := search.NewMatch(pattern)
                        prefix := mod.Path
-                       if mod == Target {
-                               prefix = targetPrefix
+                       if MainModules.Contains(mod.Path) {
+                               prefix = MainModules.PathPrefix(module.Version{Path: mod.Path})
                        }
-                       if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
-                               m.AddError(err)
-                       } else if ok {
-                               m.Pkgs = []string{pattern}
+                       for _, root := range roots {
+                               if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
+                                       m.AddError(err)
+                               } else if ok {
+                                       m.Pkgs = []string{pattern}
+                               }
                        }
                        return m
                }
        }
 
-       var queryMatchesMainModule bool
-       if HasModRoot() {
-               m := match(Target, modRoot, true)
+       var mainModuleMatches []module.Version
+       for _, mainModule := range MainModules.Versions() {
+               m := match(mainModule, modRoots, true)
                if len(m.Pkgs) > 0 {
                        if query != "upgrade" && query != "patch" {
                                return nil, nil, &QueryMatchesPackagesInMainModuleError{
@@ -591,12 +595,12 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
                                        Packages: m.Pkgs,
                                }
                        }
-                       if err := allowed(ctx, Target); err != nil {
-                               return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, Target.Path, err)
+                       if err := allowed(ctx, mainModule); err != nil {
+                               return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, mainModule.Path, err)
                        }
                        return []QueryResult{{
-                               Mod:      Target,
-                               Rev:      &modfetch.RevInfo{Version: Target.Version},
+                               Mod:      mainModule,
+                               Rev:      &modfetch.RevInfo{Version: mainModule.Version},
                                Packages: m.Pkgs,
                        }}, nil, nil
                }
@@ -604,15 +608,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
                        return nil, nil, err
                }
 
-               if matchPattern(Target.Path) {
-                       queryMatchesMainModule = true
+               var matchesMainModule bool
+               if matchPattern(mainModule.Path) {
+                       mainModuleMatches = append(mainModuleMatches, mainModule)
+                       matchesMainModule = true
                }
 
-               if (query == "upgrade" || query == "patch") && queryMatchesMainModule {
-                       if err := allowed(ctx, Target); err == nil {
+               if (query == "upgrade" || query == "patch") && matchesMainModule {
+                       if err := allowed(ctx, mainModule); err == nil {
                                modOnly = &QueryResult{
-                                       Mod: Target,
-                                       Rev: &modfetch.RevInfo{Version: Target.Version},
+                                       Mod: mainModule,
+                                       Rev: &modfetch.RevInfo{Version: mainModule.Version},
                                }
                        }
                }
@@ -625,16 +631,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
        if len(candidateModules) == 0 {
                if modOnly != nil {
                        return nil, modOnly, nil
-               } else if queryMatchesMainModule {
-                       return nil, nil, &QueryMatchesMainModuleError{
-                               Pattern: pattern,
-                               Query:   query,
+               } else if len(mainModuleMatches) != 0 {
+                       return nil, nil, &QueryMatchesMainModulesError{
+                               MainModules: mainModuleMatches,
+                               Pattern:     pattern,
+                               Query:       query,
                        }
                } else {
                        return nil, nil, &PackageNotInModuleError{
-                               Mod:     Target,
-                               Query:   query,
-                               Pattern: pattern,
+                               MainModules: mainModuleMatches,
+                               Query:       query,
+                               Pattern:     pattern,
                        }
                }
        }
@@ -656,15 +663,16 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
                        if err != nil {
                                return r, err
                        }
-                       m := match(r.Mod, root, isLocal)
+                       m := match(r.Mod, []string{root}, isLocal)
                        r.Packages = m.Pkgs
                        if len(r.Packages) == 0 && !matchPattern(path) {
                                if err := firstError(m); err != nil {
                                        return r, err
                                }
+                               replacement := Replacement(r.Mod)
                                return r, &PackageNotInModuleError{
                                        Mod:         r.Mod,
-                                       Replacement: Replacement(r.Mod),
+                                       Replacement: replacement,
                                        Query:       query,
                                        Pattern:     pattern,
                                }
@@ -684,8 +692,8 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
                return err
        })
 
-       if queryMatchesMainModule && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
-               return nil, nil, &QueryMatchesMainModuleError{
+       if len(mainModuleMatches) > 0 && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
+               return nil, nil, &QueryMatchesMainModulesError{
                        Pattern: pattern,
                        Query:   query,
                }
@@ -701,8 +709,13 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
 func modulePrefixesExcludingTarget(path string) []string {
        prefixes := make([]string, 0, strings.Count(path, "/")+1)
 
+       mainModulePrefixes := make(map[string]bool)
+       for _, m := range MainModules.Versions() {
+               mainModulePrefixes[m.Path] = true
+       }
+
        for {
-               if path != targetPrefix {
+               if !mainModulePrefixes[path] {
                        if _, _, ok := module.SplitPathVersion(path); ok {
                                prefixes = append(prefixes, path)
                        }
@@ -759,7 +772,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
                case *PackageNotInModuleError:
                        // Given the option, prefer to attribute “package not in module”
                        // to modules other than the main one.
-                       if noPackage == nil || noPackage.Mod == Target {
+                       if noPackage == nil || MainModules.Contains(noPackage.Mod.Path) {
                                noPackage = rErr
                        }
                case *NoMatchingVersionError:
@@ -878,6 +891,7 @@ func (e *WildcardInFirstElementError) Error() string {
 // code for the versions it knows about, and thus did not have the opportunity
 // to return a non-400 status code to suppress fallback.
 type PackageNotInModuleError struct {
+       MainModules []module.Version
        Mod         module.Version
        Replacement module.Version
        Query       string
@@ -885,11 +899,15 @@ type PackageNotInModuleError struct {
 }
 
 func (e *PackageNotInModuleError) Error() string {
-       if e.Mod == Target {
+       if len(e.MainModules) > 0 {
+               prefix := "workspace modules do"
+               if len(e.MainModules) == 1 {
+                       prefix = fmt.Sprintf("main module (%s) does", e.MainModules[0])
+               }
                if strings.Contains(e.Pattern, "...") {
-                       return fmt.Sprintf("main module (%s) does not contain packages matching %s", Target.Path, e.Pattern)
+                       return fmt.Sprintf("%s not contain packages matching %s", prefix, e.Pattern)
                }
-               return fmt.Sprintf("main module (%s) does not contain package %s", Target.Path, e.Pattern)
+               return fmt.Sprintf("%s not contain package %s", prefix, e.Pattern)
        }
 
        found := ""
@@ -978,14 +996,13 @@ func lookupRepo(proxy, path string) (repo versionRepo, err error) {
                repo = emptyRepo{path: path, err: err}
        }
 
-       if index == nil {
-               return repo, err
-       }
-       if _, ok := index.highestReplaced[path]; !ok {
+       if MainModules == nil {
                return repo, err
+       } else if _, ok := MainModules.HighestReplaced()[path]; ok {
+               return &replacementRepo{repo: repo}, nil
        }
 
-       return &replacementRepo{repo: repo}, nil
+       return repo, err
 }
 
 // An emptyRepo is a versionRepo that contains no versions.
@@ -1024,11 +1041,13 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
        }
 
        versions := repoVersions
-       if index != nil && len(index.replace) > 0 {
-               path := rr.ModulePath()
-               for m, _ := range index.replace {
-                       if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) {
-                               versions = append(versions, m.Version)
+       for _, mm := range MainModules.Versions() {
+               if index := MainModules.Index(mm); index != nil && len(index.replace) > 0 {
+                       path := rr.ModulePath()
+                       for m, _ := range index.replace {
+                               if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) {
+                                       versions = append(versions, m.Version)
+                               }
                        }
                }
        }
@@ -1046,7 +1065,16 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
 
 func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
        info, err := rr.repo.Stat(rev)
-       if err == nil || index == nil || len(index.replace) == 0 {
+       if err == nil {
+               return info, err
+       }
+       var hasReplacements bool
+       for _, v := range MainModules.Versions() {
+               if index := MainModules.Index(v); index != nil && len(index.replace) > 0 {
+                       hasReplacements = true
+               }
+       }
+       if !hasReplacements {
                return info, err
        }
 
@@ -1073,26 +1101,24 @@ func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
 
 func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) {
        info, err := rr.repo.Latest()
+       path := rr.ModulePath()
 
-       if index != nil {
-               path := rr.ModulePath()
-               if v, ok := index.highestReplaced[path]; ok {
-                       if v == "" {
-                               // The only replacement is a wildcard that doesn't specify a version, so
-                               // synthesize a pseudo-version with an appropriate major version and a
-                               // timestamp below any real timestamp. That way, if the main module is
-                               // used from within some other module, the user will be able to upgrade
-                               // the requirement to any real version they choose.
-                               if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 {
-                                       v = module.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
-                               } else {
-                                       v = module.PseudoVersion("v0", "", time.Time{}, "000000000000")
-                               }
+       if v, ok := MainModules.HighestReplaced()[path]; ok {
+               if v == "" {
+                       // The only replacement is a wildcard that doesn't specify a version, so
+                       // synthesize a pseudo-version with an appropriate major version and a
+                       // timestamp below any real timestamp. That way, if the main module is
+                       // used from within some other module, the user will be able to upgrade
+                       // the requirement to any real version they choose.
+                       if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 {
+                               v = module.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
+                       } else {
+                               v = module.PseudoVersion("v0", "", time.Time{}, "000000000000")
                        }
+               }
 
-                       if err != nil || semver.Compare(v, info.Version) > 0 {
-                               return rr.replacementStat(v)
-                       }
+               if err != nil || semver.Compare(v, info.Version) > 0 {
+                       return rr.replacementStat(v)
                }
        }
 
@@ -1108,20 +1134,46 @@ func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error)
        return rev, nil
 }
 
-// A QueryMatchesMainModuleError indicates that a query requests
+// A QueryMatchesMainModulesError indicates that a query requests
 // a version of the main module that cannot be satisfied.
 // (The main module's version cannot be changed.)
-type QueryMatchesMainModuleError struct {
-       Pattern string
-       Query   string
+type QueryMatchesMainModulesError struct {
+       MainModules []module.Version
+       Pattern     string
+       Query       string
 }
 
-func (e *QueryMatchesMainModuleError) Error() string {
-       if e.Pattern == Target.Path {
+func (e *QueryMatchesMainModulesError) Error() string {
+       if MainModules.Contains(e.Pattern) {
                return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern)
        }
 
-       return fmt.Sprintf("can't request version %q of pattern %q that includes the main module (%s)", e.Query, e.Pattern, Target.Path)
+       plural := ""
+       mainModulePaths := make([]string, len(e.MainModules))
+       for i := range e.MainModules {
+               mainModulePaths[i] = e.MainModules[i].Path
+       }
+       if len(e.MainModules) > 1 {
+               plural = "s"
+       }
+       return fmt.Sprintf("can't request version %q of pattern %q that includes the main module%s (%s)", e.Query, e.Pattern, plural, strings.Join(mainModulePaths, ", "))
+}
+
+// A QueryUpgradesAllError indicates that a query requests
+// an upgrade on the all pattern.
+// (The main module's version cannot be changed.)
+type QueryUpgradesAllError struct {
+       MainModules []module.Version
+       Query       string
+}
+
+func (e *QueryUpgradesAllError) Error() string {
+       var plural string = ""
+       if len(e.MainModules) != 1 {
+               plural = "s"
+       }
+
+       return fmt.Sprintf("can't request version %q of pattern \"all\" that includes the main module%s", e.Query, plural)
 }
 
 // A QueryMatchesPackagesInMainModuleError indicates that a query cannot be
index 658fc6f55a9c9bb127e600f3d5ef51ffeb8c9773..799c48e50a8caca851b197c1ee584411bf2ad55c 100644 (file)
@@ -131,9 +131,10 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
        }
 
        if cfg.BuildMod == "vendor" {
-               if HasModRoot() {
-                       walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
-                       walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
+               mod := MainModules.mustGetSingleMainModule()
+               if modRoot := MainModules.ModRoot(mod); modRoot != "" {
+                       walkPkgs(modRoot, MainModules.PathPrefix(mod), pruneGoMod|pruneVendor)
+                       walkPkgs(filepath.Join(modRoot, "vendor"), "", pruneVendor)
                }
                return
        }
@@ -147,12 +148,12 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
                        root, modPrefix string
                        isLocal         bool
                )
-               if mod == Target {
-                       if !HasModRoot() {
+               if MainModules.Contains(mod.Path) {
+                       if MainModules.ModRoot(mod) == "" {
                                continue // If there is no main module, we can't search in it.
                        }
-                       root = ModRoot()
-                       modPrefix = targetPrefix
+                       root = MainModules.ModRoot(mod)
+                       modPrefix = MainModules.PathPrefix(mod)
                        isLocal = true
                } else {
                        var err error
index 368f893198492984b0cc1efaffe988d5f172c5d5..ff7c124af58a28c6da3ddfe48d144f935a1afdfb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (js && wasm) || plan9
-// +build js,wasm plan9
 
 // On plan9, per http://9p.io/magic/man2html/2/access: “Since file permissions
 // are checked by the server and group information is not known to the client,
index e079d7399026feb44091d94973cfe0eeb6da9f05..8a3653ba80b019ae0394540b2291cffe21699850 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package modload
 
index 825e60b27af89406122aa400b92df706aba508d5..f29a99165e53001faec5e8553e670a82803522dc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package modload
 
index 80713b0812eacce928f0a39b26eba024e655a56b..a735cad90561bbc6fab4a02d0f3938fab73ee6d3 100644 (file)
@@ -15,6 +15,7 @@ import (
 
        "cmd/go/internal/base"
 
+       "golang.org/x/mod/modfile"
        "golang.org/x/mod/module"
        "golang.org/x/mod/semver"
 )
@@ -35,13 +36,13 @@ type vendorMetadata struct {
 }
 
 // readVendorList reads the list of vendored modules from vendor/modules.txt.
-func readVendorList() {
+func readVendorList(mainModule module.Version) {
        vendorOnce.Do(func() {
                vendorList = nil
                vendorPkgModule = make(map[string]module.Version)
                vendorVersion = make(map[string]string)
                vendorMeta = make(map[module.Version]vendorMetadata)
-               data, err := os.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
+               data, err := os.ReadFile(filepath.Join(MainModules.ModRoot(mainModule), "vendor/modules.txt"))
                if err != nil {
                        if !errors.Is(err, fs.ErrNotExist) {
                                base.Fatalf("go: %s", err)
@@ -134,8 +135,8 @@ func readVendorList() {
 // checkVendorConsistency verifies that the vendor/modules.txt file matches (if
 // go 1.14) or at least does not contradict (go 1.13 or earlier) the
 // requirements and replacements listed in the main module's go.mod file.
-func checkVendorConsistency() {
-       readVendorList()
+func checkVendorConsistency(index *modFileIndex, modFile *modfile.File) {
+       readVendorList(MainModules.mustGetSingleMainModule())
 
        pre114 := false
        if semver.Compare(index.goVersionV, "v1.14") < 0 {
@@ -219,6 +220,7 @@ func checkVendorConsistency() {
        }
 
        if vendErrors.Len() > 0 {
+               modRoot := MainModules.ModRoot(MainModules.mustGetSingleMainModule())
                base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors)
        }
 }
index 6969f90f2e681abf23495ab7aab8ba4432453d17..566fa4b6b390331bf92a28961e159919053a8be2 100644 (file)
@@ -8,6 +8,7 @@ package mvs
 
 import (
        "fmt"
+       "reflect"
        "sort"
        "sync"
 
@@ -85,11 +86,11 @@ type DowngradeReqs interface {
 // 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)
+func BuildList(targets []module.Version, reqs Reqs) ([]module.Version, error) {
+       return buildList(targets, reqs, nil)
 }
 
-func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
+func buildList(targets []module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
        cmp := func(v1, v2 string) int {
                if reqs.Max(v1, v2) != v1 {
                        return -1
@@ -102,7 +103,7 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
 
        var (
                mu       sync.Mutex
-               g        = NewGraph(cmp, []module.Version{target})
+               g        = NewGraph(cmp, targets)
                upgrades = map[module.Version]module.Version{}
                errs     = map[module.Version]error{} // (non-nil errors only)
        )
@@ -110,7 +111,9 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
        // Explore work graph in parallel in case reqs.Required
        // does high-latency network operations.
        var work par.Work
-       work.Add(target)
+       for _, target := range targets {
+               work.Add(target)
+       }
        work.Do(10, func(item interface{}) {
                m := item.(module.Version)
 
@@ -168,12 +171,12 @@ 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.
        list := g.BuildList()
-       if v := list[0]; v != target {
+       if vs := list[:len(targets)]; !reflect.DeepEqual(vs, targets) {
                // 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))
+               panic(fmt.Sprintf("mistake: chose versions %+v instead of targets %+v", vs, targets))
        }
        return list, nil
 }
@@ -181,8 +184,8 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
 // Req returns the minimal requirement list for the target module,
 // with the constraint that all module paths listed in base must
 // appear in the returned list.
-func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, error) {
-       list, err := BuildList(target, reqs)
+func Req(mainModule module.Version, base []string, reqs Reqs) ([]module.Version, error) {
+       list, err := BuildList([]module.Version{mainModule}, reqs)
        if err != nil {
                return nil, err
        }
@@ -194,7 +197,8 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
        // Compute postorder, cache requirements.
        var postorder []module.Version
        reqCache := map[module.Version][]module.Version{}
-       reqCache[target] = nil
+       reqCache[mainModule] = nil
+
        var walk func(module.Version) error
        walk = func(m module.Version) error {
                _, ok := reqCache[m]
@@ -273,7 +277,7 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
 // UpgradeAll returns a build list for the target module
 // in which every module is upgraded to its latest version.
 func UpgradeAll(target module.Version, reqs UpgradeReqs) ([]module.Version, error) {
-       return buildList(target, reqs, func(m module.Version) (module.Version, error) {
+       return buildList([]module.Version{target}, reqs, func(m module.Version) (module.Version, error) {
                if m.Path == target.Path {
                        return target, nil
                }
@@ -308,7 +312,7 @@ func Upgrade(target module.Version, reqs UpgradeReqs, upgrade ...module.Version)
                }
        }
 
-       return buildList(target, &override{target, list, reqs}, func(m module.Version) (module.Version, error) {
+       return buildList([]module.Version{target}, &override{target, list, reqs}, func(m module.Version) (module.Version, error) {
                if v, ok := upgradeTo[m.Path]; ok {
                        return module.Version{Path: m.Path, Version: v}, nil
                }
@@ -331,7 +335,7 @@ func Downgrade(target module.Version, reqs DowngradeReqs, downgrade ...module.Ve
        //
        // In order to generate those new requirements, we need to identify versions
        // for every module in the build list — not just reqs.Required(target).
-       list, err := BuildList(target, reqs)
+       list, err := BuildList([]module.Version{target}, reqs)
        if err != nil {
                return nil, err
        }
@@ -446,7 +450,7 @@ List:
        // list with the actual versions of the downgraded modules as selected by MVS,
        // instead of our initial downgrades.
        // (See the downhiddenartifact and downhiddencross test cases).
-       actual, err := BuildList(target, &override{
+       actual, err := BuildList([]module.Version{target}, &override{
                target: target,
                list:   downgraded,
                Reqs:   reqs,
@@ -466,7 +470,7 @@ List:
                }
        }
 
-       return BuildList(target, &override{
+       return BuildList([]module.Version{target}, &override{
                target: target,
                list:   downgraded,
                Reqs:   reqs,
index 598ed666889517a112c01e78d5b6fcb95101fcd2..26d004fee2856ebb2a19cf27033d753b01e11c8d 100644 (file)
@@ -507,7 +507,7 @@ func Test(t *testing.T) {
                                t.Fatalf("build takes one argument: %q", line)
                        }
                        fns = append(fns, func(t *testing.T) {
-                               list, err := BuildList(m(kf[1]), reqs)
+                               list, err := BuildList([]module.Version{m(kf[1])}, reqs)
                                checkList(t, key, list, err, val)
                        })
                        continue
index d5c241857b476c47cfed2c9bb1c5b1f739426ee3..c56e36ca62412aae46a98f41f5a2d9ad5191fe8e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows || darwin
-// +build windows darwin
 
 package robustio
 
index 3a20cac6cf88aef9882a484439c2298489a80e2f..da9a46e4face362eb5d95872bccc2ecd4a7a5424 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !darwin
-// +build !windows,!darwin
 
 package robustio
 
index 9e9e49ec898e1b133b96aba1ea895a560bb200ac..03895d27ebf2d68419ca0200c3ae79c139dcfa01 100644 (file)
@@ -19,7 +19,7 @@ import (
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
        "cmd/go/internal/work"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 var CmdRun = &base.Command{
@@ -65,6 +65,7 @@ func init() {
        CmdRun.Run = runRun // break init loop
 
        work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
+       base.AddWorkfileFlag(&CmdRun.Flag)
        CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
 }
 
@@ -73,6 +74,8 @@ func printStderr(args ...interface{}) (int, error) {
 }
 
 func runRun(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
+
        if shouldUseOutsideModuleMode(args) {
                // Set global module flags for 'go run cmd@version'.
                // This must be done before modload.Init, but we need to call work.BuildInit
@@ -100,7 +103,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
                        if strings.HasSuffix(file, "_test.go") {
                                // GoFilesPackage is going to assign this to TestGoFiles.
                                // Reject since it won't be part of the build.
-                               base.Fatalf("go run: cannot run *_test.go files (%s)", file)
+                               base.Fatalf("go: cannot run *_test.go files (%s)", file)
                        }
                }
                p = load.GoFilesPackage(ctx, pkgOpts, files)
@@ -111,26 +114,26 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
                        var err error
                        pkgs, err = load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args[:1])
                        if err != nil {
-                               base.Fatalf("go run: %v", err)
+                               base.Fatalf("go: %v", err)
                        }
                } else {
                        pkgs = load.PackagesAndErrors(ctx, pkgOpts, args[:1])
                }
 
                if len(pkgs) == 0 {
-                       base.Fatalf("go run: no packages loaded from %s", arg)
+                       base.Fatalf("go: no packages loaded from %s", arg)
                }
                if len(pkgs) > 1 {
                        var names []string
                        for _, p := range pkgs {
                                names = append(names, p.ImportPath)
                        }
-                       base.Fatalf("go run: pattern %s matches multiple packages:\n\t%s", arg, strings.Join(names, "\n\t"))
+                       base.Fatalf("go: pattern %s matches multiple packages:\n\t%s", arg, strings.Join(names, "\n\t"))
                }
                p = pkgs[0]
                i++
        } else {
-               base.Fatalf("go run: no go files listed")
+               base.Fatalf("go: no go files listed")
        }
        cmdArgs := args[i:]
        load.CheckPackageErrors([]*load.Package{p})
@@ -151,7 +154,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
                        if !cfg.BuildContext.CgoEnabled {
                                hint = " (cgo is disabled)"
                        }
-                       base.Fatalf("go run: no suitable source files%s", hint)
+                       base.Fatalf("go: no suitable source files%s", hint)
                }
                p.Internal.ExeName = src[:len(src)-len(".go")]
        } else {
index a0c806a259329c27c2f45739e1250550bec04f06..ebd4990a68413b2b03476f0305fff05924db2093 100644 (file)
@@ -202,12 +202,6 @@ func (m *Match) MatchPackages() {
        }
 }
 
-var modRoot string
-
-func SetModRoot(dir string) {
-       modRoot = dir
-}
-
 // MatchDirs sets m.Dirs to a non-nil slice containing all directories that
 // potentially match a local pattern. The pattern must begin with an absolute
 // path, or "./", or "../". On Windows, the pattern may use slash or backslash
@@ -215,7 +209,7 @@ func SetModRoot(dir string) {
 //
 // If any errors may have caused the set of directories to be incomplete,
 // MatchDirs appends those errors to m.Errs.
-func (m *Match) MatchDirs() {
+func (m *Match) MatchDirs(modRoots []string) {
        m.Dirs = []string{}
        if !m.IsLocal() {
                m.AddError(fmt.Errorf("internal error: MatchDirs: %s is not a valid filesystem pattern", m.pattern))
@@ -253,15 +247,24 @@ func (m *Match) MatchDirs() {
        // We need to preserve the ./ for pattern matching
        // and in the returned import paths.
 
-       if modRoot != "" {
+       if len(modRoots) > 1 {
                abs, err := filepath.Abs(dir)
                if err != nil {
                        m.AddError(err)
                        return
                }
-               if !hasFilepathPrefix(abs, modRoot) {
-                       m.AddError(fmt.Errorf("directory %s is outside module root (%s)", abs, modRoot))
-                       return
+               var found bool
+               for _, modRoot := range modRoots {
+                       if modRoot != "" && hasFilepathPrefix(abs, modRoot) {
+                               found = true
+                       }
+               }
+               if !found {
+                       plural := ""
+                       if len(modRoots) > 1 {
+                               plural = "s"
+                       }
+                       m.AddError(fmt.Errorf("directory %s is outside module root%s (%s)", abs, plural, strings.Join(modRoots, ", ")))
                }
        }
 
@@ -424,19 +427,19 @@ func WarnUnmatched(matches []*Match) {
 
 // ImportPaths returns the matching paths to use for the given command line.
 // It calls ImportPathsQuiet and then WarnUnmatched.
-func ImportPaths(patterns []string) []*Match {
-       matches := ImportPathsQuiet(patterns)
+func ImportPaths(patterns, modRoots []string) []*Match {
+       matches := ImportPathsQuiet(patterns, modRoots)
        WarnUnmatched(matches)
        return matches
 }
 
 // ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches.
-func ImportPathsQuiet(patterns []string) []*Match {
+func ImportPathsQuiet(patterns, modRoots []string) []*Match {
        var out []*Match
        for _, a := range CleanPatterns(patterns) {
                m := NewMatch(a)
                if m.IsLocal() {
-                       m.MatchDirs()
+                       m.MatchDirs(modRoots)
 
                        // Change the file import path to a regular import path if the package
                        // is in GOPATH or GOROOT. We don't report errors here; LoadImport
similarity index 74%
rename from src/cmd/internal/str/path.go
rename to src/cmd/go/internal/str/path.go
index 51ab2af82b58a6b42f5fc9eaa5e855d8de6fa5b4..0c8aaeaca1fba0f5f2cbc0d27c2262d8d43932f5 100644 (file)
@@ -49,3 +49,17 @@ func HasFilePathPrefix(s, prefix string) bool {
                return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
        }
 }
+
+// TrimFilePathPrefix returns s without the leading path elements in prefix.
+// If s does not start with prefix (HasFilePathPrefix with the same arguments
+// returns false), TrimFilePathPrefix returns s. If s equals prefix,
+// TrimFilePathPrefix returns "".
+func TrimFilePathPrefix(s, prefix string) string {
+       if !HasFilePathPrefix(s, prefix) {
+               return s
+       }
+       if len(s) == len(prefix) {
+               return ""
+       }
+       return s[len(prefix)+1:]
+}
similarity index 72%
rename from src/cmd/internal/str/str.go
rename to src/cmd/go/internal/str/str.go
index 9106ebf74d5e31cb04e7deddf26e1a72ff6e9c74..5bc521b9df46874b6f7a93d8d80ec1a4279f53bf 100644 (file)
@@ -109,47 +109,3 @@ func Uniq(ss *[]string) {
        }
        *ss = uniq
 }
-
-func isSpaceByte(c byte) bool {
-       return c == ' ' || c == '\t' || c == '\n' || c == '\r'
-}
-
-// SplitQuotedFields splits s into a list of fields,
-// allowing single or double quotes around elements.
-// There is no unescaping or other processing within
-// quoted fields.
-func SplitQuotedFields(s string) ([]string, error) {
-       // Split fields allowing '' or "" around elements.
-       // Quotes further inside the string do not count.
-       var f []string
-       for len(s) > 0 {
-               for len(s) > 0 && isSpaceByte(s[0]) {
-                       s = s[1:]
-               }
-               if len(s) == 0 {
-                       break
-               }
-               // Accepted quoted string. No unescaping inside.
-               if s[0] == '"' || s[0] == '\'' {
-                       quote := s[0]
-                       s = s[1:]
-                       i := 0
-                       for i < len(s) && s[i] != quote {
-                               i++
-                       }
-                       if i >= len(s) {
-                               return nil, fmt.Errorf("unterminated %c string", quote)
-                       }
-                       f = append(f, s[:i])
-                       s = s[i+1:]
-                       continue
-               }
-               i := 0
-               for i < len(s) && !isSpaceByte(s[i]) {
-                       i++
-               }
-               f = append(f, s[:i])
-               s = s[i:]
-       }
-       return f, nil
-}
similarity index 97%
rename from src/cmd/internal/str/str_test.go
rename to src/cmd/go/internal/str/str_test.go
index 147ce1a63ef32d89a537f49e8fb601a70387dbe5..8ea758e0a8b64bf0c8e4314660f9b79050fb4383 100644 (file)
@@ -4,7 +4,9 @@
 
 package str
 
-import "testing"
+import (
+       "testing"
+)
 
 var foldDupTests = []struct {
        list   []string
index 37ac81c26782ae226be515bc2f65a42700de978d..1b79314eff365889fa9b4b1cb9b221e91abfbd49 100644 (file)
@@ -19,6 +19,9 @@ var passFlagToTest = map[string]bool{
        "cpu":                  true,
        "cpuprofile":           true,
        "failfast":             true,
+       "fuzz":                 true,
+       "fuzzminimizetime":     true,
+       "fuzztime":             true,
        "list":                 true,
        "memprofile":           true,
        "memprofilerate":       true,
@@ -33,3 +36,37 @@ var passFlagToTest = map[string]bool{
        "trace":                true,
        "v":                    true,
 }
+
+var passAnalyzersToVet = map[string]bool{
+       "asmdecl":          true,
+       "assign":           true,
+       "atomic":           true,
+       "bool":             true,
+       "bools":            true,
+       "buildtag":         true,
+       "buildtags":        true,
+       "cgocall":          true,
+       "composites":       true,
+       "copylocks":        true,
+       "errorsas":         true,
+       "framepointer":     true,
+       "httpresponse":     true,
+       "ifaceassert":      true,
+       "loopclosure":      true,
+       "lostcancel":       true,
+       "methods":          true,
+       "nilfunc":          true,
+       "printf":           true,
+       "rangeloops":       true,
+       "shift":            true,
+       "sigchanyzer":      true,
+       "stdmethods":       true,
+       "stringintconv":    true,
+       "structtag":        true,
+       "testinggoroutine": true,
+       "tests":            true,
+       "unmarshal":        true,
+       "unreachable":      true,
+       "unsafeptr":        true,
+       "unusedresult":     true,
+}
index ab5440b3801f15af1124d3ce1738035a894926a0..40dc558e9080c01bf1ae8ea0208d07775b2f30dd 100644 (file)
@@ -5,7 +5,9 @@
 package test
 
 import (
+       "cmd/go/internal/test/internal/genflags"
        "flag"
+       "reflect"
        "strings"
        "testing"
 )
@@ -17,7 +19,7 @@ func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
                }
                name := strings.TrimPrefix(f.Name, "test.")
                switch name {
-               case "testlogfile", "paniconexit0":
+               case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker":
                        // These are internal flags.
                default:
                        if !passFlagToTest[name] {
@@ -37,3 +39,20 @@ func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
                }
        }
 }
+
+func TestVetAnalyzersSetIsCorrect(t *testing.T) {
+       vetAns, err := genflags.VetAnalyzers()
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       want := make(map[string]bool)
+       for _, a := range vetAns {
+               want[a] = true
+       }
+
+       if !reflect.DeepEqual(want, passAnalyzersToVet) {
+               t.Errorf("stale vet analyzers: want %v; got %v", want, passAnalyzersToVet)
+               t.Logf("(Run 'go generate cmd/go/internal/test' to refresh the set of analyzers.)")
+       }
+}
index 9277de7fee839e216f8c70b31b8720d839f16c5e..10f290090c7cf8e92420c8f61dae4ca559d926d0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
@@ -16,6 +15,8 @@ import (
        "strings"
        "testing"
        "text/template"
+
+       "cmd/go/internal/test/internal/genflags"
 )
 
 func main() {
@@ -25,9 +26,18 @@ func main() {
 }
 
 func regenerate() error {
+       vetAnalyzers, err := genflags.VetAnalyzers()
+       if err != nil {
+               return err
+       }
+
        t := template.Must(template.New("fileTemplate").Parse(fileTemplate))
+       tData := map[string][]string{
+               "testFlags":    testFlags(),
+               "vetAnalyzers": vetAnalyzers,
+       }
        buf := bytes.NewBuffer(nil)
-       if err := t.Execute(buf, testFlags()); err != nil {
+       if err := t.Execute(buf, tData); err != nil {
                return err
        }
 
@@ -64,7 +74,7 @@ func testFlags() []string {
                name := strings.TrimPrefix(f.Name, "test.")
 
                switch name {
-               case "testlogfile", "paniconexit0":
+               case "testlogfile", "paniconexit0", "fuzzcachedir", "fuzzworker":
                        // These flags are only for use by cmd/go.
                default:
                        names = append(names, name)
@@ -85,7 +95,13 @@ package test
 // passFlagToTest contains the flags that should be forwarded to
 // the test binary with the prefix "test.".
 var passFlagToTest = map[string]bool {
-{{- range .}}
+{{- range .testFlags}}
+       "{{.}}": true,
+{{- end }}
+}
+
+var passAnalyzersToVet = map[string]bool {
+{{- range .vetAnalyzers}}
        "{{.}}": true,
 {{- end }}
 }
diff --git a/src/cmd/go/internal/test/internal/genflags/vetflag.go b/src/cmd/go/internal/test/internal/genflags/vetflag.go
new file mode 100644 (file)
index 0000000..2195cc3
--- /dev/null
@@ -0,0 +1,68 @@
+// 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 genflags
+
+import (
+       "bytes"
+       "cmd/go/internal/base"
+       "encoding/json"
+       "fmt"
+       exec "internal/execabs"
+       "regexp"
+       "sort"
+)
+
+// VetAnalyzers computes analyzers and their aliases supported by vet.
+func VetAnalyzers() ([]string, error) {
+       // get supported vet flag information
+       tool := base.Tool("vet")
+       vetcmd := exec.Command(tool, "-flags")
+       out := new(bytes.Buffer)
+       vetcmd.Stdout = out
+       if err := vetcmd.Run(); err != nil {
+               return nil, fmt.Errorf("go vet: can't execute %s -flags: %v\n", tool, err)
+       }
+       var analysisFlags []struct {
+               Name  string
+               Bool  bool
+               Usage string
+       }
+       if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil {
+               return nil, fmt.Errorf("go vet: can't unmarshal JSON from %s -flags: %v", tool, err)
+       }
+
+       // parse the flags to figure out which ones stand for analyses
+       analyzerSet := make(map[string]bool)
+       rEnable := regexp.MustCompile("^enable .+ analysis$")
+       for _, flag := range analysisFlags {
+               if rEnable.MatchString(flag.Usage) {
+                       analyzerSet[flag.Name] = true
+               }
+       }
+
+       rDeprecated := regexp.MustCompile("^deprecated alias for -(?P<analyzer>(.+))$")
+       // Returns the original value matched by rDeprecated on input value.
+       // If there is no match, "" is returned.
+       originalValue := func(value string) string {
+               match := rDeprecated.FindStringSubmatch(value)
+               if len(match) < 2 {
+                       return ""
+               }
+               return match[1]
+       }
+       // extract deprecated aliases for existing analyses
+       for _, flag := range analysisFlags {
+               if o := originalValue(flag.Usage); analyzerSet[o] {
+                       analyzerSet[flag.Name] = true
+               }
+       }
+
+       var analyzers []string
+       for a := range analyzerSet {
+               analyzers = append(analyzers, a)
+       }
+       sort.Strings(analyzers)
+       return analyzers, nil
+}
index aeba80eb680d61f2b0d0419394f9fd2a7254bd42..7361c11786e04ea5e896457bc7c9a7fd02c18566 100644 (file)
@@ -29,11 +29,15 @@ import (
        "cmd/go/internal/cfg"
        "cmd/go/internal/load"
        "cmd/go/internal/lockedfile"
+       "cmd/go/internal/modload"
        "cmd/go/internal/search"
+       "cmd/go/internal/str"
        "cmd/go/internal/trace"
        "cmd/go/internal/work"
-       "cmd/internal/str"
+       "cmd/internal/sys"
        "cmd/internal/test2json"
+
+       "golang.org/x/mod/module"
 )
 
 // Break init loop.
@@ -60,8 +64,8 @@ followed by detailed output for each failed package.
 
 'Go test' recompiles each package along with any files with names matching
 the file pattern "*_test.go".
-These additional files can contain test functions, benchmark functions, and
-example functions. See 'go help testfunc' for more.
+These additional files can contain test functions, benchmark functions, fuzz
+targets and example functions. See 'go help testfunc' for more.
 Each listed package causes the execution of a separate test binary.
 Files whose names begin with "_" (including "_test.go") or "." are ignored.
 
@@ -78,7 +82,8 @@ binary. Only a high-confidence subset of the default go vet checks are
 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.
+To disable the running of go vet, use the -vet=off flag. To run all
+checks, use the -vet=all 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
@@ -119,16 +124,16 @@ elapsed time in the summary line.
 The rule for a match in the cache is that the run involves the same
 test binary and the flags on the command line come entirely from a
 restricted set of 'cacheable' test flags, defined as -benchtime, -cpu,
--list, -parallel, -run, -short, and -v. If a run of go test has any test
-or non-test flags outside this set, the result is not cached. To
-disable test caching, use any test flag or argument other than the
-cacheable flags. The idiomatic way to disable test caching explicitly
-is to use -count=1. Tests that open files within the package's source
-root (usually $GOPATH) or that consult environment variables only
-match future runs in which the files and environment variables are unchanged.
-A cached test result is treated as executing in no time at all,
-so a successful package test result will be cached and reused
-regardless of -timeout setting.
+-list, -parallel, -run, -short, -timeout, -failfast, and -v.
+If a run of go test has any test or non-test flags outside this set,
+the result is not cached. To disable test caching, use any test flag
+or argument other than the cacheable flags. The idiomatic way to disable
+test caching explicitly is to use -count=1. Tests that open files within
+the package's source root (usually $GOPATH) or that consult environment
+variables only match future runs in which the files and environment
+variables are unchanged. A cached test result is treated as executing
+in no time at all,so a successful package test result will be cached and
+reused regardless of -timeout setting.
 
 In addition to the build flags, the flags handled by 'go test' itself are:
 
@@ -206,9 +211,10 @@ control the execution of any test:
            (for example, -benchtime 100x).
 
        -count n
-           Run each test and benchmark n times (default 1).
+           Run each test, benchmark, and fuzz seed n times (default 1).
            If -cpu is set, run n times for each GOMAXPROCS value.
-           Examples are always run once.
+           Examples are always run once. -count does not apply to
+           fuzz targets matched by -fuzz.
 
        -cover
            Enable coverage analysis.
@@ -235,32 +241,60 @@ control the execution of any test:
            Sets -cover.
 
        -cpu 1,2,4
-           Specify a list of GOMAXPROCS values for which the tests or
-           benchmarks should be executed. The default is the current value
-           of GOMAXPROCS.
+           Specify a list of GOMAXPROCS values for which the tests, benchmarks or
+           fuzz targets should be executed. The default is the current value
+           of GOMAXPROCS. -cpu does not apply to fuzz targets matched by -fuzz.
 
        -failfast
            Do not start new tests after the first test failure.
 
+       -fuzz regexp
+           Run the fuzz target matching the regular expression. When specified,
+           the command line argument must match exactly one package within the
+           main module, and regexp must match exactly one fuzz target within
+           that package. After tests, benchmarks, seed corpora of other fuzz
+           targets, and examples have completed, the matching target will be
+           fuzzed. See the Fuzzing section of the testing package documentation
+           for details.
+
+       -fuzztime t
+           Run enough iterations of the fuzz test to take t, specified as a
+           time.Duration (for example, -fuzztime 1h30s). The default is to run
+           forever.
+           The special syntax Nx means to run the fuzz test N times
+           (for example, -fuzztime 100x).
+
+       -json
+           Log verbose output and test results in JSON. This presents the
+           same information as the -v flag in a machine-readable format.
+
        -list regexp
-           List tests, benchmarks, or examples matching the regular expression.
-           No tests, benchmarks or examples will be run. This will only
-           list top-level tests. No subtest or subbenchmarks will be shown.
+           List tests, benchmarks, fuzz targets, or examples matching the regular
+           expression. No tests, benchmarks, fuzz targets, or examples will be run.
+           This will only list top-level tests. No subtest or subbenchmarks will be
+           shown.
 
        -parallel n
-           Allow parallel execution of test functions that call t.Parallel.
+           Allow parallel execution of test functions that call t.Parallel, and
+           f.Fuzz functions that call t.Parallel when running the seed corpus.
            The value of this flag is the maximum number of tests to run
-           simultaneously; by default, it is set to the value of GOMAXPROCS.
+           simultaneously.
+           While fuzzing, the value of this flag is the maximum number of
+           subprocesses that may call the fuzz function simultaneously, regardless of
+           whether T.Parallel is called.
+           By default, -parallel is set to the value of GOMAXPROCS.
+           Setting -parallel to values higher than GOMAXPROCS may cause degraded
+           performance due to CPU contention, especially when fuzzing.
            Note that -parallel only applies within a single test binary.
            The 'go test' command may run tests for different packages
            in parallel as well, according to the setting of the -p flag
            (see 'go help build').
 
        -run regexp
-           Run only those tests and examples matching the regular expression.
-           For tests, the regular expression is split by unbracketed slash (/)
-           characters into a sequence of regular expressions, and each part
-           of a test's identifier must match the corresponding element in
+           Run only those tests, examples, and fuzz targets matching the regular
+           expression. For tests, the regular expression is split by unbracketed
+           slash (/) characters into a sequence of regular expressions, and each
+           part of a test's identifier must match the corresponding element in
            the sequence, if any. Note that possible parents of matches are
            run too, so that -run=X/Y matches and runs and reports the result
            of all tests matching X, even those without sub-tests matching Y,
@@ -273,11 +307,11 @@ control the execution of any test:
            exhaustive tests.
 
        -shuffle off,on,N
-               Randomize the execution order of tests and benchmarks.
-               It is off by default. If -shuffle is set to on, then it will seed
-               the randomizer using the system clock. If -shuffle is set to an
-               integer N, then N will be used as the seed value. In both cases,
-               the seed will be reported for reproducibility.
+           Randomize the execution order of tests and benchmarks.
+           It is off by default. If -shuffle is set to on, then it will seed
+           the randomizer using the system clock. If -shuffle is set to an
+           integer N, then N will be used as the seed value. In both cases,
+           the seed will be reported for reproducibility.
 
        -timeout d
            If a test binary runs longer than duration d, panic.
@@ -373,7 +407,11 @@ leave the test binary in pkg.test for use when analyzing the profiles.
 When 'go test' runs a test binary, it does so from within the
 corresponding package's source code directory. Depending on the test,
 it may be necessary to do the same when invoking a generated test
-binary directly.
+binary directly. Because that directory may be located within the
+module cache, which may be read-only and is verified by checksums, the
+test must not write to it or any other directory within the module
+unless explicitly requested by the user (such as with the -fuzz flag,
+which writes failures to testdata/fuzz).
 
 The command-line package list, if present, must appear before any
 flag not known to the go test command. Continuing the example above,
@@ -430,6 +468,10 @@ A benchmark function is one named BenchmarkXxx and should have the signature,
 
        func BenchmarkXxx(b *testing.B) { ... }
 
+A fuzz target is one named FuzzXxx and should have the signature,
+
+       func FuzzXxx(f *testing.F) { ... }
+
 An example function is similar to a test function but, instead of using
 *testing.T to report success or failure, prints output to os.Stdout.
 If the last comment in the function starts with "Output:" then the output
@@ -469,7 +511,7 @@ Here is another example where the ordering of the output is ignored:
 
 The entire test file is presented as the example when it contains a single
 example function, at least one other function, type, variable, or constant
-declaration, and no test or benchmark functions.
+declaration, and no fuzz targets or test or benchmark functions.
 
 See the documentation of the testing package for more information.
 `,
@@ -483,6 +525,7 @@ var (
        testCoverPaths   []string                          // -coverpkg flag
        testCoverPkgs    []*load.Package                   // -coverpkg flag
        testCoverProfile string                            // -coverprofile flag
+       testFuzz         string                            // -fuzz flag
        testJSON         bool                              // -json flag
        testList         string                            // -list flag
        testO            string                            // -o flag
@@ -577,6 +620,7 @@ var defaultVetFlags = []string{
 }
 
 func runTest(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
        pkgArgs, testArgs = testFlags(args)
 
        if cfg.DebugTrace != "" {
@@ -615,6 +659,52 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
        if testO != "" && len(pkgs) != 1 {
                base.Fatalf("cannot use -o flag with multiple packages")
        }
+       if testFuzz != "" {
+               if !sys.FuzzSupported(cfg.Goos, cfg.Goarch) {
+                       base.Fatalf("-fuzz flag is not supported on %s/%s", cfg.Goos, cfg.Goarch)
+               }
+               if len(pkgs) != 1 {
+                       base.Fatalf("cannot use -fuzz flag with multiple packages")
+               }
+               if testCoverProfile != "" {
+                       base.Fatalf("cannot use -coverprofile flag with -fuzz flag")
+               }
+               if profileFlag := testProfile(); profileFlag != "" {
+                       base.Fatalf("cannot use %s flag with -fuzz flag", profileFlag)
+               }
+
+               // Reject the '-fuzz' flag if the package is outside the main module.
+               // Otherwise, if fuzzing identifies a failure it could corrupt checksums in
+               // the module cache (or permanently alter the behavior of std tests for all
+               // users) by writing the failing input to the package's testdata directory.
+               // (See https://golang.org/issue/48495 and test_fuzz_modcache.txt.)
+               mainMods := modload.MainModules
+               if m := pkgs[0].Module; m != nil && m.Path != "" {
+                       if !mainMods.Contains(m.Path) {
+                               base.Fatalf("cannot use -fuzz flag on package outside the main module")
+                       }
+               } else if pkgs[0].Standard && modload.Enabled() {
+                       // Because packages in 'std' and 'cmd' are part of the standard library,
+                       // they are only treated as part of a module in 'go mod' subcommands and
+                       // 'go get'. However, we still don't want to accidentally corrupt their
+                       // testdata during fuzzing, nor do we want to fail with surprising errors
+                       // if GOROOT isn't writable (as is often the case for Go toolchains
+                       // installed through package managers).
+                       //
+                       // If the user is requesting to fuzz a standard-library package, ensure
+                       // that they are in the same module as that package (just like when
+                       // fuzzing any other package).
+                       if strings.HasPrefix(pkgs[0].ImportPath, "cmd/") {
+                               if !mainMods.Contains("cmd") || !mainMods.InGorootSrc(module.Version{Path: "cmd"}) {
+                                       base.Fatalf("cannot use -fuzz flag on package outside the main module")
+                               }
+                       } else {
+                               if !mainMods.Contains("std") || !mainMods.InGorootSrc(module.Version{Path: "std"}) {
+                                       base.Fatalf("cannot use -fuzz flag on package outside the main module")
+                               }
+                       }
+               }
+       }
        if testProfile() != "" && len(pkgs) != 1 {
                base.Fatalf("cannot use %s flag with multiple packages", testProfile())
        }
@@ -625,7 +715,9 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
        // to that timeout plus one minute. This is a backup alarm in case
        // the test wedges with a goroutine spinning and its background
        // timer does not get a chance to fire.
-       if testTimeout > 0 {
+       // Don't set this if fuzzing, since it should be able to run
+       // indefinitely.
+       if testTimeout > 0 && testFuzz == "" {
                testKillTimeout = testTimeout + 1*time.Minute
        }
 
@@ -649,7 +741,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
        b.Init()
 
        if cfg.BuildI {
-               fmt.Fprint(os.Stderr, "go test: -i flag is deprecated\n")
+               fmt.Fprint(os.Stderr, "go: -i flag is deprecated\n")
                cfg.BuildV = testV
 
                deps := make(map[string]bool)
@@ -775,6 +867,30 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
                }
        }
 
+       // Inform the compiler that it should instrument the binary at
+       // build-time when fuzzing is enabled.
+       if testFuzz != "" {
+               // Don't instrument packages which may affect coverage guidance but are
+               // unlikely to be useful. Most of these are used by the testing or
+               // internal/fuzz packages concurrently with fuzzing.
+               var skipInstrumentation = map[string]bool{
+                       "context":       true,
+                       "internal/fuzz": true,
+                       "reflect":       true,
+                       "runtime":       true,
+                       "sync":          true,
+                       "sync/atomic":   true,
+                       "syscall":       true,
+                       "testing":       true,
+                       "time":          true,
+               }
+               for _, p := range load.TestPackageList(ctx, pkgOpts, pkgs) {
+                       if !skipInstrumentation[p.ImportPath] {
+                               p.Internal.FuzzInstrument = true
+                       }
+               }
+       }
+
        // Prepare build + run + print actions for all packages being tested.
        for _, p := range pkgs {
                // sync/atomic import is inserted by the cover tool. See #18486
@@ -1080,6 +1196,8 @@ func declareCoverVars(p *load.Package, files ...string) map[string]*load.CoverVa
 }
 
 var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
+var noTargetsToFuzz = []byte("\ntesting: warning: no targets to fuzz\n")
+var tooManyTargetsToFuzz = []byte("\ntesting: warning: -fuzz matches more than one target, won't fuzz\n")
 
 type runCache struct {
        disableCache bool // cache should be disabled for this run
@@ -1127,10 +1245,10 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
        }
 
        var buf bytes.Buffer
-       if len(pkgArgs) == 0 || (testBench != "") {
+       if len(pkgArgs) == 0 || testBench != "" || testFuzz != "" {
                // Stream test output (no buffering) when no package has
                // been given on the command line (implicit current directory)
-               // or when benchmarking.
+               // or when benchmarking or fuzzing.
                // No change to stdout.
        } else {
                // If we're only running a single package under test or if parallelism is
@@ -1183,7 +1301,12 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
                testlogArg = []string{"-test.testlogfile=" + a.Objdir + "testlog.txt"}
        }
        panicArg := "-test.paniconexit0"
-       args := str.StringList(execCmd, a.Deps[0].BuiltTarget(), testlogArg, panicArg, testArgs)
+       fuzzArg := []string{}
+       if testFuzz != "" {
+               fuzzCacheDir := filepath.Join(cache.Default().FuzzDir(), a.Package.ImportPath)
+               fuzzArg = []string{"-test.fuzzcachedir=" + fuzzCacheDir}
+       }
+       args := str.StringList(execCmd, a.Deps[0].BuiltTarget(), testlogArg, panicArg, fuzzArg, testArgs)
 
        if testCoverProfile != "" {
                // Write coverage to temporary profile, for merging later.
@@ -1276,15 +1399,31 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
                if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
                        norun = " [no tests to run]"
                }
+               if bytes.HasPrefix(out, noTargetsToFuzz[1:]) || bytes.Contains(out, noTargetsToFuzz) {
+                       norun = " [no targets to fuzz]"
+               }
+               if bytes.HasPrefix(out, tooManyTargetsToFuzz[1:]) || bytes.Contains(out, tooManyTargetsToFuzz) {
+                       norun = " [will not fuzz, -fuzz matches more than one target]"
+               }
+               if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
+                       // Ensure that the output ends with a newline before the "ok"
+                       // line we're about to print (https://golang.org/issue/49317).
+                       cmd.Stdout.Write([]byte("\n"))
+               }
                fmt.Fprintf(cmd.Stdout, "ok  \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun)
                c.saveOutput(a)
        } else {
                base.SetExitStatus(1)
-               // If there was test output, assume we don't need to print the exit status.
-               // Buf there's no test output, do print the exit status.
                if len(out) == 0 {
+                       // If there was no test output, print the exit status so that the reason
+                       // for failure is clear.
                        fmt.Fprintf(cmd.Stdout, "%s\n", err)
+               } else if !bytes.HasSuffix(out, []byte("\n")) {
+                       // Otherwise, ensure that the output ends with a newline before the FAIL
+                       // line we're about to print (https://golang.org/issue/49317).
+                       cmd.Stdout.Write([]byte("\n"))
                }
+
                // NOTE(golang.org/issue/37555): test2json reports that a test passes
                // unless "FAIL" is printed at the beginning of a line. The test may not
                // actually print that if it panics, exits, or terminates abnormally,
@@ -1347,6 +1486,7 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo
                        "-test.run",
                        "-test.short",
                        "-test.timeout",
+                       "-test.failfast",
                        "-test.v":
                        // These are cacheable.
                        // Note that this list is documented above,
@@ -1711,9 +1851,23 @@ func builderNoTest(b *work.Builder, ctx context.Context, a *work.Action) error {
        return nil
 }
 
-// printExitStatus is the action for printing the exit status
+// printExitStatus is the action for printing the final exit status.
+// If we are running multiple test targets, print a final "FAIL"
+// in case a failure in an early package has already scrolled
+// off of the user's terminal.
+// (See https://golang.org/issue/30507#issuecomment-470593235.)
+//
+// In JSON mode, we need to maintain valid JSON output and
+// we assume that the test output is being parsed by a tool
+// anyway, so the failure will not be missed and would be
+// awkward to try to wedge into the JSON stream.
+//
+// In fuzz mode, we only allow a single package for now
+// (see CL 350156 and https://golang.org/issue/46312),
+// so there is no possibility of scrolling off and no need
+// to print the final status.
 func printExitStatus(b *work.Builder, ctx context.Context, a *work.Action) error {
-       if !testJSON && len(pkgArgs) != 0 {
+       if !testJSON && testFuzz == "" && len(pkgArgs) != 0 {
                if base.GetExitStatus() != 0 {
                        fmt.Println("FAIL")
                        return nil
index 08f1efa2c0d26a0cf398f2b778c0adde90fc97ae..b9d1ec91ff7552aba0e1667d96f16d55349931a5 100644 (file)
@@ -5,6 +5,10 @@
 package test
 
 import (
+       "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/cmdflag"
+       "cmd/go/internal/work"
        "errors"
        "flag"
        "fmt"
@@ -13,11 +17,6 @@ import (
        "strconv"
        "strings"
        "time"
-
-       "cmd/go/internal/base"
-       "cmd/go/internal/cfg"
-       "cmd/go/internal/cmdflag"
-       "cmd/go/internal/work"
 )
 
 //go:generate go run ./genflags.go
@@ -29,6 +28,7 @@ import (
 
 func init() {
        work.AddBuildFlags(CmdTest, work.OmitVFlag)
+       base.AddWorkfileFlag(&CmdTest.Flag)
 
        cf := CmdTest.Flag
        cf.BoolVar(&testC, "c", false, "")
@@ -57,6 +57,7 @@ func init() {
        cf.String("cpu", "", "")
        cf.StringVar(&testCPUProfile, "cpuprofile", "", "")
        cf.Bool("failfast", false, "")
+       cf.StringVar(&testFuzz, "fuzz", "", "")
        cf.StringVar(&testList, "list", "", "")
        cf.StringVar(&testMemProfile, "memprofile", "", "")
        cf.String("memprofilerate", "", "")
@@ -67,6 +68,8 @@ func init() {
        cf.String("run", "", "")
        cf.Bool("short", false, "")
        cf.DurationVar(&testTimeout, "timeout", 10*time.Minute, "")
+       cf.String("fuzztime", "", "")
+       cf.String("fuzzminimizetime", "", "")
        cf.StringVar(&testTrace, "trace", "", "")
        cf.BoolVar(&testV, "v", false, "")
        cf.Var(&testShuffle, "shuffle", "")
@@ -134,6 +137,7 @@ type outputdirFlag struct {
 func (f *outputdirFlag) String() string {
        return f.abs
 }
+
 func (f *outputdirFlag) Set(value string) (err error) {
        if value == "" {
                f.abs = ""
@@ -142,6 +146,7 @@ func (f *outputdirFlag) Set(value string) (err error) {
        }
        return err
 }
+
 func (f *outputdirFlag) getAbs() string {
        if f.abs == "" {
                return base.Cwd()
@@ -150,8 +155,12 @@ func (f *outputdirFlag) getAbs() string {
 }
 
 // vetFlag implements the special parsing logic for the -vet flag:
-// a comma-separated list, with a distinguished value "off" and
-// a boolean tracking whether it was set explicitly.
+// a comma-separated list, with distinguished values "all" and
+// "off", plus a boolean tracking whether it was set explicitly.
+//
+// "all" is encoded as vetFlag{true, false, nil}, since it will
+// pass no flags to the vet binary, and by default, it runs all
+// analyzers.
 type vetFlag struct {
        explicit bool
        off      bool
@@ -159,7 +168,10 @@ type vetFlag struct {
 }
 
 func (f *vetFlag) String() string {
-       if f.off {
+       switch {
+       case !f.off && !f.explicit && len(f.flags) == 0:
+               return "all"
+       case f.off:
                return "off"
        }
 
@@ -174,31 +186,45 @@ func (f *vetFlag) String() string {
 }
 
 func (f *vetFlag) Set(value string) error {
-       if value == "" {
+       switch {
+       case value == "":
                *f = vetFlag{flags: defaultVetFlags}
                return nil
-       }
-
-       if value == "off" {
-               *f = vetFlag{
-                       explicit: true,
-                       off:      true,
-               }
-               return nil
-       }
-
-       if strings.Contains(value, "=") {
+       case strings.Contains(value, "="):
                return fmt.Errorf("-vet argument cannot contain equal signs")
-       }
-       if strings.Contains(value, " ") {
+       case strings.Contains(value, " "):
                return fmt.Errorf("-vet argument is comma-separated list, cannot contain spaces")
        }
+
        *f = vetFlag{explicit: true}
+       var single string
        for _, arg := range strings.Split(value, ",") {
-               if arg == "" {
+               switch arg {
+               case "":
                        return fmt.Errorf("-vet argument contains empty list element")
+               case "all":
+                       single = arg
+                       *f = vetFlag{explicit: true}
+                       continue
+               case "off":
+                       single = arg
+                       *f = vetFlag{
+                               explicit: true,
+                               off:      true,
+                       }
+                       continue
+               default:
+                       if _, ok := passAnalyzersToVet[arg]; !ok {
+                               return fmt.Errorf("-vet argument must be a supported analyzer or a distinguished value; found %s", arg)
+                       }
+                       f.flags = append(f.flags, "-"+arg)
                }
-               f.flags = append(f.flags, "-"+arg)
+       }
+       if len(f.flags) > 1 && single != "" {
+               return fmt.Errorf("-vet does not accept %q in a list with other analyzers", single)
+       }
+       if len(f.flags) > 1 && single != "" {
+               return fmt.Errorf("-vet does not accept %q in a list with other analyzers", single)
        }
        return nil
 }
@@ -369,7 +395,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                if !testC {
                        buildFlag = "-i"
                }
-               fmt.Fprintf(os.Stderr, "go test: unknown flag %s cannot be used with %s\n", firstUnknownFlag, buildFlag)
+               fmt.Fprintf(os.Stderr, "go: unknown flag %s cannot be used with %s\n", firstUnknownFlag, buildFlag)
                exitWithUsage()
        }
 
index 95c90ea7c8da4a3f5121af3d78db4b80d8b18f65..4fe4c2baeda1ff7dbe1a1360f9a1d6d8dd9cb5f4 100644 (file)
@@ -61,7 +61,7 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) {
                switch {
                case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
                default:
-                       fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
+                       fmt.Fprintf(os.Stderr, "go: bad tool name %q\n", toolName)
                        base.SetExitStatus(2)
                        return
                }
@@ -117,14 +117,14 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) {
 func listTools() {
        f, err := os.Open(base.ToolDir)
        if err != nil {
-               fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
+               fmt.Fprintf(os.Stderr, "go: no tool directory: %s\n", err)
                base.SetExitStatus(2)
                return
        }
        defer f.Close()
        names, err := f.Readdirnames(-1)
        if err != nil {
-               fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
+               fmt.Fprintf(os.Stderr, "go: can't read tool directory: %s\n", err)
                base.SetExitStatus(2)
                return
        }
diff --git a/src/cmd/go/internal/txtar/archive_test.go b/src/cmd/go/internal/txtar/archive_test.go
deleted file mode 100644 (file)
index 3f734f6..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package txtar
-
-import (
-       "bytes"
-       "fmt"
-       "reflect"
-       "testing"
-)
-
-var tests = []struct {
-       name   string
-       text   string
-       parsed *Archive
-}{
-       {
-               name: "basic",
-               text: `comment1
-comment2
--- file1 --
-File 1 text.
--- foo ---
-More file 1 text.
--- file 2 --
-File 2 text.
--- empty --
--- noNL --
-hello world`,
-               parsed: &Archive{
-                       Comment: []byte("comment1\ncomment2\n"),
-                       Files: []File{
-                               {"file1", []byte("File 1 text.\n-- foo ---\nMore file 1 text.\n")},
-                               {"file 2", []byte("File 2 text.\n")},
-                               {"empty", []byte{}},
-                               {"noNL", []byte("hello world\n")},
-                       },
-               },
-       },
-}
-
-func Test(t *testing.T) {
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       a := Parse([]byte(tt.text))
-                       if !reflect.DeepEqual(a, tt.parsed) {
-                               t.Fatalf("Parse: wrong output:\nhave:\n%s\nwant:\n%s", shortArchive(a), shortArchive(tt.parsed))
-                       }
-                       text := Format(a)
-                       a = Parse(text)
-                       if !reflect.DeepEqual(a, tt.parsed) {
-                               t.Fatalf("Parse after Format: wrong output:\nhave:\n%s\nwant:\n%s", shortArchive(a), shortArchive(tt.parsed))
-                       }
-               })
-       }
-}
-
-func shortArchive(a *Archive) string {
-       var buf bytes.Buffer
-       fmt.Fprintf(&buf, "comment: %q\n", a.Comment)
-       for _, f := range a.Files {
-               fmt.Fprintf(&buf, "file %q: %q\n", f.Name, f.Data)
-       }
-       return buf.String()
-}
index 97b2a631ae63cd0f5dc2f2dddb7b790601463725..b2ce80325a19c58583c8fcddb6e084dd03e0234b 100644 (file)
@@ -5,6 +5,7 @@
 package vcs
 
 import (
+       "bytes"
        "encoding/json"
        "errors"
        "fmt"
@@ -17,23 +18,26 @@ import (
        "os"
        "path/filepath"
        "regexp"
+       "strconv"
        "strings"
        "sync"
+       "time"
 
        "cmd/go/internal/base"
        "cmd/go/internal/cfg"
        "cmd/go/internal/search"
        "cmd/go/internal/web"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 
        "golang.org/x/mod/module"
 )
 
-// A vcsCmd describes how to use a version control system
+// A Cmd describes how to use a version control system
 // like Mercurial, Git, or Subversion.
 type Cmd struct {
-       Name string
-       Cmd  string // name of binary to invoke command
+       Name      string
+       Cmd       string   // name of binary to invoke command
+       RootNames []string // filename indicating the root of a checkout directory
 
        CreateCmd   []string // commands to download a fresh copy of a repository
        DownloadCmd []string // commands to download updates into an existing repository
@@ -48,6 +52,14 @@ type Cmd struct {
 
        RemoteRepo  func(v *Cmd, rootDir string) (remoteRepo string, err error)
        ResolveRepo func(v *Cmd, rootDir, remoteRepo string) (realRepo string, err error)
+       Status      func(v *Cmd, rootDir string) (Status, error)
+}
+
+// Status is the current state of a local repository.
+type Status struct {
+       Revision    string    // Optional.
+       CommitTime  time.Time // Optional.
+       Uncommitted bool      // Required.
 }
 
 var defaultSecureScheme = map[string]bool{
@@ -118,8 +130,9 @@ func vcsByCmd(cmd string) *Cmd {
 
 // vcsHg describes how to use Mercurial.
 var vcsHg = &Cmd{
-       Name: "Mercurial",
-       Cmd:  "hg",
+       Name:      "Mercurial",
+       Cmd:       "hg",
+       RootNames: []string{".hg"},
 
        CreateCmd:   []string{"clone -U -- {repo} {dir}"},
        DownloadCmd: []string{"pull"},
@@ -139,6 +152,7 @@ var vcsHg = &Cmd{
        Scheme:     []string{"https", "http", "ssh"},
        PingCmd:    "identify -- {scheme}://{repo}",
        RemoteRepo: hgRemoteRepo,
+       Status:     hgStatus,
 }
 
 func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) {
@@ -149,10 +163,60 @@ func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) {
        return strings.TrimSpace(string(out)), nil
 }
 
+func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) {
+       // Output changeset ID and seconds since epoch.
+       out, err := vcsHg.runOutputVerboseOnly(rootDir, `log -l1 -T {node}:{date(date,"%s")}`)
+       if err != nil {
+               return Status{}, err
+       }
+
+       // Successful execution without output indicates an empty repo (no commits).
+       var rev string
+       var commitTime time.Time
+       if len(out) > 0 {
+               rev, commitTime, err = parseRevTime(out)
+               if err != nil {
+                       return Status{}, err
+               }
+       }
+
+       // Also look for untracked files.
+       out, err = vcsHg.runOutputVerboseOnly(rootDir, "status")
+       if err != nil {
+               return Status{}, err
+       }
+       uncommitted := len(out) > 0
+
+       return Status{
+               Revision:    rev,
+               CommitTime:  commitTime,
+               Uncommitted: uncommitted,
+       }, nil
+}
+
+// parseRevTime parses commit details in "revision:seconds" format.
+func parseRevTime(out []byte) (string, time.Time, error) {
+       buf := string(bytes.TrimSpace(out))
+
+       i := strings.IndexByte(buf, ':')
+       if i < 1 {
+               return "", time.Time{}, errors.New("unrecognized VCS tool output")
+       }
+       rev := buf[:i]
+
+       secs, err := strconv.ParseInt(string(buf[i+1:]), 10, 64)
+       if err != nil {
+               return "", time.Time{}, fmt.Errorf("unrecognized VCS tool output: %v", err)
+       }
+
+       return rev, time.Unix(secs, 0), nil
+}
+
 // vcsGit describes how to use Git.
 var vcsGit = &Cmd{
-       Name: "Git",
-       Cmd:  "git",
+       Name:      "Git",
+       Cmd:       "git",
+       RootNames: []string{".git"},
 
        CreateCmd:   []string{"clone -- {repo} {dir}", "-go-internal-cd {dir} submodule update --init --recursive"},
        DownloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"},
@@ -182,6 +246,7 @@ var vcsGit = &Cmd{
        PingCmd: "ls-remote {scheme}://{repo}",
 
        RemoteRepo: gitRemoteRepo,
+       Status:     gitStatus,
 }
 
 // scpSyntaxRe matches the SCP-like addresses used by Git to access
@@ -232,10 +297,40 @@ func gitRemoteRepo(vcsGit *Cmd, rootDir string) (remoteRepo string, err error) {
        return "", errParse
 }
 
+func gitStatus(vcsGit *Cmd, rootDir string) (Status, error) {
+       out, err := vcsGit.runOutputVerboseOnly(rootDir, "status --porcelain")
+       if err != nil {
+               return Status{}, err
+       }
+       uncommitted := len(out) > 0
+
+       // "git status" works for empty repositories, but "git show" does not.
+       // Assume there are no commits in the repo when "git show" fails with
+       // uncommitted files and skip tagging revision / committime.
+       var rev string
+       var commitTime time.Time
+       out, err = vcsGit.runOutputVerboseOnly(rootDir, "show -s --format=%H:%ct")
+       if err != nil && !uncommitted {
+               return Status{}, err
+       } else if err == nil {
+               rev, commitTime, err = parseRevTime(out)
+               if err != nil {
+                       return Status{}, err
+               }
+       }
+
+       return Status{
+               Revision:    rev,
+               CommitTime:  commitTime,
+               Uncommitted: uncommitted,
+       }, nil
+}
+
 // vcsBzr describes how to use Bazaar.
 var vcsBzr = &Cmd{
-       Name: "Bazaar",
-       Cmd:  "bzr",
+       Name:      "Bazaar",
+       Cmd:       "bzr",
+       RootNames: []string{".bzr"},
 
        CreateCmd: []string{"branch -- {repo} {dir}"},
 
@@ -251,6 +346,7 @@ var vcsBzr = &Cmd{
        PingCmd:     "info -- {scheme}://{repo}",
        RemoteRepo:  bzrRemoteRepo,
        ResolveRepo: bzrResolveRepo,
+       Status:      bzrStatus,
 }
 
 func bzrRemoteRepo(vcsBzr *Cmd, rootDir string) (remoteRepo string, err error) {
@@ -294,10 +390,68 @@ func bzrResolveRepo(vcsBzr *Cmd, rootDir, remoteRepo string) (realRepo string, e
        return strings.TrimSpace(out), nil
 }
 
+func bzrStatus(vcsBzr *Cmd, rootDir string) (Status, error) {
+       outb, err := vcsBzr.runOutputVerboseOnly(rootDir, "version-info")
+       if err != nil {
+               return Status{}, err
+       }
+       out := string(outb)
+
+       // Expect (non-empty repositories only):
+       //
+       // revision-id: gopher@gopher.net-20211021072330-qshok76wfypw9lpm
+       // date: 2021-09-21 12:00:00 +1000
+       // ...
+       var rev string
+       var commitTime time.Time
+
+       for _, line := range strings.Split(out, "\n") {
+               i := strings.IndexByte(line, ':')
+               if i < 0 {
+                       continue
+               }
+               key := line[:i]
+               value := strings.TrimSpace(line[i+1:])
+
+               switch key {
+               case "revision-id":
+                       rev = value
+               case "date":
+                       var err error
+                       commitTime, err = time.Parse("2006-01-02 15:04:05 -0700", value)
+                       if err != nil {
+                               return Status{}, errors.New("unable to parse output of bzr version-info")
+                       }
+               }
+       }
+
+       outb, err = vcsBzr.runOutputVerboseOnly(rootDir, "status")
+       if err != nil {
+               return Status{}, err
+       }
+
+       // Skip warning when working directory is set to an older revision.
+       if bytes.HasPrefix(outb, []byte("working tree is out of date")) {
+               i := bytes.IndexByte(outb, '\n')
+               if i < 0 {
+                       i = len(outb)
+               }
+               outb = outb[:i]
+       }
+       uncommitted := len(outb) > 0
+
+       return Status{
+               Revision:    rev,
+               CommitTime:  commitTime,
+               Uncommitted: uncommitted,
+       }, nil
+}
+
 // vcsSvn describes how to use Subversion.
 var vcsSvn = &Cmd{
-       Name: "Subversion",
-       Cmd:  "svn",
+       Name:      "Subversion",
+       Cmd:       "svn",
+       RootNames: []string{".svn"},
 
        CreateCmd:   []string{"checkout -- {repo} {dir}"},
        DownloadCmd: []string{"update"},
@@ -346,8 +500,9 @@ const fossilRepoName = ".fossil"
 
 // vcsFossil describes how to use Fossil (fossil-scm.org)
 var vcsFossil = &Cmd{
-       Name: "Fossil",
-       Cmd:  "fossil",
+       Name:      "Fossil",
+       Cmd:       "fossil",
+       RootNames: []string{".fslckout", "_FOSSIL_"},
 
        CreateCmd:   []string{"-go-internal-mkdir {dir} clone -- {repo} " + filepath.Join("{dir}", fossilRepoName), "-go-internal-cd {dir} open .fossil"},
        DownloadCmd: []string{"up"},
@@ -358,6 +513,7 @@ var vcsFossil = &Cmd{
 
        Scheme:     []string{"https", "http"},
        RemoteRepo: fossilRemoteRepo,
+       Status:     fossilStatus,
 }
 
 func fossilRemoteRepo(vcsFossil *Cmd, rootDir string) (remoteRepo string, err error) {
@@ -368,6 +524,60 @@ func fossilRemoteRepo(vcsFossil *Cmd, rootDir string) (remoteRepo string, err er
        return strings.TrimSpace(string(out)), nil
 }
 
+var errFossilInfo = errors.New("unable to parse output of fossil info")
+
+func fossilStatus(vcsFossil *Cmd, rootDir string) (Status, error) {
+       outb, err := vcsFossil.runOutputVerboseOnly(rootDir, "info")
+       if err != nil {
+               return Status{}, err
+       }
+       out := string(outb)
+
+       // Expect:
+       // ...
+       // checkout:     91ed71f22c77be0c3e250920f47bfd4e1f9024d2 2021-09-21 12:00:00 UTC
+       // ...
+
+       // Extract revision and commit time.
+       // Ensure line ends with UTC (known timezone offset).
+       const prefix = "\ncheckout:"
+       const suffix = " UTC"
+       i := strings.Index(out, prefix)
+       if i < 0 {
+               return Status{}, errFossilInfo
+       }
+       checkout := out[i+len(prefix):]
+       i = strings.Index(checkout, suffix)
+       if i < 0 {
+               return Status{}, errFossilInfo
+       }
+       checkout = strings.TrimSpace(checkout[:i])
+
+       i = strings.IndexByte(checkout, ' ')
+       if i < 0 {
+               return Status{}, errFossilInfo
+       }
+       rev := checkout[:i]
+
+       commitTime, err := time.ParseInLocation("2006-01-02 15:04:05", checkout[i+1:], time.UTC)
+       if err != nil {
+               return Status{}, fmt.Errorf("%v: %v", errFossilInfo, err)
+       }
+
+       // Also look for untracked changes.
+       outb, err = vcsFossil.runOutputVerboseOnly(rootDir, "changes --differ")
+       if err != nil {
+               return Status{}, err
+       }
+       uncommitted := len(outb) > 0
+
+       return Status{
+               Revision:    rev,
+               CommitTime:  commitTime,
+               Uncommitted: uncommitted,
+       }, nil
+}
+
 func (v *Cmd) String() string {
        return v.Name
 }
@@ -395,6 +605,12 @@ func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error
        return v.run1(dir, cmd, keyval, true)
 }
 
+// runOutputVerboseOnly is like runOutput but only generates error output to
+// standard error in verbose mode.
+func (v *Cmd) runOutputVerboseOnly(dir string, cmd string, keyval ...string) ([]byte, error) {
+       return v.run1(dir, cmd, keyval, false)
+}
+
 // run1 is the generalized implementation of run and runOutput.
 func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
        m := make(map[string]string)
@@ -550,58 +766,86 @@ type vcsPath struct {
 
 // FromDir inspects dir and its parents to determine the
 // version control system and code repository to use.
-// On return, root is the import path
-// corresponding to the root of the repository.
-func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) {
+// If no repository is found, FromDir returns an error
+// equivalent to os.ErrNotExist.
+func FromDir(dir, srcRoot string, allowNesting bool) (repoDir string, vcsCmd *Cmd, err error) {
        // Clean and double-check that dir is in (a subdirectory of) srcRoot.
        dir = filepath.Clean(dir)
-       srcRoot = filepath.Clean(srcRoot)
-       if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
-               return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
+       if srcRoot != "" {
+               srcRoot = filepath.Clean(srcRoot)
+               if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
+                       return "", nil, fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
+               }
        }
 
-       var vcsRet *Cmd
-       var rootRet string
-
        origDir := dir
        for len(dir) > len(srcRoot) {
                for _, vcs := range vcsList {
-                       if _, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil {
-                               root := filepath.ToSlash(dir[len(srcRoot)+1:])
-                               // Record first VCS we find, but keep looking,
-                               // to detect mistakes like one kind of VCS inside another.
-                               if vcsRet == nil {
-                                       vcsRet = vcs
-                                       rootRet = root
+                       if _, err := statAny(dir, vcs.RootNames); err == nil {
+                               // Record first VCS we find.
+                               // If allowNesting is false (as it is in GOPATH), keep looking for
+                               // repositories in parent directories and report an error if one is
+                               // found to mitigate VCS injection attacks.
+                               if vcsCmd == nil {
+                                       vcsCmd = vcs
+                                       repoDir = dir
+                                       if allowNesting {
+                                               return repoDir, vcsCmd, nil
+                                       }
                                        continue
                                }
                                // Allow .git inside .git, which can arise due to submodules.
-                               if vcsRet == vcs && vcs.Cmd == "git" {
+                               if vcsCmd == vcs && vcs.Cmd == "git" {
                                        continue
                                }
                                // Otherwise, we have one VCS inside a different VCS.
-                               return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
-                                       filepath.Join(srcRoot, rootRet), vcsRet.Cmd, filepath.Join(srcRoot, root), vcs.Cmd)
+                               return "", nil, fmt.Errorf("directory %q uses %s, but parent %q uses %s",
+                                       repoDir, vcsCmd.Cmd, dir, vcs.Cmd)
                        }
                }
 
                // Move to parent.
                ndir := filepath.Dir(dir)
                if len(ndir) >= len(dir) {
-                       // Shouldn't happen, but just in case, stop.
                        break
                }
                dir = ndir
        }
+       if vcsCmd == nil {
+               return "", nil, &vcsNotFoundError{dir: origDir}
+       }
+       return repoDir, vcsCmd, nil
+}
+
+// statAny provides FileInfo for the first filename found in the directory.
+// Otherwise, it returns the last error seen.
+func statAny(dir string, filenames []string) (os.FileInfo, error) {
+       if len(filenames) == 0 {
+               return nil, errors.New("invalid argument: no filenames provided")
+       }
 
-       if vcsRet != nil {
-               if err := checkGOVCS(vcsRet, rootRet); err != nil {
-                       return nil, "", err
+       var err error
+       var fi os.FileInfo
+       for _, name := range filenames {
+               fi, err = os.Stat(filepath.Join(dir, name))
+               if err == nil {
+                       return fi, nil
                }
-               return vcsRet, rootRet, nil
        }
 
-       return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
+       return nil, err
+}
+
+type vcsNotFoundError struct {
+       dir string
+}
+
+func (e *vcsNotFoundError) Error() string {
+       return fmt.Sprintf("directory %q is not using a known version control system", e.dir)
+}
+
+func (e *vcsNotFoundError) Is(err error) bool {
+       return err == os.ErrNotExist
 }
 
 // A govcsRule is a single GOVCS rule like private:hg|svn.
@@ -707,7 +951,11 @@ var defaultGOVCS = govcsConfig{
        {"public", []string{"git", "hg"}},
 }
 
-func checkGOVCS(vcs *Cmd, root string) error {
+// CheckGOVCS checks whether the policy defined by the environment variable
+// GOVCS allows the given vcs command to be used with the given repository
+// root path. Note that root may not be a real package or module path; it's
+// the same as the root path in the go-import meta tag.
+func CheckGOVCS(vcs *Cmd, root string) error {
        if vcs == vcsMod {
                // Direct module (proxy protocol) fetches don't
                // involve an external version control system
@@ -745,7 +993,7 @@ func CheckNested(vcs *Cmd, dir, srcRoot string) error {
        otherDir := dir
        for len(otherDir) > len(srcRoot) {
                for _, otherVCS := range vcsList {
-                       if _, err := os.Stat(filepath.Join(otherDir, "."+otherVCS.Cmd)); err == nil {
+                       if _, err := statAny(otherDir, otherVCS.RootNames); err == nil {
                                // Allow expected vcs in original dir.
                                if otherDir == dir && otherVCS == vcs {
                                        continue
@@ -885,7 +1133,7 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths
                if vcs == nil {
                        return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
                }
-               if err := checkGOVCS(vcs, match["root"]); err != nil {
+               if err := CheckGOVCS(vcs, match["root"]); err != nil {
                        return nil, err
                }
                var repoURL string
@@ -1012,7 +1260,7 @@ func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.Se
                }
        }
 
-       if err := checkGOVCS(vcs, mmi.Prefix); err != nil {
+       if err := CheckGOVCS(vcs, mmi.Prefix); err != nil {
                return nil, err
        }
 
index c5c7a3283bce57d1fbc8ac0c09549fe80ace5290..c4e4f4d3c6a6c43106e3731811baf027db6e9361 100644 (file)
@@ -6,9 +6,9 @@ package vcs
 
 import (
        "errors"
+       "fmt"
        "internal/testenv"
        "os"
-       "path"
        "path/filepath"
        "strings"
        "testing"
@@ -205,7 +205,8 @@ func TestRepoRootForImportPath(t *testing.T) {
        }
 }
 
-// Test that vcsFromDir correctly inspects a given directory and returns the right VCS and root.
+// Test that vcs.FromDir correctly inspects a given directory and returns the
+// right VCS and repo directory.
 func TestFromDir(t *testing.T) {
        tempDir, err := os.MkdirTemp("", "vcstest")
        if err != nil {
@@ -214,36 +215,35 @@ func TestFromDir(t *testing.T) {
        defer os.RemoveAll(tempDir)
 
        for j, vcs := range vcsList {
-               dir := filepath.Join(tempDir, "example.com", vcs.Name, "."+vcs.Cmd)
-               if j&1 == 0 {
-                       err := os.MkdirAll(dir, 0755)
-                       if err != nil {
-                               t.Fatal(err)
+               for r, rootName := range vcs.RootNames {
+                       vcsName := fmt.Sprint(vcs.Name, r)
+                       dir := filepath.Join(tempDir, "example.com", vcsName, rootName)
+                       if j&1 == 0 {
+                               err := os.MkdirAll(dir, 0755)
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                       } else {
+                               err := os.MkdirAll(filepath.Dir(dir), 0755)
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                               f, err := os.Create(dir)
+                               if err != nil {
+                                       t.Fatal(err)
+                               }
+                               f.Close()
                        }
-               } else {
-                       err := os.MkdirAll(filepath.Dir(dir), 0755)
+
+                       wantRepoDir := filepath.Dir(dir)
+                       gotRepoDir, gotVCS, err := FromDir(dir, tempDir, false)
                        if err != nil {
-                               t.Fatal(err)
+                               t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
+                               continue
                        }
-                       f, err := os.Create(dir)
-                       if err != nil {
-                               t.Fatal(err)
+                       if gotRepoDir != wantRepoDir || gotVCS.Name != vcs.Name {
+                               t.Errorf("FromDir(%q, %q) = RepoDir(%s), VCS(%s); want RepoDir(%s), VCS(%s)", dir, tempDir, gotRepoDir, gotVCS.Name, wantRepoDir, vcs.Name)
                        }
-                       f.Close()
-               }
-
-               want := RepoRoot{
-                       VCS:  vcs,
-                       Root: path.Join("example.com", vcs.Name),
-               }
-               var got RepoRoot
-               got.VCS, got.Root, err = FromDir(dir, tempDir)
-               if err != nil {
-                       t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
-                       continue
-               }
-               if got.VCS.Name != want.VCS.Name || got.Root != want.Root {
-                       t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.VCS, got.Root, want.VCS, want.Root)
                }
        }
 }
diff --git a/src/cmd/go/internal/version/exe.go b/src/cmd/go/internal/version/exe.go
deleted file mode 100644 (file)
index 0e7deef..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-// 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 version
-
-import (
-       "bytes"
-       "debug/elf"
-       "debug/macho"
-       "debug/pe"
-       "fmt"
-       "internal/xcoff"
-       "io"
-       "os"
-)
-
-// An exe is a generic interface to an OS executable (ELF, Mach-O, PE, XCOFF).
-type exe interface {
-       // Close closes the underlying file.
-       Close() error
-
-       // ReadData reads and returns up to size byte starting at virtual address addr.
-       ReadData(addr, size uint64) ([]byte, error)
-
-       // DataStart returns the writable data segment start address.
-       DataStart() uint64
-}
-
-// openExe opens file and returns it as an exe.
-func openExe(file string) (exe, error) {
-       f, err := os.Open(file)
-       if err != nil {
-               return nil, err
-       }
-       data := make([]byte, 16)
-       if _, err := io.ReadFull(f, data); err != nil {
-               return nil, err
-       }
-       f.Seek(0, 0)
-       if bytes.HasPrefix(data, []byte("\x7FELF")) {
-               e, err := elf.NewFile(f)
-               if err != nil {
-                       f.Close()
-                       return nil, err
-               }
-               return &elfExe{f, e}, nil
-       }
-       if bytes.HasPrefix(data, []byte("MZ")) {
-               e, err := pe.NewFile(f)
-               if err != nil {
-                       f.Close()
-                       return nil, err
-               }
-               return &peExe{f, e}, nil
-       }
-       if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) {
-               e, err := macho.NewFile(f)
-               if err != nil {
-                       f.Close()
-                       return nil, err
-               }
-               return &machoExe{f, e}, nil
-       }
-       if bytes.HasPrefix(data, []byte{0x01, 0xDF}) || bytes.HasPrefix(data, []byte{0x01, 0xF7}) {
-               e, err := xcoff.NewFile(f)
-               if err != nil {
-                       f.Close()
-                       return nil, err
-               }
-               return &xcoffExe{f, e}, nil
-
-       }
-       return nil, fmt.Errorf("unrecognized executable format")
-}
-
-// elfExe is the ELF implementation of the exe interface.
-type elfExe struct {
-       os *os.File
-       f  *elf.File
-}
-
-func (x *elfExe) Close() error {
-       return x.os.Close()
-}
-
-func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
-       for _, prog := range x.f.Progs {
-               if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {
-                       n := prog.Vaddr + prog.Filesz - addr
-                       if n > size {
-                               n = size
-                       }
-                       data := make([]byte, n)
-                       _, err := prog.ReadAt(data, int64(addr-prog.Vaddr))
-                       if err != nil {
-                               return nil, err
-                       }
-                       return data, nil
-               }
-       }
-       return nil, fmt.Errorf("address not mapped")
-}
-
-func (x *elfExe) DataStart() uint64 {
-       for _, s := range x.f.Sections {
-               if s.Name == ".go.buildinfo" {
-                       return s.Addr
-               }
-       }
-       for _, p := range x.f.Progs {
-               if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W {
-                       return p.Vaddr
-               }
-       }
-       return 0
-}
-
-// peExe is the PE (Windows Portable Executable) implementation of the exe interface.
-type peExe struct {
-       os *os.File
-       f  *pe.File
-}
-
-func (x *peExe) Close() error {
-       return x.os.Close()
-}
-
-func (x *peExe) imageBase() uint64 {
-       switch oh := x.f.OptionalHeader.(type) {
-       case *pe.OptionalHeader32:
-               return uint64(oh.ImageBase)
-       case *pe.OptionalHeader64:
-               return oh.ImageBase
-       }
-       return 0
-}
-
-func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
-       addr -= x.imageBase()
-       for _, sect := range x.f.Sections {
-               if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
-                       n := uint64(sect.VirtualAddress+sect.Size) - addr
-                       if n > size {
-                               n = size
-                       }
-                       data := make([]byte, n)
-                       _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
-                       if err != nil {
-                               return nil, err
-                       }
-                       return data, nil
-               }
-       }
-       return nil, fmt.Errorf("address not mapped")
-}
-
-func (x *peExe) DataStart() uint64 {
-       // Assume data is first writable section.
-       const (
-               IMAGE_SCN_CNT_CODE               = 0x00000020
-               IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
-               IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
-               IMAGE_SCN_MEM_EXECUTE            = 0x20000000
-               IMAGE_SCN_MEM_READ               = 0x40000000
-               IMAGE_SCN_MEM_WRITE              = 0x80000000
-               IMAGE_SCN_MEM_DISCARDABLE        = 0x2000000
-               IMAGE_SCN_LNK_NRELOC_OVFL        = 0x1000000
-               IMAGE_SCN_ALIGN_32BYTES          = 0x600000
-       )
-       for _, sect := range x.f.Sections {
-               if sect.VirtualAddress != 0 && sect.Size != 0 &&
-                       sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE {
-                       return uint64(sect.VirtualAddress) + x.imageBase()
-               }
-       }
-       return 0
-}
-
-// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface.
-type machoExe struct {
-       os *os.File
-       f  *macho.File
-}
-
-func (x *machoExe) Close() error {
-       return x.os.Close()
-}
-
-func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
-       for _, load := range x.f.Loads {
-               seg, ok := load.(*macho.Segment)
-               if !ok {
-                       continue
-               }
-               if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 {
-                       if seg.Name == "__PAGEZERO" {
-                               continue
-                       }
-                       n := seg.Addr + seg.Filesz - addr
-                       if n > size {
-                               n = size
-                       }
-                       data := make([]byte, n)
-                       _, err := seg.ReadAt(data, int64(addr-seg.Addr))
-                       if err != nil {
-                               return nil, err
-                       }
-                       return data, nil
-               }
-       }
-       return nil, fmt.Errorf("address not mapped")
-}
-
-func (x *machoExe) DataStart() uint64 {
-       // Look for section named "__go_buildinfo".
-       for _, sec := range x.f.Sections {
-               if sec.Name == "__go_buildinfo" {
-                       return sec.Addr
-               }
-       }
-       // Try the first non-empty writable segment.
-       const RW = 3
-       for _, load := range x.f.Loads {
-               seg, ok := load.(*macho.Segment)
-               if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW {
-                       return seg.Addr
-               }
-       }
-       return 0
-}
-
-// xcoffExe is the XCOFF (AIX eXtended COFF) implementation of the exe interface.
-type xcoffExe struct {
-       os *os.File
-       f  *xcoff.File
-}
-
-func (x *xcoffExe) Close() error {
-       return x.os.Close()
-}
-
-func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) {
-       for _, sect := range x.f.Sections {
-               if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
-                       n := uint64(sect.VirtualAddress+sect.Size) - addr
-                       if n > size {
-                               n = size
-                       }
-                       data := make([]byte, n)
-                       _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
-                       if err != nil {
-                               return nil, err
-                       }
-                       return data, nil
-               }
-       }
-       return nil, fmt.Errorf("address not mapped")
-}
-
-func (x *xcoffExe) DataStart() uint64 {
-       return x.f.SectionByType(xcoff.STYP_DATA).VirtualAddress
-}
index 58cbd32e78d1158700c64c2d207f40e4456802c1..febc7c638ae9ed33f61d09022570af2eb80faecf 100644 (file)
@@ -8,7 +8,8 @@ package version
 import (
        "bytes"
        "context"
-       "encoding/binary"
+       "debug/buildinfo"
+       "errors"
        "fmt"
        "io/fs"
        "os"
@@ -62,8 +63,14 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) {
                // a reasonable use case. For example, imagine GOFLAGS=-v to
                // turn "verbose mode" on for all Go commands, which should not
                // break "go version".
-               if (!base.InGOFLAGS("-m") && *versionM) || (!base.InGOFLAGS("-v") && *versionV) {
-                       fmt.Fprintf(os.Stderr, "go version: flags can only be used with arguments\n")
+               var argOnlyFlag string
+               if !base.InGOFLAGS("-m") && *versionM {
+                       argOnlyFlag = "-m"
+               } else if !base.InGOFLAGS("-v") && *versionV {
+                       argOnlyFlag = "-v"
+               }
+               if argOnlyFlag != "" {
+                       fmt.Fprintf(os.Stderr, "go: 'go version' only accepts %s flag with arguments\n", argOnlyFlag)
                        base.SetExitStatus(2)
                        return
                }
@@ -135,90 +142,25 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) {
                return
        }
 
-       x, err := openExe(file)
+       bi, err := buildinfo.ReadFile(file)
        if err != nil {
                if mustPrint {
-                       fmt.Fprintf(os.Stderr, "%s: %v\n", file, err)
-               }
-               return
-       }
-       defer x.Close()
-
-       vers, mod := findVers(x)
-       if vers == "" {
-               if mustPrint {
-                       fmt.Fprintf(os.Stderr, "%s: go version not found\n", file)
+                       if pathErr := (*os.PathError)(nil); errors.As(err, &pathErr) && filepath.Clean(pathErr.Path) == filepath.Clean(file) {
+                               fmt.Fprintf(os.Stderr, "%v\n", file)
+                       } else {
+                               fmt.Fprintf(os.Stderr, "%s: %v\n", file, err)
+                       }
                }
-               return
-       }
-
-       fmt.Printf("%s: %s\n", file, vers)
-       if *versionM && mod != "" {
-               fmt.Printf("\t%s\n", strings.ReplaceAll(mod[:len(mod)-1], "\n", "\n\t"))
        }
-}
 
-// The build info blob left by the linker is identified by
-// a 16-byte header, consisting of buildInfoMagic (14 bytes),
-// the binary's pointer size (1 byte),
-// and whether the binary is big endian (1 byte).
-var buildInfoMagic = []byte("\xff Go buildinf:")
-
-// findVers finds and returns the Go version and module version information
-// in the executable x.
-func findVers(x exe) (vers, mod string) {
-       // Read the first 64kB of text to find the build info blob.
-       text := x.DataStart()
-       data, err := x.ReadData(text, 64*1024)
+       fmt.Printf("%s: %s\n", file, bi.GoVersion)
+       bi.GoVersion = "" // suppress printing go version again
+       mod, err := bi.MarshalText()
        if err != nil {
+               fmt.Fprintf(os.Stderr, "%s: formatting build info: %v\n", file, err)
                return
        }
-       for ; !bytes.HasPrefix(data, buildInfoMagic); data = data[32:] {
-               if len(data) < 32 {
-                       return
-               }
-       }
-
-       // Decode the blob.
-       ptrSize := int(data[14])
-       bigEndian := data[15] != 0
-       var bo binary.ByteOrder
-       if bigEndian {
-               bo = binary.BigEndian
-       } else {
-               bo = binary.LittleEndian
-       }
-       var readPtr func([]byte) uint64
-       if ptrSize == 4 {
-               readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) }
-       } else {
-               readPtr = bo.Uint64
-       }
-       vers = readString(x, ptrSize, readPtr, readPtr(data[16:]))
-       if vers == "" {
-               return
-       }
-       mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:]))
-       if len(mod) >= 33 && mod[len(mod)-17] == '\n' {
-               // Strip module framing.
-               mod = mod[16 : len(mod)-16]
-       } else {
-               mod = ""
-       }
-       return
-}
-
-// readString returns the string at address addr in the executable x.
-func readString(x exe, ptrSize int, readPtr func([]byte) uint64, addr uint64) string {
-       hdr, err := x.ReadData(addr, uint64(2*ptrSize))
-       if err != nil || len(hdr) < 2*ptrSize {
-               return ""
-       }
-       dataAddr := readPtr(hdr)
-       dataLen := readPtr(hdr[ptrSize:])
-       data, err := x.ReadData(dataAddr, dataLen)
-       if err != nil || uint64(len(data)) < dataLen {
-               return ""
+       if *versionM && len(mod) > 0 {
+               fmt.Printf("\t%s\n", bytes.ReplaceAll(mod[:len(mod)-1], []byte("\n"), []byte("\n\t")))
        }
-       return string(data)
 }
index 1d419dddb98d6cdcc53ef5e3e6eb67b477531988..88b3c570a03b5c52328eaf745dc795d86174c830 100644 (file)
@@ -103,7 +103,7 @@ func runVet(ctx context.Context, cmd *base.Command, args []string) {
                        continue
                }
                if len(ptest.GoFiles) == 0 && len(ptest.CgoFiles) == 0 && pxtest == nil {
-                       base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir)
+                       base.Errorf("go: can't vet %s: no Go files in %s", p.ImportPath, p.Dir)
                        continue
                }
                if len(ptest.GoFiles) > 0 || len(ptest.CgoFiles) > 0 {
index b5b3c462ff2acced306e495a173b43be76fd579b..3551a5997c5f887d5c3f9f8dd00ac462a902f46b 100644 (file)
@@ -82,7 +82,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
        vetcmd := exec.Command(tool, "-flags")
        vetcmd.Stdout = out
        if err := vetcmd.Run(); err != nil {
-               fmt.Fprintf(os.Stderr, "go vet: can't execute %s -flags: %v\n", tool, err)
+               fmt.Fprintf(os.Stderr, "go: can't execute %s -flags: %v\n", tool, err)
                base.SetExitStatus(2)
                base.Exit()
        }
@@ -92,7 +92,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
                Usage string
        }
        if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil {
-               fmt.Fprintf(os.Stderr, "go vet: can't unmarshal JSON from %s -flags: %v", tool, err)
+               fmt.Fprintf(os.Stderr, "go: can't unmarshal JSON from %s -flags: %v", tool, err)
                base.SetExitStatus(2)
                base.Exit()
        }
index 08686cdfcf9f4c11e96587a99738a09aa62b4324..ab88e9e4781f4666c9102104d4e1eccf7948c90b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cmd_go_bootstrap
-// +build cmd_go_bootstrap
 
 // This code is compiled only into the bootstrap 'go' binary.
 // These stubs avoid importing packages with large dependency
index f177278eba1e7d9088014ee0ae246e2efb0dca39..a92326db01e629093235ad88d809329bcadb1ab9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !cmd_go_bootstrap
-// +build !cmd_go_bootstrap
 
 // This code is compiled into the real 'go' binary, but it is not
 // compiled into the binary that is built during all.bash, so as
@@ -17,6 +16,7 @@ import (
        "errors"
        "fmt"
        "mime"
+       "net"
        "net/http"
        urlpkg "net/url"
        "os"
@@ -84,8 +84,15 @@ func get(security SecurityMode, url *urlpkg.URL) (*Response, error) {
        if url.Host == "localhost.localdev" {
                return nil, fmt.Errorf("no such host localhost.localdev")
        }
-       if os.Getenv("TESTGONETWORK") == "panic" && !strings.HasPrefix(url.Host, "127.0.0.1") && !strings.HasPrefix(url.Host, "0.0.0.0") {
-               panic("use of network: " + url.String())
+       if os.Getenv("TESTGONETWORK") == "panic" {
+               host := url.Host
+               if h, _, err := net.SplitHostPort(url.Host); err == nil && h != "" {
+                       host = h
+               }
+               addr := net.ParseIP(host)
+               if addr == nil || (!addr.IsLoopback() && !addr.IsUnspecified()) {
+                       panic("use of network: " + url.String())
+               }
        }
 
        fetch := func(url *urlpkg.URL) (*urlpkg.URL, *http.Response, error) {
index 453af402b43dd9eb9208af234701127cfa887f25..84bbd72820fcab516624f09755265dcd97f0f81d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows
-// +build !windows
 
 package web
 
index 4d6ed2ec7f8c1dd0d9ab90f83f4478057c36b46d..5c197de800dc1f31e73ca132da21218f7c8df148 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows
-// +build !windows
 
 package web
 
index 69940cb00159b64c60024a9f248e5a0db337b266..6f5ac1364cc90ed4c14700506cf64ab15fc6f3b3 100644 (file)
@@ -294,14 +294,14 @@ func (b *Builder) Init() {
        }
 
        if err := CheckGOOSARCHPair(cfg.Goos, cfg.Goarch); err != nil {
-               fmt.Fprintf(os.Stderr, "cmd/go: %v\n", err)
+               fmt.Fprintf(os.Stderr, "go: %v\n", err)
                base.SetExitStatus(2)
                base.Exit()
        }
 
        for _, tag := range cfg.BuildContext.BuildTags {
                if strings.Contains(tag, ",") {
-                       fmt.Fprintf(os.Stderr, "cmd/go: -tags space-separated list contains comma\n")
+                       fmt.Fprintf(os.Stderr, "go: -tags space-separated list contains comma\n")
                        base.SetExitStatus(2)
                        base.Exit()
                }
index 0ed2389cd5a81af6f3ff862dd275b9fb9ba0109e..9d0ad27f0dc7b7d284d582ca5450fc44048b780b 100644 (file)
@@ -68,13 +68,16 @@ and test commands:
                The default is GOMAXPROCS, normally the number of CPUs available.
        -race
                enable data race detection.
-               Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64,
+               Supported only on linux/amd64, freebsd/amd64, darwin/amd64, darwin/arm64, windows/amd64,
                linux/ppc64le and linux/arm64 (only for 48-bit VMA).
        -msan
                enable interoperation with memory sanitizer.
                Supported only on linux/amd64, linux/arm64
                and only with Clang/LLVM as the host C compiler.
                On linux/arm64, pie build mode will be used.
+       -asan
+               enable interoperation with address sanitizer.
+               Supported only on linux/arm64, linux/amd64.
        -v
                print the names of packages as they are compiled.
        -work
@@ -85,8 +88,19 @@ and test commands:
 
        -asmflags '[pattern=]arg list'
                arguments to pass on each go tool asm invocation.
+       -buildinfo
+               Whether to stamp binaries with build flags. By default, the compiler name
+               (gc or gccgo), toolchain flags (like -gcflags), and environment variables
+               containing flags (like CGO_CFLAGS) are stamped into binaries. Use
+               -buildinfo=false to omit build information. See also -buildvcs.
        -buildmode mode
                build mode to use. See 'go help buildmode' for more.
+       -buildvcs
+               Whether to stamp binaries with version control information. By default,
+               version control information is stamped into a binary if the main package
+               and the main module containing it are in the repository containing the
+               current directory (if there is a repository). Use -buildvcs=false to
+               omit version control information. See also -buildinfo.
        -compiler name
                name of compiler to use, as in runtime.Compiler (gccgo or gc).
        -gccgoflags '[pattern=]arg list'
@@ -98,8 +112,8 @@ and test commands:
                in order to keep output separate from default builds.
                If using the -race flag, the install suffix is automatically set to race
                or, if set explicitly, has _race appended to it. Likewise for the -msan
-               flag. Using a -buildmode option that requires non-default compile flags
-               has a similar effect.
+               and -asan flags. Using a -buildmode option that requires non-default compile
+               flags has a similar effect.
        -ldflags '[pattern=]arg list'
                arguments to pass on each go tool link invocation.
        -linkshared
@@ -121,6 +135,14 @@ and test commands:
                directory, but it is not accessed. When -modfile is specified, an
                alternate go.sum file is also used: its path is derived from the
                -modfile flag by trimming the ".mod" extension and appending ".sum".
+       -workfile file
+               in module aware mode, use the given go.work file as a workspace file.
+               By default or when -workfile is "auto", the go command searches for a
+               file named go.work in the current directory and then containing directories
+               until one is found. If a valid go.work file is found, the modules
+               specified will collectively be used as the main modules. If -workfile
+               is "off", or a go.work file is not found in "auto" mode, workspace
+               mode is disabled.
        -overlay file
                read a JSON config file that provides an overlay for build operations.
                The file is a JSON struct with a single field, named 'Replace', that
@@ -201,6 +223,7 @@ func init() {
 
        AddBuildFlags(CmdBuild, DefaultBuildFlags)
        AddBuildFlags(CmdInstall, DefaultBuildFlags)
+       base.AddWorkfileFlag(&CmdBuild.Flag)
 }
 
 // Note that flags consulted by other parts of the code
@@ -289,10 +312,13 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
        cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "")
        cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "")
        cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "")
+       cmd.Flag.BoolVar(&cfg.BuildASan, "asan", false, "")
        cmd.Flag.Var((*tagsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
        cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
        cmd.Flag.BoolVar(&cfg.BuildTrimpath, "trimpath", false, "")
        cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
+       cmd.Flag.BoolVar(&cfg.BuildBuildinfo, "buildinfo", true, "")
+       cmd.Flag.BoolVar(&cfg.BuildBuildvcs, "buildvcs", true, "")
 
        // Undocumented, unstable debugging flags.
        cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
@@ -364,6 +390,7 @@ var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
 var runtimeVersion = runtime.Version()
 
 func runBuild(ctx context.Context, cmd *base.Command, args []string) {
+       modload.InitWorkfile()
        BuildInit()
        var b Builder
        b.Init()
@@ -396,7 +423,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) {
        depMode := ModeBuild
        if cfg.BuildI {
                depMode = ModeInstall
-               fmt.Fprint(os.Stderr, "go build: -i flag is deprecated\n")
+               fmt.Fprint(os.Stderr, "go: -i flag is deprecated\n")
        }
 
        pkgs = omitTestOnly(pkgsFilter(pkgs))
@@ -415,7 +442,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) {
                        strings.HasSuffix(cfg.BuildO, "/") ||
                        strings.HasSuffix(cfg.BuildO, string(os.PathSeparator)) {
                        if !explicitO {
-                               base.Fatalf("go build: build output %q already exists and is a directory", cfg.BuildO)
+                               base.Fatalf("go: build output %q already exists and is a directory", cfg.BuildO)
                        }
                        a := &Action{Mode: "go build"}
                        for _, p := range pkgs {
@@ -430,13 +457,13 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) {
                                a.Deps = append(a.Deps, b.AutoAction(ModeInstall, depMode, p))
                        }
                        if len(a.Deps) == 0 {
-                               base.Fatalf("go build: no main packages to build")
+                               base.Fatalf("go: no main packages to build")
                        }
                        b.Do(ctx, a)
                        return
                }
                if len(pkgs) > 1 {
-                       base.Fatalf("go build: cannot write multiple packages to non-directory %s", cfg.BuildO)
+                       base.Fatalf("go: cannot write multiple packages to non-directory %s", cfg.BuildO)
                } else if len(pkgs) == 0 {
                        base.Fatalf("no packages to build")
                }
@@ -486,14 +513,17 @@ allowed, even if they refer to the same version.
 
 - All arguments must refer to packages in the same module at the same version.
 
+- Package path arguments must refer to main packages. Pattern arguments
+will only match main packages.
+
 - No module is considered the "main" module. If the module containing
 packages named on the command line has a go.mod file, it must not contain
 directives (replace and exclude) that would cause it to be interpreted
 differently than if it were the main module. The module must not require
 a higher version of itself.
 
-- Package path arguments must refer to main packages. Pattern arguments
-will only match main packages.
+- Vendor directories are not used in any module. (Vendor directories are not
+included in the module zip files downloaded by 'go install'.)
 
 If the arguments don't have version suffixes, "go install" may run in
 module-aware mode or GOPATH mode, depending on the GO111MODULE environment
@@ -580,7 +610,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) {
        for _, arg := range args {
                if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) {
                        if cfg.BuildI {
-                               fmt.Fprint(os.Stderr, "go install: -i flag is deprecated\n")
+                               fmt.Fprint(os.Stderr, "go: -i flag is deprecated\n")
                        }
                        installOutsideModule(ctx, args)
                        return
@@ -608,7 +638,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) {
                                latestArgs[i] = args[i] + "@latest"
                        }
                        hint := strings.Join(latestArgs, " ")
-                       base.Fatalf("go install: version is required when current directory is not in a module\n\tTry 'go install %s' to install the latest version", hint)
+                       base.Fatalf("go: 'go install' requires a version when current directory is not in a module\n\tTry 'go install %s' to install the latest version", hint)
                }
        }
        load.CheckPackageErrors(pkgs)
@@ -621,7 +651,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) {
                        }
                }
                if !allGoroot {
-                       fmt.Fprint(os.Stderr, "go install: -i flag is deprecated\n")
+                       fmt.Fprintf(os.Stderr, "go: -i flag is deprecated\n")
                }
        }
 
@@ -667,14 +697,14 @@ func InstallPackages(ctx context.Context, patterns []string, pkgs []*load.Packag
                        case p.Name != "main" && p.Module != nil:
                                // Non-executables have no target (except the cache) when building with modules.
                        case p.Internal.GobinSubdir:
-                               base.Errorf("go %s: cannot install cross-compiled binaries when GOBIN is set", cfg.CmdName)
+                               base.Errorf("go: cannot install cross-compiled binaries when GOBIN is set")
                        case p.Internal.CmdlineFiles:
-                               base.Errorf("go %s: no install location for .go files listed on command line (GOBIN not set)", cfg.CmdName)
+                               base.Errorf("go: no install location for .go files listed on command line (GOBIN not set)")
                        case p.ConflictDir != "":
-                               base.Errorf("go %s: no install location for %s: hidden by %s", cfg.CmdName, p.Dir, p.ConflictDir)
+                               base.Errorf("go: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
                        default:
-                               base.Errorf("go %s: no install location for directory %s outside GOPATH\n"+
-                                       "\tFor more details see: 'go help gopath'", cfg.CmdName, p.Dir)
+                               base.Errorf("go: no install location for directory %s outside GOPATH\n"+
+                                       "\tFor more details see: 'go help gopath'", p.Dir)
                        }
                }
        }
@@ -769,7 +799,7 @@ func installOutsideModule(ctx context.Context, args []string) {
        pkgOpts := load.PackageOpts{MainOnly: true}
        pkgs, err := load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args)
        if err != nil {
-               base.Fatalf("go install: %v", err)
+               base.Fatalf("go: %v", err)
        }
        load.CheckPackageErrors(pkgs)
        patterns := make([]string, len(args))
index 15f944d2af219e398a59b68ae1ab3f0a5edb6690..d4f2a716d7b98c76dabbc5ff0e592a2adf7f04ee 100644 (file)
@@ -16,7 +16,7 @@ import (
        "cmd/go/internal/cfg"
        "cmd/go/internal/fsys"
        "cmd/internal/buildid"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 // Build IDs
index 2aa099bf1716adde033ffc6953a4e1b47d67d0ac..03f8866cf2cc210e9840d420fee0adeea926f1cc 100644 (file)
@@ -34,8 +34,10 @@ import (
        "cmd/go/internal/fsys"
        "cmd/go/internal/load"
        "cmd/go/internal/modload"
+       "cmd/go/internal/str"
        "cmd/go/internal/trace"
-       "cmd/internal/str"
+       "cmd/internal/quoted"
+       "cmd/internal/sys"
 )
 
 // actionList returns the list of actions in the dag rooted at root
@@ -222,18 +224,32 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
        // same compiler settings and can reuse each other's results.
        // If not, the reason is already recorded in buildGcflags.
        fmt.Fprintf(h, "compile\n")
-       // Only include the package directory if it may affect the output.
-       // We trim workspace paths for all packages when -trimpath is set.
-       // The compiler hides the exact value of $GOROOT
-       // when building things in GOROOT.
-       // Assume b.WorkDir is being trimmed properly.
-       // When -trimpath is used with a package built from the module cache,
-       // use the module path and version instead of the directory.
-       if !p.Goroot && !cfg.BuildTrimpath && !strings.HasPrefix(p.Dir, b.WorkDir) {
+
+       // Include information about the origin of the package that
+       // may be embedded in the debug info for the object file.
+       if cfg.BuildTrimpath {
+               // When -trimpath is used with a package built from the module cache,
+               // its debug information refers to the module path and version
+               // instead of the directory.
+               if p.Module != nil {
+                       fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version)
+               }
+       } else if p.Goroot {
+               // The Go compiler always hides the exact value of $GOROOT
+               // when building things in GOROOT, but the C compiler
+               // merely rewrites GOROOT to GOROOT_FINAL.
+               if len(p.CFiles) > 0 {
+                       fmt.Fprintf(h, "goroot %s\n", cfg.GOROOT_FINAL)
+               }
+               // b.WorkDir is always either trimmed or rewritten to
+               // the literal string "/tmp/go-build".
+       } else if !strings.HasPrefix(p.Dir, b.WorkDir) {
+               // -trimpath is not set and no other rewrite rules apply,
+               // so the object file may refer to the absolute directory
+               // containing the package.
                fmt.Fprintf(h, "dir %s\n", p.Dir)
-       } else if cfg.BuildTrimpath && p.Module != nil {
-               fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version)
        }
+
        if p.Module != nil {
                fmt.Fprintf(h, "go %s\n", p.Module.GoVersion)
        }
@@ -281,6 +297,11 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
        if p.Internal.CoverMode != "" {
                fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover"))
        }
+       if p.Internal.FuzzInstrument {
+               if fuzzFlags := fuzzInstrumentFlags(); fuzzFlags != nil {
+                       fmt.Fprintf(h, "fuzz %q\n", fuzzFlags)
+               }
+       }
        fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo)
 
        // Configuration specific to compiler toolchain.
@@ -1487,6 +1508,8 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
                        return nil, nil, errPrintedOutput
                }
                if len(out) > 0 {
+                       // NOTE: we don't attempt to parse quotes and unescapes here. pkg-config
+                       // is typically used within shell backticks, which treats quotes literally.
                        ldflags = strings.Fields(string(out))
                        if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
                                return nil, nil, err
@@ -2429,12 +2452,6 @@ func (b *Builder) gccld(a *Action, p *load.Package, objdir, outfile string, flag
        return err
 }
 
-// Grab these before main helpfully overwrites them.
-var (
-       origCC  = cfg.Getenv("CC")
-       origCXX = cfg.Getenv("CXX")
-)
-
 // gccCmd returns a gcc command line prefix
 // defaultCC is defined in zdefaultcc.go, written by cmd/dist.
 func (b *Builder) GccCmd(incdir, workdir string) []string {
@@ -2454,40 +2471,23 @@ func (b *Builder) gfortranCmd(incdir, workdir string) []string {
 
 // ccExe returns the CC compiler setting without all the extra flags we add implicitly.
 func (b *Builder) ccExe() []string {
-       return b.compilerExe(origCC, cfg.DefaultCC(cfg.Goos, cfg.Goarch))
+       return envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
 }
 
 // cxxExe returns the CXX compiler setting without all the extra flags we add implicitly.
 func (b *Builder) cxxExe() []string {
-       return b.compilerExe(origCXX, cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
+       return envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
 }
 
 // fcExe returns the FC compiler setting without all the extra flags we add implicitly.
 func (b *Builder) fcExe() []string {
-       return b.compilerExe(cfg.Getenv("FC"), "gfortran")
-}
-
-// compilerExe returns the compiler to use given an
-// environment variable setting (the value not the name)
-// and a default. The resulting slice is usually just the name
-// of the compiler but can have additional arguments if they
-// were present in the environment value.
-// For example if CC="gcc -DGOPHER" then the result is ["gcc", "-DGOPHER"].
-func (b *Builder) compilerExe(envValue string, def string) []string {
-       compiler := strings.Fields(envValue)
-       if len(compiler) == 0 {
-               compiler = strings.Fields(def)
-       }
-       return compiler
+       return envList("FC", "gfortran")
 }
 
 // compilerCmd returns a command line prefix for the given environment
 // variable and using the default command when the variable is empty.
 func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string {
-       // NOTE: env.go's mkEnv knows that the first three
-       // strings returned are "gcc", "-I", incdir (and cuts them off).
-       a := []string{compiler[0], "-I", incdir}
-       a = append(a, compiler[1:]...)
+       a := append(compiler, "-I", incdir)
 
        // Definitely want -fPIC but on Windows gcc complains
        // "-fPIC ignored for target (all code is position independent)"
@@ -2658,12 +2658,20 @@ func (b *Builder) gccArchArgs() []string {
 
 // envList returns the value of the given environment variable broken
 // into fields, using the default value when the variable is empty.
+//
+// The environment variable must be quoted correctly for
+// str.SplitQuotedFields. This should be done before building
+// anything, for example, in BuildInit.
 func envList(key, def string) []string {
        v := cfg.Getenv(key)
        if v == "" {
                v = def
        }
-       return strings.Fields(v)
+       args, err := quoted.Split(v)
+       if err != nil {
+               panic(fmt.Sprintf("could not parse environment variable %s with value %q: %v", key, v, err))
+       }
+       return args
 }
 
 // CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
@@ -2729,6 +2737,10 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
                cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
                cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
        }
+       if cfg.BuildASan {
+               cgoCFLAGS = append([]string{"-fsanitize=address"}, cgoCFLAGS...)
+               cgoLDFLAGS = append([]string{"-fsanitize=address"}, cgoLDFLAGS...)
+       }
 
        // Allows including _cgo_export.h, as well as the user's .h files,
        // from .[ch] files in the package.
@@ -2750,7 +2762,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
        if p.Standard && p.ImportPath == "runtime/cgo" {
                cgoflags = append(cgoflags, "-import_runtime_cgo=false")
        }
-       if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") {
+       if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo" || p.ImportPath == "runtime/asan") {
                cgoflags = append(cgoflags, "-import_syscall=false")
        }
 
@@ -2976,18 +2988,24 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
        linkobj := str.StringList(ofile, outObj, mkAbsFiles(p.Dir, p.SysoFiles))
        dynobj := objdir + "_cgo_.o"
 
-       // we need to use -pie for Linux/ARM to get accurate imported sym
        ldflags := cgoLDFLAGS
        if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" {
-               // -static -pie doesn't make sense, and causes link errors.
-               // Issue 26197.
-               n := make([]string, 0, len(ldflags))
-               for _, flag := range ldflags {
-                       if flag != "-static" {
-                               n = append(n, flag)
+               if !str.Contains(ldflags, "-no-pie") {
+                       // we need to use -pie for Linux/ARM to get accurate imported sym (added in https://golang.org/cl/5989058)
+                       // this seems to be outdated, but we don't want to break existing builds depending on this (Issue 45940)
+                       ldflags = append(ldflags, "-pie")
+               }
+               if str.Contains(ldflags, "-pie") && str.Contains(ldflags, "-static") {
+                       // -static -pie doesn't make sense, and causes link errors.
+                       // Issue 26197.
+                       n := make([]string, 0, len(ldflags)-1)
+                       for _, flag := range ldflags {
+                               if flag != "-static" {
+                                       n = append(n, flag)
+                               }
                        }
+                       ldflags = n
                }
-               ldflags = append(n, "-pie")
        }
        if err := b.gccld(a, p, objdir, dynobj, ldflags, linkobj); err != nil {
                return err
@@ -3309,12 +3327,6 @@ func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) {
        return cleanup
 }
 
-// Windows has a limit of 32 KB arguments. To be conservative and not worry
-// about whether that includes spaces or not, just use 30 KB. Darwin's limit is
-// less clear. The OS claims 256KB, but we've seen failures with arglen as
-// small as 50KB.
-const ArgLengthForResponseFile = (30 << 10)
-
 func useResponseFile(path string, argLen int) bool {
        // Unless the program uses objabi.Flagparse, which understands
        // response files, don't use response files.
@@ -3326,7 +3338,7 @@ func useResponseFile(path string, argLen int) bool {
                return false
        }
 
-       if argLen > ArgLengthForResponseFile {
+       if argLen > sys.ExecArgLengthLimit {
                return true
        }
 
index 4eb762cb289d28394668f501d1f54b2902da651e..8bbf25bb337e8b44e49cf56ae3dd8dfba4aafcf7 100644 (file)
@@ -7,6 +7,7 @@ package work
 import (
        "bytes"
        "cmd/internal/objabi"
+       "cmd/internal/sys"
        "fmt"
        "math/rand"
        "testing"
@@ -56,7 +57,7 @@ func TestEncodeDecodeFuzz(t *testing.T) {
        }
        t.Parallel()
 
-       nRunes := ArgLengthForResponseFile + 100
+       nRunes := sys.ExecArgLengthLimit + 100
        rBuffer := make([]rune, nRunes)
        buf := bytes.NewBuffer([]byte(string(rBuffer)))
 
@@ -67,7 +68,7 @@ func TestEncodeDecodeFuzz(t *testing.T) {
        for i := 0; i < 50; i++ {
                // Generate a random string of runes.
                buf.Reset()
-               for buf.Len() < ArgLengthForResponseFile+1 {
+               for buf.Len() < sys.ExecArgLengthLimit+1 {
                        var r rune
                        for {
                                r = rune(rng.Intn(utf8.MaxRune + 1))
index 70ca5d69f8378f018df76b72259eda801669625a..e3b4a817e782c0c7e30e7d0dd8713d920c1a5a0a 100644 (file)
@@ -20,8 +20,9 @@ import (
        "cmd/go/internal/cfg"
        "cmd/go/internal/fsys"
        "cmd/go/internal/load"
+       "cmd/go/internal/str"
        "cmd/internal/objabi"
-       "cmd/internal/str"
+       "cmd/internal/quoted"
        "cmd/internal/sys"
        "crypto/sha1"
 )
@@ -75,7 +76,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
        }
 
        pkgpath := pkgPath(a)
-       gcargs := []string{"-p", pkgpath}
+       defaultGcFlags := []string{"-p", pkgpath}
        if p.Module != nil {
                v := p.Module.GoVersion
                if v == "" {
@@ -94,11 +95,11 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
                        v = "1.16"
                }
                if allowedVersion(v) {
-                       gcargs = append(gcargs, "-lang=go"+v)
+                       defaultGcFlags = append(defaultGcFlags, "-lang=go"+v)
                }
        }
        if p.Standard {
-               gcargs = append(gcargs, "-std")
+               defaultGcFlags = append(defaultGcFlags, "-std")
        }
        _, compilingRuntime := runtimePackages[p.ImportPath]
        compilingRuntime = compilingRuntime && p.Standard
@@ -106,7 +107,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
                // runtime compiles with a special gc flag to check for
                // memory allocations that are invalid in the runtime package,
                // and to implement some special compiler pragmas.
-               gcargs = append(gcargs, "-+")
+               defaultGcFlags = append(defaultGcFlags, "-+")
        }
 
        // If we're giving the compiler the entire package (no C etc files), tell it that,
@@ -125,25 +126,28 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
                }
        }
        if extFiles == 0 {
-               gcargs = append(gcargs, "-complete")
+               defaultGcFlags = append(defaultGcFlags, "-complete")
        }
        if cfg.BuildContext.InstallSuffix != "" {
-               gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
+               defaultGcFlags = append(defaultGcFlags, "-installsuffix", cfg.BuildContext.InstallSuffix)
        }
        if a.buildID != "" {
-               gcargs = append(gcargs, "-buildid", a.buildID)
+               defaultGcFlags = append(defaultGcFlags, "-buildid", a.buildID)
        }
        if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" {
-               gcargs = append(gcargs, "-dwarf=false")
+               defaultGcFlags = append(defaultGcFlags, "-dwarf=false")
        }
        if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
-               gcargs = append(gcargs, "-goversion", runtimeVersion)
+               defaultGcFlags = append(defaultGcFlags, "-goversion", runtimeVersion)
        }
        if symabis != "" {
-               gcargs = append(gcargs, "-symabis", symabis)
+               defaultGcFlags = append(defaultGcFlags, "-symabis", symabis)
        }
 
        gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags)
+       if p.Internal.FuzzInstrument {
+               gcflags = append(gcflags, fuzzInstrumentFlags()...)
+       }
        if compilingRuntime {
                // Remove -N, if present.
                // It is not possible to build the runtime with no optimizations,
@@ -156,10 +160,15 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
                        }
                }
        }
+       // Add -c=N to use concurrent backend compilation, if possible.
+       if c := gcBackendConcurrency(gcflags); c > 1 {
+               gcflags = append(gcflags, fmt.Sprintf("-c=%d", c))
+       }
 
-       args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), gcflags, gcargs}
-       if p.Internal.LocalPrefix != "" {
-               // Workaround #43883.
+       args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), defaultGcFlags, gcflags}
+       if p.Internal.LocalPrefix == "" {
+               args = append(args, "-nolocalimports")
+       } else {
                args = append(args, "-D", p.Internal.LocalPrefix)
        }
        if importcfg != nil {
@@ -181,11 +190,6 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
                args = append(args, "-asmhdr", objdir+"go_asm.h")
        }
 
-       // Add -c=N to use concurrent backend compilation, if possible.
-       if c := gcBackendConcurrency(gcflags); c > 1 {
-               args = append(args, fmt.Sprintf("-c=%d", c))
-       }
-
        for _, f := range gofiles {
                f := mkAbs(p.Dir, f)
 
@@ -232,7 +236,7 @@ CheckFlags:
                // 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":
+               case "-N", "-l", "-S", "-B", "-C", "-I", "-shared":
                        // OK
                default:
                        canDashC = false
@@ -374,6 +378,16 @@ func asmArgs(a *Action, p *load.Package) []interface{} {
                args = append(args, "-compiling-runtime")
        }
 
+       if cfg.Goarch == "386" {
+               // Define GO386_value from cfg.GO386.
+               args = append(args, "-D", "GO386_"+cfg.GO386)
+       }
+
+       if cfg.Goarch == "amd64" {
+               // Define GOAMD64_value from cfg.GOAMD64.
+               args = append(args, "-D", "GOAMD64_"+cfg.GOAMD64)
+       }
+
        if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" {
                // Define GOMIPS_value from cfg.GOMIPS.
                args = append(args, "-D", "GOMIPS_"+cfg.GOMIPS)
@@ -545,33 +559,18 @@ func packInternal(afile string, ofiles []string) error {
 }
 
 // setextld sets the appropriate linker flags for the specified compiler.
-func setextld(ldflags []string, compiler []string) []string {
+func setextld(ldflags []string, compiler []string) ([]string, error) {
        for _, f := range ldflags {
                if f == "-extld" || strings.HasPrefix(f, "-extld=") {
                        // don't override -extld if supplied
-                       return ldflags
+                       return ldflags, nil
                }
        }
-       ldflags = append(ldflags, "-extld="+compiler[0])
-       if len(compiler) > 1 {
-               extldflags := false
-               add := strings.Join(compiler[1:], " ")
-               for i, f := range ldflags {
-                       if f == "-extldflags" && i+1 < len(ldflags) {
-                               ldflags[i+1] = add + " " + ldflags[i+1]
-                               extldflags = true
-                               break
-                       } else if strings.HasPrefix(f, "-extldflags=") {
-                               ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
-                               extldflags = true
-                               break
-                       }
-               }
-               if !extldflags {
-                       ldflags = append(ldflags, "-extldflags="+add)
-               }
+       joined, err := quoted.Join(compiler)
+       if err != nil {
+               return nil, err
        }
-       return ldflags
+       return append(ldflags, "-extld="+joined), nil
 }
 
 // pluginPath computes the package path for a plugin main package.
@@ -658,7 +657,10 @@ func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string)
        }
        ldflags = append(ldflags, forcedLdflags...)
        ldflags = append(ldflags, root.Package.Internal.Ldflags...)
-       ldflags = setextld(ldflags, compiler)
+       ldflags, err := setextld(ldflags, compiler)
+       if err != nil {
+               return err
+       }
 
        // On OS X when using external linking to build a shared library,
        // the argument passed here to -o ends up recorded in the final
@@ -702,7 +704,10 @@ func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action,
        } else {
                compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
        }
-       ldflags = setextld(ldflags, compiler)
+       ldflags, err := setextld(ldflags, compiler)
+       if err != nil {
+               return err
+       }
        for _, d := range toplevelactions {
                if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries
                        continue
index 3cb7b641833a48db0acf35f4a31697d336a9df16..60181b99e471d409b91408ccf26a7ff891cd89b2 100644 (file)
@@ -17,7 +17,7 @@ import (
        "cmd/go/internal/fsys"
        "cmd/go/internal/load"
        "cmd/internal/pkgpath"
-       "cmd/internal/str"
+       "cmd/go/internal/str"
 )
 
 // The Gccgo toolchain.
index 37a3e2d0ffd1232368863992603432fbd783e828..dc368de1c18e1868b258bcd12488599933498992 100644 (file)
@@ -11,8 +11,8 @@ import (
        "cmd/go/internal/cfg"
        "cmd/go/internal/fsys"
        "cmd/go/internal/modload"
+       "cmd/internal/quoted"
        "cmd/internal/sys"
-       "flag"
        "fmt"
        "os"
        "path/filepath"
@@ -32,27 +32,63 @@ func BuildInit() {
        if cfg.BuildPkgdir != "" && !filepath.IsAbs(cfg.BuildPkgdir) {
                p, err := filepath.Abs(cfg.BuildPkgdir)
                if err != nil {
-                       fmt.Fprintf(os.Stderr, "go %s: evaluating -pkgdir: %v\n", flag.Args()[0], err)
+                       fmt.Fprintf(os.Stderr, "go: evaluating -pkgdir: %v\n", err)
                        base.SetExitStatus(2)
                        base.Exit()
                }
                cfg.BuildPkgdir = p
        }
 
-       // Make sure CC and CXX are absolute paths
-       for _, key := range []string{"CC", "CXX"} {
-               if path := cfg.Getenv(key); !filepath.IsAbs(path) && path != "" && path != filepath.Base(path) {
-                       base.Fatalf("go %s: %s environment variable is relative; must be absolute path: %s\n", flag.Args()[0], key, path)
+       if cfg.BuildP <= 0 {
+               base.Fatalf("go: -p must be a positive integer: %v\n", cfg.BuildP)
+       }
+
+       // Make sure CC, CXX, and FC are absolute paths.
+       for _, key := range []string{"CC", "CXX", "FC"} {
+               value := cfg.Getenv(key)
+               args, err := quoted.Split(value)
+               if err != nil {
+                       base.Fatalf("go: %s environment variable could not be parsed: %v", key, err)
                }
+               if len(args) == 0 {
+                       continue
+               }
+               path := args[0]
+               if !filepath.IsAbs(path) && path != filepath.Base(path) {
+                       base.Fatalf("go: %s environment variable is relative; must be absolute path: %s\n", key, path)
+               }
+       }
+}
+
+// fuzzInstrumentFlags returns compiler flags that enable fuzzing instrumation
+// on supported platforms.
+//
+// On unsupported platforms, fuzzInstrumentFlags returns nil, meaning no
+// instrumentation is added. 'go test -fuzz' still works without coverage,
+// but it generates random inputs without guidance, so it's much less effective.
+func fuzzInstrumentFlags() []string {
+       if !sys.FuzzInstrumented(cfg.Goos, cfg.Goarch) {
+               return nil
        }
+       return []string{"-d=libfuzzer"}
 }
 
 func instrumentInit() {
-       if !cfg.BuildRace && !cfg.BuildMSan {
+       if !cfg.BuildRace && !cfg.BuildMSan && !cfg.BuildASan {
                return
        }
        if cfg.BuildRace && cfg.BuildMSan {
-               fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
+               fmt.Fprintf(os.Stderr, "go: may not use -race and -msan simultaneously\n")
+               base.SetExitStatus(2)
+               base.Exit()
+       }
+       if cfg.BuildRace && cfg.BuildASan {
+               fmt.Fprintf(os.Stderr, "go: may not use -race and -asan simultaneously\n")
+               base.SetExitStatus(2)
+               base.Exit()
+       }
+       if cfg.BuildMSan && cfg.BuildASan {
+               fmt.Fprintf(os.Stderr, "go: may not use -msan and -asan simultaneously\n")
                base.SetExitStatus(2)
                base.Exit()
        }
@@ -61,12 +97,15 @@ func instrumentInit() {
                base.SetExitStatus(2)
                base.Exit()
        }
-       if cfg.BuildRace {
-               if !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) {
-                       fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64\n", flag.Args()[0])
-                       base.SetExitStatus(2)
-                       base.Exit()
-               }
+       if cfg.BuildRace && !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) {
+               fmt.Fprintf(os.Stderr, "-race is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
+               base.SetExitStatus(2)
+               base.Exit()
+       }
+       if cfg.BuildASan && !sys.ASanSupported(cfg.Goos, cfg.Goarch) {
+               fmt.Fprintf(os.Stderr, "-asan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
+               base.SetExitStatus(2)
+               base.Exit()
        }
        mode := "race"
        if cfg.BuildMSan {
@@ -77,13 +116,16 @@ func instrumentInit() {
                        cfg.BuildBuildmode = "pie"
                }
        }
+       if cfg.BuildASan {
+               mode = "asan"
+       }
        modeFlag := "-" + mode
 
        if !cfg.BuildContext.CgoEnabled {
                if runtime.GOOS != cfg.Goos || runtime.GOARCH != cfg.Goarch {
-                       fmt.Fprintf(os.Stderr, "go %s: %s requires cgo\n", flag.Args()[0], modeFlag)
+                       fmt.Fprintf(os.Stderr, "go: %s requires cgo\n", modeFlag)
                } else {
-                       fmt.Fprintf(os.Stderr, "go %s: %s requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0], modeFlag)
+                       fmt.Fprintf(os.Stderr, "go: %s requires cgo; enable cgo by setting CGO_ENABLED=1\n", modeFlag)
                }
 
                base.SetExitStatus(2)
index 8b77871b23f26922b4612c9017522710f1511af5..a09b65a23c35cd3bc928200faec75f5fa8de334c 100644 (file)
@@ -5,7 +5,6 @@
 // This file contains extra hooks for testing the go command.
 
 //go:build testgo
-// +build testgo
 
 package work
 
index 74bfecc08dbc6de1ca9768c536113eb878d7f3da..a387fe67dbfc83f227500b24cc9b3130d0fef8bb 100644 (file)
@@ -25,12 +25,12 @@ import (
 
        "cmd/go/internal/modfetch/codehost"
        "cmd/go/internal/par"
-       "cmd/go/internal/txtar"
 
        "golang.org/x/mod/module"
        "golang.org/x/mod/semver"
        "golang.org/x/mod/sumdb"
        "golang.org/x/mod/sumdb/dirhash"
+       "golang.org/x/tools/txtar"
 )
 
 var (
index 9ca297e89b4e5b439b11b1b0facd0915e48595d7..98c1b68ed9f1ad2f80876f91160ec0ac93056cfd 100644 (file)
@@ -31,9 +31,10 @@ import (
        "cmd/go/internal/imports"
        "cmd/go/internal/par"
        "cmd/go/internal/robustio"
-       "cmd/go/internal/txtar"
        "cmd/go/internal/work"
        "cmd/internal/sys"
+
+       "golang.org/x/tools/txtar"
 )
 
 var testSum = flag.String("testsum", "", `may be tidy, listm, or listall. If set, TestScript generates a go.sum file at the beginning of each test and updates test files if they pass.`)
@@ -184,6 +185,7 @@ func (ts *testScript) setup() {
                "devnull=" + os.DevNull,
                "goversion=" + goVersion(ts),
                ":=" + string(os.PathListSeparator),
+               "/=" + string(os.PathSeparator),
        }
        if !testenv.HasExternalNetwork() {
                ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic")
@@ -351,8 +353,14 @@ Script:
                                ok = canCgo
                        case "msan":
                                ok = canMSan
+                       case "asan":
+                               ok = canASan
                        case "race":
                                ok = canRace
+                       case "fuzz":
+                               ok = canFuzz
+                       case "fuzz-instrumented":
+                               ok = fuzzInstrumented
                        case "net":
                                ok = testenv.HasExternalNetwork()
                        case "link":
@@ -1128,6 +1136,17 @@ func (ts *testScript) startBackground(want simpleStatus, command string, args ..
                done: done,
        }
 
+       // Use the script's PATH to look up the command if it contains a separator
+       // instead of the test process's PATH (see lookPath).
+       // Don't use filepath.Clean, since that changes "./foo" to "foo".
+       command = filepath.FromSlash(command)
+       if !strings.Contains(command, string(filepath.Separator)) {
+               var err error
+               command, err = ts.lookPath(command)
+               if err != nil {
+                       return nil, err
+               }
+       }
        cmd := exec.Command(command, args...)
        cmd.Dir = ts.cd
        cmd.Env = append(ts.env, "PWD="+ts.cd)
@@ -1144,6 +1163,73 @@ func (ts *testScript) startBackground(want simpleStatus, command string, args ..
        return bg, nil
 }
 
+// lookPath is (roughly) like exec.LookPath, but it uses the test script's PATH
+// instead of the test process's PATH to find the executable. We don't change
+// the test process's PATH since it may run scripts in parallel.
+func (ts *testScript) lookPath(command string) (string, error) {
+       var strEqual func(string, string) bool
+       if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
+               // Using GOOS as a proxy for case-insensitive file system.
+               strEqual = strings.EqualFold
+       } else {
+               strEqual = func(a, b string) bool { return a == b }
+       }
+
+       var pathExt []string
+       var searchExt bool
+       var isExecutable func(os.FileInfo) bool
+       if runtime.GOOS == "windows" {
+               // Use the test process's PathExt instead of the script's.
+               // If PathExt is set in the command's environment, cmd.Start fails with
+               // "parameter is invalid". Not sure why.
+               // If the command already has an extension in PathExt (like "cmd.exe")
+               // don't search for other extensions (not "cmd.bat.exe").
+               pathExt = strings.Split(os.Getenv("PathExt"), string(filepath.ListSeparator))
+               searchExt = true
+               cmdExt := filepath.Ext(command)
+               for _, ext := range pathExt {
+                       if strEqual(cmdExt, ext) {
+                               searchExt = false
+                               break
+                       }
+               }
+               isExecutable = func(fi os.FileInfo) bool {
+                       return fi.Mode().IsRegular()
+               }
+       } else {
+               isExecutable = func(fi os.FileInfo) bool {
+                       return fi.Mode().IsRegular() && fi.Mode().Perm()&0111 != 0
+               }
+       }
+
+       pathName := "PATH"
+       if runtime.GOOS == "plan9" {
+               pathName = "path"
+       }
+
+       for _, dir := range strings.Split(ts.envMap[pathName], string(filepath.ListSeparator)) {
+               if searchExt {
+                       ents, err := os.ReadDir(dir)
+                       if err != nil {
+                               continue
+                       }
+                       for _, ent := range ents {
+                               for _, ext := range pathExt {
+                                       if !ent.IsDir() && strEqual(ent.Name(), command+ext) {
+                                               return dir + string(filepath.Separator) + ent.Name(), nil
+                                       }
+                               }
+                       }
+               } else {
+                       path := dir + string(filepath.Separator) + command
+                       if fi, err := os.Stat(path); err == nil && isExecutable(fi) {
+                               return path, nil
+                       }
+               }
+       }
+       return "", &exec.Error{Name: command, Err: exec.ErrNotFound}
+}
+
 // 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.
@@ -1170,7 +1256,7 @@ func waitOrStop(ctx context.Context, cmd *exec.Cmd, interrupt os.Signal, killDel
                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" {
+               } else if err == os.ErrProcessDone {
                        errc <- nil
                        return
                }
index e1cc6cf8ba755fffd719f14a2e0455b2ae7874e5..35c12858c1d5e1d36772a0285313c410b7643058 100644 (file)
@@ -3,15 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !(aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris)
-// +build !aix
-// +build !darwin
-// +build !dragonfly
-// +build !freebsd
-// +build !js !wasm
-// +build !linux
-// +build !netbsd
-// +build !openbsd
-// +build !solaris
 
 package main_test
 
index ac35b240f0ad9727845fed622a5112f704b95909..5939f0d40d996777493cc6f64263ed340d71029e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package main_test
 
index 03869e68defe0845c5cbdef60fa08f2fd3fdf42d..a1ace4ce5907e84c7c21d5c9d4ba0df863d8f305 100644 (file)
@@ -29,7 +29,7 @@ import (
        "path/filepath"
        "strings"
 
-       "cmd/go/internal/txtar"
+       "golang.org/x/tools/txtar"
 )
 
 func usage() {
diff --git a/src/cmd/go/testdata/mod/example.com_fuzzfail_v0.1.0.txt b/src/cmd/go/testdata/mod/example.com_fuzzfail_v0.1.0.txt
new file mode 100644 (file)
index 0000000..af005ff
--- /dev/null
@@ -0,0 +1,20 @@
+-- .mod --
+module example.com/fuzzfail
+
+go 1.18
+-- .info --
+{"Version":"v0.1.0"}
+-- go.mod --
+module example.com/fuzzfail
+
+go 1.18
+-- fuzzfail_test.go --
+package fuzzfail
+
+import "testing"
+
+func FuzzFail(f *testing.F) {
+       f.Fuzz(func(t *testing.T, b []byte) {
+               t.Fatalf("oops: %q", b)
+       })
+}
diff --git a/src/cmd/go/testdata/mod/example.com_fuzzfail_v0.2.0.txt b/src/cmd/go/testdata/mod/example.com_fuzzfail_v0.2.0.txt
new file mode 100644 (file)
index 0000000..ea599aa
--- /dev/null
@@ -0,0 +1,23 @@
+-- .mod --
+module example.com/fuzzfail
+
+go 1.18
+-- .info --
+{"Version":"v0.2.0"}
+-- go.mod --
+module example.com/fuzzfail
+
+go 1.18
+-- fuzzfail_test.go --
+package fuzzfail
+
+import "testing"
+
+func FuzzFail(f *testing.F) {
+       f.Fuzz(func(t *testing.T, b []byte) {
+               t.Fatalf("oops: %q", b)
+       })
+}
+-- testdata/fuzz/FuzzFail/bbb0c2d22aa1a24617301566dc7486f8b625d38024603ba62757c1124013b49a --
+go test fuzz v1
+[]byte("\x05")
index 35c3f277103df132a0588eb4fe5ef6ca4689e18f..00076d74fc2f8868a1e78de129bcbe6a6fbf1d51 100644 (file)
@@ -1,6 +1,6 @@
 Written by hand.
 Test case for getting a package that has been moved to a nested module,
-with a +incompatible verison (and thus no go.mod file) at the root module.
+with a +incompatible version (and thus no go.mod file) at the root module.
 
 -- .mod --
 module example.com/split-incompatible
index 917fc0f55992efa69f6767a486fd2a2908bded95..bb1c1fecc9d2713360069cf593b6df89e6e1c303 100644 (file)
@@ -1,6 +1,6 @@
 Written by hand.
 Test case for getting a package that has been moved to a nested module,
-with a +incompatible verison (and thus no go.mod file) at the root module.
+with a +incompatible version (and thus no go.mod file) at the root module.
 
 -- .mod --
 module example.com/split-incompatible
index d469c31a919821171affd2be2e88b12ef3861de0..6a8a232702f550341efd7351da97295645b28604 100644 (file)
@@ -24,7 +24,7 @@ import (
        "strings"
        "unicode/utf8"
 
-       "../internal/txtar"
+       "golang.org/x/tools/txtar"
 )
 
 func usage() {
index 48e4055b0bdb971397be7dd2b0b909205a46a588..2b55fa89777d17f7e2927980a5a52a69b01e60c4 100644 (file)
@@ -79,7 +79,9 @@ should only run when the condition is satisfied. The available conditions are:
  - Compiler names, like [gccgo], [gc].
  - Test environment details:
    - [short] for testing.Short()
-   - [cgo], [msan], [race] for whether cgo, msan, and the race detector can be used
+   - [cgo], [msan], [asan], [race] for whether cgo, msan, asan, and the race detector can be used
+   - [fuzz] for whether 'go test -fuzz' can be used at all
+   - [fuzz-instrumented] for whether 'go test -fuzz' uses coverage-instrumented binaries
    - [net] for whether the external network can be used
    - [link] for testenv.HasLink()
    - [root] for os.Geteuid() == 0
index 8b005c857fcf99dd89fda7ef752cf13b52864471..cb1a7558fca71f3edab009c32329376f45b7a45e 100644 (file)
@@ -9,7 +9,7 @@
 # * go fix
 # * go fmt
 # * go generate
-# * go get -d
+# * go get
 # * go list (without -export or -compiled)
 
 env GOCACHE=off
index 9a4b9d7b40c7264ea9cec6df11a66006be3a41fe..7ee3c3b41d489a7cd3059efe567737f25b040559 100644 (file)
@@ -16,10 +16,10 @@ stderr 'link( |\.exe)'
 # Two distinct versions of the same module with identical content should
 # still be cached separately.
 # Verifies golang.org/issue/35412.
-go get -d example.com/stack@v1.0.0
+go get example.com/stack@v1.0.0
 go run -trimpath printstack.go
 stdout '^example.com/stack@v1.0.0/stack.go$'
-go get -d example.com/stack@v1.0.1
+go get example.com/stack@v1.0.1
 go run -trimpath printstack.go
 stdout '^example.com/stack@v1.0.1/stack.go$'
 
diff --git a/src/cmd/go/testdata/script/build_concurrent_backend.txt b/src/cmd/go/testdata/script/build_concurrent_backend.txt
new file mode 100644 (file)
index 0000000..9cac635
--- /dev/null
@@ -0,0 +1,10 @@
+# Tests golang.org/issue/48490
+# cmd/go should enable concurrent compilation by default
+
+# Reset all experiments, since one of them can disable
+# concurrent compilation, e.g: fieldtrack.
+env GOEXPERIMENT=none
+
+env GOMAXPROCS=4
+go build -n -x -a fmt
+stderr ' -c=4 '
diff --git a/src/cmd/go/testdata/script/build_gcflags_order.txt b/src/cmd/go/testdata/script/build_gcflags_order.txt
new file mode 100644 (file)
index 0000000..0ffe157
--- /dev/null
@@ -0,0 +1,20 @@
+# Tests golang.org/issue/47682
+# Flags specified with -gcflags should appear after other flags generated by cmd/go.
+
+cd m
+go build -n -gcflags=-lang=go1.17
+stderr ' -lang=go1.16.* -lang=go1.17'
+
+-- m/go.mod --
+module example.com
+
+go 1.16
+
+-- m/main.go --
+package main
+
+func main() {
+    var s = []int{1, 2, 3}
+    var pa = (*[2]int)(s[1:])
+    println(pa[1])
+}
index 71356e5321eb1ca3ab2b9227c55ceba8eb4710d1..5c1799566999e44a76c4555af4e06cfd67b592fd 100644 (file)
@@ -2,13 +2,13 @@
 # TODO(golang.org/issue/41696): remove the -i flag after Go 1.16, and this test.
 
 go build -n -i
-stderr '^go build: -i flag is deprecated$'
+stderr '^go: -i flag is deprecated$'
 
 go install -n -i
-stderr '^go install: -i flag is deprecated$'
+stderr '^go: -i flag is deprecated$'
 
 go test -n -i
-stderr '^go test: -i flag is deprecated$'
+stderr '^go: -i flag is deprecated$'
 
 
 # 'go clean -i' should not print a deprecation warning.
diff --git a/src/cmd/go/testdata/script/build_issue48319.txt b/src/cmd/go/testdata/script/build_issue48319.txt
new file mode 100644 (file)
index 0000000..f58a5fa
--- /dev/null
@@ -0,0 +1,153 @@
+[short] skip
+[!cgo] skip
+
+# Set up fresh GOCACHE
+env GOCACHE=$WORK/gocache
+mkdir $GOCACHE
+
+# 1. unset GOROOT_FINAL, Build a simple binary with cgo by origin go.
+# The DW_AT_comp_dir of runtime/cgo should have a prefix with origin goroot.
+env GOROOT_FINAL=
+# If using "go run", it is no debuginfo in binary. So use "go build".
+# And we can check the stderr to judge if the cache of "runtime/cgo"
+# was used or not.
+go build -o binary.exe
+exec ./binary.exe $TESTGO_GOROOT
+stdout 'cgo DW_AT_comp_dir is right in binary'
+
+
+# 2. GOROOT_FINAL will be changed, the runtime/cgo will be rebuild.
+env GOROOT_FINAL=$WORK/gorootfinal
+go build -x -o binary.exe
+stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
+exec ./binary.exe $GOROOT_FINAL
+stdout 'cgo DW_AT_comp_dir is right in binary'
+
+
+[!symlink] skip
+
+# Symlink the compiler to another path
+env GOROOT=$WORK/goroot
+symlink $GOROOT -> $TESTGO_GOROOT
+
+# 3. GOROOT_FINAL is same with 2, build with the other go
+# the runtime/cgo will not be rebuild.
+go build -x -o binary.exe
+! stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
+exec ./binary.exe $GOROOT_FINAL
+stdout 'cgo DW_AT_comp_dir is right in binary'
+
+
+# 4. unset GOROOT_FINAL, build with the other go
+# the runtime/cgo will be rebuild.
+env GOROOT_FINAL=
+go build -x -o binary.exe
+stderr '(clang|gcc)( |\.exe).*gcc_.*\.c'
+exec ./binary.exe $GOROOT
+stdout 'cgo DW_AT_comp_dir is right in binary'
+
+-- go.mod --
+module main
+
+go 1.18
+-- main.go --
+package main
+
+import "C"
+import (
+       "debug/dwarf"
+       "fmt"
+       "log"
+       "os"
+       "path/filepath"
+       "strings"
+)
+
+var _ C.int
+
+func main() {
+       dwarfData, err := readDWARF(os.Args[0])
+       if err != nil {
+               log.Fatal(err)
+       }
+       goroot := filepath.Join(os.Args[1], "src")
+       dwarfReader := dwarfData.Reader()
+       cgopackage := filepath.Join("runtime", "cgo")
+       var hascgo bool
+       for {
+               e, err := dwarfReader.Next()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               if e == nil {
+                       break
+               }
+               field := e.AttrField(dwarf.AttrCompDir)
+               if field == nil {
+                       continue
+               }
+               compdir := field.Val.(string)
+               if strings.HasSuffix(compdir, cgopackage) {
+                       hascgo = true
+                       if !strings.HasPrefix(compdir, goroot) {
+                               fmt.Printf("cgo DW_AT_comp_dir %s contains incorrect path in binary.\n", compdir)
+                               return
+                       }
+               }
+       }
+       if hascgo {
+               fmt.Println("cgo DW_AT_comp_dir is right in binary")
+       } else {
+               fmt.Println("binary does not contain cgo")
+       }
+}
+-- read_darwin.go --
+package main
+
+import (
+       "debug/dwarf"
+       "debug/macho"
+)
+
+func readDWARF(exePath string) (*dwarf.Data, error) {
+       machoFile, err := macho.Open(exePath)
+       if err != nil {
+               return nil, err
+       }
+       defer machoFile.Close()
+       return machoFile.DWARF()
+}
+-- read_elf.go --
+// +build android dragonfly freebsd illumos linux netbsd openbsd solaris
+
+package main
+
+import (
+       "debug/dwarf"
+       "debug/elf"
+)
+
+func readDWARF(exePath string) (*dwarf.Data, error) {
+       elfFile, err := elf.Open(exePath)
+       if err != nil {
+               return nil, err
+       }
+       defer elfFile.Close()
+       return elfFile.DWARF()
+}
+-- read_windows.go --
+package main
+
+import (
+       "debug/dwarf"
+       "debug/pe"
+)
+
+func readDWARF(exePath string) (*dwarf.Data, error) {
+       peFile, err := pe.Open(exePath)
+       if err != nil {
+               return nil, err
+       }
+       defer peFile.Close()
+       return peFile.DWARF()
+}
diff --git a/src/cmd/go/testdata/script/build_negative_p.txt b/src/cmd/go/testdata/script/build_negative_p.txt
new file mode 100644 (file)
index 0000000..9123907
--- /dev/null
@@ -0,0 +1,5 @@
+! go build -p=-1 example.go
+stderr 'go: -p must be a positive integer: -1'
+
+-- example.go --
+package example
\ No newline at end of file
index da1b65f06c849788fbf7b7b73a50ee0f40979892..c87e480911933a6211fd31991cbf17ec2e75da44 100644 (file)
@@ -8,4 +8,4 @@ mkdir $GOCACHE
 # Verify the standard library (specifically runtime/internal/atomic) can be
 # built with -gcflags when -n is given. See golang.org/issue/29346.
 go build -n -gcflags=all='-l' std
-stderr 'compile.* -l .* runtime/internal/atomic'
+stderr 'compile.* runtime/internal/atomic .* -l'
index 2c3bee8fdc7a925bb9bd9bdcee078a36b0ed9581..f36b1237dc09413f8cf95fea76a278ed48b187f6 100644 (file)
@@ -32,7 +32,8 @@ stdout 'binary contains GOROOT: false'
 
 # A binary from an external module built with -trimpath should not contain
 # the current workspace or GOROOT.
-go get -trimpath rsc.io/fortune
+go get rsc.io/fortune
+go install -trimpath rsc.io/fortune
 exec $WORK/paths-a.exe $GOPATH/bin/fortune$GOEXE
 stdout 'binary contains module root: false'
 stdout 'binary contains GOROOT: false'
diff --git a/src/cmd/go/testdata/script/cgo_path_space_quote.txt b/src/cmd/go/testdata/script/cgo_path_space_quote.txt
new file mode 100644 (file)
index 0000000..9556101
--- /dev/null
@@ -0,0 +1,58 @@
+# This test checks that the CC environment variable may contain quotes and
+# spaces. Arguments are normally split on spaces, tabs, newlines. If an
+# argument contains these characters, the entire argument may be quoted
+# with single or double quotes. This is the same as -gcflags and similar
+# options.
+
+[short] skip
+[!exec:clang] [!exec:gcc] skip
+[!cgo] skip
+
+env GOENV=$WORK/go.env
+mkdir 'program files'
+go build -o 'program files' './which cc/which cc.go'
+[exec:clang] env CC='"'$PWD${/}program' 'files${/}which' 'cc"' 'clang
+[!exec:clang] env CC='"'$PWD${/}program' 'files${/}which' 'cc"' 'gcc
+go env CC
+stdout 'program files[/\\]which cc" (clang|gcc)$'
+go env -w CC=$CC
+env CC=
+go env CC
+stdout 'program files[/\\]which cc" (clang|gcc)$'
+
+go run .
+stdout 1
+
+-- go.mod --
+module test
+
+go 1.17
+-- which cc/which cc.go --
+package main
+
+import (
+       "fmt"
+       "os"
+       "os/exec"
+)
+
+func main() {
+       args := append([]string{"-DWRAPPER_WAS_USED=1"}, os.Args[2:]...)
+       cmd := exec.Command(os.Args[1], args...)
+       cmd.Stdout = os.Stdout
+       cmd.Stderr = os.Stderr
+       if err := cmd.Run(); err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+}
+-- hello.go --
+package main
+
+// int x = WRAPPER_WAS_USED;
+import "C"
+import "fmt"
+
+func main() {
+       fmt.Println(C.x)
+}
index 4e0f249509873ed7355470f5bd0a1326defbb1a0..22bc845c37bf4ecc7cde8b989b1d899e7a01e522 100644 (file)
@@ -12,13 +12,13 @@ stderr '^go(\.exe)?: unknown GOEXPERIMENT badexp$'
 go env -u GOEXPERIMENT
 
 ! go env
-stderr '^cmd/go: unsupported GOOS/GOARCH pair bados/badarch$'
+stderr '^go: unsupported GOOS/GOARCH pair bados/badarch$'
 
 ! go env -u GOOS
-stderr '^go env -u: unsupported GOOS/GOARCH pair \w+/badarch$'
+stderr '^go: unsupported GOOS/GOARCH pair \w+/badarch$'
 
 ! go env -u GOARCH
-stderr '^go env -u: unsupported GOOS/GOARCH pair bados/\w+$'
+stderr '^go: unsupported GOOS/GOARCH pair bados/\w+$'
 
 go env -u GOOS GOARCH
 
index b5e97391679cc52442322e972c7a82fbed0e30bc..132947c623ff2f0472bad5ac22b9baf99d99cce5 100644 (file)
@@ -30,9 +30,9 @@ go env
 
 # checking errors
 ! go env -w
-stderr 'go env -w: no KEY=VALUE arguments given'
+stderr 'go: no KEY=VALUE arguments given'
 ! go env -u
-stderr 'go env -u: no arguments given'
+stderr 'go: ''go env -u'' requires an argument'
 
 # go env -w changes default setting
 env root=
@@ -111,7 +111,7 @@ stderr 'GOPATH entry is relative; must be absolute path'
 
 # go env -w rejects invalid GOTMPDIR values
 ! go env -w GOTMPDIR=x
-stderr 'go env -w: GOTMPDIR must be an absolute path'
+stderr 'go: GOTMPDIR must be an absolute path'
 
 # go env -w should accept absolute GOTMPDIR value
 # and should not create it
@@ -134,24 +134,24 @@ stdout ^$
 go env -w CC=clang
 [!windows] ! go env -w CC=./clang
 [!windows] ! go env -w CC=bin/clang
-[!windows] stderr 'go env -w: CC entry is relative; must be absolute path'
+[!windows] stderr 'go: CC entry is relative; must be absolute path'
 
 [windows] go env -w CC=$WORK\bin\clang
 [windows] ! go env -w CC=.\clang
 [windows] ! go env -w CC=bin\clang
-[windows] stderr 'go env -w: CC entry is relative; must be absolute path'
+[windows] stderr 'go: CC entry is relative; must be absolute path'
 
 # go env -w rejects relative CXX values
 [!windows] go env -w CC=/usr/bin/cpp
 go env -w CXX=cpp
 [!windows] ! go env -w CXX=./cpp
 [!windows] ! go env -w CXX=bin/cpp
-[!windows] stderr 'go env -w: CXX entry is relative; must be absolute path'
+[!windows] stderr 'go: CXX entry is relative; must be absolute path'
 
 [windows] go env -w CXX=$WORK\bin\cpp
 [windows] ! go env -w CXX=.\cpp
 [windows] ! go env -w CXX=bin\cpp
-[windows] stderr 'go env -w: CXX entry is relative; must be absolute path'
+[windows] stderr 'go: CXX entry is relative; must be absolute path'
 
 # go env -w/-u checks validity of GOOS/ARCH combinations
 env GOOS=
@@ -176,9 +176,9 @@ stderr 'unsupported GOOS/GOARCH.*windows/mips$'
 
 # go env -w should reject relative paths in GOMODCACHE environment.
 ! go env -w GOMODCACHE=~/test
-stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "~/test"'
+stderr 'go: GOMODCACHE entry is relative; must be absolute path: "~/test"'
 ! go env -w GOMODCACHE=./test
-stderr 'go env -w: GOMODCACHE entry is relative; must be absolute path: "./test"'
+stderr 'go: GOMODCACHE entry is relative; must be absolute path: "./test"'
 
 # go env -w checks validity of GOEXPERIMENT
 env GOEXPERIMENT=
index f23cecefd3aa30e87ef45d26b15949c2f88d3f28..5b81e9481ad4dde1f7ba32a253c81d6ea4fa63db 100644 (file)
@@ -7,28 +7,28 @@ env GOCACHE=$WORK/gocache  # Looking for compile commands, so need a clean cache
 
 # -gcflags=-e applies to named packages, not dependencies
 go build -n -v -gcflags=-e z1 z2
-stderr 'compile.* -e.* -p z1'
-stderr 'compile.* -e.* -p z2'
+stderr 'compile.* -p z1.* -e '
+stderr 'compile.* -p z2.* -e '
 stderr 'compile.* -p y'
-! stderr 'compile.* -e.* -p [^z]'
+! stderr 'compile.* -p [^z].* -e '
 
 # -gcflags can specify package=flags, and can be repeated; last match wins
 go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2
-stderr 'compile.* -N.* -p z1'
-! stderr 'compile.* -e.* -p z1'
-! stderr 'compile.* -N.* -p z2'
-stderr 'compile.* -e.* -p z2'
+stderr 'compile.* -p z1.* -N '
+! stderr 'compile.* -p z1.* -e '
+! stderr 'compile.* -p z2.* -N '
+stderr 'compile.* -p z2.* -e '
 stderr 'compile.* -p y'
-! stderr 'compile.* -e.* -p [^z]'
-! stderr 'compile.* -N.* -p [^z]'
+! stderr 'compile.* -p [^z].* -e '
+! stderr 'compile.* -p [^z].* -N '
 
 # -gcflags can have arbitrary spaces around the flags
 go build -n -v -gcflags='  z1 =        -e      ' z1
-stderr 'compile.* -e.* -p z1'
+stderr 'compile.* -p z1.* -e '
 
 # -gcflags='all=-e' should apply to all packages, even with go test
 go test -c -n -gcflags='all=-e' z1
-stderr 'compile.* -e.* -p z3 '
+stderr 'compile.* -p z3.* -e '
 
 # this particular -gcflags argument made the compiler crash
 ! go build -gcflags=-d=ssa/ z1
index ec4f8d32432179bc97c5fe9fccb56d1527c664e3..29fc5421e12fb9824c62dcec8d4f0bc526d16cf4 100644 (file)
@@ -9,4 +9,10 @@ go get -d bazil.org/fuse/fs/fstestutil
 
 env GO111MODULE=on
 env GOPROXY=direct
-go get -d bazil.org/fuse/fs/fstestutil
+go get bazil.org/fuse/fs/fstestutil
+
+
+-- go.mod --
+module m
+
+go 1.18
index bed872098769249e851a30ac13a4957c83aed913..f6d0de4d06fe540d92c580fbec4c4f9a9743dfb7 100644 (file)
@@ -9,15 +9,15 @@ go get -d test
 
 # argument has .go suffix, is a file and exists
 ! go get -d test.go
-stderr 'go get test.go: arguments must be package or module paths'
+stderr 'go: test.go: arguments must be package or module paths'
 
 # argument has .go suffix, doesn't exist and has no slashes
 ! go get -d test_missing.go
-stderr 'go get test_missing.go: arguments must be package or module paths'
+stderr 'go: test_missing.go: arguments must be package or module paths'
 
 # argument has .go suffix, is a file and exists in sub-directory
 ! go get -d test/test.go
-stderr 'go get: test/test.go exists as a file, but ''go get'' requires package arguments'
+stderr 'go: test/test.go exists as a file, but ''go get'' requires package arguments'
 
 # argument has .go suffix, doesn't exist and has slashes
 ! go get -d test/test_missing.go
@@ -27,19 +27,19 @@ stderr 'go get: test/test.go exists as a file, but ''go get'' requires package a
 # argument has .go suffix, is a symlink and exists
 [symlink] symlink test_sym.go -> test.go
 [symlink] ! go get -d test_sym.go
-[symlink] stderr 'go get test_sym.go: arguments must be package or module paths'
+[symlink] stderr 'go: test_sym.go: arguments must be package or module paths'
 [symlink] rm test_sym.go
 
 # argument has .go suffix, is a symlink and exists in sub-directory
 [symlink] symlink test/test_sym.go -> test.go
 [symlink] ! go get -d test/test_sym.go
-[symlink] stderr 'go get: test/test_sym.go exists as a file, but ''go get'' requires package arguments'
+[symlink] stderr 'go: test/test_sym.go exists as a file, but ''go get'' requires package arguments'
 [symlink] rm test_sym.go
 
 # argument has .go suffix, is a directory and exists
 mkdir test_dir.go
 ! go get -d test_dir.go
-stderr 'go get test_dir.go: arguments must be package or module paths'
+stderr 'go: test_dir.go: arguments must be package or module paths'
 rm test_dir.go
 
 # argument has .go suffix, is a directory and exists in sub-directory
index 2517664dd02308901fe338e5daac43a73c16b306..00bf32fc78effbb635570ffa919e96af69e561ee 100644 (file)
@@ -3,11 +3,11 @@ env GO111MODULE=off
 
 # GOPATH: Fetch with insecure, should error
 ! go get -insecure test
-stderr 'go get: -insecure flag is no longer supported; use GOINSECURE instead'
+stderr 'go: -insecure flag is no longer supported; use GOINSECURE instead'
 
 # Modules: Set up
 env GO111MODULE=on
 
 # Modules: Fetch with insecure, should error
 ! go get -insecure test
-stderr 'go get: -insecure flag is no longer supported; use GOINSECURE instead'
+stderr 'go: -insecure flag is no longer supported; use GOINSECURE instead'
index 686d1138b8318e3d0ed5affd6673ee66ead24c96..f4872ffd356b5b3874e1205c0959c20c79a38ca0 100644 (file)
@@ -9,7 +9,7 @@ stdout '[\\/]runtime$'
 
 env GOFLAGS=-race OLDGOARCH=$GOARCH OLDGOOS=$GOOS GOARCH=386 GOOS=linux
 ! go list runtime
-stderr 'race is only supported on'
+stderr 'race is not supported on linux/386'
 
 env GOARCH=$OLDGOARCH GOOS=$OLDGOOS
 
index 4b42fc593f9ddf4b9927d1bcadfab461ef0b74e5..6c572eae619f067eac3ec44681314e1706a851f9 100644 (file)
@@ -26,7 +26,7 @@ cd ..
 env GOPATH= # reset to default ($HOME/go, which does not exist)
 env GOBIN=
 ! go install go-cmd-test/helloworld.go
-stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$'
+stderr '^go: no install location for \.go files listed on command line \(GOBIN not set\)$'
 
 # With $GOBIN set, should install there.
 env GOBIN=$WORK/bin1
index 7ee1f83471c631f4b5f41bab1105bdefa76c5973..54beaca5e8a9c211db89a82d3d729a673880c1dc 100644 (file)
@@ -22,7 +22,7 @@ stdout '^sub\.Hello'
 # Explicit source files listed on the command line should not install without
 # GOBIN set, since individual source files aren't part of the containing GOPATH.
 ! go install testdata/local/easy.go
-stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$'
+stderr '^go: no install location for \.go files listed on command line \(GOBIN not set\)$'
 
 [windows] stop  # Windows does not allow the ridiculous directory name we're about to use.
 
@@ -58,7 +58,7 @@ stdout '^sub\.Hello'
 # Explicit source files listed on the command line should not install without
 # GOBIN set, since individual source files aren't part of the containing GOPATH.
 ! go install testdata/$BAD_DIR_NAME/easy.go
-stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$'
+stderr '^go: no install location for \.go files listed on command line \(GOBIN not set\)$'
 
 -- testdata/local/easy.go --
 package main
index 4180d7da6ab159addd14d344d7d5135e07d50f9d..46f1bd0da2ada67d7cb80664699f6ac3d7e3881c 100644 (file)
@@ -5,64 +5,64 @@ env GOPROXY=direct
 # GOVCS stops go get
 env GOVCS='*:none'
 ! go get github.com/google/go-cmp
-stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
+stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
 env GOPRIVATE='github.com/google'
 ! go get github.com/google/go-cmp
-stderr '^go get: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$'
+stderr '^go: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$'
 
 # public pattern works
 env GOPRIVATE='github.com/google'
 env GOVCS='public:all,private:none'
 ! go get github.com/google/go-cmp
-stderr '^go get: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$'
+stderr '^go: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$'
 
 # private pattern works
 env GOPRIVATE='hubgit.com/google'
 env GOVCS='private:all,public:none'
 ! go get github.com/google/go-cmp
-stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
+stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
 
 # other patterns work (for more patterns, see TestGOVCS)
 env GOPRIVATE=
 env GOVCS='github.com:svn|hg'
 ! go get github.com/google/go-cmp
-stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
+stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
 env GOVCS='github.com/google/go-cmp/inner:git,github.com:svn|hg'
 ! go get github.com/google/go-cmp
-stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
+stderr '^go: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$'
 
 # bad patterns are reported (for more bad patterns, see TestGOVCSErrors)
 env GOVCS='git'
 ! go get github.com/google/go-cmp
-stderr '^go get github.com/google/go-cmp: malformed entry in GOVCS \(missing colon\): "git"$'
+stderr '^go: github.com/google/go-cmp: malformed entry in GOVCS \(missing colon\): "git"$'
 
 env GOVCS=github.com:hg,github.com:git
 ! go get github.com/google/go-cmp
-stderr '^go get github.com/google/go-cmp: unreachable pattern in GOVCS: "github.com:git" after "github.com:hg"$'
+stderr '^go: github.com/google/go-cmp: unreachable pattern in GOVCS: "github.com:git" after "github.com:hg"$'
 
 # bad GOVCS patterns do not stop commands that do not need to check VCS
 go list
 env GOPROXY=$proxy
-go get -d rsc.io/quote # ok because used proxy
+go get rsc.io/quote # ok because used proxy
 env GOPROXY=direct
 
 # svn is disallowed by default
 env GOPRIVATE=
 env GOVCS=
 ! go get rsc.io/nonexist.svn/hello
-stderr '^go get rsc.io/nonexist.svn/hello: GOVCS disallows using svn for public rsc.io/nonexist.svn; see ''go help vcs''$'
+stderr '^go: rsc.io/nonexist.svn/hello: GOVCS disallows using svn for public rsc.io/nonexist.svn; see ''go help vcs''$'
 
 # fossil is disallowed by default
 env GOPRIVATE=
 env GOVCS=
 ! go get rsc.io/nonexist.fossil/hello
-stderr '^go get rsc.io/nonexist.fossil/hello: GOVCS disallows using fossil for public rsc.io/nonexist.fossil; see ''go help vcs''$'
+stderr '^go: rsc.io/nonexist.fossil/hello: GOVCS disallows using fossil for public rsc.io/nonexist.fossil; see ''go help vcs''$'
 
 # bzr is disallowed by default
 env GOPRIVATE=
 env GOVCS=
 ! go get rsc.io/nonexist.bzr/hello
-stderr '^go get rsc.io/nonexist.bzr/hello: GOVCS disallows using bzr for public rsc.io/nonexist.bzr; see ''go help vcs''$'
+stderr '^go: rsc.io/nonexist.bzr/hello: GOVCS disallows using bzr for public rsc.io/nonexist.bzr; see ''go help vcs''$'
 
 # git is OK by default
 env GOVCS=
@@ -77,12 +77,12 @@ env GONOSUMDB='*'
 # git can be disallowed
 env GOVCS=public:hg
 ! go get rsc.io/nonexist.git/hello
-stderr '^go get rsc.io/nonexist.git/hello: GOVCS disallows using git for public rsc.io/nonexist.git; see ''go help vcs''$'
+stderr '^go: rsc.io/nonexist.git/hello: GOVCS disallows using git for public rsc.io/nonexist.git; see ''go help vcs''$'
 
 # hg can be disallowed
 env GOVCS=public:git
 ! go get rsc.io/nonexist.hg/hello
-stderr '^go get rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$'
+stderr '^go: rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$'
 
 # Repeat in GOPATH mode. Error texts slightly different.
 
index 7985cd2ab2728dfbb7311e6e96069b62f4b86792..5e88f7b8dbdc7288c3bdc6d8f7c4774b7e7fa1a0 100644 (file)
@@ -1,7 +1,5 @@
 # Tests Issue #21895
 
-[!msan] [!race] skip 'skipping because both msan and the race detector are not supported'
-
 env CGO_ENABLED=0
 
 [race] ! go install -race triv.go
@@ -12,6 +10,10 @@ env CGO_ENABLED=0
 [msan] stderr '-msan requires cgo'
 [msan] ! stderr '-race'
 
+[asan] ! go install -asan triv.go
+[asan] stderr '-asan requires cgo'
+[asan] ! stderr '-msan'
+
 -- triv.go --
 package main
 
diff --git a/src/cmd/go/testdata/script/link_external_undef.txt b/src/cmd/go/testdata/script/link_external_undef.txt
new file mode 100644 (file)
index 0000000..d86b3a3
--- /dev/null
@@ -0,0 +1,48 @@
+
+# Test case for issue 47993, in which the linker crashes
+# on a bad input instead of issuing an error and exiting.
+
+# This test requires external linking, so use cgo as a proxy 
+[!cgo] skip
+
+! go build -ldflags='-linkmode=external' .
+! stderr 'panic'
+stderr '^.*unreachable sym in relocation.*'
+
+-- go.mod --
+
+module issue47993
+
+go 1.16
+
+-- main.go --
+
+package main
+
+type M struct {
+       b bool
+}
+
+// Note the body-less func def here. This is what causes the problems.
+func (m *M) run(fp func())
+
+func doit(m *M) {
+        InAsm()
+       m.run(func() {
+       })
+}
+
+func main() {
+     m := &M{true}
+     doit(m)
+}
+
+func InAsm() 
+
+-- main.s --
+
+// Add an assembly function so as to leave open the possibility
+// that body-less functions in Go might be defined in assembly.
+
+// Currently we just need an empty file here.
+
diff --git a/src/cmd/go/testdata/script/list_all_gobuild.txt b/src/cmd/go/testdata/script/list_all_gobuild.txt
new file mode 100644 (file)
index 0000000..e0a4739
--- /dev/null
@@ -0,0 +1,41 @@
+# go list all should work with GOOS=linux because all packages build on Linux
+env GOOS=linux
+go list all
+
+# go list all should work with GOOS=darwin, but it used to fail because
+# in the absence of //go:build support, p looked like it needed q
+# (p_test.go was not properly excluded), and q was Linux-only.
+#
+# Also testing with r and s that +build lines keep working.
+env GOOS=darwin
+go list all
+
+-- go.mod --
+go 1.17
+module m
+
+-- p/p.go --
+package p
+
+-- p/p_test.go --
+//go:build linux
+
+package p
+
+import "m/q"
+
+-- q/q_linux.go --
+package q
+
+-- r/r.go --
+package r
+
+-- r/r_test.go --
+// +build linux
+
+package r
+
+import "m/s"
+
+-- s/s_linux.go --
+package s
diff --git a/src/cmd/go/testdata/script/list_reserved.txt b/src/cmd/go/testdata/script/list_reserved.txt
new file mode 100644 (file)
index 0000000..b9c5361
--- /dev/null
@@ -0,0 +1,7 @@
+# https://golang.org/issue/37641: the paths "example" and "test" are reserved
+# for end users, and must never exist in the standard library.
+
+go list example/... test/...
+stderr 'go: warning: "example/..." matched no packages$'
+stderr 'go: warning: "test/..." matched no packages$'
+! stdout .
index 7b24d9367aede1c6e3c32c38fda4b93c571b90dc..660508de9ff83c1b75b8814682823d866109ca9b 100644 (file)
@@ -15,7 +15,7 @@ stdout '^\(.*gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo\) \('$WORK
 
 # The error for go install should mention the conflicting directory.
 ! go install -n ./shadow/root2/src/foo
-stderr 'go install: no install location for '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo: hidden by '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)foo'
+stderr 'go: no install location for '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo: hidden by '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)foo'
 
 -- shadow/root1/src/foo/foo.go --
 package foo
index c6f1ecf40039097acadbde2977f817bf52f17c74..25dbb969b01c06a04d1869879168f4a52422923e 100644 (file)
@@ -44,6 +44,10 @@ stdout 'testdep_b <nil>'
 stdout 'nameerr\.test "[^"]*wrong signature for TestBad'
 ! stderr 'wrong signature for TestBad'
 
+# go list prints a useful error for generic test functions
+! go list -test -deps genericerr
+stderr 'wrong signature for TestGeneric, test functions cannot have type parameters'
+
 # go list prints partial information with error if test has cyclic import
 ! go list -test -deps cycleerr
 stdout cycleerr
@@ -106,6 +110,16 @@ import (
 
 func TestBad(t *testing.B) {}
 
+-- genericerr/genericerr.go --
+package genericerr
+
+-- genericerr/genericerr_test.go --
+package genericerr
+
+import "testing"
+
+func TestGeneric[T any](t *testing.T) {}
+
 -- cycleerr/cycleerr_test.go --
 package cycleerr
 
index 6fa2d8323965f025a5fdaa819ba117307eabad3c..b71a920870a9bb7ffd2ad3668e10af24eb98991c 100644 (file)
@@ -202,9 +202,9 @@ go mod edit -go=1.17 u/go.mod
 go mod edit -go=1.17 w/go.mod
 go mod edit -go=1.17 x/go.mod
 go mod edit -go=1.17
-cp go.mod go.mod.orig
+cmp go.mod go.mod.beforetidy
 go mod tidy
-cmp go.mod go.mod.orig
+cmp go.mod go.mod.aftertidy
 
 # With lazy loading, 'go list all' with neither -mod=vendor nor -test should
 # match -mod=vendor without -test in 1.15.
@@ -466,3 +466,66 @@ module example.com/x
 go 1.15
 -- x/x.go --
 package x
+-- go.mod.beforetidy --
+module example.com/main
+
+// Note: this go.mod file initially specifies go 1.15,
+// but includes some redundant roots so that it
+// also already obeys the 1.17 lazy loading invariants.
+go 1.17
+
+require (
+       example.com/a v0.1.0
+       example.com/b v0.1.0 // indirect
+       example.com/q v0.1.0
+       example.com/r v0.1.0 // indirect
+       example.com/t v0.1.0
+       example.com/u v0.1.0 // indirect
+)
+
+replace (
+       example.com/a v0.1.0 => ./a
+       example.com/b v0.1.0 => ./b
+       example.com/c v0.1.0 => ./c
+       example.com/d v0.1.0 => ./d
+       example.com/q v0.1.0 => ./q
+       example.com/r v0.1.0 => ./r
+       example.com/s v0.1.0 => ./s
+       example.com/t v0.1.0 => ./t
+       example.com/u v0.1.0 => ./u
+       example.com/w v0.1.0 => ./w
+       example.com/x v0.1.0 => ./x
+)
+-- go.mod.aftertidy --
+module example.com/main
+
+// Note: this go.mod file initially specifies go 1.15,
+// but includes some redundant roots so that it
+// also already obeys the 1.17 lazy loading invariants.
+go 1.17
+
+require (
+       example.com/a v0.1.0
+       example.com/q v0.1.0
+       example.com/t v0.1.0
+)
+
+require (
+       example.com/b v0.1.0 // indirect
+       example.com/r v0.1.0 // indirect
+       example.com/u v0.1.0 // indirect
+)
+
+replace (
+       example.com/a v0.1.0 => ./a
+       example.com/b v0.1.0 => ./b
+       example.com/c v0.1.0 => ./c
+       example.com/d v0.1.0 => ./d
+       example.com/q v0.1.0 => ./q
+       example.com/r v0.1.0 => ./r
+       example.com/s v0.1.0 => ./s
+       example.com/t v0.1.0 => ./t
+       example.com/u v0.1.0 => ./u
+       example.com/w v0.1.0 => ./w
+       example.com/x v0.1.0 => ./x
+)
index 7a270d0f07cac7fa76a670037dbb6678536db7d6..afd6e5186c152ac7f9ad6ba6547c7d9bafa10064 100644 (file)
@@ -2,7 +2,7 @@ env GO111MODULE=on
 
 # explicit get should report errors about bad names
 ! go get appengine
-stderr '^go get: malformed module path "appengine": missing dot in first path element$'
+stderr '^go: malformed module path "appengine": missing dot in first path element$'
 ! go get x/y.z
 stderr 'malformed module path "x/y.z": missing dot in first path element'
 
@@ -24,10 +24,10 @@ stderr '^usenonexistent[/\\]x.go:2:8: no required module provides package nonexi
 
 # 'get -d' should be similarly definitive
 
-go get -d ./useappengine  # TODO(#41315): This should fail.
+go get ./useappengine  # TODO(#41315): This should fail.
  # stderr '^useappengine[/\\]x.go:2:8: cannot find package$'
 
-! go get -d  ./usenonexistent
+! go get  ./usenonexistent
 stderr '^x/usenonexistent imports\n\tnonexistent.rsc.io: cannot find module providing package nonexistent.rsc.io$'
 
 
index cee055eabe9c26d0c1d6c4ca79d3b2121eb29956..5c3c309b0dc86e40394e88625e9fc3520ba7f263 100644 (file)
@@ -11,7 +11,7 @@ stderr '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": in
 
 # TODO(#41688): This should include a file and line, and report the reason for the error..
 # (Today it includes only an import stack.)
-! go get -d ./main
+! go get ./main
 stderr '^m/main imports\n\tm/bad imports\n\t🐧.example.com/string: malformed import path "🐧.example.com/string": invalid char ''🐧''$'
 
 
diff --git a/src/cmd/go/testdata/script/mod_build_trimpath_issue48557.txt b/src/cmd/go/testdata/script/mod_build_trimpath_issue48557.txt
new file mode 100644 (file)
index 0000000..859eafc
--- /dev/null
@@ -0,0 +1,52 @@
+# Regression test for issue #48557.
+# Since builds in module mode do not support relative imports at all, the build
+# ID for (and other contents of) a binary built with -trimpath in module mode
+# should not depend on its working directory, even if the binary is specified as
+# a list of relative source files.
+
+[short] skip  # links and runs binaries
+
+env GOFLAGS=-trimpath
+env GOCACHE=$WORK/gocache
+
+
+# When we build a binary in module mode with -trimpath, the -D flag (for the
+# "local import prefix") should not be passed to it.
+
+cd $WORK/tmp/foo
+go build -x -o a.exe main.go
+stderr ${/}compile$GOEXE.*' -nolocalimports'
+! stderr ${/}compile$GOEXE.*' -D[ =]'
+
+go tool buildid a.exe
+cp stdout ../foo-buildid.txt
+go version a.exe
+cp stdout ../foo-version.txt
+cd ..
+
+
+# On the second build — in a different directory but with -trimpath — the
+# compiler should not be invoked, since the cache key should be identical.
+# Only the linker and buildid tool should be needed.
+
+mkdir bar
+cp foo/main.go bar/main.go
+cd bar
+go build -x -o a.exe main.go
+! stderr ${/}compile$GOEXE
+
+go tool buildid a.exe
+cp stdout ../bar-buildid.txt
+go version a.exe
+cp stdout ../bar-version.txt
+cd ..
+
+cmp bar-buildid.txt foo-buildid.txt
+cmp bar-version.txt foo-version.txt
+cmp bar/a.exe foo/a.exe
+
+
+-- $WORK/tmp/foo/main.go --
+package main
+
+func main() {}
index d1d74de10c22b1b75cd79a237b8e6c3b36db519c..f55041834aefe874bb195b4ce77999545846a668 100644 (file)
@@ -1,7 +1,7 @@
 env GO111MODULE=on
 [short] skip
 
-go get -d rsc.io/fortune/v2
+go get rsc.io/fortune/v2
 
 # The default executable name shouldn't be v2$GOEXE
 go build rsc.io/fortune/v2
index 7284ccf8bab735aa5613f08608228f41ec778c9f..4045928a9781b7e5cbb826508be511f551f395b3 100644 (file)
@@ -3,9 +3,9 @@ env GO111MODULE=on
 # Go should reject relative paths in GOMODCACHE environment.
 
 env GOMODCACHE="~/test"
-! go get example.com/tools/cmd/hello
+! go install example.com/tools/cmd/hello@latest
 stderr 'must be absolute path'
 
 env GOMODCACHE="./test"
-! go get example.com/tools/cmd/hello
+! go install example.com/tools/cmd/hello@latest
 stderr 'must be absolute path'
index a5410764bc00f86469f13173f0bf465d87be9cd4..07755415d608a46748b658ae808f67e575ec5d9b 100644 (file)
@@ -5,7 +5,7 @@ env GO111MODULE=on
 # golang.org/issue/31481: an explicit flag should make directories in the module
 # cache writable in order to work around the historical inability of 'rm -rf' to
 # forcibly remove files in unwritable directories.
-go get -modcacherw -d rsc.io/quote@v1.5.2
+go get -modcacherw rsc.io/quote@v1.5.2
 cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
 
 # After adding an extraneous file, 'go mod verify' should fail.
@@ -28,7 +28,7 @@ cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
 # Windows does not respect FILE_ATTRIBUTE_READONLY on directories, according
 # to MSDN, so there we disable testing whether the directory itself is
 # unwritable.
-go get -d rsc.io/quote@latest
+go get rsc.io/quote@latest
 [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
 [!windows] [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
 ! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
index 4a4698600f7fb965162272a5eb7df75919712bc0..d3fb11dfa332168acb0ffa4188800d4bbb4a7d60 100644 (file)
@@ -1,6 +1,6 @@
 env GO111MODULE=on
 
-go get -d
+go get
 go list -m all
 stdout '^rsc.io/quote v1.5.2'
 stdout '^rsc.io/QUOTE v1.5.2'
@@ -9,7 +9,7 @@ go list -f 'DIR {{.Dir}} DEPS {{.Deps}}' rsc.io/QUOTE/QUOTE
 stdout 'DEPS.*rsc.io/quote'
 stdout 'DIR.*!q!u!o!t!e'
 
-go get -d rsc.io/QUOTE@v1.5.3-PRE
+go get rsc.io/QUOTE@v1.5.3-PRE
 go list -m all
 stdout '^rsc.io/QUOTE v1.5.3-PRE'
 
index f3d6aaa5abc77bc02d61faed05e242de12cb5476..7c768a096395d93ec984a73eaf712c0ba389ba78 100644 (file)
@@ -2,7 +2,7 @@
 
 env GO111MODULE=on
 
-go get -d rsc.io/CGO
+go get rsc.io/CGO
 [short] stop
 
 go build rsc.io/CGO
index 8c215251587180600da62bdbde2a77b61f5beed4..e2224d659b23a53dc28092a3eb153a5b0648a655 100644 (file)
@@ -1,7 +1,7 @@
 env GO111MODULE=on
 
 # Concurrent builds should succeed, even if they need to download modules.
-go get -d ./x ./y
+go get ./x ./y
 go build ./x &
 go build ./y
 wait
index 567027935dc338c32ec73644c594253b640c3cc6..8e2771dc1f2250b542c4c737ec0cfeeb196a1278 100644 (file)
@@ -1,25 +1,25 @@
 # When there is a short single-line message, 'go get' should print it all.
-go get -d short
+go get short
 stderr '^go: module short is deprecated: short$'
 go list -m -u -f '{{.Deprecated}}' short
 stdout '^short$'
 
 # When there is a multi-line message, 'go get' should print the first line.
-go get -d multiline
+go get multiline
 stderr '^go: module multiline is deprecated: first line$'
 ! stderr 'second line'
 go list -m -u -f '{{.Deprecated}}' multiline
 stdout '^first line\nsecond line.$'
 
 # When there is a long message, 'go get' should print a placeholder.
-go get -d long
+go get long
 stderr '^go: module long is deprecated: \(message omitted: too long\)$'
 go list -m -u -f '{{.Deprecated}}' long
 stdout '^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa$'
 
 # When a message contains unprintable chracters, 'go get' should say that
 # without printing the message.
-go get -d unprintable
+go get unprintable
 stderr '^go: module unprintable is deprecated: \(message omitted: contains non-printable characters\)$'
 go list -m -u -f '{{.Deprecated}}' unprintable
 stdout '^message contains ASCII BEL\x07$'
index 14745b5812c68296354cb7116cc9553b16357b94..c13029d534163e0f58b7e2de27d989cc7fadcf96 100644 (file)
@@ -2,7 +2,7 @@
 # (example.com not example.com/something)
 
 env GO111MODULE=on
-go get -d
+go get
 
 -- go.mod --
 module x
index ca8d5c6cc2d62d9ebd1a64f72efdfaae15d22cf4..cb60e988b6dfcc671e59c35f31a9f28b08f67ac0 100644 (file)
@@ -5,11 +5,11 @@ env GO111MODULE=on
 # to resolve an external module.
 cd dir
 ! go get
-stderr '^go get: no package in current directory$'
+stderr '^go: no package to get in current directory$'
 ! go get .
-stderr '^go get \.: no package in current directory$'
+stderr '^go: .: no package to get in current directory$'
 ! go get ./subdir
-stderr '^go get: \.[/\\]subdir \('$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir\) is not a package in module rooted at '$WORK'[/\\]gopath[/\\]src[/\\]dir$'
+stderr '^go: \.[/\\]subdir \('$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir\) is not a package in module rooted at '$WORK'[/\\]gopath[/\\]src[/\\]dir$'
 ! go list
 ! stderr 'cannot find module providing package'
 stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir$'
index c2b72b2a02cab8f681872c637d1d9990c9131db5..154e68338b6b3e2f2bdfd63e3d789c7f664dd1e9 100644 (file)
@@ -93,19 +93,19 @@ exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip
 
 # download reports errors encountered when locating modules
 ! go mod download bad/path
-stderr '^go mod download: module bad/path: not a known dependency$'
+stderr '^go: module bad/path: not a known dependency$'
 ! go mod download bad/path@latest
-stderr '^go mod download: bad/path@latest: malformed module path "bad/path": missing dot in first path element$'
+stderr '^go: bad/path@latest: malformed module path "bad/path": missing dot in first path element$'
 ! go mod download rsc.io/quote@v1.999.999
-stderr '^go mod download: rsc.io/quote@v1.999.999: reading .*/v1.999.999.info: 404 Not Found$'
+stderr '^go: rsc.io/quote@v1.999.999: reading .*/v1.999.999.info: 404 Not Found$'
 ! go mod download -json bad/path
 stdout '^\t"Error": "module bad/path: not a known dependency"'
 
 # download main module produces a warning or error
 go mod download m
-stderr '^go mod download: skipping argument m that resolves to the main module\n'
+stderr '^go: skipping download of m that resolves to the main module\n'
 ! go mod download m@latest
-stderr '^go mod download: m@latest: malformed module path "m": missing dot in first path element$'
+stderr '^go: m@latest: malformed module path "m": missing dot in first path element$'
 
 # download without arguments updates go.mod and go.sum after loading the
 # build list, but does not save sums for downloaded zips.
@@ -128,6 +128,50 @@ rm go.sum
 go mod download all
 cmp go.mod.update go.mod
 grep '^rsc.io/sampler v1.3.0 ' go.sum
+
+# https://golang.org/issue/44435: At go 1.17 or higher, 'go mod download'
+# (without arguments) should only download the modules explicitly required in
+# the go.mod file, not (presumed-irrelevant) transitive dependencies.
+#
+# (If the go.mod file is inconsistent, the version downloaded should be the
+# selected version from the broader graph, but the go.mod file will also be
+# updated to list the correct versions. If at some point we change 'go mod
+# download' to stop updating for consistency, then it should fail if the
+# requirements are inconsistent.)
+
+rm go.sum
+cp go.mod.orig go.mod
+go mod edit -go=1.17
+cp go.mod.update go.mod.go117
+go mod edit -go=1.17 go.mod.go117
+
+go clean -modcache
+go mod download
+cmp go.mod go.mod.go117
+
+go list -e -m all
+stdout '^rsc.io/quote v1.5.2$'
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+stdout '^rsc.io/sampler v1.3.0$'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.2.1.zip
+exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.3.0.zip
+stdout '^golang\.org/x/text v0.0.0-20170915032832-14c0d48ead0c$'
+! exists $GOPATH/pkg/mod/cache/download/golang.org/x/text/@v/v0.0.0-20170915032832-14c0d48ead0c.zip
+cmp go.mod go.mod.go117
+
+# However, 'go mod download all' continues to download the selected version
+# of every module reported by 'go list -m all'.
+
+cp go.mod.orig go.mod
+go mod edit -go=1.17
+go clean -modcache
+go mod download all
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.2.1.zip
+exists $GOPATH/pkg/mod/cache/download/rsc.io/sampler/@v/v1.3.0.zip
+exists $GOPATH/pkg/mod/cache/download/golang.org/x/text/@v/v0.0.0-20170915032832-14c0d48ead0c.zip
+cmp go.mod go.mod.go117
+
 cd ..
 
 # allow go mod download without go.mod
similarity index 65%
rename from src/cmd/go/testdata/script/mod_get_insecure_redirect.txt
rename to src/cmd/go/testdata/script/mod_download_insecure_redirect.txt
index 2e1283449554072c43509f293f8e64c11221e30d..46eb666686502cafdea600ab9b0ec044bb454212 100644 (file)
@@ -7,26 +7,26 @@ env GO111MODULE=on
 env GOPROXY=direct
 env GOSUMDB=off
 
-! go get -d vcs-test.golang.org/insecure/go/insecure
+! go mod download vcs-test.golang.org/insecure/go/insecure@latest
 stderr 'redirected .* to insecure URL'
 
 # insecure host
 env GOINSECURE=vcs-test.golang.org
 go clean -modcache
-go get -d vcs-test.golang.org/insecure/go/insecure
+go mod download vcs-test.golang.org/insecure/go/insecure@latest
 
 # insecure glob host
 env GOINSECURE=*.golang.org
 go clean -modcache
-go get -d vcs-test.golang.org/insecure/go/insecure
+go mod download vcs-test.golang.org/insecure/go/insecure@latest
 
 # insecure multiple host
 env GOINSECURE=somewhere-else.com,*.golang.org
 go clean -modcache
-go get -d vcs-test.golang.org/insecure/go/insecure
+go mod download vcs-test.golang.org/insecure/go/insecure@latest
 
 # different insecure host does not fetch
 env GOINSECURE=somewhere-else.com
 go clean -modcache
-! go get -d vcs-test.golang.org/insecure/go/insecure
+! go mod download vcs-test.golang.org/insecure/go/insecure@latest
 stderr 'redirected .* to insecure URL'
index 0aab60ddaf00f84c24f19073af65dc0bec5dc8a2..3a02fcd7474b5b795f3159d1ac718e3b541f3764 100644 (file)
@@ -1,5 +1,5 @@
 # Download modules and populate go.sum.
-go get -d -modcacherw
+go get -modcacherw
 exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
 
 # 'go mod verify' should fail if we delete a file.
similarity index 79%
rename from src/cmd/go/testdata/script/mod_get_private_vcs.txt
rename to src/cmd/go/testdata/script/mod_download_private_vcs.txt
index 75c776a7fa29c78d1856d381fa2a938b15348034..e126793907241b65c6de002dc3cb200f37dd2fea 100644 (file)
@@ -5,18 +5,18 @@ env GO111MODULE=on
 [!exec:git] skip
 env GOPROXY=direct
 
-! go get github.com/golang/nonexist
+! go mod download github.com/golang/nonexist@latest
 stderr 'Confirm the import path was entered correctly.'
 stderr 'If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.'
 ! stdout .
 
 # Fetching a nonexistent commit should return an "unknown revision"
 # error message.
-! go get github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b
-stderr '^go get: github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b: invalid version: unknown revision 86186f3aba07ed0212cfb944f3398997d2d07c6b$'
+! go mod download github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b
+stderr '^go: github.com/golang/term@86186f3aba07ed0212cfb944f3398997d2d07c6b: invalid version: unknown revision 86186f3aba07ed0212cfb944f3398997d2d07c6b$'
 ! stdout .
 
-! go get github.com/golang/nonexist@master
+! go mod download github.com/golang/nonexist@master
 stderr '^Confirm the import path was entered correctly.$'
 stderr '^If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.$'
 ! stderr 'unknown revision'
similarity index 61%
rename from src/cmd/go/testdata/script/mod_get_svn.txt
rename to src/cmd/go/testdata/script/mod_download_svn.txt
index 3817fce9b61f87ee027b88c68bcd1ad87fbc199a..79e00dc9706c9fd80ba7f7a37eec2e076678817b 100644 (file)
@@ -1,7 +1,7 @@
 [!net] skip
 [!exec:svn] skip
 
-# 'go get' will fall back to svn+ssh once svn fails over protocols like https.
+# 'go mod download' will fall back to svn+ssh once svn fails over protocols like https.
 # If vcs-test.golang.org isn't in the user's known_hosts file, this will result
 # in an ssh prompt, which will stop 'go test' entirely
 #
@@ -19,18 +19,11 @@ env GOPROXY=direct
 env GOSUMDB=off
 
 # Attempting to get a module zip using svn should succeed.
-go get vcs-test.golang.org/svn/hello.svn@000000000001
+go mod download vcs-test.golang.org/svn/hello.svn@000000000001
 exists $GOPATH/pkg/mod/cache/download/vcs-test.golang.org/svn/hello.svn/@v/v0.0.0-20170922011245-000000000001.zip
-exists $GOPATH/bin/hello.svn$GOEXE
 
 # Attempting to get a nonexistent module using svn should fail with a
 # reasonable message instead of a panic.
-! go get -d vcs-test.golang.org/svn/nonexistent.svn
+! go mod download vcs-test.golang.org/svn/nonexistent.svn@latest
 ! stderr panic
-stderr 'go get vcs-test.golang.org/svn/nonexistent.svn: no matching versions for query "upgrade"'
-
--- go.mod --
-module golang/go/issues/28943/main
--- go.sum --
-vcs-test.golang.org/svn/hello.svn v0.0.0-20170922011245-000000000001 h1:rZjvboXMfQICKXdhx/QHqJ2Y/AQsJVrXnwGqwcTxQiw=
-vcs-test.golang.org/svn/hello.svn v0.0.0-20170922011245-000000000001/go.mod h1:0memnh/BRLuxiK2zF4rvUgz6ts/fhhB28l3ULFWPusc=
+stderr 'go: module vcs-test.golang.org/svn/nonexistent.svn: no matching versions for query "latest"$'
similarity index 69%
rename from src/cmd/go/testdata/script/mod_get_too_many_redirects.txt
rename to src/cmd/go/testdata/script/mod_download_too_many_redirects.txt
index 9cbe0d279dea3073b7cbdffd60dd36a7830d4c07..a6b5a59054872926ed3fceb269e8899bc89c38d2 100644 (file)
@@ -3,8 +3,8 @@ env GOPROXYBASE=$GOPROXY
 env GOPROXY=$GOPROXYBASE/redirect/11
 env GOSUMDB=off
 
-! go get -d rsc.io/quote@v1.2.0
+! go mod download 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
+go mod download rsc.io/quote@v1.2.0
index 5aa5ca1ffc02c520d79eefa46e4d24f3b980dba4..ebc032a73cf7819171cb48b1137f16d497632d38 100644 (file)
@@ -23,18 +23,18 @@ cmpenv go.mod $WORK/go.mod.edit2
 
 # -exclude and -retract reject invalid versions.
 ! go mod edit -exclude=example.com/m@bad
-stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$'
+stderr '^go: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$'
 ! go mod edit -retract=bad
-stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$'
+stderr '^go: -retract=bad: version "bad" invalid: must be of the form v1.2.3$'
 
 ! go mod edit -exclude=example.com/m@v2.0.0
-stderr '^go mod: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$'
+stderr '^go: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$'
 
 ! go mod edit -exclude=example.com/m/v2@v1.0.0
-stderr '^go mod: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$'
+stderr '^go: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$'
 
 ! go mod edit -exclude=gopkg.in/example.v1@v2.0.0
-stderr '^go mod: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$'
+stderr '^go: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$'
 
 cmpenv go.mod $WORK/go.mod.edit2
 
index daed03b02c6cf41b6367d6ffa1846c2e37d1d39d..92149933686a6fc5e7bdbd9733ac8e414c49c808 100644 (file)
@@ -4,14 +4,14 @@ cp go.mod go.mod.orig
 # If there is no sensible *package* meaning for 'm/p', it should refer
 # to *module* m/p.
 
-go get -d m/p  # @latest
+go get m/p  # @latest
 go list -m all
 stdout '^m/p v0.3.0 '
 ! stdout '^m '
 
 cp go.mod.orig go.mod
 
-go get -d m/p@v0.1.0
+go get m/p@v0.1.0
 go list -m all
 stdout '^m/p v0.1.0 '
 ! stdout '^m '
@@ -22,7 +22,7 @@ stdout '^m/p v0.1.0 '
 # (It only refers to *module* m/p if there is no such package at the
 # requested version.)
 
-go get -d m/p@v0.2.0
+go get m/p@v0.2.0
 go list -m all
 stdout '^m v0.2.0 '
 stdout '^m/p v0.1.0 '  # unchanged from the previous case
@@ -30,7 +30,7 @@ stdout '^m/p v0.1.0 '  # unchanged from the previous case
 # Repeating the above with module m/p already in the module graph does not
 # change its meaning.
 
-go get -d m/p@v0.2.0
+go get m/p@v0.2.0
 go list -m all
 stdout '^m v0.2.0 '
 stdout '^m/p v0.1.0 '
index 33605f51a5b505570a3b7c394bfe426b72862a39..0af78bd4f252d737e2880c783055dd4414fea408 100644 (file)
@@ -8,14 +8,14 @@ cp go.mod go.mod.orig
 #
 # TODO(#27899): Should we automatically upgrade example.net/m to v0.2.0
 # to resolve the conflict?
-! go get -d example.net/m/p@v1.0.0
+! go get example.net/m/p@v1.0.0
 stderr '^example.net/m/p: ambiguous import: found package example.net/m/p in multiple modules:\n\texample.net/m v0.1.0 \(.*[/\\]m1[/\\]p\)\n\texample.net/m/p v1.0.0 \(.*[/\\]p0\)\n\z'
 cmp go.mod go.mod.orig
 
 # Upgrading both modules simultaneously resolves the ambiguous upgrade.
 # Note that this command line mixes a module path (example.net/m)
 # and a package path (example.net/m/p) in the same command.
-go get -d example.net/m@v0.2.0 example.net/m/p@v1.0.0
+go get example.net/m@v0.2.0 example.net/m/p@v1.0.0
 
 go list -m all
 stdout '^example.net/m v0.2.0 '
index 0e7f93bccb5b8773ee9b461b27efa3f5511074cf..1641196007b8e166a685f00d292207a72b69d25c 100644 (file)
@@ -8,7 +8,7 @@ cp go.mod go.mod.orig
 # From a clean slate, 'go get' currently does the same thing as 'go mod tidy':
 # it resolves the package from the module with the longest matching prefix.
 
-go get -d example.net/ambiguous/nested/pkg@v0.1.0
+go get example.net/ambiguous/nested/pkg@v0.1.0
 go list -m all
 stdout '^example.net/ambiguous/nested v0.1.0$'
 ! stdout '^example.net/ambiguous '
@@ -21,7 +21,7 @@ stdout '^example.net/ambiguous/nested v0.1.0$'
 cp go.mod.orig go.mod
 go mod edit -require=example.net/ambiguous@v0.1.0
 
-go get -d example.net/ambiguous/nested/pkg@v0.1.0
+go get example.net/ambiguous/nested/pkg@v0.1.0
 go list -m all
 stdout '^example.net/ambiguous v0.1.0$'
 ! stdout '^example.net/ambiguous/nested '
@@ -30,7 +30,7 @@ stdout '^example.net/ambiguous v0.1.0$'
 # The user should be able to make the command unambiguous by explicitly
 # upgrading the conflicting module...
 
-go get -d example.net/ambiguous@v0.2.0 example.net/ambiguous/nested/pkg@v0.1.0
+go get example.net/ambiguous@v0.2.0 example.net/ambiguous/nested/pkg@v0.1.0
 go list -m all
 stdout '^example.net/ambiguous/nested v0.1.0$'
 stdout '^example.net/ambiguous v0.2.0$'
@@ -41,7 +41,7 @@ stdout '^example.net/ambiguous v0.2.0$'
 cp go.mod.orig go.mod
 go mod edit -require=example.net/ambiguous@v0.1.0
 
-go get -d example.net/ambiguous/nested/pkg@v0.1.0 example.net/ambiguous/nested@none
+go get example.net/ambiguous/nested/pkg@v0.1.0 example.net/ambiguous/nested@none
 go list -m all
 ! stdout '^example.net/ambiguous/nested '
 stdout '^example.net/ambiguous v0.1.0$'
@@ -53,7 +53,7 @@ stdout '^example.net/ambiguous v0.1.0$'
 cp go.mod.orig go.mod
 go mod edit -require=example.net/ambiguous@v0.1.0
 
-go get -d example.net/ambiguous@none example.net/ambiguous/nested/pkg@v0.1.0
+go get example.net/ambiguous@none example.net/ambiguous/nested/pkg@v0.1.0
 go list -m all
 stdout '^example.net/ambiguous/nested v0.1.0$'
 ! stdout '^example.net/ambiguous '
@@ -66,7 +66,7 @@ stdout '^example.net/ambiguous/nested v0.1.0$'
 
 cp go.mod.orig go.mod
 
-go get -d example.net/ambiguous/nested/pkg/...@v0.1.0
+go get example.net/ambiguous/nested/pkg/...@v0.1.0
 go list -m all
 stdout '^example.net/ambiguous/nested v0.1.0$'
 ! stdout '^example.net/ambiguous '
@@ -75,7 +75,7 @@ stdout '^example.net/ambiguous/nested v0.1.0$'
 cp go.mod.orig go.mod
 go mod edit -require=example.net/ambiguous@v0.1.0
 
-go get -d example.net/ambiguous/nested/pkg/...@v0.1.0
+go get example.net/ambiguous/nested/pkg/...@v0.1.0
 go list -m all
 ! stdout '^example.net/ambiguous/nested '
 stdout '^example.net/ambiguous v0.1.0$'
index 3287b2a6095a1c180fbfbe99031f4d776be772eb..12a112b4d87af75c8302dad7e5c1eedfbfec8a09 100644 (file)
@@ -3,9 +3,9 @@
 # for changed indirect dependencies.
 go list -m all
 ! stdout golang.org/x/text
-go get -d rsc.io/quote@v1.5.2
-stderr '^go get: added rsc.io/quote v1.5.2$'
-stderr '^go get: upgraded rsc.io/sampler v1.0.0 => v1.3.0$'
+go get rsc.io/quote@v1.5.2
+stderr '^go: added rsc.io/quote v1.5.2$'
+stderr '^go: upgraded rsc.io/sampler v1.0.0 => v1.3.0$'
 ! stderr '^go get.*golang.org/x/text'
 go list -m all
 stdout golang.org/x/text
@@ -14,18 +14,18 @@ cmp go.mod go.mod.upgrade
 # When removing a requirement, 'go get' prints a message for the requiremnent
 # and for changed explicit dependencies. 'go get' does not print messages
 # for changed indirect dependencies.
-go get -d rsc.io/sampler@none
-stderr '^go get: downgraded rsc.io/quote v1.5.2 => v1.3.0$'
-stderr '^go get: removed rsc.io/sampler v1.3.0$'
+go get rsc.io/sampler@none
+stderr '^go: downgraded rsc.io/quote v1.5.2 => v1.3.0$'
+stderr '^go: removed rsc.io/sampler v1.3.0$'
 ! stderr '^go get.*golang.org/x/text'
 cmp go.mod go.mod.downgrade
 
 # When removing or downgrading a requirement, 'go get' also prints a message
 # for explicit dependencies removed as a consequence.
 cp go.mod.usequote go.mod
-go get -d rsc.io/quote@v1.5.1
-stderr '^go get: downgraded rsc.io/quote v1.5.2 => v1.5.1$'
-stderr '^go get: removed usequote v0.0.0$'
+go get rsc.io/quote@v1.5.1
+stderr '^go: downgraded rsc.io/quote v1.5.2 => v1.5.1$'
+stderr '^go: removed usequote v0.0.0$'
 
 -- go.mod --
 module m
diff --git a/src/cmd/go/testdata/script/mod_get_cmd.txt b/src/cmd/go/testdata/script/mod_get_cmd.txt
deleted file mode 100644 (file)
index d31cee1..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-env GO111MODULE=on
-[short] skip
-
-# Test that when 'go get' is run from $GOBIN, it does not delete binaries
-# after it installs them. Verifies golang.org/issue/32766.
-
-go get example.com/tools/cmd/hello
-
-# 'go get' should not delete the command when run from $GOPATH/bin
-cd $GOPATH/bin
-exists hello$GOEXE
-go get example.com/tools/cmd/hello
-exists hello$GOEXE
-
-# 'go get' should not delete the command when run from a different $GOBIN
-mkdir $WORK/bin
-cd $WORK/bin
-env GOBIN=$WORK/bin
-go get example.com/tools/cmd/hello
-exists hello$GOEXE
index 0cf94ae1821e6602d77a6ea87ddc9c3416cafa1c..f60eaab3a77e09d4aee4c57839ce7098f1443f89 100644 (file)
@@ -5,18 +5,18 @@ env GO111MODULE=on
 
 # golang.org/x/text/language@commit should resolve.
 # Because of -d, the compiler should not run.
-go get -d -x golang.org/x/text/language@14c0d48
+go get -x golang.org/x/text/language@14c0d48
 ! stderr 'compile|cp|gccgo .*language\.a$'
 
 # go get should skip build with no Go files in root
-go get -d golang.org/x/text@14c0d48
+go get golang.org/x/text@14c0d48
 
 # dropping -d, we should see a build.
 [short] skip
 
 env GOCACHE=$WORK/gocache  # Looking for compile commands, so need a clean cache.
 
-go get -x golang.org/x/text/language@14c0d48
+go build -x golang.org/x/text/language
 stderr 'compile|cp|gccgo .*language\.a$'
 
 # BUG: after the build, the package should not be stale, as 'go install' would
@@ -24,19 +24,20 @@ stderr 'compile|cp|gccgo .*language\.a$'
 go list -f '{{.Stale}}' golang.org/x/text/language
 stdout ^true
 
-# install after get should not run the compiler again.
+# install after build should not run the compiler again.
 go install -x golang.org/x/text/language
 ! stderr 'compile|cp|gccgo .*language\.a$'
 
-# even with -d, we should see an error for unknown packages.
-! go get -d -x golang.org/x/text/foo@14c0d48
+# we should see an error for unknown packages.
+! go get -x golang.org/x/text/foo@14c0d48
+stderr '^go: module golang.org/x/text@14c0d48 found \(v0.3.0\), but does not contain package golang.org/x/text/foo$'
 
 # get pseudo-version should record that version
-go get -d rsc.io/quote@v0.0.0-20180214005840-23179ee8a569
+go get rsc.io/quote@v0.0.0-20180214005840-23179ee8a569
 grep 'rsc.io/quote v0.0.0-20180214005840-23179ee8a569' go.mod
 
 # but as commit should record as v1.5.1
-go get -d rsc.io/quote@23179ee8
+go get rsc.io/quote@23179ee8
 grep 'rsc.io/quote v1.5.1' go.mod
 
 # go mod edit -require does not interpret commits
index 63cd27a42d2bc76911d0e36f589adb4f97259f22..03258f52966fc745f3a1e01ac0b182e285c18b13 100644 (file)
@@ -2,10 +2,10 @@
 
 env GO111MODULE=on
 
-# 'go get' outside a module with an executable prints a deprecation message.
-go get example.com/cmd/a
-stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
-stderr 'Use ''go install pkg@version'' instead.'
+# 'go get' outside a module prints an error.
+go get example.com/cmd/a
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
 
 cp go.mod.orig go.mod
 
@@ -13,13 +13,16 @@ cp go.mod.orig go.mod
 # This will stop building in the future, but it's the command we want to use.
 go get rsc.io/quote
 ! stderr deprecated
+! stderr 'no longer installs'
 cp go.mod.orig go.mod
 
-# 'go get' inside a module with an executable prints a different
-# deprecation message.
+# 'go get' inside a module with an executable does not print a message.
+# In 1.16 and 1.17, 'go get' did print a message in this case suggesting the
+# use of -d. In 1.18, -d is a no-op, and we'd like to begin discouraging
+# its use.
 go get example.com/cmd/a
-stderr '^go get: installing executables with ''go get'' in module mode is deprecated.$'
-stderr 'To adjust and download dependencies of the current module, use ''go get -d'''
+! stderr deprecated
+! stderr 'no longer installs'
 cp go.mod.orig go.mod
 
 # 'go get' should not print a warning for a main package inside the main module.
index 7bdd7a58a89b5d15c43520055daf3eb7b4c1d8f8..ec7bcfdb997e2e57218f11108430f09f46ab1862 100644 (file)
@@ -1,31 +1,31 @@
 # 'go get pkg' should not show a deprecation message for an unrelated module.
-go get -d ./use/nothing
+go get ./use/nothing
 ! stderr 'module.*is deprecated'
 
 # 'go get pkg' should show a deprecation message for the module providing pkg.
-go get -d example.com/deprecated/a
+go get example.com/deprecated/a
 stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
-go get -d example.com/deprecated/a@v1.0.0
+go get example.com/deprecated/a@v1.0.0
 stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
 
 # 'go get pkg' should show a deprecation message for a module providing
 # packages directly imported by pkg.
-go get -d ./use/a
+go get ./use/a
 stderr '^go: module example.com/deprecated/a is deprecated: in example.com/deprecated/a@v1.9.0$'
 
 # 'go get pkg' may show a deprecation message for an indirectly required module
 # if it provides a package named on the command line.
-go get -d ./use/b
+go get ./use/b
 ! stderr 'module.*is deprecated'
-go get -d local/use
+go get local/use
 ! stderr 'module.*is deprecated'
-go get -d example.com/deprecated/b
+go get example.com/deprecated/b
 stderr '^go: module example.com/deprecated/b is deprecated: in example.com/deprecated/b@v1.9.0$'
 
 # 'go get pkg' does not show a deprecation message for a module providing a
 # directly imported package if the module is no longer deprecated in its
 # latest version, even if the module is deprecated in its current version.
-go get -d ./use/undeprecated
+go get ./use/undeprecated
 ! stderr 'module.*is deprecated'
 
 -- go.mod --
index efc38f77c85d37b6d94840acc771bc06c2febf9e..0f5ba992da204ed28a6854cb29b0e6807f348e34 100644 (file)
@@ -18,7 +18,7 @@ cp go.mod go.mod.orig
 go mod tidy
 cmp go.mod.orig go.mod
 
-go get -d example.com/d@v0.1.0
+go get example.com/d@v0.1.0
 go list -m all
 stdout '^example.com/b v0.1.0 '
 stdout '^example.com/c v0.1.0 '
index c26c5e1c21013ada363965a4b768d36d921c6552..2eed56d9b71b899dac731e794e6bc18a50815653 100644 (file)
@@ -3,25 +3,25 @@ env GO111MODULE=on
 
 # downgrade sampler should downgrade quote
 cp go.mod.orig go.mod
-go get -d rsc.io/sampler@v1.0.0
+go get rsc.io/sampler@v1.0.0
 go list -m all
 stdout 'rsc.io/quote v1.4.0'
 stdout 'rsc.io/sampler v1.0.0'
 
 # downgrade sampler away should downgrade quote further
-go get -d rsc.io/sampler@none
+go get rsc.io/sampler@none
 go list -m all
 stdout 'rsc.io/quote v1.3.0'
 
 # downgrade should report inconsistencies and not change go.mod
-go get -d rsc.io/quote@v1.5.1
+go get rsc.io/quote@v1.5.1
 go list -m all
 stdout 'rsc.io/quote v1.5.1'
 stdout 'rsc.io/sampler v1.3.0'
 
-! go get -d rsc.io/sampler@v1.0.0 rsc.io/quote@v1.5.2 golang.org/x/text@none
-stderr -count=1 '^go get:'
-stderr '^go get: rsc.io/quote@v1.5.2 requires rsc.io/sampler@v1.3.0, not rsc.io/sampler@v1.0.0$'
+! go get rsc.io/sampler@v1.0.0 rsc.io/quote@v1.5.2 golang.org/x/text@none
+! stderr add|remove|upgrad|downgrad
+stderr '^go: rsc.io/quote@v1.5.2 requires rsc.io/sampler@v1.3.0, not rsc.io/sampler@v1.0.0$'
 
 go list -m all
 stdout 'rsc.io/quote v1.5.1'
@@ -29,7 +29,7 @@ stdout 'rsc.io/sampler v1.3.0'
 
 # go get -u args should limit upgrades
 cp go.mod.empty go.mod
-go get -d -u rsc.io/quote@v1.4.0 rsc.io/sampler@v1.0.0
+go get -u rsc.io/quote@v1.4.0 rsc.io/sampler@v1.0.0
 go list -m all
 stdout 'rsc.io/quote v1.4.0'
 stdout 'rsc.io/sampler v1.0.0'
@@ -40,7 +40,7 @@ stdout 'rsc.io/sampler v1.0.0'
 cp go.mod.orig go.mod
 go list -m -versions example.com/latemigrate/v2
 stdout v2.0.0 # proxy may serve incompatible versions
-go get -d rsc.io/quote@none
+go get rsc.io/quote@none
 go list -m all
 ! stdout 'example.com/latemigrate/v2'
 
index 5b768faeb1802c7ffca5389a0eb74d34aa7418db..582593b96cdfb6241e403216c214fd2668642549 100644 (file)
@@ -4,15 +4,15 @@ cp go.mod go.mod.orig
 # not yet present in that module should report the version mismatch
 # rather than a "matched no packages" warning.
 
-! go get -d example.net/pkgadded@v1.1.0 example.net/pkgadded/subpkg/...
-stderr '^go get: example.net/pkgadded@v1.1.0 conflicts with example.net/pkgadded/subpkg/...@upgrade \(v1.2.0\)$'
+! go get example.net/pkgadded@v1.1.0 example.net/pkgadded/subpkg/...
+stderr '^go: example.net/pkgadded@v1.1.0 conflicts with example.net/pkgadded/subpkg/...@upgrade \(v1.2.0\)$'
 ! stderr 'matched no packages'
 cmp go.mod.orig go.mod
 
 
 # A wildcard pattern should match the pattern with that path.
 
-go get -d example.net/pkgadded/...@v1.0.0
+go get example.net/pkgadded/...@v1.0.0
 go list -m all
 stdout '^example.net/pkgadded v1.0.0'
 cp go.mod.orig go.mod
@@ -22,12 +22,12 @@ cp go.mod.orig go.mod
 # and another argument constrains away the version that provides that
 # package, then 'go get' should fail with a useful error message.
 
-! go get -d example.net/pkgadded@v1.0.0 .
+! go get example.net/pkgadded@v1.0.0 .
 stderr '^example.com/m imports\n\texample.net/pkgadded/subpkg: cannot find module providing package example.net/pkgadded/subpkg$'
 ! stderr 'example.net/pkgadded v1\.2\.0'
 cmp go.mod.orig go.mod
 
-go get -d example.net/pkgadded@v1.0.0
+go get example.net/pkgadded@v1.0.0
 ! go list -deps -mod=readonly .
 stderr '^m.go:3:8: cannot find module providing package example\.net/pkgadded/subpkg: '
 
index c20583b22a136822effc89c7844217ab4ea8c8e4..111a54f8f7370cacb24af0852354e88246185921 100644 (file)
@@ -55,7 +55,7 @@ stdout '^example.com/d v0.1.0 '
 # upgrades of module d and addition of module e, which are not relevant to
 # b@v0.1.0 and should not be added to the main module's dependencies.
 
-go get -u -d example.com/a@latest example.com/c@v0.1.0
+go get -u example.com/a@latest example.com/c@v0.1.0
 
 go list -m all
 stdout '^example.com/a v0.1.0 '
index ced1dcd6b14e37a528f1a9e494c3e93a6acbf804..3a46a774ce7c4516ae97074111f3db5d6196fec4 100644 (file)
@@ -25,7 +25,7 @@ cp go.mod go.mod.orig
 go mod tidy
 cmp go.mod.orig go.mod
 
-go get -d example.com/d@v0.1.0
+go get example.com/d@v0.1.0
 go list -m all
 ! stdout '^example.com/b '
 ! stdout '^example.com/c '
index c49615cecb34d22ee114a974af6ecc2469814f4e..b678a177b521e32619b4afd6058e839813026327 100644 (file)
@@ -28,7 +28,7 @@ cmp go.mod.orig go.mod
 
 # When we downgrade d.2 to d.1, no dependency on e should be added
 # because nothing else in the module or import graph requires it.
-go get -d example.net/d@v0.1.0
+go get example.net/d@v0.1.0
 
 go list -m all
 stdout '^example.net/b v0.2.1-0.20210219000000-000000000000 '
index 5c37058d1c1b9508e8a77ce8fb3de85eabf34eaf..7cb03ce2f1e6b5b4f5b5efd63110653c0a172740 100644 (file)
@@ -1,35 +1,23 @@
 cp go.mod go.mod.orig
 
 
-# Both 'go get' and 'go get -d' should fail, without updating go.mod,
-# if the transitive dependencies of the requested package (by default,
-# the package in the current directory) cannot be resolved.
+# 'go get' should fail, without updating go.mod, if the transitive dependencies
+# of the requested package (by default, the package in the current directory)
+# cannot be resolved.
 
 ! go get
 stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$'
 cmp go.mod.orig go.mod
 
-! go get -d
-stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$'
-cmp go.mod.orig go.mod
-
 cd importsyntax
 
 
-# If 'go get' fails due to a compile error (such as a syntax error),
-# it should not update the go.mod file.
-
-! go get
-stderr '^..[/\\]badimport[/\\]syntaxerror[/\\]syntaxerror.go:1:1: expected ''package'', found pack$'  # TODO: An import stack would be nice.
-cmp ../go.mod.orig ../go.mod
-
-
 # A syntax error in a dependency prevents the compiler from needing that
-# dependency's imports, so 'go get -d' should not report an error when those
+# dependency's imports, so 'go get' should not report an error when those
 # imports cannot be resolved: it has all of the dependencies that the compiler
 # needs, and the user did not request to run the compiler.
 
-go get -d
+go get
 cmp ../go.mod.syntax-d ../go.mod
 
 
index 7efa24e87b0d3522d18a14b1c760ca6df88649c5..083e03678e48f1ebc0ffa5b1baece7841e8d258a 100644 (file)
@@ -4,7 +4,7 @@ cp go.mod go.mod.orig
 # determined by explicit queries to any version other than the explicit one.
 # Otherwise, 'go get -u' could introduce spurious dependencies.
 
-go get -d -u example.net/a@v0.1.0 example.net/b@v0.1.0
+go get -u example.net/a@v0.1.0 example.net/b@v0.1.0
 go list -m all
 stdout '^example.net/a v0.1.0 '
 stdout '^example.net/b v0.1.0 '
@@ -16,7 +16,7 @@ stdout '^example.net/b v0.1.0 '
 
 cp go.mod.orig go.mod
 
-go get -d -u example.net/a@v0.1.0 example.net/b/...@v0.1.0
+go get -u example.net/a@v0.1.0 example.net/b/...@v0.1.0
 go list -m all
 stdout '^example.net/a v0.1.0 '
 stdout '^example.net/b v0.1.0 '
index 9733fa366bea57eb19370d6cb125c87933f845f9..35722333d6a0e86b195f80ff13f1fa73c56fa3d1 100644 (file)
@@ -5,6 +5,11 @@ env GO111MODULE=on
 env GOPROXY=https://proxy.golang.org,direct
 env GOSUMDB=off
 
-go get -x -v -d golang.org/x/tools/cmd/goimports
+go get -x -v golang.org/x/tools/cmd/goimports
 stderr '# get https://proxy.golang.org/golang.org/x/tools/@v/list'
 ! stderr '# get https://golang.org'
+
+-- go.mod --
+module m
+
+go 1.18
index baad544557af8861bed6a0ab30d4126678a2bd8c..c2d42f0f596f4a01b0077a54aa515b9fba1f4f68 100644 (file)
@@ -18,11 +18,10 @@ env GOSUMDB=off
 env USER=fossiluser
 env FOSSIL_HOME=$WORK/home
 
-# Attempting to get the latest version of a fossil repo.
+# Attempt to get the latest version of a fossil repo.
 go get vcs-test.golang.org/fossil/hello.fossil
 ! stderr 'unexpected response from fossil info'
 grep 'vcs-test.golang.org/fossil/hello.fossil' go.mod
-exists $GOPATH/bin/hello.fossil$GOEXE
 
 -- go.mod --
 module x
index 0c7b5dc11c581f7a47d0bcb65e26b572da0a47e6..c81e491b947ecbe93955979ad978dfba8be7497d 100644 (file)
@@ -17,7 +17,7 @@ env GO111MODULE=on
 
 # argument has .go suffix, is a file and exists
 ! go get test.go
-stderr 'go get test.go: arguments must be package or module paths'
+stderr 'go: test.go: arguments must be package or module paths'
 
 # argument has .go suffix, doesn't exist and has no slashes
 ! go get test_missing.go
@@ -25,7 +25,7 @@ stderr 'arguments must be package or module paths'
 
 # argument has .go suffix, is a file and exists in sub-directory
 ! go get test/test.go
-stderr 'go get: test/test.go exists as a file, but ''go get'' requires package arguments'
+stderr 'go: test/test.go exists as a file, but ''go get'' requires package arguments'
 
 # argument has .go suffix, doesn't exist and has slashes
 ! go get test/test_missing.go
@@ -35,19 +35,19 @@ stderr 'go get: test/test.go exists as a file, but ''go get'' requires package a
 # argument has .go suffix, is a symlink and exists
 [symlink] symlink test_sym.go -> test.go
 [symlink] ! go get test_sym.go
-[symlink] stderr 'go get test_sym.go: arguments must be package or module paths'
+[symlink] stderr 'go: test_sym.go: arguments must be package or module paths'
 [symlink] rm test_sym.go
 
 # argument has .go suffix, is a symlink and exists in sub-directory
 [symlink] symlink test/test_sym.go -> test.go
 [symlink] ! go get test/test_sym.go
-[symlink] stderr 'go get: test/test_sym.go exists as a file, but ''go get'' requires package arguments'
+[symlink] stderr 'go: test/test_sym.go exists as a file, but ''go get'' requires package arguments'
 [symlink] rm test_sym.go
 
 # argument has .go suffix, is a directory and exists
 mkdir test_dir.go
 ! go get test_dir.go
-stderr 'go get test_dir.go: arguments must be package or module paths'
+stderr 'go: test_dir.go: arguments must be package or module paths'
 rm test_dir.go
 
 # argument has .go suffix, is a directory and exists in sub-directory
@@ -58,6 +58,11 @@ mkdir test/test_dir.go
 rm test/test_dir.go
 
 
+-- go.mod --
+module m
+
+go 1.18
+
 -- test.go --
 package main
 func main() {println("test")}
index 8000ee61481a01be883b022d17001ed2301f2a6b..5a7d70637180af3eb4c7c5483c102c47819523c8 100644 (file)
@@ -1,15 +1,15 @@
 env GO111MODULE=on
 
-go get -d x
+go get x
 go list -m all
 stdout 'rsc.io/breaker v2.0.0\+incompatible'
 
 cp go.mod2 go.mod
-go get -d rsc.io/breaker@7307b30
+go get rsc.io/breaker@7307b30
 go list -m all
 stdout 'rsc.io/breaker v2.0.0\+incompatible'
 
-go get -d rsc.io/breaker@v2.0.0
+go get rsc.io/breaker@v2.0.0
 go list -m all
 stdout 'rsc.io/breaker v2.0.0\+incompatible'
 
index e1cc1ab4115be419f6a779a508f125f17de11e6c..fa7edf22d7b997d0abd8648023d86488229e9b51 100644 (file)
@@ -27,7 +27,7 @@ grep 'golang.org/x/text v0.3.0 // indirect$' go.mod
 
 # indirect tag should be removed upon seeing direct import.
 cp $WORK/tmp/uselang.go x.go
-go get -d
+go get
 grep 'rsc.io/quote v1.5.2$' go.mod
 grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod
 
index 38b2031d3ae4a0fa16354af38e8879875c45e401..9392e73a174bd69e8efdfe49753f28f2f7d0d6fd 100644 (file)
@@ -6,7 +6,7 @@
 # 'go get foo@requested' should resolve the requested version,
 # not error out on the (unrelated) latest one.
 
-go get -d example.net/a/p@v0.2.0
+go get example.net/a/p@v0.2.0
 
 -- go.mod --
 module example
diff --git a/src/cmd/go/testdata/script/mod_get_issue47979.txt b/src/cmd/go/testdata/script/mod_get_issue47979.txt
new file mode 100644 (file)
index 0000000..848ee3a
--- /dev/null
@@ -0,0 +1,117 @@
+# Regression test for https://golang.org/issue/47979:
+#
+# An argument to 'go get' that results in an upgrade to a different existing
+# root should be allowed, and should not panic the 'go' command.
+
+cp go.mod go.mod.orig
+
+
+# Transitive upgrades from upgraded roots should not prevent
+# 'go get -u' from performing upgrades.
+
+cp go.mod.orig go.mod
+go get -u .
+cmp go.mod go.mod.want
+
+
+# 'go get' of a specific version should allow upgrades of
+# every dependency (transitively) required by that version,
+# including dependencies that are pulled into the module
+# graph by upgrading other root requirements
+# (in this case, example.net/indirect).
+
+cp go.mod.orig go.mod
+go get example.net/a@v0.2.0
+cmp go.mod go.mod.want
+
+
+-- go.mod --
+module golang.org/issue47979
+
+go 1.17
+
+replace (
+       example.net/a v0.1.0 => ./a1
+       example.net/a v0.2.0 => ./a2
+       example.net/indirect v0.1.0 => ./indirect1
+       example.net/indirect v0.2.0 => ./indirect2
+       example.net/other v0.1.0 => ./other
+       example.net/other v0.2.0 => ./other
+)
+
+require (
+       example.net/a v0.1.0
+       example.net/other v0.1.0
+)
+
+require example.net/indirect v0.1.0 // indirect
+-- go.mod.want --
+module golang.org/issue47979
+
+go 1.17
+
+replace (
+       example.net/a v0.1.0 => ./a1
+       example.net/a v0.2.0 => ./a2
+       example.net/indirect v0.1.0 => ./indirect1
+       example.net/indirect v0.2.0 => ./indirect2
+       example.net/other v0.1.0 => ./other
+       example.net/other v0.2.0 => ./other
+)
+
+require (
+       example.net/a v0.2.0
+       example.net/other v0.2.0
+)
+
+require example.net/indirect v0.2.0 // indirect
+-- issue.go --
+package issue
+
+import _ "example.net/a"
+-- useother/useother.go --
+package useother
+
+import _ "example.net/other"
+-- a1/go.mod --
+module example.net/a
+
+go 1.17
+
+require example.net/indirect v0.1.0
+-- a1/a.go --
+package a
+-- a2/go.mod --
+module example.net/a
+
+go 1.17
+
+require example.net/indirect v0.2.0
+-- a2/a.go --
+package a
+
+import "example.net/indirect"
+-- indirect1/go.mod --
+module example.net/indirect
+
+go 1.17
+
+require example.net/other v0.1.0
+-- indirect1/indirect.go --
+package indirect
+-- indirect2/go.mod --
+module example.net/indirect
+
+go 1.17
+
+require example.net/other v0.2.0
+-- indirect2/indirect.go --
+package indirect
+
+import "example.net/other"
+-- other/go.mod --
+module example.net/other
+
+go 1.17
+-- other/other.go --
+package other
index 241a0c2f0dfa8eaf6435c47007ff157f25f8ac26..00da0c316469f9bd3d5e54f8bd67eb931b53047c 100644 (file)
@@ -5,6 +5,6 @@
 env GO111MODULE=on
 
 go mod init m
-go get -d example.com/notags
+go get example.com/notags
 go list -m all
 stdout '^example.com/notags v0.0.0-20190507143103-cc8cbe209b64$'
diff --git a/src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt b/src/cmd/go/testdata/script/mod_get_lazy_upgrade_lazy.txt
new file mode 100644 (file)
index 0000000..3dae383
--- /dev/null
@@ -0,0 +1,68 @@
+# Check that 'go get -u' will upgrade a dependency (direct or indirect)
+# when the main module and the dependency are both lazy.
+# Verifies #47768.
+
+# Check that go.mod is tidy, and an upgrade is available.
+cp go.mod go.mod.orig
+go mod tidy
+cmp go.mod go.mod.orig
+
+go list -m -u example.com/lazyupgrade
+stdout '^example.com/lazyupgrade v0.1.0 \[v0.1.1\] => ./lazyupgrade@v0.1.0$'
+
+# 'go get -u' on a package that directly imports the dependency should upgrade.
+go get -u ./usedirect
+go list -m example.com/lazyupgrade
+stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$'
+cp go.mod.orig go.mod
+
+# 'go get -u' on a package that indirectly imports the dependency should upgrade.
+go get -u ./useindirect
+go list -m example.com/lazyupgrade
+stdout '^example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1$'
+
+-- go.mod --
+module use
+
+go 1.17
+
+require (
+       direct v0.0.0
+       example.com/lazyupgrade v0.1.0
+)
+
+replace (
+       direct => ./direct
+       example.com/lazyupgrade v0.1.0 => ./lazyupgrade@v0.1.0
+       example.com/lazyupgrade v0.1.1 => ./lazyupgrade@v0.1.1
+)
+-- usedirect/usedirect.go --
+package use
+
+import _ "example.com/lazyupgrade"
+-- useindirect/useindirect.go --
+package use
+
+import _ "direct"
+-- direct/go.mod --
+module direct
+
+go 1.17
+
+require example.com/lazyupgrade v0.1.0
+-- direct/direct.go --
+package direct
+
+import _ "example.com/lazyupgrade"
+-- lazyupgrade@v0.1.0/go.mod --
+module example.com/lazyupgrade
+
+go 1.17
+-- lazyupgrade@v0.1.0/lazyupgrade.go --
+package lazyupgrade
+-- lazyupgrade@v0.1.1/go.mod --
+module example.com/lazyupgrade
+
+go 1.17
+-- lazyupgrade@v0.1.1/lazyupgrade.go --
+package lazyupgrade
index eb09da58b3e23404626e37993efd9747d0811ff1..4c81d16a1fe072058a6cd4aeb5abcc6fc1ab519d 100644 (file)
@@ -7,7 +7,7 @@ cp go.mod go.mod.orig
 
 # 'go get -u' within the main module should work, even if it has a local-only name.
 cp go.mod.orig go.mod
-go get -d -u ./...
+go get -u ./...
 grep 'rsc.io/quote.*v1.5.2' go.mod
 grep 'golang.org/x/text.*v0.3.0' go.mod
 cp go.mod go.mod.implicitmod
@@ -15,34 +15,34 @@ cp go.mod go.mod.implicitmod
 # 'go get -u local/...' should be equivalent to 'go get -u ./...'
 # (assuming no nested modules)
 cp go.mod.orig go.mod
-go get -d -u local/...
+go get -u local/...
 cmp go.mod go.mod.implicitmod
 
 # For the main module, @patch should be a no-op.
 cp go.mod.orig go.mod
-go get -d -u local/...@patch
+go get -u local/...@patch
 cmp go.mod go.mod.implicitmod
 
-# 'go get -u -d' in the empty root of the main module should fail.
-# 'go get -u -d .' should also fail.
+# 'go get -u' in the empty root of the main module should fail.
+# 'go get -u .' should also fail.
 cp go.mod.orig go.mod
-! go get -u -d
-! go get -u -d .
+! go get -u
+! go get -u .
 
-# 'go get -u -d .' within a package in the main module updates the dependencies
+# 'go get -u .' within a package in the main module updates the dependencies
 # of that package.
 cp go.mod.orig go.mod
 cd uselang
-go get -u -d .
+go get -u .
 cd ..
 grep 'rsc.io/quote.*v1.3.0' go.mod
 grep 'golang.org/x/text.*v0.3.0' go.mod
 cp go.mod go.mod.dotpkg
 
-# 'go get -u -d' with an explicit package in the main module updates the
+# 'go get -u' with an explicit package in the main module updates the
 # dependencies of that package.
 cp go.mod.orig go.mod
-go get -u -d local/uselang
+go get -u local/uselang
 cmp go.mod go.mod.dotpkg
 
 -- go.mod --
index 50b2fee9ae1bfd82cd66feecfd420a324c5a10f7..cddd5f70826eb406a18e9efb55ed018f241f4ab0 100644 (file)
@@ -2,44 +2,44 @@ env GO111MODULE=on
 cp go.mod.orig go.mod
 
 # relative and absolute paths must be within the main module.
-! go get -d ..
-stderr '^go get: \.\. \('$WORK'[/\\]gopath\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
-! go get -d $WORK
-stderr '^go get: '$WORK' is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
-! go get -d ../...
-stderr '^go get: \.\./\.\.\. \('$WORK'[/\\]gopath([/\\]...)?\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
-! go get -d $WORK/...
-stderr '^go get: '$WORK'[/\\]\.\.\. is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
+! go get ..
+stderr '^go: \.\. \('$WORK'[/\\]gopath\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
+! go get $WORK
+stderr '^go: '$WORK' is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
+! go get ../...
+stderr '^go: \.\./\.\.\. \('$WORK'[/\\]gopath([/\\]...)?\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
+! go get $WORK/...
+stderr '^go: '$WORK'[/\\]\.\.\. is not within module rooted at '$WORK'[/\\]gopath[/\\]src$'
 
 # @patch and @latest within the main module refer to the current version.
 # The main module won't be upgraded, but missing dependencies will be added.
-go get -d rsc.io/x
+go get rsc.io/x
 grep 'rsc.io/quote v1.5.2' go.mod
-go get -d rsc.io/x@upgrade
+go get rsc.io/x@upgrade
 grep 'rsc.io/quote v1.5.2' go.mod
 cp go.mod.orig go.mod
-go get -d rsc.io/x@patch
+go get rsc.io/x@patch
 grep 'rsc.io/quote v1.5.2' go.mod
 cp go.mod.orig go.mod
 
 
 # Upgrading a package pattern not contained in the main module should not
 # attempt to upgrade the main module.
-go get -d rsc.io/quote/...@v1.5.1
+go get rsc.io/quote/...@v1.5.1
 grep 'rsc.io/quote v1.5.1' go.mod
 
 
 # The main module cannot be updated to a specific version.
-! go get -d rsc.io@v0.1.0
-stderr '^go get: can''t request version "v0.1.0" of the main module \(rsc.io\)$'
+! go get rsc.io@v0.1.0
+stderr '^go: can''t request version "v0.1.0" of the main module \(rsc.io\)$'
 
 # A package in the main module can't be upgraded either.
-! go get -d rsc.io/x@v0.1.0
-stderr '^go get: package rsc.io/x is in the main module, so can''t request version v0.1.0$'
+! go get rsc.io/x@v0.1.0
+stderr '^go: package rsc.io/x is in the main module, so can''t request version v0.1.0$'
 
 # Nor can a pattern matching packages in the main module.
-! go get -d rsc.io/x/...@latest
-stderr '^go get: pattern rsc.io/x/... matches package rsc.io/x in the main module, so can''t request version latest$'
+! go get rsc.io/x/...@latest
+stderr '^go: pattern rsc.io/x/... matches package rsc.io/x in the main module, so can''t request version latest$'
 
 -- go.mod.orig --
 module rsc.io
index 367ede9ded45ba5278d47437a4c989bdf44fb2d9..2db13180bd79786283919bba2e6e5d61ebe2c5c3 100644 (file)
@@ -8,12 +8,12 @@ env GOSUMDB=off
 # golang.org/issue/34383: if a module path ends in a major-version suffix,
 # ensure that 'direct' mode can resolve the package to a module.
 
-go get -d vcs-test.golang.org/git/v3pkg.git/v3@v3.0.0
+go get vcs-test.golang.org/git/v3pkg.git/v3@v3.0.0
 
 go list -m vcs-test.golang.org/git/v3pkg.git/v3
 stdout '^vcs-test.golang.org/git/v3pkg.git/v3 v3.0.0$'
 
-go get -d vcs-test.golang.org/git/empty-v2-without-v1.git/v2@v2.0.0
+go get vcs-test.golang.org/git/empty-v2-without-v1.git/v2@v2.0.0
 
 go list -m vcs-test.golang.org/git/empty-v2-without-v1.git/v2
 stdout '^vcs-test.golang.org/git/empty-v2-without-v1.git/v2 v2.0.0$'
index 789d42d24dbca7184ff3572e50162f448acc5ab4..5934251e4b8b74688a40d060c261147b77a3e6d1 100644 (file)
@@ -13,7 +13,7 @@ env GOSUMDB=off
 cp go.sum.bug go.sum
 ! go build -n use
 stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$'
-go get -d use
+go get use
 cmp go.sum go.sum.tidy
 go build -n use
 
@@ -22,7 +22,7 @@ cp go.sum.bug go.sum
 rm $WORK/gopath/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.ziphash
 ! go build -n use
 stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$'
-go get -d use
+go get use
 cmp go.sum go.sum.tidy
 go build -n use
 
index 8430a737c40ca00842f14faede5001baa2f81a7e..ba79c8263c06dab4ab02ee466cf08275b99ea02c 100644 (file)
@@ -4,17 +4,17 @@ env GO111MODULE=on
 # A 'go get' that worked at a previous version should continue to work at that version,
 # even if the package was subsequently moved into a submodule.
 go mod init example.com/foo
-go get -d example.com/split/subpkg@v1.0.0
+go get example.com/split/subpkg@v1.0.0
 go list -m all
 stdout 'example.com/split v1.0.0'
 
 # A 'go get' that simultaneously upgrades away conflicting package defitions is not ambiguous.
-go get -d example.com/split/subpkg@v1.1.0
+go get example.com/split/subpkg@v1.1.0
 
 # A 'go get' without an upgrade should find the package.
 rm go.mod
 go mod init example.com/foo
-go get -d example.com/split/subpkg
+go get example.com/split/subpkg
 go list -m all
 stdout 'example.com/split/subpkg v1.1.0'
 
@@ -23,18 +23,18 @@ stdout 'example.com/split/subpkg v1.1.0'
 # even if the package was subsequently moved into a parent module.
 rm go.mod
 go mod init example.com/foo
-go get -d example.com/join/subpkg@v1.0.0
+go get example.com/join/subpkg@v1.0.0
 go list -m all
 stdout 'example.com/join/subpkg v1.0.0'
 
 # A 'go get' that simultaneously upgrades away conflicting package definitions is not ambiguous.
 # (A wildcard pattern applies to both packages and modules,
 # because we define wildcard matching to apply after version resolution.)
-go get -d example.com/join/subpkg/...@v1.1.0
+go get example.com/join/subpkg/...@v1.1.0
 
 # A 'go get' without an upgrade should find the package.
 rm go.mod
 go mod init example.com/foo
-go get -d example.com/join/subpkg@v1.1.0
+go get example.com/join/subpkg@v1.1.0
 go list -m all
 stdout 'example.com/join v1.1.0'
index f71620c1bcb41cac9e49ffc102c683f533a7ae4f..18dc6503617a566937844904736f80c50ab2a341 100644 (file)
@@ -11,4 +11,4 @@ go mod init m
 cmp stderr stderr-expected
 
 -- stderr-expected --
-go get: example.com/newcycle/a@v1.0.0 requires example.com/newcycle/a@v1.0.1, not example.com/newcycle/a@v1.0.0
+go: example.com/newcycle/a@v1.0.0 requires example.com/newcycle/a@v1.0.1, not example.com/newcycle/a@v1.0.0
index b358f05af36745226e909e1f4a81154bbf6fcdae..5aec209f59fe6fa54ffa3f67ce9d31d73fb665de 100644 (file)
@@ -3,10 +3,10 @@ env GO111MODULE=on
 go mod init example.com/foo
 
 # 'go get bar@none' should be a no-op if module bar is not active.
-go get -d example.com/bar@none
+go get example.com/bar@none
 go list -m all
 ! stdout example.com/bar
 
-go get -d example.com/bar@none
+go get example.com/bar@none
 go list -m all
 ! stdout example.com/bar
index 078e71a041c470463a9a7e7065de6fadb94bc30a..14176a7dc8786d0538c10ea5ec61b1fe1adefdba 100644 (file)
@@ -6,17 +6,17 @@ cd subdir
 go get ./...
 stderr -count=1 'matched no packages'
 
-go get -d ./...
+go get ./...
 stderr -count=1 'matched no packages'
 
 # 'go get' on patterns that could conceivably match nested modules
 # should report a module resolution error.
 
-go get -d example.net/emptysubdir/... # control case
+go get example.net/emptysubdir/... # control case
 
-! go get -d example.net/emptysubdir/subdir/...
+! go get example.net/emptysubdir/subdir/...
 ! stderr 'matched no packages'
-stderr '^go get example\.net/emptysubdir/subdir/\.\.\.: module example\.net/emptysubdir/subdir: reading http://.*: 404 Not Found\n\tserver response: 404 page not found\n\z'
+stderr '^go: example\.net/emptysubdir/subdir/\.\.\.: module example\.net/emptysubdir/subdir: reading http://.*: 404 Not Found\n\tserver response: 404 page not found\n\z'
 
 # It doesn't make sense to 'go get' a path in the standard library,
 # since the standard library necessarily can't have unresolved imports.
@@ -26,8 +26,8 @@ stderr '^go get example\.net/emptysubdir/subdir/\.\.\.: module example\.net/empt
 # For that case, we emit a "malformed module path" error message,
 # which isn't ideal either.
 
-! go get -d builtin/...  # in GOROOT/src, but contains no packages
-stderr '^go get builtin/...: malformed module path "builtin": missing dot in first path element$'
+! go get builtin/...  # in GOROOT/src, but contains no packages
+stderr '^go: builtin/...: malformed module path "builtin": missing dot in first path element$'
 
 -- go.mod --
 module example.net/emptysubdir
index 053ef621471ecc6b784ae095573aef6f409352ca..35cc276c5c36839788d2e7dd60be4f122d9d648b 100644 (file)
@@ -7,8 +7,8 @@ cp go.mod go.mod.orig
 # example.net/b@patch refers to the patch for the version of b that was selected
 # at the start of 'go get', not the version after applying other changes.
 
-! go get -d example.net/a@v0.2.0 example.net/b@patch
-stderr '^go get: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$'
+! go get example.net/a@v0.2.0 example.net/b@patch
+stderr '^go: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$'
 cmp go.mod go.mod.orig
 
 
@@ -18,8 +18,8 @@ cmp go.mod go.mod.orig
 #
 # TODO(#42360): Reconsider the change in defaults.
 
-! go get -d -u=patch example.net/a@v0.2.0 example.net/b
-stderr '^go get: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$'
+! go get -u=patch example.net/a@v0.2.0 example.net/b
+stderr '^go: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$'
 cmp go.mod go.mod.orig
 
 
@@ -27,7 +27,7 @@ cmp go.mod go.mod.orig
 # applying other version changes, not the versions that were selected at the start.
 # However, it should not patch versions determined by explicit arguments.
 
-go get -d -u=patch example.net/a@v0.2.0
+go get -u=patch example.net/a@v0.2.0
 go list -m all
 stdout '^example.net/a v0.2.0 '
 stdout '^example.net/b v0.2.1 '
@@ -38,7 +38,7 @@ stdout '^example.net/b v0.2.1 '
 
 cp go.mod.orig go.mod
 ! go get -u=patch all
-stderr '^go get: example.net/a@v0.1.1 \(matching all@patch\) requires example.net/b@v0.2.0, not example.net/b@v0.1.1 \(matching all@patch\)$'
+stderr '^go: example.net/a@v0.1.1 \(matching all@patch\) requires example.net/b@v0.2.0, not example.net/b@v0.1.1 \(matching all@patch\)$'
 cmp go.mod go.mod.orig
 
 
index 4fd1ec53e16045fa8def31af242b41e486263144..e4d3c491f45611f45919ef3aca1c3a0d26efe6dd 100644 (file)
@@ -5,7 +5,7 @@ go list -m all
 stdout '^example.net/a v0.1.0 '
 stdout '^example.net/b v0.1.0 '
 
-go get -d -u=patch example.net/a@v0.2.0
+go get -u=patch example.net/a@v0.2.0
 go list -m all
 stdout '^example.net/a v0.2.0 '
 stdout '^example.net/b v0.1.1 '  # not v0.1.2, which requires …/a v0.3.0.
index d1db56f935ca2ee7c0983bb37fd30c9febf8782a..6600109d2dad9be00b39c17478dec0ec17f1a8f4 100644 (file)
@@ -6,7 +6,7 @@
 # (It used to print v0.1.1 but then silently upgrade to v0.2.0.)
 
 ! go get example.net/a@patch
-stderr '^go get: example.net/a@patch \(v0.1.1\) requires example.net/a@v0.2.0, not example.net/a@patch \(v0.1.1\)$'  # TODO: A mention of b v0.1.0 would be nice.
+stderr '^go: example.net/a@patch \(v0.1.1\) requires example.net/a@v0.2.0, not example.net/a@patch \(v0.1.1\)$'  # TODO: A mention of b v0.1.0 would be nice.
 
 -- go.mod --
 module example
index e39d13a0f4184e515e14f7b097f5ddd0d7935491..28277310aa15e5041c137d69dcc2bbdf9cefb242 100644 (file)
@@ -1,5 +1,5 @@
 # example.net/pkgremoved@v0.1.0 refers to a package.
-go get -d example.net/pkgremoved@v0.1.0
+go get example.net/pkgremoved@v0.1.0
 
 go list example.net/pkgremoved
 stdout '^example.net/pkgremoved'
@@ -15,8 +15,8 @@ cp go.mod go.mod.orig
 # be constrained to the latest patch of its originally-selected version (v0.1.0),
 # not upgraded to the latest patch of the new transitive dependency.
 
-! go get -d example.net/pkgremoved@patch example.net/other@v0.1.0
-stderr '^go get: example.net/other@v0.1.0 requires example.net/pkgremoved@v0.2.0, not example.net/pkgremoved@patch \(v0.1.1\)$'
+! go get example.net/pkgremoved@patch example.net/other@v0.1.0
+stderr '^go: example.net/other@v0.1.0 requires example.net/pkgremoved@v0.2.0, not example.net/pkgremoved@patch \(v0.1.1\)$'
 cmp go.mod.orig go.mod
 
 
@@ -24,19 +24,19 @@ cmp go.mod.orig go.mod
 
 # Package to module ...
 
-go get -d example.net/pkgremoved@v0.3.0
+go get example.net/pkgremoved@v0.3.0
 go list example.net/pkgremoved
 stdout 'example.net/pkgremoved'
 
-go get -d example.net/pkgremoved@patch
+go get example.net/pkgremoved@patch
 ! go list example.net/pkgremoved
 
 # ... and module to package.
 
-go get -d example.net/pkgremoved@v0.4.0
+go get example.net/pkgremoved@v0.4.0
 ! go list example.net/pkgremoved
 
-go get -d example.net/pkgremoved@patch
+go get example.net/pkgremoved@patch
 go list example.net/pkgremoved
 stdout 'example.net/pkgremoved'
 
index aee4374dc8a88a5dff020078c9e392178d9e7ba1..891353fd4b9a0b6ef59098a609bbe97ddc2112ae 100644 (file)
@@ -5,29 +5,29 @@ env GO111MODULE=on
 # in the build list, we assume the pattern matches a single module
 # whose path is a prefix of the part of the pattern before "...".
 cp go.mod.orig go.mod
-go get -d rsc.io/quote/...
+go get rsc.io/quote/...
 grep 'require rsc.io/quote' go.mod
 
 cp go.mod.orig go.mod
-! go get -d rsc.io/quote/x...
-stderr 'go get: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x...'
+! go get rsc.io/quote/x...
+stderr 'go: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x...'
 ! grep 'require rsc.io/quote' go.mod
 
-! go get -d rsc.io/quote/x/...
-stderr 'go get: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x/...'
+! go get rsc.io/quote/x/...
+stderr 'go: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x/...'
 ! grep 'require rsc.io/quote' go.mod
 
 # If a pattern matches no packages within a module, the module should not
 # be upgraded, even if the module path is a prefix of the pattern.
 cp go.mod.orig go.mod
 go mod edit -require example.com/nest@v1.0.0
-go get -d example.com/nest/sub/y...
+go get example.com/nest/sub/y...
 grep 'example.com/nest/sub v1.0.0' go.mod
 grep 'example.com/nest v1.0.0' go.mod
 
 # However, if the pattern matches the module path itself, the module
 # should be upgraded even if it contains no matching packages.
-go get -d example.com/n...t
+go get example.com/n...t
 grep 'example.com/nest v1.1.0' go.mod
 grep 'example.com/nest/sub v1.0.0' go.mod
 
index 0c79ec71b7b41d628d6a412e34816399d4599007..7ad3c3c7c44a4caf8c40c05f8d764580815f587b 100644 (file)
@@ -12,10 +12,10 @@ stderr '^module example\.net/cmd provides package example\.net/cmd/tool and is r
 go mod edit -droprequire example.net/tools
 
 
-# 'go get -d' makes a best effort to fetch those dependencies, but shouldn't
+# 'go get' makes a best effort to fetch those dependencies, but shouldn't
 # error out if dependencies of tag-guarded files are missing.
 
-go get -d example.net/tools@v0.1.0
+go get example.net/tools@v0.1.0
 ! stderr 'no Go source files'
 
 ! go list example.net/tools
@@ -48,27 +48,27 @@ stderr '^package example.net/tools: build constraints exclude all Go files in .*
 # 'go get' should fetch modules whose roots contain test-only packages, but
 # without the -t flag shouldn't error out if the test has missing dependencies.
 
-go get -d example.net/testonly@v0.1.0
+go get example.net/testonly@v0.1.0
 
 # With the -t flag, the test dependencies must resolve successfully.
-! go get -d -t example.net/testonly@v0.1.0
+! go get -t example.net/testonly@v0.1.0
 stderr '^example.net/testonly tested by\n\texample.net/testonly\.test imports\n\texample.net/missing: cannot find module providing package example.net/missing$'
 
 
-# 'go get -d' should succeed for a module path that does not contain a package,
+# 'go get' should succeed for a module path that does not contain a package,
 # but fail for a non-package subdirectory of a module.
 
-! go get -d example.net/missing/subdir@v0.1.0
-stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$'
+! go get example.net/missing/subdir@v0.1.0
+stderr '^go: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$'
 
-go get -d example.net/missing@v0.1.0
+go get example.net/missing@v0.1.0
 
 
 # Getting the subdirectory should continue to fail even if the corresponding
 # module is already present in the build list.
 
-! go get -d example.net/missing/subdir@v0.1.0
-stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$'
+! go get example.net/missing/subdir@v0.1.0
+stderr '^go: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$'
 
 
 -- go.mod --
index be3db42d1d9c1f104c78e0ba0c92c90b49288300..06e2fc686029184d8b15cfa2f0b4e39edb8aad7f 100644 (file)
@@ -8,7 +8,7 @@ cmp go.mod.orig go.mod
 grep '^example.com/incompatiblewithsub v2\.0\.0\+incompatible' go.sum
 ! grep '^example.com/incompatiblewithsub v1.0.0' go.sum
 
-go get -d example.com/incompatiblewithsub/sub
+go get example.com/incompatiblewithsub/sub
 cmp go.mod.orig go.mod
 ! grep '^example.com/incompatiblewithsub v1.0.0' go.sum
 
index 9eec2013210350fdd7b4234eeea6160abaa70ec7..03f6810e354a0a3e56a112a424b499ffdb7d1fcb 100644 (file)
@@ -12,7 +12,7 @@ stderr '^package m/use-indirect imports indirect-with-pkg from implicitly requir
 # NOTE: the hint recommends getting the imported package (tested below) since
 # it's more obvious and doesn't require -d. However, that adds an '// indirect'
 # comment on the requirement.
-go get -d m/use-indirect
+go get m/use-indirect
 cmp go.mod go.mod.use
 cp go.mod.orig go.mod
 
@@ -21,7 +21,7 @@ cp go.mod.orig go.mod
 # know they're needed by the main module. See #43131 for the rationale.
 # The hint above recommends this because it's more obvious usage and doesn't
 # require the -d flag.
-go get -d indirect-with-pkg indirect-without-pkg
+go get indirect-with-pkg indirect-without-pkg
 cmp go.mod go.mod.indirect
 
 -- go.mod.orig --
index 582837a1665e28aaa0b2fd4e4ea83e92d3ca50b9..b964ae448453b9860fa1d854109110e975649b7c 100644 (file)
@@ -9,69 +9,69 @@ env GOSUMDB=off
 # We can resolve the @master branch without unshallowing the local repository
 # (even with older gits), so try that before we do anything else.
 # (This replicates https://golang.org/issue/26713 with git 2.7.4.)
-go get -d github.com/rsc/legacytest@master
+go get github.com/rsc/legacytest@master
 go list -m all
 stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
 
 # get should include incompatible tags in "latest" calculation.
 go mod edit -droprequire github.com/rsc/legacytest
-go get -d github.com/rsc/legacytest@latest
+go get github.com/rsc/legacytest@latest
 go list
 go list -m all
 stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
 
 # v2.0.1-0.pseudo+incompatible
-go get -d ...test@7303f77
+go get ...test@7303f77
 go list -m all
 stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
 
 # v2.0.0+incompatible by tag+incompatible
-go get -d ...test@v2.0.0+incompatible
+go get ...test@v2.0.0+incompatible
 go list -m all
 stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
 
 # v2.0.0+incompatible by tag
-go get -d ...test@v2.0.0
+go get ...test@v2.0.0
 go list -m all
 stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
 
 # v2.0.0+incompatible by hash (back on master)
-go get -d ...test@d7ae1e4
+go get ...test@d7ae1e4
 go list -m all
 stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
 
 # v1.2.1-0.pseudo
-go get -d ...test@d2d4c3e
+go get ...test@d2d4c3e
 go list -m all
 stdout '^github.com/rsc/legacytest v1\.2\.1-0\.\d{14}-d2d4c3ea6623$'
 
 # v1.2.0
-go get -d ...test@9f6f860
+go get ...test@9f6f860
 go list -m all
 stdout '^github.com/rsc/legacytest v1\.2\.0$'
 
 # v1.1.0-pre.0.pseudo
-go get -d ...test@fb3c628
+go get ...test@fb3c628
 go list -m all
 stdout '^github.com/rsc/legacytest v1\.1\.0-pre\.0\.\d{14}-fb3c628075e3$'
 
 # v1.1.0-pre (no longer on master)
-go get -d ...test@731e3b1
+go get ...test@731e3b1
 go list -m all
 stdout '^github.com/rsc/legacytest v1\.1\.0-pre$'
 
 # v1.0.1-0.pseudo
-go get -d ...test@fa4f5d6
+go get ...test@fa4f5d6
 go list -m all
 stdout '^github.com/rsc/legacytest v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$'
 
 # v1.0.0
-go get -d ...test@7fff7f3
+go get ...test@7fff7f3
 go list -m all
 stdout '^github.com/rsc/legacytest v1\.0\.0$'
 
 # v0.0.0-pseudo
-go get -d ...test@52853eb
+go get ...test@52853eb
 go list -m all
 stdout '^github.com/rsc/legacytest v0\.0\.0-\d{14}-52853eb7b552$'
 
index 0fbd041f8603fd57a3b94e09008072431a56e285..d085f4fa3c8e6b2319bce5ed94c9b569f58d3ded 100644 (file)
@@ -17,7 +17,7 @@ env GOSUMDB=off
 # The pseudo-version hence sorts immediately after v0.2.2 rather
 # than v0.2.1, even though the v0.2.2 tag is not on master.
 
-go get -d vcs-test.golang.org/git/tagtests.git@master
+go get vcs-test.golang.org/git/tagtests.git@master
 go list -m all
 stdout '^vcs-test.golang.org/git/tagtests.git v0.2.3-0\.'
 
index b78e6e644f7622a3d22dd4333672c7f3731dcf48..8e6cd907f183495842855232179f2ed9f16e3bb1 100644 (file)
@@ -16,11 +16,11 @@ env GOSUMDB=off
 #
 # The pseudo-version is based on sub/v0.0.10, since v0.2.0 doesn't
 # contain the prefix.
-go get -d vcs-test.golang.org/git/prefixtagtests.git/sub
+go get vcs-test.golang.org/git/prefixtagtests.git/sub
 go list -m all
 stdout '^vcs-test.golang.org/git/prefixtagtests.git/sub v0.0.10$'
 
-go get -d -u vcs-test.golang.org/git/prefixtagtests.git/sub@master
+go get -u vcs-test.golang.org/git/prefixtagtests.git/sub@master
 go list -m all
 stdout '^vcs-test.golang.org/git/prefixtagtests.git/sub v0.0.11-0\.'
 
index d97f3f1a40117242fba478162505e0abb9d6eb97..b1fc8b80563307cb948b50361507275bd8b578ff 100644 (file)
@@ -6,7 +6,7 @@ env oldGOPROXY=$GOPROXY
 # 'go get' should resolve it to the minimum valid pseudo-version.
 
 go mod edit -replace=example.com/x=./x
-go get -d example.com/x
+go get example.com/x
 
 go list -m example.com/x
 stdout '^example.com/x v0.0.0-00010101000000-000000000000 '
@@ -15,11 +15,11 @@ stdout '^example.com/x v0.0.0-00010101000000-000000000000 '
 go mod edit -replace=example.com/x@v0.1.0=./x
 go mod edit -replace=example.com/x@v0.2.0=./x
 
-go get -d example.com/x
+go get example.com/x
 go list -m example.com/x
 stdout '^example.com/x v0.2.0 '
 
-go get -d example.com/x@<v0.2.0
+go get example.com/x@<v0.2.0
 go list -m example.com/x
 stdout '^example.com/x v0.1.0 '
 
@@ -30,7 +30,7 @@ env GOPROXY=off
 cp go.mod.orig go.mod
 
 go mod edit -replace=example.com/x=./x
-go get -d example.com/x
+go get example.com/x
 
 go list -m example.com/x
 stdout '^example.com/x v0.0.0-00010101000000-000000000000 '
@@ -39,11 +39,11 @@ stdout '^example.com/x v0.0.0-00010101000000-000000000000 '
 go mod edit -replace=example.com/x@v0.1.0=./x
 go mod edit -replace=example.com/x@v0.2.0=./x
 
-go get -d example.com/x
+go get example.com/x
 go list -m example.com/x
 stdout '^example.com/x v0.2.0 '
 
-go get -d example.com/x@<v0.2.0
+go get example.com/x@<v0.2.0
 go list -m example.com/x
 stdout '^example.com/x v0.1.0 '
 
@@ -57,7 +57,7 @@ cp go.mod.orig go.mod
 go list -versions -m rsc.io/quote
 stdout 'v1.3.0 v1.4.0'
 
-go get -d rsc.io/quote@v1.3
+go get rsc.io/quote@v1.3
 go list -m rsc.io/quote
 stdout '^rsc.io/quote v1.3.0'
 
@@ -66,11 +66,11 @@ go mod edit -replace rsc.io/quote@v1.3.1=rsc.io/quote@v1.4.0
 go list -versions -m rsc.io/quote
 stdout 'v1.3.0 v1.3.1 v1.4.0'
 
-go get -d rsc.io/quote@v1.3
+go get rsc.io/quote@v1.3
 go list -m rsc.io/quote
 stdout '^rsc.io/quote v1.3.1 '
 
-go get -d rsc.io/quote@>v1.3.1
+go get rsc.io/quote@>v1.3.1
 go list -m rsc.io/quote
 stdout '^rsc.io/quote v1.4.0'
 
@@ -81,15 +81,15 @@ cp go.mod.orig go.mod
 
 ! go list example
 stderr '^package example is not in GOROOT \(.*\)$'
-! go get -d example
-stderr '^go get: malformed module path "example": missing dot in first path element$'
+! go get example
+stderr '^go: malformed module path "example": missing dot in first path element$'
 
 go mod edit -replace example@v0.1.0=./example
 
 ! go list example
 stderr '^module example provides package example and is replaced but not required; to add it:\n\tgo get example@v0.1.0$'
 
-go get -d example
+go get example
 go list -m example
 stdout '^example v0.1.0 '
 
index 560fa7bfb256ffee487cb2303faa1267f128a2bf..9757989666728eb3050c3c63a8cd37fce848f6cb 100644 (file)
@@ -1,7 +1,7 @@
 # 'go get pkg' should not upgrade to a retracted version.
 cp go.mod.orig go.mod
 go mod edit -require example.com/retract/self/prev@v1.1.0
-go get -d example.com/retract/self/prev
+go get example.com/retract/self/prev
 go list -m example.com/retract/self/prev
 stdout '^example.com/retract/self/prev v1.1.0$'
 
@@ -9,7 +9,7 @@ stdout '^example.com/retract/self/prev v1.1.0$'
 # version is available.
 cp go.mod.orig go.mod
 go mod edit -require example.com/retract/self/prev@v1.9.0
-go get -d example.com/retract/self/prev
+go get example.com/retract/self/prev
 stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$'
 stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest\n$'
 go list -m example.com/retract/self/prev
@@ -18,14 +18,14 @@ stdout '^example.com/retract/self/prev v1.9.0$'
 # 'go get pkg@latest' should downgrade from a retracted version.
 cp go.mod.orig go.mod
 go mod edit -require example.com/retract/self/prev@v1.9.0
-go get -d example.com/retract/self/prev@latest
+go get example.com/retract/self/prev@latest
 go list -m example.com/retract/self/prev
 stdout '^example.com/retract/self/prev v1.1.0$'
 
 # 'go get pkg@version' should update to a specific version, even if that
 # version is retracted.
 cp go.mod.orig go.mod
-go get -d example.com/retract@v1.0.0-bad
+go get example.com/retract@v1.0.0-bad
 stderr '^go: warning: example.com/retract@v1.0.0-bad: retracted by module author: bad$'
 go list -m example.com/retract
 stdout '^example.com/retract v1.0.0-bad$'
@@ -34,16 +34,16 @@ stdout '^example.com/retract v1.0.0-bad$'
 # version is available.
 cp go.mod.orig go.mod
 go mod edit -require example.com/retract/self/prev@v1.9.0
-go get -d -u ./use
+go get -u ./use
 stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$'
 go list -m example.com/retract/self/prev
 stdout '^example.com/retract/self/prev v1.9.0$'
 
 # 'go get' should warn if a module needed to build named packages is retracted.
 # 'go get' should not warn about unrelated modules.
-go get -d ./empty
+go get ./empty
 ! stderr retracted
-go get -d ./use
+go get ./use
 stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$'
 
 -- go.mod.orig --
index b49ba54982b643bc5c395b1e05449bc8ae509fd3..4b4f5da03cdba618d7abed6d297c71af5572f8e9 100644 (file)
@@ -1,4 +1,4 @@
-! go get -d example.com/retract/ambiguous/other
+! go get example.com/retract/ambiguous/other
 stderr 'ambiguous import: found package example.com/retract/ambiguous/nested in multiple modules:'
 stderr '^go: warning: example.com/retract/ambiguous/nested@v1.9.0-bad: retracted by module author: nested modules are bad$'
 
index f4e7661f9b2a036135dccb2daa50fe39b64cba5f..0fb22c85d3943efb3d01890772c599962ebd0817 100644 (file)
@@ -4,7 +4,7 @@ cp go.mod go.mod.orig
 # 'go get' on a package already provided by the build list should update
 # the module already in the build list, not fail with an ambiguous import error.
 
-go get -d example.net/split/nested@patch
+go get example.net/split/nested@patch
 go list -m all
 stdout '^example.net/split v0.2.1 '
 ! stdout '^example.net/split/nested'
@@ -13,7 +13,7 @@ stdout '^example.net/split v0.2.1 '
 
 cp go.mod.orig go.mod
 
-go get -d example.net/split/nested/...@patch
+go get example.net/split/nested/...@patch
 go list -m all
 stdout '^example.net/split v0.2.1 '
 ! stdout '^example.net/split/nested'
@@ -32,7 +32,7 @@ stdout '^example.net/split v0.2.1 '
 
 cp go.mod.orig go.mod
 
-! go get -d example.net/split/nested@v0.1.0
+! go get example.net/split/nested@v0.1.0
 stderr '^example.net/split/nested: ambiguous import: found package example.net/split/nested in multiple modules:\n\texample.net/split v0.2.0 \(.*split.2[/\\]nested\)\n\texample.net/split/nested v0.1.0 \(.*nested.1\)$'
 
 # A wildcard that matches packages in some module at its selected version
@@ -54,22 +54,22 @@ stderr '^example.net/split/nested: ambiguous import: found package example.net/s
 #
 # TODO(#27899): Should we instead upgrade or downgrade to an arbirary version?
 
-! go get -d example.net/split/nested/...@v0.1.0
-stderr '^go get: example.net/split/nested/\.\.\.@v0.1.0 matches packages in example.net/split@v0.2.0 but not example.net/split@v0.1.0: specify a different version for module example.net/split$'
+! go get example.net/split/nested/...@v0.1.0
+stderr '^go: example.net/split/nested/\.\.\.@v0.1.0 matches packages in example.net/split@v0.2.0 but not example.net/split@v0.1.0: specify a different version for module example.net/split$'
 
 cmp go.mod go.mod.orig
 
 
 # If another argument resolves the ambiguity, we should be ok again.
 
-go get -d example.net/split@none example.net/split/nested@v0.1.0
+go get example.net/split@none example.net/split/nested@v0.1.0
 go list -m all
 ! stdout '^example.net/split '
 stdout '^example.net/split/nested v0.1.0 '
 
 cp go.mod.orig go.mod
 
-go get -d example.net/split@v0.3.0 example.net/split/nested@v0.1.0
+go get example.net/split@v0.3.0 example.net/split/nested@v0.1.0
 go list -m all
 stdout '^example.net/split v0.3.0 '
 stdout '^example.net/split/nested v0.1.0 '
@@ -80,14 +80,14 @@ stdout '^example.net/split/nested v0.1.0 '
 # to match the pattern if possible.
 
 cp go.mod.orig go.mod
-go get -d example.net/split/nested@v0.0.0
+go get example.net/split/nested@v0.0.0
 
-go get -d example.net/...@v0.1.0
+go get example.net/...@v0.1.0
 go list -m all
 stdout '^example.net/split v0.1.0 '
 stdout '^example.net/split/nested v0.1.0 '
 
-go get -d example.net/...
+go get example.net/...
 go list -m all
 stdout '^example.net/split v0.3.0 '
 stdout '^example.net/split/nested v0.2.0 '
@@ -96,15 +96,15 @@ stdout '^example.net/split/nested v0.2.0 '
 # @none applies to all matching module paths,
 # regardless of whether they contain any packages.
 
-go get -d example.net/...@none
+go get example.net/...@none
 go list -m all
 ! stdout '^example.net'
 
 # Starting from no dependencies, a wildcard can resolve to an empty module with
 # the same prefix even if it contains no packages.
 
-go get -d example.net/...@none
-go get -d example.net/split/...@v0.1.0
+go get example.net/...@none
+go get example.net/split/...@v0.1.0
 go list -m all
 stdout '^example.net/split v0.1.0 '
 
index 4f1cf0327770389511b2fb2da0f7178544cab311..0d9a840e779cc4334544df743213f67ea58b5cc7 100644 (file)
@@ -2,7 +2,7 @@
 # it should add sums for the module's go.mod file and its content to go.sum.
 # Verifies golang.org/issue/41103.
 go mod init m
-go get -d rsc.io/QUOTE
+go get rsc.io/QUOTE
 grep '^rsc.io/QUOTE v1.5.2/go.mod ' go.sum
 grep '^rsc.io/QUOTE v1.5.2 ' go.sum
 
index e9869e3f0230b3ab6f6bdbb1f756071a2c624a1c..e4fb6c4326b46f52a14b4d8316896a9e18e0d5ce 100644 (file)
@@ -1,25 +1,14 @@
 env GO111MODULE=on
 
-[short] skip
-
 # get should add modules needed to build packages, even if those
 # dependencies are in sources excluded by build tags.
 # All build tags are considered true except "ignore".
 go mod init m
-go get -d .
+go get .
 go list -m all
 stdout 'example.com/version v1.1.0'
 stdout 'rsc.io/quote v1.5.2'
 
-[short] skip
-
-# Packages that are only imported in excluded files should not be built.
-env GOCACHE=$WORK/gocache  # Looking for compile commands, so need a clean cache.
-go get -n -x .
-stderr 'compile.* -p m '
-! stderr 'compile.* -p example.com/version '
-! stderr 'compile.* -p rsc.io/quote '
-
 -- empty.go --
 package m
 
index 23722bd4e4dcd7f749386b2e68dee7efea25e9a3..0fa7cd98b98fb2fd0f38d08d35ce27b0503a6484 100644 (file)
@@ -2,38 +2,38 @@ env GO111MODULE=on
 
 # By default, 'go get' should ignore tests
 cp go.mod.empty go.mod
-go get -d m/a
+go get m/a
 ! grep rsc.io/quote go.mod
 
 # 'go get -t' should consider test dependencies of the named package.
 cp go.mod.empty go.mod
-go get -d -t m/a
+go get -t m/a
 grep 'rsc.io/quote v1.5.2$' go.mod
 
 # 'go get -t' should not consider test dependencies of imported packages,
 # including packages imported from tests.
 cp go.mod.empty go.mod
-go get -d -t m/b
+go get -t m/b
 ! grep rsc.io/quote go.mod
 
 # 'go get -t -u' should update test dependencies of the named package.
 cp go.mod.empty go.mod
 go mod edit -require=rsc.io/quote@v1.5.1
-go get -d -t -u m/a
+go get -t -u m/a
 grep 'rsc.io/quote v1.5.2$' go.mod
 
 # 'go get -t -u' should not add or update test dependencies
 # of imported packages, including packages imported from tests.
 cp go.mod.empty go.mod
-go get -d -t -u m/b
+go get -t -u m/b
 ! grep rsc.io/quote go.mod
 go mod edit -require=rsc.io/quote@v1.5.1
-go get -d -t -u m/b
+go get -t -u m/b
 grep 'rsc.io/quote v1.5.1$' go.mod
 
 # 'go get all' should consider test dependencies with or without -t.
 cp go.mod.empty go.mod
-go get -d all
+go get all
 grep 'rsc.io/quote v1.5.2$' go.mod
 
 -- go.mod.empty --
index c53669353794ade0e4eb2039d0f91f48a89ad1d2..7b469008baffd414014094578da7b0ee36618b3b 100644 (file)
@@ -7,16 +7,9 @@ stdout ^example.com/dotgo.go$
 go list example.com/dotgo.go/
 stdout ^example.com/dotgo.go$
 
-# go get -d should succeed in either case, with or without a version.
+# go get should succeed in either case, with or without a version.
 # Arguments are interpreted as packages or package patterns with versions,
 # not source files.
-go get -d example.com/dotgo.go
-go get -d example.com/dotgo.go/
-go get -d example.com/dotgo.go@v1.0.0
-go get -d example.com/dotgo.go/@v1.0.0
-
-# go get (without -d) should also succeed in either case.
-[short] skip
 go get example.com/dotgo.go
 go get example.com/dotgo.go/
 go get example.com/dotgo.go@v1.0.0
index 0093c0eda0c8270eabe147901828f994f88122af..a5651e934181a70dc5e302193792fb939bbe4bd9 100644 (file)
@@ -18,7 +18,7 @@ cmp go.sum.orig go.sum
 # Upgrade a module. This also upgrades rsc.io/quote, and though we didn't load
 # a package from it, we had the sum for its old version, so we need the
 # sum for the new version, too.
-go get -d example.com/upgrade@v0.0.2
+go get example.com/upgrade@v0.0.2
 grep '^rsc.io/quote v1.5.2 ' go.sum
 
 # The upgrade still breaks the build because the new version of quote imports
@@ -34,7 +34,7 @@ cp go.sum.orig go.sum
 # We didn't need a sum for it before (even though we had one), so we won't
 # fetch a new sum.
 go mod edit -replace rsc.io/quote@v1.0.0=./dummy
-go get -d example.com/upgrade@v0.0.2
+go get example.com/upgrade@v0.0.2
 ! grep '^rsc.io/quote v1.5.2 ' go.sum
 cp go.mod.orig go.mod
 cp go.sum.orig go.sum
@@ -43,7 +43,7 @@ cp go.sum.orig go.sum
 # Replace the new version with a directory before upgrading.
 # We can't get a sum for a directory.
 go mod edit -replace rsc.io/quote@v1.5.2=./dummy
-go get -d example.com/upgrade@v0.0.2
+go get example.com/upgrade@v0.0.2
 ! grep '^rsc.io/quote v1.5.2 ' go.sum
 cp go.mod.orig go.mod
 cp go.sum.orig go.sum
@@ -52,7 +52,7 @@ cp go.sum.orig go.sum
 # Replace the new version with a different version.
 # We should get a sum for that version.
 go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
-go get -d example.com/upgrade@v0.0.2
+go get example.com/upgrade@v0.0.2
 ! grep '^rsc.io/quote v1.5.2 ' go.sum
 grep '^rsc.io/quote v1.5.1 ' go.sum
 cp go.mod.orig go.mod
@@ -63,7 +63,7 @@ cp go.sum.orig go.sum
 # 'go get' should fail when fetching the zip.
 rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
 env GOPROXY=off
-! go get -d example.com/upgrade@v0.0.2
+! go get example.com/upgrade@v0.0.2
 stderr '^go: upgraded rsc.io/quote v1.0.0 => v1.5.2: error finding sum for rsc.io/quote@v1.5.2: module lookup disabled by GOPROXY=off$'
 
 -- go.mod.orig --
index eeb6d6f6af6f414b5545034bbabf80f9cceec096..51d5990ee179c73a90bcd42661a29f764313a813 100644 (file)
@@ -1,35 +1,35 @@
 env GO111MODULE=on
 
-go get -d rsc.io/quote@v1.5.1
+go get rsc.io/quote@v1.5.1
 go list -m all
 stdout 'rsc.io/quote v1.5.1'
 grep 'rsc.io/quote v1.5.1$' go.mod
 
 # get -u should update dependencies of the package in the current directory
-go get -d -u
+go get -u
 grep 'rsc.io/quote v1.5.2$' go.mod
 grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
 
 # get -u rsc.io/sampler should update only sampler's dependencies
 cp go.mod-v1.5.1 go.mod
-go get -d -u rsc.io/sampler
+go get -u rsc.io/sampler
 grep 'rsc.io/quote v1.5.1$' go.mod
 grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
 
 # move to a pseudo-version after any tags
-go get -d rsc.io/quote@dd9747d
+go get rsc.io/quote@dd9747d
 grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod
 
 # get -u should not jump off newer pseudo-version to earlier tag
-go get -d -u
+go get -u
 grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod
 
 # move to earlier pseudo-version
-go get -d rsc.io/quote@e7a685a342
+go get rsc.io/quote@e7a685a342
 grep 'rsc.io/quote v0.0.0-20180214005133-e7a685a342c0' go.mod
 
 # get -u should jump off earlier pseudo-version to newer tag
-go get -d -u
+go get -u
 grep 'rsc.io/quote v1.5.2' go.mod
 
 -- go.mod --
index f5f415aa3fae25e66ec10e62a04469c14c115157..deff9358f060f462a74c0ab349a97139d553202e 100644 (file)
@@ -10,52 +10,52 @@ env GO111MODULE=on
 # The v0.0.0 pseudo-version is chronologically newer.
 
 # Start at v0.1.1-0.20190429073117-b5426c86b553
-go get -d example.com/pseudoupgrade@b5426c8
+go get example.com/pseudoupgrade@b5426c8
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
 # 'get -u' should not downgrade to the (lower) tagged version.
-go get -d -u
+go get -u
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
 # 'get example.com/pseudoupgrade@upgrade' should not downgrade.
-go get -d example.com/pseudoupgrade@upgrade
+go get example.com/pseudoupgrade@upgrade
 go list -m all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
 # 'get example.com/pseudoupgrade' should not downgrade.
 # This is equivalent to 'get example.com/pseudoupgrade@upgrade'.
-go get -d example.com/pseudoupgrade
+go get example.com/pseudoupgrade
 go list -m all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
 # 'get example.com/pseudoupgrade@latest' should downgrade.
 # @latest should not consider the current version.
-go get -d example.com/pseudoupgrade@latest
+go get example.com/pseudoupgrade@latest
 go list -m all
 stdout '^example.com/pseudoupgrade v0.1.0$'
 
 # We should observe the same behavior with the newer pseudo-version.
-go get -d example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534
+go get example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534
 
 # 'get -u' should not downgrade to the chronologically older tagged version.
-go get -d -u
+go get -u
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
 
 # 'get example.com/pseudoupgrade@upgrade should not downgrade.
-go get -d example.com/pseudoupgrade@upgrade
+go get example.com/pseudoupgrade@upgrade
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
 
 # 'get example.com/pseudoupgrade' should not downgrade.
-go get -d example.com/pseudoupgrade
+go get example.com/pseudoupgrade
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
 
 # 'get example.com/pseudoupgrade@latest' should downgrade.
-go get -d example.com/pseudoupgrade@latest
+go get example.com/pseudoupgrade@latest
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.1.0$'
 
index 78c645c6b9f3fe4174cd75f82ee0af1066837a7c..06f9973e431932f35923d937e0e3378247b9ad7a 100644 (file)
@@ -11,15 +11,15 @@ stdout '^example.net/a v0.1.0 '
 # already in the build list, and the wildcard in the first element prevents us
 # from attempting to resolve a new module whose path is a prefix of the pattern.
 
-! go get -d -u=patch example.../b@upgrade
-stderr '^go get: no modules to query for example\.\.\./b@upgrade because first path element contains a wildcard$'
+! go get -u=patch example.../b@upgrade
+stderr '^go: no modules to query for example\.\.\./b@upgrade because first path element contains a wildcard$'
 
 
 # Patching . causes a patch to example.net/a, which introduces a new match
 # for example.net/b/..., which is itself patched and causes another upgrade to
 # example.net/a, which is then patched again.
 
-go get -d -u=patch . example.../b@upgrade
+go get -u=patch . example.../b@upgrade
 go list -m all
 stdout '^example.net/a v0.2.1 '  # upgraded by dependency of b and -u=patch
 stdout '^example.net/b v0.2.0 '  # introduced by patch of a and upgraded by wildcard
index 00070c03b534446fc969fd1ba0144e07ebb03ddb..aaf526b2ab54beb3245ea4737a313bc54456055f 100644 (file)
@@ -1,6 +1,6 @@
 env GO111MODULE=on
 
-go get -d rsc.io/quote@v1.5.1
+go get rsc.io/quote@v1.5.1
 go mod vendor
 env GOPATH=$WORK/empty
 env GOPROXY=file:///nonexist
@@ -11,16 +11,16 @@ stdout '^rsc.io/quote v1.5.1 .*vendor[\\/]rsc.io[\\/]quote$'
 stdout '^golang.org/x/text v0.0.0.* .*vendor[\\/]golang.org[\\/]x[\\/]text[\\/]language$'
 
 ! go list -mod=vendor -m rsc.io/quote@latest
-stderr 'go list -m: rsc.io/quote@latest: cannot query module due to -mod=vendor'
+stderr 'go: rsc.io/quote@latest: cannot query module due to -mod=vendor'
 ! go get -mod=vendor -u
 stderr 'flag provided but not defined: -mod'
 
 # Since we don't have a complete module graph, 'go list -m' queries
 # that require the complete graph should fail with a useful error.
 ! go list -mod=vendor -m all
-stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 ! go list -mod=vendor -m ...
-stderr 'go list -m: can''t match module patterns using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: can''t match module patterns using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 
 -- go.mod --
 module x
index ccb8d1375aa7dd2dd16fcfa60a20ff295b5ddc99..b3d06c17c85afa0111bdcc10999d5425a2d8deca 100644 (file)
@@ -8,7 +8,12 @@ env GOSUMDB=off
 
 # 'go get -x' should log URLs with an HTTP or HTTPS scheme.
 # A bug had caused us to log schemeless URLs instead.
-go get -x -d golang.org/x/text@v0.1.0
+go get -x golang.org/x/text@v0.1.0
 stderr '^# get https://golang.org/x/text\?go-get=1$'
 stderr '^# get https://golang.org/x/text\?go-get=1: 200 OK \([0-9.]+s\)$'
 ! stderr '^# get //.*'
+
+-- go.mod --
+module m
+
+go 1.18
index 74a3c79622f1f5ff916edd64cb39facd386edee4..bafa5876241ece08b9e06340673761bf912ce7bf 100644 (file)
@@ -5,7 +5,7 @@ env GO111MODULE=on
 env GOMODCACHE=$WORK/modcache
 go env GOMODCACHE
 stdout $WORK[/\\]modcache
-go get -d rsc.io/quote@v1.0.0
+go get rsc.io/quote@v1.0.0
 exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info
 grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info
 
@@ -18,7 +18,7 @@ exists $WORK/modcache/cache/download/sumdb
 env GOMODCACHE=
 go env GOMODCACHE
 stdout $GOPATH[/\\]pkg[/\\]mod
-go get -d rsc.io/quote@v1.0.0
+go get rsc.io/quote@v1.0.0
 exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info
 grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info
 
@@ -31,11 +31,18 @@ env GOPATH=
 go env GOMODCACHE
 stdout $HOME[/\\]go[/\\]pkg[/\\]mod
 
-# If GOMODCACHE isn't set and GOPATH starts with the path list separator, it's an error.
+# If GOMODCACHE isn't set and GOPATH starts with the path list separator,
+# GOMODCACHE is empty and any command that needs it errors out.
 env GOMODCACHE=
 env GOPATH=${:}$WORK/this/is/ignored
-! go env GOMODCACHE
-stderr 'missing \$GOPATH'
+
+go env GOMODCACHE
+stdout '^$'
+! stdout .
+! stderr .
+
+! go mod download rsc.io/quote@v1.0.0
+stderr '^go: module cache not found: neither GOMODCACHE nor GOPATH is set$'
 
 # If GOMODCACHE isn't set and GOPATH has multiple elements only the first is used.
 env GOMODCACHE=
index 204786969f5b25923e9d9928541cb7a0ebd982e8..d42d668f679eeaf57a76adcdda70d0f6ee313dca 100644 (file)
@@ -7,16 +7,16 @@ env dbname=localhost.localdev/sumdb
 # disagree with sumdb fails
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb' '$proxy/sumdb-wrong
-! go get -d rsc.io/quote
+! go get rsc.io/quote
 stderr 'SECURITY ERROR'
 
 # GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text
 env GONOSUMDB='*/quote,*/*mple*,golang.org/x'
-go get -d rsc.io/quote
+go get rsc.io/quote
 rm go.sum
 env GOPRIVATE='*/quote,*/*mple*,golang.org/x'
 env GONOPROXY=none # that is, proxy all despite GOPRIVATE
-go get -d rsc.io/quote
+go get rsc.io/quote
 
 # Download .info files needed for 'go list -m all' later.
 # TODO(#42723): either 'go list -m' should not read these files,
@@ -26,27 +26,27 @@ stdout '^golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c$'
 
 # When GOPROXY is not empty but contains no entries, an error should be reported.
 env GOPROXY=','
-! go get -d golang.org/x/text
-stderr '^go get golang.org/x/text: GOPROXY list is not the empty string, but contains no entries$'
+! go get golang.org/x/text
+stderr '^go: 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 -d golang.org/x/text
-stderr '^go get golang.org/x/text: module lookup disabled by GOPROXY=off$'
+! go get golang.org/x/text
+stderr '^go: golang.org/x/text: module lookup disabled by GOPROXY=off$'
 
 # GONOPROXY bypasses proxy
 [!net] skip
 [!exec:git] skip
 env GOPRIVATE=none
 env GONOPROXY='*/fortune'
-! go get -d rsc.io/fortune # does not exist in real world, only on test proxy
+! go get rsc.io/fortune # does not exist in real world, only on test proxy
 stderr 'git ls-remote'
 
 env GOSUMDB=
 env GONOPROXY=
 env GOPRIVATE='*/x'
-go get -d golang.org/x/text
+go get golang.org/x/text
 go list -m all
 ! stdout 'text.*v0.0.0-2017' # should not have the version from the proxy
 
index 5ad9106378f33303b82dfad6df2d99bfedb87bee..beba3e7b02cd6b3e12d62428e5df0ee61a544661 100644 (file)
@@ -1,7 +1,7 @@
 env GO111MODULE=on
 
 cp go.mod.empty go.mod
-go get -d gopkg.in/dummy.v2-unstable
+go get gopkg.in/dummy.v2-unstable
 
 cp x.go.txt x.go
 cp go.mod.empty go.mod
@@ -12,7 +12,7 @@ go list
 
 env GOPROXY=direct
 env GOSUMDB=off
-go get -d gopkg.in/macaroon-bakery.v2-unstable/bakery
+go get gopkg.in/macaroon-bakery.v2-unstable/bakery
 go list -m all
 stdout 'gopkg.in/macaroon-bakery.v2-unstable v2.0.0-[0-9]+-[0-9a-f]+$'
 
index 28358b5b0c5b560527643096e8e27aa049e968c3..07714e92c720d1d498e4fb4000f6bf00a669399d 100644 (file)
@@ -1,7 +1,7 @@
 env GO111MODULE=on
 
 # latest rsc.io/quote should be v1.5.2 not v1.5.3-pre1
-go get -d
+go get
 go list -m all
 stdout 'rsc.io/quote v1.5.2'
 
index a4294504661454461eff34a570f60c377f7d2008..75b3374bca0016ebdb3160fd0b35720187d7cb79 100644 (file)
@@ -1,6 +1,6 @@
 env GO111MODULE=on
 
-! go get -d example.com/invalidpath/v1
+! go get example.com/invalidpath/v1
 ! go install .
 
 -- go.mod --
index 66f79faa6d9b8dd65d11746777be76eda72843f8..866f7841b9fbb1104e45244a630978c16d10d9e0 100644 (file)
@@ -9,7 +9,7 @@ cd $WORK/testdata
 go mod init testdata.tld/foo
 
 # Getting a package within that module should resolve its dependencies.
-go get -d
+go get
 grep 'rsc.io/quote' go.mod
 
 # Tidying the module should preserve those dependencies.
diff --git a/src/cmd/go/testdata/script/mod_init_invalid_major.txt b/src/cmd/go/testdata/script/mod_init_invalid_major.txt
new file mode 100644 (file)
index 0000000..ae93e70
--- /dev/null
@@ -0,0 +1,82 @@
+env GO111MODULE=on
+env GOFLAGS=-mod=mod
+
+! go mod init example.com/user/repo/v0
+stderr '(?s)^go: invalid module path "example.com/user/repo/v0": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v02
+stderr '(?s)^go: invalid module path "example.com/user/repo/v02": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v023
+stderr '(?s)^go: invalid module path "example.com/user/repo/v023": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v23$'
+
+! go mod init example.com/user/repo/v1
+stderr '(?s)^go: invalid module path "example.com/user/repo/v1": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v2.0
+stderr '(?s)^go: invalid module path "example.com/user/repo/v2.0": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v2.1.4
+stderr '(?s)^go: invalid module path "example.com/user/repo/v2.1.4": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v3.5
+stderr '(?s)^go: invalid module path "example.com/user/repo/v3.5": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v3$'
+
+! go mod init example.com/user/repo/v4.1.4
+stderr '(?s)^go: invalid module path "example.com/user/repo/v4.1.4": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v4$'
+
+! go mod init example.com/user/repo/v.2.3
+stderr '(?s)^go: invalid module path "example.com/user/repo/v.2.3": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v2$'
+
+! go mod init example.com/user/repo/v.5.3
+stderr '(?s)^go: invalid module path "example.com/user/repo/v.5.3": major version suffixes must be in the form of /vN and are only allowed for v2 or later(.*)go mod init example.com/user/repo/v5$'
+
+! go mod init gopkg.in/pkg
+stderr '(?s)^go: invalid module path "gopkg.in/pkg": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg/v0
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v0": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg/v1
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg/v2
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg/v2": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v2$'
+
+! go mod init gopkg.in/user/pkg.v
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v0.1
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v0.1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v.1
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v.1": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v01
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v01": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v1$'
+
+! go mod init gopkg.in/user/pkg.v.2.3
+stderr '(?s)^go: invalid module path "gopkg.in/user/pkg.v.2.3": module paths beginning with gopkg.in/ must always have a major version suffix in the form of .vN(.*)go mod init gopkg.in/user/pkg.v2$'
+
+# module paths with a trailing dot are rejected as invalid import paths
+! go mod init example.com/user/repo/v2.
+stderr '(?s)^go: malformed module path "example.com/user/repo/v2.": trailing dot in path element$'
+
+! go mod init example.com/user/repo/v2..
+stderr '(?s)^go: malformed module path "example.com/user/repo/v2..": trailing dot in path element$'
+
+! go mod init gopkg.in/user/pkg.v.2.
+stderr '(?s)^go: malformed module path "gopkg.in/user/pkg.v.2.": trailing dot in path element$'
+
+! go mod init gopkg.in/user/pkg.v.2..
+stderr '(?s)^go: malformed module path "gopkg.in/user/pkg.v.2..": trailing dot in path element$'
+
+# module paths with spaces are also rejected
+! go mod init 'foo bar'
+stderr '(?s)^go: malformed module path "foo bar": invalid char '' ''$'
+
+! go mod init 'foo  bar baz'
+stderr '(?s)^go: malformed module path "foo  bar baz": invalid char '' ''$'
index fd02392af1b29387bcd072db6aa802e8a3738ac5..14153b8e9ec60903fba9486f72b516c2500db76b 100644 (file)
@@ -16,7 +16,7 @@ env GO111MODULE=auto
 cd m
 cp go.mod go.mod.orig
 ! go list -m all
-stderr '^go list -m: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
+stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
 go install example.com/cmd/a@latest
 cmp go.mod go.mod.orig
 exists $GOPATH/bin/a$GOEXE
@@ -70,7 +70,7 @@ go mod edit -require=rsc.io/fortune@v1.0.0
 stderr '^missing go\.sum entry for module providing package rsc\.io/fortune; to add:\n\tgo mod download rsc\.io/fortune$'
 ! go install -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0
 stderr '^missing go\.sum entry for module providing package rsc\.io/fortune; to add:\n\tgo mod download rsc\.io/fortune$'
-go get -d rsc.io/fortune@v1.0.0
+go get rsc.io/fortune@v1.0.0
 go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
 exists $GOPATH/bin/fortune$GOEXE
 cd ..
@@ -81,15 +81,15 @@ env GO111MODULE=auto
 # 'go install pkg@version' reports errors for meta packages, std packages,
 # and directories.
 ! go install std@v1.0.0
-stderr '^go install: std@v1.0.0: argument must be a package path, not a meta-package$'
+stderr '^go: std@v1.0.0: argument must be a package path, not a meta-package$'
 ! go install fmt@v1.0.0
-stderr '^go install: fmt@v1.0.0: argument must not be a package in the standard library$'
+stderr '^go: fmt@v1.0.0: argument must not be a package in the standard library$'
 ! go install example.com//cmd/a@v1.0.0
-stderr '^go install: example.com//cmd/a@v1.0.0: argument must be a clean package path$'
+stderr '^go: example.com//cmd/a@v1.0.0: argument must be a clean package path$'
 ! go install example.com/cmd/a@v1.0.0 ./x@v1.0.0
-stderr '^go install: ./x@v1.0.0: argument must be a package path, not a relative path$'
+stderr '^go: ./x@v1.0.0: argument must be a package path, not a relative path$'
 ! go install example.com/cmd/a@v1.0.0 $GOPATH/src/x@v1.0.0
-stderr '^go install: '$WORK'[/\\]gopath/src/x@v1.0.0: argument must be a package path, not an absolute path$'
+stderr '^go: '$WORK'[/\\]gopath/src/x@v1.0.0: argument must be a package path, not an absolute path$'
 ! go install example.com/cmd/a@v1.0.0 cmd/...@v1.0.0
 stderr '^package cmd/go not provided by module example.com/cmd@v1.0.0$'
 
@@ -106,7 +106,7 @@ stdout '^example.com/cmd v1.0.0$'
 env GO111MODULE=auto
 
 ! go install example.com/cmd/a@v1.0.0 example.com/cmd/b@latest
-stderr '^go install: example.com/cmd/b@latest: all arguments must have the same version \(@v1.0.0\)$'
+stderr '^go: example.com/cmd/b@latest: all arguments must have the same version \(@v1.0.0\)$'
 
 
 # 'go install pkg@version' should report an error if the arguments are in
@@ -125,7 +125,7 @@ stderr '^package example.com/cmd/err is not a main package$'
 mkdir tmp
 cd tmp
 go mod init m
-go get -d example.com/cmd@v1.0.0
+go get example.com/cmd@v1.0.0
 ! go build example.com/cmd/...
 stderr 'err[/\\]err.go:3:9: undefined: DoesNotCompile$'
 cd ..
@@ -137,7 +137,7 @@ rm $GOPATH/bin
 
 # If a wildcard matches no packages, we should see a warning.
 ! go install example.com/cmd/nomatch...@v1.0.0
-stderr '^go install: example.com/cmd/nomatch\.\.\.@v1.0.0: module example.com/cmd@v1.0.0 found, but does not contain packages matching example.com/cmd/nomatch\.\.\.$'
+stderr '^go: example.com/cmd/nomatch\.\.\.@v1.0.0: module example.com/cmd@v1.0.0 found, but does not contain packages matching example.com/cmd/nomatch\.\.\.$'
 go install example.com/cmd/a@v1.0.0 example.com/cmd/nomatch...@v1.0.0
 stderr '^go: warning: "example.com/cmd/nomatch\.\.\." matched no packages$'
 
@@ -159,7 +159,7 @@ cmp stderr exclude-err
 # 'go install pkg@version' should report an error if the module requires a
 # higher version of itself.
 ! go install example.com/cmd/a@v1.0.0-newerself
-stderr '^go install: example.com/cmd/a@v1.0.0-newerself: version constraints conflict:\n\texample.com/cmd@v1.0.0-newerself requires example.com/cmd@v1.0.0, but example.com/cmd@v1.0.0-newerself is requested$'
+stderr '^go: example.com/cmd/a@v1.0.0-newerself: version constraints conflict:\n\texample.com/cmd@v1.0.0-newerself requires example.com/cmd@v1.0.0, but example.com/cmd@v1.0.0-newerself is requested$'
 
 
 # 'go install pkg@version' will only match a retracted version if it's
@@ -192,12 +192,12 @@ package main
 
 func main() {}
 -- replace-err --
-go install: example.com/cmd/a@v1.0.0-replace (in example.com/cmd@v1.0.0-replace):
+go: example.com/cmd/a@v1.0.0-replace (in example.com/cmd@v1.0.0-replace):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.
 -- exclude-err --
-go install: example.com/cmd/a@v1.0.0-exclude (in example.com/cmd@v1.0.0-exclude):
+go: example.com/cmd/a@v1.0.0-exclude (in example.com/cmd@v1.0.0-exclude):
        The go.mod file for the module providing named packages contains one or
        more exclude directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.
index c6bce418b4fa7093749bf780341a81d749635a60..627a9a81b0bead5747f3ae5793c8e14c150a3225 100644 (file)
@@ -1,11 +1,11 @@
 env GO111MODULE=on
 
-go get -d rsc.io/fortune
+go get rsc.io/fortune
 go list -f '{{.Target}}' rsc.io/fortune
 ! stdout fortune@v1
 stdout 'fortune(\.exe)?$'
 
-go get -d rsc.io/fortune/v2
+go get rsc.io/fortune/v2
 go list -f '{{.Target}}' rsc.io/fortune/v2
 ! stdout v2
 stdout 'fortune(\.exe)?$'
index 687269d18f6f33e05ce4572423d2d7cfa4efb8be..787b21f379c793f0428d90eb2ecdfc690a493cac 100644 (file)
@@ -3,34 +3,34 @@ env GO111MODULE=on
 
 # golang.org/x/internal should be importable from other golang.org/x modules.
 go mod edit -module=golang.org/x/anything
-go get -d .
+go get .
 
 # ...and their tests...
 go test
 stdout PASS
 
 # ...but that should not leak into other modules.
-go get -d ./baddep
+go get ./baddep
 ! go build ./baddep
 stderr golang.org[/\\]notx[/\\]useinternal
 stderr 'use of internal package golang.org/x/.* not allowed'
 
 # Internal packages in the standard library should not leak into modules.
-go get -d ./fromstd
+go get ./fromstd
 ! go build ./fromstd
 stderr 'use of internal package internal/testenv not allowed'
 
 # Dependencies should be able to use their own internal modules...
 go mod edit -module=golang.org/notx
-go get -d ./throughdep
+go get ./throughdep
 
 # ... but other modules should not, even if they have transitive dependencies.
-go get -d .
+go get .
 ! go build .
 stderr 'use of internal package golang.org/x/.* not allowed'
 
 # And transitive dependencies still should not leak.
-go get -d ./baddep
+go get ./baddep
 ! go build ./baddep
 stderr golang.org[/\\]notx[/\\]useinternal
 stderr 'use of internal package golang.org/x/.* not allowed'
@@ -38,17 +38,17 @@ stderr 'use of internal package golang.org/x/.* not allowed'
 # Replacing an internal module should keep it internal to the same paths.
 go mod edit -module=golang.org/notx
 go mod edit -replace golang.org/x/internal=./replace/golang.org/notx/internal
-go get -d ./throughdep
+go get ./throughdep
 
-go get -d ./baddep
+go get ./baddep
 ! go build ./baddep
 stderr golang.org[/\\]notx[/\\]useinternal
 stderr 'use of internal package golang.org/x/.* not allowed'
 
 go mod edit -replace golang.org/x/internal=./vendor/golang.org/x/internal
-go get -d ./throughdep
+go get ./throughdep
 
-go get -d ./baddep
+go get ./baddep
 ! go build ./baddep
 stderr golang.org[/\\]notx[/\\]useinternal
 stderr 'use of internal package golang.org/x/.* not allowed'
index 333a3ffa35cba157e6228157414be59a4cb59b92..667b76e340a5c4a02f1c22c95b75efde9313ed5e 100644 (file)
@@ -29,9 +29,9 @@ stdout '^example.com/dotname/.dot$'
 go list ./use
 stdout '^example.com/dotname/use$'
 ! go list -m example.com/dotname/.dot@latest
-stderr '^go list -m: example.com/dotname/.dot@latest: malformed module path "example.com/dotname/.dot": leading dot in path element$'
-go get -d example.com/dotname/.dot
-go get -d example.com/dotname/use
+stderr '^go: example.com/dotname/.dot@latest: malformed module path "example.com/dotname/.dot": leading dot in path element$'
+go get example.com/dotname/.dot
+go get example.com/dotname/use
 go mod tidy
 
 -- mod/go.mod --
index 85934332d145db7194fc62dc1ddb68aaa49e2e7d..484c208f0f7567196b39d19dc00683d787efdc15 100644 (file)
@@ -3,19 +3,19 @@
 
 # 'go get' works with no version query.
 cp go.mod.empty go.mod
-go get -d example.com/dotname/.dot
+go get example.com/dotname/.dot
 go list -m example.com/dotname
 stdout '^example.com/dotname v1.0.0$'
 
 # 'go get' works with a version query.
 cp go.mod.empty go.mod
-go get -d example.com/dotname/.dot@latest
+go get example.com/dotname/.dot@latest
 go list -m example.com/dotname
 stdout '^example.com/dotname v1.0.0$'
 
 # 'go get' works on an importing package.
 cp go.mod.empty go.mod
-go get -d .
+go get .
 go list -m example.com/dotname
 stdout '^example.com/dotname v1.0.0$'
 
index 51dbf936888769d0e4b777292ce807b235b918c3..dd59eb1fedac6870c1696869959f63a5a945d638 100644 (file)
@@ -4,16 +4,16 @@
 
 # 'go list' accepts package paths with pluses.
 cp go.mod.orig go.mod
-go get -d example.net/cmd
+go get example.net/cmd
 go list example.net/cmd/x++
 
 # 'go list -m' rejects module paths with pluses.
 ! go list -versions -m 'example.net/bad++'
-stderr '^go list -m: malformed module path "example.net/bad\+\+": invalid char ''\+''$'
+stderr '^go: malformed module path "example.net/bad\+\+": invalid char ''\+''$'
 
 # 'go get' accepts package paths with pluses.
 cp go.mod.orig go.mod
-go get -d example.net/cmd/x++
+go get example.net/cmd/x++
 go list -m example.net/cmd
 stdout '^example.net/cmd v0.0.0-00010101000000-000000000000 => ./cmd$'
 
index 6846a792a5df587e00b2ce7d497333413d4f0dd5..428b8aa60e6f8827b32bc424e685c815bc91ccde 100644 (file)
@@ -19,7 +19,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3'
+stderr 'go: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3'
 cd ..
 go list -m golang.org/x/text
 stdout 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c'
@@ -30,14 +30,14 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c'
 
 # However, arguments to 'go get' can name packages above the root.
 cp go.mod.orig go.mod
-go get -d golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c
+go get golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c
 go list -m golang.org/x/text/...
 stdout 'golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c'
 ! stdout 'golang.org/x/text/unicode'
@@ -47,7 +47,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v2.1.1-0.20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
+stderr 'go: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
 cd ..
 ! go list -m golang.org/x/text
 stderr $WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2'
@@ -57,27 +57,27 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(14c0d48ead0c\)'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(expected 14c0d48ead0c\)'
 cd ..
 ! go list -m golang.org/x/text
-stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(14c0d48ead0c\)'
+stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(expected 14c0d48ead0c\)'
 
 # A pseudo-version with more than 12 digits of SHA-1 prefix is invalid.
 cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(14c0d48ead0c\)'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(expected 14c0d48ead0c\)'
 cd ..
 ! go list -m golang.org/x/text
-stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(14c0d48ead0c\)'
+stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(expected 14c0d48ead0c\)'
 
 # A pseudo-version that does not match the commit timestamp is invalid.
 cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
@@ -87,7 +87,7 @@ stderr 'golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-v
 go mod edit -replace golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c=golang.org/x/text@14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)'
 cd ..
 go list -m golang.org/x/text
 stdout 'golang.org/x/text v0.1.1-0.20190915032832-14c0d48ead0c => golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c'
@@ -97,7 +97,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found'
@@ -109,7 +109,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1'
@@ -120,7 +120,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number'
@@ -130,7 +130,7 @@ stderr 'golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-v
 go mod edit -replace golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number'
 cd ..
 go list -m golang.org/x/text
 stdout 'golang.org/x/text v0.0.0-0.20170915032832-14c0d48ead0c => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c'
@@ -141,10 +141,10 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v1.999999.0
 go mod edit -replace golang.org/x/text@v1.999999.0=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
 cd outside
-! go get -d golang.org/x/text@upgrade
+! go get golang.org/x/text@upgrade
 stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999999.0: reading golang.org/x/text/go.mod at revision v1.999999.0: unknown revision v1.999999.0'
 cd ..
-go get -d golang.org/x/text@upgrade
+go get golang.org/x/text@upgrade
 go list -m golang.org/x/text
 stdout 'golang.org/x/text v1.999999.0 => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c'
 
@@ -153,7 +153,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)'
@@ -163,7 +163,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag'
@@ -173,7 +173,7 @@ cp go.mod.orig go.mod
 go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c+incompatible
 cd outside
 ! go list -m golang.org/x/text
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible'
+stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible'
 cd ..
 ! go list -m golang.org/x/text
 stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible'
@@ -194,7 +194,7 @@ cp go.mod.orig go.mod
 go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible
 cd outside
 ! go list -m github.com/pierrec/lz4
-stderr 'go list -m: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
+stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
 cd ..
 ! go list -m github.com/pierrec/lz4
 stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required'
@@ -214,15 +214,15 @@ stdout 'github.com/pierrec/lz4 v2.0.4-0.20180826165652-dbe9298ce099\+incompatibl
 # to the equivalent +incompatible version, not a pseudo-version with a different
 # major version.
 cp go.mod.orig go.mod
-go get -d github.com/pierrec/lz4@v2.0.5
+go get github.com/pierrec/lz4@v2.0.5
 go list -m github.com/pierrec/lz4
 stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible'
 
 # 'go get' for a mismatched major version with a go.mod file should error out,
 # not resolve to a pseudo-version with a different major version.
 cp go.mod.orig go.mod
-! go get -d github.com/pierrec/lz4@v2.0.8
-stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2'
+! go get github.com/pierrec/lz4@v2.0.8
+stderr 'go: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2'
 
 # An invalid +incompatible suffix for a canonical version should error out,
 # not resolve to a pseudo-version.
index b1852ab0319ebbccdc6e15b063719332fad938a6..92416a54e474e0a8bb22c6422e1dd2a2fca01154 100644 (file)
@@ -5,4 +5,4 @@ env GO111MODULE=on
 [short] skip
 
 go mod init example.com
-go get -d golang.org/x/text@v0.3.0 golang.org/x/internal@v0.1.0 golang.org/x/exp@none
+go get golang.org/x/text@v0.3.0 golang.org/x/internal@v0.1.0 golang.org/x/exp@none
index 2f815fef22ff6398d894ba5d4d74475fa728d525..eb69d2eb8f81e12bb2ee762c290cb25529c4e040 100644 (file)
@@ -27,7 +27,7 @@ stdout '^example.com/c v0.2.0 '
 
 # Downgrading c should also downgrade the b that requires it.
 
-go get -d example.com/c@v0.1.0
+go get example.com/c@v0.1.0
 go list -m all
 stdout '^example.com/a v0.1.0 '
 stdout '^example.com/b v0.2.0 '
@@ -35,7 +35,7 @@ stdout '^example.com/c v0.1.0 '
 
 # Removing c entirely should also remove the a and b that require it.
 
-go get -d example.com/c@none
+go get example.com/c@none
 go list -m all
 ! stdout '^example.com/a '
 ! stdout '^example.com/b '
@@ -53,7 +53,7 @@ stdout '^example.com/a v0.1.0 '
 stdout '^example.com/b v0.3.0 '
 stdout '^example.com/c v0.2.0 '
 
-go get -d example.com/c@v0.1.0
+go get example.com/c@v0.1.0
 go list -m all
 stdout '^example.com/a v0.1.0 '
 stdout '^example.com/b v0.2.0 '
@@ -63,7 +63,7 @@ stdout '^example.com/c v0.1.0 '
 # is still tracked, and it will still be downgraded away if we remove c.
 # ('go get' never makes a root into a non-root. Only 'go mod tidy' does that.)
 
-go get -d example.com/c@none
+go get example.com/c@none
 go list -m all
 ! stdout '^example.com/a '
 ! stdout '^example.com/b '
@@ -84,7 +84,7 @@ stdout '^example.com/a v0.1.0 '
 stdout '^example.com/b v0.3.0 '
 stdout '^example.com/c v0.2.0 '
 
-go get -d example.com/c@v0.1.0 example.com/b@v0.1.0
+go get example.com/c@v0.1.0 example.com/b@v0.1.0
 go list -m all
 stdout '^example.com/a v0.1.0 '
 stdout '^example.com/b v0.1.0 '
@@ -96,7 +96,7 @@ stdout '^example.com/a v0.1.0 '
 stdout '^example.com/b v0.1.0 '
 ! stdout '^example.com/c '
 
-go get -d example.com/c@none
+go get example.com/c@none
 go list -m all
 stdout '^example.com/a v0.1.0'
 stdout '^example.com/b v0.1.0'
index 97718c4513b55bffd6819544119f32b74b734173..60d4187b1178aec7deb1a5e554fe55d936899d76 100644 (file)
@@ -66,7 +66,7 @@ stdout '^b v0.1.0 '
 ! stdout '^c '
 
 # After adding a new direct import of b/y,
-# the existing verison of b should be promoted to a root,
+# the existing version of b should be promoted to a root,
 # bringing the version of c required by b into the build list.
 
 cp m.go.new m.go
index 239c7caa4a2246e87eaaef22b2ace9ce6ba800dc..06316cc335ed677e32cc0647f3b0f3d2d975d0b1 100644 (file)
@@ -39,8 +39,8 @@ stdout '^module nonexist: not a known dependency$'
 stdout '^module rsc.io/quote/buggy: not a known dependency$'
 
 ! go list -m nonexist rsc.io/quote/buggy
-stderr '^go list -m: module nonexist: not a known dependency'
-stderr '^go list -m: module rsc.io/quote/buggy: not a known dependency'
+stderr '^go: module nonexist: not a known dependency'
+stderr '^go: module rsc.io/quote/buggy: not a known dependency'
 
 # Module loader does not interfere with list -e (golang.org/issue/24149).
 go list -e -f '{{.Error.Err}}' database
diff --git a/src/cmd/go/testdata/script/mod_list_command_line_arguments.txt b/src/cmd/go/testdata/script/mod_list_command_line_arguments.txt
new file mode 100644 (file)
index 0000000..fd99ae8
--- /dev/null
@@ -0,0 +1,35 @@
+# The command-line-arguments package does not belong to a module...
+cd a
+go list -f '{{.Module}}' ../b/b.go
+stdout '^<nil>$'
+
+# ... even if the arguments are sources from that module
+go list -f '{{.Module}}' a.go
+stdout '^<nil>$'
+
+[short] skip
+
+# check that the version of command-line-arguments doesn't include a module
+go build -o a.exe a.go
+go version -m a.exe
+stdout '^\tpath\tcommand-line-arguments$'
+stdout '^\tdep\ta\t\(devel\)\t$'
+! stdout mod
+
+-- a/go.mod --
+module a
+go 1.17
+-- a/a.go --
+package main
+
+import "a/dep"
+
+func main() {
+    dep.D()
+}
+-- a/dep/dep.go --
+package dep
+
+func D() {}
+-- b/b.go --
+package b
\ No newline at end of file
index f0ecbba2cea13d8c65f512036e3d0b8c887a3703..ee985cccbf3a91f5a3fc29dd08d2f181630ed8cb 100644 (file)
@@ -20,7 +20,7 @@ stdout '^in example.com/deprecated/a@v1.9.0$'
 
 # This works even if we use an old version that does not have the deprecation
 # message in its go.mod file.
-go get -d example.com/deprecated/a@v1.0.0
+go get example.com/deprecated/a@v1.0.0
 ! grep Deprecated: $WORK/gopath/pkg/mod/cache/download/example.com/deprecated/a/@v/v1.0.0.mod
 go list -m -u -f {{.Deprecated}} example.com/deprecated/a
 stdout '^in example.com/deprecated/a@v1.9.0$'
index 1adab8f027d7374869b7ebba276b528ea5229ca1..7ad65ffbc734dea082e662c407a40e732913a33f 100644 (file)
@@ -3,7 +3,7 @@
 # go list with path to directory should work
 
 # populate go.sum
-go get -d
+go get
 
 env GO111MODULE=off
 go list -f '{{.ImportPath}}' $GOROOT/src/math
@@ -20,7 +20,7 @@ go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
 stdout '^rsc.io/quote$'
 go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0
 stdout '^rsc.io/sampler$'
-go get -d rsc.io/sampler@v1.3.1
+go get rsc.io/sampler@v1.3.1
 go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.1
 stdout '^rsc.io/sampler$'
 ! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0
index 62a472f475e7f8f58a13177977a6b4c4c94abc1d..9b7a04c5044302b4aaac7fb5b24fb6738e6bf014 100644 (file)
@@ -10,7 +10,7 @@ env GOSUMDB=off
 # For a while, (*modfetch.codeRepo).Stat was not checking for a go.mod file,
 # which would produce a hard error at the subsequent call to GoMod.
 
-go get -d
+go get
 
 -- go.mod --
 module example.com
index f2f2d2b2bb23c40e7993894fcf0ba28ca4ce9f35..eac5ca7dd322040b1dd0dc6a7dc6128b823b8772 100644 (file)
@@ -3,7 +3,7 @@
 # Verifies golang.org/issue/29548
 
 # Populate go.sum and download dependencies.
-go get -d
+go get
 
 # Ensure v1.5.2 is also in the cache so we can list it.
 go mod download rsc.io/quote@v1.5.2
index 86c528f82907b0d2989b014bf49f154ba4b1353d..6c2f57c2b2d88de231fdd05407f3d2daf5308b59 100644 (file)
@@ -29,4 +29,4 @@ stderr '^go: updates to go.sum needed, disabled by -mod=readonly$'
 #
 # TODO(#41297): This should not be an error either.
 ! go list -m -mod=readonly -versions rsc.io/sampler
-stderr '^go list -m: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
+stderr '^go: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
index c6bbbb04ec7268486fb45e47f80612c527054fcf..7eebe266dbb8f07bc0c87f7f67364f45166314f0 100644 (file)
@@ -26,7 +26,7 @@ stdout '^example.com/nolatest v0.0.0$'
 # If proxy returns an invalid response, we should see an error.
 env GOPROXY=$testproxy/invalid
 ! go list -m -u example.com/nolatest
-stderr '^go list -m: loading module retractions for example.com/nolatest@v0.0.0: invalid response from proxy "[^"]*": invalid character ''i'' looking for beginning of value$'
+stderr '^go: loading module retractions for example.com/nolatest@v0.0.0: invalid response from proxy "[^"]*": invalid character ''i'' looking for beginning of value$'
 
 -- go.mod --
 module m
index b983bec73db903c6414effad41b00c06e9720343..8e51dfcd2aadf8327d79657204e9d61828665d5c 100644 (file)
@@ -12,11 +12,11 @@ env GO111MODULE=on
 # The latest pseudo-version is semantically higher than the latest tag.
 # 'list -u' should not suggest a lower version as an upgrade.
 
-go get -d example.com/pseudoupgrade@b5426c8
+go get example.com/pseudoupgrade@b5426c8
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$'
 
-go get -d example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534
+go get example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534
 go list -m -u all
 stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$'
 
index eb464ab0d3b84ea1faec6d201ccf10eb7e476389..be2a4bc1db283b92e0c59871cb361b67a0613ae8 100644 (file)
@@ -10,13 +10,13 @@ go mod download example.com/badchain/b@v1.1.0
 go mod download example.com/badchain/c@v1.1.0
 
 # Try to update example.com/badchain/a (and its dependencies).
-! go get -d example.com/badchain/a
+! go get example.com/badchain/a
 cmp stderr update-a-expected
 cmp go.mod go.mod.orig
 
 # Try to update the main module. This updates everything, including
 # modules that aren't direct requirements, so the error stack is shorter.
-! go get -d -u ./...
+! go get -u ./...
 cmp stderr update-main-expected
 cmp go.mod go.mod.orig
 
@@ -69,17 +69,17 @@ import (
 
 func Test(t *testing.T) {}
 -- update-main-expected --
-go get: example.com/badchain/c@v1.1.0: parsing go.mod:
+go: example.com/badchain/c@v1.1.0: parsing go.mod:
        module declares its path as: badchain.example.com/c
                but was required as: example.com/badchain/c
 -- update-a-expected --
-go get: example.com/badchain/a@v1.1.0 requires
+go: example.com/badchain/a@v1.1.0 requires
        example.com/badchain/b@v1.1.0 requires
        example.com/badchain/c@v1.1.0: parsing go.mod:
        module declares its path as: badchain.example.com/c
                but was required as: example.com/badchain/c
 -- list-expected --
-go list -m: example.com/badchain/a@v1.1.0 requires
+go: example.com/badchain/a@v1.1.0 requires
        example.com/badchain/b@v1.1.0 requires
        example.com/badchain/c@v1.1.0: parsing go.mod:
        module declares its path as: badchain.example.com/c
index 65374d2a6d1fdc219b0ed608818679738cf55bd3..58160b4d442252f5903845158950bcd635ac5708 100644 (file)
@@ -1,7 +1,7 @@
 # Zip files with unexpected file names inside should be rejected.
 env GO111MODULE=on
 
-! go get -d rsc.io/badzip
+! go get rsc.io/badzip
 stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt'
 ! grep rsc.io/badzip go.mod
 
index 8dae85fa88d1508b724e2574b83c786621001d72..b91a8dbedacb52277ef4cf0f9285a341e92e109c 100644 (file)
@@ -9,7 +9,7 @@ env GO111MODULE=on
 env GOPROXY=direct
 env GOSUMDB=off
 
-! go get -d vcs-test.golang.org/go/missingrepo/missingrepo-git
+! go mod download vcs-test.golang.org/go/missingrepo/missingrepo-git@latest
 stderr 'vcs-test.golang.org/go/missingrepo/missingrepo-git: git ls-remote .*: exit status .*'
 
-go get -d vcs-test.golang.org/go/missingrepo/missingrepo-git/notmissing
+go mod download vcs-test.golang.org/go/missingrepo/missingrepo-git/notmissing@latest
index 0f335a11f0fb3bf3d2ecf2abc81b10ee3c3b1da9..bbefb78d90a48ee9b25874fb1853e33478126e5c 100644 (file)
@@ -7,7 +7,7 @@ go list -deps -f {{.Dir}}
 # v2 import should use a downloaded module
 # both without an explicit go.mod entry ...
 cp tmp/use_v2.go x.go
-go get -d .
+go get .
 go list -deps -f {{.Dir}}
 stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$'
 
diff --git a/src/cmd/go/testdata/script/mod_no_gopath.txt b/src/cmd/go/testdata/script/mod_no_gopath.txt
new file mode 100644 (file)
index 0000000..ed91f5d
--- /dev/null
@@ -0,0 +1,15 @@
+# https://golang.org/issue/43938: 'go build' should succeed
+# if GOPATH and the variables needed for its default value
+# are all unset but not relevant to the specific command.
+
+env HOME=''
+env home=''
+env GOPATH=''
+
+go list -deps main.go
+stdout '^io$'
+
+-- main.go --
+package main
+
+import _ "io"
index 33341f7d4b3656fbfb37132fd9e4ec72bf2354a2..f88e2ae7efa6763b93a58929830c3cd52fe553d5 100644 (file)
@@ -123,30 +123,30 @@ stderr '^go: go.mod file not found in current directory or any parent directory;
 stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
 
 
-# 'go get' without arguments implicitly operates on the main module, and thus
-# should fail.
+# 'go get' has no go.mod file to update outside a module and should fail.
 ! go get
-stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
 ! go get -u
-stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
 ! go get -u ./needmod
-stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
-
-# 'go get -u all' upgrades the transitive import graph of the main module,
-# which is empty.
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
 ! go get -u all
-stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
-
-# 'go get' should check the proposed module graph for consistency,
-# even though we won't write it anywhere.
-! go get -d example.com/printversion@v1.0.0 example.com/version@none
-stderr '^go get: example.com/printversion@v1.0.0 requires example.com/version@v1.0.0, not example.com/version@none$'
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
+! go get example.com/printversion@v1.0.0 example.com/version@none
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
 
-# 'go get -d' should download and extract the source code needed to build the requested version.
-rm -r $GOPATH/pkg/mod/example.com
-go get -d example.com/printversion@v1.0.0
-exists $GOPATH/pkg/mod/example.com/printversion@v1.0.0
-exists $GOPATH/pkg/mod/example.com/version@v1.0.0
+# 'go get' should not download anything.
+go clean -modcache
+! go get example.com/printversion@v1.0.0
+stderr '^go: go.mod file not found in current directory or any parent directory.$'
+stderr '^\t''go get'' is no longer supported outside a module.$'
+! exists $GOPATH/pkg/mod/example.com/printversion@v1.0.0
+! exists $GOPATH/pkg/mod/example.com/version@v1.0.0
 
 
 # 'go build' without arguments implicitly operates on the current directory, and should fail.
@@ -196,7 +196,7 @@ exists $GOPATH/bin/printversion$GOEXE
 
 # 'go install' should fail if a package argument must be resolved to a module.
 ! go install example.com/printversion
-stderr '^go install: version is required when current directory is not in a module\n\tTry ''go install example.com/printversion@latest'' to install the latest version$'
+stderr '^go: ''go install'' requires a version when current directory is not in a module\n\tTry ''go install example.com/printversion@latest'' to install the latest version$'
 
 # 'go install' should fail if a source file imports a package that must be
 # resolved to a module.
@@ -223,35 +223,11 @@ go fmt needmod/needmod.go
 
 # The remainder of the test checks dependencies by linking and running binaries.
 
-# 'go get' of a binary without a go.mod should install the requested version,
-# resolving outside dependencies to the latest available versions.
-go get example.com/printversion@v0.1.0
-exec ../bin/printversion
-stdout 'path is example.com/printversion'
-stdout 'main is example.com/printversion v0.1.0'
-stdout 'using example.com/version v1.1.0'
-
-# 'go get' of a versioned binary should build and install the latest version
-# using its minimal required modules, ignoring replacements and exclusions.
-go get example.com/printversion
-exec ../bin/printversion
-stdout 'path is example.com/printversion'
-stdout 'main is example.com/printversion v1.0.0'
-stdout 'using example.com/version v1.0.0'
-
-# 'go get -u=patch' should patch dependencies before installing,
-# again ignoring replacements and exclusions.
-go get -u=patch example.com/printversion@v1.0.0
-exec ../bin/printversion
-stdout 'path is example.com/printversion'
-stdout 'main is example.com/printversion v1.0.0'
-stdout 'using example.com/version v1.0.1'
-
 # 'go run' should work with file arguments if they don't import anything
 # outside std.
 go run ./stdonly/stdonly.go
 stdout 'path is command-line-arguments$'
-stdout 'main is command-line-arguments \(devel\)'
+stdout 'main is  $'
 
 # 'go generate' should work with file arguments.
 [exec:touch] go generate ./needmod/needmod.go
index 86ab04bd3cfab4a8c4a594dce374bbff8a2e1f46..da35be6a196ed619d54d6f00668550b16c7c4b29 100644 (file)
@@ -20,7 +20,7 @@ go list -deps -overlay overlay.json .
 # Overlaid go.mod is not rewritten by 'go get'.
 cd $WORK/gopath/src/get-doesnt-add-dep
 cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
-! go get -d -overlay overlay.json .
+! go get -overlay overlay.json .
 stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
 cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
 
@@ -30,17 +30,17 @@ cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
 # the correct go.sum is used with the overlay, 'go get .' should
 # not report a security error.
 cd $WORK/gopath/src/overlay-sum-used
-! go get -d .
+! go get .
 stderr 'SECURITY ERROR'
 ! go mod verify
 stderr 'SECURITY ERROR'
-go get -d -overlay overlay.json .
+go get -overlay overlay.json .
 go mod verify -overlay overlay.json
 # Overlaid go.sum is not rewritten.
 # Copy an incomplete file to the overlay file, and expect an error
 # attempting to update the file
 cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
-! go get -d -overlay overlay.json .
+! go get -overlay overlay.json .
 stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
 cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
 ! go mod tidy -overlay overlay.json
@@ -55,7 +55,7 @@ cd $WORK/gopath/src/overlay-and-dash-modfile
 go list -modfile=alternate.mod -overlay overlay.json .
 stdout 'found.the/module'
 # Even with -modfile, overlaid files can't be opened for write.
-! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote
+! go get -modfile=alternate.mod -overlay overlay.json rsc.io/quote
 stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
 
 # Carving out a module by adding an overlaid go.mod file
@@ -77,11 +77,11 @@ go list -overlay overlay.json all
 ! stdout ^carve2$
 stdout ^carve2/nomod$
 # Editing go.mod file fails because overlay is read only
-! go get -overlay overlay.json -d rsc.io/quote
+! go get -overlay overlay.json rsc.io/quote
 stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
 ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod
 # Editing go.mod file succeeds because we use -modfile to redirect to same file
-go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote
+go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod rsc.io/quote
 grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod
 
 -- no-go-mod/file.go --
index 2d32dcd10fd4c91e35636b88d994d7a51c2eb0a0..77e2508cb7f3b13a6998ddcb89bab5431e32d0d5 100644 (file)
@@ -12,7 +12,7 @@ chmod 0640 go.mod
 chmod 0604 go.sum
 go mod edit -module=golang.org/issue/34634
 
-go get -d
+go get
 cmp go.mod go.mod.want
 cmp go.sum go.sum.want
 
index 1b408c3e9e925d02cf6ea590bc721fb4880b2f7a..8e88997a3c3089c9360128c1d58dac2cd841e1eb 100644 (file)
@@ -24,7 +24,7 @@ go list -m github.com/russross/blackfriday@upgrade
 stdout '^github.com/russross/blackfriday v1\.'
 
 ! go list -m github.com/russross/blackfriday@patch
-stderr '^go list -m: github.com/russross/blackfriday@patch: can''t query version "patch" of module github.com/russross/blackfriday: no existing version is required$'
+stderr '^go: github.com/russross/blackfriday@patch: can''t query version "patch" of module github.com/russross/blackfriday: no existing version is required$'
 
 # If we're fetching directly from version control, ignored +incompatible
 # versions should also be omitted by 'go list'.
index 6427cc1527af3793236f9e42d4f5c31acc17514e..63980b839e7743780d6959b26e6dbd6e542e38a2 100644 (file)
@@ -2,7 +2,7 @@ env GO111MODULE=on
 env GOPROXY=$GOPROXY/invalid
 
 ! go list -m rsc.io/quote@latest
-stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
+stderr '^go: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
 
 ! go list -m rsc.io/quote@1.5.2
-stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
+stderr '^go: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
index 89129f4fe237d6440935fd836ac9cacf7c2887f9..849cf2c476406554244339100d1699327f5857aa 100644 (file)
@@ -3,34 +3,34 @@ env proxy=$GOPROXY
 
 # Proxy that can't serve should fail.
 env GOPROXY=$proxy/404
-! go get -d rsc.io/quote@v1.0.0
+! go get rsc.io/quote@v1.0.0
 stderr '404 Not Found'
 
 # get should walk down the proxy list past 404 and 410 responses.
 env GOPROXY=$proxy/404,$proxy/410,$proxy
-go get -d rsc.io/quote@v1.1.0
+go get rsc.io/quote@v1.1.0
 
 # get should not walk past other 4xx errors if proxies are separated with ','.
 env GOPROXY=$proxy/403,$proxy
-! go get -d rsc.io/quote@v1.2.0
+! go get rsc.io/quote@v1.2.0
 stderr 'reading.*/403/rsc.io/.*: 403 Forbidden'
 
 # get should not walk past non-4xx errors if proxies are separated with ','.
 env GOPROXY=$proxy/500,$proxy
-! go get -d rsc.io/quote@v1.3.0
+! go get rsc.io/quote@v1.3.0
 stderr 'reading.*/500/rsc.io/.*: 500 Internal Server Error'
 
 # get should walk past other 4xx errors if proxies are separated with '|'.
 env GOPROXY=$proxy/403|https://0.0.0.0|$proxy
-go get -d rsc.io/quote@v1.2.0
+go get rsc.io/quote@v1.2.0
 
 # get should walk past non-4xx errors if proxies are separated with '|'.
 env GOPROXY=$proxy/500|https://0.0.0.0|$proxy
-go get -d rsc.io/quote@v1.3.0
+go get rsc.io/quote@v1.3.0
 
 # get should return the final error if that's all we have.
 env GOPROXY=$proxy/404,$proxy/410
-! go get -d rsc.io/quote@v1.4.0
+! go get rsc.io/quote@v1.4.0
 stderr 'reading.*/410/rsc.io/.*: 410 Gone'
 
 -- go.mod --
index a75f86ed7c5729d3c4b55734ae48b33f2f68170b..3758732504d0ca3f056acf169d1d96cf1171af40 100644 (file)
@@ -25,7 +25,7 @@ go list -m rsc.io/quote@<v1.5.4
 stdout 'rsc.io/quote v1.5.2$'
 
 ! go list -m rsc.io/quote@>v1.5.3
-stderr 'go list -m: module rsc.io/quote: no matching versions for query ">v1.5.3"'
+stderr 'go: module rsc.io/quote: no matching versions for query ">v1.5.3"'
 
 go list -m -e -f '{{.Error.Err}}' rsc.io/quote@>v1.5.3
 stdout 'no matching versions for query ">v1.5.3"'
index f8b6e3e97edcff1c2c2d2ec0abadb5b3d3bc04b4..1c39eae5744c31d0b12a483eddd3a59a6d75ce1e 100644 (file)
@@ -7,14 +7,14 @@ go mod download example.com/join@v1.1.0
 # reading that version should cause 'go get' to fail.
 env GOPROXY=file:///$WORK/badproxy
 cp go.mod.orig go.mod
-! go get -d example.com/join/subpkg
-stderr 'go get: example.com/join/subpkg@v0.0.0-20190624000000-123456abcdef: .*'
+! go get example.com/join/subpkg
+stderr 'go: example.com/join/subpkg@v0.0.0-20190624000000-123456abcdef: .*'
 
 # If @v/list is empty, the 'go' command should still try to resolve
 # other module paths.
 env GOPROXY=file:///$WORK/emptysub
 cp go.mod.orig go.mod
-go get -d example.com/join/subpkg
+go get example.com/join/subpkg
 go list -m example.com/join/...
 ! stdout 'example.com/join/subpkg'
 stdout 'example.com/join v1.1.0'
@@ -23,7 +23,7 @@ stdout 'example.com/join v1.1.0'
 # that version is treated as nonexistent.
 env GOPROXY=file:///$WORK/notfound
 cp go.mod.orig go.mod
-go get -d example.com/join/subpkg
+go get example.com/join/subpkg
 go list -m example.com/join/...
 ! stdout 'example.com/join/subpkg'
 stdout 'example.com/join v1.1.0'
@@ -39,8 +39,8 @@ stdout 'example.com/join v1.1.0'
 env GOPROXY=file:///$WORK/gatekeeper
 chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest
 cp go.mod.orig go.mod
-! go get -d example.com/join/subpkg
-stderr 'go get: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
+! go get example.com/join/subpkg
+stderr 'go: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
 
 -- go.mod.orig --
 module example.com/othermodule
index b0019694119bb17b2e95bfd180055aafc32daafb..f76b20c6d8830693856d8f59420cb7bb07aa9cb8 100644 (file)
@@ -18,17 +18,17 @@ stdout '^rsc.io/quote v1.5.1$'
 
 # get excluded version
 cp go.exclude.mod go.exclude.mod.orig
-! go get -modfile=go.exclude.mod -d rsc.io/quote@v1.5.0
-stderr '^go get: rsc.io/quote@v1.5.0: excluded by go.mod$'
+! go get -modfile=go.exclude.mod rsc.io/quote@v1.5.0
+stderr '^go: rsc.io/quote@v1.5.0: excluded by go.mod$'
 
 # get non-excluded version
 cp go.exclude.mod.orig go.exclude.mod
-go get -modfile=go.exclude.mod -d rsc.io/quote@v1.5.1
+go get -modfile=go.exclude.mod rsc.io/quote@v1.5.1
 stderr 'rsc.io/quote v1.5.1'
 
 # get query with excluded version
 cp go.exclude.mod.orig go.exclude.mod
-go get -modfile=go.exclude.mod -d rsc.io/quote@>=v1.5
+go get -modfile=go.exclude.mod rsc.io/quote@>=v1.5
 go list -modfile=go.exclude.mod -m ...quote
 stdout 'rsc.io/quote v1.5.[1-9]'
 
index 39e5841a9cfa42e06a42d7018e958fa867536ccd..2a2fa42318aa1d10ceaef2d8725b868bd6013de6 100644 (file)
@@ -6,9 +6,9 @@ go mod download rsc.io/quote@latest
 # 'go mod download' will not download @upgrade or @patch, since they always
 # resolve to the main module.
 go mod download rsc.io/quote@upgrade
-stderr '^go mod download: skipping argument rsc.io/quote@upgrade that resolves to the main module$'
+stderr '^go: skipping download of rsc.io/quote@upgrade that resolves to the main module$'
 go mod download rsc.io/quote@patch
-stderr '^go mod download: skipping argument rsc.io/quote@patch that resolves to the main module$'
+stderr '^go: skipping download of rsc.io/quote@patch that resolves to the main module$'
 
 # 'go list -m' can show a version of the main module.
 go list -m rsc.io/quote@5d9f230b
@@ -31,11 +31,11 @@ stdout '^rsc.io/quote$'
 # 'go get' will not attempt to upgrade the main module to any specific version.
 # See also: mod_get_main.txt.
 ! go get rsc.io/quote@5d9f230b
-stderr '^go get: can''t request version "5d9f230b" of the main module \(rsc.io/quote\)$'
+stderr '^go: can''t request version "5d9f230b" of the main module \(rsc.io/quote\)$'
 ! go get rsc.io/quote@v1.5.2
-stderr '^go get: can''t request version "v1.5.2" of the main module \(rsc.io/quote\)$'
+stderr '^go: can''t request version "v1.5.2" of the main module \(rsc.io/quote\)$'
 ! go get rsc.io/quote@latest
-stderr '^go get: can''t request version "latest" of the main module \(rsc.io/quote\)$'
+stderr '^go: can''t request version "latest" of the main module \(rsc.io/quote\)$'
 
 -- go.mod --
 module rsc.io/quote
index d05ad2a3174f8ed5066299fb25516d131e654a08..9e950c389821208b1f4fd9e75459555261ebb8b0 100644 (file)
@@ -19,7 +19,7 @@ cmp go.mod go.mod.empty
 env GOFLAGS=-mod=readonly
 
 # update go.mod - go get allowed
-go get -d rsc.io/quote
+go get rsc.io/quote
 grep rsc.io/quote go.mod
 
 # update go.mod - go mod tidy allowed
@@ -41,7 +41,7 @@ go list -m all
 
 # -mod=readonly should reject inconsistent go.mod files
 # (ones that would be rewritten).
-go get -d rsc.io/sampler@v1.2.0
+go get rsc.io/sampler@v1.2.0
 go mod edit -require rsc.io/quote@v1.5.2
 cp go.mod go.mod.inconsistent
 ! go list
@@ -81,7 +81,7 @@ stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\
 stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$'
 
 # However, if we didn't see an import from the main module, we should suggest
-# 'go get -d' instead, because we don't know whether 'go mod tidy' would add it.
+# 'go get' instead, because we don't know whether 'go mod tidy' would add it.
 ! go list rsc.io/quote
 stderr '^no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$'
 
index a0a367fb1db11c7765ae0f09945fe13bbe2fe622..26b15518d94fa3bcf7e762abdd1f4d0667a0c50b 100644 (file)
@@ -42,7 +42,7 @@ stdout 'Concurrency is not parallelism.'
 # indicate the replacement module.
 cp go.mod.orig go.mod
 go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3
-! go get -d rsc.io/quote/v3/missing-package
+! go get rsc.io/quote/v3/missing-package
 stderr 'module rsc.io/quote/v3@upgrade found \(v3.0.0, replaced by ./local/rsc.io/quote/v3\), but does not contain package'
 
 # The reported Dir and GoMod for a replaced module should be accurate.
index d24f37b7880920f9a3f7d949fdafabe09fd92103..df752d9716e538b4bb89c73679d45df8e1b395ca 100644 (file)
@@ -35,7 +35,7 @@ go list -m gopkg.in/src-d/go-git.v4
 # A mismatched gopkg.in path should not be able to replace a different major version.
 cd ../3-to-gomod-4
 ! go list -m gopkg.in/src-d/go-git.v3
-stderr '^go list -m: gopkg\.in/src-d/go-git\.v3@v3\.2\.0 \(replaced by gopkg\.in/src-d/go-git\.v3@v3\.0\.0-20190801152248-0d1a009cbb60\): version "v3\.0\.0-20190801152248-0d1a009cbb60" invalid: go\.mod has non-\.\.\.\.v3 module path "gopkg\.in/src-d/go-git\.v4" at revision 0d1a009cbb60$'
+stderr '^go: gopkg\.in/src-d/go-git\.v3@v3\.2\.0 \(replaced by gopkg\.in/src-d/go-git\.v3@v3\.0\.0-20190801152248-0d1a009cbb60\): version "v3\.0\.0-20190801152248-0d1a009cbb60" invalid: go\.mod has non-\.\.\.\.v3 module path "gopkg\.in/src-d/go-git\.v4" at revision 0d1a009cbb60$'
 
 -- 4-to-4/go.mod --
 module golang.org/issue/34254
index 2add31f71c10d43f828c953cfbd7ebe9d29bffb3..7bf3a86fed876faec6d6ff206493bcea64693863 100644 (file)
@@ -6,7 +6,7 @@ cp go.mod go.mod.orig
 cmp go.mod go.mod.orig
 
 # 'go list' should resolve imports using replacements.
-go get -d
+go get
 go list all
 stdout 'example.com/a/b$'
 stdout 'example.com/x/v3$'
index d950d78bd3c621b7ebf429e33458214bb0f6cb30..5c1226b15efd46e06af85ed7277b83123bf0e83f 100644 (file)
@@ -10,7 +10,7 @@ cp go.mod go.mod.orig
 go mod edit -replace rsc.io/quote=./quote
 ! go list rsc.io/quote
 stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote$'
-go get -d rsc.io/quote
+go get rsc.io/quote
 cmp go.mod go.mod.latest
 go list rsc.io/quote
 cp go.mod.orig go.mod
@@ -19,7 +19,7 @@ cp go.mod.orig go.mod
 go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote
 ! go list rsc.io/quote
 stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote@v1.0.0-doesnotexist$'
-go get -d rsc.io/quote@v1.0.0-doesnotexist
+go get rsc.io/quote@v1.0.0-doesnotexist
 cmp go.mod go.mod.specific
 go list rsc.io/quote
 cp go.mod.orig go.mod
index 481c10d2b7d26ae25a47a93733d2f0994c617def..9d30026459a8af6440f0eb8bbce61eb0f4d9a179 100644 (file)
@@ -83,14 +83,14 @@ require (
 package x
 import _ "rsc.io/quote"
 -- go.mod.crlf --
-module m\r
-\r
-go 1.14\r
-\r
-require (\r
-       rsc.io/quote v1.5.2\r
-       rsc.io/testonly v1.0.0 // indirect\r
-)\r
+module m
+
+go 1.14
+
+require (
+       rsc.io/quote v1.5.2
+       rsc.io/testonly v1.0.0 // indirect
+)
 -- go.mod.unsorted --
 module m
 
@@ -141,10 +141,10 @@ module m
 
 go $goversion
 
+require rsc.io/quote v1.5.2
+
 require (
-       rsc.io/quote v1.5.2
+       golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
        rsc.io/sampler v1.3.0 // indirect
        rsc.io/testonly v1.0.0 // indirect
 )
-
-require golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
index 4f95ece8d7aaaeb72016d12d273d9c61fe60befe..37aae4896d0c718b983f2a6f15375c2e38f0159c 100644 (file)
@@ -17,7 +17,7 @@ exists $GOPATH/pkg/mod/cache/download/example.com/retract/@v/v1.0.0-bad.mod
 
 # Importing a package from a module with a retracted latest version will
 # select the latest non-retracted version.
-go get -d ./use_self_prev
+go get ./use_self_prev
 go list -m example.com/retract/self/prev
 stdout '^example.com/retract/self/prev v1.1.0$'
 exists $GOPATH/pkg/mod/cache/download/example.com/retract/self/prev/@v/v1.9.0.mod
index e45758b627016da1252ace1231bbf4bb11a6c881..9ae49f53ab3797cbcd86b0e5dd899bef5fbd5fb0 100644 (file)
@@ -15,7 +15,7 @@ cmp go.mod go.mod.want
 # If a retracted version doesn't match the module's major version suffx,
 # an error should be reported.
 ! go mod edit -retract=v3.0.1
-stderr '^go mod: -retract=v3.0.1: version "v3.0.1" invalid: should be v2, not v3$'
+stderr '^go: -retract=v3.0.1: version "v3.0.1" invalid: should be v2, not v3$'
 cp go.mod.mismatch-v2 go.mod
 ! go list -m all
 stderr 'go.mod:3: retract rsc.io/quote/v2: version "v3.0.1" invalid: should be v2, not v3$'
index 61538e8024445c60874850b5ca6d501b7f19606d..5d09532529239b9201d14b38a6a22a1112eae8c8 100644 (file)
@@ -6,10 +6,10 @@
 go mod init m
 
 # Request a +incompatible version retracted in v1.0.0.
-go get -d example.com/retract/incompatible@v2.0.0+incompatible
+go get example.com/retract/incompatible@v2.0.0+incompatible
 stderr '^go: warning: example.com/retract/incompatible@v2.0.0\+incompatible: retracted by module author$'
 
 # We should still see a warning if the +incompatible was previously in the
 # build list.
-go get -d example.com/retract/incompatible@v2.0.0+incompatible
+go get example.com/retract/incompatible@v2.0.0+incompatible
 stderr '^go: warning: example.com/retract/incompatible@v2.0.0\+incompatible: retracted by module author$'
index eb00e8405c01073740f44c1d769647324182b092..27c2b670658e214bd27be9f739da3a6a64560812 100644 (file)
@@ -24,12 +24,12 @@ stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-64c061
 
 # A retracted version is a valid base. Retraction should not validate existing
 # pseudo-versions, nor should it turn invalid pseudo-versions valid.
-go get -d vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-713affd19d7b
+go get vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-713affd19d7b
 go list -m vcs-test.golang.org/git/retract-pseudo.git
 stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.1-0.20201009173747-713affd19d7b$'
 
-! go get -d vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371
-stderr '^go get: vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371: invalid pseudo-version: tag \(v1.0.0\) found on revision 64c061ed4371 is already canonical, so should not be replaced with a pseudo-version derived from that tag$'
+! go get vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371
+stderr '^go: vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371: invalid pseudo-version: tag \(v1.0.0\) found on revision 64c061ed4371 is already canonical, so should not be replaced with a pseudo-version derived from that tag$'
 
 -- retract-pseudo.sh --
 #!/bin/bash
index 823c384e488ff6d109d12fd2ae2e01bd419ffa70..92e9b7d6ea573c28e3b55471f5f6fd97a2a3ea1b 100644 (file)
@@ -1,5 +1,5 @@
 # When there is no rationale, 'go get' should print a hard-coded message.
-go get -d example.com/retract/rationale@v1.0.0-empty
+go get example.com/retract/rationale@v1.0.0-empty
 stderr '^go: warning: example.com/retract/rationale@v1.0.0-empty: retracted by module author$'
 
 # 'go list' should print the same hard-coded message.
@@ -8,7 +8,7 @@ stdout '^\[retracted by module author\]$'
 
 
 # When there is a multi-line message, 'go get' should print the first line.
-go get -d example.com/retract/rationale@v1.0.0-multiline1
+go get example.com/retract/rationale@v1.0.0-multiline1
 stderr '^go: warning: example.com/retract/rationale@v1.0.0-multiline1: retracted by module author: short description$'
 ! stderr 'detail'
 
@@ -18,7 +18,7 @@ cmp stdout multiline
 
 # 'go get' output should be the same whether the retraction appears at top-level
 # or in a block.
-go get -d example.com/retract/rationale@v1.0.0-multiline2
+go get example.com/retract/rationale@v1.0.0-multiline2
 stderr '^go: warning: example.com/retract/rationale@v1.0.0-multiline2: retracted by module author: short description$'
 ! stderr 'detail'
 
@@ -28,7 +28,7 @@ cmp stdout multiline
 
 
 # 'go get' should omit long messages.
-go get -d example.com/retract/rationale@v1.0.0-long
+go get example.com/retract/rationale@v1.0.0-long
 stderr '^go: warning: example.com/retract/rationale@v1.0.0-long: retracted by module author: \(message omitted: too long\)'
 
 # 'go list' should show the full message.
@@ -37,7 +37,7 @@ stdout '^\[lo{500}ng\]$'
 
 
 # 'go get' should omit messages with unprintable characters.
-go get -d example.com/retract/rationale@v1.0.0-unprintable
+go get example.com/retract/rationale@v1.0.0-unprintable
 stderr '^go: warning: example.com/retract/rationale@v1.0.0-unprintable: retracted by module author: \(message omitted: contains non-printable characters\)'
 
 # 'go list' should show the full message.
@@ -61,9 +61,9 @@ go list -m -retracted -f '{{range .Retracted}}{{.}},{{end}}' example.com/retract
 stdout '^single version,degenerate range,$'
 
 # 'go get' will only report the first retraction to avoid being too verbose.
-go get -d example.com/retract/rationale@v1.0.0-order
+go get example.com/retract/rationale@v1.0.0-order
 stderr '^go: warning: example.com/retract/rationale@v1.0.0-order: retracted by module author: degenerate range$'
-go get -d example.com/retract/rationale@v1.0.1-order
+go get example.com/retract/rationale@v1.0.1-order
 stderr '^go: warning: example.com/retract/rationale@v1.0.1-order: retracted by module author: single version$'
 
 -- go.mod --
index f54742c5232253b6d4f44927fab010f5770d24a7..38986f333f6474e4ac456162b693224c11f1255d 100644 (file)
@@ -1,5 +1,5 @@
 # Populate go.sum.
-go get -d
+go get
 
 # 'go list -m -retracted' should load retractions, even if the version
 # containing retractions has a different module path.
@@ -9,11 +9,11 @@ go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retra
 go list -m -u -f '{{with .Retracted}}retracted{{end}}' example.com/retract/rename
 
 # 'go get' should warn about the retracted version.
-go get -d
+go get
 stderr '^go: warning: example.com/retract/rename@v1.0.0-bad: retracted by module author: bad$'
 
 # We can't upgrade, since this latest version has a different module path.
-! go get -d example.com/retract/rename
+! go get example.com/retract/rename
 stderr 'module declares its path as: example.com/retract/newname'
 
 -- go.mod --
index 9cd714739abf556dc8818d3ef6f9c93f0a68e66e..788968f420ec54a10cfc302bca1d9938cb7c4169 100644 (file)
@@ -2,7 +2,7 @@
 # obtain retractions from the replacement.
 
 # Populate go.sum.
-go get -d
+go get
 
 # The latest version, v1.9.0, is not available on the proxy.
 go list -m -retracted example.com/retract/missingmod
index 036755d2d1ac2781df0d92185f59975520d93328..8435fc05b496365dcc1b6ebbd97bed7b11c57ac5 100644 (file)
@@ -7,7 +7,7 @@ stderr '^package example.net/nonmain is not a main package$'
 
 ! go run ./...
 stderr '^go: warning: "\./\.\.\." matched only non-main packages$'
-stderr '^go run: no packages loaded from \./\.\.\.$'
+stderr '^go: no packages loaded from \./\.\.\.$'
 
 -- go.mod --
 module example.net/nonmain
index e921fab508540433d4c240af4bfb68346e53b03b..c3a218d553d5ca19f8f8556d5f3ce71e9148b5d2 100644 (file)
@@ -21,7 +21,7 @@ env GO111MODULE=on
 cd m
 cp go.mod go.mod.orig
 ! go list -m all
-stderr '^go list -m: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
+stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
 go run example.com/cmd/a@v1.0.0
 stdout '^a@v1.0.0$'
 cmp go.mod go.mod.orig
@@ -92,12 +92,12 @@ package main
 
 func main() {}
 -- replace-err --
-go run: example.com/cmd/a@v1.0.0-replace (in example.com/cmd@v1.0.0-replace):
+go: example.com/cmd/a@v1.0.0-replace (in example.com/cmd@v1.0.0-replace):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.
 -- exclude-err --
-go run: example.com/cmd/a@v1.0.0-exclude (in example.com/cmd@v1.0.0-exclude):
+go: example.com/cmd/a@v1.0.0-exclude (in example.com/cmd@v1.0.0-exclude):
        The go.mod file for the module providing named packages contains one or
        more exclude directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.
diff --git a/src/cmd/go/testdata/script/mod_skip_write.txt b/src/cmd/go/testdata/script/mod_skip_write.txt
new file mode 100644 (file)
index 0000000..9fdb6fc
--- /dev/null
@@ -0,0 +1,92 @@
+# Commands used to debug the module graph should not write go.mod or go.sum
+# or report errors when those files need to be updated.
+
+# Everything's okay initially.
+go list -m all
+
+# Downgrading sampler makes go.mod inconsistent, but 'go mod graph',
+# 'go mod verify', and 'go mod why' still work.
+cp go.mod go.mod.orig
+go mod edit -require=rsc.io/sampler@v1.2.0
+cp go.mod go.mod.edit
+! go list -m all
+stderr 'updates to go.mod needed'
+
+go mod graph
+cmp stdout graph.want
+cmp go.mod go.mod.edit
+
+go mod verify
+stdout '^all modules verified$'
+cmp go.mod go.mod.edit
+
+go mod why rsc.io/sampler
+cmp stdout why.want
+cmp go.mod go.mod.edit
+
+go mod why -m rsc.io/sampler
+cmp stdout why.want
+cmp go.mod go.mod.edit
+
+cp go.mod.orig go.mod
+
+# Removing go.sum breaks other commands, but 'go mod graph' and
+# 'go mod why' still work.
+rm go.sum
+! go list -m all
+stderr 'missing go.sum entry'
+
+go mod graph
+cmp stdout graph.want
+! exists go.sum
+
+go mod verify
+stdout '^all modules verified$'
+! exists go.sum
+
+go mod why rsc.io/sampler
+cmp stdout why.want
+! exists go.sum
+
+go mod why -m rsc.io/sampler
+cmp stdout why.want
+! exists go.sum
+
+-- go.mod --
+module m
+
+go 1.18
+
+require rsc.io/quote v1.5.2
+
+require (
+       golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
+       rsc.io/sampler v1.3.0 // indirect
+       rsc.io/testonly v1.0.0 // indirect
+)
+-- go.sum --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.2.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64=
+rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY=
+-- use.go --
+package use
+
+import _ "rsc.io/quote"
+-- graph.want --
+m golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
+m rsc.io/quote@v1.5.2
+m rsc.io/sampler@v1.3.0
+m rsc.io/testonly@v1.0.0
+rsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0
+rsc.io/sampler@v1.3.0 golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
+-- why.want --
+# rsc.io/sampler
+m
+rsc.io/quote
+rsc.io/sampler
index e021921380068778b5befe82ea0d6ba35368fdcb..7513f7f49f352ee9e7af699d358db364999404da 100644 (file)
@@ -8,7 +8,7 @@ go list -e -mod=mod -tags=ignore ./noexist
 # When an import is resolved successfully, we should only save hashes for
 # the module that provides the package, not for other modules looked up.
 # Verifies golang.org/issue/31580.
-go get -d ./exist
+go get ./exist
 grep '^example.com/join v1.1.0 h1:' go.sum
 ! grep '^example.com/join/subpkg' go.sum
 cp go.sum go.list.sum
index 113f13ea390852c5138afc1df78dd6794ca0fa1f..57c5bbeefdf0203c43f28b50d8294500b6dff7a7 100644 (file)
@@ -4,7 +4,7 @@ env GO111MODULE=on
 # When a sum is needed to load the build list, we get an error for the
 # specific module. The .mod file is not downloaded, and go.sum is not written.
 ! go list -m all
-stderr '^go list -m: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
+stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
 ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
 ! exists go.sum
 
@@ -12,7 +12,7 @@ stderr '^go list -m: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo
 # we should see the same error.
 cp go.sum.h2only go.sum
 ! go list -m all
-stderr '^go list -m: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
+stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
 ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
 cmp go.sum go.sum.h2only
 rm go.sum
@@ -21,7 +21,7 @@ rm go.sum
 cp go.mod go.mod.orig
 go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
 ! go list -m all
-stderr '^go list -m: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
+stderr '^go: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
 ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.mod
 ! exists go.sum
 cp go.mod.orig go.mod
index b03982d9cff442648606cd83886c6c936a82b6c0..6c322a00d607a95a0ea04c8972cd5beb4a3f590c 100644 (file)
@@ -1,7 +1,7 @@
 env GO111MODULE=on
 
-# After 'go get -d', the go.sum file should contain the sum for the module.
-go get -d rsc.io/quote@v1.5.0
+# After 'go get', the go.sum file should contain the sum for the module.
+go get rsc.io/quote@v1.5.0
 grep 'rsc.io/quote v1.5.0' go.sum
 
 # If we replace the module and run 'go mod tidy', we should get a sum for the replacement.
index fa3483c5cb1a510b9d5c19cbf16c4bdf116f155d..d06db4ae69271a53849b8a0cbfbe1a205a7f02f1 100644 (file)
@@ -8,13 +8,13 @@ env dbname=localhost.localdev/sumdb
 # (this also populates tiles on the sumdb server).
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb' '$proxy/sumdb-wrong
-! go get -d rsc.io/quote
-stderr 'go get: rsc.io/quote@v1.5.2: verifying module: checksum mismatch'
+! go get rsc.io/quote
+stderr 'go: rsc.io/quote@v1.5.2: verifying module: checksum mismatch'
 stderr 'downloaded: h1:3fEy'
 stderr 'localhost.localdev/sumdb: h1:wrong'
 stderr 'SECURITY ERROR\nThis download does NOT match the one reported by the checksum server.'
-! go get -d rsc.io/sampler
-! go get -d golang.org/x/text
+! go get rsc.io/sampler
+! go get golang.org/x/text
 
 go mod edit -require rsc.io/quote@v1.5.2
 ! go mod tidy
@@ -26,14 +26,14 @@ rm go.sum
 # switching to truthful sumdb detects timeline inconsistency
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb
-! go get -d rsc.io/fortune
+! go get rsc.io/fortune
 stderr 'SECURITY ERROR\ngo.sum database server misbehavior detected!'
 stderr 'proof of misbehavior:'
 
 # removing the cached wrong tree head and cached tiles clears the bad data
 rm $GOPATH/pkg/sumdb/$dbname/latest
 go clean -modcache
-go get -d rsc.io/fortune
+go get rsc.io/fortune
 
 -- go.mod.orig --
 module m
index 1b38475fb5e378c0e1d4fbb88ec266bba83fe90b..063fd20964fde230070699433e4d8ae577f7d65f 100644 (file)
@@ -7,40 +7,40 @@ env GOPROXY GONOPROXY GOSUMDB GONOSUMDB
 cp go.mod.orig go.mod
 rm go.sum
 env GOPROXY=$proxy/sumdb-503
-! go get -d rsc.io/quote
+! go get rsc.io/quote
 stderr 503
 
 # fetch through working proxy is OK
 cp go.mod.orig go.mod
 rm go.sum
 env GOPROXY=$proxy
-go get -d rsc.io/quote
+go get rsc.io/quote
 
 # repeated fetch works entirely from cache, does not consult sumdb
 cp go.mod.orig go.mod
 rm go.sum
 env GOPROXY=$proxy/sumdb-503
-go get -d rsc.io/quote
+go get rsc.io/quote
 rm go.sum
 
 # fetch specific module can work without proxy, using cache or go.sum
 cp go.mod.orig go.mod
 rm go.sum
 env GOPROXY=off
-go get -d rsc.io/quote@v1.5.2 # using cache
+go get rsc.io/quote@v1.5.2 # using cache
 rm $GOPATH/pkg/mod/cache/download/sumdb/localhost.localdev/sumdb/lookup/rsc.io/quote@v1.5.2
-go get -d rsc.io/quote@v1.5.2 # using go.sum
+go get rsc.io/quote@v1.5.2 # using go.sum
 
 # fetch fails once we lose access to both cache and go.sum
 rm go.sum
 env GOPROXY=$proxy/sumdb-504
-! go get -d rsc.io/quote@v1.5.2
+! go get rsc.io/quote@v1.5.2
 stderr 504
 
 # GOINSECURE does not bypass checksum lookup
 env GOINSECURE=rsc.io
 env GOPROXY=$proxy/sumdb-504
-! go get -d rsc.io/quote@v1.5.2
+! go get rsc.io/quote@v1.5.2
 stderr 504
 
 -- go.mod.orig --
index 22fcbf3de84a71f92d3ebbd83aa56377d9485f0f..a834c4800dcf5fa352fff8a1f35797a865a367d9 100644 (file)
@@ -12,15 +12,15 @@ env GOPATH=$WORK/gopath1
 # It comes from the sumweb package, which isn't yet producing structured errors.
 [windows] env GOPROXY=file:///$WORK/sumproxy,https://proxy.golang.org
 [!windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org
-! go get -d golang.org/x/text@v0.3.2
-stderr '^go get: golang.org/x/text@v0.3.2: verifying module: golang.org/x/text@v0.3.2: reading file://.*/sumdb/sum.golang.org/lookup/golang.org/x/text@v0.3.2: (no such file or directory|.*cannot find the path specified.*)'
+! go get golang.org/x/text@v0.3.2
+stderr '^go: golang.org/x/text@v0.3.2: verifying module: golang.org/x/text@v0.3.2: reading file://.*/sumdb/sum.golang.org/lookup/golang.org/x/text@v0.3.2: (no such file or directory|.*cannot find the path specified.*)'
 
 # If the proxy does not claim to support the database,
 # checksum verification should fall through to the next proxy,
 # and downloading should succeed.
 [windows] env GOPROXY=file:///$WORK/emptyproxy,https://proxy.golang.org
 [!windows] env GOPROXY=file://$WORK/emptyproxy,https://proxy.golang.org
-go get -d golang.org/x/text@v0.3.2
+go get golang.org/x/text@v0.3.2
 
 # After a successful sumdb lookup, the lookup can be repeated
 # using the download cache as a proxy.
@@ -29,7 +29,7 @@ cp supported $GOPATH/pkg/mod/cache/download/sumdb/sum.golang.org/supported
 [!windows] env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download,file://$WORK/sumproxy
 env GOPATH=$WORK/gopath2
 rm go.sum
-go get -d -x -v golang.org/x/text@v0.3.2
+go get -x -v golang.org/x/text@v0.3.2
 
 # Once the checksum is present in the go.sum file,
 # an empty file-based sumdb can be used in conjunction with
@@ -38,10 +38,10 @@ grep golang.org/x/text go.sum
 env GOPATH=$WORK/gopath3
 [windows] env GOPROXY=file:///$WORK/sumproxy
 [!windows] env GOPROXY=file://$WORK/sumproxy
-! go get -d golang.org/x/text@v0.3.2
+! go get golang.org/x/text@v0.3.2
 [windows] env GOPROXY=file:///$WORK/sumproxy,https://proxy.golang.org
 [!windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org
-go get -d golang.org/x/text@v0.3.2
+go get golang.org/x/text@v0.3.2
 
 -- supported --
 
index becd88b52e7cffaa18b94b99a574b84c1ab7df2f..a48a5ba1b048c038c63d79fec29903cba91f99f5 100644 (file)
@@ -16,7 +16,7 @@ stdout '^sum.golang.org$'
 env GOSUMDB=sum.golang.org
 env GOPROXY=direct
 
-go get -d rsc.io/quote@v1.5.2
+go get rsc.io/quote@v1.5.2
 cp go.sum saved.sum
 
 
index 70b8e3fc4466ffab5676cb06b2aebe8d23aedd39..194c0c92e5705179f7658fd4e1f6f79f9de40c62 100644 (file)
@@ -5,14 +5,14 @@ env GOPROXY GONOPROXY GOSUMDB GONOSUMDB
 
 # basic fetch (through proxy) works
 cp go.mod.orig go.mod
-go get -d rsc.io/fortune@v1.0.0 # note: must use test proxy, does not exist in real world
+go get rsc.io/fortune@v1.0.0 # note: must use test proxy, does not exist in real world
 rm $GOPATH/pkg/mod/cache/download/sumdb # rm sumdb cache but NOT package download cache
 rm go.sum
 
 # can fetch by explicit URL
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb' '$proxy/sumdb-direct
-go get -d rsc.io/fortune@v1.0.0
+go get rsc.io/fortune@v1.0.0
 rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
 
@@ -21,7 +21,7 @@ rm go.sum
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb
 env GOPROXY=direct
-! go get -d rsc.io/fortune@v1.0.0
+! go get rsc.io/fortune@v1.0.0
 stderr 'verifying module: rsc.io/fortune@v1.0.0: .*: no such host localhost.localdev'
 rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
@@ -30,7 +30,7 @@ rm go.sum
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb
 env GOPROXY=$proxy/sumdb-404
-! go get -d rsc.io/fortune@v1.0.0
+! go get rsc.io/fortune@v1.0.0
 stderr 'verifying.*localhost.localdev'
 rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
@@ -39,7 +39,7 @@ rm go.sum
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb
 env GOPROXY=$proxy/sumdb-503
-! go get -d rsc.io/fortune@v1.0.0
+! go get rsc.io/fortune@v1.0.0
 stderr '503 Service Unavailable'
 rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
@@ -48,7 +48,7 @@ rm go.sum
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb
 env GOPROXY=$proxy/sumdb-404,$proxy/sumdb-503
-! go get -d rsc.io/fortune@v1.0.0
+! go get rsc.io/fortune@v1.0.0
 stderr '503 Service Unavailable'
 rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
@@ -57,7 +57,7 @@ rm go.sum
 cp go.mod.orig go.mod
 env GOSUMDB=$sumdb
 env GOPROXY=$proxy/sumdb-503|https://0.0.0.0|$proxy
-go get -d rsc.io/fortune@v1.0.0
+go get rsc.io/fortune@v1.0.0
 rm $GOPATH/pkg/mod/cache/download/sumdb
 rm go.sum
 
index dbc23fb8f0984722e49f24201fbfe6c20ec95978..0604e1a4c4f1c28493c378d707783506282496f9 100644 (file)
@@ -1,12 +1,12 @@
 env GO111MODULE=on
 [!symlink] skip
 
-# 'go get -d' should resolve modules of imported packages.
-go get -d
+# 'go get' should resolve modules of imported packages.
+go get
 go list -deps -f '{{.Module}}' .
 stdout golang.org/x/text
 
-go get -d ./subpkg
+go get ./subpkg
 go list -deps -f '{{.Module}}' ./subpkg
 stdout golang.org/x/text
 
index e6edef5ee3b78c83a59063f990bf4527f2493b99..18b297da60e1a2cb5d3b1ed1a6866f073947d539 100644 (file)
@@ -20,7 +20,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
 # + ---- example.net/lazy v0.1.0 ---- example.com/version v1.0.1
 #
 # Go 1.17 avoids loading the go.mod file for example.com/version v1.0.1
-# (because it is lower than the verison explicitly required by m,
+# (because it is lower than the version explicitly required by m,
 # and the module that requires it — m — specifies 'go 1.17').
 #
 # That go.mod file happens not to affect the final 1.16 module graph anyway,
@@ -50,7 +50,7 @@ cmp stdout m_all.txt
 
 go mod edit -go=1.16
 ! go list -m all
-stderr '^go list -m: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry; to add it:\n\tgo mod download example.com/version$'
+stderr '^go: example.net/lazy@v0.1.0 requires\n\texample.com/version@v1.0.1: missing go.sum entry; to add it:\n\tgo mod download example.com/version$'
 
 
 -- go.mod --
index c544cb7413fcdc6b4f791d98429fd7c8e3bc7feb..a45de5ad8cdcb8133d9bca070be5168707a31ba9 100644 (file)
@@ -62,7 +62,7 @@ cmp stdout all-m.txt
 
 go mod edit -go=1.16
 ! go list -m all
-stderr '^go list -m: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.net/ambiguous\n'
+stderr '^go: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.net/ambiguous\n'
 
 
 -- go.mod --
@@ -72,10 +72,9 @@ go 1.17
 
 replace example.net/indirect v0.1.0 => ./indirect
 
-require (
-       example.net/ambiguous/nested v0.1.0 // indirect
-       example.net/indirect v0.1.0
-)
+require example.net/indirect v0.1.0
+
+require example.net/ambiguous/nested v0.1.0 // indirect
 -- all-m.txt --
 example.com/m
 example.net/ambiguous v0.1.0
index ea9e42e87e20fc57b7e14164f9f606954ccad269..11313f144c3a340f35da2cb037d3512ee39680dd 100644 (file)
@@ -97,10 +97,9 @@ replace (
        example.net/requireincompatible v0.1.0 => ./requireincompatible
 )
 
-require (
-       example.com/retract/incompatible v1.0.0 // indirect
-       example.net/lazy v0.1.0
-)
+require example.net/lazy v0.1.0
+
+require example.com/retract/incompatible v1.0.0 // indirect
 -- incompatible.go --
 package incompatible
 
index 09c46f764bf06fd434f80454fa15f6eb2f2f53af..be0a8e9b8c591444fa32c586061d58f96407ba62 100644 (file)
@@ -79,7 +79,7 @@ cmp go.mod go.mod.tidye
 # succeed and remain stable. y.1 does not upgrade x, and can therefore be used
 # with it.
 
-go get -d example.net/x@v0.1.0 example.net/y@v0.1.0
+go get example.net/x@v0.1.0 example.net/y@v0.1.0
 go mod tidy
 cmp go.mod go.mod.postget
 
@@ -96,7 +96,7 @@ cmp go.mod go.mod.tidye
 stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
 stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
 
-go get -d example.net/x@v0.1.0 example.net/y@v0.1.0
+go get example.net/x@v0.1.0 example.net/y@v0.1.0
 go mod tidy
 cmp go.mod go.mod.postget-117
 
index 3c4d3244d5daa4e5ba92d4df0ba512473a19d42e..99599e551a1d6c21b174b79fe6c14707621b3ba0 100644 (file)
@@ -94,7 +94,7 @@ cmp go.mod go.mod.orig
 # packages simultaneously over-upgrades all of the dependencies, and 'go mod
 # tidy' treats "no package can be added" as a terminal state.
 
-go get -d example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
+go get example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
 go mod tidy -e
 cmp go.mod go.mod.postget
 go mod tidy -e
@@ -154,7 +154,7 @@ cmp go.mod go.mod.117
 # As in the eager case, for the lazy module the fully-upgraded dependency graph
 # becomes empty, and the empty graph is stable.
 
-go get -d example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
+go get example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
 go mod tidy -e
 cmp go.mod go.mod.postget
 go mod tidy -e
diff --git a/src/cmd/go/testdata/script/mod_tidy_downgrade_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_downgrade_ambiguous.txt
new file mode 100644 (file)
index 0000000..8b508c7
--- /dev/null
@@ -0,0 +1,58 @@
+# Verifies golang.org/issue/47738.
+
+# In this test, the user has rewritten their imports to use rsc.io/quote/v3,
+# but their go.mod still requires rsc.io/quote@v1.5.2, and they indirectly
+# require rsc.io/quote@v1.5.1 but don't import anything from it.
+go list -m -f '{{.Path}}@{{.Version}}{{if .Indirect}} indirect{{end}}' all
+stdout '^rsc.io/quote@v1.5.2$'
+! stdout 'rsc.io/quote/v3'
+go list -e all
+! stdout '^rsc.io/quote$'
+
+# 'go mod tidy' should preserve the requirement on rsc.io/quote but mark it
+# indirect. This prevents a downgrade to v1.5.1, which could introduce
+# an ambiguity.
+go mod tidy
+go list -m -f '{{.Path}}@{{.Version}}{{if .Indirect}} indirect{{end}}' all
+stdout '^rsc.io/quote@v1.5.2 indirect$'
+stdout '^rsc.io/quote/v3@v3.0.0$'
+
+-- go.mod --
+module use
+
+go 1.16
+
+require (
+       old-indirect v0.0.0
+       rsc.io/quote v1.5.2
+)
+
+replace old-indirect v0.0.0 => ./old-indirect
+-- go.sum --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.1/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- use.go --
+package use
+
+import (
+       _ "old-indirect/empty"
+
+       _ "rsc.io/quote/v3"
+)
+-- old-indirect/empty/empty.go --
+package empty
+-- old-indirect/go.mod --
+module old-indirect
+
+go 1.16
+
+require rsc.io/quote v1.5.1
+-- old-indirect/go.sum --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
index 297f6a6a45c872da732b127e8a4cb8d376b3ba68..274f3bf5090f633bde9680ee2efca1819867772f 100644 (file)
@@ -35,7 +35,7 @@ grep 'golang.org/x/text' go.mod
 # 'go get' and 'go mod tidy' should follow the requirements of the replacements,
 # not the originals, even if that results in a set of versions that are
 # misleading or redundant without those replacements.
-go get -d rsc.io/sampler@v1.2.0
+go get rsc.io/sampler@v1.2.0
 go mod tidy
 go list -m all
 stdout 'rsc.io/quote/v3 v3.0.0'
index c583f560586970c6741fc3d975da15ddb5384b9d..5a15818543ef2c4318d4f059624001ebc7d273df 100644 (file)
@@ -1,12 +1,12 @@
 env GO111MODULE=on
 
 # go.sum should list directly used modules and dependencies
-go get -d rsc.io/quote@v1.5.2
+go get rsc.io/quote@v1.5.2
 go mod tidy
 grep rsc.io/sampler go.sum
 
 # go.sum should not normally lose old entries
-go get -d rsc.io/quote@v1.0.0
+go get rsc.io/quote@v1.0.0
 grep 'rsc.io/quote v1.0.0' go.sum
 grep 'rsc.io/quote v1.5.2' go.sum
 grep rsc.io/sampler go.sum
index b9c53b510daeb06c5d91e8fb2c720d5dd89b12ca..8c34a997c956a5642d24e69fd76095d36ab0419f 100644 (file)
@@ -9,7 +9,7 @@ cp go.mod go.mod.orig
 # would look like.
 
 ! go mod tidy
-stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$'
+stderr 'go: go.mod file indicates go 2000.0, but maximum version supported by tidy is '$goversion'$'
 cmp go.mod go.mod.orig
 
 
@@ -18,7 +18,7 @@ cmp go.mod go.mod.orig
 
 cp go.mod.orig go.mod
 go mod tidy -e
-stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$'
+stderr 'go: go.mod file indicates go 2000.0, but maximum version supported by tidy is '$goversion'$'
 cmp go.mod go.mod.tidy
 
 
index 8b34f8bf27dfc66070075e4efe2efe78fa2e20ad..79a9808ef03796037489e0e44b17a70db4381b54 100644 (file)
@@ -2,7 +2,7 @@ env GO111MODULE=on
 [short] skip
 
 # Initially, we are at v1.0.0 for all dependencies.
-go get -d
+go get
 cp go.mod go.mod.orig
 go list -m all
 stdout '^patch.example.com/direct v1.0.0'
@@ -10,15 +10,15 @@ stdout '^patch.example.com/indirect v1.0.0'
 ! stdout '^patch.example.com/depofdirectpatch'
 
 # @patch should be rejected for modules not already in the build list.
-! go get -d patch.example.com/depofdirectpatch@patch
-stderr '^go get: can''t query version "patch" of module patch.example.com/depofdirectpatch: no existing version is required$'
+! go get patch.example.com/depofdirectpatch@patch
+stderr '^go: can''t query version "patch" of module patch.example.com/depofdirectpatch: no existing version is required$'
 cmp go.mod.orig go.mod
 
 # get -u=patch, with no arguments, should patch-update all dependencies
 # of the package in the current directory, pulling in transitive dependencies
 # and also patching those.
 cp go.mod.orig go.mod
-go get -d -u=patch
+go get -u=patch
 go list -m all
 stdout '^patch.example.com/direct v1.0.1'
 stdout '^patch.example.com/indirect v1.0.1'
@@ -26,7 +26,7 @@ stdout '^patch.example.com/depofdirectpatch v1.0.0'
 
 # 'get all@patch' should patch the modules that provide packages in 'all'.
 cp go.mod.orig go.mod
-go get -d all@patch
+go get all@patch
 go list -m all
 stdout '^patch.example.com/direct v1.0.1'
 stdout '^patch.example.com/indirect v1.0.1'
@@ -37,14 +37,14 @@ stdout '^patch.example.com/depofdirectpatch v1.0.0'
 cp go.mod.orig go.mod
 go mod edit -droprequire=patch.example.com/direct
 cp go.mod go.mod.dropped
-! go get -d all@patch
-stderr '^go get all@patch: can''t query version "patch" of module patch.example.com/direct: no existing version is required$'
+! go get all@patch
+stderr '^go: all@patch: can''t query version "patch" of module patch.example.com/direct: no existing version is required$'
 cmp go.mod.dropped go.mod
 
 # Requesting the direct dependency with -u=patch but without an explicit version
 # should patch-update it and its dependencies.
 cp go.mod.orig go.mod
-go get -d -u=patch patch.example.com/direct
+go get -u=patch patch.example.com/direct
 go list -m all
 stdout '^patch.example.com/direct v1.0.1'
 stdout '^patch.example.com/indirect v1.0.1'
@@ -52,7 +52,7 @@ stdout '^patch.example.com/depofdirectpatch v1.0.0'
 
 # Requesting only the indirect dependency should not update the direct one.
 cp go.mod.orig go.mod
-go get -d -u=patch patch.example.com/indirect
+go get -u=patch patch.example.com/indirect
 go list -m all
 stdout '^patch.example.com/direct v1.0.0'
 stdout '^patch.example.com/indirect v1.0.1'
@@ -61,7 +61,7 @@ stdout '^patch.example.com/indirect v1.0.1'
 # @patch should apply only to the specific module,
 # but the result must reflect its upgraded requirements.
 cp go.mod.orig go.mod
-go get -d patch.example.com/direct@patch
+go get patch.example.com/direct@patch
 go list -m all
 stdout '^patch.example.com/direct v1.0.1'
 stdout '^patch.example.com/indirect v1.0.0'
@@ -69,7 +69,7 @@ stdout '^patch.example.com/depofdirectpatch v1.0.0'
 
 # An explicit @patch should override a general -u.
 cp go.mod.orig go.mod
-go get -d -u patch.example.com/direct@patch
+go get -u patch.example.com/direct@patch
 go list -m all
 stdout '^patch.example.com/direct v1.0.1'
 stdout '^patch.example.com/indirect v1.1.0'
@@ -77,7 +77,7 @@ stdout '^patch.example.com/depofdirectpatch v1.0.0'
 
 # An explicit @latest should override a general -u=patch.
 cp go.mod.orig go.mod
-go get -d -u=patch patch.example.com/direct@latest
+go get -u=patch patch.example.com/direct@latest
 go list -m all
 stdout '^patch.example.com/direct v1.1.0'
 stdout '^patch.example.com/indirect v1.0.1'
@@ -86,16 +86,16 @@ stdout '^patch.example.com/indirect v1.0.1'
 # Standard library packages cannot be upgraded explicitly.
 cp go.mod.orig go.mod
 ! go get cmd/vet@patch
-stderr 'go get: can''t request explicit version "patch" of standard library package cmd/vet$'
+stderr 'go: can''t request explicit version "patch" of standard library package cmd/vet$'
 
 # However, standard-library packages without explicit versions are fine.
-go get -d -u=patch -d cmd/go
+go get -u=patch cmd/go
 
 # We can upgrade to a new version of a module with no root package.
-go get -d example.com/noroot@v1.0.0
+go get example.com/noroot@v1.0.0
 go list -m all
 stdout '^example.com/noroot v1.0.0$'
-go get -d example.com/noroot@patch
+go get example.com/noroot@patch
 go list -m all
 stdout '^example.com/noroot v1.0.1$'
 
index f8be43cf4c6494442cea992819a23f16b42e435c..9e6e371927bef9f83cd31d9247928201c200dcf2 100644 (file)
@@ -5,7 +5,7 @@ env GO111MODULE=on
 env GOPROXY=direct
 
 cd empty
-! go get -d launchpad.net/gocheck
+! go get launchpad.net/gocheck
 stderr '"bzr": executable file not found'
 cd ..
 
index 2622916f614140cf09b49cb4afba4a9655e22609..4eb80c23324c68f7e78cfe09c56e7edec27a4e49 100644 (file)
@@ -40,15 +40,15 @@ stdout '^v1.0.0 $'
 
 # -mod=vendor should cause 'go list' flags that look up versions to fail.
 ! go list -mod=vendor -versions -m x
-stderr '^go list -m: can''t determine available versions using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$'
+stderr '^go: can''t determine available versions using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$'
 ! go list -mod=vendor -u -m x
-stderr '^go list -m: can''t determine available upgrades using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$'
+stderr '^go: can''t determine available upgrades using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$'
 
 # 'go list -mod=vendor -m' on a transitive dependency that does not
 # provide vendored packages should give a helpful error rather than
 # 'not a known dependency'.
 ! go list -mod=vendor -f '{{.Version}} {{.Dir}}' -m diamondright
-stderr 'go list -m: module diamondright: can''t resolve module using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: module diamondright: can''t resolve module using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 
 # 'go list -mod=mod' should report packages outside the import graph,
 # but 'go list -mod=vendor' should error out for them.
index b0ea907206a44902b6001a8df73bd80d283f7893..3cace73a896410595cef799f146de5f09a5ad570 100644 (file)
@@ -17,10 +17,10 @@ stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$'
 stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$'
 
 ! go list -m all
-stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 
 ! go list -m -f '{{.Dir}}' all
-stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 
 # An explicit -mod=mod should force the vendor directory to be ignored.
 env GOFLAGS=-mod=mod
@@ -105,10 +105,10 @@ stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$'
 # ...but 'go list -m' should continue to fail, this time without
 # referring to a -mod default that the user didn't set.
 ! go list -m all
-stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 
 ! go list -m -f '{{.Dir}}' all
-stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
+stderr 'go: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)'
 
 
 # 'go mod init' should work if there is already a GOPATH-mode vendor directory
@@ -177,7 +177,7 @@ stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$'
 
 # 'go get' should update from the network or module cache,
 # even if a vendor directory is present.
-go get -d example.com/version@v1.1.0
+go get example.com/version@v1.1.0
 ! go list -f {{.Dir}} -tags tools all
 stderr '^go: inconsistent vendoring'
 
index 3b8eec0119b3fd64c23cfd346aab5ecfe2d63b6d..4efda55e08f10fb391c12324bbd2e52813be9f2b 100644 (file)
@@ -10,7 +10,7 @@ stdout rsc.io/sampler
 ! grep 'rsc.io/sampler v1.3.0' go.mod
 
 # update to v1.3.1, now indirect in go.mod.
-go get -d rsc.io/sampler@v1.3.1
+go get rsc.io/sampler@v1.3.1
 grep 'rsc.io/sampler v1.3.1 // indirect' go.mod
 cp go.mod go.mod.good
 
index be114159a1fbf7475fc1fba69ff18bae2e7ac0a1..b14fd9915646f38ac0db6239f2740fb0f8b1cbb4 100644 (file)
@@ -6,11 +6,11 @@ cmp vendor/example.com/a/subdir/test/xtest/embed.txt a/subdir/test/xtest/embed.t
 
 cd broken_no_matching_files
 ! go mod vendor
-stderr 'go mod vendor: pattern foo.txt: no matching files found'
+stderr 'go: pattern foo.txt: no matching files found'
 
 cd ../broken_bad_pattern
 ! go mod vendor
-stderr 'go mod vendor: pattern ../foo.txt: invalid pattern syntax'
+stderr 'go: pattern ../foo.txt: invalid pattern syntax'
 
 # matchPotentialSourceFile prunes out tests and unbuilt code.
 # Make sure that they are vendored if they are embedded files.
index aa4cb41171a5199aaf94fd8566d050798ec31fff..a92eb73d274da0bea4c5cc0fe83a8e379c800864 100644 (file)
@@ -3,7 +3,6 @@
 
 [short] skip
 
-
 # Control case: without a vendor directory, need117 builds and bad114 doesn't.
 
 go build example.net/need117
@@ -26,7 +25,8 @@ go mod vendor
 
 ! grep 1.17 vendor/modules.txt
 ! go build example.net/need117
-stderr '^vendor[/\\]example\.net[/\\]need117[/\\]need117.go:5:18: .*\n\tconversion of slices to array pointers only supported as of -lang=go1\.17'
+stderr '^vendor[/\\]example\.net[/\\]need117[/\\]need117.go:5:1[89]:'
+stderr 'conversion of slices to array pointers only supported as of -lang=go1\.17'
 
 ! grep 1.13 vendor/modules.txt
 go build example.net/bad114
index f02d15aa28935602bddc0fa8285ded1f0d4b92de..018709e33b42e3032df92363bad95d0296ef85ef 100644 (file)
@@ -54,7 +54,7 @@ go mod verify
 # Packages below module root should not be mentioned in go.sum.
 rm go.sum
 go mod edit -droprequire rsc.io/quote
-go get -d rsc.io/quote/buggy
+go get rsc.io/quote/buggy
 grep '^rsc.io/quote v1.5.2/go.mod ' go.sum
 ! grep buggy go.sum
 
index baf25d31b89b5dd69d1fedd2655e6ce8c5ed9a88..398e523a9ceb65b5438bbc8cd04c9ae4a0c1387c 100644 (file)
@@ -46,7 +46,7 @@ go list -mod=mod .
 grep rsc.io/quote go.alt.mod
 go build -n -mod=mod .
 go test -n -mod=mod .
-go get -d rsc.io/quote
+go get rsc.io/quote
 
 
 # 'go mod vendor' should work.
@@ -78,7 +78,7 @@ cmp go.mod go.mod.orig
 cmp go.sum go.sum.orig
 
 
-# If the altnernate mod file does not have a ".mod" suffix, an error
+# If the alternate mod file does not have a ".mod" suffix, an error
 # should be reported.
 cp go.alt.mod goaltmod
 ! go mod tidy -modfile=goaltmod
index 538a6ac6f39cc803b2740d35e32428b6ceb8c09f..bd5cfbe3fb272cb8e0095375f9fcd9be42439666 100644 (file)
@@ -1,11 +1,21 @@
 cd rundir
 
 ! go run x.go sub/sub.go
-stderr 'named files must all be in one directory; have ./ and sub/'
+stderr 'named files must all be in one directory; have . and sub'
 ! go run sub/sub.go x.go
-stderr 'named files must all be in one directory; have sub/ and ./'
+stderr 'named files must all be in one directory; have sub and .'
+
+cd ../
+go run rundir/foo.go ./rundir/bar.go
+stderr 'hello world'
 
 -- rundir/sub/sub.go --
 package main
 -- rundir/x.go --
 package main
+-- rundir/foo.go --
+package main
+func main() { println(msg) }
+-- rundir/bar.go --
+package main
+const msg = "hello world"
index 72036d1d8dbdc7469dfac3db4d9aa3a0e57ab282..3e7e7b7e42f3066f4328677f6466e4059629f04b 100644 (file)
@@ -4,4 +4,4 @@ env GO111MODULE=off
 # go run x/... should not panic when directory x doesn't exist.
 
 ! go run nonexistent/...
-stderr '^go run: no packages loaded from nonexistent/...$'
+stderr '^go: no packages loaded from nonexistent/...$'
diff --git a/src/cmd/go/testdata/script/test_benchmark_1x.txt b/src/cmd/go/testdata/script/test_benchmark_1x.txt
new file mode 100644 (file)
index 0000000..b1d4c39
--- /dev/null
@@ -0,0 +1,37 @@
+# Test that -benchtime 1x only runs a total of 1 loop iteration.
+# See golang.org/issue/32051.
+
+go test -run ^$ -bench . -benchtime 1x
+
+-- go.mod --
+module bench
+
+go 1.16
+-- x_test.go --
+package bench
+
+import (
+       "fmt"
+       "os"
+       "testing"
+)
+
+var called = false
+
+func TestMain(m *testing.M) {
+       m.Run()
+       if !called {
+               fmt.Println("benchmark never called")
+               os.Exit(1)
+       }
+}
+
+func Benchmark(b *testing.B) {
+       if b.N > 1 {
+               b.Fatalf("called with b.N=%d; want b.N=1 only", b.N)
+       }
+       if called {
+               b.Fatal("called twice")
+       }
+       called = true
+}
index d694a30994710e70145469998b3fd086b5f2964f..3705c700d10bc905f7cfdd63657a1ca7e3dbe1f0 100644 (file)
@@ -108,6 +108,12 @@ go test testcache -run=Benchtime -bench=Benchtime -benchtime=1x
 go test testcache -run=Benchtime -bench=Benchtime -benchtime=1x
 ! stdout '\(cached\)'
 
+# golang.org/issue/47355: that includes the `-failfast` argument.
+go test testcache -run=TestOSArgs -failfast
+! stdout '\(cached\)'
+go test testcache -run=TestOSArgs -failfast
+stdout '\(cached\)'
+
 # Executables within GOROOT and GOPATH should affect caching,
 # even if the test does not stat them explicitly.
 
diff --git a/src/cmd/go/testdata/script/test_fail_newline.txt b/src/cmd/go/testdata/script/test_fail_newline.txt
new file mode 100644 (file)
index 0000000..43cee56
--- /dev/null
@@ -0,0 +1,65 @@
+[short] skip
+
+# In package list mode, output is buffered.
+# Check that a newline is printed after the buffer's contents.
+cd fail
+! go test .
+! stderr .
+stdout '^exitcode=1\n'
+stdout '^FAIL\s+example/fail'
+
+# In local directory mode output is streamed, so we don't know
+# whether the test printed anything at all, so we print the exit code
+# (just in case it failed without emitting any output at all),
+# and that happens to add the needed newline as well.
+! go test
+! stderr .
+stdout '^exitcode=1exit status 1\n'
+stdout '^FAIL\s+example/fail'
+
+# In package list mode, if the test passes the 'ok' message appears
+# on its own line.
+cd ../skip
+go test -v .
+! stderr .
+stdout '^skipping\n'
+stdout '^ok\s+example/skip'
+
+# If the output is streamed and the test passes, we can't tell whether it ended
+# in a partial line, and don't want to emit any extra output in the
+# overwhelmingly common case that it did not.
+# (In theory we could hook the 'os' package to report whether output
+# was emitted and whether it ended in a newline, but that seems too invasive.)
+go test
+! stderr .
+stdout '^skippingok\s+example/skip'
+
+
+-- go.mod --
+module example
+
+go 1.18
+-- fail/fail_test.go --
+package fail
+
+import (
+       "os"
+       "testing"
+)
+
+func TestMain(m *testing.M) {
+       os.Stderr.WriteString("exitcode=1")
+       os.Exit(1)
+}
+-- skip/skip_test.go --
+package skip
+
+import (
+       "os"
+       "testing"
+)
+
+func TestMain(m *testing.M) {
+       os.Stderr.WriteString("skipping")
+       os.Exit(0)
+}
index 0142b3f308f3b28005cb05f39819ca7073fa2a67..d168cfe6a8c882b5fb7b1b50347f852f35acb848 100644 (file)
@@ -9,13 +9,13 @@ go test -count=1 -custom -args -v=7
 # However, it should be an error to use custom flags when -i or -c are used,
 # since we know for sure that no test binary will run at all.
 ! go test -i -custom
-stderr '^go test: unknown flag -custom cannot be used with -i$'
+stderr '^go: unknown flag -custom cannot be used with -i$'
 ! go test -c -custom
-stderr '^go test: unknown flag -custom cannot be used with -c$'
+stderr '^go: unknown flag -custom cannot be used with -c$'
 
 # The same should apply even if -c or -i come after a custom flag.
 ! go test -custom -c
-stderr '^go test: unknown flag -custom cannot be used with -c$'
+stderr '^go: unknown flag -custom cannot be used with -c$'
 
 -- go.mod --
 module m
diff --git a/src/cmd/go/testdata/script/test_fuzz.txt b/src/cmd/go/testdata/script/test_fuzz.txt
new file mode 100644 (file)
index 0000000..150491b
--- /dev/null
@@ -0,0 +1,498 @@
+[!fuzz] skip
+
+# Test that running a fuzz target that returns without failing or calling
+# f.Fuzz fails and causes a non-zero exit status.
+! go test noop_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that fuzzing a fuzz target that returns without failing or calling
+# f.Fuzz fails and causes a non-zero exit status.
+! go test -fuzz=Fuzz -fuzztime=1x noop_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that calling f.Error in a fuzz target causes a non-zero exit status.
+! go test -fuzz=Fuzz -fuzztime=1x error_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that calling f.Fatal in a fuzz target causes a non-zero exit status.
+! go test fatal_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that successful test exits cleanly.
+go test success_fuzz_test.go
+stdout ^ok
+! stdout FAIL
+
+# Test that successful fuzzing exits cleanly.
+go test -fuzz=Fuzz -fuzztime=1x success_fuzz_test.go
+stdout ok
+! stdout FAIL
+
+# Test that calling f.Fatal while fuzzing causes a non-zero exit status.
+! go test -fuzz=Fuzz -fuzztime=1x fatal_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test error with seed corpus in f.Fuzz
+! go test -run FuzzError fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'error here'
+
+[short] stop
+
+# Test that calling panic(nil) in a fuzz target causes a non-zero exit status.
+! go test panic_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that skipped test exits cleanly.
+go test skipped_fuzz_test.go
+stdout ok
+! stdout FAIL
+
+# Test that f.Fatal within f.Fuzz panics
+! go test fatal_fuzz_fn_fuzz_test.go
+! stdout ^ok
+! stdout 'fatal here'
+stdout FAIL
+stdout 'f.Fuzz function'
+
+# Test that f.Error within f.Fuzz panics
+! go test error_fuzz_fn_fuzz_test.go
+! stdout ^ok
+! stdout 'error here'
+stdout FAIL
+stdout 'f.Fuzz function'
+
+# Test that f.Fail within f.Fuzz panics
+! go test fail_fuzz_fn_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'f.Fuzz function'
+
+# Test that f.Skip within f.Fuzz panics
+! go test skip_fuzz_fn_fuzz_test.go
+! stdout ^ok
+! stdout 'skip here'
+stdout FAIL
+stdout 'f.Fuzz function'
+
+# Test that f.Skipped within f.Fuzz panics
+! go test skipped_fuzz_fn_fuzz_test.go
+! stdout ^ok
+! stdout 'f.Skipped is'
+stdout FAIL
+stdout 'f.Fuzz function'
+stdout 't.Skipped is false'
+
+# Test that runtime.Goexit within the fuzz function is an error.
+! go test goexit_fuzz_fn_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that a call to f.Fatal after the Fuzz func is executed.
+! go test fatal_after_fuzz_func_fuzz_test.go
+! stdout ok
+stdout FAIL
+
+# Test that missing *T in f.Fuzz causes a non-zero exit status.
+! go test incomplete_fuzz_call_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that a panic in the Cleanup func is executed.
+! go test cleanup_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'failed some precondition'
+
+# Test success with seed corpus in f.Fuzz
+go test -run FuzzPass fuzz_add_test.go
+stdout ok
+! stdout FAIL
+! stdout 'off by one error'
+
+# Test fatal with seed corpus in f.Fuzz
+! go test -run FuzzFatal fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'fatal here'
+
+# Test panic with seed corpus in f.Fuzz
+! go test -run FuzzPanic fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'off by one error'
+
+# Test panic(nil) with seed corpus in f.Fuzz
+! go test -run FuzzNilPanic fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test panic with unsupported seed corpus
+! go test -run FuzzUnsupported fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test panic with different number of args to f.Add
+! go test -run FuzzAddDifferentNumber fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test panic with different type of args to f.Add
+! go test -run FuzzAddDifferentType fuzz_add_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test that the wrong type given with f.Add will fail.
+! go test -run FuzzWrongType fuzz_add_test.go
+! stdout ^ok
+stdout '\[string int\], want \[\[\]uint8 int8\]'
+stdout FAIL
+
+# Test fatal with testdata seed corpus
+! go test -run FuzzFail corpustesting/fuzz_testdata_corpus_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'fatal here'
+
+# Test pass with testdata seed corpus
+go test -run FuzzPass corpustesting/fuzz_testdata_corpus_test.go
+stdout ok
+! stdout FAIL
+! stdout 'fatal here'
+
+# Test pass with testdata and f.Add seed corpus
+go test -run FuzzPassString corpustesting/fuzz_testdata_corpus_test.go
+stdout ok
+! stdout FAIL
+
+# Fuzzing pass with testdata and f.Add seed corpus (skip running tests first)
+go test -run=None -fuzz=FuzzPassString corpustesting/fuzz_testdata_corpus_test.go -fuzztime=10x
+stdout ok
+! stdout FAIL
+
+# Fuzzing pass with testdata and f.Add seed corpus
+go test -run=FuzzPassString -fuzz=FuzzPassString corpustesting/fuzz_testdata_corpus_test.go -fuzztime=10x
+stdout ok
+! stdout FAIL
+
+# Test panic with malformed seed corpus
+! go test -run FuzzFail corpustesting/fuzz_testdata_corpus_test.go
+! stdout ^ok
+stdout FAIL
+
+# Test pass with file in other nested testdata directory
+go test -run FuzzInNestedDir corpustesting/fuzz_testdata_corpus_test.go
+stdout ok
+! stdout FAIL
+! stdout 'fatal here'
+
+# Test fails with file containing wrong type
+! go test -run FuzzWrongType corpustesting/fuzz_testdata_corpus_test.go
+! stdout ^ok
+stdout FAIL
+
+-- noop_fuzz_test.go --
+package noop_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {}
+
+-- error_fuzz_test.go --
+package error_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Error("error in target")
+}
+
+-- fatal_fuzz_test.go --
+package fatal_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Fatal("fatal in target")
+}
+
+-- panic_fuzz_test.go --
+package panic_fuzz
+
+import "testing"
+
+func FuzzPanic(f *testing.F) {
+    panic(nil)
+}
+
+-- success_fuzz_test.go --
+package success_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Fuzz(func (*testing.T, []byte) {})
+}
+
+-- skipped_fuzz_test.go --
+package skipped_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Skip()
+}
+
+-- fatal_fuzz_fn_fuzz_test.go --
+package fatal_fuzz_fn_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Add([]byte("aa"))
+    f.Fuzz(func(t *testing.T, b []byte) {
+        f.Fatal("fatal here")
+    })
+}
+
+-- error_fuzz_fn_fuzz_test.go --
+package error_fuzz_fn_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Add([]byte("aa"))
+    f.Fuzz(func(t *testing.T, b []byte) {
+        f.Error("error here")
+    })
+}
+
+-- fail_fuzz_fn_fuzz_test.go --
+package skip_fuzz_fn_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Add([]byte("aa"))
+    f.Fuzz(func(t *testing.T, b []byte) {
+        f.Fail()
+    })
+}
+
+-- skip_fuzz_fn_fuzz_test.go --
+package skip_fuzz_fn_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Add([]byte("aa"))
+    f.Fuzz(func(t *testing.T, b []byte) {
+        f.Skip("skip here")
+    })
+}
+
+-- skipped_fuzz_fn_fuzz_test.go --
+package skipped_fuzz_fn_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Add([]byte("aa"))
+    f.Fuzz(func(t *testing.T, b []byte) {
+        t.Logf("t.Skipped is %t\n", t.Skipped())
+        t.Logf("f.Skipped is %t\n", f.Skipped())
+    })
+}
+
+-- goexit_fuzz_fn_fuzz_test.go --
+package goexit_fuzz_fn_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Add([]byte("aa"))
+    f.Fuzz(func(t *testing.T, b []byte) {
+        runtime.Goexit()
+    })
+}
+
+-- fatal_after_fuzz_func_fuzz_test.go --
+package fatal_after_fuzz_func_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Fuzz(func(t *testing.T, b []byte) {
+        // no-op
+    })
+    f.Fatal("this shouldn't be called")
+}
+
+-- incomplete_fuzz_call_fuzz_test.go --
+package incomplete_fuzz_call_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Fuzz(func(b []byte) {
+        // this is missing *testing.T as the first param, so should panic
+    })
+}
+
+-- cleanup_fuzz_test.go --
+package cleanup_fuzz_test
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Cleanup(func() {
+        panic("failed some precondition")
+    })
+    f.Fuzz(func(t *testing.T, b []byte) {
+        // no-op
+    })
+}
+
+-- fuzz_add_test.go --
+package fuzz_add
+
+import "testing"
+
+func add(f *testing.F) {
+    f.Helper()
+    f.Add([]byte("123"))
+    f.Add([]byte("12345"))
+    f.Add([]byte(""))
+}
+
+func FuzzPass(f *testing.F) {
+    add(f)
+    f.Fuzz(func(t *testing.T, b []byte) {
+        if len(b) == -1 {
+            t.Fatal("fatal here") // will not be executed
+        }
+    })
+}
+
+func FuzzError(f *testing.F) {
+    add(f)
+    f.Fuzz(func(t *testing.T, b []byte) {
+        if len(b) == 3 {
+            t.Error("error here")
+        }
+    })
+}
+
+func FuzzFatal(f *testing.F) {
+    add(f)
+    f.Fuzz(func(t *testing.T, b []byte) {
+        if len(b) == 0 {
+            t.Fatal("fatal here")
+        }
+    })
+}
+
+func FuzzPanic(f *testing.F) {
+    add(f)
+    f.Fuzz(func(t *testing.T, b []byte) {
+        if len(b) == 5 {
+            panic("off by one error")
+        }
+    })
+}
+
+func FuzzNilPanic(f *testing.F) {
+    add(f)
+    f.Fuzz(func(t *testing.T, b []byte) {
+        if len(b) == 3 {
+            panic(nil)
+        }
+    })
+}
+
+func FuzzUnsupported(f *testing.F) {
+    m := make(map[string]bool)
+    f.Add(m)
+    f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzAddDifferentNumber(f *testing.F) {
+    f.Add([]byte("a"))
+    f.Add([]byte("a"), []byte("b"))
+    f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzAddDifferentType(f *testing.F) {
+    f.Add(false)
+    f.Add(1234)
+    f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzWrongType(f *testing.F) {
+    f.Add("hello", 50)
+    f.Fuzz(func(*testing.T, []byte, int8) {})
+}
+
+-- corpustesting/fuzz_testdata_corpus_test.go --
+package fuzz_testdata_corpus
+
+import "testing"
+
+func fuzzFn(f *testing.F) {
+    f.Helper()
+    f.Fuzz(func(t *testing.T, b []byte) {
+        if string(b) == "12345" {
+            t.Fatal("fatal here")
+        }
+    })
+}
+
+func FuzzFail(f *testing.F) {
+    fuzzFn(f)
+}
+
+func FuzzPass(f *testing.F) {
+    fuzzFn(f)
+}
+
+func FuzzPassString(f *testing.F) {
+    f.Add("some seed corpus")
+    f.Fuzz(func(*testing.T, string) {})
+}
+
+func FuzzPanic(f *testing.F) {
+    f.Fuzz(func(t *testing.T, b []byte) {})
+}
+
+func FuzzInNestedDir(f *testing.F) {
+    f.Fuzz(func(t *testing.T, b []byte) {})
+}
+
+func FuzzWrongType(f *testing.F) {
+    f.Fuzz(func(t *testing.T, b []byte) {})
+}
+
+-- corpustesting/testdata/fuzz/FuzzFail/1 --
+go test fuzz v1
+[]byte("12345")
+-- corpustesting/testdata/fuzz/FuzzPass/1 --
+go test fuzz v1
+[]byte("00000")
+-- corpustesting/testdata/fuzz/FuzzPassString/1 --
+go test fuzz v1
+string("hello")
+-- corpustesting/testdata/fuzz/FuzzPanic/1 --
+malformed
+-- corpustesting/testdata/fuzz/FuzzInNestedDir/anotherdir/1 --
+go test fuzz v1
+[]byte("12345")
+-- corpustesting/testdata/fuzz/FuzzWrongType/1 --
+go test fuzz v1
+int("00000")
diff --git a/src/cmd/go/testdata/script/test_fuzz_cache.txt b/src/cmd/go/testdata/script/test_fuzz_cache.txt
new file mode 100644 (file)
index 0000000..552966b
--- /dev/null
@@ -0,0 +1,97 @@
+[!fuzz-instrumented] skip
+
+[short] skip
+env GOCACHE=$WORK/cache
+
+# Fuzz cache should not exist after a regular test run.
+go test .
+exists $GOCACHE
+! exists $GOCACHE/fuzz
+
+# Fuzzing should write interesting values to the cache.
+go test -fuzz=FuzzY -fuzztime=100x .
+go run ./contains_files $GOCACHE/fuzz/example.com/y/FuzzY
+
+# 'go clean -cache' should not delete the fuzz cache.
+go clean -cache
+exists $GOCACHE/fuzz
+
+# 'go clean -fuzzcache' should delete the fuzz cache but not the build cache.
+go list -f {{.Stale}} ./empty
+stdout true
+go install ./empty
+go list -f {{.Stale}} ./empty
+stdout false
+go clean -fuzzcache
+! exists $GOCACHE/fuzz
+go list -f {{.Stale}} ./empty
+stdout false
+
+# Fuzzing indicates that one new interesting value was found with an empty
+# corpus, and the total size of the cache is now 1.
+go clean -fuzzcache
+go test -fuzz=FuzzEmpty -fuzztime=10000x .
+stdout 'new interesting: 1'
+stdout 'total: 1'
+
+# Fuzzing again with a small fuzztime does not find any other interesting
+# values but still indicates that the cache size is 1.
+go test -fuzz=FuzzEmpty -fuzztime=2x .
+stdout 'new interesting: 0'
+stdout 'total: 1'
+
+-- go.mod --
+module example.com/y
+
+go 1.16
+-- y_test.go --
+package y
+
+import (
+       "io"
+       "testing"
+)
+
+func FuzzEmpty(f *testing.F) {
+    f.Fuzz(func (*testing.T, []byte) {})
+}
+
+func FuzzY(f *testing.F) {
+       f.Add([]byte("y"))
+       f.Fuzz(func(t *testing.T, b []byte) { Y(io.Discard, b) })
+}
+-- y.go --
+package y
+
+import (
+       "bytes"
+       "io"
+)
+
+func Y(w io.Writer, b []byte) {
+       if !bytes.Equal(b, []byte("y")) {
+               w.Write([]byte("not equal"))
+       }
+}
+-- empty/empty.go --
+package empty
+-- contains_files/contains_files.go --
+package main
+
+import (
+       "fmt"
+       "path/filepath"
+       "io/ioutil"
+       "os"
+)
+
+func main() {
+       infos, err := ioutil.ReadDir(filepath.Clean(os.Args[1]))
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       if len(infos) == 0 {
+               os.Exit(1)
+       }
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_chatty.txt b/src/cmd/go/testdata/script/test_fuzz_chatty.txt
new file mode 100644 (file)
index 0000000..1abcbbd
--- /dev/null
@@ -0,0 +1,104 @@
+[!fuzz] skip
+[short] skip
+
+# Run chatty fuzz targets with an error.
+! go test -v chatty_error_fuzz_test.go
+! stdout '^ok'
+stdout 'FAIL'
+stdout 'error in target'
+
+# Run chatty fuzz targets with a fatal.
+! go test -v chatty_fatal_fuzz_test.go
+! stdout '^ok'
+stdout 'FAIL'
+stdout 'fatal in target'
+
+# Run chatty fuzz target with a panic
+! go test -v chatty_panic_fuzz_test.go
+! stdout ^ok
+stdout FAIL
+stdout 'this is bad'
+
+# Run skipped chatty fuzz targets.
+go test -v chatty_skipped_fuzz_test.go
+stdout ok
+stdout SKIP
+! stdout FAIL
+
+# Run successful chatty fuzz targets.
+go test -v chatty_fuzz_test.go
+stdout ok
+stdout PASS
+stdout 'all good here'
+! stdout FAIL
+
+# Fuzz successful chatty fuzz target that includes a separate unit test.
+go test -v chatty_with_test_fuzz_test.go -fuzz=Fuzz -fuzztime=1x
+stdout ok
+stdout PASS
+! stdout FAIL
+# TODO: It's currently the case that it's logged twice. Fix that, and change
+# this check to verify it.
+stdout 'all good here'
+# Verify that the unit test is only run once.
+! stdout '(?s)logged foo.*logged foo'
+
+-- chatty_error_fuzz_test.go --
+package chatty_error_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Error("error in target")
+}
+
+-- chatty_fatal_fuzz_test.go --
+package chatty_fatal_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Fatal("fatal in target")
+}
+
+-- chatty_panic_fuzz_test.go --
+package chatty_panic_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    panic("this is bad")
+}
+
+-- chatty_skipped_fuzz_test.go --
+package chatty_skipped_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Skip()
+}
+
+-- chatty_fuzz_test.go --
+package chatty_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+    f.Log("all good here")
+    f.Fuzz(func(*testing.T, []byte) {})
+}
+
+-- chatty_with_test_fuzz_test.go --
+package chatty_with_test_fuzz
+
+import "testing"
+
+func TestFoo(t *testing.T) {
+    t.Log("logged foo")
+}
+
+func Fuzz(f *testing.F) {
+    f.Log("all good here")
+    f.Fuzz(func(*testing.T, []byte) {})
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_cleanup.txt b/src/cmd/go/testdata/script/test_fuzz_cleanup.txt
new file mode 100644 (file)
index 0000000..b65022b
--- /dev/null
@@ -0,0 +1,66 @@
+[!fuzz] skip
+[short] skip
+
+# Cleanup should run after F.Skip.
+go test -run=FuzzTargetSkip
+stdout cleanup
+
+# Cleanup should run after F.Fatal.
+! go test -run=FuzzTargetFatal
+stdout cleanup
+
+# Cleanup should run after an unexpected runtime.Goexit.
+! go test -run=FuzzTargetGoexit
+stdout cleanup
+
+# Cleanup should run after panic.
+! go test -run=FuzzTargetPanic
+stdout cleanup
+
+# Cleanup should run in fuzz function on seed corpus.
+go test -v -run=FuzzFunction
+stdout '(?s)inner.*outer'
+
+# TODO(jayconrod): test cleanup while fuzzing. For now, the worker process's
+# stdout and stderr is connected to the coordinator's, but it should eventually
+# be connected to os.DevNull, so we wouldn't see t.Log output.
+
+-- go.mod --
+module cleanup
+
+go 1.15
+-- cleanup_test.go --
+package cleanup
+
+import (
+       "runtime"
+       "testing"
+)
+
+func FuzzTargetSkip(f *testing.F) {
+       f.Cleanup(func() { f.Log("cleanup") })
+       f.Skip()
+}
+
+func FuzzTargetFatal(f *testing.F) {
+       f.Cleanup(func() { f.Log("cleanup") })
+       f.Fatal()
+}
+
+func FuzzTargetGoexit(f *testing.F) {
+       f.Cleanup(func() { f.Log("cleanup") })
+       runtime.Goexit()
+}
+
+func FuzzTargetPanic(f *testing.F) {
+       f.Cleanup(func() { f.Log("cleanup") })
+       panic("oh no")
+}
+
+func FuzzFunction(f *testing.F) {
+       f.Add([]byte{0})
+       f.Cleanup(func() { f.Log("outer") })
+       f.Fuzz(func(t *testing.T, b []byte) {
+               t.Cleanup(func() { t.Logf("inner") })
+       })
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_deadline.txt b/src/cmd/go/testdata/script/test_fuzz_deadline.txt
new file mode 100644 (file)
index 0000000..5ba76a3
--- /dev/null
@@ -0,0 +1,35 @@
+[!fuzz] skip
+[short] skip
+
+# The fuzz function should be able to detect whether -timeout
+# was set with T.Deadline. Note there is no F.Deadline, and
+# there is no timeout while fuzzing, even if -fuzztime is set.
+go test -run=FuzzDeadline -wantdeadline=true # -timeout defaults to 10m
+go test -run=FuzzDeadline -timeout=0 -wantdeadline=false
+! go test -run=FuzzDeadline -timeout=1s -wantdeadline=false
+go test -run=FuzzDeadline -timeout=1s -wantdeadline=true
+go test -fuzz=FuzzDeadline -timeout=0 -fuzztime=1s -wantdeadline=false
+go test -fuzz=FuzzDeadline -timeout=0 -fuzztime=100x -wantdeadline=false
+
+-- go.mod --
+module fuzz
+
+go 1.16
+-- fuzz_deadline_test.go --
+package fuzz_test
+
+import (
+       "flag"
+       "testing"
+)
+
+var wantDeadline = flag.Bool("wantdeadline", false, "whether the test should have a deadline")
+
+func FuzzDeadline(f *testing.F) {
+       f.Add("run once")
+       f.Fuzz(func (t *testing.T, _ string) {
+               if _, hasDeadline := t.Deadline(); hasDeadline != *wantDeadline {
+                       t.Fatalf("function got %v; want %v", hasDeadline, *wantDeadline)
+               }
+       })
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_fuzztime.txt b/src/cmd/go/testdata/script/test_fuzz_fuzztime.txt
new file mode 100644 (file)
index 0000000..56d94a4
--- /dev/null
@@ -0,0 +1,121 @@
+[!fuzz] skip
+[short] skip
+
+# There are no seed values, so 'go test' should finish quickly.
+go test
+
+# Fuzzing should exit 0 after fuzztime, even if timeout is short.
+go test -timeout=3s -fuzz=FuzzFast -fuzztime=5s
+
+# We should see the same behavior when invoking the test binary directly.
+go test -c
+exec ./fuzz.test$GOEXE -test.timeout=3s -test.fuzz=FuzzFast -test.fuzztime=5s -test.parallel=1 -test.fuzzcachedir=$WORK/cache
+
+# Timeout should not cause inputs to be written as crashers.
+! exists testdata/fuzz
+
+env GOCACHE=$WORK/tmp
+
+# When we use fuzztime with an "x" suffix, it runs a specific number of times.
+# This fuzz function creates a file with a unique name ($pid.$count) on each
+# run. We count the files to find the number of runs.
+mkdir count
+go test -fuzz=FuzzTestCount -fuzztime=1000x -fuzzminimizetime=1x
+go run check_file_count.go count 1000
+
+# When we use fuzzminimizetime with an "x" suffix, it runs a specific number of
+# times while minimizing. This fuzz function creates a file with a unique name
+# ($pid.$count) on each run once the first crash has been found. That means that
+# there should be one file for each execution of the fuzz function during
+# minimization, so we count these to determine how many times minimization was
+# run.
+mkdir minimizecount
+! go test -fuzz=FuzzMinimizeCount -fuzzminimizetime=3x -parallel=1
+go run check_file_count.go minimizecount 3
+
+-- go.mod --
+module fuzz
+
+go 1.16
+-- fuzz_fast_test.go --
+package fuzz_test
+
+import "testing"
+
+func FuzzFast(f *testing.F) {
+       f.Fuzz(func (*testing.T, []byte) {})
+}
+-- fuzz_count_test.go --
+package fuzz
+
+import (
+       "fmt"
+       "os"
+       "testing"
+)
+
+func FuzzTestCount(f *testing.F) {
+       pid := os.Getpid()
+       n := 0
+       f.Fuzz(func(t *testing.T, _ []byte) {
+               name := fmt.Sprintf("count/%v.%d", pid, n)
+               if err := os.WriteFile(name, nil, 0666); err != nil {
+                       t.Fatal(err)
+               }
+               n++
+       })
+}
+-- fuzz_minimize_count_test.go --
+package fuzz
+
+import (
+       "bytes"
+       "fmt"
+       "os"
+       "testing"
+)
+
+func FuzzMinimizeCount(f *testing.F) {
+       pid := os.Getpid()
+       n := 0
+       seed := bytes.Repeat([]byte("a"), 357)
+       f.Add(seed)
+       crashFound := false
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if crashFound {
+                       name := fmt.Sprintf("minimizecount/%v.%d", pid, n)
+                       if err := os.WriteFile(name, nil, 0666); err != nil {
+                               t.Fatal(err)
+                       }
+                       n++
+               }
+               if !bytes.Equal(b, seed) {  // this should happen right away
+                       crashFound = true
+                       t.Error("minimize this!")
+               }
+       })
+}
+-- check_file_count.go --
+// +build ignore
+
+package main
+
+import (
+       "fmt"
+       "os"
+       "strconv"
+)
+
+func main() {
+       dir, err := os.ReadDir(os.Args[1])
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       got := len(dir)
+       want, _ := strconv.Atoi(os.Args[2])
+       if got != want {
+               fmt.Fprintf(os.Stderr, "got %d files; want %d\n", got, want)
+               os.Exit(1)
+       }
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_io_error.txt b/src/cmd/go/testdata/script/test_fuzz_io_error.txt
new file mode 100644 (file)
index 0000000..1a0aa64
--- /dev/null
@@ -0,0 +1,101 @@
+# Test that when the coordinator experiences an I/O error communicating
+# with a worker, the coordinator stops the worker and reports the error.
+# The coordinator should not record a crasher.
+#
+# We simulate an I/O error in the test by writing garbage to fuzz_out.
+# This is unlikely, but possible. It's difficult to simulate interruptions
+# due to ^C and EOF errors which are more common. We don't report those.
+[short] skip
+[!fuzz] skip
+
+# If the I/O error occurs before F.Fuzz is called, the coordinator should
+# stop the worker and say that.
+! go test -fuzz=FuzzClosePipeBefore -parallel=1
+stdout '\s*fuzzing process terminated without fuzzing:'
+! stdout 'communicating with fuzzing process'
+! exists testdata
+
+# If the I/O error occurs after F.Fuzz is called (unlikely), just exit.
+# It's hard to distinguish this case from the worker being interrupted by ^C
+# or exiting with status 0 (which it should do when interrupted by ^C).
+! go test -fuzz=FuzzClosePipeAfter -parallel=1
+stdout '^\s*communicating with fuzzing process: invalid character ''!'' looking for beginning of value$'
+! exists testdata
+
+-- go.mod --
+module test
+
+go 1.17
+-- io_error_test.go --
+package io_error
+
+import (
+       "flag"
+       "testing"
+       "time"
+)
+
+func isWorker() bool {
+       f := flag.Lookup("test.fuzzworker")
+       if f == nil {
+               return false
+       }
+       get, ok := f.Value.(flag.Getter)
+       if !ok {
+               return false
+       }
+       return get.Get() == interface{}(true)
+}
+
+func FuzzClosePipeBefore(f *testing.F) {
+       if isWorker() {
+               sendGarbageToCoordinator(f)
+               time.Sleep(3600 * time.Second) // pause until coordinator terminates the process
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzClosePipeAfter(f *testing.F) {
+       f.Fuzz(func(t *testing.T, _ []byte) {
+               if isWorker() {
+                       sendGarbageToCoordinator(t)
+                       time.Sleep(3600 * time.Second) // pause until coordinator terminates the process
+               }
+       })
+}
+-- io_error_windows_test.go --
+package io_error
+
+import (
+       "fmt"
+       "os"
+       "testing"
+)
+
+func sendGarbageToCoordinator(tb testing.TB) {
+       v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES")
+       var fuzzInFD, fuzzOutFD uintptr
+       if _, err := fmt.Sscanf(v, "%x,%x", &fuzzInFD, &fuzzOutFD); err != nil {
+               tb.Fatalf("parsing GO_TEST_FUZZ_WORKER_HANDLES: %v", err)
+       }
+       f := os.NewFile(fuzzOutFD, "fuzz_out")
+       if _, err := f.Write([]byte("!!")); err != nil {
+               tb.Fatalf("writing fuzz_out: %v", err)
+       }
+}
+-- io_error_notwindows_test.go --
+// +build !windows
+
+package io_error
+
+import (
+       "os"
+       "testing"
+)
+
+func sendGarbageToCoordinator(tb testing.TB) {
+       f := os.NewFile(4, "fuzz_out")
+       if _, err := f.Write([]byte("!!")); err != nil {
+               tb.Fatalf("writing fuzz_out: %v", err)
+       }
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_match.txt b/src/cmd/go/testdata/script/test_fuzz_match.txt
new file mode 100644 (file)
index 0000000..0c0085f
--- /dev/null
@@ -0,0 +1,38 @@
+[!fuzz] skip
+
+# Matches only fuzz targets to test.
+go test standalone_fuzz_test.go
+! stdout '^ok.*\[no tests to run\]'
+stdout '^ok'
+
+# Matches only for fuzzing.
+go test -fuzz Fuzz -fuzztime 1x standalone_fuzz_test.go
+! stdout '^ok.*\[no tests to run\]'
+stdout '^ok'
+
+# Matches none for fuzzing but will run the fuzz target as a test.
+go test -fuzz ThisWillNotMatch -fuzztime 1x standalone_fuzz_test.go
+! stdout '^ok.*no tests to run'
+stdout '^ok'
+stdout 'no targets to fuzz'
+
+[short] stop
+
+# Matches only fuzz targets to test with -run.
+go test -run Fuzz standalone_fuzz_test.go
+! stdout '^ok.*\[no tests to run\]'
+stdout '^ok'
+
+# Matches no fuzz targets.
+go test -run ThisWillNotMatch standalone_fuzz_test.go
+stdout '^ok.*no tests to run'
+! stdout 'no targets to fuzz'
+
+-- standalone_fuzz_test.go --
+package standalone_fuzz
+
+import "testing"
+
+func Fuzz(f *testing.F) {
+       f.Fuzz(func (*testing.T, []byte) {})
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize.txt b/src/cmd/go/testdata/script/test_fuzz_minimize.txt
new file mode 100644 (file)
index 0000000..462fb9a
--- /dev/null
@@ -0,0 +1,203 @@
+[!fuzz] skip
+[short] skip
+
+# We clean the fuzz cache during this test. Don't clean the user's cache.
+env GOCACHE=$WORK/gocache
+
+# Test that fuzzminimizetime cannot be negative seconds
+! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x -fuzzminimizetime=-1ms .
+! stdout '^ok'
+! stdout 'contains a non-zero byte'
+stdout 'invalid duration'
+stdout FAIL
+
+# Test that fuzzminimizetime cannot be negative times
+! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x -fuzzminimizetime=-1x .
+! stdout '^ok'
+! stdout 'contains a non-zero byte'
+stdout 'invalid count'
+stdout FAIL
+
+# Test that fuzzminimizetime can be zero seconds, and minimization is disabled
+! go test -fuzz=FuzzMinimizeZeroDurationSet -run=FuzzMinimizeZeroDurationSet -fuzztime=10000x -fuzzminimizetime=0s .
+! stdout '^ok'
+! stdout 'minimizing'
+stdout 'there was an Error'
+stdout FAIL
+
+# Test that fuzzminimizetime can be zero times, and minimization is disabled
+! go test -fuzz=FuzzMinimizeZeroLimitSet -run=FuzzMinimizeZeroLimitSet -fuzztime=10000x -fuzzminimizetime=0x .
+! stdout '^ok'
+! stdout 'minimizing'
+stdout -count=1 'there was an Error'
+stdout FAIL
+
+# Test that minimization is working for recoverable errors.
+! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x .
+! stdout '^ok'
+stdout 'got the minimum size!'
+# The error message that was printed should be for the one written to testdata.
+stdout 'contains a non-zero byte of length 50'
+stdout FAIL
+
+# Check that the bytes written to testdata are of length 50 (the minimum size)
+go run ./check_testdata FuzzMinimizerRecoverable 50
+
+# Test that re-running the minimized value causes a crash.
+! go test -run=FuzzMinimizerRecoverable .
+rm testdata
+
+# Test that minimization is working for recoverable errors. Run it with -v this
+# time to ensure the command line output still looks right.
+! go test -v -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x .
+! stdout '^ok'
+stdout 'got the minimum size!'
+# The error message that was printed should be for the one written to testdata.
+stdout 'contains a non-zero byte of length 50'
+stdout FAIL
+
+# Check that the bytes written to testdata are of length 50 (the minimum size)
+go run ./check_testdata FuzzMinimizerRecoverable 50
+
+# Test that re-running the minimized value causes a crash.
+! go test -run=FuzzMinimizerRecoverable .
+rm testdata
+
+# Test that minimization doesn't run for non-recoverable errors.
+! go test -fuzz=FuzzMinimizerNonrecoverable -run=FuzzMinimizerNonrecoverable -fuzztime=10000x .
+! stdout '^ok'
+! stdout 'minimizing'
+stdout -count=1 'fuzzing process terminated unexpectedly: exit status 99'
+stdout FAIL
+
+# Check that re-running the value causes a crash.
+! go test -run=FuzzMinimizerNonrecoverable .
+rm testdata
+
+# Clear the fuzzing cache. There may already be minimized inputs that would
+# interfere with the next stage of the test.
+go clean -fuzzcache
+
+# Test that minimization can be cancelled by fuzzminimizetime and the latest
+# crash will still be logged and written to testdata.
+! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=100x -fuzzminimizetime=1x .
+! stdout '^ok'
+stdout 'testdata[/\\]fuzz[/\\]FuzzMinimizerRecoverable[/\\]'
+! stdout 'got the minimum size!'  # it shouldn't have had enough time to minimize it
+stdout FAIL
+
+# Test that re-running the unminimized value causes a crash.
+! go test -run=FuzzMinimizerRecoverable .
+
+# TODO(jayconrod,katiehockman): add a test which verifies that the right bytes
+# are written to testdata in the case of an interrupt during minimization.
+
+-- go.mod --
+module example.com/y
+
+go 1.16
+-- y_test.go --
+package y
+
+import (
+       "os"
+       "testing"
+)
+
+func FuzzMinimizeZeroDurationSet(f *testing.F) {
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if len(b) > 5 {
+                       t.Errorf("there was an Error")
+               }
+       })
+}
+
+func FuzzMinimizeZeroLimitSet(f *testing.F) {
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if len(b) > 5 {
+                       t.Errorf("there was an Error")
+               }
+       })
+}
+
+func FuzzMinimizerRecoverable(f *testing.F) {
+       f.Add(make([]byte, 100))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if len(b) < 50 {
+                       // Make sure that b is large enough that it can be minimized
+                       return
+               }
+               // Given the randomness of the mutations, this should allow the
+               // minimizer to trim down the value a bit.
+               for _, n := range b {
+                       if n != 0 {
+                               if len(b) == 50 {
+                                       t.Log("got the minimum size!")
+                               }
+                               t.Fatalf("contains a non-zero byte of length %d", len(b))
+                       }
+               }
+       })
+}
+
+func FuzzMinimizerNonrecoverable(f *testing.F) {
+       f.Fuzz(func(t *testing.T, b []byte) {
+               os.Exit(99)
+       })
+}
+-- empty/empty.go --
+package empty
+-- check_testdata/check_testdata.go --
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "strconv"
+)
+
+func main() {
+       target := os.Args[1]
+       numBytes, err := strconv.Atoi(os.Args[2])
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+
+       // Open the file in testdata (there should only be one)
+       dir := fmt.Sprintf("testdata/fuzz/%s", target)
+       files, err := ioutil.ReadDir(dir)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       if len(files) != 1 {
+               fmt.Fprintf(os.Stderr, "expected one file, got %d", len(files))
+               os.Exit(1)
+       }
+       got, err := ioutil.ReadFile(filepath.Join(dir, files[0].Name()))
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+
+       // Trim the newline at the end of the file
+       got = bytes.TrimSpace(got)
+
+       // Make sure that there were exactly 100 bytes written to the corpus entry
+       prefix := []byte("[]byte(")
+       i := bytes.Index(got, prefix)
+       gotBytes := got[i+len(prefix) : len(got)-1]
+       s, err := strconv.Unquote(string(gotBytes))
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       if want, got := numBytes, len(s); want != got {
+               fmt.Fprintf(os.Stderr, "want %d bytes, got %d\n", want, got)
+               os.Exit(1)
+       }
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt b/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt
new file mode 100644 (file)
index 0000000..e017a4c
--- /dev/null
@@ -0,0 +1,158 @@
+[!fuzz-instrumented] skip
+
+# Test that when an interesting value is discovered (one that expands coverage),
+# the fuzzing engine minimizes it before writing it to the cache.
+#
+# The program below starts with a seed value of length 100, but more coverage
+# will be found for any value other than the seed. We should end with a value
+# in the cache of length 1 (the minimizer currently does not produce empty
+# strings). check_cache.go confirms that.
+#
+# We would like to verify that ALL values in the cache were minimized to a
+# length of 1, but this isn't always possible when new coverage is found in
+# functions called by testing or internal/fuzz in the background.
+
+go test -c -fuzz=.  # Build using shared build cache for speed.
+env GOCACHE=$WORK/gocache
+exec ./fuzz.test$GOEXE -test.fuzzcachedir=$GOCACHE/fuzz -test.fuzz=FuzzMinCache -test.fuzztime=1000x
+go run check_cache.go $GOCACHE/fuzz/FuzzMinCache
+
+# Test that minimization occurs for a crash that appears while minimizing a
+# newly found interesting input. There must be only one worker for this test to
+# be flaky like we want.
+go test -c -fuzz=.  # Build using shared build cache for speed.
+env GOCACHE=$WORK/gocache
+! exec ./fuzz.test$GOEXE -test.fuzzcachedir=$GOCACHE/fuzz -test.fuzz=FuzzMinimizerCrashInMinimization -test.fuzztime=10000x -test.parallel=1
+! stdout '^ok'
+stdout 'got the minimum size!'
+stdout -count=1 'flaky failure'
+stdout FAIL
+
+# Make sure the crash that was written will fail when run with go test
+! go test -run=FuzzMinimizerCrashInMinimization .
+
+-- go.mod --
+module fuzz
+
+go 1.17
+-- y.go --
+package fuzz
+
+import (
+       "bytes"
+       "io"
+)
+
+func Y(w io.Writer, b []byte) {
+       if !bytes.Equal(b, []byte("y")) {
+               w.Write([]byte("not equal"))
+       }
+}
+-- fuzz_test.go --
+package fuzz
+
+import (
+       "bytes"
+       "io"
+       "testing"
+)
+
+func FuzzMinimizerCrashInMinimization(f *testing.F) {
+       seed := make([]byte, 1000)
+       f.Add(seed)
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if len(b) < 50 || len(b) > 1100 {
+                       // Make sure that b is large enough that it can be minimized
+                       return
+               }
+               if !bytes.Equal(b, seed) {
+                       // This should have hit a new edge, and the interesting input
+                       // should be attempting minimization
+                       Y(io.Discard, b)
+               }
+               if len(b) < 350 {
+                       t.Error("flaky failure")
+               }
+               if len(b) == 50 {
+                       t.Log("got the minimum size!")
+               }
+       })
+}
+
+func FuzzMinCache(f *testing.F) {
+       seed := bytes.Repeat([]byte("a"), 20)
+       f.Add(seed)
+       f.Fuzz(func(t *testing.T, buf []byte) {
+               if bytes.Equal(buf, seed) {
+                       return
+               }
+               if n := sum(buf); n < 0 {
+                       t.Error("sum cannot be negative")
+               }
+       })
+}
+
+func sum(buf []byte) int {
+       n := 0
+       for _, b := range buf {
+               n += int(b)
+       }
+       return n
+}
+-- check_cache.go --
+//go:build ignore
+// +build ignore
+
+// check_cache.go checks that each file in the cached corpus has a []byte
+// of length at most 1. This verifies that at least one cached input is minimized.
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "os"
+       "path/filepath"
+       "regexp"
+       "strconv"
+)
+
+func main() {
+       dir := os.Args[1]
+       ents, err := os.ReadDir(dir)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       for _, ent := range ents {
+               name := filepath.Join(dir, ent.Name())
+               if good, err := checkCacheFile(name); err != nil {
+                       fmt.Fprintln(os.Stderr, err)
+                       os.Exit(1)
+               } else if good {
+                       os.Exit(0)
+               }
+       }
+       fmt.Fprintln(os.Stderr, "no cached inputs were minimized")
+       os.Exit(1)
+}
+
+func checkCacheFile(name string) (good bool, err error) {
+       data, err := os.ReadFile(name)
+       if err != nil {
+               return false, err
+       }
+       for _, line := range bytes.Split(data, []byte("\n")) {
+               m := valRe.FindSubmatch(line)
+               if m == nil {
+                       continue
+               }
+               if s, err := strconv.Unquote(string(m[1])); err != nil {
+                       return false, err
+               } else if len(s) <= 1 {
+                       return true, nil
+               }
+       }
+       return false, nil
+}
+
+var valRe = regexp.MustCompile(`^\[\]byte\(([^)]+)\)$`)
diff --git a/src/cmd/go/testdata/script/test_fuzz_modcache.txt b/src/cmd/go/testdata/script/test_fuzz_modcache.txt
new file mode 100644 (file)
index 0000000..c0f18ea
--- /dev/null
@@ -0,0 +1,58 @@
+# This test demonstrates the fuzz corpus behavior for packages outside of the main module.
+# (See https://golang.org/issue/48495.)
+
+[short] skip
+
+# Set -modcacherw so that the test behaves the same regardless of whether the
+# module cache is writable. (For example, on some platforms it can always be
+# written if the user is running as root.) At one point, a failing fuzz test
+# in a writable module cache would corrupt module checksums in the cache.
+env GOFLAGS=-modcacherw
+
+
+# When the upstream module has no test corpus, running 'go test' should succeed,
+# but 'go test -fuzz=.' should error out before running the test.
+# (It should NOT corrupt the module cache by writing out new fuzz inputs,
+# even if the cache is writable.)
+
+go get -t example.com/fuzzfail@v0.1.0
+go test example.com/fuzzfail
+
+! go test -fuzz=. example.com/fuzzfail
+! stdout .
+stderr '^cannot use -fuzz flag on package outside the main module$'
+
+go mod verify
+
+
+# If the module does include a test corpus, 'go test' (without '-fuzz') should
+# load that corpus and run the fuzz tests against it, but 'go test -fuzz=.'
+# should continue to be rejected.
+
+go get -t example.com/fuzzfail@v0.2.0
+
+! go test example.com/fuzzfail
+stdout '^\s*fuzzfail_test\.go:7: oops:'
+
+! go test -fuzz=. example.com/fuzzfail
+! stdout .
+stderr '^cannot use -fuzz flag on package outside the main module$'
+
+go mod verify
+
+
+# Packages in 'std' cannot be fuzzed when the corresponding GOROOT module is not
+# the main module — either the failures would not be recorded or the behavior of
+# the 'std' tests would change globally.
+
+! go test -fuzz . encoding/json
+stderr '^cannot use -fuzz flag on package outside the main module$'
+
+! go test -fuzz . cmd/buildid
+stderr '^cannot use -fuzz flag on package outside the main module$'
+
+
+-- go.mod --
+module example.com/m
+
+go 1.18
diff --git a/src/cmd/go/testdata/script/test_fuzz_multiple.txt b/src/cmd/go/testdata/script/test_fuzz_multiple.txt
new file mode 100644 (file)
index 0000000..d96b2b6
--- /dev/null
@@ -0,0 +1,49 @@
+# This test checks that 'go test' prints a reasonable error when fuzzing is
+# enabled, and multiple package or multiple fuzz targets match.
+# TODO(#46312): support fuzzing multiple targets in multiple packages.
+
+[!fuzz] skip
+[short] skip
+
+# With fuzzing disabled, multiple targets can be tested.
+go test ./...
+
+# With fuzzing enabled, at most one package may be tested,
+# even if only one package contains fuzz targets.
+! go test -fuzz=. ./...
+stderr '^cannot use -fuzz flag with multiple packages$'
+! go test -fuzz=. ./zero ./one
+stderr '^cannot use -fuzz flag with multiple packages$'
+go test -fuzz=. -fuzztime=1x ./one
+
+# With fuzzing enabled, at most one target in the same package may match.
+! go test -fuzz=. ./two
+stdout '^testing: will not fuzz, -fuzz matches more than one target: \[FuzzOne FuzzTwo\]$'
+go test -fuzz=FuzzTwo -fuzztime=1x ./two
+
+-- go.mod --
+module fuzz
+
+go 1.18
+-- zero/zero.go --
+package zero
+-- one/one_test.go --
+package one
+
+import "testing"
+
+func FuzzOne(f *testing.F) {
+  f.Fuzz(func(*testing.T, []byte) {})
+}
+-- two/two_test.go --
+package two
+
+import "testing"
+
+func FuzzOne(f *testing.F) {
+  f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzTwo(f *testing.F) {
+  f.Fuzz(func(*testing.T, []byte) {})
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt b/src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt
new file mode 100644 (file)
index 0000000..4c4fa8e
--- /dev/null
@@ -0,0 +1,309 @@
+[!fuzz] skip
+
+# Tests that a crash caused by a mutator-discovered input writes the bad input
+# to testdata, and fails+reports correctly. This tests the end-to-end behavior
+# of the mutator finding a crash while fuzzing, adding it as a regression test
+# to the seed corpus in testdata, and failing the next time the test is run.
+
+[short] skip
+
+# Running the seed corpus for all of the targets should pass the first
+# time, since nothing in the seed corpus will cause a crash.
+go test
+
+# Running the fuzzer should find a crashing input quickly.
+! go test -fuzz=FuzzWithBug -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithBug[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzWithBug
+
+# Now, the failing bytes should have been added to the seed corpus for
+# the target, and should fail when run without fuzzing.
+! go test
+stdout 'FuzzWithBug/[a-f0-9]{64}'
+stdout 'this input caused a crash!'
+
+! go test -run=FuzzWithNilPanic -fuzz=FuzzWithNilPanic -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithNilPanic[/\\]'
+stdout 'runtime.Goexit'
+go run check_testdata.go FuzzWithNilPanic
+
+! go test -run=FuzzWithGoexit -fuzz=FuzzWithGoexit -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithGoexit[/\\]'
+stdout 'runtime.Goexit'
+go run check_testdata.go FuzzWithGoexit
+
+! go test -run=FuzzWithFail -fuzz=FuzzWithFail -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithFail[/\\]'
+go run check_testdata.go FuzzWithFail
+
+! go test -run=FuzzWithLogFail -fuzz=FuzzWithLogFail -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithLogFail[/\\]'
+stdout 'logged something'
+go run check_testdata.go FuzzWithLogFail
+
+! go test -run=FuzzWithErrorf -fuzz=FuzzWithErrorf -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithErrorf[/\\]'
+stdout 'errorf was called here'
+go run check_testdata.go FuzzWithErrorf
+
+! go test -run=FuzzWithFatalf -fuzz=FuzzWithFatalf -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithFatalf[/\\]'
+stdout 'fatalf was called here'
+go run check_testdata.go FuzzWithFatalf
+
+! go test -run=FuzzWithBadExit -fuzz=FuzzWithBadExit -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithBadExit[/\\]'
+stdout 'unexpectedly'
+go run check_testdata.go FuzzWithBadExit
+
+# Running the fuzzer should find a crashing input quickly for fuzzing two types.
+! go test -run=FuzzWithTwoTypes -fuzz=FuzzWithTwoTypes -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzWithTwoTypes[/\\]'
+stdout 'these inputs caused a crash!'
+go run check_testdata.go FuzzWithTwoTypes
+
+# Running the fuzzer should find a crashing input quickly for an integer.
+! go test -run=FuzzInt -fuzz=FuzzInt -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzInt[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzInt
+
+! go test -run=FuzzUint -fuzz=FuzzUint -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzUint[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzUint
+
+# Running the fuzzer should find a crashing input quickly for a bool.
+! go test -run=FuzzBool -fuzz=FuzzBool -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzBool[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzBool
+
+# Running the fuzzer should find a crashing input quickly for a float.
+! go test -run=FuzzFloat -fuzz=FuzzFloat -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzFloat[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzFloat
+
+# Running the fuzzer should find a crashing input quickly for a byte.
+! go test -run=FuzzByte -fuzz=FuzzByte -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzByte[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzByte
+
+# Running the fuzzer should find a crashing input quickly for a rune.
+! go test -run=FuzzRune -fuzz=FuzzRune -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzRune[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzRune
+
+# Running the fuzzer should find a crashing input quickly for a string.
+! go test -run=FuzzString -fuzz=FuzzString -fuzztime=100x -fuzzminimizetime=1000x
+stdout 'testdata[/\\]fuzz[/\\]FuzzString[/\\]'
+stdout 'this input caused a crash!'
+go run check_testdata.go FuzzString
+
+-- go.mod --
+module m
+
+go 1.16
+-- fuzz_crash_test.go --
+package fuzz_crash
+
+import (
+       "os"
+       "runtime"
+       "testing"
+)
+
+func FuzzWithBug(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzWithNilPanic(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       panic(nil)
+               }
+       })
+}
+
+func FuzzWithGoexit(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       runtime.Goexit()
+               }
+       })
+}
+
+func FuzzWithFail(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       t.Fail()
+               }
+       })
+}
+
+func FuzzWithLogFail(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       t.Log("logged something")
+                       t.Fail()
+               }
+       })
+}
+
+func FuzzWithErrorf(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       t.Errorf("errorf was called here")
+               }
+       })
+}
+
+func FuzzWithFatalf(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       t.Fatalf("fatalf was called here")
+               }
+       })
+}
+
+func FuzzWithBadExit(f *testing.F) {
+       f.Add([]byte("aa"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               if string(b) != "aa" {
+                       os.Exit(1)
+               }
+       })
+}
+
+func FuzzWithTwoTypes(f *testing.F) {
+       f.Fuzz(func(t *testing.T, a, b []byte) {
+               if len(a) > 0 && len(b) > 0 {
+                       panic("these inputs caused a crash!")
+               }
+       })
+}
+
+func FuzzInt(f *testing.F) {
+       f.Add(0)
+       f.Fuzz(func(t *testing.T, a int) {
+               if a != 0 {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzUint(f *testing.F) {
+       f.Add(uint(0))
+       f.Fuzz(func(t *testing.T, a uint) {
+               if a != 0 {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzBool(f *testing.F) {
+       f.Add(false)
+       f.Fuzz(func(t *testing.T, a bool) {
+               if a {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzFloat(f *testing.F) {
+       f.Fuzz(func(t *testing.T, a float64) {
+               if a != float64(int64(a)) {
+                       // It has a decimal, so it was mutated by division
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzByte(f *testing.F) {
+       f.Add(byte(0))
+       f.Fuzz(func(t *testing.T, a byte) {
+               if a != 0 {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzRune(f *testing.F) {
+       f.Add(rune(0))
+       f.Fuzz(func(t *testing.T, a rune) {
+               if a != 0 {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+func FuzzString(f *testing.F) {
+       f.Add("")
+       f.Fuzz(func(t *testing.T, a string) {
+               if a != "" {
+                       panic("this input caused a crash!")
+               }
+       })
+}
+
+-- check_testdata.go --
+// +build ignore
+
+package main
+
+import (
+       "bytes"
+       "crypto/sha256"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+)
+
+func main() {
+       target := os.Args[1]
+       dir := filepath.Join("testdata/fuzz", target)
+
+       files, err := ioutil.ReadDir(dir)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+
+       if len(files) == 0 {
+               fmt.Fprintf(os.Stderr, "expect at least one new mutation to be written to testdata\n")
+               os.Exit(1)
+       }
+
+       fname := files[0].Name()
+       contents, err := ioutil.ReadFile(filepath.Join(dir, fname))
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       if bytes.Equal(contents, []byte("aa")) {
+               fmt.Fprintf(os.Stderr, "newly written testdata entry was not mutated\n")
+               os.Exit(1)
+       }
+       // The hash of the bytes in the file should match the filename.
+       h := []byte(fmt.Sprintf("%x", sha256.Sum256(contents)))
+       if !bytes.Equal([]byte(fname), h) {
+               fmt.Fprintf(os.Stderr, "hash of bytes %q does not match filename %q\n", h, fname)
+               os.Exit(1)
+       }
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_mutate_fail.txt b/src/cmd/go/testdata/script/test_fuzz_mutate_fail.txt
new file mode 100644 (file)
index 0000000..b5eab17
--- /dev/null
@@ -0,0 +1,102 @@
+[!fuzz] skip
+
+# Check that if a worker does not call F.Fuzz or calls F.Fail first,
+# 'go test' exits non-zero and no crasher is recorded.
+
+[short] skip
+
+! go test -fuzz=FuzzReturn
+! exists testdata
+
+! go test -fuzz=FuzzSkip
+! exists testdata
+
+! go test -fuzz=FuzzFail
+! exists testdata
+
+! go test -fuzz=FuzzPanic
+! exists testdata
+
+! go test -fuzz=FuzzNilPanic
+! exists testdata
+
+! go test -fuzz=FuzzGoexit
+! exists testdata
+
+! go test -fuzz=FuzzExit
+! exists testdata
+
+-- go.mod --
+module m
+
+go 1.17
+-- fuzz_fail_test.go --
+package fuzz_fail
+
+import (
+       "flag"
+       "os"
+       "runtime"
+       "testing"
+)
+
+func isWorker() bool {
+       f := flag.Lookup("test.fuzzworker")
+       if f == nil {
+               return false
+       }
+       get, ok := f.Value.(flag.Getter)
+       if !ok {
+               return false
+       }
+       return get.Get() == interface{}(true)
+}
+
+func FuzzReturn(f *testing.F) {
+       if isWorker() {
+               return
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzSkip(f *testing.F) {
+       if isWorker() {
+               f.Skip()
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzFail(f *testing.F) {
+       if isWorker() {
+               f.Fail()
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzPanic(f *testing.F) {
+       if isWorker() {
+               panic("nope")
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzNilPanic(f *testing.F) {
+       if isWorker() {
+               panic(nil)
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzGoexit(f *testing.F) {
+       if isWorker() {
+               runtime.Goexit()
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzExit(f *testing.F) {
+       if isWorker() {
+               os.Exit(99)
+       }
+       f.Fuzz(func(*testing.T, []byte) {})
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_mutator.txt b/src/cmd/go/testdata/script/test_fuzz_mutator.txt
new file mode 100644 (file)
index 0000000..76b8648
--- /dev/null
@@ -0,0 +1,165 @@
+[!fuzz] skip
+
+# Test basic fuzzing mutator behavior.
+#
+# fuzz_test.go has two fuzz targets (FuzzA, FuzzB) which both add a seed value.
+# Each fuzz function writes the input to a log file. The coordinator and worker
+# use separate log files. check_logs.go verifies that the coordinator only
+# tests seed values and the worker tests mutated values on the fuzz target.
+
+[short] skip
+
+go test -fuzz=FuzzA -fuzztime=100x -parallel=1 -log=fuzz
+go run check_logs.go fuzz fuzz.worker
+
+# TODO(b/181800488): remove -parallel=1, here and below. For now, when a
+# crash is found, all workers keep running, wasting resources and reducing
+# the number of executions available to the minimizer, increasing flakiness.
+
+# Test that the mutator is good enough to find several unique mutations.
+! go test -fuzz=FuzzMutator -parallel=1 -fuzztime=100x mutator_test.go
+! stdout '^ok'
+stdout FAIL
+stdout 'mutator found enough unique mutations'
+
+-- go.mod --
+module m
+
+go 1.16
+-- fuzz_test.go --
+package fuzz_test
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "testing"
+)
+
+var (
+       logPath = flag.String("log", "", "path to log file")
+       logFile *os.File
+)
+
+func TestMain(m *testing.M) {
+       flag.Parse()
+       var err error
+       logFile, err = os.OpenFile(*logPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+       if os.IsExist(err) {
+               *logPath += ".worker"
+               logFile, err = os.OpenFile(*logPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+       }
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       os.Exit(m.Run())
+}
+
+func FuzzA(f *testing.F) {
+       f.Add([]byte("seed"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               fmt.Fprintf(logFile, "FuzzA %q\n", b)
+       })
+}
+
+func FuzzB(f *testing.F) {
+       f.Add([]byte("seed"))
+       f.Fuzz(func(t *testing.T, b []byte) {
+               fmt.Fprintf(logFile, "FuzzB %q\n", b)
+       })
+}
+
+-- check_logs.go --
+// +build ignore
+
+package main
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "os"
+       "strings"
+)
+
+func main() {
+       coordPath, workerPath := os.Args[1], os.Args[2]
+
+       coordLog, err := os.Open(coordPath)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       defer coordLog.Close()
+       if err := checkCoordLog(coordLog); err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+
+       workerLog, err := os.Open(workerPath)
+       if err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+       defer workerLog.Close()
+       if err := checkWorkerLog(workerLog); err != nil {
+               fmt.Fprintln(os.Stderr, err)
+               os.Exit(1)
+       }
+}
+
+func checkCoordLog(r io.Reader) error {
+       b, err := io.ReadAll(r)
+       if err != nil {
+               return err
+       }
+       if string(bytes.TrimSpace(b)) != `FuzzB "seed"` {
+               return fmt.Errorf("coordinator: did not test FuzzB seed")
+       }
+       return nil
+}
+
+func checkWorkerLog(r io.Reader) error {
+       scan := bufio.NewScanner(r)
+       var sawAMutant bool
+       for scan.Scan() {
+               line := scan.Text()
+               if !strings.HasPrefix(line, "FuzzA ") {
+                       return fmt.Errorf("worker: tested something other than target: %s", line)
+               }
+               if strings.TrimPrefix(line, "FuzzA ") != `"seed"` {
+                       sawAMutant = true
+               }
+       }
+       if err := scan.Err(); err != nil && err != bufio.ErrTooLong {
+               return err
+       }
+       if !sawAMutant {
+               return fmt.Errorf("worker: did not test any mutants")
+       }
+       return nil
+}
+-- mutator_test.go --
+package fuzz_test
+
+import (
+       "testing"
+)
+
+// TODO(katiehockman): re-work this test once we have a better fuzzing engine
+// (ie. more mutations, and compiler instrumentation)
+func FuzzMutator(f *testing.F) {
+       // TODO(katiehockman): simplify this once we can dedupe crashes (e.g.
+       // replace map with calls to panic, and simply count the number of crashes
+       // that were added to testdata)
+       crashes := make(map[string]bool)
+       // No seed corpus initiated
+       f.Fuzz(func(t *testing.T, b []byte) {
+               crashes[string(b)] = true
+               if len(crashes) >= 10 {
+                       panic("mutator found enough unique mutations")
+               }
+       })
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_mutator_repeat.txt b/src/cmd/go/testdata/script/test_fuzz_mutator_repeat.txt
new file mode 100644 (file)
index 0000000..15d7cb6
--- /dev/null
@@ -0,0 +1,74 @@
+# TODO(jayconrod): support shared memory on more platforms.
+[!darwin] [!linux] [!windows] skip
+
+# Verify that the fuzzing engine records the actual crashing input, even when
+# a worker process terminates without communicating the crashing input back
+# to the coordinator.
+
+[short] skip
+
+# Start fuzzing. The worker crashes after 100 iterations.
+# The fuzz function writes the crashing input to "want" before exiting.
+# The fuzzing engine reconstructs the crashing input and saves it to testdata.
+! exists want
+! go test -fuzz=. -parallel=1 -fuzztime=110x -fuzzminimizetime=10x -v
+stdout 'fuzzing process terminated unexpectedly'
+stdout 'Crash written to testdata'
+
+# Run the fuzz target without fuzzing. The fuzz function is called with the
+# crashing input in testdata. The test passes if that input is identical to
+# the one saved in "want".
+exists want
+go test -want=want
+
+-- go.mod --
+module fuzz
+
+go 1.17
+-- fuzz_test.go --
+package fuzz
+
+import (
+       "bytes"
+       "flag"
+       "os"
+       "testing"
+)
+
+var wantFlag = flag.String("want", "", "file containing previous crashing input")
+
+func FuzzRepeat(f *testing.F) {
+       i := 0
+       f.Fuzz(func(t *testing.T, b []byte) {
+               i++
+               if i == 100 {
+                       f, err := os.OpenFile("want", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
+                       if err != nil {
+                               // Couldn't create the file. Return without crashing, and try
+                               // again.
+                               i--
+                               t.Skip(err)
+                       }
+                       if _, err := f.Write(b); err != nil {
+                               // We already created the file, so if we failed to write it
+                               // there's not much we can do. The test will fail anyway, but
+                               // at least make sure the error is logged to stdout.
+                               t.Fatal(err)
+                       }
+                       if err := f.Close(); err != nil {
+                               t.Fatal(err)
+                       }
+                       os.Exit(1) // crash without communicating
+               }
+
+               if *wantFlag != "" {
+                       want, err := os.ReadFile(*wantFlag)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if !bytes.Equal(want, b) {
+                               t.Fatalf("inputs are not equal!\n got: %q\nwant:%q", b, want)
+                       }
+               }
+       })
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_non_crash_signal.txt b/src/cmd/go/testdata/script/test_fuzz_non_crash_signal.txt
new file mode 100644 (file)
index 0000000..31d54bc
--- /dev/null
@@ -0,0 +1,75 @@
+# NOTE: this test is skipped on Windows, since there's no concept of signals.
+# When a process terminates another process, it provides an exit code.
+[windows] skip
+[!fuzz] skip
+[short] skip
+
+# FuzzNonCrash sends itself a signal that does not appear to be a crash.
+# We should not save a crasher.
+! go test -fuzz=FuzzNonCrash
+! exists testdata
+! stdout unreachable
+! stderr unreachable
+stdout 'fuzzing process terminated by unexpected signal; no crash will be recorded: signal: terminated'
+
+# FuzzKill sends itself a signal that cannot be caught by the worker process
+# and does not appear to be a crash.
+# We should not save a crasher.
+! go test -fuzz=FuzzKill
+! exists testdata
+! stdout unreachable
+! stderr unreachable
+stdout 'fuzzing process terminated by unexpected signal; no crash will be recorded: signal: killed'
+
+# FuzzCrash sends itself a signal that looks like a crash.
+# We should save a crasher.
+! go test -fuzz=FuzzCrash
+exists testdata/fuzz/FuzzCrash
+stdout 'fuzzing process terminated unexpectedly'
+
+-- go.mod --
+module test
+
+go 1.17
+-- fuzz_posix_test.go --
+// +build darwin freebsd linux
+
+package fuzz
+
+import (
+       "syscall"
+       "testing"
+)
+
+func FuzzNonCrash(f *testing.F) {
+       f.Fuzz(func(*testing.T, bool) {
+               pid := syscall.Getpid()
+               if err := syscall.Kill(pid, syscall.SIGTERM); err != nil {
+                       panic(err)
+               }
+               // signal may not be received immediately. Wait for it.
+               select{}
+       })
+}
+
+func FuzzKill(f *testing.F) {
+       f.Fuzz(func(*testing.T, bool) {
+               pid := syscall.Getpid()
+               if err := syscall.Kill(pid, syscall.SIGKILL); err != nil {
+                       panic(err)
+               }
+               // signal may not be received immediately. Wait for it.
+               select{}
+       })
+}
+
+func FuzzCrash(f *testing.F) {
+       f.Fuzz(func(*testing.T, bool) {
+               pid := syscall.Getpid()
+               if err := syscall.Kill(pid, syscall.SIGILL); err != nil {
+                       panic(err)
+               }
+               // signal may not be received immediately. Wait for it.
+               select{}
+       })
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_parallel.txt b/src/cmd/go/testdata/script/test_fuzz_parallel.txt
new file mode 100644 (file)
index 0000000..1795e0b
--- /dev/null
@@ -0,0 +1,59 @@
+[!fuzz] skip
+[short] skip
+
+# When running seed inputs, T.Parallel should let multiple inputs run in
+# parallel.
+go test -run=FuzzSeed
+
+# When fuzzing, T.Parallel should be safe to call, but it should have no effect.
+# We just check that it doesn't hang, which would be the most obvious
+# failure mode.
+# TODO(jayconrod): check for the string "after T.Parallel". It's not printed
+# by 'go test', so we can't distinguish that crasher from some other panic.
+! go test -run=FuzzMutate -fuzz=FuzzMutate
+exists testdata/fuzz/FuzzMutate
+
+-- go.mod --
+module fuzz_parallel
+
+go 1.17
+-- fuzz_parallel_test.go --
+package fuzz_parallel
+
+import (
+       "sort"
+       "sync"
+       "testing"
+)
+
+func FuzzSeed(f *testing.F) {
+       for _, v := range [][]byte{{'a'}, {'b'}, {'c'}} {
+               f.Add(v)
+       }
+
+       var mu sync.Mutex
+       var before, after []byte
+       f.Cleanup(func() {
+               sort.Slice(after, func(i, j int) bool { return after[i] < after[j] })
+               got := string(before) + string(after)
+               want := "abcabc"
+               if got != want {
+                       f.Fatalf("got %q; want %q", got, want)
+               }
+       })
+
+       f.Fuzz(func(t *testing.T, b []byte) {
+               before = append(before, b...)
+               t.Parallel()
+               mu.Lock()
+               after = append(after, b...)
+               mu.Unlock()
+       })
+}
+
+func FuzzMutate(f *testing.F) {
+       f.Fuzz(func(t *testing.T, _ []byte) {
+               t.Parallel()
+               t.Error("after T.Parallel")
+       })
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_profile_flags.txt b/src/cmd/go/testdata/script/test_fuzz_profile_flags.txt
new file mode 100644 (file)
index 0000000..5434c72
--- /dev/null
@@ -0,0 +1,38 @@
+[!fuzz] skip
+
+! go test -fuzz=FuzzTrivial -coverprofile=prof
+! stdout .
+stderr '^cannot use -coverprofile flag with -fuzz flag$'
+
+! go test -fuzz=FuzzTrivial -blockprofile=prof
+! stdout .
+stderr '^cannot use -blockprofile flag with -fuzz flag$'
+
+! go test -fuzz=FuzzTrivial -cpuprofile=prof
+! stdout .
+stderr '^cannot use -cpuprofile flag with -fuzz flag$'
+
+! go test -fuzz=FuzzTrivial -memprofile=prof
+! stdout .
+stderr '^cannot use -memprofile flag with -fuzz flag$'
+
+! go test -fuzz=FuzzTrivial -mutexprofile=prof
+! stdout .
+stderr '^cannot use -mutexprofile flag with -fuzz flag$'
+
+! go test -fuzz=FuzzTrivial -trace=prof
+! stdout .
+stderr '^cannot use -trace flag with -fuzz flag$'
+
+-- go.mod --
+module example
+
+go 1.18
+-- fuzz_test.go --
+package example
+
+import "testing"
+
+func FuzzTrivial(f *testing.F) {
+       f.Fuzz(func(t *testing.T, _ []byte) {})
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_run.txt b/src/cmd/go/testdata/script/test_fuzz_run.txt
new file mode 100644 (file)
index 0000000..99a4413
--- /dev/null
@@ -0,0 +1,143 @@
+[!fuzz] skip
+[short] skip
+env GOCACHE=$WORK/cache
+
+# Tests which verify the behavior and command line output when
+# running a fuzz target as a unit test.
+
+# Tests without -run.
+
+! go test
+stdout FAIL
+stdout 'error here'
+
+! go test -v
+stdout FAIL
+stdout 'error here'
+stdout '=== RUN   FuzzFoo/thisfails'
+stdout '--- FAIL: FuzzFoo/thisfails'
+stdout '=== RUN   FuzzFoo/thispasses'
+stdout '--- PASS: FuzzFoo/thispasses'
+
+# Tests where -run matches all seed corpora.
+
+! go test -run FuzzFoo/this
+stdout FAIL
+stdout 'error here'
+! stdout 'no tests to run'
+
+! go test -run /this
+stdout FAIL
+stdout 'error here'
+! stdout 'no tests to run'
+
+! go test -v -run FuzzFoo/this
+stdout FAIL
+stdout 'error here'
+stdout '=== RUN   FuzzFoo/thisfails'
+stdout '--- FAIL: FuzzFoo/thisfails'
+stdout '=== RUN   FuzzFoo/thispasses'
+stdout '--- PASS: FuzzFoo/thispasses'
+! stdout 'no tests to run'
+
+! go test -v -run /this
+stdout FAIL
+stdout 'error here'
+stdout '=== RUN   FuzzFoo/thisfails'
+stdout '--- FAIL: FuzzFoo/thisfails'
+stdout '=== RUN   FuzzFoo/thispasses'
+stdout '--- PASS: FuzzFoo/thispasses'
+! stdout 'no tests to run'
+
+# Tests where -run only matches one seed corpus which passes.
+
+go test -run FuzzFoo/thispasses
+stdout ok
+! stdout 'no tests to run'
+
+go test -run /thispasses
+stdout ok
+! stdout 'no tests to run'
+
+# Same tests in verbose mode
+go test -v -run FuzzFoo/thispasses
+stdout '=== RUN   FuzzFoo/thispasses'
+stdout '--- PASS: FuzzFoo/thispasses'
+! stdout '=== RUN   FuzzFoo/thisfails'
+! stdout 'no tests to run'
+
+go test -v -run /thispasses
+stdout '=== RUN   FuzzFoo/thispasses'
+stdout '--- PASS: FuzzFoo/thispasses'
+! stdout '=== RUN   FuzzFoo/thisfails'
+! stdout 'no tests to run'
+
+# Tests where -run only matches one seed corpus which fails.
+
+! go test -run FuzzFoo/thisfails
+stdout FAIL
+stdout 'error here'
+! stdout 'no tests to run'
+
+! go test -run /thisfails
+stdout FAIL
+stdout 'error here'
+! stdout 'no tests to run'
+
+! go test -v -run FuzzFoo/thisfails
+stdout 'error here'
+stdout '=== RUN   FuzzFoo/thisfails'
+stdout '--- FAIL: FuzzFoo/thisfails'
+! stdout '=== RUN   FuzzFoo/thispasses'
+! stdout 'no tests to run'
+
+! go test -v -run /thisfails
+stdout 'error here'
+stdout '=== RUN   FuzzFoo/thisfails'
+stdout '--- FAIL: FuzzFoo/thisfails'
+! stdout '=== RUN   FuzzFoo/thispasses'
+! stdout 'no tests to run'
+
+# Tests where -run doesn't match any seed corpora.
+
+go test -run FuzzFoo/nomatch
+stdout ok
+
+go test -run /nomatch
+stdout ok
+
+go test -v -run FuzzFoo/nomatch
+stdout '=== RUN   FuzzFoo'
+stdout '--- PASS: FuzzFoo'
+stdout ok
+! stdout 'no tests to run'
+
+go test -v -run /nomatch
+stdout '=== RUN   FuzzFoo'
+stdout '--- PASS: FuzzFoo'
+stdout ok
+! stdout 'no tests to run'
+
+-- go.mod --
+module example.com/x
+
+go 1.16
+-- x_test.go --
+package x
+
+import "testing"
+
+func FuzzFoo(f *testing.F) {
+    f.Add("this is fine")
+    f.Fuzz(func(t *testing.T, s string) {
+        if s == "fails" {
+            t.Error("error here")
+        }
+    })
+}
+-- testdata/fuzz/FuzzFoo/thisfails --
+go test fuzz v1
+string("fails")
+-- testdata/fuzz/FuzzFoo/thispasses --
+go test fuzz v1
+string("passes")
diff --git a/src/cmd/go/testdata/script/test_fuzz_seed_corpus.txt b/src/cmd/go/testdata/script/test_fuzz_seed_corpus.txt
new file mode 100644 (file)
index 0000000..4be9a6e
--- /dev/null
@@ -0,0 +1,203 @@
+[!fuzz-instrumented] skip
+[short] skip
+env GOCACHE=$WORK/cache
+
+# Test that fuzzing a target with a failure in f.Add prints the crash
+# and doesn't write anything to testdata/fuzz
+! go test -fuzz=FuzzWithAdd -run=FuzzWithAdd -fuzztime=1x
+! stdout ^ok
+! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
+stdout FAIL
+
+# Test that fuzzing a target with a sucess in f.Add and a fuzztime of only
+# 1 does not produce a crash.
+go test -fuzz=FuzzWithGoodAdd -run=FuzzWithGoodAdd -fuzztime=1x
+stdout ok
+! stdout FAIL
+
+# Test that fuzzing a target with a failure in testdata/fuzz prints the crash
+# and doesn't write anything to testdata/fuzz
+! go test -fuzz=FuzzWithTestdata -run=FuzzWithTestdata -fuzztime=1x
+! stdout ^ok
+! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
+stdout 'found a crash while testing seed corpus entry: FuzzWithTestdata/1'
+stdout FAIL
+
+# Test that fuzzing a target with no seed corpus or cache finds a crash, prints
+# it, and write it to testdata
+! go test -fuzz=FuzzWithNoCache -run=FuzzWithNoCache -fuzztime=1x
+! stdout ^ok
+stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithNoCache[/\\]'
+stdout FAIL
+
+# Write a crashing input to the cache
+mkdir $GOCACHE/fuzz/example.com/x/FuzzWithCache
+cp cache-file $GOCACHE/fuzz/example.com/x/FuzzWithCache/1
+
+# Test that fuzzing a target with a failure in the cache prints the crash
+# and writes this as a "new" crash to testdata/fuzz
+! go test -fuzz=FuzzWithCache -run=FuzzWithCache -fuzztime=1x
+! stdout ^ok
+stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithCache[/\\]'
+stdout FAIL
+
+# Write a crashing input to the cache
+mkdir $GOCACHE/fuzz/example.com/x/FuzzWithMinimizableCache
+cp cache-file-bytes $GOCACHE/fuzz/example.com/x/FuzzWithMinimizableCache/1
+
+# Test that fuzzing a target with a failure in the cache minimizes it and writes
+# the new crash to testdata/fuzz
+! go test -fuzz=FuzzWithMinimizableCache -run=FuzzWithMinimizableCache -fuzztime=10000x
+! stdout ^ok
+stdout 'gathering baseline coverage'
+stdout 'got the minimum size!'
+stdout 'contains a non-zero byte of length 10'
+stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithMinimizableCache[/\\]'
+stdout FAIL
+# Make sure this crash didn't come from fuzzing
+# (the log line that states fuzzing began shouldn't have printed)
+! stdout 'execs'
+
+# Clear the fuzz cache and make sure it's gone
+go clean -fuzzcache
+! exists $GOCACHE/fuzz
+
+# The tests below should operate the exact same as the previous tests. If -fuzz
+# is enabled, then whatever target is going to be fuzzed shouldn't be run by
+# anything other than the workers.
+
+# Test that fuzzing a target (with -run=None set) with a failure in f.Add prints
+# the crash and doesn't write anything to testdata/fuzz -fuzztime=1x
+! go test -fuzz=FuzzWithAdd -run=None
+! stdout ^ok
+! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
+stdout FAIL
+
+# Test that fuzzing a target (with -run=None set) with a sucess in f.Add and a
+# fuzztime of only 1 does not produce a crash.
+go test -fuzz=FuzzWithGoodAdd -run=None -fuzztime=1x
+stdout ok
+! stdout FAIL
+
+# Test that fuzzing a target (with -run=None set) with a failure in
+# testdata/fuzz prints the crash and doesn't write anything to testdata/fuzz
+! go test -fuzz=FuzzWithTestdata -run=None -fuzztime=1x
+! stdout ^ok
+! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
+stdout FAIL
+
+# Write a crashing input to the cache
+mkdir $GOCACHE/fuzz/example.com/x/FuzzRunNoneWithCache
+cp cache-file $GOCACHE/fuzz/example.com/x/FuzzRunNoneWithCache/1
+
+# Test that fuzzing a target (with -run=None set) with a failure in the cache
+# prints the crash and writes this as a "new" crash to testdata/fuzz
+! go test -fuzz=FuzzRunNoneWithCache -run=None -fuzztime=1x
+! stdout ^ok
+stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzRunNoneWithCache[/\\]'
+stdout FAIL
+
+# Clear the fuzz cache and make sure it's gone
+go clean -fuzzcache
+! exists $GOCACHE/fuzz
+
+# The tests below should operate the exact same way for the previous tests with
+# a seed corpus (namely, they should still fail). However, the binary is built
+# without instrumentation, so this should be a "testing only" run which executes
+# the seed corpus before attempting to fuzz.
+
+go test -c
+! exec ./x.test$GOEXE -test.fuzz=FuzzWithAdd -test.run=FuzzWithAdd -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache
+! stdout ^ok
+! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
+stdout FAIL
+stderr warning
+
+go test -c
+! exec ./x.test$GOEXE -test.fuzz=FuzzWithTestdata -test.run=FuzzWithTestdata -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache
+! stdout ^ok
+! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
+stdout FAIL
+stderr warning
+
+-- go.mod --
+module example.com/x
+
+go 1.16
+-- x_test.go --
+package x
+
+import "testing"
+
+func FuzzWithAdd(f *testing.F) {
+    f.Add(10)
+    f.Fuzz(func(t *testing.T, i int) {
+        if i == 10 {
+            t.Error("bad thing here")
+        }
+    })
+}
+
+func FuzzWithGoodAdd(f *testing.F) {
+    f.Add(10)
+    f.Fuzz(func(t *testing.T, i int) {
+        if i != 10 {
+            t.Error("bad thing here")
+        }
+    })
+}
+
+func FuzzWithTestdata(f *testing.F) {
+    f.Fuzz(func(t *testing.T, i int) {
+        if i == 10 {
+            t.Error("bad thing here")
+        }
+    })
+}
+
+func FuzzWithNoCache(f *testing.F) {
+    f.Fuzz(func(t *testing.T, i int) {
+        t.Error("bad thing here")
+    })
+}
+
+func FuzzWithCache(f *testing.F) {
+    f.Fuzz(func(t *testing.T, i int) {
+        if i == 10 {
+            t.Error("bad thing here")
+        }
+    })
+}
+
+func FuzzWithMinimizableCache(f *testing.F) {
+    f.Fuzz(func(t *testing.T, b []byte) {
+               if len(b) < 10 {
+                       return
+               }
+               for _, n := range b {
+                       if n != 0 {
+                               if len(b) == 10 {
+                                       t.Log("got the minimum size!")
+                               }
+                               t.Fatalf("contains a non-zero byte of length %d", len(b))
+                       }
+               }
+    })
+}
+
+func FuzzRunNoneWithCache(f *testing.F) {
+    f.Fuzz(func(t *testing.T, i int) {
+        if i == 10 {
+            t.Error("bad thing here")
+        }
+    })
+}
+-- testdata/fuzz/FuzzWithTestdata/1 --
+go test fuzz v1
+int(10)
+-- cache-file --
+go test fuzz v1
+int(10)
+-- cache-file-bytes --
+go test fuzz v1
+[]byte("11111111111111111111")
diff --git a/src/cmd/go/testdata/script/test_fuzz_setenv.txt b/src/cmd/go/testdata/script/test_fuzz_setenv.txt
new file mode 100644 (file)
index 0000000..2924569
--- /dev/null
@@ -0,0 +1,45 @@
+[!fuzz] skip
+[short] skip
+
+go test -fuzz=FuzzA -fuzztime=100x fuzz_setenv_test.go
+
+-- fuzz_setenv_test.go --
+package fuzz
+
+import (
+  "flag"
+  "os"
+  "testing"
+)
+
+func FuzzA(f *testing.F) {
+  if s := os.Getenv("TEST_FUZZ_SETENV_A"); isWorker() && s == "" {
+    f.Fatal("environment variable not set")
+  } else if !isWorker() && s != "" {
+    f.Fatal("environment variable already set")
+  }
+  f.Setenv("TEST_FUZZ_SETENV_A", "A")
+  if os.Getenv("TEST_FUZZ_SETENV_A") == "" {
+    f.Fatal("Setenv did not set environment variable")
+  }
+  f.Fuzz(func(*testing.T, []byte) {})
+}
+
+func FuzzB(f *testing.F) {
+  if os.Getenv("TEST_FUZZ_SETENV_A") != "" {
+    f.Fatal("environment variable not cleared after FuzzA")
+  }
+  f.Skip()
+}
+
+func isWorker() bool {
+       f := flag.Lookup("test.fuzzworker")
+       if f == nil {
+               return false
+       }
+       get, ok := f.Value.(flag.Getter)
+       if !ok {
+               return false
+       }
+       return get.Get() == interface{}(true)
+}
diff --git a/src/cmd/go/testdata/script/test_fuzz_unsupported.txt b/src/cmd/go/testdata/script/test_fuzz_unsupported.txt
new file mode 100644 (file)
index 0000000..1ed0b8a
--- /dev/null
@@ -0,0 +1,18 @@
+[fuzz] skip
+
+! go test -fuzz=. -fuzztime=1x
+! stdout .
+stderr '^-fuzz flag is not supported on '$GOOS'/'$GOARCH'$'
+
+-- go.mod --
+module example
+
+go 1.18
+-- fuzz_test.go --
+package example
+
+import "testing"
+
+func FuzzTrivial(f *testing.F) {
+       f.Fuzz(func(t *testing.T, _ []byte) {})
+}
index 8b1f343a32595495183343d28178850e540f8fc3..a1d47a7dd3c7b544589d22b61b8b8a84679be399 100644 (file)
@@ -15,4 +15,4 @@ go 1.16
 -- pkg/pkg.go --
 package p
 -- stderr.txt --
-go test: -i flag is deprecated
+go: -i flag is deprecated
index 5af26b54f9141bb189bbf15b55edef6fa09c0919..6151f912ae0db150eb1ede771f4628743d12e87a 100644 (file)
@@ -16,6 +16,22 @@ go test -vet=off p1.go
 ! stderr '[\\/]vet.*-shift'
 stdout '\[no test files\]'
 
+# ensure all runs non-default vet
+! go test -vet=all ./vetall/...
+stderr 'using resp before checking for errors'
+
+# Test issue #47309
+! go test -vet=bools,xyz ./vetall/...
+stderr '-vet argument must be a supported analyzer'
+
+# Test with a single analyzer
+! go test -vet=httpresponse ./vetall/...
+stderr 'using resp before checking for errors'
+
+# Test with a list of analyzers
+go test -vet=atomic,bools,nilfunc ./vetall/...
+stdout 'm/vetall.*\[no tests to run\]'
+
 # Test issue #22890
 go test m/vetcycle
 stdout 'm/vetcycle.*\[no test files\]'
@@ -51,6 +67,21 @@ import "fmt"
 func F() {
        fmt.Printf("%d") // oops
 }
+-- vetall/p.go --
+package p
+
+import "net/http"
+
+func F() {
+       resp, err := http.Head("example.com")
+       defer resp.Body.Close()
+       if err != nil {
+               panic(err)
+       }
+       // (defer statement belongs here)
+}
+-- vetall/p_test.go --
+package p
 -- vetcycle/p.go --
 package p
 
index ce2e29f99a7902e0313d58e48353e3aa29c1a086..cdab33c0892bff21c93c41a17d155c711be0eb16 100644 (file)
@@ -2,7 +2,7 @@
 [!exec:git] skip
 env GO111MODULE=off
 
-go get -d github.com/rsc/go-get-issue-11864
+go get github.com/rsc/go-get-issue-11864
 
 go list -f '{{join .TestImports "\n"}}' github.com/rsc/go-get-issue-11864/t
 stdout 'go-get-issue-11864/vendor/vendor.org/p'
index 8615a4aac5978bdf00d8b4c3022a54567cf0cb06..8c08bae7256fb8349e9e260bf1bec19a9a8cf102 100644 (file)
@@ -20,7 +20,7 @@ env GO111MODULE=on
 [short] skip
 
 # Check that 'go version' and 'go version -m' work on a binary built in module mode.
-go get -d rsc.io/fortune
+go get rsc.io/fortune
 go build -o fortune.exe rsc.io/fortune
 go version fortune.exe
 stdout '^fortune.exe: .+'
@@ -28,6 +28,13 @@ go version -m fortune.exe
 stdout '^\tpath\trsc.io/fortune'
 stdout '^\tmod\trsc.io/fortune\tv1.0.0'
 
+# Check the build info of a binary built from $GOROOT/src/cmd
+go build -o test2json.exe cmd/test2json
+go version -m test2json.exe
+stdout '^test2json.exe: .+'
+stdout '^\tpath\tcmd/test2json$'
+! stdout 'mod'
+
 # Repeat the test with -buildmode=pie.
 [!buildmode:pie] stop
 go build -buildmode=pie -o external.exe rsc.io/fortune
diff --git a/src/cmd/go/testdata/script/version_build_settings.txt b/src/cmd/go/testdata/script/version_build_settings.txt
new file mode 100644 (file)
index 0000000..1ced285
--- /dev/null
@@ -0,0 +1,66 @@
+[short] skip
+
+# Compiler name is always added.
+go build
+go version -m m$GOEXE
+stdout '^\tbuild\tcompiler\tgc$'
+! stdout asmflags|gcflags|ldflags|gccgoflags
+
+# Toolchain flags are added if present.
+# The raw flags are included, with package patterns if specified.
+go build -asmflags=example.com/m=-D=FOO=bar
+go version -m m$GOEXE
+stdout '^\tbuild\tasmflags\texample\.com/m=-D=FOO=bar$'
+
+go build -gcflags=example.com/m=-N
+go version -m m$GOEXE
+stdout '^\tbuild\tgcflags\texample\.com/m=-N$'
+
+go build -ldflags=example.com/m=-w
+go version -m m$GOEXE
+stdout '^\tbuild\tldflags\texample\.com/m=-w$'
+
+# gccgoflags are not added when gc is used, and vice versa.
+# TODO: test gccgo.
+go build -gccgoflags=all=UNUSED
+go version -m m$GOEXE
+! stdout gccgoflags
+
+# Build and tool tags are added but not release tags.
+# "race" is included with build tags but not "cgo".
+go build -tags=a,b
+go version -m m$GOEXE
+stdout '^\tbuild\ttags\ta,b(,goexperiment\.[a-z0-9]+)*$'
+[race] go build -race
+[race] go version -m m$GOEXE
+[race] stdout '^\tbuild\ttags\t.*race.*$'
+
+# CGO flags are separate settings.
+# CGO_ENABLED is always present.
+# Other flags are added if CGO_ENABLED is true.
+env CGO_ENABLED=0
+go build
+go version -m m$GOEXE
+stdout '^\tbuild\tCGO_ENABLED\tfalse$'
+! stdout CGO_CPPFLAGS|CGO_CFLAGS|CGO_CXXFLAGS|CGO_LDFLAGS
+[cgo] env CGO_ENABLED=1
+[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1
+[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1
+[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1
+[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist
+[cgo] go build
+[cgo] go version -m m$GOEXE
+[cgo] stdout '^\tbuild\tCGO_ENABLED\ttrue$'
+[cgo] stdout '^\tbuild\tCGO_CPPFLAGS\t-DFROM_CPPFLAGS=1$'
+[cgo] stdout '^\tbuild\tCGO_CFLAGS\t-DFROM_CFLAGS=1$'
+[cgo] stdout '^\tbuild\tCGO_CXXFLAGS\t-DFROM_CXXFLAGS=1$'
+[cgo] stdout '^\tbuild\tCGO_LDFLAGS\t-L/extra/dir/does/not/exist$'
+
+-- go.mod --
+module example.com/m
+
+go 1.18
+-- m.go --
+package main
+
+func main() {}
diff --git a/src/cmd/go/testdata/script/version_buildvcs_bzr.txt b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt
new file mode 100644 (file)
index 0000000..8306971
--- /dev/null
@@ -0,0 +1,104 @@
+# This test checks that VCS information is stamped into Go binaries by default,
+# controlled with -buildvcs. This test focuses on Bazaar specifics.
+# The Git test covers common functionality.
+
+[!exec:bzr] skip
+[short] skip
+env GOBIN=$WORK/gopath/bin
+env oldpath=$PATH
+env HOME=$WORK
+cd repo/a
+exec bzr whoami 'J.R. Gopher <gopher@golang.org>'
+
+# If there's no local repository, there's no VCS info.
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout bzrrevision
+rm $GOBIN/a$GOEXE
+
+# If there is a repository, but it can't be used for some reason,
+# there should be an error. It should hint about -buildvcs=false.
+cd ..
+mkdir .bzr
+env PATH=$WORK${/}fakebin${:}$oldpath
+chmod 0755 $WORK/fakebin/bzr
+! exec bzr help
+cd a
+! go install
+stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$'
+rm $GOBIN/a$GOEXE
+cd ..
+env PATH=$oldpath
+rm .bzr
+
+# If there is an empty repository in a parent directory, only "uncommitted" is tagged.
+exec bzr init
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout bzrrevision
+! stdout bzrcommittime
+stdout '^\tbuild\tbzruncommitted\ttrue$'
+cd ..
+
+# Revision and commit time are tagged for repositories with commits.
+exec bzr add a README
+exec bzr commit -m 'initial commit'
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tbzrrevision\t'
+stdout '^\tbuild\tbzrcommittime\t'
+stdout '^\tbuild\tbzruncommitted\tfalse$'
+rm $GOBIN/a$GOEXE
+
+# Building an earlier commit should still build clean.
+cp ../../outside/empty.txt ../NEWS
+exec bzr add ../NEWS
+exec bzr commit -m 'add NEWS'
+exec bzr update -r1
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tbzrrevision\t'
+stdout '^\tbuild\tbzrcommittime\t'
+stdout '^\tbuild\tbzruncommitted\tfalse$'
+
+# Building with -buildvcs=false suppresses the info.
+go install -buildvcs=false
+go version -m $GOBIN/a$GOEXE
+! stdout bzrrevision
+rm $GOBIN/a$GOEXE
+
+# An untracked file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt .
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tbzruncommitted\ttrue$'
+rm empty.txt
+rm $GOBIN/a$GOEXE
+
+# An edited file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt ../README
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tbzruncommitted\ttrue$'
+exec bzr revert ../README
+rm $GOBIN/a$GOEXE
+
+-- $WORK/fakebin/bzr --
+#!/bin/sh
+exit 1
+-- $WORK/fakebin/bzr.bat --
+exit 1
+-- repo/README --
+Far out in the uncharted backwaters of the unfashionable end of the western
+spiral arm of the Galaxy lies a small, unregarded yellow sun.
+-- repo/a/go.mod --
+module example.com/a
+
+go 1.18
+-- repo/a/a.go --
+package main
+
+func main() {}
+-- outside/empty.txt --
diff --git a/src/cmd/go/testdata/script/version_buildvcs_fossil.txt b/src/cmd/go/testdata/script/version_buildvcs_fossil.txt
new file mode 100644 (file)
index 0000000..3a4bde8
--- /dev/null
@@ -0,0 +1,90 @@
+# This test checks that VCS information is stamped into Go binaries by default,
+# controlled with -buildvcs. This test focuses on Fossil specifics.
+# The Git test covers common functionality.
+
+# "fossil" is the Fossil file server on Plan 9.
+[plan9] skip
+[!exec:fossil] skip
+[short] skip
+env GOBIN=$WORK/gopath/bin
+env oldpath=$PATH
+env HOME=$WORK
+env USER=gopher
+[!windows] env fslckout=.fslckout
+[windows] env fslckout=_FOSSIL_
+exec pwd
+exec fossil init repo.fossil
+cd repo/a
+
+# If there's no local repository, there's no VCS info.
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout fossilrevision
+rm $GOBIN/a$GOEXE
+
+# If there is a repository, but it can't be used for some reason,
+# there should be an error. It should hint about -buildvcs=false.
+cd ..
+mkdir $fslckout
+env PATH=$WORK${/}fakebin${:}$oldpath
+chmod 0755 $WORK/fakebin/fossil
+! exec fossil help
+cd a
+! go install
+stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$'
+rm $GOBIN/a$GOEXE
+cd ..
+env PATH=$oldpath
+rm $fslckout
+
+# Revision and commit time are tagged for repositories with commits.
+exec fossil open ../repo.fossil -f
+exec fossil add a README
+exec fossil commit -m 'initial commit'
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tfossilrevision\t'
+stdout '^\tbuild\tfossilcommittime\t'
+stdout '^\tbuild\tfossiluncommitted\tfalse$'
+rm $GOBIN/a$GOEXE
+
+# Building with -buildvcs=false suppresses the info.
+go install -buildvcs=false
+go version -m $GOBIN/a$GOEXE
+! stdout fossilrevision
+rm $GOBIN/a$GOEXE
+
+# An untracked file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt .
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tfossiluncommitted\ttrue$'
+rm empty.txt
+rm $GOBIN/a$GOEXE
+
+# An edited file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt ../README
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tfossiluncommitted\ttrue$'
+exec fossil revert ../README
+rm $GOBIN/a$GOEXE
+
+-- $WORK/fakebin/fossil --
+#!/bin/sh
+exit 1
+-- $WORK/fakebin/fossil.bat --
+exit 1
+-- repo/README --
+Far out in the uncharted backwaters of the unfashionable end of the western
+spiral arm of the Galaxy lies a small, unregarded yellow sun.
+-- repo/a/go.mod --
+module example.com/a
+
+go 1.18
+-- repo/a/a.go --
+package main
+
+func main() {}
+-- outside/empty.txt --
diff --git a/src/cmd/go/testdata/script/version_buildvcs_git.txt b/src/cmd/go/testdata/script/version_buildvcs_git.txt
new file mode 100644 (file)
index 0000000..3d56c6d
--- /dev/null
@@ -0,0 +1,144 @@
+# This test checks that VCS information is stamped into Go binaries by default,
+# controlled with -buildvcs. This test focuses on Git. Other tests focus on
+# other VCS tools but may not cover common functionality.
+
+[!exec:git] skip
+[short] skip
+env GOBIN=$WORK/gopath/bin
+env oldpath=$PATH
+cd repo/a
+
+# If there's no local repository, there's no VCS info.
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout gitrevision
+rm $GOBIN/a$GOEXE
+
+# If there is a repository, but it can't be used for some reason,
+# there should be an error. It should hint about -buildvcs=false.
+cd ..
+mkdir .git
+env PATH=$WORK${/}fakebin${:}$oldpath
+chmod 0755 $WORK/fakebin/git
+! exec git help
+cd a
+! go install
+stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$'
+cd ..
+env PATH=$oldpath
+rm .git
+
+# If there is an empty repository in a parent directory, only "uncommitted" is tagged.
+exec git init
+exec git config user.email gopher@golang.org
+exec git config user.name 'J.R. Gopher'
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout gitrevision
+! stdout gitcommittime
+stdout '^\tbuild\tgituncommitted\ttrue$'
+rm $GOBIN/a$GOEXE
+
+# Revision and commit time are tagged for repositories with commits.
+exec git add -A
+exec git commit -m 'initial commit'
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tgitrevision\t'
+stdout '^\tbuild\tgitcommittime\t'
+stdout '^\tbuild\tgituncommitted\tfalse$'
+rm $GOBIN/a$GOEXE
+
+# Building with -buildvcs=false suppresses the info.
+go install -buildvcs=false
+go version -m $GOBIN/a$GOEXE
+! stdout gitrevision
+rm $GOBIN/a$GOEXE
+
+# An untracked file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt .
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tgituncommitted\ttrue$'
+rm empty.txt
+rm $GOBIN/a$GOEXE
+
+# An edited file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt ../README
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\tgituncommitted\ttrue$'
+exec git checkout ../README
+rm $GOBIN/a$GOEXE
+
+# If the build doesn't include any packages from the repository,
+# there should be no VCS info.
+go install example.com/cmd/a@v1.0.0
+go version -m $GOBIN/a$GOEXE
+! stdout gitrevision
+rm $GOBIN/a$GOEXE
+
+go mod edit -require=example.com/c@v0.0.0
+go mod edit -replace=example.com/c@v0.0.0=../../outside/c
+go install example.com/c
+go version -m $GOBIN/c$GOEXE
+! stdout gitrevision
+rm $GOBIN/c$GOEXE
+exec git checkout go.mod
+
+# If the build depends on a package in the repository, but it's not in the
+# main module, there should be no VCS info.
+go mod edit -require=example.com/b@v0.0.0
+go mod edit -replace=example.com/b@v0.0.0=../b
+go mod edit -require=example.com/d@v0.0.0
+go mod edit -replace=example.com/d@v0.0.0=../../outside/d
+go install example.com/d
+go version -m $GOBIN/d$GOEXE
+! stdout gitrevision
+exec git checkout go.mod
+rm $GOBIN/d$GOEXE
+
+-- $WORK/fakebin/git --
+#!/bin/sh
+exit 1
+-- $WORK/fakebin/git.bat --
+exit 1
+-- repo/README --
+Far out in the uncharted backwaters of the unfashionable end of the western
+spiral arm of the Galaxy lies a small, unregarded yellow sun.
+-- repo/a/go.mod --
+module example.com/a
+
+go 1.18
+-- repo/a/a.go --
+package main
+
+func main() {}
+-- repo/b/go.mod --
+module example.com/b
+
+go 1.18
+-- repo/b/b.go --
+package b
+-- outside/empty.txt --
+-- outside/c/go.mod --
+module example.com/c
+
+go 1.18
+-- outside/c/main.go --
+package main
+
+func main() {}
+-- outside/d/go.mod --
+module example.com/d
+
+go 1.18
+
+require example.com/b v0.0.0
+-- outside/d/main.go --
+package main
+
+import _ "example.com/b"
+
+func main() {}
diff --git a/src/cmd/go/testdata/script/version_buildvcs_hg.txt b/src/cmd/go/testdata/script/version_buildvcs_hg.txt
new file mode 100644 (file)
index 0000000..df49387
--- /dev/null
@@ -0,0 +1,91 @@
+# This test checks that VCS information is stamped into Go binaries by default,
+# controlled with -buildvcs. This test focuses on Mercurial specifics.
+# The Git test covers common functionality.
+
+[!exec:hg] skip
+[short] skip
+env GOBIN=$WORK/gopath/bin
+env oldpath=$PATH
+cd repo/a
+
+# If there's no local repository, there's no VCS info.
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout hgrevision
+rm $GOBIN/a$GOEXE
+
+# If there is a repository, but it can't be used for some reason,
+# there should be an error. It should hint about -buildvcs=false.
+cd ..
+mkdir .hg
+env PATH=$WORK${/}fakebin${:}$oldpath
+chmod 0755 $WORK/fakebin/hg
+! exec hg help
+cd a
+! go install
+stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$'
+rm $GOBIN/a$GOEXE
+cd ..
+env PATH=$oldpath
+rm .hg
+
+# If there is an empty repository in a parent directory, only "uncommitted" is tagged.
+exec hg init
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+! stdout hgrevision
+! stdout hgcommittime
+stdout '^\tbuild\thguncommitted\ttrue$'
+cd ..
+
+# Revision and commit time are tagged for repositories with commits.
+exec hg add a README
+exec hg commit -m 'initial commit'
+cd a
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\thgrevision\t'
+stdout '^\tbuild\thgcommittime\t'
+stdout '^\tbuild\thguncommitted\tfalse$'
+rm $GOBIN/a$GOEXE
+
+# Building with -buildvcs=false suppresses the info.
+go install -buildvcs=false
+go version -m $GOBIN/a$GOEXE
+! stdout hgrevision
+rm $GOBIN/a$GOEXE
+
+# An untracked file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt .
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\thguncommitted\ttrue$'
+rm empty.txt
+rm $GOBIN/a$GOEXE
+
+# An edited file is shown as uncommitted, even if it isn't part of the build.
+cp ../../outside/empty.txt ../README
+go install
+go version -m $GOBIN/a$GOEXE
+stdout '^\tbuild\thguncommitted\ttrue$'
+exec hg revert ../README
+rm $GOBIN/a$GOEXE
+
+-- $WORK/fakebin/hg --
+#!/bin/sh
+exit 1
+-- $WORK/fakebin/hg.bat --
+exit 1
+-- repo/README --
+Far out in the uncharted backwaters of the unfashionable end of the western
+spiral arm of the Galaxy lies a small, unregarded yellow sun.
+-- repo/a/go.mod --
+module example.com/a
+
+go 1.18
+-- repo/a/a.go --
+package main
+
+func main() {}
+-- outside/empty.txt --
diff --git a/src/cmd/go/testdata/script/version_buildvcs_nested.txt b/src/cmd/go/testdata/script/version_buildvcs_nested.txt
new file mode 100644 (file)
index 0000000..08d4c92
--- /dev/null
@@ -0,0 +1,51 @@
+[!exec:git] skip
+[!exec:hg] skip
+[short] skip
+env GOFLAGS=-n
+
+# Create a root module in a root Git repository.
+mkdir root
+cd root
+go mod init example.com/root
+exec git init
+
+# Nesting repositories in parent directories are ignored, as the current
+# directory main package, and containing main module are in the same repository.
+# This is an error in GOPATH mode (to prevent VCS injection), but for modules,
+# we assume users have control over repositories they've checked out.
+mkdir hgsub
+cd hgsub
+exec hg init
+cp ../../main.go main.go
+! go build
+stderr '^error obtaining VCS status: main module is in repository ".*root" but current directory is in repository ".*hgsub"$'
+stderr '^\tUse -buildvcs=false to disable VCS stamping.$'
+go build -buildvcs=false
+go mod init example.com/root/hgsub
+go build
+cd ..
+
+# It's an error to build a package from a nested Git repository if the package
+# is in a separate repository from the current directory or from the module
+# root directory.
+mkdir gitsub
+cd gitsub
+exec git init
+exec git config user.name 'J.R.Gopher'
+exec git config user.email 'gopher@golang.org'
+cp ../../main.go main.go
+! go build
+stderr '^error obtaining VCS status: main module is in repository ".*root" but current directory is in repository ".*gitsub"$'
+go build -buildvcs=false
+go mod init example.com/root/gitsub
+exec git commit --allow-empty -m empty # status commands fail without this
+go build
+rm go.mod
+cd ..
+! go build ./gitsub
+stderr '^error obtaining VCS status: main package is in repository ".*gitsub" but current directory is in repository ".*root"$'
+go build -buildvcs=false -o=gitsub${/} ./gitsub
+
+-- main.go --
+package main
+func main() {}
index ec98f4e3f3ac260341468fd91374a36eaff28cf6..82b8504458be9af7fd5da4322c2b5fa7307bd605 100644 (file)
@@ -1,7 +1,7 @@
 [short] skip
 
 go mod download example.com/printversion@v0.1.0 example.com/printversion@v1.0.0
-go get -d example.com/printversion@v0.1.0
+go get example.com/printversion@v0.1.0
 go install example.com/printversion
 
 go run example.com/printversion
diff --git a/src/cmd/go/testdata/script/work.txt b/src/cmd/go/testdata/script/work.txt
new file mode 100644 (file)
index 0000000..613f037
--- /dev/null
@@ -0,0 +1,147 @@
+! go mod initwork doesnotexist
+stderr 'go: creating workspace file: no go.mod file exists in directory doesnotexist'
+go env GOWORK
+! stdout .
+
+go mod initwork ./a ./b
+cmp go.work go.work.want
+go env GOWORK
+stdout '^'$WORK'(\\|/)gopath(\\|/)src(\\|/)go.work$'
+
+! go run  example.com/b
+stderr 'a(\\|/)a.go:4:8: no required module provides package rsc.io/quote; to add it:\n\tcd '$WORK(\\|/)gopath(\\|/)src(\\|/)a'\n\tgo get rsc.io/quote'
+cd a
+go get rsc.io/quote
+go env GOMOD # go env GOMOD reports the module in a single module context
+stdout $GOPATH(\\|/)src(\\|/)a(\\|/)go.mod
+cd ..
+go run example.com/b
+stdout 'Hello, world.'
+
+# And try from a different directory
+cd c
+go run  example.com/b
+stdout 'Hello, world.'
+cd $GOPATH/src
+
+go list all # all includes both modules
+stdout 'example.com/a'
+stdout 'example.com/b'
+
+# -mod can only be set to readonly in workspace mode
+go list -mod=readonly all
+! go list -mod=mod all
+stderr '^go: -mod may only be set to readonly when in workspace mode'
+go list -mod=mod -workfile=off all
+
+# Test that duplicates in the directory list return an error
+cp go.work go.work.backup
+cp go.work.dup go.work
+! go run example.com/b
+stderr 'reading go.work: path .* appears multiple times in workspace'
+cp go.work.backup go.work
+
+cp go.work.d go.work
+go run example.com/d
+
+# Test that we don't run into "newRequirements called with unsorted roots"
+# panic with unsorted main modules.
+cp go.work.backwards go.work
+go run example.com/d
+
+# Test that command-line-arguments work inside and outside modules.
+# This exercises the code that determines which module command-line-arguments
+# belongs to.
+go list ./b/main.go
+go build -n -workfile=off -o foo foo.go
+go build -n -o foo foo.go
+
+-- go.work.dup --
+go 1.18
+
+directory (
+  a
+  b
+  ../src/a
+)
+-- go.work.want --
+go 1.18
+
+directory (
+       ./a
+       ./b
+)
+-- go.work.d --
+go 1.18
+
+directory (
+       a
+       b
+       d
+)
+-- a/go.mod --
+
+module example.com/a
+
+-- a/a.go --
+package a
+
+import "fmt"
+import "rsc.io/quote"
+
+func HelloFromA() {
+  fmt.Println(quote.Hello())
+}
+
+-- b/go.mod --
+
+module example.com/b
+
+-- b/main.go --
+package main
+
+import "example.com/a"
+
+func main() {
+  a.HelloFromA()
+}
+-- b/lib/hello.go --
+package lib
+
+import "example.com/a"
+
+func Hello() {
+       a.HelloFromA()
+}
+
+-- c/README --
+Create this directory so we can cd to
+it and make sure paths are interpreted
+relative to the go.work, not the cwd.
+-- d/go.mod --
+module example.com/d
+
+-- d/main.go --
+package main
+
+import "example.com/b/lib"
+
+func main() {
+       lib.Hello()
+}
+
+-- go.work.backwards --
+go 1.18
+
+directory (
+    d
+    b
+    a
+)
+
+-- foo.go --
+package main
+import "fmt"
+func main() {
+       fmt.Println("Hello, World")
+}
diff --git a/src/cmd/go/testdata/script/work_edit.txt b/src/cmd/go/testdata/script/work_edit.txt
new file mode 100644 (file)
index 0000000..979c1f9
--- /dev/null
@@ -0,0 +1,161 @@
+# Test editing go.work files.
+
+go mod initwork m
+cmp go.work go.work.want_initial
+
+go mod editwork -directory n
+cmp go.work go.work.want_directory_n
+
+go mod editwork -go 1.18
+cmp go.work go.work.want_go_118
+
+go mod editwork -dropdirectory m
+cmp go.work go.work.want_dropdirectory_m
+
+go mod editwork -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z'
+cmp go.work go.work.want_add_replaces
+
+go mod editwork -directory n -directory ../a -directory /b -directory c -directory c
+cmp go.work go.work.want_multidirectory
+
+go mod editwork -dropdirectory /b -dropdirectory n
+cmp go.work go.work.want_multidropdirectory
+
+go mod editwork -dropreplace='x.1@v1.4.0'
+cmp go.work go.work.want_dropreplace
+
+go mod editwork -print -go 1.19 -directory b -dropdirectory c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
+cmp stdout go.work.want_print
+
+go mod editwork -json -go 1.19 -directory b -dropdirectory c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
+cmp stdout go.work.want_json
+
+go mod editwork -print -fmt -workfile $GOPATH/src/unformatted
+cmp stdout formatted
+
+-- m/go.mod --
+module m
+
+go 1.18
+-- go.work.want_initial --
+go 1.18
+
+directory ./m
+-- go.work.want_directory_n --
+go 1.18
+
+directory (
+       ./m
+       ./n
+)
+-- go.work.want_go_118 --
+go 1.18
+
+directory (
+       ./m
+       ./n
+)
+-- go.work.want_dropdirectory_m --
+go 1.18
+
+directory ./n
+-- go.work.want_add_replaces --
+go 1.18
+
+directory ./n
+
+replace (
+       x.1 v1.3.0 => y.1 v1.4.0
+       x.1 v1.4.0 => ../z
+)
+-- go.work.want_multidirectory --
+go 1.18
+
+directory (
+       ../a
+       ./c
+       ./n
+       /b
+)
+
+replace (
+       x.1 v1.3.0 => y.1 v1.4.0
+       x.1 v1.4.0 => ../z
+)
+-- go.work.want_multidropdirectory --
+go 1.18
+
+directory (
+       ../a
+       ./c
+)
+
+replace (
+       x.1 v1.3.0 => y.1 v1.4.0
+       x.1 v1.4.0 => ../z
+)
+-- go.work.want_dropreplace --
+go 1.18
+
+directory (
+       ../a
+       ./c
+)
+
+replace x.1 v1.3.0 => y.1 v1.4.0
+-- go.work.want_print --
+go 1.19
+
+directory (
+       ../a
+       ./b
+)
+
+replace x.1 v1.4.0 => ../z
+-- go.work.want_json --
+{
+       "Go": "1.19",
+       "Directory": [
+               {
+                       "DiskPath": "../a"
+               },
+               {
+                       "DiskPath": "./b"
+               }
+       ],
+       "Replace": [
+               {
+                       "Old": {
+                               "Path": "x.1",
+                               "Version": "v1.4.0"
+                       },
+                       "New": {
+                               "Path": "../z"
+                       }
+               }
+       ]
+}
+-- unformatted --
+go 1.18
+ directory (
+ a
+  b
+  c
+  )
+  replace (
+  x.1 v1.3.0 => y.1 v1.4.0
+                            x.1 v1.4.0 => ../z
+                            )
+-- formatted --
+go 1.18
+
+directory (
+       a
+       b
+       c
+)
+
+replace (
+       x.1 v1.3.0 => y.1 v1.4.0
+       x.1 v1.4.0 => ../z
+)
\ No newline at end of file
diff --git a/src/cmd/go/testdata/script/work_env.txt b/src/cmd/go/testdata/script/work_env.txt
new file mode 100644 (file)
index 0000000..de67255
--- /dev/null
@@ -0,0 +1,24 @@
+go env GOWORK
+stdout '^'$GOPATH'[\\/]src[\\/]go.work$'
+go env
+stdout '^(set )?GOWORK="?'$GOPATH'[\\/]src[\\/]go.work"?$'
+
+cd ..
+go env GOWORK
+! stdout .
+go env
+stdout 'GOWORK=("")?'
+
+cd src
+go env GOWORK
+stdout 'go.work'
+
+! go env -w GOWORK=off
+stderr '^go: GOWORK cannot be modified$'
+
+-- go.work --
+go 1.18
+
+directory a
+-- a/go.mod --
+module example.com/a
diff --git a/src/cmd/go/testdata/script/work_prune.txt b/src/cmd/go/testdata/script/work_prune.txt
new file mode 100644 (file)
index 0000000..f0fb073
--- /dev/null
@@ -0,0 +1,104 @@
+# This test makes sure workspace mode's handling of the module graph
+# is compatible with module pruning. The graph we load from either of
+# the workspace modules should be the same, even if their graphs
+# don't overlap.
+#
+# This is the module graph in the test:
+#
+#  example.com/a -> example.com/b v1.0.0 -> example.com/q v1.1.0
+#  example.com/p -> example.com/q v1.0.0
+#
+# If we didn't load the whole graph and didn't load the dependencies of b
+# when loading p, we would end up loading q v1.0.0, rather than v1.1.0,
+# which is selected by MVS.
+# TODO(#48331): We currently load the wrong version of q. Fix this.
+
+go list -m -f '{{.Version}}' example.com/q
+stdout '^v1.0.0$' # TODO(#48331): This should be 1.1.0. Fix this.
+
+-- go.work --
+go 1.18
+
+directory (
+       ./a
+       ./p
+)
+-- a/go.mod --
+module example.com/a
+
+go 1.18
+
+require example.com/b v1.0.0
+
+replace example.com/b v1.0.0 => ../b
+-- a/foo.go --
+package main
+
+import "example.com/b"
+
+func main() {
+       b.B()
+}
+-- b/go.mod --
+module example.com/b
+
+go 1.18
+
+require example.com/q v1.1.0
+
+replace example.com/q v1.0.0 => ../q1_0_0
+replace example.com/q v1.1.0 => ../q1_1_0
+-- b/b.go --
+package b
+
+func B() {
+}
+-- b/b_test.go --
+package b
+
+import "example.com/q"
+
+func TestB() {
+       q.PrintVersion()
+}
+-- p/go.mod --
+module example.com/p
+
+go 1.18
+
+require example.com/q v1.0.0
+
+replace example.com/q v1.0.0 => ../q1_0_0
+replace example.com/q v1.1.0 => ../q1_1_0
+-- p/main.go --
+package main
+
+import "example.com/q"
+
+func main() {
+       q.PrintVersion()
+}
+-- q1_0_0/go.mod --
+module example.com/q
+
+go 1.18
+-- q1_0_0/q.go --
+package q
+
+import "fmt"
+
+func PrintVersion() {
+       fmt.Println("version 1.0.0")
+}
+-- q1_1_0/go.mod --
+module example.com/q
+
+go 1.18
+-- q1_1_0/q.go --
+package q
+
+import "fmt"
+
+func PrintVersion() {
+       fmt.Println("version 1.1.0")
+}
diff --git a/src/cmd/go/testdata/script/work_replace.txt b/src/cmd/go/testdata/script/work_replace.txt
new file mode 100644 (file)
index 0000000..5a4cb0e
--- /dev/null
@@ -0,0 +1,55 @@
+# Support replace statement in go.work file
+
+# Replacement in go.work file, and none in go.mod file.
+go list -m example.com/dep
+stdout 'example.com/dep v1.0.0 => ./dep'
+
+# Wildcard replacement in go.work file overrides version replacement in go.mod
+# file.
+go list -m example.com/other
+stdout 'example.com/other v1.0.0 => ./other2'
+
+-- go.work --
+directory m
+
+replace example.com/dep => ./dep
+replace example.com/other => ./other2
+
+-- m/go.mod --
+module example.com/m
+
+require example.com/dep v1.0.0
+require example.com/other v1.0.0
+
+replace example.com/other v1.0.0 => ./other
+-- m/m.go --
+package m
+
+import "example.com/dep"
+import "example.com/other"
+
+func F() {
+       dep.G()
+       other.H()
+}
+-- dep/go.mod --
+module example.com/dep
+-- dep/dep.go --
+package dep
+
+func G() {
+}
+-- other/go.mod --
+module example.com/other
+-- other/dep.go --
+package other
+
+func G() {
+}
+-- other2/go.mod --
+module example.com/other
+-- other2/dep.go --
+package other
+
+func G() {
+}
\ No newline at end of file
diff --git a/src/cmd/go/testdata/script/work_replace_conflict.txt b/src/cmd/go/testdata/script/work_replace_conflict.txt
new file mode 100644 (file)
index 0000000..a2f76d1
--- /dev/null
@@ -0,0 +1,53 @@
+# Conflicting replaces in workspace modules returns error that suggests
+# overriding it in the go.work file.
+
+! go list -m example.com/dep
+stderr 'go: conflicting replacements for example.com/dep@v1.0.0:\n\t./dep1\n\t./dep2\nuse "go mod editwork -replace example.com/dep@v1.0.0=\[override\]" to resolve'
+go mod editwork -replace example.com/dep@v1.0.0=./dep1
+go list -m example.com/dep
+stdout 'example.com/dep v1.0.0 => ./dep1'
+
+-- foo --
+-- go.work --
+directory m
+directory n
+-- m/go.mod --
+module example.com/m
+
+require example.com/dep v1.0.0
+replace example.com/dep v1.0.0 => ./dep1
+-- m/m.go --
+package m
+
+import "example.com/dep"
+
+func F() {
+       dep.G()
+}
+-- n/go.mod --
+module example.com/n
+
+require example.com/dep v1.0.0
+replace example.com/dep v1.0.0 => ./dep2
+-- n/n.go --
+package n
+
+import "example.com/dep"
+
+func F() {
+       dep.G()
+}
+-- dep1/go.mod --
+module example.com/dep
+-- dep1/dep.go --
+package dep
+
+func G() {
+}
+-- dep2/go.mod --
+module example.com/dep
+-- dep2/dep.go --
+package dep
+
+func G() {
+}
diff --git a/src/cmd/go/testdata/script/work_replace_conflict_override.txt b/src/cmd/go/testdata/script/work_replace_conflict_override.txt
new file mode 100644 (file)
index 0000000..ebb517d
--- /dev/null
@@ -0,0 +1,57 @@
+# Conflicting workspace module replaces can be overridden by a replace in the
+# go.work file.
+
+go list -m example.com/dep
+stdout 'example.com/dep v1.0.0 => ./dep3'
+
+-- go.work --
+directory m
+directory n
+replace example.com/dep => ./dep3
+-- m/go.mod --
+module example.com/m
+
+require example.com/dep v1.0.0
+replace example.com/dep => ./dep1
+-- m/m.go --
+package m
+
+import "example.com/dep"
+
+func F() {
+       dep.G()
+}
+-- n/go.mod --
+module example.com/n
+
+require example.com/dep v1.0.0
+replace example.com/dep => ./dep2
+-- n/n.go --
+package n
+
+import "example.com/dep"
+
+func F() {
+       dep.G()
+}
+-- dep1/go.mod --
+module example.com/dep
+-- dep1/dep.go --
+package dep
+
+func G() {
+}
+-- dep2/go.mod --
+module example.com/dep
+-- dep2/dep.go --
+package dep
+
+func G() {
+}
+-- dep3/go.mod --
+module example.com/dep
+-- dep3/dep.go --
+package dep
+
+func G() {
+}
diff --git a/src/cmd/go/testdata/script/work_sum.txt b/src/cmd/go/testdata/script/work_sum.txt
new file mode 100644 (file)
index 0000000..99f66a4
--- /dev/null
@@ -0,0 +1,33 @@
+# Test adding sums to go.work.sum when sum isn't in go.mod.
+
+go run .
+cmp go.work.sum want.sum
+
+-- want.sum --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- go.work --
+go 1.18
+
+directory .
+-- go.mod --
+go 1.18
+
+module example.com/hi
+
+require "rsc.io/quote" v1.5.2
+-- main.go --
+package main
+
+import (
+       "fmt"
+       "rsc.io/quote"
+)
+
+func main() {
+       fmt.Println(quote.Hello())
+}
\ No newline at end of file
index b3c120daab42c41c824c91f6bd901b3eeda25a0c..860d77aaf04085a28b69f31a765a968ae1d56eed 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "bytes"
+       "context"
        "flag"
        "fmt"
        "go/ast"
@@ -22,6 +23,8 @@ import (
        "strings"
 
        "cmd/internal/diff"
+
+       "golang.org/x/sync/semaphore"
 )
 
 var (
@@ -50,17 +53,10 @@ const (
 )
 
 var (
-       fileSet    = token.NewFileSet() // per process FileSet
-       exitCode   = 0
-       rewrite    func(*ast.File) *ast.File
+       rewrite    func(*token.FileSet, *ast.File) *ast.File
        parserMode parser.Mode
 )
 
-func report(err error) {
-       scanner.PrintError(os.Stderr, err)
-       exitCode = 2
-}
-
 func usage() {
        fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
        flag.PrintDefaults()
@@ -76,41 +72,211 @@ func initParserMode() {
 func isGoFile(f fs.DirEntry) bool {
        // ignore non-Go files
        name := f.Name()
-       return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
+       return !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && !f.IsDir()
+}
+
+// A sequencer performs concurrent tasks that may write output, but emits that
+// output in a deterministic order.
+type sequencer struct {
+       maxWeight int64
+       sem       *semaphore.Weighted   // weighted by input bytes (an approximate proxy for memory overhead)
+       prev      <-chan *reporterState // 1-buffered
+}
+
+// newSequencer returns a sequencer that allows concurrent tasks up to maxWeight
+// and writes tasks' output to out and err.
+func newSequencer(maxWeight int64, out, err io.Writer) *sequencer {
+       sem := semaphore.NewWeighted(maxWeight)
+       prev := make(chan *reporterState, 1)
+       prev <- &reporterState{out: out, err: err}
+       return &sequencer{
+               maxWeight: maxWeight,
+               sem:       sem,
+               prev:      prev,
+       }
+}
+
+// exclusive is a weight that can be passed to a sequencer to cause
+// a task to be executed without any other concurrent tasks.
+const exclusive = -1
+
+// Add blocks until the sequencer has enough weight to spare, then adds f as a
+// task to be executed concurrently.
+//
+// If the weight is either negative or larger than the sequencer's maximum
+// weight, Add blocks until all other tasks have completed, then the task
+// executes exclusively (blocking all other calls to Add until it completes).
+//
+// f may run concurrently in a goroutine, but its output to the passed-in
+// reporter will be sequential relative to the other tasks in the sequencer.
+//
+// If f invokes a method on the reporter, execution of that method may block
+// until the previous task has finished. (To maximize concurrency, f should
+// avoid invoking the reporter until it has finished any parallelizable work.)
+//
+// If f returns a non-nil error, that error will be reported after f's output
+// (if any) and will cause a nonzero final exit code.
+func (s *sequencer) Add(weight int64, f func(*reporter) error) {
+       if weight < 0 || weight > s.maxWeight {
+               weight = s.maxWeight
+       }
+       if err := s.sem.Acquire(context.TODO(), weight); err != nil {
+               // Change the task from "execute f" to "report err".
+               weight = 0
+               f = func(*reporter) error { return err }
+       }
+
+       r := &reporter{prev: s.prev}
+       next := make(chan *reporterState, 1)
+       s.prev = next
+
+       // Start f in parallel: it can run until it invokes a method on r, at which
+       // point it will block until the previous task releases the output state.
+       go func() {
+               if err := f(r); err != nil {
+                       r.Report(err)
+               }
+               next <- r.getState() // Release the next task.
+               s.sem.Release(weight)
+       }()
+}
+
+// AddReport prints an error to s after the output of any previously-added
+// tasks, causing the final exit code to be nonzero.
+func (s *sequencer) AddReport(err error) {
+       s.Add(0, func(*reporter) error { return err })
+}
+
+// GetExitCode waits for all previously-added tasks to complete, then returns an
+// exit code for the sequence suitable for passing to os.Exit.
+func (s *sequencer) GetExitCode() int {
+       c := make(chan int, 1)
+       s.Add(0, func(r *reporter) error {
+               c <- r.ExitCode()
+               return nil
+       })
+       return <-c
+}
+
+// A reporter reports output, warnings, and errors.
+type reporter struct {
+       prev  <-chan *reporterState
+       state *reporterState
+}
+
+// reporterState carries the state of a reporter instance.
+//
+// Only one reporter at a time may have access to a reporterState.
+type reporterState struct {
+       out, err io.Writer
+       exitCode int
+}
+
+// getState blocks until any prior reporters are finished with the reporter
+// state, then returns the state for manipulation.
+func (r *reporter) getState() *reporterState {
+       if r.state == nil {
+               r.state = <-r.prev
+       }
+       return r.state
 }
 
+// Warnf emits a warning message to the reporter's error stream,
+// without changing its exit code.
+func (r *reporter) Warnf(format string, args ...interface{}) {
+       fmt.Fprintf(r.getState().err, format, args...)
+}
+
+// Write emits a slice to the reporter's output stream.
+//
+// Any error is returned to the caller, and does not otherwise affect the
+// reporter's exit code.
+func (r *reporter) Write(p []byte) (int, error) {
+       return r.getState().out.Write(p)
+}
+
+// Report emits a non-nil error to the reporter's error stream,
+// changing its exit code to a nonzero value.
+func (r *reporter) Report(err error) {
+       if err == nil {
+               panic("Report with nil error")
+       }
+       st := r.getState()
+       scanner.PrintError(st.err, err)
+       st.exitCode = 2
+}
+
+func (r *reporter) ExitCode() int {
+       return r.getState().exitCode
+}
+
+// If info == nil, we are formatting stdin instead of a file.
 // If in == nil, the source is the contents of the file with the given filename.
-func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
-       var perm fs.FileMode = 0644
+func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) error {
        if in == nil {
-               f, err := os.Open(filename)
+               var err error
+               in, err = os.Open(filename)
                if err != nil {
                        return err
                }
-               defer f.Close()
-               fi, err := f.Stat()
+       }
+
+       // Compute the file's size and read its contents with minimal allocations.
+       //
+       // If the size is unknown (or bogus, or overflows an int), fall back to
+       // a size-independent ReadAll.
+       var src []byte
+       size := -1
+       if info != nil && info.Mode().IsRegular() && int64(int(info.Size())) == info.Size() {
+               size = int(info.Size())
+       }
+       if size+1 > 0 {
+               // If we have the FileInfo from filepath.WalkDir, use it to make
+               // a buffer of the right size and avoid ReadAll's reallocations.
+               //
+               // We try to read size+1 bytes so that we can detect modifications: if we
+               // read more than size bytes, then the file was modified concurrently.
+               // (If that happens, we could, say, append to src to finish the read, or
+               // proceed with a truncated buffer — but the fact that it changed at all
+               // indicates a possible race with someone editing the file, so we prefer to
+               // stop to avoid corrupting it.)
+               src = make([]byte, size+1)
+               n, err := io.ReadFull(in, src)
+               if err != nil && err != io.ErrUnexpectedEOF {
+                       return err
+               }
+               if n < size {
+                       return fmt.Errorf("error: size of %s changed during reading (from %d to %d bytes)", filename, size, n)
+               } else if n > size {
+                       return fmt.Errorf("error: size of %s changed during reading (from %d to >=%d bytes)", filename, size, len(src))
+               }
+               src = src[:n]
+       } else {
+               // The file is not known to be regular, so we don't have a reliable size for it.
+               var err error
+               src, err = io.ReadAll(in)
                if err != nil {
                        return err
                }
-               in = f
-               perm = fi.Mode().Perm()
        }
 
-       src, err := io.ReadAll(in)
-       if err != nil {
-               return err
+       fileSet := token.NewFileSet()
+       fragmentOk := false
+       if info == nil {
+               // If we are formatting stdin, we accept a program fragment in lieu of a
+               // complete source file.
+               fragmentOk = true
        }
-
-       file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
+       file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, fragmentOk)
        if err != nil {
                return err
        }
 
        if rewrite != nil {
                if sourceAdj == nil {
-                       file = rewrite(file)
+                       file = rewrite(fileSet, file)
                } else {
-                       fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
+                       r.Warnf("warning: rewrite ignored for incomplete programs\n")
                }
        }
 
@@ -128,10 +294,14 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
        if !bytes.Equal(src, res) {
                // formatting has changed
                if *list {
-                       fmt.Fprintln(out, filename)
+                       fmt.Fprintln(r, filename)
                }
                if *write {
+                       if info == nil {
+                               panic("-w should not have been allowed with stdin")
+                       }
                        // make a temporary backup before overwriting original
+                       perm := info.Mode().Perm()
                        bakname, err := backupFile(filename+".", src, perm)
                        if err != nil {
                                return err
@@ -151,45 +321,42 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
                        if err != nil {
                                return fmt.Errorf("computing diff: %s", err)
                        }
-                       fmt.Fprintf(out, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename))
-                       out.Write(data)
+                       fmt.Fprintf(r, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename))
+                       r.Write(data)
                }
        }
 
        if !*list && !*write && !*doDiff {
-               _, err = out.Write(res)
+               _, err = r.Write(res)
        }
 
        return err
 }
 
-func visitFile(path string, f fs.DirEntry, err error) error {
-       if err != nil || !isGoFile(f) {
-               return err
-       }
-       if err := processFile(path, nil, os.Stdout, false); err != nil {
-               report(err)
-       }
-       return nil
-}
-
 func main() {
+       // Arbitrarily limit in-flight work to 2MiB times the number of threads.
+       //
+       // The actual overhead for the parse tree and output will depend on the
+       // specifics of the file, but this at least keeps the footprint of the process
+       // roughly proportional to GOMAXPROCS.
+       maxWeight := (2 << 20) * int64(runtime.GOMAXPROCS(0))
+       s := newSequencer(maxWeight, os.Stdout, os.Stderr)
+
        // call gofmtMain in a separate function
        // so that it can use defer and have them
        // run before the exit.
-       gofmtMain()
-       os.Exit(exitCode)
+       gofmtMain(s)
+       os.Exit(s.GetExitCode())
 }
 
-func gofmtMain() {
+func gofmtMain(s *sequencer) {
        flag.Usage = usage
        flag.Parse()
 
        if *cpuprofile != "" {
                f, err := os.Create(*cpuprofile)
                if err != nil {
-                       fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
-                       exitCode = 2
+                       s.AddReport(fmt.Errorf("creating cpu profile: %s", err))
                        return
                }
                defer f.Close()
@@ -203,34 +370,67 @@ func gofmtMain() {
        args := flag.Args()
        if len(args) == 0 {
                if *write {
-                       fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
-                       exitCode = 2
+                       s.AddReport(fmt.Errorf("error: cannot use -w with standard input"))
                        return
                }
-               if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
-                       report(err)
-               }
+               s.Add(0, func(r *reporter) error {
+                       return processFile("<standard input>", nil, os.Stdin, r)
+               })
                return
        }
 
        for _, arg := range args {
                switch info, err := os.Stat(arg); {
                case err != nil:
-                       report(err)
+                       s.AddReport(err)
                case !info.IsDir():
                        // Non-directory arguments are always formatted.
-                       if err := processFile(arg, nil, os.Stdout, false); err != nil {
-                               report(err)
-                       }
+                       arg := arg
+                       s.Add(fileWeight(arg, info), func(r *reporter) error {
+                               return processFile(arg, info, nil, r)
+                       })
                default:
                        // Directories are walked, ignoring non-Go files.
-                       if err := filepath.WalkDir(arg, visitFile); err != nil {
-                               report(err)
+                       err := filepath.WalkDir(arg, func(path string, f fs.DirEntry, err error) error {
+                               if err != nil || !isGoFile(f) {
+                                       return err
+                               }
+                               info, err := f.Info()
+                               if err != nil {
+                                       s.AddReport(err)
+                                       return nil
+                               }
+                               s.Add(fileWeight(path, info), func(r *reporter) error {
+                                       return processFile(path, info, nil, r)
+                               })
+                               return nil
+                       })
+                       if err != nil {
+                               s.AddReport(err)
                        }
                }
        }
 }
 
+func fileWeight(path string, info fs.FileInfo) int64 {
+       if info == nil {
+               return exclusive
+       }
+       if info.Mode().Type() == fs.ModeSymlink {
+               var err error
+               info, err = os.Stat(path)
+               if err != nil {
+                       return exclusive
+               }
+       }
+       if !info.Mode().IsRegular() {
+               // For non-regular files, FileInfo.Size is system-dependent and thus not a
+               // reliable indicator of weight.
+               return exclusive
+       }
+       return info.Size()
+}
+
 func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) {
        data, err := diff.Diff("gofmt", b1, b2)
        if len(data) > 0 {
index 9ef7676214c9f53a93aea54c39edae9580f0090c..676c5b43ede28074c7f6ed1694e59b8bb930687b 100644 (file)
@@ -58,7 +58,11 @@ func runTest(t *testing.T, in, out string) {
        // process flags
        *simplifyAST = false
        *rewriteRule = ""
-       stdin := false
+       info, err := os.Lstat(in)
+       if err != nil {
+               t.Error(err)
+               return
+       }
        for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
                elts := strings.SplitN(flag, "=", 2)
                name := elts[0]
@@ -75,7 +79,7 @@ func runTest(t *testing.T, in, out string) {
                        *simplifyAST = true
                case "-stdin":
                        // fake flag - pretend input is from stdin
-                       stdin = true
+                       info = nil
                default:
                        t.Errorf("unrecognized flag name: %s", name)
                }
@@ -84,11 +88,17 @@ func runTest(t *testing.T, in, out string) {
        initParserMode()
        initRewrite()
 
-       var buf bytes.Buffer
-       err := processFile(in, nil, &buf, stdin)
-       if err != nil {
-               t.Error(err)
-               return
+       const maxWeight = 2 << 20
+       var buf, errBuf bytes.Buffer
+       s := newSequencer(maxWeight, &buf, &errBuf)
+       s.Add(fileWeight(in, info), func(r *reporter) error {
+               return processFile(in, info, nil, r)
+       })
+       if errBuf.Len() > 0 {
+               t.Logf("%q", errBuf.Bytes())
+       }
+       if s.GetExitCode() != 0 {
+               t.Fail()
        }
 
        expected, err := os.ReadFile(out)
index bab22e04cdac00284170d792fa7a4812ff769e9d..a98c6a0cd9b4837d3cfbc23ba68255dfe4c989e2 100644 (file)
@@ -28,7 +28,9 @@ func initRewrite() {
        }
        pattern := parseExpr(f[0], "pattern")
        replace := parseExpr(f[1], "replacement")
-       rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
+       rewrite = func(fset *token.FileSet, p *ast.File) *ast.File {
+               return rewriteFile(fset, pattern, replace, p)
+       }
 }
 
 // parseExpr parses s as an expression.
@@ -54,7 +56,7 @@ func dump(msg string, val reflect.Value) {
 */
 
 // rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
-func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
+func rewriteFile(fileSet *token.FileSet, pattern, replace ast.Expr, p *ast.File) *ast.File {
        cmap := ast.NewCommentMap(fileSet, p, p.Comments)
        m := make(map[string]reflect.Value)
        pat := reflect.ValueOf(pattern)
@@ -290,7 +292,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value)
                }
                return v
 
-       case reflect.Ptr:
+       case reflect.Pointer:
                v := reflect.New(p.Type()).Elem()
                if elem := p.Elem(); elem.IsValid() {
                        v.Set(subst(m, elem, pos).Addr())
index f71bd130db4ab075aa5f8296ff6315958688c82f..d57a2ba59b03e6b42ff96656a08c2910c7c2b984 100644 (file)
@@ -21,7 +21,7 @@ func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
 func f[P interface{}](x P)
 func f[P1, P2, P3 interface {
        m1(P1)
-       type P2, P3
+       ~P2 | ~P3
 }](x1 P1, x2 P2, x3 P3) struct{}
 func f[P any](T1[P], T2[P]) T3[P]
 
index 5d4c53d9f767a97e0f9cff8be06b8a2662e9004b..775cf9eb7bdc85242b3af2864803855976e08c5c 100644 (file)
@@ -19,7 +19,7 @@ func f[P any](x P)
 func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
 
 func f[P interface{}](x P)
-func f[P1, P2, P3 interface{ m1(P1); type P2, P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P1, P2, P3 interface{ m1(P1); ~P2|~P3 }](x1 P1, x2 P2, x3 P3) struct{}
 func f[P any](T1[P], T2[P]) T3[P]
 
 func (x T[P]) m()
index e832f9987e582eb9b262c50f12aa4c8abae23fef..4895a49e1118a29c2546c5985aed6660ca70fbd0 100644 (file)
@@ -177,3 +177,11 @@ func TestExcludedReader(t *testing.T) {
                }
        }
 }
+
+func TestEmptyID(t *testing.T) {
+       r := strings.NewReader("aha!")
+       matches, hash, err := FindAndHash(r, "", 1000)
+       if matches != nil || hash != ([32]byte{}) || err == nil || !strings.Contains(err.Error(), "no id") {
+               t.Errorf("FindAndHash: want nil, [32]byte{}, no id specified, got %v, %v, %v", matches, hash, err)
+       }
+}
index a7928959c483da9f467fefb6209030c8d34b030d..8814950db0d83f142aaf551b1a2071e4ac59b66d 100644 (file)
@@ -22,6 +22,9 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
        if bufSize == 0 {
                bufSize = 31 * 1024 // bufSize+little will likely fit in 32 kB
        }
+       if len(id) == 0 {
+               return nil, [32]byte{}, fmt.Errorf("buildid.FindAndHash: no id specified")
+       }
        if len(id) > bufSize {
                return nil, [32]byte{}, fmt.Errorf("buildid.FindAndHash: buffer too small")
        }
index 860c7d6c0d9dc134b79f244ce7bf3c03ad4ab168..be3764170694684e2b61f21fb2750c84289fc1c3 100644 (file)
@@ -50,6 +50,7 @@ type Var struct {
        Abbrev        int // Either DW_ABRV_AUTO[_LOCLIST] or DW_ABRV_PARAM[_LOCLIST]
        IsReturnValue bool
        IsInlFormal   bool
+       DictIndex     uint16 // index of the dictionary entry describing the type of this variable
        StackOffset   int32
        // This package can't use the ssa package, so it can't mention ssa.FuncDebug,
        // so indirect through a closure.
@@ -97,6 +98,8 @@ type FnState struct {
        Scopes        []Scope
        InlCalls      InlCalls
        UseBASEntries bool
+
+       dictIndexToOffset []int64
 }
 
 func EnableLogging(doit bool) {
@@ -315,6 +318,7 @@ const (
        DW_AT_go_runtime_type   = 0x2904
 
        DW_AT_go_package_name = 0x2905 // Attribute for DW_TAG_compile_unit
+       DW_AT_go_dict_index   = 0x2906 // Attribute for DW_TAG_typedef_type, index of the dictionary entry describing the real type of this type shape
 
        DW_AT_internal_location = 253 // params and locals; not emitted
 )
@@ -325,8 +329,10 @@ const (
        DW_ABRV_COMPUNIT
        DW_ABRV_COMPUNIT_TEXTLESS
        DW_ABRV_FUNCTION
+       DW_ABRV_WRAPPER
        DW_ABRV_FUNCTION_ABSTRACT
        DW_ABRV_FUNCTION_CONCRETE
+       DW_ABRV_WRAPPER_CONCRETE
        DW_ABRV_INLINED_SUBROUTINE
        DW_ABRV_INLINED_SUBROUTINE_RANGES
        DW_ABRV_VARIABLE
@@ -360,6 +366,7 @@ const (
        DW_ABRV_STRINGTYPE
        DW_ABRV_STRUCTTYPE
        DW_ABRV_TYPEDECL
+       DW_ABRV_DICT_INDEX
        DW_NABRV
 )
 
@@ -455,6 +462,19 @@ var abbrevs = [DW_NABRV]dwAbbrev{
                },
        },
 
+       /* WRAPPER */
+       {
+               DW_TAG_subprogram,
+               DW_CHILDREN_yes,
+               []dwAttrForm{
+                       {DW_AT_name, DW_FORM_string},
+                       {DW_AT_low_pc, DW_FORM_addr},
+                       {DW_AT_high_pc, DW_FORM_addr},
+                       {DW_AT_frame_base, DW_FORM_block1},
+                       {DW_AT_trampoline, DW_FORM_flag},
+               },
+       },
+
        /* FUNCTION_ABSTRACT */
        {
                DW_TAG_subprogram,
@@ -478,6 +498,19 @@ var abbrevs = [DW_NABRV]dwAbbrev{
                },
        },
 
+       /* WRAPPER_CONCRETE */
+       {
+               DW_TAG_subprogram,
+               DW_CHILDREN_yes,
+               []dwAttrForm{
+                       {DW_AT_abstract_origin, DW_FORM_ref_addr},
+                       {DW_AT_low_pc, DW_FORM_addr},
+                       {DW_AT_high_pc, DW_FORM_addr},
+                       {DW_AT_frame_base, DW_FORM_block1},
+                       {DW_AT_trampoline, DW_FORM_flag},
+               },
+       },
+
        /* INLINED_SUBROUTINE */
        {
                DW_TAG_inlined_subroutine,
@@ -854,6 +887,17 @@ var abbrevs = [DW_NABRV]dwAbbrev{
                        {DW_AT_type, DW_FORM_ref_addr},
                },
        },
+
+       /* DICT_INDEX */
+       {
+               DW_TAG_typedef,
+               DW_CHILDREN_no,
+               []dwAttrForm{
+                       {DW_AT_name, DW_FORM_string},
+                       {DW_AT_type, DW_FORM_ref_addr},
+                       {DW_AT_go_dict_index, DW_FORM_udata},
+               },
+       },
 }
 
 // GetAbbrev returns the contents of the .debug_abbrev section.
@@ -1168,6 +1212,9 @@ func putPrunedScopes(ctxt Context, s *FnState, fnabbrev int) error {
                sort.Sort(byChildIndex(pruned.Vars))
                scopes[k] = pruned
        }
+
+       s.dictIndexToOffset = putparamtypes(ctxt, s, scopes, fnabbrev)
+
        var encbuf [20]byte
        if putscope(ctxt, s, scopes, 0, fnabbrev, encbuf[:0]) < int32(len(scopes)) {
                return errors.New("multiple toplevel scopes")
@@ -1329,11 +1376,14 @@ func putInlinedFunc(ctxt Context, s *FnState, callIdx int) error {
 // for the function (which holds location-independent attributes such
 // as name, type), then the remainder of the attributes are specific
 // to this instance (location, frame base, etc).
-func PutConcreteFunc(ctxt Context, s *FnState) error {
+func PutConcreteFunc(ctxt Context, s *FnState, isWrapper bool) error {
        if logDwarf {
                ctxt.Logf("PutConcreteFunc(%v)\n", s.Info)
        }
        abbrev := DW_ABRV_FUNCTION_CONCRETE
+       if isWrapper {
+               abbrev = DW_ABRV_WRAPPER_CONCRETE
+       }
        Uleb128put(ctxt, s.Info, int64(abbrev))
 
        // Abstract origin.
@@ -1346,6 +1396,10 @@ func PutConcreteFunc(ctxt Context, s *FnState) error {
        // cfa / frame base
        putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
 
+       if isWrapper {
+               putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
+       }
+
        // Scopes
        if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
                return err
@@ -1368,11 +1422,14 @@ func PutConcreteFunc(ctxt Context, s *FnState) error {
 // when its containing package was compiled (hence there is no need to
 // emit an abstract version for it to use as a base for inlined
 // routine records).
-func PutDefaultFunc(ctxt Context, s *FnState) error {
+func PutDefaultFunc(ctxt Context, s *FnState, isWrapper bool) error {
        if logDwarf {
                ctxt.Logf("PutDefaultFunc(%v)\n", s.Info)
        }
        abbrev := DW_ABRV_FUNCTION
+       if isWrapper {
+               abbrev = DW_ABRV_WRAPPER
+       }
        Uleb128put(ctxt, s.Info, int64(abbrev))
 
        // Expand '"".' to import path.
@@ -1385,13 +1442,16 @@ func PutDefaultFunc(ctxt Context, s *FnState) error {
        putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC)
        putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC)
        putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
-       ctxt.AddFileRef(s.Info, s.Filesym)
-
-       var ev int64
-       if s.External {
-               ev = 1
+       if isWrapper {
+               putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, int64(1), 0)
+       } else {
+               ctxt.AddFileRef(s.Info, s.Filesym)
+               var ev int64
+               if s.External {
+                       ev = 1
+               }
+               putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
        }
-       putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
 
        // Scopes
        if err := putPrunedScopes(ctxt, s, abbrev); err != nil {
@@ -1410,6 +1470,47 @@ func PutDefaultFunc(ctxt Context, s *FnState) error {
        return nil
 }
 
+// putparamtypes writes typedef DIEs for any parametric types that are used by this function.
+func putparamtypes(ctxt Context, s *FnState, scopes []Scope, fnabbrev int) []int64 {
+       if fnabbrev == DW_ABRV_FUNCTION_CONCRETE {
+               return nil
+       }
+
+       maxDictIndex := uint16(0)
+
+       for i := range scopes {
+               for _, v := range scopes[i].Vars {
+                       if v.DictIndex > maxDictIndex {
+                               maxDictIndex = v.DictIndex
+                       }
+               }
+       }
+
+       if maxDictIndex == 0 {
+               return nil
+       }
+
+       dictIndexToOffset := make([]int64, maxDictIndex)
+
+       for i := range scopes {
+               for _, v := range scopes[i].Vars {
+                       if v.DictIndex == 0 || dictIndexToOffset[v.DictIndex-1] != 0 {
+                               continue
+                       }
+
+                       dictIndexToOffset[v.DictIndex-1] = ctxt.CurrentOffset(s.Info)
+
+                       Uleb128put(ctxt, s.Info, int64(DW_ABRV_DICT_INDEX))
+                       n := fmt.Sprintf(".param%d", v.DictIndex-1)
+                       putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
+                       putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
+                       putattr(ctxt, s.Info, DW_ABRV_DICT_INDEX, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DictIndex-1), nil)
+               }
+       }
+
+       return dictIndexToOffset
+}
+
 func putscope(ctxt Context, s *FnState, scopes []Scope, curscope int32, fnabbrev int, encbuf []byte) int32 {
 
        if logDwarf {
@@ -1489,10 +1590,10 @@ func determineVarAbbrev(v *Var, fnabbrev int) (int, bool, bool) {
        // Determine whether to use a concrete variable or regular variable DIE.
        concrete := true
        switch fnabbrev {
-       case DW_ABRV_FUNCTION:
+       case DW_ABRV_FUNCTION, DW_ABRV_WRAPPER:
                concrete = false
                break
-       case DW_ABRV_FUNCTION_CONCRETE:
+       case DW_ABRV_FUNCTION_CONCRETE, DW_ABRV_WRAPPER_CONCRETE:
                // If we're emitting a concrete subprogram DIE and the variable
                // in question is not part of the corresponding abstract function DIE,
                // then use the default (non-concrete) abbrev for this param.
@@ -1583,7 +1684,12 @@ func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int,
                        putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil)
                }
                putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil)
-               putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
+               if v.DictIndex > 0 && s.dictIndexToOffset != nil && s.dictIndexToOffset[v.DictIndex-1] != 0 {
+                       // If the type of this variable is parametric use the entry emitted by putparamtypes
+                       putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, s.dictIndexToOffset[v.DictIndex-1], s.Info)
+               } else {
+                       putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
+               }
        }
 
        if abbrevUsesLoclist(abbrev) {
@@ -1617,8 +1723,10 @@ func (s byChildIndex) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 // current extld.
 // AIX ld doesn't support DWARF with -bnoobjreorder with version
 // prior to 7.2.2.
-func IsDWARFEnabledOnAIXLd(extld string) (bool, error) {
-       out, err := exec.Command(extld, "-Wl,-V").CombinedOutput()
+func IsDWARFEnabledOnAIXLd(extld []string) (bool, error) {
+       name, args := extld[0], extld[1:]
+       args = append(args, "-Wl,-V")
+       out, err := exec.Command(name, args...).CombinedOutput()
        if err != nil {
                // The normal output should display ld version and
                // then fails because ".main" is not defined:
index e7d612aeb746f9237ffe93279b186edce70b5770..aa665fde99a6a2957d2c9d9b4e5479fd3091ca39 100644 (file)
@@ -4,6 +4,8 @@
 
 package goobj
 
+import "internal/buildcfg"
+
 // Builtin (compiler-generated) function references appear
 // frequently. We assign special indices for them, so they
 // don't need to be referenced by name.
@@ -27,7 +29,7 @@ func BuiltinIdx(name string, abi int) int {
        if !ok {
                return -1
        }
-       if builtins[i].abi != abi {
+       if buildcfg.Experiment.RegabiWrappers && builtins[i].abi != abi {
                return -1
        }
        return i
index 6d33a10a51cda4cde69a36aaf281f6c61a520a1c..59cb957fa7df5c600f2ab0a373a02784a833dfaa 100644 (file)
@@ -16,23 +16,13 @@ type CUFileIndex uint32
 
 // FuncInfo is serialized as a symbol (aux symbol). The symbol data is
 // the binary encoding of the struct below.
-//
-// TODO: make each pcdata a separate symbol?
 type FuncInfo struct {
        Args     uint32
        Locals   uint32
        FuncID   objabi.FuncID
        FuncFlag objabi.FuncFlag
-
-       Pcsp        SymRef
-       Pcfile      SymRef
-       Pcline      SymRef
-       Pcinline    SymRef
-       Pcdata      []SymRef
-       Funcdataoff []uint32
-       File        []CUFileIndex
-
-       InlTree []InlTreeNode
+       File     []CUFileIndex
+       InlTree  []InlTreeNode
 }
 
 func (a *FuncInfo) Write(w *bytes.Buffer) {
@@ -44,10 +34,6 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
                binary.LittleEndian.PutUint32(b[:], x)
                w.Write(b[:])
        }
-       writeSymRef := func(s SymRef) {
-               writeUint32(s.PkgIdx)
-               writeUint32(s.SymIdx)
-       }
 
        writeUint32(a.Args)
        writeUint32(a.Locals)
@@ -55,19 +41,7 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
        writeUint8(uint8(a.FuncFlag))
        writeUint8(0) // pad to uint32 boundary
        writeUint8(0)
-       writeSymRef(a.Pcsp)
-       writeSymRef(a.Pcfile)
-       writeSymRef(a.Pcline)
-       writeSymRef(a.Pcinline)
-       writeUint32(uint32(len(a.Pcdata)))
-       for _, sym := range a.Pcdata {
-               writeSymRef(sym)
-       }
 
-       writeUint32(uint32(len(a.Funcdataoff)))
-       for _, x := range a.Funcdataoff {
-               writeUint32(x)
-       }
        writeUint32(uint32(len(a.File)))
        for _, f := range a.File {
                writeUint32(uint32(f))
@@ -84,31 +58,19 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
 // corresponding "off" field stores the byte offset of the start of
 // the items in question.
 type FuncInfoLengths struct {
-       NumPcdata      uint32
-       PcdataOff      uint32
-       NumFuncdataoff uint32
-       FuncdataoffOff uint32
-       NumFile        uint32
-       FileOff        uint32
-       NumInlTree     uint32
-       InlTreeOff     uint32
-       Initialized    bool
+       NumFile     uint32
+       FileOff     uint32
+       NumInlTree  uint32
+       InlTreeOff  uint32
+       Initialized bool
 }
 
 func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
        var result FuncInfoLengths
 
-       // Offset to the number of pcdata values. This value is determined by counting
-       // the number of bytes until we write pcdata to the file.
-       const numpcdataOff = 44
-       result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
-       result.PcdataOff = numpcdataOff + 4
-
-       numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata
-       result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
-       result.FuncdataoffOff = numfuncdataoffOff + 4
-
-       numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
+       // Offset to the number of the file table. This value is determined by counting
+       // the number of bytes until we write funcdataoff to the file.
+       const numfileOff = 12
        result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
        result.FileOff = numfileOff + 4
 
@@ -129,34 +91,6 @@ func (*FuncInfo) ReadFuncID(b []byte) objabi.FuncID { return objabi.FuncID(b[8])
 
 func (*FuncInfo) ReadFuncFlag(b []byte) objabi.FuncFlag { return objabi.FuncFlag(b[9]) }
 
-func (*FuncInfo) ReadPcsp(b []byte) SymRef {
-       return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])}
-}
-
-func (*FuncInfo) ReadPcfile(b []byte) SymRef {
-       return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])}
-}
-
-func (*FuncInfo) ReadPcline(b []byte) SymRef {
-       return SymRef{binary.LittleEndian.Uint32(b[28:]), binary.LittleEndian.Uint32(b[32:])}
-}
-
-func (*FuncInfo) ReadPcinline(b []byte) SymRef {
-       return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])}
-}
-
-func (*FuncInfo) ReadPcdata(b []byte) []SymRef {
-       syms := make([]SymRef, binary.LittleEndian.Uint32(b[44:]))
-       for i := range syms {
-               syms[i] = SymRef{binary.LittleEndian.Uint32(b[48+i*8:]), binary.LittleEndian.Uint32(b[52+i*8:])}
-       }
-       return syms
-}
-
-func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
-       return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
-}
-
 func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex {
        return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:]))
 }
index e2858bd57da0ca42abe5eafc7f8df2f7c8a36882..976505839240bd868d96abeca1c26379ba4b8607 100644 (file)
 package goobj
 
 import (
-       "bytes"
        "cmd/internal/bio"
        "crypto/sha1"
        "encoding/binary"
        "errors"
        "fmt"
        "internal/unsafeheader"
-       "io"
        "unsafe"
 )
 
 // New object file format.
 //
 //    Header struct {
-//       Magic       [...]byte   // "\x00go117ld"
+//       Magic       [...]byte   // "\x00go118ld"
 //       Fingerprint [8]byte
 //       Flags       uint32
 //       Offsets     [...]uint32 // byte offset of each block below
@@ -100,7 +98,6 @@ import (
 //    }
 //
 //    Data   [...]byte
-//    Pcdata [...]byte
 //
 //    // blocks only used by tools (objdump, nm)
 //
@@ -204,7 +201,6 @@ const (
        BlkReloc
        BlkAux
        BlkData
-       BlkPcdata
        BlkRefName
        BlkEnd
        NBlk
@@ -219,7 +215,7 @@ type Header struct {
        Offsets     [NBlk]uint32
 }
 
-const Magic = "\x00go117ld"
+const Magic = "\x00go118ld"
 
 func (h *Header) Write(w *Writer) {
        w.RawString(h.Magic)
@@ -304,6 +300,7 @@ const (
 const (
        SymFlagUsedInIface = 1 << iota
        SymFlagItab
+       SymFlagDict
 )
 
 // Returns the length of the name of the symbol.
@@ -333,6 +330,7 @@ func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
 func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
 func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
 func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
+func (s *Sym) IsDict() bool        { return s.Flag2()&SymFlagDict != 0 }
 
 func (s *Sym) SetName(x string, w *Writer) {
        binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
@@ -357,6 +355,8 @@ type SymRef struct {
        SymIdx uint32
 }
 
+func (s SymRef) IsZero() bool { return s == SymRef{} }
+
 // Hash64
 type Hash64Type [Hash64Size]byte
 
@@ -592,13 +592,12 @@ type Reader struct {
        b        []byte // mmapped bytes, if not nil
        readonly bool   // whether b is backed with read-only memory
 
-       rd    io.ReaderAt
        start uint32
        h     Header // keep block offsets
 }
 
 func NewReaderFromBytes(b []byte, readonly bool) *Reader {
-       r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
+       r := &Reader{b: b, readonly: readonly, start: 0}
        err := r.h.Read(r)
        if err != nil {
                return nil
index 1454d8a7c92045e0f9b6a9af7a282ecfc577d080..38aa11cde9845e3868787cf96ced56947940e247 100644 (file)
@@ -634,6 +634,61 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 }
 
 func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
+       if c.ctxt.Flag_maymorestack != "" {
+               // Save LR and make room for REGCTXT.
+               const frameSize = 8
+               // MOVW.W R14,$-8(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVW
+               p.Scond |= C_WBIT
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGLINK
+               p.To.Type = obj.TYPE_MEM
+               p.To.Offset = -frameSize
+               p.To.Reg = REGSP
+               p.Spadj = frameSize
+
+               // MOVW REGCTXT, 4(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVW
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGCTXT
+               p.To.Type = obj.TYPE_MEM
+               p.To.Offset = 4
+               p.To.Reg = REGSP
+
+               // CALL maymorestack
+               p = obj.Appendp(p, c.newprog)
+               p.As = obj.ACALL
+               p.To.Type = obj.TYPE_BRANCH
+               // See ../x86/obj6.go
+               p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
+
+               // Restore REGCTXT and LR.
+
+               // MOVW 4(SP), REGCTXT
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVW
+               p.From.Type = obj.TYPE_MEM
+               p.From.Offset = 4
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGCTXT
+
+               // MOVW.P 8(SP), R14
+               p.As = AMOVW
+               p.Scond |= C_PBIT
+               p.From.Type = obj.TYPE_MEM
+               p.From.Offset = frameSize
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGLINK
+               p.Spadj = -frameSize
+       }
+
+       // Jump back to here after morestack returns.
+       startPred := p
+
        // MOVW g_stackguard(g), R1
        p = obj.Appendp(p, c.newprog)
 
@@ -761,7 +816,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
        b := obj.Appendp(pcdata, c.newprog)
        b.As = obj.AJMP
        b.To.Type = obj.TYPE_BRANCH
-       b.To.SetTarget(c.cursym.Func().Text.Link)
+       b.To.SetTarget(startPred.Link)
        b.Spadj = +framesize
 
        return end
index bf75bb4a89156cede1626c676a11c58702c647b0..aa7c54df9aefa9180e9e755386af2efacc902485 100644 (file)
@@ -1060,9 +1060,10 @@ const (
 
 const (
        // shift types
-       SHIFT_LL = 0 << 22
-       SHIFT_LR = 1 << 22
-       SHIFT_AR = 2 << 22
+       SHIFT_LL  = 0 << 22
+       SHIFT_LR  = 1 << 22
+       SHIFT_AR  = 2 << 22
+       SHIFT_ROR = 3 << 22
 )
 
 // Arrangement for ARM64 SIMD instructions
index d99afa3d27606f362798eeeed403e8e1420dc4c2..68f0921d4d9aa4cecb22122ab512bc9c867ef115 100644 (file)
@@ -361,12 +361,12 @@ var optab = []Optab{
        {AANDS, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
        {ATST, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0},
        {AAND, C_MBCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0},
-       {AAND, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
+       {AAND, C_MBCON, C_NONE, C_NONE, C_RSP, 53, 4, 0, 0, 0},
        {AANDS, C_MBCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0},
        {AANDS, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
        {ATST, C_MBCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0},
        {AAND, C_BITCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0},
-       {AAND, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
+       {AAND, C_BITCON, C_NONE, C_NONE, C_RSP, 53, 4, 0, 0, 0},
        {AANDS, C_BITCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0},
        {AANDS, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
        {ATST, C_BITCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0},
@@ -404,6 +404,8 @@ var optab = []Optab{
        /* TODO: MVN C_SHIFT */
 
        /* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */
+       {AMOVW, C_MBCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
+       {AMOVD, C_MBCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
        {AMOVW, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
        {AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
        {AMOVW, C_BITCON, C_NONE, C_NONE, C_RSP, 32, 4, 0, 0, 0},
@@ -415,7 +417,7 @@ var optab = []Optab{
 
        {AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
        {AMOVD, C_AACON, C_NONE, C_NONE, C_RSP, 4, 4, REGFROM, 0, 0},
-       {AMOVD, C_AACON2, C_NONE, C_NONE, C_RSP, 4, 8, REGFROM, 0, 0},
+       {AMOVD, C_AACON2, C_NONE, C_NONE, C_RSP, 4, 8, REGFROM, NOTUSETMP, 0},
 
        /* load long effective stack address (load int32 offset and add) */
        {AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0},
@@ -692,13 +694,12 @@ var optab = []Optab{
        {AFMOVD, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
 
        /* pre/post-indexed/signed-offset load/store register pair
-          (unscaled, signed 10-bit quad-aligned and long offset) */
+          (unscaled, signed 10-bit quad-aligned and long offset).
+       The pre/post-indexed format only supports OREG cases because
+       the RSP and pseudo registers are not allowed to be modified
+       in this way. */
        {AFLDPQ, C_NQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {AFLDPQ, C_NQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {AFLDPQ, C_NQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {AFLDPQ, C_PQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {AFLDPQ, C_PQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {AFLDPQ, C_PQAUTO_16, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {AFLDPQ, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {AFLDPQ, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {AFLDPQ, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
@@ -714,11 +715,7 @@ var optab = []Optab{
        {AFLDPQ, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
 
        {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQAUTO_16, 67, 4, REGSP, 0, 0},
-       {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQAUTO_16, 67, 4, REGSP, 0, C_XPRE},
-       {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NQAUTO_16, 67, 4, REGSP, 0, C_XPOST},
        {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQAUTO_16, 67, 4, REGSP, 0, 0},
-       {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQAUTO_16, 67, 4, REGSP, 0, C_XPRE},
-       {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_PQAUTO_16, 67, 4, REGSP, 0, C_XPOST},
        {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
        {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 8, REGSP, 0, 0},
        {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
@@ -734,11 +731,7 @@ var optab = []Optab{
        {AFSTPQ, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
 
        {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
@@ -754,11 +747,7 @@ var optab = []Optab{
        {ALDP, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
 
        {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, 0},
-       {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPRE},
-       {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPOST},
        {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, 0},
-       {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPRE},
-       {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPOST},
        {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
        {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 8, REGSP, 0, 0},
        {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
@@ -775,11 +764,7 @@ var optab = []Optab{
 
        // differ from LDP/STP for C_NSAUTO_4/C_PSAUTO_4/C_NSOREG_4/C_PSOREG_4
        {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
@@ -795,11 +780,7 @@ var optab = []Optab{
        {ALDPW, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
 
        {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, 0},
-       {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
-       {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, 0},
-       {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
-       {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
        {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 8, REGSP, 0, 0},
        {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
@@ -2089,13 +2070,18 @@ func cmp(a int, b int) bool {
                        return true
                }
 
+       case C_MBCON:
+               if b == C_ABCON0 {
+                       return true
+               }
+
        case C_BITCON:
                if b == C_ABCON0 || b == C_ABCON || b == C_MBCON {
                        return true
                }
 
        case C_MOVCON:
-               if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 || b == C_AMCON {
+               if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 || b == C_ABCON0 || b == C_AMCON {
                        return true
                }
 
@@ -3299,8 +3285,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                }
 
                if int(o.size) == 8 {
-                       o1 = c.oaddi(p, op, v&0xfff000, r, REGTMP)
-                       o2 = c.oaddi(p, op, v&0x000fff, REGTMP, rt)
+                       // NOTE: this case does not use REGTMP. If it ever does,
+                       // remove the NOTUSETMP flag in optab.
+                       o1 = c.oaddi(p, op, v&0xfff000, r, rt)
+                       o2 = c.oaddi(p, op, v&0x000fff, rt, rt)
                        break
                }
 
@@ -3419,6 +3407,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o4 = os[3]
 
        case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
+               if p.Reg == REGTMP {
+                       c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
+               }
                if p.To.Reg == REG_RSP && isADDSop(p.As) {
                        c.ctxt.Diag("illegal destination register: %v\n", p)
                }
@@ -3736,6 +3727,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o1 |= (uint32(r&31) << 5) | uint32(rt&31)
 
        case 28: /* logop $vcon, [R], R (64 bit literal) */
+               if p.Reg == REGTMP {
+                       c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
+               }
                o := uint32(0)
                num := uint8(0)
                cls := oclass(&p.From)
@@ -3883,6 +3877,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o1 = c.opirr(p, p.As)
 
                d := p.From.Offset
+               if d == 0 {
+                       c.ctxt.Diag("zero shifts cannot be handled correctly: %v", p)
+               }
                s := movcon(d)
                if s < 0 || s >= 4 {
                        c.ctxt.Diag("bad constant for MOVK: %#x\n%v", uint64(d), p)
@@ -4198,6 +4195,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if r == 0 {
                        r = rt
                }
+               if r == REG_RSP {
+                       c.ctxt.Diag("illegal source register: %v", p)
+                       break
+               }
                mode := 64
                v := uint64(p.From.Offset)
                switch p.As {
@@ -4362,6 +4363,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
 
                /* reloc ops */
        case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
+               if p.From.Reg == REGTMP {
+                       c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
+               }
                o1 = ADR(1, 0, REGTMP)
                o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
                rel := obj.Addrel(c.cursym)
@@ -4593,6 +4597,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                //      add Rtmp, R, Rtmp
                //      ldp (Rtmp), (R1, R2)
                r := int(p.From.Reg)
+               if r == REGTMP {
+                       c.ctxt.Diag("REGTMP used in large offset load: %v", p)
+               }
                if r == obj.REG_NONE {
                        r = int(o.param)
                }
@@ -4609,6 +4616,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
        case 76:
                //      add $O, R, Rtmp or sub $O, R, Rtmp
                //      stp (R1, R2), (Rtmp)
+               if p.From.Reg == REGTMP || p.From.Offset == REGTMP {
+                       c.ctxt.Diag("cannot use REGTMP as source: %v", p)
+               }
                r := int(p.To.Reg)
                if r == obj.REG_NONE {
                        r = int(o.param)
@@ -4636,6 +4646,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                //      add Rtmp, R, Rtmp
                //      stp (R1, R2), (Rtmp)
                r := int(p.To.Reg)
+               if r == REGTMP || p.From.Reg == REGTMP || p.From.Offset == REGTMP {
+                       c.ctxt.Diag("REGTMP used in large offset store: %v", p)
+               }
                if r == obj.REG_NONE {
                        r = int(o.param)
                }
@@ -4941,6 +4954,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o1 |= (uint32(Q&1) << 30) | (uint32((r>>5)&7) << 16) | (uint32(r&0x1f) << 5) | uint32(rt&31)
 
        case 87: /* stp (r,r), addr(SB) -> adrp + add + stp */
+               if p.From.Reg == REGTMP || p.From.Offset == REGTMP {
+                       c.ctxt.Diag("cannot use REGTMP as source: %v", p)
+               }
                o1 = ADR(1, 0, REGTMP)
                o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
                rel := obj.Addrel(c.cursym)
@@ -7039,8 +7055,8 @@ func (c *ctxt7) omovlit(as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 {
 
 // load a constant (MOVCON or BITCON) in a into rt
 func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) {
-       if cls := oclass(a); cls == C_BITCON || cls == C_ABCON || cls == C_ABCON0 {
-               // or $bitcon, REGZERO, rt
+       if cls := oclass(a); (cls == C_BITCON || cls == C_ABCON || cls == C_ABCON0) && rt != REGZERO {
+               // or $bitcon, REGZERO, rt. rt can't be ZR.
                mode := 64
                var as1 obj.As
                switch as {
index efd4577f56bae0c8c65813df5756890a7c4c1cea..14f0f4c616f227e9b4175195152d8d817b726e5e 100644 (file)
@@ -96,6 +96,19 @@ And for a 128-bit interger, it take two 64-bit operands, for the high and low pa
     VMOVD $0x1122334455667788, V1
     VMOVQ $0x1122334455667788, $8877665544332211, V2   // V2=0x11223344556677888877665544332211
 
+8. Move an optionally-shifted 16-bit immediate value to a register.
+
+The instructions are MOVK(W), MOVZ(W) and MOVN(W), the assembly syntax is "op $(uimm16<<shift), <Rd>". The <uimm16>
+is the 16-bit unsigned immediate, in the range 0 to 65535; For the 32-bit variant, the <shift> is 0 or 16, for the
+64-bit variant, the <shift> is 0, 16, 32 or 48.
+
+The current Go assembler does not accept zero shifts, such as "op $0, Rd" and "op $(0<<(16|32|48)), Rd" instructions.
+
+  Examples:
+    MOVK $(10<<32), R20     <=>      movk x20, #10, lsl #32
+    MOVZW $(20<<16), R8     <=>      movz w8, #20, lsl #16
+    MOVK $(0<<16), R10 will be reported as an error by the assembler.
+
 Special Cases.
 
 (1) umov is written as VMOV.
index 31b7c432451d7b060b70b83e8103cfca6816a1bc..e9eb786cb24f602fd21c218731743a3e08a657ce 100644 (file)
@@ -51,7 +51,98 @@ var complements = []obj.As{
        ACMNW: ACMPW,
 }
 
+// noZRreplace is the set of instructions for which $0 in the To operand
+// should NOT be replaced with REGZERO.
+var noZRreplace = map[obj.As]bool{
+       APRFM: true,
+}
+
 func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
+       if c.ctxt.Flag_maymorestack != "" {
+               p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
+
+               // Save LR and make room for FP, REGCTXT. Leave room
+               // for caller's saved FP.
+               const frameSize = 32
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGLINK
+               p.To.Type = obj.TYPE_MEM
+               p.Scond = C_XPRE
+               p.To.Offset = -frameSize
+               p.To.Reg = REGSP
+               p.Spadj = frameSize
+
+               // Save FP.
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGFP
+               p.To.Type = obj.TYPE_MEM
+               p.To.Reg = REGSP
+               p.To.Offset = -8
+
+               p = obj.Appendp(p, c.newprog)
+               p.As = ASUB
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = 8
+               p.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGFP
+
+               // Save REGCTXT (for simplicity we do this whether or
+               // not we need it.)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGCTXT
+               p.To.Type = obj.TYPE_MEM
+               p.To.Reg = REGSP
+               p.To.Offset = 8
+
+               // BL maymorestack
+               p = obj.Appendp(p, c.newprog)
+               p.As = ABL
+               p.To.Type = obj.TYPE_BRANCH
+               // See ../x86/obj6.go
+               p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
+
+               // Restore REGCTXT.
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_MEM
+               p.From.Reg = REGSP
+               p.From.Offset = 8
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGCTXT
+
+               // Restore FP.
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_MEM
+               p.From.Reg = REGSP
+               p.From.Offset = -8
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGFP
+
+               // Restore LR and SP.
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_MEM
+               p.Scond = C_XPOST
+               p.From.Offset = frameSize
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGLINK
+               p.Spadj = -frameSize
+
+               p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
+       }
+
+       // Jump back to here after morestack returns.
+       startPred := p
+
        // MOV  g_stackguard(g), RT1
        p = obj.Appendp(p, c.newprog)
 
@@ -206,7 +297,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
        jmp := obj.Appendp(pcdata, c.newprog)
        jmp.As = AB
        jmp.To.Type = obj.TYPE_BRANCH
-       jmp.To.SetTarget(c.cursym.Func().Text.Link)
+       jmp.To.SetTarget(startPred.Link)
        jmp.Spadj = +framesize
 
        return end
@@ -226,7 +317,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
                p.From.Type = obj.TYPE_REG
                p.From.Reg = REGZERO
        }
-       if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 {
+       if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 && !noZRreplace[p.As] {
                p.To.Type = obj.TYPE_REG
                p.To.Reg = REGZERO
        }
@@ -305,7 +396,9 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
        // for both 32-bit and 64-bit. 32-bit ops will
        // zero the high 32-bit of the destination register
        // anyway.
-       if (isANDWop(p.As) || isADDWop(p.As) || p.As == AMOVW) && p.From.Type == obj.TYPE_CONST {
+       // For MOVW, the destination register can't be ZR,
+       // so don't bother rewriting it in this situation.
+       if (isANDWop(p.As) || isADDWop(p.As) || p.As == AMOVW && p.To.Reg != REGZERO) && p.From.Type == obj.TYPE_CONST {
                v := p.From.Offset & 0xffffffff
                p.From.Offset = v | v<<32
        }
index 6dd53ffd1215e839b91d8657101e4a44ee9648c7..29e367aa4cc0ef34ac63eb20a22dc85e2e2f4d29 100644 (file)
@@ -378,9 +378,9 @@ func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string)
                if err != nil {
                        ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
                }
-               err = dwarf.PutConcreteFunc(dwctxt, fnstate)
+               err = dwarf.PutConcreteFunc(dwctxt, fnstate, s.Wrapper())
        } else {
-               err = dwarf.PutDefaultFunc(dwctxt, fnstate)
+               err = dwarf.PutDefaultFunc(dwctxt, fnstate, s.Wrapper())
        }
        if err != nil {
                ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
index 28626e6e037a5c33f131aec8e2ba81aec5cf086c..11af143f22c3c76ced5568c7fd75bbb6ab578f62 100644 (file)
@@ -283,7 +283,7 @@ func (a *Addr) SetConst(v int64) {
 // Each Prog is charged to a specific source line in the debug information,
 // specified by Pos.Line().
 // Every Prog has a Ctxt field that defines its context.
-// For performance reasons, Progs usually are usually bulk allocated, cached, and reused;
+// For performance reasons, Progs are usually bulk allocated, cached, and reused;
 // those bulk allocators should always be used, rather than new(Prog).
 //
 // The other fields not yet mentioned are for use by the back ends and should
@@ -486,6 +486,7 @@ type FuncInfo struct {
        StackObjects       *LSym
        OpenCodedDeferInfo *LSym
        ArgInfo            *LSym // argument info for traceback
+       ArgLiveInfo        *LSym // argument liveness info for traceback
 
        FuncInfoSym *LSym
 }
@@ -700,6 +701,9 @@ const (
        // convert between ABI0 and ABIInternal calling conventions.
        AttrABIWrapper
 
+       // IsPcdata indicates this is a pcdata symbol.
+       AttrPcdata
+
        // attrABIBase is the value at which the ABI is encoded in
        // Attribute. This must be last; all bits after this are
        // assumed to be an ABI value.
@@ -727,6 +731,7 @@ func (a *Attribute) Indexed() bool            { return a.load()&AttrIndexed != 0
 func (a *Attribute) UsedInIface() bool        { return a.load()&AttrUsedInIface != 0 }
 func (a *Attribute) ContentAddressable() bool { return a.load()&AttrContentAddressable != 0 }
 func (a *Attribute) ABIWrapper() bool         { return a.load()&AttrABIWrapper != 0 }
+func (a *Attribute) IsPcdata() bool           { return a.load()&AttrPcdata != 0 }
 
 func (a *Attribute) Set(flag Attribute, value bool) {
        for {
@@ -826,15 +831,14 @@ func (*LSym) CanBeAnSSAAux() {}
 
 type Pcln struct {
        // Aux symbols for pcln
-       Pcsp        *LSym
-       Pcfile      *LSym
-       Pcline      *LSym
-       Pcinline    *LSym
-       Pcdata      []*LSym
-       Funcdata    []*LSym
-       Funcdataoff []int64
-       UsedFiles   map[goobj.CUFileIndex]struct{} // file indices used while generating pcfile
-       InlTree     InlTree                        // per-function inlining tree extracted from the global tree
+       Pcsp      *LSym
+       Pcfile    *LSym
+       Pcline    *LSym
+       Pcinline  *LSym
+       Pcdata    []*LSym
+       Funcdata  []*LSym
+       UsedFiles map[goobj.CUFileIndex]struct{} // file indices used while generating pcfile
+       InlTree   InlTree                        // per-function inlining tree extracted from the global tree
 }
 
 type Reloc struct {
@@ -876,7 +880,8 @@ type Link struct {
        Flag_linkshared    bool
        Flag_optimize      bool
        Flag_locationlists bool
-       Retpoline          bool // emit use of retpoline stubs for indirect jmp/call
+       Retpoline          bool   // emit use of retpoline stubs for indirect jmp/call
+       Flag_maymorestack  string // If not "", call this function before stack checks
        Bso                *bufio.Writer
        Pathname           string
        Pkgpath            string           // the current package's import path, "" if unknown
@@ -902,16 +907,6 @@ type Link struct {
        Text []*LSym
        Data []*LSym
 
-       // ABIAliases are text symbols that should be aliased to all
-       // ABIs. These symbols may only be referenced and not defined
-       // by this object, since the need for an alias may appear in a
-       // different object than the definition. Hence, this
-       // information can't be carried in the symbol definition.
-       //
-       // TODO(austin): Replace this with ABI wrappers once the ABIs
-       // actually diverge.
-       ABIAliases []*LSym
-
        // Constant symbols (e.g. $i64.*) are data symbols created late
        // in the concurrent phase. To ensure a deterministic order, we
        // add them to a separate list, sort at the end, and append it
index 1f31d0c4cdd32768d7f52ddc374594899589930b..9e2ccc1929774e4fcbe974ac8ca0d77f26ebc1c6 100644 (file)
@@ -658,6 +658,82 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
                mov = AMOVW
        }
 
+       if c.ctxt.Flag_maymorestack != "" {
+               // Save LR and REGCTXT.
+               frameSize := 2 * c.ctxt.Arch.PtrSize
+
+               p = c.ctxt.StartUnsafePoint(p, c.newprog)
+
+               // MOV  REGLINK, -8/-16(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = mov
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGLINK
+               p.To.Type = obj.TYPE_MEM
+               p.To.Offset = int64(-frameSize)
+               p.To.Reg = REGSP
+
+               // MOV  REGCTXT, -4/-8(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = mov
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGCTXT
+               p.To.Type = obj.TYPE_MEM
+               p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
+               p.To.Reg = REGSP
+
+               // ADD  $-8/$-16, SP
+               p = obj.Appendp(p, c.newprog)
+               p.As = add
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = int64(-frameSize)
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGSP
+               p.Spadj = int32(frameSize)
+
+               // JAL  maymorestack
+               p = obj.Appendp(p, c.newprog)
+               p.As = AJAL
+               p.To.Type = obj.TYPE_BRANCH
+               // See ../x86/obj6.go
+               p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
+               p.Mark |= BRANCH
+
+               // Restore LR and REGCTXT.
+
+               // MOV  0(SP), REGLINK
+               p = obj.Appendp(p, c.newprog)
+               p.As = mov
+               p.From.Type = obj.TYPE_MEM
+               p.From.Offset = 0
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGLINK
+
+               // MOV  4/8(SP), REGCTXT
+               p = obj.Appendp(p, c.newprog)
+               p.As = mov
+               p.From.Type = obj.TYPE_MEM
+               p.From.Offset = int64(c.ctxt.Arch.PtrSize)
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGCTXT
+
+               // ADD  $8/$16, SP
+               p = obj.Appendp(p, c.newprog)
+               p.As = add
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = int64(frameSize)
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGSP
+               p.Spadj = int32(-frameSize)
+
+               p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
+       }
+
+       // Jump back to here after morestack returns.
+       startPred := p
+
        // MOV  g_stackguard(g), R1
        p = obj.Appendp(p, c.newprog)
 
@@ -787,7 +863,8 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
 
        p.As = AJMP
        p.To.Type = obj.TYPE_BRANCH
-       p.To.SetTarget(c.cursym.Func().Text.Link)
+       p.To.SetTarget(startPred.Link)
+       startPred.Link.Mark |= LABEL
        p.Mark |= BRANCH
 
        // placeholder for q1's jump target
index 01466ea73606a6e7dadc86d939ee87a3b8df4db2..fa616691eb5c073eeef20af55d0d5751db0a2bad 100644 (file)
@@ -193,25 +193,6 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
                }
        }
 
-       // Pcdata
-       h.Offsets[goobj.BlkPcdata] = w.Offset()
-       for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
-               // Because of the phase order, it's possible that we try to write an invalid
-               // object file, and the Pcln variables haven't been filled in. As such, we
-               // need to check that Pcsp exists, and assume the other pcln variables exist
-               // as well. Tests like test/fixedbugs/issue22200.go demonstrate this issue.
-               if fn := s.Func(); fn != nil && fn.Pcln.Pcsp != nil {
-                       pc := &fn.Pcln
-                       w.Bytes(pc.Pcsp.P)
-                       w.Bytes(pc.Pcfile.P)
-                       w.Bytes(pc.Pcline.P)
-                       w.Bytes(pc.Pcinline.P)
-                       for i := range pc.Pcdata {
-                               w.Bytes(pc.Pcdata[i].P)
-                       }
-               }
-       }
-
        // Blocks used only by tools (objdump, nm).
 
        // Referenced symbol names from other packages
@@ -340,6 +321,9 @@ func (w *writer) Sym(s *LSym) {
        if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
                flag2 |= goobj.SymFlagItab
        }
+       if strings.HasPrefix(s.Name, w.ctxt.Pkgpath) && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath):], ".") && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath)+1:], objabi.GlobalDictPrefix) {
+               flag2 |= goobj.SymFlagDict
+       }
        name := s.Name
        if strings.HasPrefix(name, "gofile..") {
                name = filepath.ToSlash(name)
@@ -348,14 +332,29 @@ func (w *writer) Sym(s *LSym) {
        if fn := s.Func(); fn != nil {
                align = uint32(fn.Align)
        }
-       if s.ContentAddressable() {
-               // We generally assume data symbols are natually aligned,
-               // except for strings. If we dedup a string symbol and a
-               // non-string symbol with the same content, we should keep
+       if s.ContentAddressable() && s.Size != 0 {
+               // We generally assume data symbols are natually aligned
+               // (e.g. integer constants), except for strings and a few
+               // compiler-emitted funcdata. If we dedup a string symbol and
+               // a non-string symbol with the same content, we should keep
                // the largest alignment.
                // TODO: maybe the compiler could set the alignment for all
                // data symbols more carefully.
-               if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
+               switch {
+               case strings.HasPrefix(s.Name, "go.string."),
+                       strings.HasPrefix(name, "type..namedata."),
+                       strings.HasPrefix(name, "type..importpath."),
+                       strings.HasPrefix(name, "runtime.gcbits."),
+                       strings.HasSuffix(name, ".opendefer"),
+                       strings.HasSuffix(name, ".arginfo0"),
+                       strings.HasSuffix(name, ".arginfo1"),
+                       strings.HasSuffix(name, ".argliveinfo"):
+                       // These are just bytes, or varints.
+                       align = 1
+               case strings.HasPrefix(name, "gclocals·"):
+                       // It has 32-bit fields.
+                       align = 4
+               default:
                        switch {
                        case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
                                align = 8
@@ -363,8 +362,9 @@ func (w *writer) Sym(s *LSym) {
                                align = 4
                        case s.Size%2 == 0:
                                align = 2
+                       default:
+                               align = 1
                        }
-                       // don't bother setting align to 1.
                }
        }
        if s.Size > cutoff {
@@ -397,7 +397,40 @@ func (w *writer) Hash(s *LSym) {
        w.Bytes(b[:])
 }
 
+// contentHashSection returns a mnemonic for s's section.
+// The goal is to prevent content-addressability from moving symbols between sections.
+// contentHashSection only distinguishes between sets of sections for which this matters.
+// Allowing flexibility increases the effectiveness of content-addressibility.
+// But in some cases, such as doing addressing based on a base symbol,
+// we need to ensure that a symbol is always in a prticular section.
+// Some of these conditions are duplicated in cmd/link/internal/ld.(*Link).symtab.
+// TODO: instead of duplicating them, have the compiler decide where symbols go.
+func contentHashSection(s *LSym) byte {
+       name := s.Name
+       if s.IsPcdata() {
+               return 'P'
+       }
+       if strings.HasPrefix(name, "gcargs.") ||
+               strings.HasPrefix(name, "gclocals.") ||
+               strings.HasPrefix(name, "gclocals·") ||
+               strings.HasSuffix(name, ".opendefer") ||
+               strings.HasSuffix(name, ".arginfo0") ||
+               strings.HasSuffix(name, ".arginfo1") ||
+               strings.HasSuffix(name, ".argliveinfo") ||
+               strings.HasSuffix(name, ".args_stackmap") ||
+               strings.HasSuffix(name, ".stkobj") {
+               return 'F' // go.func.* or go.funcrel.*
+       }
+       if strings.HasPrefix(name, "type.") {
+               return 'T'
+       }
+       return 0
+}
+
 func contentHash64(s *LSym) goobj.Hash64Type {
+       if contentHashSection(s) != 0 {
+               panic("short hash of non-default-section sym " + s.Name)
+       }
        var b goobj.Hash64Type
        copy(b[:], s.P)
        return b
@@ -432,15 +465,10 @@ func (w *writer) contentHash(s *LSym) goobj.HashType {
        // In this case, if the smaller symbol is alive, the larger is not kept unless
        // needed.
        binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
-       h.Write(tmp[:8])
+       // Some symbols require being in separate sections.
+       tmp[8] = contentHashSection(s)
+       h.Write(tmp[:9])
 
-       // Don't dedup type symbols with others, as they are in a different
-       // section.
-       if strings.HasPrefix(s.Name, "type.") {
-               h.Write([]byte{'T'})
-       } else {
-               h.Write([]byte{0})
-       }
        // The compiler trims trailing zeros _sometimes_. We just do
        // it always.
        h.Write(bytes.TrimRight(s.P, "\x00"))
@@ -657,16 +685,6 @@ func nAuxSym(s *LSym) int {
 func genFuncInfoSyms(ctxt *Link) {
        infosyms := make([]*LSym, 0, len(ctxt.Text))
        hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
-       preparePcSym := func(s *LSym) *LSym {
-               if s == nil {
-                       return s
-               }
-               s.PkgIdx = goobj.PkgIdxHashed
-               s.SymIdx = int32(len(hashedsyms) + len(ctxt.hasheddefs))
-               s.Set(AttrIndexed, true)
-               hashedsyms = append(hashedsyms, s)
-               return s
-       }
        var b bytes.Buffer
        symidx := int32(len(ctxt.defs))
        for _, s := range ctxt.Text {
@@ -681,18 +699,6 @@ func genFuncInfoSyms(ctxt *Link) {
                        FuncFlag: fn.FuncFlag,
                }
                pc := &fn.Pcln
-               o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
-               o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
-               o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
-               o.Pcinline = makeSymRef(preparePcSym(pc.Pcinline))
-               o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
-               for i, pcSym := range pc.Pcdata {
-                       o.Pcdata[i] = makeSymRef(preparePcSym(pcSym))
-               }
-               o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
-               for i, x := range pc.Funcdataoff {
-                       o.Funcdataoff[i] = uint32(x)
-               }
                i := 0
                o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
                for f := range pc.UsedFiles {
@@ -794,10 +800,13 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
        if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 {
                fmt.Fprintf(ctxt.Bso, "topframe ")
        }
+       if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_ASM != 0 {
+               fmt.Fprintf(ctxt.Bso, "asm ")
+       }
        fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
        if s.Type == objabi.STEXT {
                fn := s.Func()
-               fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
+               fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x align=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID), uint64(fn.Align))
                if s.Leaf() {
                        fmt.Fprintf(ctxt.Bso, " leaf")
                }
index 7af81335fb10f61be799c90f4b50d5ca4331cbae..49b425b12415639c0dcbba1d703b32e9b69084ee 100644 (file)
@@ -8,6 +8,7 @@ import (
        "cmd/internal/goobj"
        "cmd/internal/objabi"
        "encoding/binary"
+       "fmt"
        "log"
 )
 
@@ -26,7 +27,7 @@ func funcpctab(ctxt *Link, func_ *LSym, desc string, valfunc func(*Link, *LSym,
        dst := []byte{}
        sym := &LSym{
                Type:      objabi.SRODATA,
-               Attribute: AttrContentAddressable,
+               Attribute: AttrContentAddressable | AttrPcdata,
        }
 
        if dbg {
@@ -280,8 +281,6 @@ func linkpcln(ctxt *Link, cursym *LSym) {
 
        pcln.Pcdata = make([]*LSym, npcdata)
        pcln.Funcdata = make([]*LSym, nfuncdata)
-       pcln.Funcdataoff = make([]int64, nfuncdata)
-       pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
 
        pcln.Pcsp = funcpctab(ctxt, cursym, "pctospadj", pctospadj, nil)
        pcln.Pcfile = funcpctab(ctxt, cursym, "pctofile", pctofileline, pcln)
@@ -337,7 +336,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
                        // use an empty symbol.
                        pcln.Pcdata[i] = &LSym{
                                Type:      objabi.SRODATA,
-                               Attribute: AttrContentAddressable,
+                               Attribute: AttrContentAddressable | AttrPcdata,
                        }
                } else {
                        pcln.Pcdata[i] = funcpctab(ctxt, cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
@@ -351,12 +350,10 @@ func linkpcln(ctxt *Link, cursym *LSym) {
                                continue
                        }
                        i := int(p.From.Offset)
-                       pcln.Funcdataoff[i] = p.To.Offset
-                       if p.To.Type != TYPE_CONST {
-                               // TODO: Dedup.
-                               //funcdata_bytes += p->to.sym->size;
-                               pcln.Funcdata[i] = p.To.Sym
+                       if p.To.Type != TYPE_MEM || p.To.Offset != 0 {
+                               panic(fmt.Sprintf("bad funcdata: %v", p))
                        }
+                       pcln.Funcdata[i] = p.To.Sym
                }
        }
 }
index 6beb4dd94cfdc61a9a3716fa6ab7b831fed2ea51..e5bbdd51a7548de50edb7553b79d8686e5e5574e 100644 (file)
@@ -54,11 +54,28 @@ func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string
                        if curtext == nil { // func _() {}
                                continue
                        }
-                       if p.To.Sym.Name == "go_args_stackmap" {
+                       switch p.To.Sym.Name {
+                       case "go_args_stackmap":
                                if p.From.Type != TYPE_CONST || p.From.Offset != objabi.FUNCDATA_ArgsPointerMaps {
                                        ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
                                }
                                p.To.Sym = ctxt.LookupDerived(curtext, curtext.Name+".args_stackmap")
+                       case "no_pointers_stackmap":
+                               if p.From.Type != TYPE_CONST || p.From.Offset != objabi.FUNCDATA_LocalsPointerMaps {
+                                       ctxt.Diag("FUNCDATA use of no_pointers_stackmap(SB) without FUNCDATA_LocalsPointerMaps")
+                               }
+                               // funcdata for functions with no local variables in frame.
+                               // Define two zero-length bitmaps, because the same index is used
+                               // for the local variables as for the argument frame, and assembly
+                               // frames have two argument bitmaps, one without results and one with results.
+                               // Write []uint32{2, 0}.
+                               b := make([]byte, 8)
+                               ctxt.Arch.ByteOrder.PutUint32(b, 2)
+                               s := ctxt.GCLocalsSym(b)
+                               if !s.OnList() {
+                                       ctxt.Globl(s, int64(len(s.P)), int(RODATA|DUPOK))
+                               }
+                               p.To.Sym = s
                        }
 
                }
@@ -156,7 +173,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
        }
        name := strings.Replace(s.Name, "\"\"", ctxt.Pkgpath, -1)
        s.Func().FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0 || flag&ABIWRAPPER != 0)
-       s.Func().FuncFlag = toFuncFlag(flag)
+       s.Func().FuncFlag = ctxt.toFuncFlag(flag)
        s.Set(AttrOnList, true)
        s.Set(AttrDuplicateOK, flag&DUPOK != 0)
        s.Set(AttrNoSplit, flag&NOSPLIT != 0)
@@ -172,11 +189,14 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
        ctxt.dwarfSym(s)
 }
 
-func toFuncFlag(flag int) objabi.FuncFlag {
+func (ctxt *Link) toFuncFlag(flag int) objabi.FuncFlag {
        var out objabi.FuncFlag
        if flag&TOPFRAME != 0 {
                out |= objabi.FuncFlag_TOPFRAME
        }
+       if ctxt.IsAsm {
+               out |= objabi.FuncFlag_ASM
+       }
        return out
 }
 
index 428cac528ac3b63748691c80a501e7ea86b99bf1..1e74e64a29fb5ff0089632923935cfe76dd21c0b 100644 (file)
@@ -79,7 +79,43 @@ const (
        REG_R30
        REG_R31
 
-       /* F0=4128 ... F31=4159 */
+       // CR bits. Use Book 1, chapter 2 naming for bits. Keep aligned to 32
+       REG_CR0LT
+       REG_CR0GT
+       REG_CR0EQ
+       REG_CR0SO
+       REG_CR1LT
+       REG_CR1GT
+       REG_CR1EQ
+       REG_CR1SO
+       REG_CR2LT
+       REG_CR2GT
+       REG_CR2EQ
+       REG_CR2SO
+       REG_CR3LT
+       REG_CR3GT
+       REG_CR3EQ
+       REG_CR3SO
+       REG_CR4LT
+       REG_CR4GT
+       REG_CR4EQ
+       REG_CR4SO
+       REG_CR5LT
+       REG_CR5GT
+       REG_CR5EQ
+       REG_CR5SO
+       REG_CR6LT
+       REG_CR6GT
+       REG_CR6EQ
+       REG_CR6SO
+       REG_CR7LT
+       REG_CR7GT
+       REG_CR7EQ
+       REG_CR7SO
+
+       /* Align FPR and VSR vectors such that when masked with 0x3F they produce
+          an equivalent VSX register. */
+       /* F0=4160 ... F31=4191 */
        REG_F0
        REG_F1
        REG_F2
@@ -113,7 +149,7 @@ const (
        REG_F30
        REG_F31
 
-       /* V0=4160 ... V31=4191 */
+       /* V0=4192 ... V31=4223 */
        REG_V0
        REG_V1
        REG_V2
@@ -147,7 +183,7 @@ const (
        REG_V30
        REG_V31
 
-       /* VS0=4192 ... VS63=4255 */
+       /* VS0=4224 ... VS63=4287 */
        REG_VS0
        REG_VS1
        REG_VS2
@@ -229,7 +265,6 @@ const (
        REG_SPECIAL = REG_CR0
 
        REG_SPR0 = obj.RBasePPC64 + 1024 // first of 1024 registers
-       REG_DCR0 = obj.RBasePPC64 + 2048 // first of 1024 registers
 
        REG_XER = REG_SPR0 + 1
        REG_LR  = REG_SPR0 + 8
@@ -240,8 +275,8 @@ const (
        REGSB   = REG_R2
        REGRET  = REG_R3
        REGARG  = -1      /* -1 disables passing the first argument in register */
-       REGRT1  = REG_R /* reserved for runtime, duffzero and duffcopy */
-       REGRT2  = REG_R /* reserved for runtime, duffcopy */
+       REGRT1  = REG_R20 /* reserved for runtime, duffzero and duffcopy */
+       REGRT2  = REG_R21 /* reserved for runtime, duffcopy */
        REGMIN  = REG_R7  /* register variables allocated from here to REGMAX */
        REGCTXT = REG_R11 /* context for closures */
        REGTLS  = REG_R13 /* C ABI TLS base pointer */
@@ -294,16 +329,17 @@ const (
 
 const (
        /* mark flags */
-       LABEL   = 1 << 0
-       LEAF    = 1 << 1
-       FLOAT   = 1 << 2
-       BRANCH  = 1 << 3
-       LOAD    = 1 << 4
-       FCMP    = 1 << 5
-       SYNC    = 1 << 6
-       LIST    = 1 << 7
-       FOLL    = 1 << 8
-       NOSCHED = 1 << 9
+       LABEL    = 1 << 0
+       LEAF     = 1 << 1
+       FLOAT    = 1 << 2
+       BRANCH   = 1 << 3
+       LOAD     = 1 << 4
+       FCMP     = 1 << 5
+       SYNC     = 1 << 6
+       LIST     = 1 << 7
+       FOLL     = 1 << 8
+       NOSCHED  = 1 << 9
+       PFX_X64B = 1 << 10 // A prefixed instruction crossing a 64B boundary
 )
 
 // Values for use in branch instruction BC
@@ -329,18 +365,13 @@ const (
        BI_OVF = 3
 )
 
-// Values for the BO field.  Add the branch type to
-// the likely bits, if a likely setting is known.
-// If branch likely or unlikely is not known, don't set it.
-// e.g. branch on cr+likely = 15
+// Common values for the BO field.
 
 const (
-       BO_BCTR     = 16 // branch on ctr value
-       BO_BCR      = 12 // branch on cr value
-       BO_BCRBCTR  = 8  // branch on ctr and cr value
-       BO_NOTBCR   = 4  // branch on not cr value
-       BO_UNLIKELY = 2  // value for unlikely
-       BO_LIKELY   = 3  // value for likely
+       BO_BCTR    = 16 // decrement ctr, branch on ctr != 0
+       BO_BCR     = 12 // branch on cr value
+       BO_BCRBCTR = 8  // decrement ctr, branch on ctr != 0 and cr value
+       BO_NOTBCR  = 4  // branch on not cr value
 )
 
 // Bit settings from the CR
@@ -353,41 +384,65 @@ const (
 )
 
 const (
-       C_NONE = iota
-       C_REG
-       C_FREG
-       C_VREG
-       C_VSREG
-       C_CREG
-       C_SPR /* special processor register */
-       C_ZCON
-       C_SCON   /* 16 bit signed */
-       C_UCON   /* 32 bit signed, low 16 bits 0 */
-       C_ADDCON /* -0x8000 <= v < 0 */
-       C_ANDCON /* 0 < v <= 0xFFFF */
-       C_LCON   /* other 32 */
-       C_DCON   /* other 64 (could subdivide further) */
-       C_SACON  /* $n(REG) where n <= int16 */
-       C_LACON  /* $n(REG) where int16 < n <= int32 */
-       C_DACON  /* $n(REG) where int32 < n */
-       C_SBRA
-       C_LBRA
-       C_LBRAPIC
-       C_ZOREG // conjecture: either (1) register + zeroed offset, or (2) "R0" implies zero or C_REG
-       C_SOREG // D/DS form memory operation
-       C_LOREG // 32 bit addis + D/DS-form memory operation
-       C_FPSCR
-       C_XER
-       C_LR
-       C_CTR
-       C_ANY
-       C_GOK
-       C_ADDR
-       C_TLS_LE
-       C_TLS_IE
-       C_TEXTSIZE
+       C_NONE     = iota
+       C_REGP     /* An even numbered gpr which can be used a gpr pair argument */
+       C_REG      /* Any gpr register */
+       C_FREGP    /* An even numbered fpr which can be used a fpr pair argument */
+       C_FREG     /* Any fpr register */
+       C_VREG     /* Any vector register */
+       C_VSREGP   /* An even numbered vsx register which can be used as a vsx register pair argument */
+       C_VSREG    /* Any vector-scalar register */
+       C_CREG     /* The condition registor (CR) */
+       C_CRBIT    /* A single bit of the CR register (0-31) */
+       C_SPR      /* special processor register */
+       C_ZCON     /* The constant zero */
+       C_U1CON    /* 1 bit unsigned constant */
+       C_U2CON    /* 2 bit unsigned constant */
+       C_U3CON    /* 3 bit unsigned constant */
+       C_U4CON    /* 4 bit unsigned constant */
+       C_U5CON    /* 5 bit unsigned constant */
+       C_U8CON    /* 8 bit unsigned constant */
+       C_U15CON   /* 15 bit unsigned constant */
+       C_S16CON   /* 16 bit signed constant */
+       C_U16CON   /* 16 bit unsigned constant */
+       C_32S16CON /* Any 32 bit constant of the form 0x....0000, signed or unsigned */
+       C_32CON    /* Any constant which fits into 32 bits. Can be signed or unsigned */
+       C_S34CON   /* 34 bit signed constant */
+       C_64CON    /* Any constant which fits into 64 bits. Can be signed or unsigned */
+       C_SACON    /* $n(REG) where n <= int16 */
+       C_LACON    /* $n(REG) where n <= int32 */
+       C_DACON    /* $n(REG) where n <= int64 */
+       C_SBRA     /* A short offset argument to a branching instruction */
+       C_LBRA     /* A long offset argument to a branching instruction */
+       C_LBRAPIC  /* Like C_LBRA, but requires an extra NOP for potential TOC restore by the linker. */
+       C_ZOREG    /* An reg+reg memory arg, or a $0+reg memory op */
+       C_SOREG    /* An $n+reg memory arg where n is a 16 bit signed offset */
+       C_LOREG    /* An $n+reg memory arg where n is a 32 bit signed offset */
+       C_FPSCR    /* The fpscr register */
+       C_XER      /* The xer, holds the carry bit */
+       C_LR       /* The link register */
+       C_CTR      /* The count register */
+       C_ANY      /* Any argument */
+       C_GOK      /* A non-matched argument */
+       C_ADDR     /* A symbolic memory location */
+       C_TLS_LE   /* A thread local, local-exec, type memory arg */
+       C_TLS_IE   /* A thread local, initial-exec, type memory arg */
+       C_TEXTSIZE /* An argument with Type obj.TYPE_TEXTSIZE */
 
        C_NCLASS /* must be the last */
+
+       /* Aliased names which should be cleaned up, or integrated. */
+       C_SCON   = C_U15CON
+       C_UCON   = C_32S16CON
+       C_ADDCON = C_S16CON
+       C_ANDCON = C_U16CON
+       C_LCON   = C_32CON
+
+       /* Aliased names which may be generated by ppc64map for the optab. */
+       C_S3216CON = C_32S16CON // TODO: these should be treated differently (e.g xoris vs addis)
+       C_U3216CON = C_32S16CON
+       C_S32CON   = C_32CON
+       C_U32CON   = C_32CON
 )
 
 const (
@@ -1017,6 +1072,9 @@ const (
        AXVCVUXDSP
        AXVCVUXWSP
 
+       /* ISA 3.1 opcodes */
+       APNOP
+
        ALAST
 
        // aliases
index fca4b3e35558b464710b4bce6d370e05cceeef99..0da73ca91ed6c9f8d1036e94c481c918ddc39f12 100644 (file)
@@ -613,5 +613,6 @@ var Anames = []string{
        "XVCVSXWSP",
        "XVCVUXDSP",
        "XVCVUXWSP",
+       "PNOP",
        "LAST",
 }
index b2632aa9ed00918155f408e0576935d3581b2eb6..05bfd944d111f099fa915c3784e35b7d41720fb6 100644 (file)
@@ -6,19 +6,30 @@ package ppc64
 
 var cnames9 = []string{
        "NONE",
+       "REGP",
        "REG",
+       "FREGP",
        "FREG",
        "VREG",
+       "VSREGP",
        "VSREG",
        "CREG",
+       "CRBIT",
        "SPR",
        "ZCON",
-       "SCON",
-       "UCON",
-       "ADDCON",
-       "ANDCON",
-       "LCON",
-       "DCON",
+       "U1CON",
+       "U2CON",
+       "U3CON",
+       "U4CON",
+       "U5CON",
+       "U8CON",
+       "U15CON",
+       "S16CON",
+       "U16CON",
+       "32S16CON",
+       "32CON",
+       "S34CON",
+       "64CON",
        "SACON",
        "LACON",
        "DACON",
index 316959f62d792763b16382e13b8ba6123ee6be06..31fbb7f7bf9723237e816982f71043bc0ba96bd7 100644 (file)
@@ -36,6 +36,7 @@ import (
        "fmt"
        "log"
        "math"
+       "math/bits"
        "sort"
 )
 
@@ -72,6 +73,12 @@ type Optab struct {
        a6    uint8  // p.To (obj.Addr)
        type_ int8   // cases in asmout below. E.g., 44 = st r,(ra+rb); 45 = ld (ra+rb), r
        size  int8   // Text space in bytes to lay operation
+
+       // A prefixed instruction is generated by this opcode. This cannot be placed
+       // across a 64B PC address. Opcodes should not translate to more than one
+       // prefixed instruction. The prefixed instruction should be written first
+       // (e.g when Optab.size > 8).
+       ispfx bool
 }
 
 // optab contains an array to be sliced of accepted operand combinations for an
@@ -300,8 +307,7 @@ var optab = []Optab{
        {as: ABC, a6: C_ZOREG, type_: 15, size: 8},
        {as: ASYNC, type_: 46, size: 4},
        {as: AWORD, a1: C_LCON, type_: 40, size: 4},
-       {as: ADWORD, a1: C_LCON, type_: 31, size: 8},
-       {as: ADWORD, a1: C_DCON, type_: 31, size: 8},
+       {as: ADWORD, a1: C_64CON, type_: 31, size: 8},
        {as: ADWORD, a1: C_LACON, type_: 31, size: 8},
        {as: AADDME, a1: C_REG, a6: C_REG, type_: 47, size: 4},
        {as: AEXTSB, a1: C_REG, a6: C_REG, type_: 48, size: 4},
@@ -329,7 +335,7 @@ var optab = []Optab{
        {as: ALDMX, a1: C_SOREG, a6: C_REG, type_: 45, size: 4},                       /* load doubleword monitored, x-form */
        {as: AMADDHD, a1: C_REG, a2: C_REG, a3: C_REG, a6: C_REG, type_: 83, size: 4}, /* multiply-add high/low doubleword, va-form */
        {as: AADDEX, a1: C_REG, a2: C_REG, a3: C_SCON, a6: C_REG, type_: 94, size: 4}, /* add extended using alternate carry, z23-form */
-       {as: ACRAND, a1: C_CREG, a6: C_CREG, type_: 2, size: 4},                       /* logical ops for condition registers xl-form */
+       {as: ACRAND, a1: C_CRBIT, a2: C_CRBIT, a6: C_CRBIT, type_: 2, size: 4},        /* logical ops for condition register bits xl-form */
 
        /* Vector instructions */
 
@@ -428,15 +434,13 @@ var optab = []Optab{
        {as: ASTXSIWX, a1: C_VSREG, a6: C_SOREG, type_: 86, size: 4}, /* vsx scalar as integer store, xx1-form */
 
        /* VSX move from VSR */
-       {as: AMFVSRD, a1: C_VSREG, a6: C_REG, type_: 88, size: 4}, /* vsx move from vsr, xx1-form */
+       {as: AMFVSRD, a1: C_VSREG, a6: C_REG, type_: 88, size: 4},
        {as: AMFVSRD, a1: C_FREG, a6: C_REG, type_: 88, size: 4},
-       {as: AMFVSRD, a1: C_VREG, a6: C_REG, type_: 88, size: 4},
 
        /* VSX move to VSR */
-       {as: AMTVSRD, a1: C_REG, a6: C_VSREG, type_: 88, size: 4}, /* vsx move to vsr, xx1-form */
-       {as: AMTVSRD, a1: C_REG, a2: C_REG, a6: C_VSREG, type_: 88, size: 4},
-       {as: AMTVSRD, a1: C_REG, a6: C_FREG, type_: 88, size: 4},
-       {as: AMTVSRD, a1: C_REG, a6: C_VREG, type_: 88, size: 4},
+       {as: AMTVSRD, a1: C_REG, a6: C_VSREG, type_: 104, size: 4},
+       {as: AMTVSRD, a1: C_REG, a6: C_FREG, type_: 104, size: 4},
+       {as: AMTVSRDD, a1: C_REG, a2: C_REG, a6: C_VSREG, type_: 104, size: 4},
 
        /* VSX logical */
        {as: AXXLAND, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx and, xx3-form */
@@ -480,15 +484,15 @@ var optab = []Optab{
        {as: AXVCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */
 
        {as: ACMP, a1: C_REG, a6: C_REG, type_: 70, size: 4},
-       {as: ACMP, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4},
+       {as: ACMP, a1: C_REG, a2: C_CREG, a6: C_REG, type_: 70, size: 4},
        {as: ACMP, a1: C_REG, a6: C_ADDCON, type_: 71, size: 4},
-       {as: ACMP, a1: C_REG, a2: C_REG, a6: C_ADDCON, type_: 71, size: 4},
+       {as: ACMP, a1: C_REG, a2: C_CREG, a6: C_ADDCON, type_: 71, size: 4},
        {as: ACMPU, a1: C_REG, a6: C_REG, type_: 70, size: 4},
-       {as: ACMPU, a1: C_REG, a2: C_REG, a6: C_REG, type_: 70, size: 4},
+       {as: ACMPU, a1: C_REG, a2: C_CREG, a6: C_REG, type_: 70, size: 4},
        {as: ACMPU, a1: C_REG, a6: C_ANDCON, type_: 71, size: 4},
-       {as: ACMPU, a1: C_REG, a2: C_REG, a6: C_ANDCON, type_: 71, size: 4},
+       {as: ACMPU, a1: C_REG, a2: C_CREG, a6: C_ANDCON, type_: 71, size: 4},
        {as: AFCMPO, a1: C_FREG, a6: C_FREG, type_: 70, size: 4},
-       {as: AFCMPO, a1: C_FREG, a2: C_REG, a6: C_FREG, type_: 70, size: 4},
+       {as: AFCMPO, a1: C_FREG, a2: C_CREG, a6: C_FREG, type_: 70, size: 4},
        {as: ATW, a1: C_LCON, a2: C_REG, a6: C_REG, type_: 60, size: 4},
        {as: ATW, a1: C_LCON, a2: C_REG, a6: C_ADDCON, type_: 61, size: 4},
        {as: ADCBF, a1: C_ZOREG, type_: 43, size: 4},
@@ -510,6 +514,9 @@ var optab = []Optab{
        {as: ASTSW, a1: C_REG, a3: C_LCON, a6: C_ZOREG, type_: 41, size: 4},
        {as: ALSW, a1: C_ZOREG, a6: C_REG, type_: 45, size: 4},
        {as: ALSW, a1: C_ZOREG, a3: C_LCON, a6: C_REG, type_: 42, size: 4},
+
+       {as: APNOP, type_: 105, size: 8, ispfx: true},
+
        {as: obj.AUNDEF, type_: 78, size: 4},
        {as: obj.APCDATA, a1: C_LCON, a6: C_LCON, type_: 0, size: 0},
        {as: obj.AFUNCDATA, a1: C_SCON, a6: C_ADDR, type_: 0, size: 0},
@@ -576,9 +583,11 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
 // or "MOVD R5, foo+10(SP) or pseudo-register is used.  The other common case is when
 // generating constants in register like "MOVD $constant, Rx".
 func (c *ctxt9) getimpliedreg(a *obj.Addr, p *obj.Prog) int {
-       switch oclass(a) {
-       case C_ADDCON, C_ANDCON, C_UCON, C_LCON, C_SCON, C_ZCON:
+       class := oclass(a)
+       if class >= C_ZCON && class <= C_64CON {
                return REGZERO
+       }
+       switch class {
        case C_SACON, C_LACON:
                return REGSP
        case C_LOREG, C_SOREG, C_ZOREG:
@@ -642,9 +651,12 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 
        var otxt int64
        var q *obj.Prog
+       var out [6]uint32
+       var falign int32 // Track increased alignment requirements for prefix.
        for bflag != 0 {
                bflag = 0
                pc = 0
+               falign = 0 // Note, linker bumps function symbols to funcAlign.
                for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
                        p.Pc = pc
                        o = c.oplook(p)
@@ -653,22 +665,74 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                        if (o.type_ == 16 || o.type_ == 17) && p.To.Target() != nil {
                                otxt = p.To.Target().Pc - pc
                                if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
-                                       q = c.newprog()
-                                       q.Link = p.Link
-                                       p.Link = q
-                                       q.As = ABR
-                                       q.To.Type = obj.TYPE_BRANCH
-                                       q.To.SetTarget(p.To.Target())
-                                       p.To.SetTarget(q)
-                                       q = c.newprog()
-                                       q.Link = p.Link
-                                       p.Link = q
-                                       q.As = ABR
-                                       q.To.Type = obj.TYPE_BRANCH
-                                       q.To.SetTarget(q.Link.Link)
-
-                                       //addnop(p->link);
-                                       //addnop(p);
+                                       // Assemble the instruction with a target not too far to figure out BI and BO fields.
+                                       // If only the CTR or BI (the CR bit) are tested, the conditional branch can be inverted,
+                                       // and only one extra branch is needed to reach the target.
+                                       tgt := p.To.Target()
+                                       p.To.SetTarget(p.Link)
+                                       c.asmout(p, o, out[:])
+                                       p.To.SetTarget(tgt)
+
+                                       bo := int64(out[0]>>21) & 31
+                                       bi := int16((out[0] >> 16) & 31)
+                                       invertible := false
+
+                                       if bo&0x14 == 0x14 {
+                                               // A conditional branch that is unconditionally taken. This cannot be inverted.
+                                       } else if bo&0x10 == 0x10 {
+                                               // A branch based on the value of CTR. Invert the CTR comparison against zero bit.
+                                               bo ^= 0x2
+                                               invertible = true
+                                       } else if bo&0x04 == 0x04 {
+                                               // A branch based on CR bit. Invert the BI comparison bit.
+                                               bo ^= 0x8
+                                               invertible = true
+                                       }
+
+                                       if invertible {
+                                               // Rewrite
+                                               //     BC bo,...,far_away_target
+                                               //     NEXT_INSN
+                                               // to:
+                                               //     BC invert(bo),next_insn
+                                               //     JMP far_away_target
+                                               //   next_insn:
+                                               //     NEXT_INSN
+                                               p.As = ABC
+                                               p.From = obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: bo}
+                                               q = c.newprog()
+                                               q.As = ABR
+                                               q.To.Type = obj.TYPE_BRANCH
+                                               q.To.SetTarget(p.To.Target())
+                                               q.Link = p.Link
+                                               p.To.SetTarget(p.Link)
+                                               p.Link = q
+                                               p.Reg = bi // TODO: This is a hack since BI bits are not enumerated as registers
+                                       } else {
+                                               // Rewrite
+                                               //     BC ...,far_away_target
+                                               //     NEXT_INSN
+                                               // to
+                                               //     BC ...,tmp
+                                               //     JMP next_insn
+                                               //   tmp:
+                                               //     JMP far_away_target
+                                               //   next_insn:
+                                               //     NEXT_INSN
+                                               q = c.newprog()
+                                               q.Link = p.Link
+                                               p.Link = q
+                                               q.As = ABR
+                                               q.To.Type = obj.TYPE_BRANCH
+                                               q.To.SetTarget(p.To.Target())
+                                               p.To.SetTarget(q)
+                                               q = c.newprog()
+                                               q.Link = p.Link
+                                               p.Link = q
+                                               q.As = ABR
+                                               q.To.Type = obj.TYPE_BRANCH
+                                               q.To.SetTarget(q.Link.Link)
+                                       }
                                        bflag = 1
                                }
                        }
@@ -686,27 +750,57 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                }
                        }
 
+                       // Prefixed instructions cannot be placed across a 64B boundary.
+                       // Mark and adjust the PC of those which do. A nop will be
+                       // inserted during final assembly.
+                       if o.ispfx {
+                               mark := p.Mark &^ PFX_X64B
+                               if pc&63 == 60 {
+                                       p.Pc += 4
+                                       m += 4
+                                       mark |= PFX_X64B
+                               }
+
+                               // Marks may be adjusted if a too-far conditional branch is
+                               // fixed up above. Likewise, inserting a NOP may cause a
+                               // branch target to become too far away.  We need to run
+                               // another iteration and verify no additional changes
+                               // are needed.
+                               if mark != p.Mark {
+                                       bflag = 1
+                                       p.Mark = mark
+                               }
+
+                               // Check for 16 or 32B crossing of this prefixed insn.
+                               // These do no require padding, but do require increasing
+                               // the function alignment to prevent them from potentially
+                               // crossing a 64B boundary when the linker assigns the final
+                               // PC.
+                               switch p.Pc & 31 {
+                               case 28: // 32B crossing
+                                       falign = 64
+                               case 12: // 16B crossing
+                                       if falign < 64 {
+                                               falign = 32
+                                       }
+                               }
+                       }
+
                        pc += int64(m)
                }
 
                c.cursym.Size = pc
        }
 
-       if r := pc & funcAlignMask; r != 0 {
-               pc += funcAlign - r
-       }
-
        c.cursym.Size = pc
-
-       /*
-        * lay out the code, emitting code and data relocations.
-        */
-
+       c.cursym.Func().Align = falign
        c.cursym.Grow(c.cursym.Size)
 
+       // lay out the code, emitting code and data relocations.
+
        bp := c.cursym.P
+       nop := LOP_IRR(OP_ORI, REGZERO, REGZERO, 0)
        var i int32
-       var out [6]uint32
        for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
                c.pc = p.Pc
                o = c.oplook(p)
@@ -715,17 +809,20 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                }
                // asmout is not set up to add large amounts of padding
                if o.type_ == 0 && p.As == obj.APCALIGN {
-                       pad := LOP_RRR(OP_OR, REGZERO, REGZERO, REGZERO)
                        aln := c.vregoff(&p.From)
                        v := addpad(p.Pc, aln, c.ctxt, c.cursym)
                        if v > 0 {
                                // Same padding instruction for all
                                for i = 0; i < int32(v/4); i++ {
-                                       c.ctxt.Arch.ByteOrder.PutUint32(bp, pad)
+                                       c.ctxt.Arch.ByteOrder.PutUint32(bp, nop)
                                        bp = bp[4:]
                                }
                        }
                } else {
+                       if p.Mark&PFX_X64B != 0 {
+                               c.ctxt.Arch.ByteOrder.PutUint32(bp, nop)
+                               bp = bp[4:]
+                       }
                        c.asmout(p, o, out[:])
                        for i = 0; i < int32(o.size/4); i++ {
                                c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
@@ -743,49 +840,52 @@ func isuint32(v uint64) bool {
        return uint64(uint32(v)) == v
 }
 
+func (c *ctxt9) aclassreg(reg int16) int {
+       if REG_R0 <= reg && reg <= REG_R31 {
+               return C_REGP + int(reg&1)
+       }
+       if REG_F0 <= reg && reg <= REG_F31 {
+               return C_FREGP + int(reg&1)
+       }
+       if REG_V0 <= reg && reg <= REG_V31 {
+               return C_VREG
+       }
+       if REG_VS0 <= reg && reg <= REG_VS63 {
+               return C_VSREGP + int(reg&1)
+       }
+       if REG_CR0 <= reg && reg <= REG_CR7 || reg == REG_CR {
+               return C_CREG
+       }
+       if REG_CR0LT <= reg && reg <= REG_CR7SO {
+               return C_CRBIT
+       }
+       if REG_SPR0 <= reg && reg <= REG_SPR0+1023 {
+               switch reg {
+               case REG_LR:
+                       return C_LR
+
+               case REG_XER:
+                       return C_XER
+
+               case REG_CTR:
+                       return C_CTR
+               }
+
+               return C_SPR
+       }
+       if reg == REG_FPSCR {
+               return C_FPSCR
+       }
+       return C_GOK
+}
+
 func (c *ctxt9) aclass(a *obj.Addr) int {
        switch a.Type {
        case obj.TYPE_NONE:
                return C_NONE
 
        case obj.TYPE_REG:
-               if REG_R0 <= a.Reg && a.Reg <= REG_R31 {
-                       return C_REG
-               }
-               if REG_F0 <= a.Reg && a.Reg <= REG_F31 {
-                       return C_FREG
-               }
-               if REG_V0 <= a.Reg && a.Reg <= REG_V31 {
-                       return C_VREG
-               }
-               if REG_VS0 <= a.Reg && a.Reg <= REG_VS63 {
-                       return C_VSREG
-               }
-               if REG_CR0 <= a.Reg && a.Reg <= REG_CR7 || a.Reg == REG_CR {
-                       return C_CREG
-               }
-               if REG_SPR0 <= a.Reg && a.Reg <= REG_SPR0+1023 {
-                       switch a.Reg {
-                       case REG_LR:
-                               return C_LR
-
-                       case REG_XER:
-                               return C_XER
-
-                       case REG_CTR:
-                               return C_CTR
-                       }
-
-                       return C_SPR
-               }
-
-               if REG_DCR0 <= a.Reg && a.Reg <= REG_DCR0+1023 {
-                       return C_SPR
-               }
-               if a.Reg == REG_FPSCR {
-                       return C_FPSCR
-               }
-               return C_GOK
+               return c.aclassreg(a.Reg)
 
        case obj.TYPE_MEM:
                switch a.Name {
@@ -856,7 +956,7 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
                case obj.NAME_NONE:
                        c.instoffset = a.Offset
                        if a.Reg != 0 {
-                               if -BIG <= c.instoffset && c.instoffset <= BIG {
+                               if -BIG <= c.instoffset && c.instoffset < BIG {
                                        return C_SACON
                                }
                                if isint32(c.instoffset) {
@@ -893,35 +993,47 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
                }
 
                if c.instoffset >= 0 {
-                       if c.instoffset == 0 {
-                               return C_ZCON
-                       }
-                       if c.instoffset <= 0x7fff {
-                               return C_SCON
-                       }
-                       if c.instoffset <= 0xffff {
-                               return C_ANDCON
-                       }
-                       if c.instoffset&0xffff == 0 && isuint32(uint64(c.instoffset)) { /* && (instoffset & (1<<31)) == 0) */
-                               return C_UCON
+                       sbits := bits.Len64(uint64(c.instoffset))
+                       switch {
+                       case sbits <= 5:
+                               return C_ZCON + sbits
+                       case sbits <= 8:
+                               return C_U8CON
+                       case sbits <= 15:
+                               return C_U15CON
+                       case sbits <= 16:
+                               return C_U16CON
+                       case sbits <= 31:
+                               // Special case, a positive int32 value which is a multiple of 2^16
+                               if c.instoffset&0xFFFF == 0 {
+                                       return C_U3216CON
+                               }
+                               return C_U32CON
+                       case sbits <= 32:
+                               return C_U32CON
+                       case sbits <= 33:
+                               return C_S34CON
+                       default:
+                               return C_64CON
                        }
-                       if isint32(c.instoffset) || isuint32(uint64(c.instoffset)) {
-                               return C_LCON
+               } else {
+                       sbits := bits.Len64(uint64(^c.instoffset))
+                       switch {
+                       case sbits <= 15:
+                               return C_S16CON
+                       case sbits <= 31:
+                               // Special case, a negative int32 value which is a multiple of 2^16
+                               if c.instoffset&0xFFFF == 0 {
+                                       return C_S3216CON
+                               }
+                               return C_S32CON
+                       case sbits <= 33:
+                               return C_S34CON
+                       default:
+                               return C_64CON
                        }
-                       return C_DCON
                }
 
-               if c.instoffset >= -0x8000 {
-                       return C_ADDCON
-               }
-               if c.instoffset&0xffff == 0 && isint32(c.instoffset) {
-                       return C_UCON
-               }
-               if isint32(c.instoffset) {
-                       return C_LCON
-               }
-               return C_DCON
-
        case obj.TYPE_BRANCH:
                if a.Sym != nil && c.ctxt.Flag_dynlink {
                        return C_LBRAPIC
@@ -970,27 +1082,20 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
 
        a2 := C_NONE
        if p.Reg != 0 {
-               if REG_R0 <= p.Reg && p.Reg <= REG_R31 {
-                       a2 = C_REG
-               } else if REG_V0 <= p.Reg && p.Reg <= REG_V31 {
-                       a2 = C_VREG
-               } else if REG_VS0 <= p.Reg && p.Reg <= REG_VS63 {
-                       a2 = C_VSREG
-               } else if REG_F0 <= p.Reg && p.Reg <= REG_F31 {
-                       a2 = C_FREG
-               }
+               a2 = c.aclassreg(p.Reg)
        }
 
        // c.ctxt.Logf("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4, a5, a6)
        ops := oprange[p.As&obj.AMask]
        c1 := &xcmp[a1]
+       c2 := &xcmp[a2]
        c3 := &xcmp[a3]
        c4 := &xcmp[a4]
        c5 := &xcmp[a5]
        c6 := &xcmp[a6]
        for i := range ops {
                op := &ops[i]
-               if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && c4[op.a4] && c5[op.a5] && c6[op.a6] {
+               if c1[op.a1] && c2[op.a2] && c3[op.a3] && c4[op.a4] && c5[op.a5] && c6[op.a6] {
                        p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
                        return op
                }
@@ -1004,65 +1109,72 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
        return &ops[0]
 }
 
+// Compare two operand types (ex C_REG, or C_SCON)
+// and return true if b is compatible with a.
+//
+// Argument comparison isn't reflexitive, so care must be taken.
+// a is the argument type as found in optab, b is the argument as
+// fitted by aclass.
 func cmp(a int, b int) bool {
        if a == b {
                return true
        }
        switch a {
-       case C_LCON:
-               if b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON {
-                       return true
-               }
-
-       case C_ADDCON:
-               if b == C_ZCON || b == C_SCON {
-                       return true
-               }
-
-       case C_ANDCON:
-               if b == C_ZCON || b == C_SCON {
-                       return true
-               }
 
        case C_SPR:
                if b == C_LR || b == C_XER || b == C_CTR {
                        return true
                }
 
-       case C_UCON:
-               if b == C_ZCON {
-                       return true
-               }
-
-       case C_SCON:
-               if b == C_ZCON {
-                       return true
-               }
+       case C_U1CON:
+               return cmp(C_ZCON, b)
+       case C_U2CON:
+               return cmp(C_U1CON, b)
+       case C_U3CON:
+               return cmp(C_U2CON, b)
+       case C_U4CON:
+               return cmp(C_U3CON, b)
+       case C_U5CON:
+               return cmp(C_U4CON, b)
+       case C_U8CON:
+               return cmp(C_U5CON, b)
+       case C_U15CON:
+               return cmp(C_U8CON, b)
+       case C_U16CON:
+               return cmp(C_U15CON, b)
+
+       case C_S16CON:
+               return cmp(C_U15CON, b)
+       case C_32CON:
+               return cmp(C_S16CON, b) || cmp(C_U16CON, b) || cmp(C_32S16CON, b)
+       case C_S34CON:
+               return cmp(C_32CON, b)
+       case C_64CON:
+               return cmp(C_S34CON, b)
+
+       case C_32S16CON:
+               return cmp(C_ZCON, b)
 
        case C_LACON:
-               if b == C_SACON {
-                       return true
-               }
+               return cmp(C_SACON, b)
 
        case C_LBRA:
-               if b == C_SBRA {
-                       return true
-               }
+               return cmp(C_SBRA, b)
 
        case C_SOREG:
-               if b == C_ZOREG {
-                       return true
-               }
+               return cmp(C_ZOREG, b)
 
        case C_LOREG:
-               if b == C_SOREG || b == C_ZOREG {
-                       return true
-               }
+               return cmp(C_SOREG, b)
 
+       // An even/odd register input always matches the regular register types.
        case C_REG:
-               if b == C_ZCON {
-                       return r0iszero != 0 /*TypeKind(100016)*/
-               }
+               return cmp(C_REGP, b) || (b == C_ZCON && r0iszero != 0)
+       case C_FREG:
+               return cmp(C_FREGP, b)
+       case C_VSREG:
+               /* Allow any VR argument as a VSR operand. */
+               return cmp(C_VSREGP, b) || cmp(C_VREG, b)
 
        case C_ANY:
                return true
@@ -1542,7 +1654,6 @@ func buildop(ctxt *obj.Link) {
                        opset(AMTVRD, r0)
                        opset(AMTVSRWA, r0)
                        opset(AMTVSRWZ, r0)
-                       opset(AMTVSRDD, r0)
                        opset(AMTVSRWS, r0)
 
                case AXXLAND: /* xxland, xxlandc, xxleqv, xxlnand */
@@ -1925,6 +2036,8 @@ func buildop(ctxt *obj.Link) {
                        ACMPEQB,
                        AECIWX,
                        ACLRLSLWI,
+                       AMTVSRDD,
+                       APNOP,
                        obj.ANOP,
                        obj.ATEXT,
                        obj.AUNDEF,
@@ -2023,50 +2136,32 @@ func AOP_IR(op uint32, d uint32, simm uint32) uint32 {
 }
 
 /* XX1-form 3-register operands, 1 VSR operand */
-func AOP_XX1(op uint32, d uint32, a uint32, b uint32) uint32 {
-       /* For the XX-form encodings, we need the VSX register number to be exactly */
-       /* between 0-63, so we can properly set the rightmost bits. */
-       r := d - REG_VS0
+func AOP_XX1(op uint32, r uint32, a uint32, b uint32) uint32 {
        return op | (r&31)<<21 | (a&31)<<16 | (b&31)<<11 | (r&32)>>5
 }
 
 /* XX2-form 3-register operands, 2 VSR operands */
-func AOP_XX2(op uint32, d uint32, a uint32, b uint32) uint32 {
-       xt := d - REG_VS0
-       xb := b - REG_VS0
+func AOP_XX2(op uint32, xt uint32, a uint32, xb uint32) uint32 {
        return op | (xt&31)<<21 | (a&3)<<16 | (xb&31)<<11 | (xb&32)>>4 | (xt&32)>>5
 }
 
 /* XX3-form 3 VSR operands */
-func AOP_XX3(op uint32, d uint32, a uint32, b uint32) uint32 {
-       xt := d - REG_VS0
-       xa := a - REG_VS0
-       xb := b - REG_VS0
+func AOP_XX3(op uint32, xt uint32, xa uint32, xb uint32) uint32 {
        return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
 }
 
 /* XX3-form 3 VSR operands + immediate */
-func AOP_XX3I(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
-       xt := d - REG_VS0
-       xa := a - REG_VS0
-       xb := b - REG_VS0
+func AOP_XX3I(op uint32, xt uint32, xa uint32, xb uint32, c uint32) uint32 {
        return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (c&3)<<8 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
 }
 
 /* XX4-form, 4 VSR operands */
-func AOP_XX4(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
-       xt := d - REG_VS0
-       xa := a - REG_VS0
-       xb := b - REG_VS0
-       xc := c - REG_VS0
+func AOP_XX4(op uint32, xt uint32, xa uint32, xb uint32, xc uint32) uint32 {
        return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (xc&31)<<6 | (xc&32)>>2 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
 }
 
 /* DQ-form, VSR register, register + offset operands */
-func AOP_DQ(op uint32, d uint32, a uint32, b uint32) uint32 {
-       /* For the DQ-form encodings, we need the VSX register number to be exactly */
-       /* between 0-63, so we can properly set the SX bit. */
-       r := d - REG_VS0
+func AOP_DQ(op uint32, xt uint32, a uint32, b uint32) uint32 {
        /* The EA for this instruction form is (RA) + DQ << 4, where DQ is a 12-bit signed integer. */
        /* In order to match the output of the GNU objdump (and make the usage in Go asm easier), the */
        /* instruction is called using the sign extended value (i.e. a valid offset would be -32752 or 32752, */
@@ -2074,7 +2169,7 @@ func AOP_DQ(op uint32, d uint32, a uint32, b uint32) uint32 {
        /* bits 0 to 3 in 'dq' need to be zero, otherwise this will generate an illegal instruction. */
        /* If in doubt how this instruction form is encoded, refer to ISA 3.0b, pages 492 and 507. */
        dq := b >> 4
-       return op | (r&31)<<21 | (a&31)<<16 | (dq&4095)<<4 | (r&32)>>2
+       return op | (xt&31)<<21 | (a&31)<<16 | (dq&4095)<<4 | (xt&32)>>2
 }
 
 /* Z23-form, 3-register operands + CY field */
@@ -3302,56 +3397,46 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                }
                o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(c.regoff(&p.From))&31)<<12
 
-       case 66: /* mov spr,r1; mov r1,spr, also dcr */
+       case 66: /* mov spr,r1; mov r1,spr */
                var r int
                var v int32
                if REG_R0 <= p.From.Reg && p.From.Reg <= REG_R31 {
                        r = int(p.From.Reg)
                        v = int32(p.To.Reg)
-                       if REG_DCR0 <= v && v <= REG_DCR0+1023 {
-                               o1 = OPVCC(31, 451, 0, 0) /* mtdcr */
-                       } else {
-                               o1 = OPVCC(31, 467, 0, 0) /* mtspr */
-                       }
+                       o1 = OPVCC(31, 467, 0, 0) /* mtspr */
                } else {
                        r = int(p.To.Reg)
                        v = int32(p.From.Reg)
-                       if REG_DCR0 <= v && v <= REG_DCR0+1023 {
-                               o1 = OPVCC(31, 323, 0, 0) /* mfdcr */
-                       } else {
-                               o1 = OPVCC(31, 339, 0, 0) /* mfspr */
-                       }
+                       o1 = OPVCC(31, 339, 0, 0) /* mfspr */
                }
 
                o1 = AOP_RRR(o1, uint32(r), 0, 0) | (uint32(v)&0x1f)<<16 | ((uint32(v)>>5)&0x1f)<<11
 
        case 67: /* mcrf crfD,crfS */
-               if p.From.Type != obj.TYPE_REG || p.From.Reg < REG_CR0 || REG_CR7 < p.From.Reg || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
-                       c.ctxt.Diag("illegal CR field number\n%v", p)
+               if p.From.Reg == REG_CR || p.To.Reg == REG_CR {
+                       c.ctxt.Diag("CR argument must be a conditional register field (CR0-CR7)\n%v", p)
                }
                o1 = AOP_RRR(OP_MCRF, ((uint32(p.To.Reg) & 7) << 2), ((uint32(p.From.Reg) & 7) << 2), 0)
 
        case 68: /* mfcr rD; mfocrf CRM,rD */
-               if p.From.Type == obj.TYPE_REG && REG_CR0 <= p.From.Reg && p.From.Reg <= REG_CR7 {
-                       v := int32(1 << uint(7-(p.To.Reg&7)))                                 /* CR(n) */
-                       o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) | 1<<20 | uint32(v)<<12 /* new form, mfocrf */
-               } else {
-                       o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /* old form, whole register */
+               o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /*  form, whole register */
+               if p.From.Reg != REG_CR {
+                       v := uint32(1) << uint(7-(p.From.Reg&7)) /* CR(n) */
+                       o1 |= 1<<20 | v<<12                      /* new form, mfocrf */
                }
 
-       case 69: /* mtcrf CRM,rS */
-               var v int32
-               if p.From3Type() != obj.TYPE_NONE {
-                       if p.To.Reg != 0 {
-                               c.ctxt.Diag("can't use both mask and CR(n)\n%v", p)
-                       }
-                       v = c.regoff(p.GetFrom3()) & 0xff
-               } else {
-                       if p.To.Reg == 0 {
-                               v = 0xff /* CR */
-                       } else {
-                               v = 1 << uint(7-(p.To.Reg&7)) /* CR(n) */
-                       }
+       case 69: /* mtcrf CRM,rS, mtocrf CRx,rS */
+               var v uint32
+               if p.To.Reg == REG_CR {
+                       v = 0xff
+               } else if p.To.Offset != 0 { // MOVFL gpr, constant
+                       v = uint32(p.To.Offset)
+               } else { // p.To.Reg == REG_CRx
+                       v = 1 << uint(7-(p.To.Reg&7))
+               }
+               // Use mtocrf form if only one CR field moved.
+               if bits.OnesCount32(v) == 1 {
+                       v |= 1 << 8
                }
 
                o1 = AOP_RRR(OP_MTCRF, uint32(p.From.Reg), 0, 0) | uint32(v)<<12
@@ -3534,33 +3619,8 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                /* 3-register operand order: (RB)(RA*1), XT */
                o1 = AOP_XX1(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
 
-       case 88: /* VSX instructions, XX1-form */
-               /* reg reg none OR reg reg reg */
-               /* 3-register operand order: RA, RB, XT */
-               /* 2-register operand order: XS, RA or RA, XT */
-               xt := int32(p.To.Reg)
-               xs := int32(p.From.Reg)
-               /* We need to treat the special case of extended mnemonics that may have a FREG/VREG as an argument */
-               if REG_V0 <= xt && xt <= REG_V31 {
-                       /* Convert V0-V31 to VS32-VS63 */
-                       xt = xt + 64
-                       o1 = AOP_XX1(c.oprrr(p.As), uint32(xt), uint32(p.From.Reg), uint32(p.Reg))
-               } else if REG_F0 <= xt && xt <= REG_F31 {
-                       /* Convert F0-F31 to VS0-VS31 */
-                       xt = xt + 64
-                       o1 = AOP_XX1(c.oprrr(p.As), uint32(xt), uint32(p.From.Reg), uint32(p.Reg))
-               } else if REG_VS0 <= xt && xt <= REG_VS63 {
-                       o1 = AOP_XX1(c.oprrr(p.As), uint32(xt), uint32(p.From.Reg), uint32(p.Reg))
-               } else if REG_V0 <= xs && xs <= REG_V31 {
-                       /* Likewise for XS */
-                       xs = xs + 64
-                       o1 = AOP_XX1(c.oprrr(p.As), uint32(xs), uint32(p.To.Reg), uint32(p.Reg))
-               } else if REG_F0 <= xs && xs <= REG_F31 {
-                       xs = xs + 64
-                       o1 = AOP_XX1(c.oprrr(p.As), uint32(xs), uint32(p.To.Reg), uint32(p.Reg))
-               } else if REG_VS0 <= xs && xs <= REG_VS63 {
-                       o1 = AOP_XX1(c.oprrr(p.As), uint32(xs), uint32(p.To.Reg), uint32(p.Reg))
-               }
+       case 88: /* VSX mfvsr* instructions, XX1-form XS,RA */
+               o1 = AOP_XX1(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
 
        case 89: /* VSX instructions, XX2-form */
                /* reg none reg OR reg imm reg */
@@ -3691,6 +3751,13 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                mb := uint32(c.regoff(&p.RestArgs[0].Addr))
                me := uint32(c.regoff(&p.RestArgs[1].Addr))
                o1 = OP_RLW(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From.Reg), mb, me)
+
+       case 104: /* VSX mtvsr* instructions, XX1-form RA,RB,XT */
+               o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
+
+       case 105: /* PNOP */
+               o1 = 0x07000000
+               o2 = 0x00000000
        }
 
        out[0] = o1
index 70dabc20175a61ffddb75683b8056b3f6cfe6d0a..ee2e5962f753ea43fdf6e5500858d911a73fd513 100644 (file)
@@ -5,8 +5,13 @@
 package ppc64
 
 import (
+       "bytes"
+       "cmd/internal/obj"
+       "cmd/internal/objabi"
+       "fmt"
        "internal/testenv"
        "io/ioutil"
+       "math"
        "os"
        "os/exec"
        "path/filepath"
@@ -15,14 +20,20 @@ import (
        "testing"
 )
 
-var invalidPCAlignSrc = `
+var platformEnvs = [][]string{
+       {"GOOS=aix", "GOARCH=ppc64"},
+       {"GOOS=linux", "GOARCH=ppc64"},
+       {"GOOS=linux", "GOARCH=ppc64le"},
+}
+
+const invalidPCAlignSrc = `
 TEXT test(SB),0,$0-0
 ADD $2, R3
 PCALIGN $64
 RET
 `
 
-var validPCAlignSrc = `
+const validPCAlignSrc = `
 TEXT test(SB),0,$0-0
 ADD $2, R3
 PCALIGN $16
@@ -35,6 +46,287 @@ ADD $4, R8
 RET
 `
 
+const x64pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+`
+const x32pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+`
+
+const x16pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+`
+
+const x0pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+`
+const x64pgmA64 = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+`
+
+const x64pgmA32 = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+`
+
+// Test that nops are inserted when crossing 64B boundaries, and
+// alignment is adjusted to avoid crossing.
+func TestPfxAlign(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       dir, err := ioutil.TempDir("", "testpfxalign")
+       if err != nil {
+               t.Fatalf("could not create directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       pgms := []struct {
+               text   []byte
+               align  string
+               hasNop bool
+       }{
+               {[]byte(x0pgm), "align=0x0", false},     // No alignment or nop adjustments needed
+               {[]byte(x16pgm), "align=0x20", false},   // Increased alignment needed
+               {[]byte(x32pgm), "align=0x40", false},   // Worst case alignment needed
+               {[]byte(x64pgm), "align=0x0", true},     // 0 aligned is default (16B) alignment
+               {[]byte(x64pgmA64), "align=0x40", true}, // extra alignment + nop
+               {[]byte(x64pgmA32), "align=0x20", true}, // extra alignment + nop
+       }
+
+       for _, pgm := range pgms {
+               tmpfile := filepath.Join(dir, "x.s")
+               err = ioutil.WriteFile(tmpfile, pgm.text, 0644)
+               if err != nil {
+                       t.Fatalf("can't write output: %v\n", err)
+               }
+               cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
+               cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=ppc64le")
+               out, err := cmd.CombinedOutput()
+               if err != nil {
+                       t.Errorf("Failed to compile %v: %v\n", pgm, err)
+               }
+               if !strings.Contains(string(out), pgm.align) {
+                       t.Errorf(fmt.Sprintf("Fatal, misaligned text with prefixed instructions:\n%s\n", string(out)))
+               }
+               hasNop := strings.Contains(string(out), "00 00 00 60")
+               if hasNop != pgm.hasNop {
+                       t.Errorf(fmt.Sprintf("Fatal, prefixed instruction is missing nop padding:\n%s\n", string(out)))
+               }
+       }
+}
+
+// TestLarge generates a very large file to verify that large
+// program builds successfully, and branches which exceed the
+// range of BC are rewritten to reach.
+func TestLarge(t *testing.T) {
+       if testing.Short() {
+               t.Skip("Skip in short mode")
+       }
+       testenv.MustHaveGoBuild(t)
+
+       dir, err := ioutil.TempDir("", "testlarge")
+       if err != nil {
+               t.Fatalf("could not create directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       // A few interesting test cases for long conditional branch fixups
+       tests := []struct {
+               jmpinsn     string
+               backpattern []string
+               fwdpattern  []string
+       }{
+               // Test the interesting cases of conditional branch rewrites for too-far targets. Simple conditional
+               // branches can be made to reach with one JMP insertion, compound conditionals require two.
+               //
+               // TODO: BI is interpreted as a register (the R???x/R0 should be $x)
+               // beq <-> bne conversion (insert one jump)
+               {"BEQ",
+                       []string{``,
+                               `0x20030 131120\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s131128`,
+                               `0x20034 131124\s\(.*\)\tJMP\t0`},
+                       []string{``,
+                               `0x0000 00000\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s8`,
+                               `0x0004 00004\s\(.*\)\tJMP\t131128`},
+               },
+               {"BNE",
+                       []string{``,
+                               `0x20030 131120\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s131128`,
+                               `0x20034 131124\s\(.*\)\tJMP\t0`},
+                       []string{``,
+                               `0x0000 00000\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s8`,
+                               `0x0004 00004\s\(.*\)\tJMP\t131128`}},
+               // bdnz (BC 16,0,tgt) <-> bdz (BC 18,0,+4) conversion (insert one jump)
+               {"BC 16,0,",
+                       []string{``,
+                               `0x20030 131120\s\(.*\)\tBC\t\$18,\s131128`,
+                               `0x20034 131124\s\(.*\)\tJMP\t0`},
+                       []string{``,
+                               `0x0000 00000\s\(.*\)\tBC\t\$18,\s8`,
+                               `0x0004 00004\s\(.*\)\tJMP\t131128`}},
+               {"BC 18,0,",
+                       []string{``,
+                               `0x20030 131120\s\(.*\)\tBC\t\$16,\s131128`,
+                               `0x20034 131124\s\(.*\)\tJMP\t0`},
+                       []string{``,
+                               `0x0000 00000\s\(.*\)\tBC\t\$16,\s8`,
+                               `0x0004 00004\s\(.*\)\tJMP\t131128`}},
+               // bdnzt (BC 8,0,tgt) <-> bdnzt (BC 8,0,+4) conversion (insert two jumps)
+               {"BC 8,0,",
+                       []string{``,
+                               `0x20034 131124\s\(.*\)\tBC\t\$8,\sR0,\s131132`,
+                               `0x20038 131128\s\(.*\)\tJMP\t131136`,
+                               `0x2003c 131132\s\(.*\)\tJMP\t0\n`},
+                       []string{``,
+                               `0x0000 00000\s\(.*\)\tBC\t\$8,\sR0,\s8`,
+                               `0x0004 00004\s\(.*\)\tJMP\t12`,
+                               `0x0008 00008\s\(.*\)\tJMP\t131136\n`}},
+       }
+
+       for _, test := range tests {
+               // generate a very large function
+               buf := bytes.NewBuffer(make([]byte, 0, 7000000))
+               gen(buf, test.jmpinsn)
+
+               tmpfile := filepath.Join(dir, "x.s")
+               err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
+               if err != nil {
+                       t.Fatalf("can't write output: %v\n", err)
+               }
+
+               // Test on all supported ppc64 platforms
+               for _, platenv := range platformEnvs {
+                       cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
+                       cmd.Env = append(os.Environ(), platenv...)
+                       out, err := cmd.CombinedOutput()
+                       if err != nil {
+                               t.Errorf("Assemble failed (%v): %v, output: %s", platenv, err, out)
+                       }
+                       matched, err := regexp.MatchString(strings.Join(test.fwdpattern, "\n\t*"), string(out))
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if !matched {
+                               t.Errorf("Failed to detect long foward BC fixup in (%v):%s\n", platenv, out)
+                       }
+                       matched, err = regexp.MatchString(strings.Join(test.backpattern, "\n\t*"), string(out))
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if !matched {
+                               t.Errorf("Failed to detect long backward BC fixup in (%v):%s\n", platenv, out)
+                       }
+               }
+       }
+}
+
+// gen generates a very large program with a very long forward and backwards conditional branch.
+func gen(buf *bytes.Buffer, jmpinsn string) {
+       fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
+       fmt.Fprintln(buf, "label_start:")
+       fmt.Fprintln(buf, jmpinsn, "label_end")
+       for i := 0; i < (1<<15 + 10); i++ {
+               fmt.Fprintln(buf, "MOVD R0, R1")
+       }
+       fmt.Fprintln(buf, jmpinsn, "label_start")
+       fmt.Fprintln(buf, "label_end:")
+       fmt.Fprintln(buf, "MOVD R0, R1")
+       fmt.Fprintln(buf, "RET")
+}
+
 // TestPCalign generates two asm files containing the
 // PCALIGN directive, to verify correct values are and
 // accepted, and incorrect values are flagged in error.
@@ -107,3 +399,157 @@ func TestPCalign(t *testing.T) {
                t.Errorf("Invalid alignment not detected for PCALIGN\n")
        }
 }
+
+// Verify register constants are correctly aligned. Much of the ppc64 assembler assumes masking out significant
+// bits will produce a valid register number:
+// REG_Rx & 31 == x
+// REG_Fx & 31 == x
+// REG_Vx & 31 == x
+// REG_VSx & 63 == x
+// REG_SPRx & 1023 == x
+// REG_CRx & 7 == x
+//
+// VR and FPR disjointly overlap VSR, interpreting as VSR registers should produce the correctly overlapped VSR.
+// REG_FPx & 63 == x
+// REG_Vx & 63 == x + 32
+func TestRegValueAlignment(t *testing.T) {
+       tstFunc := func(rstart, rend, msk, rout int) {
+               for i := rstart; i <= rend; i++ {
+                       if i&msk != rout {
+                               t.Errorf("%v is not aligned to 0x%X (expected %d, got %d)\n", rconv(i), msk, rout, rstart&msk)
+                       }
+                       rout++
+               }
+       }
+       var testType = []struct {
+               rstart int
+               rend   int
+               msk    int
+               rout   int
+       }{
+               {REG_VS0, REG_VS63, 63, 0},
+               {REG_R0, REG_R31, 31, 0},
+               {REG_F0, REG_F31, 31, 0},
+               {REG_V0, REG_V31, 31, 0},
+               {REG_V0, REG_V31, 63, 32},
+               {REG_F0, REG_F31, 63, 0},
+               {REG_SPR0, REG_SPR0 + 1023, 1023, 0},
+               {REG_CR0, REG_CR7, 7, 0},
+               {REG_CR0LT, REG_CR7SO, 31, 0},
+       }
+       for _, t := range testType {
+               tstFunc(t.rstart, t.rend, t.msk, t.rout)
+       }
+}
+
+// Verify interesting obj.Addr arguments are classified correctly.
+func TestAddrClassifier(t *testing.T) {
+       type cmplx struct {
+               pic     int
+               pic_dyn int
+               dyn     int
+               nonpic  int
+       }
+       tsts := [...]struct {
+               arg    obj.Addr
+               output interface{}
+       }{
+               // Supported register type args
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R1}, C_REG},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R2}, C_REGP},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F1}, C_FREG},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F2}, C_FREGP},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_V2}, C_VREG},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS1}, C_VSREG},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS2}, C_VSREGP},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR}, C_CREG},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1}, C_CREG},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1SO}, C_CRBIT},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0}, C_SPR},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 1}, C_XER},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 8}, C_LR},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 9}, C_CTR},
+               {obj.Addr{Type: obj.TYPE_REG, Reg: REG_FPSCR}, C_FPSCR},
+
+               // Memory type arguments.
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_GOTREF}, C_ADDR},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_TOCREF}, C_ADDR},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.STLSBSS}}, cmplx{C_TLS_IE, C_TLS_IE, C_TLS_LE, C_TLS_LE}},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_ADDR},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO}, C_SOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: BIG}, C_LOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM}, C_SOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: BIG}, C_LOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LOREG}, // 33 is FixedFrameSize-1
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE}, C_ZOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: 1}, C_SOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: BIG}, C_LOREG},
+               {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: -BIG - 33}, C_LOREG},
+
+               // Misc (golang initializes -0.0 to 0.0, hence the obfuscation below)
+               {obj.Addr{Type: obj.TYPE_TEXTSIZE}, C_TEXTSIZE},
+               {obj.Addr{Type: obj.TYPE_FCONST, Val: 0.0}, C_ZCON},
+               {obj.Addr{Type: obj.TYPE_FCONST, Val: math.Float64frombits(0x8000000000000000)}, C_S16CON},
+
+               // Address type arguments
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1}, C_SACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: BIG}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: -BIG - 1}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1 << 32}, C_DACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_STATIC, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: 1}, C_SACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: BIG}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: 1}, C_SACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: BIG}, C_LACON},
+               {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LACON}, // 33 is FixedFrameSize-1
+
+               // Constant type arguments
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 0}, C_ZCON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1}, C_U1CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 2}, C_U2CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 4}, C_U3CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 8}, C_U4CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 16}, C_U5CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 32}, C_U8CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 14}, C_U15CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 15}, C_U16CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 16}, C_U3216CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 + 1<<16}, C_U32CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 32}, C_S34CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 33}, C_64CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -1}, C_S16CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10000}, C_S3216CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10001}, C_S32CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 33)}, C_S34CON},
+               {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 34)}, C_64CON},
+
+               // Branch like arguments
+               {obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_SBRA, C_LBRAPIC, C_LBRAPIC, C_SBRA}},
+               {obj.Addr{Type: obj.TYPE_BRANCH}, C_SBRA},
+       }
+
+       pic_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Arch: &Linkppc64}, autosize: 0}
+       pic_dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
+       dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
+       nonpic_ctxt9 := ctxt9{ctxt: &obj.Link{Arch: &Linkppc64}, autosize: 0}
+       ctxts := [...]*ctxt9{&pic_ctxt9, &pic_dyn_ctxt9, &dyn_ctxt9, &nonpic_ctxt9}
+       name := [...]string{"pic", "pic_dyn", "dyn", "nonpic"}
+       for _, tst := range tsts {
+               var expect []int
+               switch tst.output.(type) {
+               case cmplx:
+                       v := tst.output.(cmplx)
+                       expect = []int{v.pic, v.pic_dyn, v.dyn, v.nonpic}
+               case int:
+                       expect = []int{tst.output.(int), tst.output.(int), tst.output.(int), tst.output.(int)}
+               }
+               for i, _ := range ctxts {
+                       if output := ctxts[i].aclass(&tst.arg); output != expect[i] {
+                               t.Errorf("%s.aclass(%v) = %v, expected %v\n", name[i], tst.arg, DRconv(output), DRconv(expect[i]))
+                       }
+               }
+       }
+}
index 6e601df82e3060f8931a27f472b70bbdec8677b7..a9d89c93b4ef00bb3f3cee34d95f3b8d58ede47e 100644 (file)
@@ -239,6 +239,12 @@ Register naming
   VSn is used for vector-scalar registers. V0-V31 overlap with VS32-VS63. (0-63)
   CTR represents the count register.
   LR represents the link register.
+  CR represents the condition register
+  CRn represents a condition register field. (0-7)
+  CRnLT represents CR bit 0 of CR field n. (0-7)
+  CRnGT represents CR bit 1 of CR field n. (0-7)
+  CRnEQ represents CR bit 2 of CR field n. (0-7)
+  CRnSO represents CR bit 3 of CR field n. (0-7)
 
 */
 package ppc64
index 461950dc6054e474bebcb2ac6c3a71604c0970d1..ea0dae9e0283638d430343d8315ddac3d9a058ba 100644 (file)
@@ -35,7 +35,7 @@ import (
 )
 
 func init() {
-       obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, rconv)
+       obj.RegisterRegister(obj.RBasePPC64, REG_SPR0+1024, rconv)
        obj.RegisterOpcode(obj.ABasePPC64, Anames)
 }
 
@@ -62,6 +62,11 @@ func rconv(r int) string {
        if REG_CR0 <= r && r <= REG_CR7 {
                return fmt.Sprintf("CR%d", r-REG_CR0)
        }
+       if REG_CR0LT <= r && r <= REG_CR7SO {
+               bits := [4]string{"LT", "GT", "EQ", "SO"}
+               crf := (r - REG_CR0LT) / 4
+               return fmt.Sprintf("CR%d%s", crf, bits[r%4])
+       }
        if r == REG_CR {
                return "CR"
        }
@@ -80,9 +85,6 @@ func rconv(r int) string {
                return fmt.Sprintf("SPR(%d)", r-REG_SPR0)
        }
 
-       if REG_DCR0 <= r && r <= REG_DCR0+1023 {
-               return fmt.Sprintf("DCR(%d)", r-REG_DCR0)
-       }
        if r == REG_FPSCR {
                return "FPSCR"
        }
index c2722b0afb05de401ecb5fc1ba2af29ac69c8465..7ac6465a7296b824a2fc25b93beadc0f47cf402e 100644 (file)
@@ -294,9 +294,9 @@ func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
                //     BL (LR)
                var sym *obj.LSym
                if p.As == obj.ADUFFZERO {
-                       sym = c.ctxt.Lookup("runtime.duffzero")
+                       sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
                } else {
-                       sym = c.ctxt.Lookup("runtime.duffcopy")
+                       sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
                }
                offset := p.To.Offset
                p.As = AMOVD
@@ -687,7 +687,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                        q.From.Reg = REG_LR
                                        q.To.Type = obj.TYPE_REG
                                        q.To.Reg = REGTMP
-
                                        prologueEnd = q
 
                                        q = obj.Appendp(q, c.newprog)
@@ -787,14 +786,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                q.From.Reg = REGG
                                q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
                                q.To.Type = obj.TYPE_REG
-                               q.To.Reg = REG_R3
+                               q.To.Reg = REG_R22
 
                                q = obj.Appendp(q, c.newprog)
                                q.As = ACMP
                                q.From.Type = obj.TYPE_REG
                                q.From.Reg = REG_R0
                                q.To.Type = obj.TYPE_REG
-                               q.To.Reg = REG_R3
+                               q.To.Reg = REG_R22
 
                                q = obj.Appendp(q, c.newprog)
                                q.As = ABEQ
@@ -804,10 +803,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                q = obj.Appendp(q, c.newprog)
                                q.As = AMOVD
                                q.From.Type = obj.TYPE_MEM
-                               q.From.Reg = REG_R3
+                               q.From.Reg = REG_R22
                                q.From.Offset = 0 // Panic.argp
                                q.To.Type = obj.TYPE_REG
-                               q.To.Reg = REG_R4
+                               q.To.Reg = REG_R23
 
                                q = obj.Appendp(q, c.newprog)
                                q.As = AADD
@@ -815,14 +814,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
                                q.Reg = REGSP
                                q.To.Type = obj.TYPE_REG
-                               q.To.Reg = REG_R5
+                               q.To.Reg = REG_R24
 
                                q = obj.Appendp(q, c.newprog)
                                q.As = ACMP
                                q.From.Type = obj.TYPE_REG
-                               q.From.Reg = REG_R4
+                               q.From.Reg = REG_R23
                                q.To.Type = obj.TYPE_REG
-                               q.To.Reg = REG_R5
+                               q.To.Reg = REG_R24
 
                                q = obj.Appendp(q, c.newprog)
                                q.As = ABNE
@@ -835,14 +834,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                q.From.Offset = c.ctxt.FixedFrameSize()
                                q.Reg = REGSP
                                q.To.Type = obj.TYPE_REG
-                               q.To.Reg = REG_R6
+                               q.To.Reg = REG_R25
 
                                q = obj.Appendp(q, c.newprog)
                                q.As = AMOVD
                                q.From.Type = obj.TYPE_REG
-                               q.From.Reg = REG_R6
+                               q.From.Reg = REG_R25
                                q.To.Type = obj.TYPE_MEM
-                               q.To.Reg = REG_R3
+                               q.To.Reg = REG_R22
                                q.To.Offset = 0 // Panic.argp
 
                                q = obj.Appendp(q, c.newprog)
@@ -1049,9 +1048,98 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
        }
 */
 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
-       p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
+       if c.ctxt.Flag_maymorestack != "" {
+               if c.ctxt.Flag_shared || c.ctxt.Flag_dynlink {
+                       // See the call to morestack for why these are
+                       // complicated to support.
+                       c.ctxt.Diag("maymorestack with -shared or -dynlink is not supported")
+               }
+
+               // Spill arguments. This has to happen before we open
+               // any more frame space.
+               p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
+
+               // Save LR and REGCTXT
+               frameSize := 8 + c.ctxt.FixedFrameSize()
+
+               // MOVD LR, REGTMP
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REG_LR
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGTMP
+               // MOVDU REGTMP, -16(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVDU
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGTMP
+               p.To.Type = obj.TYPE_MEM
+               p.To.Offset = -frameSize
+               p.To.Reg = REGSP
+               p.Spadj = int32(frameSize)
+
+               // MOVD REGCTXT, 8(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGCTXT
+               p.To.Type = obj.TYPE_MEM
+               p.To.Offset = 8
+               p.To.Reg = REGSP
+
+               // BL maymorestack
+               p = obj.Appendp(p, c.newprog)
+               p.As = ABL
+               p.To.Type = obj.TYPE_BRANCH
+               // See ../x86/obj6.go
+               p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
+
+               // Restore LR and REGCTXT
+
+               // MOVD 8(SP), REGCTXT
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_MEM
+               p.From.Offset = 8
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGCTXT
 
-       // MOVD g_stackguard(g), R3
+               // MOVD 0(SP), REGTMP
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_MEM
+               p.From.Offset = 0
+               p.From.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGTMP
+
+               // MOVD REGTMP, LR
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGTMP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REG_LR
+
+               // ADD $16, SP
+               p = obj.Appendp(p, c.newprog)
+               p.As = AADD
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = frameSize
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGSP
+               p.Spadj = -int32(frameSize)
+
+               // Unspill arguments.
+               p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
+       }
+
+       // save entry point, but skipping the two instructions setting R2 in shared mode and maymorestack
+       startPred := p
+
+       // MOVD g_stackguard(g), R22
        p = obj.Appendp(p, c.newprog)
 
        p.As = AMOVD
@@ -1062,7 +1150,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
                p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
        }
        p.To.Type = obj.TYPE_REG
-       p.To.Reg = REG_R3
+       p.To.Reg = REG_R22
 
        // Mark the stack bound check and morestack call async nonpreemptible.
        // If we get preempted here, when resumed the preemption request is
@@ -1078,7 +1166,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
 
                p.As = ACMPU
                p.From.Type = obj.TYPE_REG
-               p.From.Reg = REG_R3
+               p.From.Reg = REG_R22
                p.To.Type = obj.TYPE_REG
                p.To.Reg = REGSP
        } else {
@@ -1108,14 +1196,14 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
                                p.From.Type = obj.TYPE_CONST
                                p.From.Offset = offset
                                p.To.Type = obj.TYPE_REG
-                               p.To.Reg = REG_R4
+                               p.To.Reg = REG_R23
 
                                p = obj.Appendp(p, c.newprog)
                                p.As = ACMPU
                                p.From.Type = obj.TYPE_REG
                                p.From.Reg = REGSP
                                p.To.Type = obj.TYPE_REG
-                               p.To.Reg = REG_R4
+                               p.To.Reg = REG_R23
                        }
 
                        p = obj.Appendp(p, c.newprog)
@@ -1134,14 +1222,14 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
                p.From.Offset = -offset
                p.Reg = REGSP
                p.To.Type = obj.TYPE_REG
-               p.To.Reg = REG_R4
+               p.To.Reg = REG_R23
 
                p = obj.Appendp(p, c.newprog)
                p.As = ACMPU
                p.From.Type = obj.TYPE_REG
-               p.From.Reg = REG_R3
+               p.From.Reg = REG_R22
                p.To.Type = obj.TYPE_REG
-               p.To.Reg = REG_R4
+               p.To.Reg = REG_R23
        }
 
        // q1: BLT      done
@@ -1151,17 +1239,25 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
        p.As = ABLT
        p.To.Type = obj.TYPE_BRANCH
 
-       // MOVD LR, R5
        p = obj.Appendp(p, c.newprog)
+       p.As = obj.ANOP // zero-width place holder
+
+       if q != nil {
+               q.To.SetTarget(p)
+       }
+
+       // Spill the register args that could be clobbered by the
+       // morestack code.
+
+       spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
 
+       // MOVD LR, R5
+       p = obj.Appendp(spill, c.newprog)
        p.As = AMOVD
        p.From.Type = obj.TYPE_REG
        p.From.Reg = REG_LR
        p.To.Type = obj.TYPE_REG
        p.To.Reg = REG_R5
-       if q != nil {
-               q.To.SetTarget(p)
-       }
 
        p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
 
@@ -1181,8 +1277,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
                // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
                // the caller's frame, but not used (0(SP) is caller's saved LR,
                // 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
-
-               // MOVD R12, 8(SP)
+               // MOVD R2, 8(SP)
                p = obj.Appendp(p, c.newprog)
                p.As = AMOVD
                p.From.Type = obj.TYPE_REG
@@ -1249,13 +1344,14 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
                p.To.Reg = REG_R2
        }
 
-       p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
+       unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
+       p = c.ctxt.EndUnsafePoint(unspill, c.newprog, -1)
 
        // BR   start
        p = obj.Appendp(p, c.newprog)
        p.As = ABR
        p.To.Type = obj.TYPE_BRANCH
-       p.To.SetTarget(p0.Link)
+       p.To.SetTarget(startPred.Link)
 
        // placeholder for q1's jump target
        p = obj.Appendp(p, c.newprog)
index 6581bb34022ad1ebf3a27f9f8e04023f495cca36..d2a3674ebef8d434e01980486d02fe258e4c3d4c 100644 (file)
@@ -236,6 +236,8 @@ var Anames = []string{
        "BLEZ",
        "BLTZ",
        "BNEZ",
+       "FABSD",
+       "FABSS",
        "FNEGD",
        "FNEGS",
        "FNED",
index f8f7b4f2ced0756c5c9ea868cf074a0e55062060..b23142dbe8ecb503ff6c683b3f9c75496bf90bc7 100644 (file)
@@ -16,32 +16,30 @@ import (
        "testing"
 )
 
-// TestLarge generates a very large file to verify that large
-// program builds successfully, in particular, too-far
-// conditional branches are fixed.
-func TestLarge(t *testing.T) {
+// TestLargeBranch generates a large function with a very far conditional
+// branch, in order to ensure that it assembles successfully.
+func TestLargeBranch(t *testing.T) {
        if testing.Short() {
-               t.Skip("Skip in short mode")
+               t.Skip("Skipping test in short mode")
        }
        testenv.MustHaveGoBuild(t)
 
-       dir, err := ioutil.TempDir("", "testlarge")
+       dir, err := ioutil.TempDir("", "testlargebranch")
        if err != nil {
-               t.Fatalf("could not create directory: %v", err)
+               t.Fatalf("Could not create directory: %v", err)
        }
        defer os.RemoveAll(dir)
 
        // Generate a very large function.
        buf := bytes.NewBuffer(make([]byte, 0, 7000000))
-       gen(buf)
+       genLargeBranch(buf)
 
        tmpfile := filepath.Join(dir, "x.s")
-       err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
-       if err != nil {
-               t.Fatalf("can't write output: %v\n", err)
+       if err := ioutil.WriteFile(tmpfile, buf.Bytes(), 0644); err != nil {
+               t.Fatalf("Failed to write file: %v", err)
        }
 
-       // Build generated file.
+       // Assemble generated file.
        cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
        cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
        out, err := cmd.CombinedOutput()
@@ -50,8 +48,7 @@ func TestLarge(t *testing.T) {
        }
 }
 
-// gen generates a very large program, with a very far conditional branch.
-func gen(buf *bytes.Buffer) {
+func genLargeBranch(buf *bytes.Buffer) {
        fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
        fmt.Fprintln(buf, "BEQ X0, X0, label")
        for i := 0; i < 1<<19; i++ {
@@ -61,6 +58,76 @@ func gen(buf *bytes.Buffer) {
        fmt.Fprintln(buf, "ADD $0, X0, X0")
 }
 
+// TestLargeCall generates a large function (>1MB of text) with a call to
+// a following function, in order to ensure that it assembles and links
+// correctly.
+func TestLargeCall(t *testing.T) {
+       if testing.Short() {
+               t.Skip("Skipping test in short mode")
+       }
+       testenv.MustHaveGoBuild(t)
+
+       dir, err := ioutil.TempDir("", "testlargecall")
+       if err != nil {
+               t.Fatalf("could not create directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module largecall"), 0644); err != nil {
+               t.Fatalf("Failed to write file: %v\n", err)
+       }
+       main := `package main
+func main() {
+        x()
+}
+
+func x()
+func y()
+`
+       if err := ioutil.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil {
+               t.Fatalf("failed to write main: %v\n", err)
+       }
+
+       // Generate a very large function with call.
+       buf := bytes.NewBuffer(make([]byte, 0, 7000000))
+       genLargeCall(buf)
+
+       if err := ioutil.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil {
+               t.Fatalf("Failed to write file: %v\n", err)
+       }
+
+       // Build generated files.
+       cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal")
+       cmd.Dir = dir
+       cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Errorf("Build failed: %v, output: %s", err, out)
+       }
+
+       if runtime.GOARCH == "riscv64" && testenv.HasCGO() {
+               cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-linkmode=external")
+               cmd.Dir = dir
+               cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
+               out, err := cmd.CombinedOutput()
+               if err != nil {
+                       t.Errorf("Build failed: %v, output: %s", err, out)
+               }
+       }
+}
+
+func genLargeCall(buf *bytes.Buffer) {
+       fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-0")
+       fmt.Fprintln(buf, "CALL ·y(SB)")
+       for i := 0; i < 1<<19; i++ {
+               fmt.Fprintln(buf, "ADD $0, X0, X0")
+       }
+       fmt.Fprintln(buf, "RET")
+       fmt.Fprintln(buf, "TEXT ·y(SB),0,$0-0")
+       fmt.Fprintln(buf, "ADD $0, X0, X0")
+       fmt.Fprintln(buf, "RET")
+}
+
 // Issue 20348.
 func TestNoRet(t *testing.T) {
        dir, err := ioutil.TempDir("", "testnoret")
@@ -134,9 +201,6 @@ TEXT _stub(SB),$0-0
 }
 
 func TestBranch(t *testing.T) {
-       if testing.Short() {
-               t.Skip("Skipping in short mode")
-       }
        if runtime.GOARCH != "riscv64" {
                t.Skip("Requires riscv64 to run")
        }
index b1324b62a0377ea415e6654258a01c10c149e6e3..ed88f621d9b76d632f778ddba3a0ee24f1bd1a51 100644 (file)
@@ -256,15 +256,23 @@ var RISCV64DWARFRegisters = map[int16]int16{
 
 // Prog.Mark flags.
 const (
+       // USES_REG_TMP indicates that a machine instruction generated from the
+       // corresponding *obj.Prog uses the temporary register.
+       USES_REG_TMP = 1 << iota
+
+       // NEED_CALL_RELOC is set on JAL instructions to indicate that a
+       // R_RISCV_CALL relocation is needed.
+       NEED_CALL_RELOC
+
        // NEED_PCREL_ITYPE_RELOC is set on AUIPC instructions to indicate that
        // it is the first instruction in an AUIPC + I-type pair that needs a
        // R_RISCV_PCREL_ITYPE relocation.
-       NEED_PCREL_ITYPE_RELOC = 1 << 0
+       NEED_PCREL_ITYPE_RELOC
 
        // NEED_PCREL_STYPE_RELOC is set on AUIPC instructions to indicate that
        // it is the first instruction in an AUIPC + S-type pair that needs a
        // R_RISCV_PCREL_STYPE relocation.
-       NEED_PCREL_STYPE_RELOC = 1 << 1
+       NEED_PCREL_STYPE_RELOC
 )
 
 // RISC-V mnemonics, as defined in the "opcodes" and "opcodes-pseudo" files
@@ -586,6 +594,8 @@ const (
        ABLEZ
        ABLTZ
        ABNEZ
+       AFABSD
+       AFABSS
        AFNEGD
        AFNEGS
        AFNED
@@ -626,6 +636,10 @@ var unaryDst = map[obj.As]bool{
 
 // Instruction encoding masks.
 const (
+       // JTypeImmMask is a mask including only the immediate portion of
+       // J-type instructions.
+       JTypeImmMask = 0xfffff000
+
        // ITypeImmMask is a mask including only the immediate portion of
        // I-type instructions.
        ITypeImmMask = 0xfff00000
@@ -637,8 +651,4 @@ const (
        // UTypeImmMask is a mask including only the immediate portion of
        // U-type instructions.
        UTypeImmMask = 0xfffff000
-
-       // UJTypeImmMask is a mask including only the immediate portion of
-       // UJ-type instructions.
-       UJTypeImmMask = UTypeImmMask
 )
index a305edab4b39348dcb803815e6ab842d28d724a7..5755b118db00f2833d5de75a3cc711d9535c05fb 100644 (file)
@@ -30,41 +30,19 @@ import (
 
 func buildop(ctxt *obj.Link) {}
 
-// jalrToSym replaces p with a set of Progs needed to jump to the Sym in p.
-// lr is the link register to use for the JALR.
-// p must be a CALL, JMP or RET.
-func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *obj.Prog {
-       if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET && p.As != obj.ADUFFZERO && p.As != obj.ADUFFCOPY {
-               ctxt.Diag("unexpected Prog in jalrToSym: %v", p)
-               return p
+func jalToSym(ctxt *obj.Link, p *obj.Prog, lr int16) {
+       switch p.As {
+       case obj.ACALL, obj.AJMP, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
+       default:
+               ctxt.Diag("unexpected Prog in jalToSym: %v", p)
+               return
        }
 
-       // TODO(jsing): Consider using a single JAL instruction and teaching
-       // the linker to provide trampolines for the case where the destination
-       // offset is too large. This would potentially reduce instructions for
-       // the common case, but would require three instructions to go via the
-       // trampoline.
-
-       to := p.To
-
-       p.As = AAUIPC
-       p.Mark |= NEED_PCREL_ITYPE_RELOC
-       p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: to.Sym})
-       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
-       p.Reg = 0
-       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-       p = obj.Appendp(p, newprog)
-
-       // Leave Sym only for the CALL reloc in assemble.
-       p.As = AJALR
+       p.As = AJAL
+       p.Mark |= NEED_CALL_RELOC
        p.From.Type = obj.TYPE_REG
        p.From.Reg = lr
-       p.Reg = 0
-       p.To.Type = obj.TYPE_REG
-       p.To.Reg = REG_TMP
-       p.To.Sym = to.Sym
-
-       return p
+       p.Reg = obj.REG_NONE
 }
 
 // progedit is called individually for each *obj.Prog. It normalizes instruction
@@ -72,7 +50,7 @@ func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *ob
 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 
        // Expand binary instructions to ternary ones.
-       if p.Reg == 0 {
+       if p.Reg == obj.REG_NONE {
                switch p.As {
                case AADDI, ASLTI, ASLTIU, AANDI, AORI, AXORI, ASLLI, ASRLI, ASRAI,
                        AADD, AAND, AOR, AXOR, ASLL, ASRL, ASUB, ASRA,
@@ -154,7 +132,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
 
        case AMOV:
                // Put >32-bit constants in memory and load them.
-               if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
+               if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == obj.REG_NONE && int64(int32(p.From.Offset)) != p.From.Offset {
                        p.From.Type = obj.TYPE_MEM
                        p.From.Sym = ctxt.Int64Sym(p.From.Offset)
                        p.From.Name = obj.NAME_EXTERN
@@ -218,169 +196,28 @@ func movToStore(mnemonic obj.As) obj.As {
        }
 }
 
-// rewriteMOV rewrites MOV pseudo-instructions.
-func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
+// markRelocs marks an obj.Prog that specifies a MOV pseudo-instruction and
+// requires relocation.
+func markRelocs(p *obj.Prog) {
        switch p.As {
        case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
-       default:
-               panic(fmt.Sprintf("%+v is not a MOV pseudo-instruction", p.As))
-       }
-
-       switch p.From.Type {
-       case obj.TYPE_MEM: // MOV c(Rs), Rd -> L $c, Rs, Rd
-               switch p.From.Name {
-               case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
-                       if p.To.Type != obj.TYPE_REG {
-                               ctxt.Diag("unsupported load at %v", p)
-                       }
-                       p.As = movToLoad(p.As)
-                       p.From.Reg = addrToReg(p.From)
-
-               case obj.NAME_EXTERN, obj.NAME_STATIC:
-                       // AUIPC $off_hi, R
-                       // L $off_lo, R
-                       as := p.As
-                       to := p.To
-
-                       p.As = AAUIPC
-                       p.Mark |= NEED_PCREL_ITYPE_RELOC
-                       p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
-                       p.Reg = 0
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: to.Reg}
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = movToLoad(as)
-                       p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: to.Reg, Offset: 0}
-                       p.To = to
-
-               default:
-                       ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
-               }
-
-       case obj.TYPE_REG:
-               switch p.To.Type {
-               case obj.TYPE_REG:
-                       switch p.As {
-                       case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
-                       default:
-                               ctxt.Diag("unsupported register-register move at %v", p)
+               switch {
+               case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
+                       switch p.From.Name {
+                       case obj.NAME_EXTERN, obj.NAME_STATIC:
+                               p.Mark |= NEED_PCREL_ITYPE_RELOC
                        }
-
-               case obj.TYPE_MEM: // MOV Rs, c(Rd) -> S $c, Rs, Rd
-                       switch p.As {
-                       case AMOVBU, AMOVHU, AMOVWU:
-                               ctxt.Diag("unsupported unsigned store at %v", p)
+               case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
+                       switch p.From.Name {
+                       case obj.NAME_EXTERN, obj.NAME_STATIC:
+                               p.Mark |= NEED_PCREL_ITYPE_RELOC
                        }
+               case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
                        switch p.To.Name {
-                       case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
-                               p.As = movToStore(p.As)
-                               p.To.Reg = addrToReg(p.To)
-
                        case obj.NAME_EXTERN, obj.NAME_STATIC:
-                               // AUIPC $off_hi, TMP
-                               // S $off_lo, TMP, R
-                               as := p.As
-                               from := p.From
-
-                               p.As = AAUIPC
                                p.Mark |= NEED_PCREL_STYPE_RELOC
-                               p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
-                               p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
-                               p.Reg = 0
-                               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                               p = obj.Appendp(p, newprog)
-
-                               p.As = movToStore(as)
-                               p.From = from
-                               p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: 0}
-
-                       default:
-                               ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
                        }
-
-               default:
-                       ctxt.Diag("unsupported MOV at %v", p)
                }
-
-       case obj.TYPE_CONST:
-               // MOV $c, R
-               // If c is small enough, convert to:
-               //   ADD $c, ZERO, R
-               // If not, convert to:
-               //   LUI top20bits(c), R
-               //   ADD bottom12bits(c), R, R
-               if p.As != AMOV {
-                       ctxt.Diag("%v: unsupported constant load", p)
-               }
-               if p.To.Type != obj.TYPE_REG {
-                       ctxt.Diag("%v: constant load must target register", p)
-               }
-               off := p.From.Offset
-               to := p.To
-
-               low, high, err := Split32BitImmediate(off)
-               if err != nil {
-                       ctxt.Diag("%v: constant %d too large: %v", p, off, err)
-               }
-
-               // LUI is only necessary if the offset doesn't fit in 12-bits.
-               needLUI := high != 0
-               if needLUI {
-                       p.As = ALUI
-                       p.To = to
-                       // Pass top 20 bits to LUI.
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
-                       p = obj.Appendp(p, newprog)
-               }
-               p.As = AADDIW
-               p.To = to
-               p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
-               p.Reg = REG_ZERO
-               if needLUI {
-                       p.Reg = to.Reg
-               }
-
-       case obj.TYPE_ADDR: // MOV $sym+off(SP/SB), R
-               if p.To.Type != obj.TYPE_REG || p.As != AMOV {
-                       ctxt.Diag("unsupported addr MOV at %v", p)
-               }
-               switch p.From.Name {
-               case obj.NAME_EXTERN, obj.NAME_STATIC:
-                       // AUIPC $off_hi, R
-                       // ADDI $off_lo, R
-                       to := p.To
-
-                       p.As = AAUIPC
-                       p.Mark |= NEED_PCREL_ITYPE_RELOC
-                       p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
-                       p.Reg = 0
-                       p.To = to
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = AADDI
-                       p.From = obj.Addr{Type: obj.TYPE_CONST}
-                       p.Reg = to.Reg
-                       p.To = to
-
-               case obj.NAME_PARAM, obj.NAME_AUTO:
-                       p.As = AADDI
-                       p.Reg = REG_SP
-                       p.From.Type = obj.TYPE_CONST
-
-               case obj.NAME_NONE:
-                       p.As = AADDI
-                       p.Reg = p.From.Reg
-                       p.From.Type = obj.TYPE_CONST
-                       p.From.Reg = 0
-
-               default:
-                       ctxt.Diag("bad addr MOV from name %v at %v", p.From.Name, p)
-               }
-
-       default:
-               ctxt.Diag("unsupported MOV at %v", p)
        }
 }
 
@@ -443,14 +280,15 @@ func containsCall(sym *obj.LSym) bool {
 }
 
 // setPCs sets the Pc field in all instructions reachable from p.
-// It uses pc as the initial value.
-func setPCs(p *obj.Prog, pc int64) {
+// It uses pc as the initial value and returns the next available pc.
+func setPCs(p *obj.Prog, pc int64) int64 {
        for ; p != nil; p = p.Link {
                p.Pc = pc
                for _, ins := range instructionsForProg(p) {
                        pc += int64(ins.length())
                }
        }
+       return pc
 }
 
 // stackOffset updates Addr offsets based on the current stack size.
@@ -590,7 +428,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
 
                ldpanic.As = AMOV
                ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)} // G.panic
-               ldpanic.Reg = 0
+               ldpanic.Reg = obj.REG_NONE
                ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X11}
 
                bneadj := obj.Appendp(ldpanic, newprog)
@@ -610,7 +448,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                getargp := obj.Appendp(last, newprog)
                getargp.As = AMOV
                getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X11, Offset: 0} // Panic.argp
-               getargp.Reg = 0
+               getargp.Reg = obj.REG_NONE
                getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12}
 
                bneadj.To.SetTarget(getargp)
@@ -637,7 +475,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                setargp := obj.Appendp(adjargp, newprog)
                setargp.As = AMOV
                setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X12}
-               setargp.Reg = 0
+               setargp.Reg = obj.REG_NONE
                setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X11, Offset: 0} // Panic.argp
 
                godone := obj.Appendp(setargp, newprog)
@@ -672,7 +510,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
                        switch p.To.Type {
                        case obj.TYPE_MEM:
-                               jalrToSym(ctxt, p, newprog, REG_LR)
+                               jalToSym(ctxt, p, REG_LR)
                        }
 
                case obj.AJMP:
@@ -680,8 +518,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                        case obj.TYPE_MEM:
                                switch p.To.Name {
                                case obj.NAME_EXTERN, obj.NAME_STATIC:
-                                       // JMP to symbol.
-                                       jalrToSym(ctxt, p, newprog, REG_ZERO)
+                                       jalToSym(ctxt, p, REG_ZERO)
                                }
                        }
 
@@ -707,11 +544,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                        if retJMP != nil {
                                p.As = obj.ARET
                                p.To.Sym = retJMP
-                               p = jalrToSym(ctxt, p, newprog, REG_ZERO)
+                               jalToSym(ctxt, p, REG_ZERO)
                        } else {
                                p.As = AJALR
                                p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
-                               p.Reg = 0
+                               p.Reg = obj.REG_NONE
                                p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
                        }
 
@@ -746,135 +583,26 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                }
        }
 
-       // Rewrite MOV pseudo-instructions. This cannot be done in
-       // progedit, as SP offsets need to be applied before we split
-       // up some of the Addrs.
+       var callCount int
        for p := cursym.Func().Text; p != nil; p = p.Link {
-               switch p.As {
-               case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
-                       rewriteMOV(ctxt, newprog, p)
-               }
-       }
-
-       // Split immediates larger than 12-bits.
-       for p := cursym.Func().Text; p != nil; p = p.Link {
-               switch p.As {
-               // <opi> $imm, REG, TO
-               case AADDI, AANDI, AORI, AXORI:
-                       // LUI $high, TMP
-                       // ADDI $low, TMP, TMP
-                       // <op> TMP, REG, TO
-                       q := *p
-                       low, high, err := Split32BitImmediate(p.From.Offset)
-                       if err != nil {
-                               ctxt.Diag("%v: constant %d too large", p, p.From.Offset, err)
-                       }
-                       if high == 0 {
-                               break // no need to split
-                       }
-
-                       p.As = ALUI
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
-                       p.Reg = 0
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Spadj = 0 // needed if TO is SP
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = AADDIW
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
-                       p.Reg = REG_TMP
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p = obj.Appendp(p, newprog)
-
-                       switch q.As {
-                       case AADDI:
-                               p.As = AADD
-                       case AANDI:
-                               p.As = AAND
-                       case AORI:
-                               p.As = AOR
-                       case AXORI:
-                               p.As = AXOR
-                       default:
-                               ctxt.Diag("unsupported instruction %v for splitting", q)
-                       }
-                       p.Spadj = q.Spadj
-                       p.To = q.To
-                       p.Reg = q.Reg
-                       p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-
-               // <load> $imm, REG, TO (load $imm+(REG), TO)
-               case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
-                       low, high, err := Split32BitImmediate(p.From.Offset)
-                       if err != nil {
-                               ctxt.Diag("%v: constant %d too large", p, p.From.Offset)
-                       }
-                       if high == 0 {
-                               break // no need to split
-                       }
-                       q := *p
-
-                       // LUI $high, TMP
-                       // ADD TMP, REG, TMP
-                       // <load> $low, TMP, TO
-                       p.As = ALUI
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
-                       p.Reg = 0
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Spadj = 0 // needed if TO is SP
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = AADD
-                       p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Reg = q.From.Reg
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = q.As
-                       p.To = q.To
-                       p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low}
-                       p.Reg = obj.REG_NONE
-
-               // <store> $imm, REG, TO (store $imm+(TO), REG)
-               case ASD, ASB, ASH, ASW, AFSW, AFSD:
-                       low, high, err := Split32BitImmediate(p.To.Offset)
-                       if err != nil {
-                               ctxt.Diag("%v: constant %d too large", p, p.To.Offset)
-                       }
-                       if high == 0 {
-                               break // no need to split
-                       }
-                       q := *p
-
-                       // LUI $high, TMP
-                       // ADD TMP, TO, TMP
-                       // <store> $low, REG, TMP
-                       p.As = ALUI
-                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: high}
-                       p.Reg = 0
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Spadj = 0 // needed if TO is SP
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = AADD
-                       p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p.Reg = q.To.Reg
-                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
-                       p = obj.Appendp(p, newprog)
-
-                       p.As = q.As
-                       p.From = obj.Addr{Type: obj.TYPE_REG, Reg: q.From.Reg, Offset: 0}
-                       p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_TMP, Offset: low}
+               markRelocs(p)
+               if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC {
+                       callCount++
                }
        }
+       const callTrampSize = 8 // 2 machine instructions.
+       maxTrampSize := int64(callCount * callTrampSize)
 
        // Compute instruction addresses.  Once we do that, we need to check for
        // overextended jumps and branches.  Within each iteration, Pc differences
        // are always lower bounds (since the program gets monotonically longer,
        // a fixed point will be reached).  No attempt to handle functions > 2GiB.
        for {
-               rescan := false
-               setPCs(cursym.Func().Text, 0)
+               big, rescan := false, false
+               maxPC := setPCs(cursym.Func().Text, 0)
+               if maxPC+maxTrampSize > (1 << 20) {
+                       big = true
+               }
 
                for p := cursym.Func().Text; p != nil; p = p.Link {
                        switch p.As {
@@ -899,8 +627,27 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                        rescan = true
                                }
                        case AJAL:
+                               // Linker will handle the intersymbol case and trampolines.
                                if p.To.Target() == nil {
-                                       panic("intersymbol jumps should be expressed as AUIPC+JALR")
+                                       if !big {
+                                               break
+                                       }
+                                       // This function is going to be too large for JALs
+                                       // to reach trampolines. Replace with AUIPC+JALR.
+                                       jmp := obj.Appendp(p, newprog)
+                                       jmp.As = AJALR
+                                       jmp.From = p.From
+                                       jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
+
+                                       p.As = AAUIPC
+                                       p.Mark = (p.Mark &^ NEED_CALL_RELOC) | NEED_PCREL_ITYPE_RELOC
+                                       p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
+                                       p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
+                                       p.Reg = obj.REG_NONE
+                                       p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
+
+                                       rescan = true
+                                       break
                                }
                                offset := p.To.Target().Pc - p.Pc
                                if offset < -(1<<20) || (1<<20) <= offset {
@@ -917,7 +664,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                        p.As = AAUIPC
                                        p.From = obj.Addr{Type: obj.TYPE_BRANCH, Sym: p.From.Sym}
                                        p.From.SetTarget(p.To.Target())
-                                       p.Reg = 0
+                                       p.Reg = obj.REG_NONE
                                        p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
 
                                        rescan = true
@@ -935,7 +682,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
        // instructions will break everything--don't do it!
        for p := cursym.Func().Text; p != nil; p = p.Link {
                switch p.As {
-               case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL:
+               case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
                        switch p.To.Type {
                        case obj.TYPE_BRANCH:
                                p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
@@ -943,6 +690,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                                panic("unhandled type")
                        }
 
+               case AJAL:
+                       // Linker will handle the intersymbol case and trampolines.
+                       if p.To.Target() != nil {
+                               p.To.Type, p.To.Offset = obj.TYPE_CONST, p.To.Target().Pc-p.Pc
+                       }
+
                case AAUIPC:
                        if p.From.Type == obj.TYPE_BRANCH {
                                low, high, err := Split32BitImmediate(p.From.Target().Pc - p.Pc)
@@ -969,6 +722,62 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
                return p
        }
 
+       if ctxt.Flag_maymorestack != "" {
+               // Save LR and REGCTXT
+               const frameSize = 16
+               p = ctxt.StartUnsafePoint(p, newprog)
+               // MOV LR, -16(SP)
+               p = obj.Appendp(p, newprog)
+               p.As = AMOV
+               p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
+               p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: -frameSize}
+               // ADDI $-16, SP
+               p = obj.Appendp(p, newprog)
+               p.As = AADDI
+               p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: -frameSize}
+               p.Reg = REG_SP
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
+               p.Spadj = frameSize
+               // MOV REGCTXT, 8(SP)
+               p = obj.Appendp(p, newprog)
+               p.As = AMOV
+               p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
+               p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
+
+               // CALL maymorestack
+               p = obj.Appendp(p, newprog)
+               p.As = obj.ACALL
+               p.To.Type = obj.TYPE_BRANCH
+               // See ../x86/obj6.go
+               p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
+               jalToSym(ctxt, p, REG_X5)
+
+               // Restore LR and REGCTXT
+
+               // MOV 8(SP), REGCTXT
+               p = obj.Appendp(p, newprog)
+               p.As = AMOV
+               p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 8}
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_CTXT}
+               // MOV (SP), LR
+               p = obj.Appendp(p, newprog)
+               p.As = AMOV
+               p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
+               // ADDI $16, SP
+               p = obj.Appendp(p, newprog)
+               p.As = AADDI
+               p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: frameSize}
+               p.Reg = REG_SP
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_SP}
+               p.Spadj = -frameSize
+
+               p = ctxt.EndUnsafePoint(p, newprog, -1)
+       }
+
+       // Jump back to here after morestack returns.
+       startPred := p
+
        // MOV  g_stackguard(g), X10
        p = obj.Appendp(p, newprog)
        p.As = AMOV
@@ -1061,14 +870,14 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
        if to_more != nil {
                to_more.To.SetTarget(p)
        }
-       p = jalrToSym(ctxt, p, newprog, REG_X5)
+       jalToSym(ctxt, p, REG_X5)
 
        // JMP start
        p = obj.Appendp(p, newprog)
        p.As = AJAL
        p.To = obj.Addr{Type: obj.TYPE_BRANCH}
        p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
-       p.To.SetTarget(cursym.Func().Text.Link)
+       p.To.SetTarget(startPred.Link)
 
        // placeholder for to_done's jump target
        p = obj.Appendp(p, newprog)
@@ -1089,10 +898,10 @@ func signExtend(val int64, bit uint) int64 {
 // generate a full 32-bit constant.
 func Split32BitImmediate(imm int64) (low, high int64, err error) {
        if !immIFits(imm, 32) {
-               return 0, 0, fmt.Errorf("immediate does not fit in 32-bits: %d", imm)
+               return 0, 0, fmt.Errorf("immediate does not fit in 32 bits: %d", imm)
        }
 
-       // Nothing special needs to be done if the immediate fits in 12-bits.
+       // Nothing special needs to be done if the immediate fits in 12 bits.
        if immIFits(imm, 12) {
                return imm, 0, nil
        }
@@ -1165,14 +974,14 @@ func immIFits(x int64, nbits uint) bool {
 // immI extracts the signed integer of the specified size from an immediate.
 func immI(as obj.As, imm int64, nbits uint) uint32 {
        if !immIFits(imm, nbits) {
-               panic(fmt.Sprintf("%v\tsigned immediate %d cannot fit in %d bits", as, imm, nbits))
+               panic(fmt.Sprintf("%vsigned immediate %d cannot fit in %d bits", as, imm, nbits))
        }
        return uint32(imm)
 }
 
 func wantImmI(ctxt *obj.Link, as obj.As, imm int64, nbits uint) {
        if !immIFits(imm, nbits) {
-               ctxt.Diag("%v\tsigned immediate cannot be larger than %d bits but got %d", as, nbits, imm)
+               ctxt.Diag("%v: signed immediate %d cannot be larger than %d bits", as, imm, nbits)
        }
 }
 
@@ -1182,13 +991,13 @@ func wantReg(ctxt *obj.Link, as obj.As, pos string, descr string, r, min, max ui
                if r != obj.REG_NONE {
                        suffix = fmt.Sprintf(" but got non-%s register %s", descr, RegName(int(r)))
                }
-               ctxt.Diag("%v\texpected %s register in %s position%s", as, descr, pos, suffix)
+               ctxt.Diag("%vexpected %s register in %s position%s", as, descr, pos, suffix)
        }
 }
 
 func wantNoneReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
        if r != obj.REG_NONE {
-               ctxt.Diag("%v\texpected no register in %s but got register %s", as, pos, RegName(int(r)))
+               ctxt.Diag("%vexpected no register in %s but got register %s", as, pos, RegName(int(r)))
        }
 }
 
@@ -1205,7 +1014,7 @@ func wantFloatReg(ctxt *obj.Link, as obj.As, pos string, r uint32) {
 // wantEvenOffset checks that the offset is a multiple of two.
 func wantEvenOffset(ctxt *obj.Link, as obj.As, offset int64) {
        if offset%1 != 0 {
-               ctxt.Diag("%v\tjump offset %v must be even", as, offset)
+               ctxt.Diag("%v: jump offset %d must be a multiple of two", as, offset)
        }
 }
 
@@ -1213,60 +1022,81 @@ func validateRIII(ctxt *obj.Link, ins *instruction) {
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
        wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateRFFF(ctxt *obj.Link, ins *instruction) {
        wantFloatReg(ctxt, ins.as, "rd", ins.rd)
        wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
        wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
+}
+
+func validateRFFFF(ctxt *obj.Link, ins *instruction) {
+       wantFloatReg(ctxt, ins.as, "rd", ins.rd)
+       wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
+       wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantFloatReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateRFFI(ctxt *obj.Link, ins *instruction) {
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
        wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateRFI(ctxt *obj.Link, ins *instruction) {
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
        wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateRIF(ctxt *obj.Link, ins *instruction) {
        wantFloatReg(ctxt, ins.as, "rd", ins.rd)
        wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
        wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateRFF(ctxt *obj.Link, ins *instruction) {
        wantFloatReg(ctxt, ins.as, "rd", ins.rd)
        wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
        wantFloatReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateII(ctxt *obj.Link, ins *instruction) {
        wantImmI(ctxt, ins.as, ins.imm, 12)
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
+       wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateIF(ctxt *obj.Link, ins *instruction) {
        wantImmI(ctxt, ins.as, ins.imm, 12)
        wantFloatReg(ctxt, ins.as, "rd", ins.rd)
        wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
+       wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateSI(ctxt *obj.Link, ins *instruction) {
        wantImmI(ctxt, ins.as, ins.imm, 12)
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
+       wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateSF(ctxt *obj.Link, ins *instruction) {
        wantImmI(ctxt, ins.as, ins.imm, 12)
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantFloatReg(ctxt, ins.as, "rs1", ins.rs1)
+       wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateB(ctxt *obj.Link, ins *instruction) {
@@ -1277,6 +1107,7 @@ func validateB(ctxt *obj.Link, ins *instruction) {
        wantNoneReg(ctxt, ins.as, "rd", ins.rd)
        wantIntReg(ctxt, ins.as, "rs1", ins.rs1)
        wantIntReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateU(ctxt *obj.Link, ins *instruction) {
@@ -1284,6 +1115,7 @@ func validateU(ctxt *obj.Link, ins *instruction) {
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
        wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateJ(ctxt *obj.Link, ins *instruction) {
@@ -1294,13 +1126,14 @@ func validateJ(ctxt *obj.Link, ins *instruction) {
        wantIntReg(ctxt, ins.as, "rd", ins.rd)
        wantNoneReg(ctxt, ins.as, "rs1", ins.rs1)
        wantNoneReg(ctxt, ins.as, "rs2", ins.rs2)
+       wantNoneReg(ctxt, ins.as, "rs3", ins.rs3)
 }
 
 func validateRaw(ctxt *obj.Link, ins *instruction) {
        // Treat the raw value specially as a 32-bit unsigned integer.
        // Nobody wants to enter negative machine code.
        if ins.imm < 0 || 1<<32 <= ins.imm {
-               ctxt.Diag("%v\timmediate in raw position cannot be larger than 32 bits but got %d", ins.as, ins.imm)
+               ctxt.Diag("%v: immediate %d in raw position cannot be larger than 32 bits", ins.as, ins.imm)
        }
 }
 
@@ -1316,6 +1149,22 @@ func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
        return funct7<<25 | enc.funct7<<25 | enc.rs2<<20 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
 }
 
+// encodeR4 encodes an R4-type RISC-V instruction.
+func encodeR4(as obj.As, rs1, rs2, rs3, rd, funct3, funct2 uint32) uint32 {
+       enc := encode(as)
+       if enc == nil {
+               panic("encodeR4: could not encode instruction")
+       }
+       if enc.rs2 != 0 {
+               panic("encodeR4: instruction uses rs2")
+       }
+       funct2 |= enc.funct7
+       if funct2&^3 != 0 {
+               panic("encodeR4: funct2 requires more than 2 bits")
+       }
+       return rs3<<27 | funct2<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | funct3<<12 | rd<<7 | enc.opcode
+}
+
 func encodeRIII(ins *instruction) uint32 {
        return encodeR(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
 }
@@ -1324,6 +1173,10 @@ func encodeRFFF(ins *instruction) uint32 {
        return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rd), ins.funct3, ins.funct7)
 }
 
+func encodeRFFFF(ins *instruction) uint32 {
+       return encodeR4(ins.as, regF(ins.rs1), regF(ins.rs2), regF(ins.rs3), regF(ins.rd), ins.funct3, ins.funct7)
+}
+
 func encodeRFFI(ins *instruction) uint32 {
        return encodeR(ins.as, regF(ins.rs1), regF(ins.rs2), regI(ins.rd), ins.funct3, ins.funct7)
 }
@@ -1402,6 +1255,11 @@ func encodeU(ins *instruction) uint32 {
        return imm<<12 | rd<<7 | enc.opcode
 }
 
+// encodeJImmediate encodes an immediate for a J-type RISC-V instruction.
+func encodeJImmediate(imm uint32) uint32 {
+       return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12
+}
+
 // encodeJ encodes a J-type RISC-V instruction.
 func encodeJ(ins *instruction) uint32 {
        imm := immI(ins.as, ins.imm, 21)
@@ -1410,7 +1268,7 @@ func encodeJ(ins *instruction) uint32 {
        if enc == nil {
                panic("encodeJ: could not encode instruction")
        }
-       return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12 | rd<<7 | enc.opcode
+       return encodeJImmediate(imm) | rd<<7 | enc.opcode
 }
 
 func encodeRawIns(ins *instruction) uint32 {
@@ -1422,6 +1280,16 @@ func encodeRawIns(ins *instruction) uint32 {
        return uint32(ins.imm)
 }
 
+func EncodeJImmediate(imm int64) (int64, error) {
+       if !immIFits(imm, 21) {
+               return 0, fmt.Errorf("immediate %#x does not fit in 21 bits", imm)
+       }
+       if imm&1 != 0 {
+               return 0, fmt.Errorf("immediate %#x is not a multiple of two", imm)
+       }
+       return int64(encodeJImmediate(uint32(imm))), nil
+}
+
 func EncodeIImmediate(imm int64) (int64, error) {
        if !immIFits(imm, 12) {
                return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
@@ -1461,12 +1329,13 @@ var (
        // integer register inputs and an integer register output; sFEncoding
        // indicates an S-type instruction with rs2 being a float register.
 
-       rIIIEncoding = encoding{encode: encodeRIII, validate: validateRIII, length: 4}
-       rFFFEncoding = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4}
-       rFFIEncoding = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4}
-       rFIEncoding  = encoding{encode: encodeRFI, validate: validateRFI, length: 4}
-       rIFEncoding  = encoding{encode: encodeRIF, validate: validateRIF, length: 4}
-       rFFEncoding  = encoding{encode: encodeRFF, validate: validateRFF, length: 4}
+       rIIIEncoding  = encoding{encode: encodeRIII, validate: validateRIII, length: 4}
+       rFFFEncoding  = encoding{encode: encodeRFFF, validate: validateRFFF, length: 4}
+       rFFFFEncoding = encoding{encode: encodeRFFFF, validate: validateRFFFF, length: 4}
+       rFFIEncoding  = encoding{encode: encodeRFFI, validate: validateRFFI, length: 4}
+       rFIEncoding   = encoding{encode: encodeRFI, validate: validateRFI, length: 4}
+       rIFEncoding   = encoding{encode: encodeRIF, validate: validateRIF, length: 4}
+       rFFEncoding   = encoding{encode: encodeRFF, validate: validateRFF, length: 4}
 
        iIEncoding = encoding{encode: encodeII, validate: validateII, length: 4}
        iFEncoding = encoding{encode: encodeIF, validate: validateIF, length: 4}
@@ -1608,13 +1477,17 @@ var encodings = [ALAST & obj.AMask]encoding{
        AFSW & obj.AMask: sFEncoding,
 
        // 11.6: Single-Precision Floating-Point Computational Instructions
-       AFADDS & obj.AMask:  rFFFEncoding,
-       AFSUBS & obj.AMask:  rFFFEncoding,
-       AFMULS & obj.AMask:  rFFFEncoding,
-       AFDIVS & obj.AMask:  rFFFEncoding,
-       AFMINS & obj.AMask:  rFFFEncoding,
-       AFMAXS & obj.AMask:  rFFFEncoding,
-       AFSQRTS & obj.AMask: rFFFEncoding,
+       AFADDS & obj.AMask:   rFFFEncoding,
+       AFSUBS & obj.AMask:   rFFFEncoding,
+       AFMULS & obj.AMask:   rFFFEncoding,
+       AFDIVS & obj.AMask:   rFFFEncoding,
+       AFMINS & obj.AMask:   rFFFEncoding,
+       AFMAXS & obj.AMask:   rFFFEncoding,
+       AFSQRTS & obj.AMask:  rFFFEncoding,
+       AFMADDS & obj.AMask:  rFFFFEncoding,
+       AFMSUBS & obj.AMask:  rFFFFEncoding,
+       AFNMSUBS & obj.AMask: rFFFFEncoding,
+       AFNMADDS & obj.AMask: rFFFFEncoding,
 
        // 11.7: Single-Precision Floating-Point Conversion and Move Instructions
        AFCVTWS & obj.AMask:  rFIEncoding,
@@ -1646,13 +1519,17 @@ var encodings = [ALAST & obj.AMask]encoding{
        AFSD & obj.AMask: sFEncoding,
 
        // 12.4: Double-Precision Floating-Point Computational Instructions
-       AFADDD & obj.AMask:  rFFFEncoding,
-       AFSUBD & obj.AMask:  rFFFEncoding,
-       AFMULD & obj.AMask:  rFFFEncoding,
-       AFDIVD & obj.AMask:  rFFFEncoding,
-       AFMIND & obj.AMask:  rFFFEncoding,
-       AFMAXD & obj.AMask:  rFFFEncoding,
-       AFSQRTD & obj.AMask: rFFFEncoding,
+       AFADDD & obj.AMask:   rFFFEncoding,
+       AFSUBD & obj.AMask:   rFFFEncoding,
+       AFMULD & obj.AMask:   rFFFEncoding,
+       AFDIVD & obj.AMask:   rFFFEncoding,
+       AFMIND & obj.AMask:   rFFFEncoding,
+       AFMAXD & obj.AMask:   rFFFEncoding,
+       AFSQRTD & obj.AMask:  rFFFEncoding,
+       AFMADDD & obj.AMask:  rFFFFEncoding,
+       AFMSUBD & obj.AMask:  rFFFFEncoding,
+       AFNMSUBD & obj.AMask: rFFFFEncoding,
+       AFNMADDD & obj.AMask: rFFFFEncoding,
 
        // 12.5: Double-Precision Floating-Point Conversion and Move Instructions
        AFCVTWD & obj.AMask:  rFIEncoding,
@@ -1718,9 +1595,10 @@ type instruction struct {
        rd     uint32 // Destination register
        rs1    uint32 // Source register 1
        rs2    uint32 // Source register 2
+       rs3    uint32 // Source register 3
        imm    int64  // Immediate
        funct3 uint32 // Function 3
-       funct7 uint32 // Function 7
+       funct7 uint32 // Function 7 (or Function 2)
 }
 
 func (ins *instruction) encode() (uint32, error) {
@@ -1751,8 +1629,12 @@ func (ins *instruction) validate(ctxt *obj.Link) {
        enc.validate(ctxt, ins)
 }
 
-// instructionsForProg returns the machine instructions for an *obj.Prog.
-func instructionsForProg(p *obj.Prog) []*instruction {
+func (ins *instruction) usesRegTmp() bool {
+       return ins.rd == REG_TMP || ins.rs1 == REG_TMP || ins.rs2 == REG_TMP
+}
+
+// instructionForProg returns the default *obj.Prog to instruction mapping.
+func instructionForProg(p *obj.Prog) *instruction {
        ins := &instruction{
                as:  p.As,
                rd:  uint32(p.To.Reg),
@@ -1760,43 +1642,190 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                rs2: uint32(p.From.Reg),
                imm: p.From.Offset,
        }
+       if len(p.RestArgs) == 1 {
+               ins.rs3 = uint32(p.RestArgs[0].Reg)
+       }
+       return ins
+}
+
+// instructionsForOpImmediate returns the machine instructions for a immedate
+// operand. The instruction is specified by as and the source register is
+// specified by rs, instead of the obj.Prog.
+func instructionsForOpImmediate(p *obj.Prog, as obj.As, rs int16) []*instruction {
+       // <opi> $imm, REG, TO
+       ins := instructionForProg(p)
+       ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
+
+       low, high, err := Split32BitImmediate(ins.imm)
+       if err != nil {
+               p.Ctxt.Diag("%v: constant %d too large", p, ins.imm, err)
+               return nil
+       }
+       if high == 0 {
+               return []*instruction{ins}
+       }
 
-       inss := []*instruction{ins}
+       // Split into two additions, if possible.
+       // Do not split SP-writing instructions, as otherwise the recorded SP delta may be wrong.
+       if p.Spadj == 0 && ins.as == AADDI && ins.imm >= -(1<<12) && ins.imm < 1<<12-1 {
+               imm0 := ins.imm / 2
+               imm1 := ins.imm - imm0
+
+               // ADDI $(imm/2), REG, TO
+               // ADDI $(imm-imm/2), TO, TO
+               ins.imm = imm0
+               insADDI := &instruction{as: AADDI, rd: ins.rd, rs1: ins.rd, imm: imm1}
+               return []*instruction{ins, insADDI}
+       }
+
+       // LUI $high, TMP
+       // ADDI $low, TMP, TMP
+       // <op> TMP, REG, TO
+       insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
+       insADDIW := &instruction{as: AADDIW, rd: REG_TMP, rs1: REG_TMP, imm: low}
        switch ins.as {
-       case AJAL, AJALR:
-               ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
-               ins.imm = p.To.Offset
+       case AADDI:
+               ins.as = AADD
+       case AANDI:
+               ins.as = AAND
+       case AORI:
+               ins.as = AOR
+       case AXORI:
+               ins.as = AXOR
+       default:
+               p.Ctxt.Diag("unsupported immediate instruction %v for splitting", p)
+               return nil
+       }
+       ins.rs2 = REG_TMP
+       if low == 0 {
+               return []*instruction{insLUI, ins}
+       }
+       return []*instruction{insLUI, insADDIW, ins}
+}
 
-       case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
-               switch ins.as {
-               case ABEQZ:
-                       ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
-               case ABGEZ:
-                       ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
-               case ABGT:
-                       ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
-               case ABGTU:
-                       ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
-               case ABGTZ:
-                       ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
-               case ABLE:
-                       ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
-               case ABLEU:
-                       ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
-               case ABLEZ:
-                       ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
-               case ABLTZ:
-                       ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
-               case ABNEZ:
-                       ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
+// instructionsForLoad returns the machine instructions for a load. The load
+// instruction is specified by as and the base/source register is specified
+// by rs, instead of the obj.Prog.
+func instructionsForLoad(p *obj.Prog, as obj.As, rs int16) []*instruction {
+       if p.From.Type != obj.TYPE_MEM {
+               p.Ctxt.Diag("%v requires memory for source", p)
+               return nil
+       }
+
+       switch as {
+       case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU, AFLW, AFLD:
+       default:
+               p.Ctxt.Diag("%v: unknown load instruction %v", p, as)
+               return nil
+       }
+
+       // <load> $imm, REG, TO (load $imm+(REG), TO)
+       ins := instructionForProg(p)
+       ins.as, ins.rs1, ins.rs2 = as, uint32(rs), obj.REG_NONE
+       ins.imm = p.From.Offset
+
+       low, high, err := Split32BitImmediate(ins.imm)
+       if err != nil {
+               p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
+               return nil
+       }
+       if high == 0 {
+               return []*instruction{ins}
+       }
+
+       // LUI $high, TMP
+       // ADD TMP, REG, TMP
+       // <load> $low, TMP, TO
+       insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
+       insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rs1}
+       ins.rs1, ins.imm = REG_TMP, low
+
+       return []*instruction{insLUI, insADD, ins}
+}
+
+// instructionsForStore returns the machine instructions for a store. The store
+// instruction is specified by as and the target/source register is specified
+// by rd, instead of the obj.Prog.
+func instructionsForStore(p *obj.Prog, as obj.As, rd int16) []*instruction {
+       if p.To.Type != obj.TYPE_MEM {
+               p.Ctxt.Diag("%v requires memory for destination", p)
+               return nil
+       }
+
+       switch as {
+       case ASW, ASH, ASB, ASD, AFSW, AFSD:
+       default:
+               p.Ctxt.Diag("%v: unknown store instruction %v", p, as)
+               return nil
+       }
+
+       // <store> $imm, REG, TO (store $imm+(TO), REG)
+       ins := instructionForProg(p)
+       ins.as, ins.rd, ins.rs1, ins.rs2 = as, uint32(rd), uint32(p.From.Reg), obj.REG_NONE
+       ins.imm = p.To.Offset
+
+       low, high, err := Split32BitImmediate(ins.imm)
+       if err != nil {
+               p.Ctxt.Diag("%v: constant %d too large", p, ins.imm)
+               return nil
+       }
+       if high == 0 {
+               return []*instruction{ins}
+       }
+
+       // LUI $high, TMP
+       // ADD TMP, TO, TMP
+       // <store> $low, REG, TMP
+       insLUI := &instruction{as: ALUI, rd: REG_TMP, imm: high}
+       insADD := &instruction{as: AADD, rd: REG_TMP, rs1: REG_TMP, rs2: ins.rd}
+       ins.rd, ins.imm = REG_TMP, low
+
+       return []*instruction{insLUI, insADD, ins}
+}
+
+// instructionsForMOV returns the machine instructions for an *obj.Prog that
+// uses a MOV pseudo-instruction.
+func instructionsForMOV(p *obj.Prog) []*instruction {
+       ins := instructionForProg(p)
+       inss := []*instruction{ins}
+
+       switch {
+       case p.From.Type == obj.TYPE_CONST && p.To.Type == obj.TYPE_REG:
+               // Handle constant to register moves.
+               if p.As != AMOV {
+                       p.Ctxt.Diag("%v: unsupported constant load", p)
+                       return nil
                }
-               ins.imm = p.To.Offset
 
-       case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
-               // Handle register to register moves.
-               if p.From.Type != obj.TYPE_REG || p.To.Type != obj.TYPE_REG {
+               low, high, err := Split32BitImmediate(ins.imm)
+               if err != nil {
+                       p.Ctxt.Diag("%v: constant %d too large: %v", p, ins.imm, err)
+                       return nil
+               }
+
+               // MOV $c, R -> ADD $c, ZERO, R
+               ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, REG_ZERO, obj.REG_NONE, low
+
+               // LUI is only necessary if the constant does not fit in 12 bits.
+               if high == 0 {
                        break
                }
+
+               // LUI top20bits(c), R
+               // ADD bottom12bits(c), R, R
+               insLUI := &instruction{as: ALUI, rd: ins.rd, imm: high}
+               inss = []*instruction{insLUI}
+               if low != 0 {
+                       ins.as, ins.rs1 = AADDIW, ins.rd
+                       inss = append(inss, ins)
+               }
+
+       case p.From.Type == obj.TYPE_CONST && p.To.Type != obj.TYPE_REG:
+               p.Ctxt.Diag("%v: constant load must target register", p)
+               return nil
+
+       case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_REG:
+               // Handle register to register moves.
                switch p.As {
                case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
                        ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
@@ -1830,27 +1859,149 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                        inss = append(inss, ins2)
                }
 
-       case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
-               if p.From.Type != obj.TYPE_MEM {
-                       p.Ctxt.Diag("%v requires memory for source", p)
+       case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG:
+               // Memory to register loads.
+               switch p.From.Name {
+               case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
+                       // MOV c(Rs), Rd -> L $c, Rs, Rd
+                       inss = instructionsForLoad(p, movToLoad(p.As), addrToReg(p.From))
+
+               case obj.NAME_EXTERN, obj.NAME_STATIC:
+                       // Note that the values for $off_hi and $off_lo are currently
+                       // zero and will be assigned during relocation.
+                       //
+                       // AUIPC $off_hi, Rd
+                       // L $off_lo, Rd, Rd
+                       insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
+                       ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), ins.rd, obj.REG_NONE, 0
+                       inss = []*instruction{insAUIPC, ins}
+
+               default:
+                       p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
                        return nil
                }
-               ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
-               ins.imm = p.From.Offset
 
-       case ASW, ASH, ASB, ASD, AFSW, AFSD:
-               if p.To.Type != obj.TYPE_MEM {
-                       p.Ctxt.Diag("%v requires memory for destination", p)
+       case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM:
+               // Register to memory stores.
+               switch p.As {
+               case AMOVBU, AMOVHU, AMOVWU:
+                       p.Ctxt.Diag("%v: unsupported unsigned store", p)
                        return nil
                }
-               ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
+               switch p.To.Name {
+               case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
+                       // MOV Rs, c(Rd) -> S $c, Rs, Rd
+                       inss = instructionsForStore(p, movToStore(p.As), addrToReg(p.To))
+
+               case obj.NAME_EXTERN, obj.NAME_STATIC:
+                       // Note that the values for $off_hi and $off_lo are currently
+                       // zero and will be assigned during relocation.
+                       //
+                       // AUIPC $off_hi, Rtmp
+                       // S $off_lo, Rtmp, Rd
+                       insAUIPC := &instruction{as: AAUIPC, rd: REG_TMP}
+                       ins.as, ins.rd, ins.rs1, ins.rs2, ins.imm = movToStore(p.As), REG_TMP, uint32(p.From.Reg), obj.REG_NONE, 0
+                       inss = []*instruction{insAUIPC, ins}
+
+               default:
+                       p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
+                       return nil
+               }
+
+       case p.From.Type == obj.TYPE_ADDR && p.To.Type == obj.TYPE_REG:
+               // MOV $sym+off(SP/SB), R
+               if p.As != AMOV {
+                       p.Ctxt.Diag("%v: unsupported address load", p)
+                       return nil
+               }
+               switch p.From.Name {
+               case obj.NAME_AUTO, obj.NAME_PARAM, obj.NAME_NONE:
+                       inss = instructionsForOpImmediate(p, AADDI, addrToReg(p.From))
+
+               case obj.NAME_EXTERN, obj.NAME_STATIC:
+                       // Note that the values for $off_hi and $off_lo are currently
+                       // zero and will be assigned during relocation.
+                       //
+                       // AUIPC $off_hi, R
+                       // ADDI $off_lo, R
+                       insAUIPC := &instruction{as: AAUIPC, rd: ins.rd}
+                       ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, ins.rd, obj.REG_NONE, 0
+                       inss = []*instruction{insAUIPC, ins}
+
+               default:
+                       p.Ctxt.Diag("unsupported name %d for %v", p.From.Name, p)
+                       return nil
+               }
+
+       case p.From.Type == obj.TYPE_ADDR && p.To.Type != obj.TYPE_REG:
+               p.Ctxt.Diag("%v: address load must target register", p)
+               return nil
+
+       default:
+               p.Ctxt.Diag("%v: unsupported MOV", p)
+               return nil
+       }
+
+       return inss
+}
+
+// instructionsForProg returns the machine instructions for an *obj.Prog.
+func instructionsForProg(p *obj.Prog) []*instruction {
+       ins := instructionForProg(p)
+       inss := []*instruction{ins}
+
+       if len(p.RestArgs) > 1 {
+               p.Ctxt.Diag("too many source registers")
+               return nil
+       }
+
+       switch ins.as {
+       case AJAL, AJALR:
+               ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
+               ins.imm = p.To.Offset
+
+       case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
+               switch ins.as {
+               case ABEQZ:
+                       ins.as, ins.rs1, ins.rs2 = ABEQ, REG_ZERO, uint32(p.From.Reg)
+               case ABGEZ:
+                       ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
+               case ABGT:
+                       ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
+               case ABGTU:
+                       ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
+               case ABGTZ:
+                       ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
+               case ABLE:
+                       ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
+               case ABLEU:
+                       ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
+               case ABLEZ:
+                       ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
+               case ABLTZ:
+                       ins.as, ins.rs1, ins.rs2 = ABLT, REG_ZERO, uint32(p.From.Reg)
+               case ABNEZ:
+                       ins.as, ins.rs1, ins.rs2 = ABNE, REG_ZERO, uint32(p.From.Reg)
+               }
                ins.imm = p.To.Offset
 
+       case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
+               return instructionsForMOV(p)
+
+       case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
+               return instructionsForLoad(p, ins.as, p.From.Reg)
+
+       case ASW, ASH, ASB, ASD, AFSW, AFSD:
+               return instructionsForStore(p, ins.as, p.To.Reg)
+
        case ALRW, ALRD:
                // Set aq to use acquire access ordering, which matches Go's memory requirements.
                ins.funct7 = 2
                ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
 
+       case AADDI, AANDI, AORI, AXORI:
+               inss = instructionsForOpImmediate(p, ins.as, p.Reg)
+
        case ASCW, ASCD, AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
                AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD:
                // Set aq to use acquire access ordering, which matches Go's memory requirements.
@@ -1898,6 +2049,12 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                ins.rs1 = uint32(p.From.Reg)
                ins.rs2 = REG_F0
 
+       case AFMADDS, AFMSUBS, AFNMADDS, AFNMSUBS,
+               AFMADDD, AFMSUBD, AFNMADDD, AFNMSUBD:
+               // Swap the first two operands so that the operands are in the same
+               // order as they are in the specification: RS1, RS2, RS3, RD.
+               ins.rs1, ins.rs2 = ins.rs2, ins.rs1
+
        case ANEG, ANEGW:
                // NEG rs, rd -> SUB rs, X0, rd
                ins.as = ASUB
@@ -1921,7 +2078,7 @@ func instructionsForProg(p *obj.Prog) []*instruction {
        case ASEQZ:
                // SEQZ rs, rd -> SLTIU $1, rs, rd
                ins.as = ASLTIU
-               ins.rs1 = uint32(p.From.Reg)
+               ins.rs1, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
                ins.imm = 1
 
        case ASNEZ:
@@ -1929,6 +2086,16 @@ func instructionsForProg(p *obj.Prog) []*instruction {
                ins.as = ASLTU
                ins.rs1 = REG_ZERO
 
+       case AFABSS:
+               // FABSS rs, rd -> FSGNJXS rs, rs, rd
+               ins.as = AFSGNJXS
+               ins.rs1 = uint32(p.From.Reg)
+
+       case AFABSD:
+               // FABSD rs, rd -> FSGNJXD rs, rs, rd
+               ins.as = AFSGNJXD
+               ins.rs1 = uint32(p.From.Reg)
+
        case AFNEGS:
                // FNEGS rs, rd -> FSGNJNS rs, rs, rd
                ins.as = AFSGNJNS
@@ -1950,37 +2117,43 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                ctxt.Retpoline = false // don't keep printing
        }
 
-       var symcode []uint32
        for p := cursym.Func().Text; p != nil; p = p.Link {
                switch p.As {
-               case AJALR:
-                       if p.To.Sym != nil {
-                               // This is a CALL/JMP. We add a relocation only
-                               // for linker stack checking. No actual
-                               // relocation is needed.
+               case AJAL:
+                       if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC {
                                rel := obj.Addrel(cursym)
                                rel.Off = int32(p.Pc)
                                rel.Siz = 4
                                rel.Sym = p.To.Sym
                                rel.Add = p.To.Offset
-                               rel.Type = objabi.R_CALLRISCV
+                               rel.Type = objabi.R_RISCV_CALL
                        }
-               case AAUIPC:
+               case AJALR:
+                       if p.To.Sym != nil {
+                               ctxt.Diag("%v: unexpected AJALR with to symbol", p)
+                       }
+
+               case AAUIPC, AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
+                       var addr *obj.Addr
                        var rt objabi.RelocType
                        if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC {
                                rt = objabi.R_RISCV_PCREL_ITYPE
+                               addr = &p.From
                        } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC {
                                rt = objabi.R_RISCV_PCREL_STYPE
+                               addr = &p.To
                        } else {
                                break
                        }
-                       if p.Link == nil {
-                               ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction")
-                               break
+                       if p.As == AAUIPC {
+                               if p.Link == nil {
+                                       ctxt.Diag("AUIPC needing PC-relative reloc missing following instruction")
+                                       break
+                               }
+                               addr = &p.RestArgs[0].Addr
                        }
-                       addr := p.RestArgs[0]
                        if addr.Sym == nil {
-                               ctxt.Diag("AUIPC needing PC-relative reloc missing symbol")
+                               ctxt.Diag("PC-relative relocation missing symbol")
                                break
                        }
                        if addr.Sym.Type == objabi.STLSBSS {
@@ -1999,25 +2172,23 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                        rel.Type = rt
                }
 
+               offset := p.Pc
                for _, ins := range instructionsForProg(p) {
-                       ic, err := ins.encode()
-                       if err == nil {
-                               symcode = append(symcode, ic)
+                       if ic, err := ins.encode(); err == nil {
+                               cursym.WriteInt(ctxt, offset, ins.length(), int64(ic))
+                               offset += int64(ins.length())
+                       }
+                       if ins.usesRegTmp() {
+                               p.Mark |= USES_REG_TMP
                        }
                }
        }
-       cursym.Size = int64(4 * len(symcode))
-
-       cursym.Grow(cursym.Size)
-       for p, i := cursym.P, 0; i < len(symcode); p, i = p[4:], i+1 {
-               ctxt.Arch.ByteOrder.PutUint32(p, symcode[i])
-       }
 
        obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
 }
 
 func isUnsafePoint(p *obj.Prog) bool {
-       return p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
+       return p.Mark&USES_REG_TMP == USES_REG_TMP || p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
 }
 
 var LinkRISCV64 = obj.LinkArch{
index de412c64a7832b4ab4dfed9c87dd25d446a25d0d..68d9589bf26174d3da3f24d07f3ef5d5cb31533a 100644 (file)
@@ -32,7 +32,7 @@ func testGoBGTU(a, b int64) bool { return uint64(a) > uint64(b) }
 func testGoBLE(a, b int64) bool  { return a <= b }
 func testGoBLEU(a, b int64) bool { return uint64(a) <= uint64(b) }
 func testGoBLT(a, b int64) bool  { return a < b }
-func testGoBLTZ(a, b int64) bool { return uint64(a) < uint64(b) }
+func testGoBLTU(a, b int64) bool { return uint64(a) < uint64(b) }
 
 func TestBranchCondition(t *testing.T) {
        tests := []struct {
index 201163b0159a1883bde0570d9a516f6a49ab9113..de40ff05aff52acecc5f93b2f8fcf7383a688dc2 100644 (file)
@@ -294,6 +294,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
        var pLast *obj.Prog
        var pPre *obj.Prog
        var pPreempt *obj.Prog
+       var pCheck *obj.Prog
        wasSplit := false
        for p := c.cursym.Func().Text; p != nil; p = p.Link {
                pLast = p
@@ -323,7 +324,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                        q := p
 
                        if !p.From.Sym.NoSplit() {
-                               p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
+                               p, pPreempt, pCheck = c.stacksplitPre(p, autosize) // emit pre part of split check
                                pPre = p
                                p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
                                wasSplit = true //need post part of split
@@ -563,14 +564,69 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                }
        }
        if wasSplit {
-               c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check
+               c.stacksplitPost(pLast, pPre, pPreempt, pCheck, autosize) // emit post part of split check
        }
 }
 
-func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
+// stacksplitPre generates the function stack check prologue following
+// Prog p (which should be the TEXT Prog). It returns one or two
+// branch Progs that must be patched to jump to the morestack epilogue,
+// and the Prog that starts the morestack check.
+func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCheck *obj.Prog) {
+       if c.ctxt.Flag_maymorestack != "" {
+               // Save LR and REGCTXT
+               const frameSize = 16
+               p = c.ctxt.StartUnsafePoint(p, c.newprog)
+               // MOVD LR, -16(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
+               p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: -frameSize}
+               // MOVD $-16(SP), SP
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From = obj.Addr{Type: obj.TYPE_ADDR, Offset: -frameSize, Reg: REGSP}
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
+               p.Spadj = frameSize
+               // MOVD REGCTXT, 8(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
+               p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
+
+               // BL maymorestack
+               p = obj.Appendp(p, c.newprog)
+               p.As = ABL
+               // See ../x86/obj6.go
+               sym := c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
+               p.To = obj.Addr{Type: obj.TYPE_BRANCH, Sym: sym}
+
+               // Restore LR and REGCTXT
+
+               // MOVD REGCTXT, 8(SP)
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
+               // MOVD (SP), LR
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 0}
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
+               // MOVD $16(SP), SP
+               p = obj.Appendp(p, c.newprog)
+               p.As = AMOVD
+               p.From = obj.Addr{Type: obj.TYPE_CONST, Reg: REGSP, Offset: frameSize}
+               p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
+               p.Spadj = -frameSize
+
+               p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
+       }
 
        // MOVD g_stackguard(g), R3
        p = obj.Appendp(p, c.newprog)
+       // Jump back to here after morestack returns.
+       pCheck = p
 
        p.As = AMOVD
        p.From.Type = obj.TYPE_MEM
@@ -599,12 +655,11 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
                p.As = ACMPUBGE
                p.To.Type = obj.TYPE_BRANCH
 
-               return p, nil
+               return p, nil, pCheck
        }
 
        // large stack: SP-framesize < stackguard-StackSmall
 
-       var q *obj.Prog
        offset := int64(framesize) - objabi.StackSmall
        if framesize > objabi.StackBig {
                // Such a large stack we need to protect against underflow.
@@ -625,7 +680,7 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
                p.To.Reg = REG_R4
 
                p = obj.Appendp(p, c.newprog)
-               q = p
+               pPreempt = p
                p.As = ACMPUBLT
                p.From.Type = obj.TYPE_REG
                p.From.Reg = REGSP
@@ -651,10 +706,16 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
        p.As = ACMPUBGE
        p.To.Type = obj.TYPE_BRANCH
 
-       return p, q
+       return p, pPreempt, pCheck
 }
 
-func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
+// stacksplitPost generates the function epilogue that calls morestack
+// and returns the new last instruction in the function.
+//
+// p is the last Prog in the function. pPre and pPreempt, if non-nil,
+// are the instructions that branch to the epilogue. This will fill in
+// their branch targets. pCheck is the Prog that begins the stack check.
+func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre, pPreempt, pCheck *obj.Prog, framesize int32) *obj.Prog {
        // Now we are at the end of the function, but logically
        // we are still in function prologue. We need to fix the
        // SP data and PCDATA.
@@ -692,12 +753,12 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
 
        p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
 
-       // BR   start
+       // BR   pCheck
        p = obj.Appendp(p, c.newprog)
 
        p.As = ABR
        p.To.Type = obj.TYPE_BRANCH
-       p.To.SetTarget(c.cursym.Func().Text.Link)
+       p.To.SetTarget(pCheck)
        return p
 }
 
index 9e8b4dd790f001435f4eac4a48d3d6a267797d32..a8360527ef725fdbaad5957964232e096127f20e 100644 (file)
@@ -34,12 +34,12 @@ package obj
 import (
        "cmd/internal/goobj"
        "cmd/internal/objabi"
+       "crypto/md5"
        "fmt"
        "internal/buildcfg"
        "log"
        "math"
        "sort"
-       "strings"
 )
 
 func Linknew(arch *LinkArch) *Link {
@@ -173,6 +173,14 @@ func (ctxt *Link) Int64Sym(i int64) *LSym {
        })
 }
 
+// GCLocalsSym generates a content-addressable sym containing data.
+func (ctxt *Link) GCLocalsSym(data []byte) *LSym {
+       return ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(data)), func(lsym *LSym) {
+               lsym.P = data
+               lsym.Set(AttrContentAddressable, true)
+       })
+}
+
 // Assign index to symbols.
 // asm is set to true if this is called by the assembler (i.e. not the compiler),
 // in which case all the symbols are non-package (for now).
@@ -202,13 +210,14 @@ func (ctxt *Link) NumberSyms() {
        ctxt.nonpkgdefs = []*LSym{}
 
        var idx, hashedidx, hashed64idx, nonpkgidx int32
-       ctxt.traverseSyms(traverseDefs, func(s *LSym) {
+       ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
                // if Pkgpath is unknown, cannot hash symbols with relocations, as it
                // may reference named symbols whose names are not fully expanded.
                if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
-                       if s.Size <= 8 && len(s.R) == 0 && !strings.HasPrefix(s.Name, "type.") {
+                       if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
                                // We can use short hash only for symbols without relocations.
-                               // Don't use short hash for type symbols, as they need special handling.
+                               // Don't use short hash for symbols that belong in a particular section
+                               // or require special handling (such as type symbols).
                                s.PkgIdx = goobj.PkgIdxHashed64
                                s.SymIdx = hashed64idx
                                if hashed64idx != int32(len(ctxt.hashed64defs)) {
@@ -324,13 +333,19 @@ const (
        traverseDefs traverseFlag = 1 << iota
        traverseRefs
        traverseAux
+       traversePcdata
 
-       traverseAll = traverseDefs | traverseRefs | traverseAux
+       traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
 )
 
 // Traverse symbols based on flag, call fn for each symbol.
 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
-       lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
+       fnNoNil := func(s *LSym) {
+               if s != nil {
+                       fn(s)
+               }
+       }
+       lists := [][]*LSym{ctxt.Text, ctxt.Data}
        for _, list := range lists {
                for _, s := range list {
                        if flag&traverseDefs != 0 {
@@ -338,15 +353,11 @@ func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
                        }
                        if flag&traverseRefs != 0 {
                                for _, r := range s.R {
-                                       if r.Sym != nil {
-                                               fn(r.Sym)
-                                       }
+                                       fnNoNil(r.Sym)
                                }
                        }
                        if flag&traverseAux != 0 {
-                               if s.Gotype != nil {
-                                       fn(s.Gotype)
-                               }
+                               fnNoNil(s.Gotype)
                                if s.Type == objabi.STEXT {
                                        f := func(parent *LSym, aux *LSym) {
                                                fn(aux)
@@ -354,6 +365,16 @@ func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
                                        ctxt.traverseFuncAux(flag, s, f)
                                }
                        }
+                       if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
+                               fi := s.Func().Pcln
+                               fnNoNil(fi.Pcsp)
+                               fnNoNil(fi.Pcfile)
+                               fnNoNil(fi.Pcline)
+                               fnNoNil(fi.Pcinline)
+                               for _, d := range fi.Pcdata {
+                                       fnNoNil(d)
+                               }
+                       }
                }
        }
 }
@@ -410,7 +431,7 @@ func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent
 
 // Traverse aux symbols, calling fn for each sym/aux pair.
 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
-       lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
+       lists := [][]*LSym{ctxt.Text, ctxt.Data}
        for _, list := range lists {
                for _, s := range list {
                        if s.Gotype != nil {
index e8441a69694452544092ef6225fdd8c7d8e3143f..0c9dde7965797c7e39fd4a4095c3edb8a0b597de 100644 (file)
@@ -7,6 +7,7 @@ package obj
 import (
        "bytes"
        "cmd/internal/objabi"
+       "cmd/internal/src"
        "fmt"
        "internal/buildcfg"
        "io"
@@ -47,6 +48,10 @@ func (p *Prog) InnermostFilename() string {
        return pos.Filename()
 }
 
+func (p *Prog) AllPos(result []src.Pos) []src.Pos {
+       return p.Ctxt.AllPos(p.Pos, result)
+}
+
 var armCondCode = []string{
        ".EQ",
        ".NE",
index 4d276db678041b0d4c9b80d75475c1e565a80d87..1c726f77d34869c9fad72b77ca357aaf2237ed3d 100644 (file)
@@ -243,6 +243,51 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
                p.Spadj = int32(framesize)
        }
 
+       needMoreStack := !s.Func().Text.From.Sym.NoSplit()
+
+       // If the maymorestack debug option is enabled, insert the
+       // call to maymorestack *before* processing resume points so
+       // we can construct a resume point after maymorestack for
+       // morestack to resume at.
+       var pMorestack = s.Func().Text
+       if needMoreStack && ctxt.Flag_maymorestack != "" {
+               p := pMorestack
+
+               // Save REGCTXT on the stack.
+               const tempFrame = 8
+               p = appendp(p, AGet, regAddr(REG_SP))
+               p = appendp(p, AI32Const, constAddr(tempFrame))
+               p = appendp(p, AI32Sub)
+               p = appendp(p, ASet, regAddr(REG_SP))
+               p.Spadj = tempFrame
+               ctxtp := obj.Addr{
+                       Type:   obj.TYPE_MEM,
+                       Reg:    REG_SP,
+                       Offset: 0,
+               }
+               p = appendp(p, AMOVD, regAddr(REGCTXT), ctxtp)
+
+               // maymorestack must not itself preempt because we
+               // don't have full stack information, so this can be
+               // ACALLNORESUME.
+               p = appendp(p, ACALLNORESUME, constAddr(0))
+               // See ../x86/obj6.go
+               sym := ctxt.LookupABI(ctxt.Flag_maymorestack, s.ABI())
+               p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: sym}
+
+               // Restore REGCTXT.
+               p = appendp(p, AMOVD, ctxtp, regAddr(REGCTXT))
+               p = appendp(p, AGet, regAddr(REG_SP))
+               p = appendp(p, AI32Const, constAddr(tempFrame))
+               p = appendp(p, AI32Add)
+               p = appendp(p, ASet, regAddr(REG_SP))
+               p.Spadj = -tempFrame
+
+               // Add an explicit ARESUMEPOINT after maymorestack for
+               // morestack to resume at.
+               pMorestack = appendp(p, ARESUMEPOINT)
+       }
+
        // Introduce resume points for CALL instructions
        // and collect other explicit resume points.
        numResumePoints := 0
@@ -303,8 +348,8 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
        tableIdxs = append(tableIdxs, uint64(numResumePoints))
        s.Size = pc + 1
 
-       if !s.Func().Text.From.Sym.NoSplit() {
-               p := s.Func().Text
+       if needMoreStack {
+               p := pMorestack
 
                if framesize <= objabi.StackSmall {
                        // small stack: SP <= stackguard
@@ -341,6 +386,13 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
                // TODO(neelance): handle wraparound case
 
                p = appendp(p, AIf)
+               // This CALL does *not* have a resume point after it
+               // (we already inserted all of the resume points). As
+               // a result, morestack will resume at the *previous*
+               // resume point (typically, the beginning of the
+               // function) and perform the morestack check again.
+               // This is why we don't need an explicit loop like
+               // other architectures.
                p = appendp(p, obj.ACALL, constAddr(0))
                if s.Func().Text.From.Sym.NeedCtxt() {
                        p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: morestack}
index 2c035641f557249b8127266bf1d2bd0bf5f95d2e..f0913d7c55194d823aa5e130ec546417f9564adf 100644 (file)
@@ -496,9 +496,9 @@ const (
        AMOVAPD
        AMOVAPS
        AMOVB
-       AMOVBELL
-       AMOVBEQQ
-       AMOVBEWW
+       AMOVBEL
+       AMOVBEQ
+       AMOVBEW
        AMOVBLSX
        AMOVBLZX
        AMOVBQSX
index e6c00bdbe0e9a88e8f827d294c8edf342c52d79a..7869e366f9be0f07cb7ebb8732ac74979d5f5a2f 100644 (file)
@@ -494,9 +494,9 @@ var Anames = []string{
        "MOVAPD",
        "MOVAPS",
        "MOVB",
-       "MOVBELL",
-       "MOVBEQQ",
-       "MOVBEWW",
+       "MOVBEL",
+       "MOVBEQ",
+       "MOVBEW",
        "MOVBLSX",
        "MOVBLZX",
        "MOVBQSX",
index 331a98dfef9a00df9399016f1c9daa2f07505aed..6555756fd3b06f27e7c8761c520b7c2006dd4ba6 100644 (file)
@@ -1735,9 +1735,9 @@ var optab =
        {ASTRL, yincq, Px, opBytes{0x0f, 0x00, 01}},
        {ASTRQ, yincq, Pw, opBytes{0x0f, 0x00, 01}},
        {AXSETBV, ynone, Pm, opBytes{0x01, 0xd1, 0}},
-       {AMOVBEWW, ymovbe, Pq, opBytes{0x38, 0xf0, 0, 0x38, 0xf1, 0}},
-       {AMOVBELL, ymovbe, Pm, opBytes{0x38, 0xf0, 0, 0x38, 0xf1, 0}},
-       {AMOVBEQQ, ymovbe, Pw, opBytes{0x0f, 0x38, 0xf0, 0, 0x0f, 0x38, 0xf1, 0}},
+       {AMOVBEW, ymovbe, Pq, opBytes{0x38, 0xf0, 0, 0x38, 0xf1, 0}},
+       {AMOVBEL, ymovbe, Pm, opBytes{0x38, 0xf0, 0, 0x38, 0xf1, 0}},
+       {AMOVBEQ, ymovbe, Pw, opBytes{0x0f, 0x38, 0xf0, 0, 0x0f, 0x38, 0xf1, 0}},
        {ANOPW, ydivl, Pe, opBytes{0x0f, 0x1f, 00}},
        {ANOPL, ydivl, Px, opBytes{0x0f, 0x1f, 00}},
        {ASLDTW, yincq, Pe, opBytes{0x0f, 0x00, 00}},
@@ -2035,6 +2035,11 @@ type nopPad struct {
 }
 
 func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
+       if ctxt.Retpoline && ctxt.Arch.Family == sys.I386 {
+               ctxt.Diag("-spectre=ret not supported on 386")
+               ctxt.Retpoline = false // don't keep printing
+       }
+
        pjc := makePjcCtx(ctxt)
 
        if s.P != nil {
index 183ca2ebe910cd7e15b02c738e2e69cf4aa48dbd..a82285a0d319448717072cc2d1f9447e8ca82340 100644 (file)
@@ -644,19 +644,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                }
        }
 
-       var regg int16
-       if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
-               if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal {
-                       regg = REGG // use the g register directly in ABIInternal
-               } else {
-                       p = obj.Appendp(p, newprog)
-                       regg = REG_CX
-                       if ctxt.Arch.Family == sys.AMD64 {
-                               regg = REGG // == REG_R14
-                       }
-                       p = load_g(ctxt, p, newprog, regg) // load g into regg
-               }
-       }
        var regEntryTmp0, regEntryTmp1 int16
        if ctxt.Arch.Family == sys.AMD64 {
                regEntryTmp0, regEntryTmp1 = REGENTRYTMP0, REGENTRYTMP1
@@ -664,8 +651,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                regEntryTmp0, regEntryTmp1 = REG_BX, REG_DI
        }
 
-       if !cursym.Func().Text.From.Sym.NoSplit() {
-               p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg), regg) // emit split check
+       var regg int16
+       if !p.From.Sym.NoSplit() {
+               // Emit split check and load G register
+               p, regg = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
+       } else if p.From.Sym.Wrapper() {
+               // Load G register for the wrapper code
+               p, regg = loadG(ctxt, cursym, p, newprog)
        }
 
        // Delve debugger would like the next instruction to be noted as the end of the function prologue.
@@ -973,12 +965,21 @@ func indir_cx(ctxt *obj.Link, a *obj.Addr) {
        a.Reg = REG_CX
 }
 
-// Append code to p to load g into cx.
-// Overwrites p with the first instruction (no first appendp).
-// Overwriting p is unusual but it lets use this in both the
-// prologue (caller must call appendp first) and in the epilogue.
-// Returns last new instruction.
-func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.Prog {
+// loadG ensures the G is loaded into a register (either CX or REGG),
+// appending instructions to p if necessary. It returns the new last
+// instruction and the G register.
+func loadG(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc) (*obj.Prog, int16) {
+       if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal {
+               // Use the G register directly in ABIInternal
+               return p, REGG
+       }
+
+       var regg int16 = REG_CX
+       if ctxt.Arch.Family == sys.AMD64 {
+               regg = REGG // == REG_R14
+       }
+
+       p = obj.Appendp(p, newprog)
        p.As = AMOVQ
        if ctxt.Arch.PtrSize == 4 {
                p.As = AMOVL
@@ -987,8 +988,9 @@ func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.P
        p.From.Reg = REG_TLS
        p.From.Offset = 0
        p.To.Type = obj.TYPE_REG
-       p.To.Reg = rg
+       p.To.Reg = regg
 
+       // Rewrite TLS instruction if necessary.
        next := p.Link
        progedit(ctxt, p, newprog)
        for p.Link != next {
@@ -1000,24 +1002,26 @@ func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.P
                p.From.Scale = 2
        }
 
-       return p
+       return p, regg
 }
 
 // Append code to p to check for stack split.
 // Appends to (does not overwrite) p.
 // Assumes g is in rg.
-// Returns last new instruction.
-func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32, rg int16) *obj.Prog {
+// Returns last new instruction and G register.
+func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) (*obj.Prog, int16) {
        cmp := ACMPQ
        lea := ALEAQ
        mov := AMOVQ
        sub := ASUBQ
+       push, pop := APUSHQ, APOPQ
 
        if ctxt.Arch.Family == sys.I386 {
                cmp = ACMPL
                lea = ALEAL
                mov = AMOVL
                sub = ASUBL
+               push, pop = APUSHL, APOPL
        }
 
        tmp := int16(REG_AX) // use AX for 32-bit
@@ -1026,6 +1030,45 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
                tmp = int16(REGENTRYTMP0)
        }
 
+       if ctxt.Flag_maymorestack != "" {
+               p = cursym.Func().SpillRegisterArgs(p, newprog)
+
+               if cursym.Func().Text.From.Sym.NeedCtxt() {
+                       p = obj.Appendp(p, newprog)
+                       p.As = push
+                       p.From.Type = obj.TYPE_REG
+                       p.From.Reg = REGCTXT
+               }
+
+               // We call maymorestack with an ABI matching the
+               // caller's ABI. Since this is the first thing that
+               // happens in the function, we have to be consistent
+               // with the caller about CPU state (notably,
+               // fixed-meaning registers).
+
+               p = obj.Appendp(p, newprog)
+               p.As = obj.ACALL
+               p.To.Type = obj.TYPE_BRANCH
+               p.To.Name = obj.NAME_EXTERN
+               p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
+
+               if cursym.Func().Text.From.Sym.NeedCtxt() {
+                       p = obj.Appendp(p, newprog)
+                       p.As = pop
+                       p.To.Type = obj.TYPE_REG
+                       p.To.Reg = REGCTXT
+               }
+
+               p = cursym.Func().UnspillRegisterArgs(p, newprog)
+       }
+
+       // Jump back to here after morestack returns.
+       startPred := p
+
+       // Load G register
+       var rg int16
+       p, rg = loadG(ctxt, cursym, p, newprog)
+
        var q1 *obj.Prog
        if framesize <= objabi.StackSmall {
                // small stack: SP <= stackguard
@@ -1171,7 +1214,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
        jmp := obj.Appendp(pcdata, newprog)
        jmp.As = obj.AJMP
        jmp.To.Type = obj.TYPE_BRANCH
-       jmp.To.SetTarget(cursym.Func().Text.Link)
+       jmp.To.SetTarget(startPred.Link)
        jmp.Spadj = +framesize
 
        jls.To.SetTarget(spill)
@@ -1179,7 +1222,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
                q1.To.SetTarget(spill)
        }
 
-       return end
+       return end, rg
 }
 
 func isR15(r int16) bool {
index e41fc570b0894926a29ccd0736fb4199f53b0c6c..f75c054fcb6110c332dfd12d5ec9fdd66d47b5fe 100644 (file)
@@ -13,6 +13,8 @@ import (
        "io/ioutil"
        "log"
        "os"
+       "reflect"
+       "sort"
        "strconv"
        "strings"
 )
@@ -202,3 +204,165 @@ func DecodeArg(arg string) string {
        }
        return b.String()
 }
+
+type debugField struct {
+       name string
+       help string
+       val  interface{} // *int or *string
+}
+
+type DebugFlag struct {
+       tab map[string]debugField
+       any *bool
+
+       debugSSA DebugSSA
+}
+
+// A DebugSSA function is called to set a -d ssa/... option.
+// If nil, those options are reported as invalid options.
+// If DebugSSA returns a non-empty string, that text is reported as a compiler error.
+// If phase is "help", it should print usage information and terminate the process.
+type DebugSSA func(phase, flag string, val int, valString string) string
+
+// NewDebugFlag constructs a DebugFlag for the fields of debug, which
+// must be a pointer to a struct.
+//
+// Each field of *debug is a different value, named for the lower-case of the field name.
+// Each field must be an int or string and must have a `help` struct tag.
+// There may be an "Any bool" field, which will be set if any debug flags are set.
+//
+// The returned flag takes a comma-separated list of settings.
+// Each setting is name=value; for ints, name is short for name=1.
+//
+// If debugSSA is non-nil, any debug flags of the form ssa/... will be
+// passed to debugSSA for processing.
+func NewDebugFlag(debug interface{}, debugSSA DebugSSA) *DebugFlag {
+       flag := &DebugFlag{
+               tab:      make(map[string]debugField),
+               debugSSA: debugSSA,
+       }
+
+       v := reflect.ValueOf(debug).Elem()
+       t := v.Type()
+       for i := 0; i < t.NumField(); i++ {
+               f := t.Field(i)
+               ptr := v.Field(i).Addr().Interface()
+               if f.Name == "Any" {
+                       switch ptr := ptr.(type) {
+                       default:
+                               panic("debug.Any must have type bool")
+                       case *bool:
+                               flag.any = ptr
+                       }
+                       continue
+               }
+               name := strings.ToLower(f.Name)
+               help := f.Tag.Get("help")
+               if help == "" {
+                       panic(fmt.Sprintf("debug.%s is missing help text", f.Name))
+               }
+               switch ptr.(type) {
+               default:
+                       panic(fmt.Sprintf("debug.%s has invalid type %v (must be int or string)", f.Name, f.Type))
+               case *int, *string:
+                       // ok
+               }
+               flag.tab[name] = debugField{name, help, ptr}
+       }
+
+       return flag
+}
+
+func (f *DebugFlag) Set(debugstr string) error {
+       if debugstr == "" {
+               return nil
+       }
+       if f.any != nil {
+               *f.any = true
+       }
+       for _, name := range strings.Split(debugstr, ",") {
+               if name == "" {
+                       continue
+               }
+               // display help about the debug option itself and quit
+               if name == "help" {
+                       fmt.Print(debugHelpHeader)
+                       maxLen, names := 0, []string{}
+                       if f.debugSSA != nil {
+                               maxLen = len("ssa/help")
+                       }
+                       for name := range f.tab {
+                               if len(name) > maxLen {
+                                       maxLen = len(name)
+                               }
+                               names = append(names, name)
+                       }
+                       sort.Strings(names)
+                       // Indent multi-line help messages.
+                       nl := fmt.Sprintf("\n\t%-*s\t", maxLen, "")
+                       for _, name := range names {
+                               help := f.tab[name].help
+                               fmt.Printf("\t%-*s\t%s\n", maxLen, name, strings.Replace(help, "\n", nl, -1))
+                       }
+                       if f.debugSSA != nil {
+                               // ssa options have their own help
+                               fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
+                       }
+                       os.Exit(0)
+               }
+
+               val, valstring, haveInt := 1, "", true
+               if i := strings.IndexAny(name, "=:"); i >= 0 {
+                       var err error
+                       name, valstring = name[:i], name[i+1:]
+                       val, err = strconv.Atoi(valstring)
+                       if err != nil {
+                               val, haveInt = 1, false
+                       }
+               }
+
+               if t, ok := f.tab[name]; ok {
+                       switch vp := t.val.(type) {
+                       case nil:
+                               // Ignore
+                       case *string:
+                               *vp = valstring
+                       case *int:
+                               if !haveInt {
+                                       log.Fatalf("invalid debug value %v", name)
+                               }
+                               *vp = val
+                       default:
+                               panic("bad debugtab type")
+                       }
+               } else if f.debugSSA != nil && strings.HasPrefix(name, "ssa/") {
+                       // expect form ssa/phase/flag
+                       // e.g. -d=ssa/generic_cse/time
+                       // _ in phase name also matches space
+                       phase := name[4:]
+                       flag := "debug" // default flag is debug
+                       if i := strings.Index(phase, "/"); i >= 0 {
+                               flag = phase[i+1:]
+                               phase = phase[:i]
+                       }
+                       err := f.debugSSA(phase, flag, val, valstring)
+                       if err != "" {
+                               log.Fatalf(err)
+                       }
+               } else {
+                       return fmt.Errorf("unknown debug key %s\n", name)
+               }
+       }
+
+       return nil
+}
+
+const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
+
+<key> is one of:
+
+`
+
+func (f *DebugFlag) String() string {
+       return ""
+}
index 4ff0ebe13d8dba777a742e6ac1f622a6508e933e..4d49a8d548dee836902669f3f35f5cd446e41ed1 100644 (file)
@@ -14,6 +14,7 @@ const (
        PCDATA_UnsafePoint   = 0
        PCDATA_StackMapIndex = 1
        PCDATA_InlTreeIndex  = 2
+       PCDATA_ArgLiveIndex  = 3
 
        FUNCDATA_ArgsPointerMaps    = 0
        FUNCDATA_LocalsPointerMaps  = 1
@@ -21,6 +22,7 @@ const (
        FUNCDATA_InlTree            = 3
        FUNCDATA_OpenCodedDeferInfo = 4
        FUNCDATA_ArgInfo            = 5
+       FUNCDATA_ArgLiveInfo        = 6
 
        // ArgsSizeUnknown is set in Func.argsize to mark all functions
        // whose argument size is unknown (C vararg functions, and
index 68f6a26a76ca4c8deb8d5d4f61e671480c111c8d..084fcdf712159104aca4cc33bed4a940074de696 100644 (file)
@@ -13,6 +13,7 @@ type FuncFlag uint8
 const (
        FuncFlag_TOPFRAME = 1 << iota
        FuncFlag_SPWRITE
+       FuncFlag_ASM
 )
 
 // A FuncID identifies particular functions that need to be treated
index 52827a6deeec5c6a3bcc6606aef5201bdf785c12..a9c3030181aead1f6fea67f4ad33469088838c86 100644 (file)
@@ -59,8 +59,6 @@ const (
        // R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address
        // of a CALL (JAL) instruction, by encoding the address into the instruction.
        R_CALLMIPS
-       // R_CALLRISCV marks RISC-V CALLs for stack checking.
-       R_CALLRISCV
        R_CONST
        R_PCREL
        // R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
@@ -95,6 +93,11 @@ const (
        // This is a marker relocation (0-sized), for the linker's reachabililty
        // analysis.
        R_USEIFACEMETHOD
+       // Similar to R_USEIFACEMETHOD, except instead of indicating a type +
+       // method offset with Sym+Add, Sym points to a symbol containing the name
+       // of the method being called. See the description in
+       // cmd/compile/internal/reflectdata/reflect.go:MarkUsedIfaceMethod for details.
+       R_USEGENERICIFACEMETHOD
        // R_METHODOFF resolves to a 32-bit offset from the beginning of the section
        // holding the data being relocated to the referenced symbol.
        // It is a variant of R_ADDROFF used when linking from the uncommonType of a
@@ -218,6 +221,15 @@ const (
 
        // RISC-V.
 
+       // R_RISCV_CALL relocates a J-type instruction with a 21 bit PC-relative
+       // address.
+       R_RISCV_CALL
+
+       // R_RISCV_CALL_TRAMP is the same as R_RISCV_CALL but denotes the use of a
+       // trampoline, which we may be able to avoid during relocation. These are
+       // only used by the linker and are not emitted by the compiler or assembler.
+       R_RISCV_CALL_TRAMP
+
        // R_RISCV_PCREL_ITYPE resolves a 32-bit PC-relative address using an
        // AUIPC + I-type instruction pair.
        R_RISCV_PCREL_ITYPE
@@ -274,7 +286,7 @@ const (
 // the target address in register or memory.
 func (r RelocType) IsDirectCall() bool {
        switch r {
-       case R_CALL, R_CALLARM, R_CALLARM64, R_CALLMIPS, R_CALLPOWER, R_CALLRISCV:
+       case R_CALL, R_CALLARM, R_CALLARM64, R_CALLMIPS, R_CALLPOWER, R_RISCV_CALL, R_RISCV_CALL_TRAMP:
                return true
        }
        return false
index 4638ef14d91f62b58be4b6e199d79432d573040b..d1b15b5a194f29f0d5faba7dbad5570fdd8044cf 100644 (file)
@@ -20,19 +20,19 @@ func _() {
        _ = x[R_CALLIND-10]
        _ = x[R_CALLPOWER-11]
        _ = x[R_CALLMIPS-12]
-       _ = x[R_CALLRISCV-13]
-       _ = x[R_CONST-14]
-       _ = x[R_PCREL-15]
-       _ = x[R_TLS_LE-16]
-       _ = x[R_TLS_IE-17]
-       _ = x[R_GOTOFF-18]
-       _ = x[R_PLT0-19]
-       _ = x[R_PLT1-20]
-       _ = x[R_PLT2-21]
-       _ = x[R_USEFIELD-22]
-       _ = x[R_USETYPE-23]
-       _ = x[R_USEIFACE-24]
-       _ = x[R_USEIFACEMETHOD-25]
+       _ = x[R_CONST-13]
+       _ = x[R_PCREL-14]
+       _ = x[R_TLS_LE-15]
+       _ = x[R_TLS_IE-16]
+       _ = x[R_GOTOFF-17]
+       _ = x[R_PLT0-18]
+       _ = x[R_PLT1-19]
+       _ = x[R_PLT2-20]
+       _ = x[R_USEFIELD-21]
+       _ = x[R_USETYPE-22]
+       _ = x[R_USEIFACE-23]
+       _ = x[R_USEIFACEMETHOD-24]
+       _ = x[R_USEGENERICIFACEMETHOD-25]
        _ = x[R_METHODOFF-26]
        _ = x[R_KEEP-27]
        _ = x[R_POWER_TOC-28]
@@ -58,21 +58,23 @@ func _() {
        _ = x[R_ADDRPOWER_PCREL-48]
        _ = x[R_ADDRPOWER_TOCREL-49]
        _ = x[R_ADDRPOWER_TOCREL_DS-50]
-       _ = x[R_RISCV_PCREL_ITYPE-51]
-       _ = x[R_RISCV_PCREL_STYPE-52]
-       _ = x[R_RISCV_TLS_IE_ITYPE-53]
-       _ = x[R_RISCV_TLS_IE_STYPE-54]
-       _ = x[R_PCRELDBL-55]
-       _ = x[R_ADDRMIPSU-56]
-       _ = x[R_ADDRMIPSTLS-57]
-       _ = x[R_ADDRCUOFF-58]
-       _ = x[R_WASMIMPORT-59]
-       _ = x[R_XCOFFREF-60]
+       _ = x[R_RISCV_CALL-51]
+       _ = x[R_RISCV_CALL_TRAMP-52]
+       _ = x[R_RISCV_PCREL_ITYPE-53]
+       _ = x[R_RISCV_PCREL_STYPE-54]
+       _ = x[R_RISCV_TLS_IE_ITYPE-55]
+       _ = x[R_RISCV_TLS_IE_STYPE-56]
+       _ = x[R_PCRELDBL-57]
+       _ = x[R_ADDRMIPSU-58]
+       _ = x[R_ADDRMIPSTLS-59]
+       _ = x[R_ADDRCUOFF-60]
+       _ = x[R_WASMIMPORT-61]
+       _ = x[R_XCOFFREF-62]
 }
 
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USEGENERICIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_CALLR_RISCV_CALL_TRAMPR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
 
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 120, 127, 134, 142, 150, 158, 164, 170, 176, 186, 195, 205, 221, 232, 238, 249, 259, 268, 281, 295, 309, 323, 339, 350, 363, 376, 390, 404, 418, 433, 447, 461, 472, 486, 501, 518, 536, 557, 576, 595, 615, 635, 645, 656, 669, 680, 692, 702}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 233, 244, 250, 261, 271, 280, 293, 307, 321, 335, 351, 362, 375, 388, 402, 416, 430, 445, 459, 473, 484, 498, 513, 530, 548, 569, 581, 599, 618, 637, 657, 677, 687, 698, 711, 722, 734, 744}
 
 func (i RelocType) String() string {
        i -= 1
index 6c991121e72d5d222984ca38cc52db6e6b2ad73b..28f430fc547cbd2160ecdde32f6665951d9332bf 100644 (file)
@@ -65,13 +65,6 @@ const (
        SDWARFRANGE
        SDWARFLOC
        SDWARFLINES
-       // ABI alias. An ABI alias symbol is an empty symbol with a
-       // single relocation with 0 size that references the native
-       // function implementation symbol.
-       //
-       // TODO(austin): Remove this and all uses once the compiler
-       // generates real ABI wrappers rather than symbol aliases.
-       SABIALIAS
        // Coverage instrumentation counter for libfuzzer.
        SLIBFUZZER_EXTRA_COUNTER
        // Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
index 1b1c394038a7d9cea376bcd17357c0de06f129ac..c90cf43b502ef12e55c1ab54bb802e716f36c74e 100644 (file)
@@ -25,13 +25,12 @@ func _() {
        _ = x[SDWARFRANGE-14]
        _ = x[SDWARFLOC-15]
        _ = x[SDWARFLINES-16]
-       _ = x[SABIALIAS-17]
-       _ = x[SLIBFUZZER_EXTRA_COUNTER-18]
+       _ = x[SLIBFUZZER_EXTRA_COUNTER-17]
 }
 
-const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSABIALIASSLIBFUZZER_EXTRA_COUNTER"
+const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSLIBFUZZER_EXTRA_COUNTER"
 
-var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 63, 74, 83, 95, 105, 114, 125, 134, 145, 154, 178}
+var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 63, 74, 83, 95, 105, 114, 125, 134, 145, 169}
 
 func (i SymKind) String() string {
        if i >= SymKind(len(_SymKind_index)-1) {
index 63640950d9f8ee609ad30e607c1528b4664d5b77..6bfa25a5caec05da06a1bd5cb3c9b725f642b85c 100644 (file)
@@ -13,7 +13,8 @@ import (
 
 const (
        ElfRelocOffset   = 256
-       MachoRelocOffset = 2048 // reserve enough space for ELF relocations
+       MachoRelocOffset = 2048    // reserve enough space for ELF relocations
+       GlobalDictPrefix = ".dict" // prefix for names of global dictionaries
 )
 
 // HeaderString returns the toolchain configuration string written in
index dd21d223511198448d127596c53095c1ab924700..24d2d0bb5c7b76c9ab91f9123d298f04b1e1c295 100644 (file)
@@ -250,26 +250,21 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
                if pc < addr || pc >= addr+uint64(osym.Siz()) {
                        continue
                }
-               isym := ^uint32(0)
-               auxs := r.Auxs(i)
-               for j := range auxs {
-                       a := &auxs[j]
-                       if a.Type() != goobj.AuxFuncInfo {
-                               continue
+               var pcfileSym, pclineSym goobj.SymRef
+               for _, a := range r.Auxs(i) {
+                       switch a.Type() {
+                       case goobj.AuxPcfile:
+                               pcfileSym = a.Sym()
+                       case goobj.AuxPcline:
+                               pclineSym = a.Sym()
                        }
-                       if a.Sym().PkgIdx != goobj.PkgIdxSelf {
-                               panic("funcinfo symbol not defined in current package")
-                       }
-                       isym = a.Sym().SymIdx
                }
-               if isym == ^uint32(0) {
+               if pcfileSym.IsZero() || pclineSym.IsZero() {
                        continue
                }
-               b := r.BytesAt(r.DataOff(isym), r.DataSize(isym))
-               var info *goobj.FuncInfo
-               pcline := getSymData(info.ReadPcline(b))
+               pcline := getSymData(pclineSym)
                line := int(pcValue(pcline, pc-addr, f.arch))
-               pcfile := getSymData(info.ReadPcfile(b))
+               pcfile := getSymData(pcfileSym)
                fileID := pcValue(pcfile, pc-addr, f.arch)
                fileName := r.File(int(fileID))
                // Note: we provide only the name in the Func structure.
diff --git a/src/cmd/internal/quoted/quoted.go b/src/cmd/internal/quoted/quoted.go
new file mode 100644 (file)
index 0000000..e7575df
--- /dev/null
@@ -0,0 +1,127 @@
+// 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 quoted provides string manipulation utilities.
+package quoted
+
+import (
+       "flag"
+       "fmt"
+       "strings"
+       "unicode"
+)
+
+func isSpaceByte(c byte) bool {
+       return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+// Split splits s into a list of fields,
+// allowing single or double quotes around elements.
+// There is no unescaping or other processing within
+// quoted fields.
+func Split(s string) ([]string, error) {
+       // Split fields allowing '' or "" around elements.
+       // Quotes further inside the string do not count.
+       var f []string
+       for len(s) > 0 {
+               for len(s) > 0 && isSpaceByte(s[0]) {
+                       s = s[1:]
+               }
+               if len(s) == 0 {
+                       break
+               }
+               // Accepted quoted string. No unescaping inside.
+               if s[0] == '"' || s[0] == '\'' {
+                       quote := s[0]
+                       s = s[1:]
+                       i := 0
+                       for i < len(s) && s[i] != quote {
+                               i++
+                       }
+                       if i >= len(s) {
+                               return nil, fmt.Errorf("unterminated %c string", quote)
+                       }
+                       f = append(f, s[:i])
+                       s = s[i+1:]
+                       continue
+               }
+               i := 0
+               for i < len(s) && !isSpaceByte(s[i]) {
+                       i++
+               }
+               f = append(f, s[:i])
+               s = s[i:]
+       }
+       return f, nil
+}
+
+// Join joins a list of arguments into a string that can be parsed
+// with Split. Arguments are quoted only if necessary; arguments
+// without spaces or quotes are kept as-is. No argument may contain both
+// single and double quotes.
+func Join(args []string) (string, error) {
+       var buf []byte
+       for i, arg := range args {
+               if i > 0 {
+                       buf = append(buf, ' ')
+               }
+               var sawSpace, sawSingleQuote, sawDoubleQuote bool
+               for _, c := range arg {
+                       switch {
+                       case c > unicode.MaxASCII:
+                               continue
+                       case isSpaceByte(byte(c)):
+                               sawSpace = true
+                       case c == '\'':
+                               sawSingleQuote = true
+                       case c == '"':
+                               sawDoubleQuote = true
+                       }
+               }
+               switch {
+               case !sawSpace && !sawSingleQuote && !sawDoubleQuote:
+                       buf = append(buf, []byte(arg)...)
+
+               case !sawSingleQuote:
+                       buf = append(buf, '\'')
+                       buf = append(buf, []byte(arg)...)
+                       buf = append(buf, '\'')
+
+               case !sawDoubleQuote:
+                       buf = append(buf, '"')
+                       buf = append(buf, []byte(arg)...)
+                       buf = append(buf, '"')
+
+               default:
+                       return "", fmt.Errorf("argument %q contains both single and double quotes and cannot be quoted", arg)
+               }
+       }
+       return string(buf), nil
+}
+
+// A Flag parses a list of string arguments encoded with Join.
+// It is useful for flags like cmd/link's -extldflags.
+type Flag []string
+
+var _ flag.Value = (*Flag)(nil)
+
+func (f *Flag) Set(v string) error {
+       fs, err := Split(v)
+       if err != nil {
+               return err
+       }
+       *f = fs[:len(fs):len(fs)]
+       return nil
+}
+
+func (f *Flag) String() string {
+       if f == nil {
+               return ""
+       }
+       s, err := Join(*f)
+       if err != nil {
+               return strings.Join(*f, " ")
+       }
+       return s
+}
diff --git a/src/cmd/internal/quoted/quoted_test.go b/src/cmd/internal/quoted/quoted_test.go
new file mode 100644 (file)
index 0000000..d76270c
--- /dev/null
@@ -0,0 +1,88 @@
+// 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 quoted
+
+import (
+       "reflect"
+       "strings"
+       "testing"
+)
+
+func TestSplit(t *testing.T) {
+       for _, test := range []struct {
+               name    string
+               value   string
+               want    []string
+               wantErr string
+       }{
+               {name: "empty", value: "", want: nil},
+               {name: "space", value: " ", want: nil},
+               {name: "one", value: "a", want: []string{"a"}},
+               {name: "leading_space", value: " a", want: []string{"a"}},
+               {name: "trailing_space", value: "a ", want: []string{"a"}},
+               {name: "two", value: "a b", want: []string{"a", "b"}},
+               {name: "two_multi_space", value: "a  b", want: []string{"a", "b"}},
+               {name: "two_tab", value: "a\tb", want: []string{"a", "b"}},
+               {name: "two_newline", value: "a\nb", want: []string{"a", "b"}},
+               {name: "quote_single", value: `'a b'`, want: []string{"a b"}},
+               {name: "quote_double", value: `"a b"`, want: []string{"a b"}},
+               {name: "quote_both", value: `'a '"b "`, want: []string{"a ", "b "}},
+               {name: "quote_contains", value: `'a "'"'b"`, want: []string{`a "`, `'b`}},
+               {name: "escape", value: `\'`, want: []string{`\'`}},
+               {name: "quote_unclosed", value: `'a`, wantErr: "unterminated ' string"},
+       } {
+               t.Run(test.name, func(t *testing.T) {
+                       got, err := Split(test.value)
+                       if err != nil {
+                               if test.wantErr == "" {
+                                       t.Fatalf("unexpected error: %v", err)
+                               } else if errMsg := err.Error(); !strings.Contains(errMsg, test.wantErr) {
+                                       t.Fatalf("error %q does not contain %q", errMsg, test.wantErr)
+                               }
+                               return
+                       }
+                       if test.wantErr != "" {
+                               t.Fatalf("unexpected success; wanted error containing %q", test.wantErr)
+                       }
+                       if !reflect.DeepEqual(got, test.want) {
+                               t.Errorf("got %q; want %q", got, test.want)
+                       }
+               })
+       }
+}
+
+func TestJoin(t *testing.T) {
+       for _, test := range []struct {
+               name          string
+               args          []string
+               want, wantErr string
+       }{
+               {name: "empty", args: nil, want: ""},
+               {name: "one", args: []string{"a"}, want: "a"},
+               {name: "two", args: []string{"a", "b"}, want: "a b"},
+               {name: "space", args: []string{"a ", "b"}, want: "'a ' b"},
+               {name: "newline", args: []string{"a\n", "b"}, want: "'a\n' b"},
+               {name: "quote", args: []string{`'a `, "b"}, want: `"'a " b`},
+               {name: "unquoteable", args: []string{`'"`}, wantErr: "contains both single and double quotes and cannot be quoted"},
+       } {
+               t.Run(test.name, func(t *testing.T) {
+                       got, err := Join(test.args)
+                       if err != nil {
+                               if test.wantErr == "" {
+                                       t.Fatalf("unexpected error: %v", err)
+                               } else if errMsg := err.Error(); !strings.Contains(errMsg, test.wantErr) {
+                                       t.Fatalf("error %q does not contain %q", errMsg, test.wantErr)
+                               }
+                               return
+                       }
+                       if test.wantErr != "" {
+                               t.Fatalf("unexpected success; wanted error containing %q", test.wantErr)
+                       }
+                       if got != test.want {
+                               t.Errorf("got %s; want %s", got, test.want)
+                       }
+               })
+       }
+}
index a3e39768b6f5057488be62711d80de8dcbe459ac..ea76b596c15cbc2079d62069d6ea180ac1d5d240 100644 (file)
@@ -16,6 +16,7 @@ const (
        ARM
        ARM64
        I386
+       Loong64
        MIPS
        MIPS64
        PPC64
@@ -46,6 +47,11 @@ type Arch struct {
        // Loads or stores smaller than Alignment must be naturally aligned.
        // Loads or stores larger than Alignment need only be Alignment-aligned.
        Alignment int8
+
+       // CanMergeLoads reports whether the backend optimization passes
+       // can combine adjacent loads into a single larger, possibly unaligned, load.
+       // Note that currently the optimizations must be able to handle little endian byte order.
+       CanMergeLoads bool
 }
 
 // InFamily reports whether a is a member of any of the specified
@@ -60,133 +66,157 @@ func (a *Arch) InFamily(xs ...ArchFamily) bool {
 }
 
 var Arch386 = &Arch{
-       Name:      "386",
-       Family:    I386,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   4,
-       RegSize:   4,
-       MinLC:     1,
-       Alignment: 1,
+       Name:          "386",
+       Family:        I386,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       4,
+       RegSize:       4,
+       MinLC:         1,
+       Alignment:     1,
+       CanMergeLoads: true,
 }
 
 var ArchAMD64 = &Arch{
-       Name:      "amd64",
-       Family:    AMD64,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     1,
-       Alignment: 1,
+       Name:          "amd64",
+       Family:        AMD64,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         1,
+       Alignment:     1,
+       CanMergeLoads: true,
 }
 
 var ArchARM = &Arch{
-       Name:      "arm",
-       Family:    ARM,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   4,
-       RegSize:   4,
-       MinLC:     4,
-       Alignment: 4, // TODO: just for arm5?
+       Name:          "arm",
+       Family:        ARM,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       4,
+       RegSize:       4,
+       MinLC:         4,
+       Alignment:     4, // TODO: just for arm5?
+       CanMergeLoads: false,
 }
 
 var ArchARM64 = &Arch{
-       Name:      "arm64",
-       Family:    ARM64,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     4,
-       Alignment: 1,
+       Name:          "arm64",
+       Family:        ARM64,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     1,
+       CanMergeLoads: true,
+}
+
+var ArchLoong64 = &Arch{
+       Name:          "loong64",
+       Family:        Loong64,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     8, // Unaligned accesses are not guaranteed to be fast
+       CanMergeLoads: false,
 }
 
 var ArchMIPS = &Arch{
-       Name:      "mips",
-       Family:    MIPS,
-       ByteOrder: binary.BigEndian,
-       PtrSize:   4,
-       RegSize:   4,
-       MinLC:     4,
-       Alignment: 4,
+       Name:          "mips",
+       Family:        MIPS,
+       ByteOrder:     binary.BigEndian,
+       PtrSize:       4,
+       RegSize:       4,
+       MinLC:         4,
+       Alignment:     4,
+       CanMergeLoads: false,
 }
 
 var ArchMIPSLE = &Arch{
-       Name:      "mipsle",
-       Family:    MIPS,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   4,
-       RegSize:   4,
-       MinLC:     4,
-       Alignment: 4,
+       Name:          "mipsle",
+       Family:        MIPS,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       4,
+       RegSize:       4,
+       MinLC:         4,
+       Alignment:     4,
+       CanMergeLoads: false,
 }
 
 var ArchMIPS64 = &Arch{
-       Name:      "mips64",
-       Family:    MIPS64,
-       ByteOrder: binary.BigEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     4,
-       Alignment: 8,
+       Name:          "mips64",
+       Family:        MIPS64,
+       ByteOrder:     binary.BigEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     8,
+       CanMergeLoads: false,
 }
 
 var ArchMIPS64LE = &Arch{
-       Name:      "mips64le",
-       Family:    MIPS64,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     4,
-       Alignment: 8,
+       Name:          "mips64le",
+       Family:        MIPS64,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     8,
+       CanMergeLoads: false,
 }
 
 var ArchPPC64 = &Arch{
-       Name:      "ppc64",
-       Family:    PPC64,
-       ByteOrder: binary.BigEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     4,
-       Alignment: 1,
+       Name:          "ppc64",
+       Family:        PPC64,
+       ByteOrder:     binary.BigEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     1,
+       CanMergeLoads: false,
 }
 
 var ArchPPC64LE = &Arch{
-       Name:      "ppc64le",
-       Family:    PPC64,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     4,
-       Alignment: 1,
+       Name:          "ppc64le",
+       Family:        PPC64,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     1,
+       CanMergeLoads: true,
 }
 
 var ArchRISCV64 = &Arch{
-       Name:      "riscv64",
-       Family:    RISCV64,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     4,
-       Alignment: 8, // riscv unaligned loads work, but are really slow (trap + simulated by OS)
+       Name:          "riscv64",
+       Family:        RISCV64,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         4,
+       Alignment:     8, // riscv unaligned loads work, but are really slow (trap + simulated by OS)
+       CanMergeLoads: false,
 }
 
 var ArchS390X = &Arch{
-       Name:      "s390x",
-       Family:    S390X,
-       ByteOrder: binary.BigEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     2,
-       Alignment: 1,
+       Name:          "s390x",
+       Family:        S390X,
+       ByteOrder:     binary.BigEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         2,
+       Alignment:     1,
+       CanMergeLoads: true,
 }
 
 var ArchWasm = &Arch{
-       Name:      "wasm",
-       Family:    Wasm,
-       ByteOrder: binary.LittleEndian,
-       PtrSize:   8,
-       RegSize:   8,
-       MinLC:     1,
-       Alignment: 1,
+       Name:          "wasm",
+       Family:        Wasm,
+       ByteOrder:     binary.LittleEndian,
+       PtrSize:       8,
+       RegSize:       8,
+       MinLC:         1,
+       Alignment:     1,
+       CanMergeLoads: false,
 }
 
 var Archs = [...]*Arch{
@@ -194,6 +224,7 @@ var Archs = [...]*Arch{
        ArchAMD64,
        ArchARM,
        ArchARM64,
+       ArchLoong64,
        ArchMIPS,
        ArchMIPSLE,
        ArchMIPS64,
diff --git a/src/cmd/internal/sys/args.go b/src/cmd/internal/sys/args.go
new file mode 100644 (file)
index 0000000..cc9fb64
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2021 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 sys
+
+// ExecArgLengthLimit is the number of bytes we can safely
+// pass as arguments to an exec.Command.
+//
+// Windows has a limit of 32 KB. To be conservative and not worry about whether
+// that includes spaces or not, just use 30 KB. Darwin's limit is less clear.
+// The OS claims 256KB, but we've seen failures with arglen as small as 50KB.
+const ExecArgLengthLimit = (30 << 10)
index 0d2bad961278f4392c3c27a1ecc4617ac2d9b74c..c6a78a51eb1aaf805bc3e2aefcbe87e793f70e2a 100644 (file)
@@ -34,6 +34,41 @@ func MSanSupported(goos, goarch string) bool {
        }
 }
 
+// ASanSupported reports whether goos/goarch supports the address
+// sanitizer option.
+// There is a copy of this function in misc/cgo/testsanitizers/cc_test.go.
+func ASanSupported(goos, goarch string) bool {
+       switch goos {
+       case "linux":
+               return goarch == "arm64" || goarch == "amd64"
+       default:
+               return false
+       }
+}
+
+// FuzzSupported reports whether goos/goarch supports fuzzing
+// ('go test -fuzz=.').
+func FuzzSupported(goos, goarch string) bool {
+       switch goos {
+       case "darwin", "linux", "windows":
+               return true
+       default:
+               return false
+       }
+}
+
+// FuzzInstrumented reports whether fuzzing on goos/goarch uses coverage
+// instrumentation. (FuzzInstrumented implies FuzzSupported.)
+func FuzzInstrumented(goos, goarch string) bool {
+       switch goarch {
+       case "amd64", "arm64":
+               // TODO(#14565): support more architectures.
+               return FuzzSupported(goos, goarch)
+       default:
+               return false
+       }
+}
+
 // MustLinkExternal reports whether goos/goarch requires external linking.
 // (This is the opposite of internal/testenv.CanInternalLink. Keep them in sync.)
 func MustLinkExternal(goos, goarch string) bool {
@@ -70,7 +105,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
 
        case "c-shared":
                switch platform {
-               case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
+               case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/riscv64", "linux/s390x",
                        "android/amd64", "android/arm", "android/arm64", "android/386",
                        "freebsd/amd64",
                        "darwin/amd64", "darwin/arm64",
index 604675caecf1f2ed72398a63a119931821ac6d5a..98c954f0f1ad76e871bb6c8a504d29a64bf0cbe4 100644 (file)
@@ -45,6 +45,8 @@ Flags:
                Note that before Go 1.5 this option took two separate arguments.
        -a
                Disassemble output.
+       -asan
+               Link with C/C++ address sanitizer support.
        -buildid id
                Record id as Go toolchain build id.
        -buildmode mode
index 3ca59bd47f025cf1eac24eac43fddec1700c2348..78ef3cfe9713691cbb053a8e180cff02dcd66820 100644 (file)
@@ -8,6 +8,7 @@ import (
        "bytes"
        cmddwarf "cmd/internal/dwarf"
        "cmd/internal/objfile"
+       "cmd/internal/quoted"
        "debug/dwarf"
        "internal/testenv"
        "os"
@@ -67,8 +68,11 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string)
                        if extld == "" {
                                extld = "gcc"
                        }
-                       var err error
-                       expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
+                       extldArgs, err := quoted.Split(extld)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extldArgs)
                        if err != nil {
                                t.Fatal(err)
                        }
index ab780214bb65f547c3dc89d7446939fade4e7c63..347932c6e1dbf97cf8985c5e14d9f509077331d4 100644 (file)
@@ -544,7 +544,6 @@ func gentrampdyn(arch *sys.Arch, tramp *loader.SymbolBuilder, target loader.Sym,
 
 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
        rs := r.Sym()
-       rs = ldr.ResolveABIAlias(rs)
        if target.IsExternal() {
                switch r.Type() {
                case objabi.R_CALLARM:
@@ -592,7 +591,7 @@ func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant
 }
 
 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        var rr loader.ExtReloc
        switch r.Type() {
        case objabi.R_CALLARM:
index c10bdc4120a601676efdede7bb6859d1b13229fe..abae0f87bcda689c7d2253535f5b38c017092a03 100644 (file)
@@ -602,7 +602,7 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
        rs := r.Xsym
        rt := r.Type
 
-       if r.Xadd != signext21(r.Xadd) {
+       if rt == objabi.R_ADDRARM64 && r.Xadd != signext21(r.Xadd) {
                // If the relocation target would overflow the addend, then target
                // a linker-manufactured label symbol with a smaller addend instead.
                label := ldr.Lookup(offsetLabelName(ldr, rs, r.Xadd/peRelocLimit*peRelocLimit), ldr.SymVersion(rs))
@@ -668,7 +668,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
        const noExtReloc = 0
        const isOk = true
 
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
 
        if target.IsExternal() {
                nExtReloc := 0
index 20f1d0b8c12c6848fd68f83a7e4b41cd1c9f2b7a..2d7e1bff68a11afda5c65b2aacdb72b0067308fe 100644 (file)
@@ -74,7 +74,7 @@ func (mode *BuildMode) Set(s string) error {
                *mode = BuildModeCArchive
        case "c-shared":
                switch buildcfg.GOARCH {
-               case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
+               case "386", "amd64", "arm", "arm64", "ppc64le", "riscv64", "s390x":
                default:
                        return badmode()
                }
@@ -193,10 +193,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
                return true, "msan"
        }
 
+       if *flagAsan {
+               return true, "asan"
+       }
+
        // Internally linking cgo is incomplete on some architectures.
        // https://golang.org/issue/14449
-       // https://golang.org/issue/21961
-       if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64, sys.RISCV64) {
+       if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.RISCV64) {
                return true, buildcfg.GOARCH + " does not support internal cgo"
        }
        if iscgo && (buildcfg.GOOS == "android" || buildcfg.GOOS == "dragonfly") {
@@ -209,12 +212,9 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
                // windows/arm64 internal linking is not implemented.
                return true, buildcfg.GOOS + "/" + buildcfg.GOARCH + " does not support internal cgo"
        }
-
-       // When the race flag is set, the LLVM tsan relocatable file is linked
-       // into the final binary, which means external linking is required because
-       // internal linking does not support it.
-       if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
-               return true, "race on " + buildcfg.GOARCH
+       if iscgo && ctxt.Arch == sys.ArchPPC64 {
+               // Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
+               return true, buildcfg.GOOS + " does not support internal cgo"
        }
 
        // Some build modes require work the internal linker cannot do (yet).
index 70fbb9dc4e24cf2d47c78c89b072684625735784..0513a0d10b567b9fbc48043b98d2070dbfb5c7cf 100644 (file)
@@ -92,10 +92,10 @@ func maxSizeTrampolines(ctxt *Link, ldr *loader.Loader, s loader.Sym, isTramp bo
        panic("unreachable")
 }
 
-// detect too-far jumps in function s, and add trampolines if necessary
-// ARM, PPC64 & PPC64LE support trampoline insertion for internal and external linking
-// On PPC64 & PPC64LE the text sections might be split but will still insert trampolines
-// where necessary.
+// Detect too-far jumps in function s, and add trampolines if necessary.
+// ARM, PPC64, PPC64LE and RISCV64 support trampoline insertion for internal
+// and external linking. On PPC64 and PPC64LE the text sections might be split
+// but will still insert trampolines where necessary.
 func trampoline(ctxt *Link, s loader.Sym) {
        if thearch.Trampoline == nil {
                return // no need or no support of trampolines on this arch
@@ -113,8 +113,11 @@ func trampoline(ctxt *Link, s loader.Sym) {
                if !ldr.AttrReachable(rs) || ldr.SymType(rs) == sym.Sxxx {
                        continue // something is wrong. skip it here and we'll emit a better error later
                }
-               rs = ldr.ResolveABIAlias(rs)
-               if ldr.SymValue(rs) == 0 && (ldr.SymType(rs) != sym.SDYNIMPORT && ldr.SymType(rs) != sym.SUNDEFEXT) {
+
+               // RISC-V is only able to reach +/-1MiB via a JAL instruction,
+               // which we can readily exceed in the same package. As such, we
+               // need to generate trampolines when the address is unknown.
+               if ldr.SymValue(rs) == 0 && !ctxt.Target.IsRISCV64() && ldr.SymType(rs) != sym.SDYNIMPORT && ldr.SymType(rs) != sym.SUNDEFEXT {
                        if ldr.SymPkg(s) != "" && ldr.SymPkg(rs) == ldr.SymPkg(s) {
                                // Symbols in the same package are laid out together.
                                // Except that if SymPkg(s) == "", it is a host object symbol
@@ -125,7 +128,6 @@ func trampoline(ctxt *Link, s loader.Sym) {
                                continue // runtime packages are laid out together
                        }
                }
-
                thearch.Trampoline(ctxt, ldr, ri, rs, s)
        }
 }
@@ -194,7 +196,6 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
                off := r.Off()
                siz := int32(r.Siz())
                rs := r.Sym()
-               rs = ldr.ResolveABIAlias(rs)
                rt := r.Type()
                weak := r.Weak()
                if off < 0 || off+siz > int32(len(P)) {
@@ -340,7 +341,6 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
                        if weak && !ldr.AttrReachable(rs) {
                                // Redirect it to runtime.unreachableMethod, which will throw if called.
                                rs = syms.unreachableMethod
-                               rs = ldr.ResolveABIAlias(rs)
                        }
                        if target.IsExternal() {
                                nExtReloc++
@@ -436,6 +436,11 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
                        if weak && !ldr.AttrReachable(rs) {
                                continue
                        }
+                       if ldr.SymSect(rs) == nil {
+                               st.err.Errorf(s, "unreachable sym in relocation: %s", ldr.SymName(rs))
+                               continue
+                       }
+
                        // The method offset tables using this relocation expect the offset to be relative
                        // to the start of the first text section, even if there are multiple.
                        if ldr.SymSect(rs).Name == ".text" {
@@ -609,7 +614,7 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa
 
        case objabi.R_TLS_LE, objabi.R_TLS_IE:
                if target.IsElf() {
-                       rs := ldr.ResolveABIAlias(r.Sym())
+                       rs := r.Sym()
                        rr.Xsym = rs
                        if rr.Xsym == 0 {
                                rr.Xsym = ctxt.Tlsg
@@ -621,10 +626,9 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa
 
        case objabi.R_ADDR:
                // set up addend for eventual relocation via outer symbol.
-               rs := ldr.ResolveABIAlias(r.Sym())
+               rs := r.Sym()
                if r.Weak() && !ldr.AttrReachable(rs) {
                        rs = ctxt.ArchSyms.unreachableMethod
-                       rs = ldr.ResolveABIAlias(rs)
                }
                rs, off := FoldSubSymbolOffset(ldr, rs)
                rr.Xadd = r.Add() + off
@@ -639,13 +643,13 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa
                if target.IsDarwin() {
                        return rr, false
                }
-               rs := ldr.ResolveABIAlias(r.Sym())
+               rs := r.Sym()
                rr.Xsym = loader.Sym(ldr.SymSect(rs).Sym)
                rr.Xadd = r.Add() + ldr.SymValue(rs) - int64(ldr.SymSect(rs).Vaddr)
 
        // r.Sym() can be 0 when CALL $(constant) is transformed from absolute PC to relative PC call.
        case objabi.R_GOTPCREL, objabi.R_CALL, objabi.R_PCREL:
-               rs := ldr.ResolveABIAlias(r.Sym())
+               rs := r.Sym()
                if rt == objabi.R_GOTPCREL && target.IsDynlinkingGo() && target.IsDarwin() && rs != 0 {
                        rr.Xadd = r.Add()
                        rr.Xadd -= int64(siz) // relative to address after the relocated chunk
@@ -687,7 +691,7 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc) (loa
 // symbol and addend.
 func ExtrelocSimple(ldr *loader.Loader, r loader.Reloc) loader.ExtReloc {
        var rr loader.ExtReloc
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        rr.Xsym = rs
        rr.Xadd = r.Add()
        rr.Type = r.Type()
@@ -700,7 +704,7 @@ func ExtrelocSimple(ldr *loader.Loader, r loader.Reloc) loader.ExtReloc {
 func ExtrelocViaOuterSym(ldr *loader.Loader, r loader.Reloc, s loader.Sym) loader.ExtReloc {
        // set up addend for eventual relocation via outer symbol.
        var rr loader.ExtReloc
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        rs, off := FoldSubSymbolOffset(ldr, rs)
        rr.Xadd = r.Add() + off
        rst := ldr.SymType(rs)
@@ -1164,13 +1168,6 @@ func symalign(ldr *loader.Loader, s loader.Sym) int32 {
        } else if align != 0 {
                return min
        }
-       // FIXME: figure out a way to avoid checking by name here.
-       sname := ldr.SymName(s)
-       if strings.HasPrefix(sname, "go.string.") || strings.HasPrefix(sname, "type..namedata.") {
-               // String data is just bytes.
-               // If we align it, we waste a lot of space to padding.
-               return min
-       }
        align = int32(thearch.Maxalign)
        ssz := ldr.SymSize(s)
        for int64(align) > ssz && align > min {
@@ -1370,6 +1367,11 @@ func (state *dodataState) makeRelroForSharedLib(target *Link) {
                                        // the relro data.
                                        isRelro = true
                                }
+                       case sym.SGOFUNC:
+                               // The only SGOFUNC symbols that contain relocations are .stkobj,
+                               // and their relocations are of type objabi.R_ADDROFF,
+                               // which always get resolved during linking.
+                               isRelro = false
                        }
                        if isRelro {
                                state.setSymType(s, symnrelro)
@@ -1705,21 +1707,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
        }
        ldr := ctxt.loader
 
-       // .got (and .toc on ppc64)
+       // .got
        if len(state.data[sym.SELFGOT]) > 0 {
-               sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
-               if ctxt.IsPPC64() {
-                       for _, s := range state.data[sym.SELFGOT] {
-                               // Resolve .TOC. symbol for this object file (ppc64)
-
-                               toc := ldr.Lookup(".TOC.", int(ldr.SymVersion(s)))
-                               if toc != 0 {
-                                       ldr.SetSymSect(toc, sect)
-                                       ldr.AddInteriorSym(s, toc)
-                                       ldr.SetSymValue(toc, 0x8000)
-                               }
-                       }
-               }
+               state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
        }
 
        /* pointer-free data */
@@ -1789,7 +1779,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
 
        // Coverage instrumentation counters for libfuzzer.
        if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
-               state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
+               sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
+               ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._counters", 0), sect)
+               ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._ecounters", 0), sect)
        }
 
        if len(state.data[sym.STLSBSS]) > 0 {
@@ -2450,6 +2442,12 @@ func splitTextSections(ctxt *Link) bool {
        return (ctxt.IsPPC64() || (ctxt.IsARM64() && ctxt.IsDarwin())) && ctxt.IsExternal()
 }
 
+// On Wasm, we reserve 4096 bytes for zero page, then 8192 bytes for wasm_exec.js
+// to store command line args and environment variables.
+// Data sections starts from at least address 12288.
+// Keep in sync with wasm_exec.js.
+const wasmMinDataAddr = 4096 + 8192
+
 // address assigns virtual addresses to all segments and sections and
 // returns all segments in file order.
 func (ctxt *Link) address() []*sym.Segment {
@@ -2459,10 +2457,14 @@ func (ctxt *Link) address() []*sym.Segment {
        order = append(order, &Segtext)
        Segtext.Rwx = 05
        Segtext.Vaddr = va
-       for _, s := range Segtext.Sections {
+       for i, s := range Segtext.Sections {
                va = uint64(Rnd(int64(va), int64(s.Align)))
                s.Vaddr = va
                va += s.Length
+
+               if ctxt.IsWasm() && i == 0 && va < wasmMinDataAddr {
+                       va = wasmMinDataAddr
+               }
        }
 
        Segtext.Length = va - uint64(*FlagTextAddr)
@@ -2529,6 +2531,7 @@ func (ctxt *Link) address() []*sym.Segment {
        var noptr *sym.Section
        var bss *sym.Section
        var noptrbss *sym.Section
+       var fuzzCounters *sym.Section
        for i, s := range Segdata.Sections {
                if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && s.Name == ".tbss" {
                        continue
@@ -2540,17 +2543,17 @@ func (ctxt *Link) address() []*sym.Segment {
                s.Vaddr = va
                va += uint64(vlen)
                Segdata.Length = va - Segdata.Vaddr
-               if s.Name == ".data" {
+               switch s.Name {
+               case ".data":
                        data = s
-               }
-               if s.Name == ".noptrdata" {
+               case ".noptrdata":
                        noptr = s
-               }
-               if s.Name == ".bss" {
+               case ".bss":
                        bss = s
-               }
-               if s.Name == ".noptrbss" {
+               case ".noptrbss":
                        noptrbss = s
+               case "__libfuzzer_extra_counters":
+                       fuzzCounters = s
                }
        }
 
@@ -2667,6 +2670,11 @@ func (ctxt *Link) address() []*sym.Segment {
        ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
        ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
 
+       if fuzzCounters != nil {
+               ctxt.xdefine("internal/fuzz._counters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr))
+               ctxt.xdefine("internal/fuzz._ecounters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
+       }
+
        if ctxt.IsSolaris() {
                // On Solaris, in the runtime it sets the external names of the
                // end symbols. Unset them and define separate symbols, so we
@@ -2685,6 +2693,24 @@ func (ctxt *Link) address() []*sym.Segment {
                ldr.SetSymSect(ldr.Lookup("_end", 0), ldr.SymSect(end))
        }
 
+       if ctxt.IsPPC64() && ctxt.IsElf() {
+               // Resolve .TOC. symbols for all objects. Only one TOC region is supported. If a
+               // GOT section is present, compute it as suggested by the ELFv2 ABI. Otherwise,
+               // choose a similar offset from the start of the data segment.
+               tocAddr := int64(Segdata.Vaddr) + 0x8000
+               if gotAddr := ldr.SymValue(ctxt.GOT); gotAddr != 0 {
+                       tocAddr = gotAddr + 0x8000
+               }
+               for i, _ := range ctxt.DotTOC {
+                       if i >= sym.SymVerABICount && i < sym.SymVerStatic { // these versions are not used currently
+                               continue
+                       }
+                       if toc := ldr.Lookup(".TOC.", i); toc != 0 {
+                               ldr.SetSymValue(toc, tocAddr)
+                       }
+               }
+       }
+
        return order
 }
 
index dd5dafc21b2361346c862c2a5af5a5abdb5b1a46..7b57a85cdec89fafaa3286f223e6e0f1ecbb0120 100644 (file)
@@ -22,10 +22,11 @@ type deadcodePass struct {
        ldr  *loader.Loader
        wq   heap // work queue, using min-heap for better locality
 
-       ifaceMethod     map[methodsig]bool // methods declared in reached interfaces
-       markableMethods []methodref        // methods of reached types
-       reflectSeen     bool               // whether we have seen a reflect method call
-       dynlink         bool
+       ifaceMethod        map[methodsig]bool // methods called from reached interface call sites
+       genericIfaceMethod map[string]bool    // names of methods called from reached generic interface call sites
+       markableMethods    []methodref        // methods of reached types
+       reflectSeen        bool               // whether we have seen a reflect method call
+       dynlink            bool
 
        methodsigstmp []methodsig // scratch buffer for decoding method signatures
 }
@@ -33,6 +34,7 @@ type deadcodePass struct {
 func (d *deadcodePass) init() {
        d.ldr.InitReachable()
        d.ifaceMethod = make(map[methodsig]bool)
+       d.genericIfaceMethod = make(map[string]bool)
        if buildcfg.Experiment.FieldTrack {
                d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
        }
@@ -96,8 +98,10 @@ func (d *deadcodePass) init() {
        for _, name := range names {
                // Mark symbol as a data/ABI0 symbol.
                d.mark(d.ldr.Lookup(name, 0), 0)
-               // Also mark any Go functions (internal ABI).
-               d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
+               if abiInternalVer != 0 {
+                       // Also mark any Go functions (internal ABI).
+                       d.mark(d.ldr.Lookup(name, abiInternalVer), 0)
+               }
        }
 
        // All dynamic exports are roots.
@@ -132,7 +136,9 @@ func (d *deadcodePass) flood() {
                methods = methods[:0]
                for i := 0; i < relocs.Count(); i++ {
                        r := relocs.At(i)
-                       if r.Weak() {
+                       // When build with "-linkshared", we can't tell if the interface
+                       // method in itab will be used or not. Ignore the weak attribute.
+                       if r.Weak() && !(d.ctxt.linkShared && d.ldr.IsItab(symIdx)) {
                                continue
                        }
                        t := r.Type()
@@ -193,6 +199,13 @@ func (d *deadcodePass) flood() {
                                }
                                d.ifaceMethod[m] = true
                                continue
+                       case objabi.R_USEGENERICIFACEMETHOD:
+                               name := d.decodeGenericIfaceMethod(d.ldr, r.Sym())
+                               if d.ctxt.Debugvlog > 1 {
+                                       d.ctxt.Logf("reached generic iface method: %s\n", name)
+                               }
+                               d.genericIfaceMethod[name] = true
+                               continue // don't mark referenced symbol - it is not needed in the final binary.
                        }
                        rs := r.Sym()
                        if isgotype && usedInIface && d.ldr.IsGoType(rs) && !d.ldr.AttrUsedInIface(rs) {
@@ -327,8 +340,8 @@ func deadcode(ctxt *Link) {
        d.init()
        d.flood()
 
-       methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
-       methByNameSym := ldr.Lookup("reflect.Value.MethodByName", sym.SymVerABIInternal)
+       methSym := ldr.Lookup("reflect.Value.Method", abiInternalVer)
+       methByNameSym := ldr.Lookup("reflect.Value.MethodByName", abiInternalVer)
 
        if ctxt.DynlinkingGo() {
                // Exported methods may satisfy interfaces we don't know
@@ -348,7 +361,7 @@ func deadcode(ctxt *Link) {
                // in the last pass.
                rem := d.markableMethods[:0]
                for _, m := range d.markableMethods {
-                       if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
+                       if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] || d.genericIfaceMethod[m.m.name] {
                                d.markMethod(m)
                        } else {
                                rem = append(rem, m)
@@ -421,6 +434,11 @@ func (d *deadcodePass) decodeIfaceMethod(ldr *loader.Loader, arch *sys.Arch, sym
        return m
 }
 
+// Decode the method name stored in symbol symIdx. The symbol should contain just the bytes of a method name.
+func (d *deadcodePass) decodeGenericIfaceMethod(ldr *loader.Loader, symIdx loader.Sym) string {
+       return string(ldr.Data(symIdx))
+}
+
 func (d *deadcodePass) decodetypeMethods(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
        p := ldr.Data(symIdx)
        if !decodetypeHasUncommon(arch, p) {
index c53d2408cbe5105fd9011b416e2d2d738241200d..47b4921cd8fe6f58290330cf9769e93151951455 100644 (file)
@@ -67,20 +67,6 @@ type dwctxt struct {
        dwmu *sync.Mutex
 }
 
-func newdwctxt(linkctxt *Link, forTypeGen bool) dwctxt {
-       d := dwctxt{
-               linkctxt: linkctxt,
-               ldr:      linkctxt.loader,
-               arch:     linkctxt.Arch,
-               tmap:     make(map[string]loader.Sym),
-               tdmap:    make(map[loader.Sym]loader.Sym),
-               rtmap:    make(map[loader.Sym]loader.Sym),
-       }
-       d.typeRuntimeEface = d.lookupOrDiag("type.runtime.eface")
-       d.typeRuntimeIface = d.lookupOrDiag("type.runtime.iface")
-       return d
-}
-
 // dwSym wraps a loader.Sym; this type is meant to obey the interface
 // rules for dwarf.Sym from the cmd/internal/dwarf package. DwDie and
 // DwAttr objects contain references to symbols via this type.
@@ -187,6 +173,16 @@ func isDwarf64(ctxt *Link) bool {
        return ctxt.HeadType == objabi.Haix
 }
 
+// https://sourceware.org/gdb/onlinedocs/gdb/dotdebug_005fgdb_005fscripts-section.html
+// Each entry inside .debug_gdb_scripts section begins with a non-null prefix
+// byte that specifies the kind of entry. The following entries are supported:
+const (
+       GdbScriptPythonFileId = 1
+       GdbScriptSchemeFileId = 3
+       GdbScriptPythonTextId = 4
+       GdbScriptSchemeTextId = 6
+)
+
 var gdbscript string
 
 // dwarfSecInfo holds information about a DWARF output section,
@@ -239,7 +235,7 @@ var dwtypes dwarf.DWDie
 // up all attrs in a single large table, then store indices into the
 // table in the DIE. This would allow us to common up storage for
 // attributes that are shared by many DIEs (ex: byte size of N).
-func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) *dwarf.DWAttr {
+func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) {
        a := new(dwarf.DWAttr)
        a.Link = die.Attr
        die.Attr = a
@@ -247,7 +243,6 @@ func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface
        a.Cls = uint8(cls)
        a.Value = value
        a.Data = data
-       return a
 }
 
 // Each DIE (except the root ones) has at least 1 attribute: its
@@ -280,7 +275,7 @@ func getattr(die *dwarf.DWDie, attr uint16) *dwarf.DWAttr {
 // The compiler does create nameless DWARF DIEs (ex: concrete subprogram
 // instance).
 // FIXME: it would be more efficient to bulk-allocate DIEs.
-func (d *dwctxt) newdie(parent *dwarf.DWDie, abbrev int, name string, version int) *dwarf.DWDie {
+func (d *dwctxt) newdie(parent *dwarf.DWDie, abbrev int, name string) *dwarf.DWDie {
        die := new(dwarf.DWDie)
        die.Abbrev = abbrev
        die.Link = parent.Child
@@ -288,10 +283,9 @@ func (d *dwctxt) newdie(parent *dwarf.DWDie, abbrev int, name string, version in
 
        newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
 
-       // Sanity check: all DIEs created in the linker should have a non-empty
-       // name and be version zero.
-       if name == "" || version != 0 {
-               panic("nameless or version non-zero DWARF DIE")
+       // Sanity check: all DIEs created in the linker should be named.
+       if name == "" {
+               panic("nameless DWARF DIE")
        }
 
        var st sym.SymKind
@@ -311,7 +305,7 @@ func (d *dwctxt) newdie(parent *dwarf.DWDie, abbrev int, name string, version in
                // this also includes loose ends such as STRUCT_FIELD.
                st = sym.SDWARFTYPE
        }
-       ds := d.ldr.LookupOrCreateSym(dwarf.InfoPrefix+name, version)
+       ds := d.ldr.LookupOrCreateSym(dwarf.InfoPrefix+name, 0)
        dsu := d.ldr.MakeSymbolUpdater(ds)
        dsu.SetType(st)
        d.ldr.SetAttrNotInSymbolTable(ds, true)
@@ -387,22 +381,20 @@ func (d *dwctxt) mustFind(name string) loader.Sym {
        return r
 }
 
-func (d *dwctxt) adddwarfref(sb *loader.SymbolBuilder, t loader.Sym, size int) int64 {
-       var result int64
+func (d *dwctxt) adddwarfref(sb *loader.SymbolBuilder, t loader.Sym, size int) {
        switch size {
        default:
                d.linkctxt.Errorf(sb.Sym(), "invalid size %d in adddwarfref\n", size)
        case d.arch.PtrSize, 4:
        }
-       result = sb.AddSymRef(d.arch, t, 0, objabi.R_DWARFSECREF, size)
-       return result
+       sb.AddSymRef(d.arch, t, 0, objabi.R_DWARFSECREF, size)
 }
 
-func (d *dwctxt) newrefattr(die *dwarf.DWDie, attr uint16, ref loader.Sym) *dwarf.DWAttr {
+func (d *dwctxt) newrefattr(die *dwarf.DWDie, attr uint16, ref loader.Sym) {
        if ref == 0 {
-               return nil
+               return
        }
-       return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, dwSym(ref))
+       newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, dwSym(ref))
 }
 
 func (d *dwctxt) dtolsym(s dwarf.Sym) loader.Sym {
@@ -471,7 +463,7 @@ func (d *dwctxt) lookupOrDiag(n string) loader.Sym {
        return symIdx
 }
 
-func (d *dwctxt) dotypedef(parent *dwarf.DWDie, gotype loader.Sym, name string, def *dwarf.DWDie) *dwarf.DWDie {
+func (d *dwctxt) dotypedef(parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
        // Only emit typedefs for real names.
        if strings.HasPrefix(name, "map[") {
                return nil
@@ -503,7 +495,7 @@ func (d *dwctxt) dotypedef(parent *dwarf.DWDie, gotype loader.Sym, name string,
        // so that future lookups will find the typedef instead
        // of the real definition. This hooks the typedef into any
        // circular definition loops, so that gdb can understand them.
-       die := d.newdie(parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
+       die := d.newdie(parent, dwarf.DW_ABRV_TYPEDECL, name)
 
        d.newrefattr(die, dwarf.DW_AT_type, tds)
 
@@ -548,7 +540,7 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
        var die, typedefdie *dwarf.DWDie
        switch kind {
        case objabi.KindBool:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
                newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_boolean, 0)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
@@ -557,7 +549,7 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                objabi.KindInt16,
                objabi.KindInt32,
                objabi.KindInt64:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
                newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_signed, 0)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
@@ -567,29 +559,29 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                objabi.KindUint32,
                objabi.KindUint64,
                objabi.KindUintptr:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
                newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
        case objabi.KindFloat32,
                objabi.KindFloat64:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
                newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_float, 0)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
        case objabi.KindComplex64,
                objabi.KindComplex128:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
                newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_complex_float, 0)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
        case objabi.KindArray:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
-               typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name)
+               typedefdie = d.dotypedef(&dwtypes, name, die)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
                s := decodetypeArrayElem(d.ldr, d.arch, gotype)
                d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
-               fld := d.newdie(die, dwarf.DW_ABRV_ARRAYRANGE, "range", 0)
+               fld := d.newdie(die, dwarf.DW_ABRV_ARRAYRANGE, "range")
 
                // use actual length not upper bound; correct for 0-length arrays.
                newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen(d.ldr, d.arch, gotype), 0)
@@ -597,7 +589,7 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
 
        case objabi.KindChan:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_CHANTYPE, name)
                s := decodetypeChanElem(d.ldr, d.arch, gotype)
                d.newrefattr(die, dwarf.DW_AT_go_elem, d.defgotype(s))
                // Save elem type for synthesizechantypes. We could synthesize here
@@ -605,9 +597,9 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                d.newrefattr(die, dwarf.DW_AT_type, s)
 
        case objabi.KindFunc:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_FUNCTYPE, name)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
-               typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+               typedefdie = d.dotypedef(&dwtypes, name, die)
                data := d.ldr.Data(gotype)
                // FIXME: add caching or reuse reloc slice.
                relocs := d.ldr.Relocs(gotype)
@@ -615,24 +607,24 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                for i := 0; i < nfields; i++ {
                        s := decodetypeFuncInType(d.ldr, d.arch, gotype, &relocs, i)
                        sn := d.ldr.SymName(s)
-                       fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:], 0)
+                       fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:])
                        d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
                }
 
                if decodetypeFuncDotdotdot(d.arch, data) {
-                       d.newdie(die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
+                       d.newdie(die, dwarf.DW_ABRV_DOTDOTDOT, "...")
                }
                nfields = decodetypeFuncOutCount(d.arch, data)
                for i := 0; i < nfields; i++ {
                        s := decodetypeFuncOutType(d.ldr, d.arch, gotype, &relocs, i)
                        sn := d.ldr.SymName(s)
-                       fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:], 0)
+                       fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:])
                        d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.defgotype(s)))
                }
 
        case objabi.KindInterface:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
-               typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_IFACETYPE, name)
+               typedefdie = d.dotypedef(&dwtypes, name, die)
                data := d.ldr.Data(gotype)
                nfields := int(decodetypeIfaceMethodCount(d.arch, data))
                var s loader.Sym
@@ -644,7 +636,7 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
 
        case objabi.KindMap:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_MAPTYPE, name)
                s := decodetypeMapKey(d.ldr, d.arch, gotype)
                d.newrefattr(die, dwarf.DW_AT_go_key, d.defgotype(s))
                s = decodetypeMapValue(d.ldr, d.arch, gotype)
@@ -654,26 +646,26 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                d.newrefattr(die, dwarf.DW_AT_type, gotype)
 
        case objabi.KindPtr:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
-               typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, name)
+               typedefdie = d.dotypedef(&dwtypes, name, die)
                s := decodetypePtrElem(d.ldr, d.arch, gotype)
                d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
 
        case objabi.KindSlice:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
-               typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_SLICETYPE, name)
+               typedefdie = d.dotypedef(&dwtypes, name, die)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
                s := decodetypeArrayElem(d.ldr, d.arch, gotype)
                elem := d.defgotype(s)
                d.newrefattr(die, dwarf.DW_AT_go_elem, elem)
 
        case objabi.KindString:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRINGTYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRINGTYPE, name)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
 
        case objabi.KindStruct:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
-               typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name)
+               typedefdie = d.dotypedef(&dwtypes, name, die)
                newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
                nfields := decodetypeStructFieldCount(d.ldr, d.arch, gotype)
                for i := 0; i < nfields; i++ {
@@ -683,7 +675,7 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                                sn := d.ldr.SymName(s)
                                f = sn[5:] // skip "type."
                        }
-                       fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
+                       fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f)
                        d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
                        offsetAnon := decodetypeStructFieldOffsAnon(d.ldr, d.arch, gotype, i)
                        newmemberoffsetattr(fld, int32(offsetAnon>>1))
@@ -693,11 +685,11 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
                }
 
        case objabi.KindUnsafePointer:
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name)
 
        default:
                d.linkctxt.Errorf(gotype, "dwarf: definition of unknown kind %d", kind)
-               die = d.newdie(&dwtypes, dwarf.DW_ABRV_TYPEDECL, name, 0)
+               die = d.newdie(&dwtypes, dwarf.DW_ABRV_TYPEDECL, name)
                d.newrefattr(die, dwarf.DW_AT_type, d.mustFind("<unspecified>"))
        }
 
@@ -744,7 +736,7 @@ func (d *dwctxt) defptrto(dwtype loader.Sym) loader.Sym {
                return die
        }
 
-       pdie := d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname, 0)
+       pdie := d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname)
        d.newrefattr(pdie, dwarf.DW_AT_type, dwtype)
 
        // The DWARF info synthesizes pointer types that don't exist at the
@@ -772,7 +764,7 @@ func (d *dwctxt) copychildrenexcept(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWD
                if src == except {
                        continue
                }
-               c := d.newdie(dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string), 0)
+               c := d.newdie(dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string))
                for a := src.Attr; a != nil; a = a.Link {
                        newattr(c, a.Atr, int(a.Cls), a.Value, a.Data)
                }
@@ -867,7 +859,7 @@ func (d *dwctxt) mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valna
        if s != 0 && d.ldr.SymType(s) == sym.SDWARFTYPE {
                return s
        }
-       die := d.newdie(&dwtypes, abbrev, name, 0)
+       die := d.newdie(&dwtypes, abbrev, name)
        f(die)
        return d.dtolsym(die.Sym)
 }
@@ -912,7 +904,7 @@ func (d *dwctxt) synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
                                t = d.defptrto(keytype)
                        }
                        d.newrefattr(dwhk, dwarf.DW_AT_type, t)
-                       fld := d.newdie(dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
+                       fld := d.newdie(dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size")
                        newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
                        d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
                })
@@ -926,7 +918,7 @@ func (d *dwctxt) synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
                                t = d.defptrto(valtype)
                        }
                        d.newrefattr(dwhv, dwarf.DW_AT_type, t)
-                       fld := d.newdie(dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
+                       fld := d.newdie(dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size")
                        newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
                        d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
                })
@@ -937,17 +929,17 @@ func (d *dwctxt) synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
                        // bucket. "data" will be replaced with keys/values below.
                        d.copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
 
-                       fld := d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys", 0)
+                       fld := d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys")
                        d.newrefattr(fld, dwarf.DW_AT_type, dwhks)
                        newmemberoffsetattr(fld, BucketSize)
-                       fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values", 0)
+                       fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values")
                        d.newrefattr(fld, dwarf.DW_AT_type, dwhvs)
                        newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
-                       fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow", 0)
+                       fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow")
                        d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.dtolsym(dwhb.Sym)))
                        newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
                        if d.arch.RegSize > d.arch.PtrSize {
-                               fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad", 0)
+                               fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad")
                                d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
                                newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(d.arch.PtrSize))
                        }
@@ -1190,7 +1182,7 @@ func (d *dwctxt) writeDirFileTables(unit *sym.CompilationUnit, lsu *loader.Symbo
                // We can't use something that may be dead-code
                // eliminated from a binary here. proc.go contains
                // main and the scheduler, so it's not going anywhere.
-               if i := strings.Index(name, "runtime/proc.go"); i >= 0 {
+               if i := strings.Index(name, "runtime/proc.go"); i >= 0 && unit.Lib.Pkg == "runtime" {
                        d.dwmu.Lock()
                        if gdbscript == "" {
                                k := strings.Index(name, "runtime/proc.go")
@@ -1425,7 +1417,7 @@ func (d *dwctxt) writeframes(fs loader.Sym) dwarfSecInfo {
                if !fi.Valid() {
                        continue
                }
-               fpcsp := fi.Pcsp()
+               fpcsp := d.ldr.Pcsp(s)
 
                // Emit a FDE, Section 6.4.1.
                // First build the section contents into a byte buffer.
@@ -1618,7 +1610,7 @@ func (d *dwctxt) writegdbscript() dwarfSecInfo {
        gs := d.ldr.CreateSymForUpdate(".debug_gdb_scripts", 0)
        gs.SetType(sym.SDWARFSECT)
 
-       gs.AddUint8(1) // magic 1 byte?
+       gs.AddUint8(GdbScriptPythonFileId)
        gs.Addstring(gdbscript)
        return dwarfSecInfo{syms: []loader.Sym{gs.Sym()}}
 }
@@ -1662,7 +1654,7 @@ func dwarfEnabled(ctxt *Link) bool {
 // newly created builtin type DIE 'typeDie'.
 func (d *dwctxt) mkBuiltinType(ctxt *Link, abrv int, tname string) *dwarf.DWDie {
        // create type DIE
-       die := d.newdie(&dwtypes, abrv, tname, 0)
+       die := d.newdie(&dwtypes, abrv, tname)
 
        // Look up type symbol.
        gotype := d.lookupOrDiag("type." + tname)
@@ -1755,7 +1747,16 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
                return
        }
 
-       d := newdwctxt(ctxt, true)
+       d := &dwctxt{
+               linkctxt: ctxt,
+               ldr:      ctxt.loader,
+               arch:     ctxt.Arch,
+               tmap:     make(map[string]loader.Sym),
+               tdmap:    make(map[loader.Sym]loader.Sym),
+               rtmap:    make(map[loader.Sym]loader.Sym),
+       }
+       d.typeRuntimeEface = d.lookupOrDiag("type.runtime.eface")
+       d.typeRuntimeIface = d.lookupOrDiag("type.runtime.iface")
 
        if ctxt.HeadType == objabi.Haix {
                // Initial map used to store package size for each DWARF section.
@@ -1766,7 +1767,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
        newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
 
        // Unspecified type. There are no references to this in the symbol table.
-       d.newdie(&dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>", 0)
+       d.newdie(&dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>")
 
        // Some types that must exist to define other ones (uintptr in particular
        // is needed for array size)
@@ -1831,7 +1832,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
                        if len(unit.Textp) == 0 {
                                cuabrv = dwarf.DW_ABRV_COMPUNIT_TEXTLESS
                        }
-                       unit.DWInfo = d.newdie(&dwroot, cuabrv, unit.Lib.Pkg, 0)
+                       unit.DWInfo = d.newdie(&dwroot, cuabrv, unit.Lib.Pkg)
                        newattr(unit.DWInfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0)
                        // OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
                        compDir := getCompilationDir()
@@ -1889,6 +1890,8 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
        // global variables. For each global of this sort, locate
        // the corresponding compiler-generated DIE symbol and tack
        // it onto the list associated with the unit.
+       // Also looks for dictionary symbols and generates DIE symbols for each
+       // type they reference.
        for idx := loader.Sym(1); idx < loader.Sym(d.ldr.NDef()); idx++ {
                if !d.ldr.AttrReachable(idx) ||
                        d.ldr.AttrNotInSymbolTable(idx) ||
@@ -1902,9 +1905,21 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
                default:
                        continue
                }
-               // Skip things with no type
+               // Skip things with no type, unless it's a dictionary
                gt := d.ldr.SymGoType(idx)
                if gt == 0 {
+                       if t == sym.SRODATA {
+                               if d.ldr.IsDict(idx) {
+                                       // This is a dictionary, make sure that all types referenced by this dictionary are reachable
+                                       relocs := d.ldr.Relocs(idx)
+                                       for i := 0; i < relocs.Count(); i++ {
+                                               reloc := relocs.At(i)
+                                               if reloc.Type() == objabi.R_USEIFACE {
+                                                       d.defgotype(reloc.Sym())
+                                               }
+                                       }
+                               }
+                       }
                        continue
                }
                // Skip file local symbols (this includes static tmps, stack
index 543dd5caac7454ade0419564fdc0bff028e38e15..db9002491e0dc015db3ec5eb9f7cde6b97043f3d 100644 (file)
@@ -11,6 +11,7 @@ import (
        "debug/pe"
        "errors"
        "fmt"
+       "internal/buildcfg"
        "internal/testenv"
        "io"
        "io/ioutil"
@@ -614,9 +615,6 @@ func TestInlinedRoutineRecords(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping on plan9; no DWARF symbol table in executables")
        }
-       if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
-               t.Skip("skipping on solaris, illumos, pending resolution of issue #23168")
-       }
 
        t.Parallel()
 
@@ -851,9 +849,6 @@ func TestAbstractOriginSanity(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping on plan9; no DWARF symbol table in executables")
        }
-       if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
-               t.Skip("skipping on solaris, illumos, pending resolution of issue #23168")
-       }
 
        if wd, err := os.Getwd(); err == nil {
                gopathdir := filepath.Join(wd, "testdata", "httptest")
@@ -869,9 +864,6 @@ func TestAbstractOriginSanityIssue25459(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping on plan9; no DWARF symbol table in executables")
        }
-       if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
-               t.Skip("skipping on solaris, illumos, pending resolution of issue #23168")
-       }
        if runtime.GOARCH != "amd64" && runtime.GOARCH != "386" {
                t.Skip("skipping on not-amd64 not-386; location lists not supported")
        }
@@ -890,9 +882,6 @@ func TestAbstractOriginSanityIssue26237(t *testing.T) {
        if runtime.GOOS == "plan9" {
                t.Skip("skipping on plan9; no DWARF symbol table in executables")
        }
-       if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
-               t.Skip("skipping on solaris, illumos, pending resolution of issue #23168")
-       }
        if wd, err := os.Getwd(); err == nil {
                gopathdir := filepath.Join(wd, "testdata", "issue26237")
                abstractOriginSanity(t, gopathdir, DefaultOpt)
@@ -1758,3 +1747,105 @@ func main() {
                        expected, found)
        }
 }
+
+func TestDictIndex(t *testing.T) {
+       // Check that variables with a parametric type have a dictionary index
+       // attribute and that types that are only referenced through dictionaries
+       // have DIEs.
+       testenv.MustHaveGoBuild(t)
+
+       if runtime.GOOS == "plan9" {
+               t.Skip("skipping on plan9; no DWARF symbol table in executables")
+       }
+       if buildcfg.Experiment.Unified {
+               t.Skip("GOEXPERIMENT=unified does not emit dictionaries yet")
+       }
+       t.Parallel()
+
+       const prog = `
+package main
+
+import "fmt"
+
+type CustomInt int
+
+func testfn[T any](arg T) {
+       var mapvar = make(map[int]T)
+       mapvar[0] = arg
+       fmt.Println(arg, mapvar)
+}
+
+func main() {
+       testfn(CustomInt(3))
+}
+`
+
+       dir := t.TempDir()
+       f := gobuild(t, dir, prog, NoOpt)
+       defer f.Close()
+
+       d, err := f.DWARF()
+       if err != nil {
+               t.Fatalf("error reading DWARF: %v", err)
+       }
+
+       rdr := d.Reader()
+       found := false
+       for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
+               if err != nil {
+                       t.Fatalf("error reading DWARF: %v", err)
+               }
+               name, _ := entry.Val(dwarf.AttrName).(string)
+               if strings.HasPrefix(name, "main.testfn") {
+                       found = true
+                       break
+               }
+       }
+
+       if !found {
+               t.Fatalf("could not find main.testfn")
+       }
+
+       offs := []dwarf.Offset{}
+       for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
+               if err != nil {
+                       t.Fatalf("error reading DWARF: %v", err)
+               }
+               if entry.Tag == 0 {
+                       break
+               }
+               name, _ := entry.Val(dwarf.AttrName).(string)
+               switch name {
+               case "arg", "mapvar":
+                       offs = append(offs, entry.Val(dwarf.AttrType).(dwarf.Offset))
+               }
+       }
+       if len(offs) != 2 {
+               t.Errorf("wrong number of variables found in main.testfn %d", len(offs))
+       }
+       for _, off := range offs {
+               rdr.Seek(off)
+               entry, err := rdr.Next()
+               if err != nil {
+                       t.Fatalf("error reading DWARF: %v", err)
+               }
+               if _, ok := entry.Val(intdwarf.DW_AT_go_dict_index).(int64); !ok {
+                       t.Errorf("could not find DW_AT_go_dict_index attribute offset %#x (%T)", off, entry.Val(intdwarf.DW_AT_go_dict_index))
+               }
+       }
+
+       rdr.Seek(0)
+       ex := examiner{}
+       if err := ex.populate(rdr); err != nil {
+               t.Fatalf("error reading DWARF: %v", err)
+       }
+       for _, typeName := range []string{"main.CustomInt", "map[int]main.CustomInt"} {
+               dies := ex.Named(typeName)
+               if len(dies) != 1 {
+                       t.Errorf("wanted 1 DIE named %s, found %v", typeName, len(dies))
+               }
+               if dies[0].Val(intdwarf.DW_AT_go_runtime_type).(uint64) == 0 {
+                       t.Errorf("type %s does not have DW_AT_go_runtime_type", typeName)
+               }
+       }
+}
index 81011638bc5fae6b52cf2898d2849dced105c74d..fb75c761a14cbc68dee095ba51d34c776821357c 100644 (file)
@@ -16,6 +16,7 @@ import (
        "fmt"
        "internal/buildcfg"
        "path/filepath"
+       "runtime"
        "sort"
        "strings"
 )
@@ -480,10 +481,6 @@ func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag elf.DynTag, val
        }
 }
 
-func elfwritedynentsym(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
-       Elfwritedynentsymplus(ctxt, s, tag, t, 0)
-}
-
 func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym, add int64) {
        if elf64 {
                s.AddUint64(ctxt.Arch, uint64(tag))
@@ -1472,24 +1469,24 @@ func (ctxt *Link) doelf() {
                /*
                 * .dynamic table
                 */
-               elfwritedynentsym(ctxt, dynamic, elf.DT_HASH, hash.Sym())
+               elfWriteDynEntSym(ctxt, dynamic, elf.DT_HASH, hash.Sym())
 
-               elfwritedynentsym(ctxt, dynamic, elf.DT_SYMTAB, dynsym.Sym())
+               elfWriteDynEntSym(ctxt, dynamic, elf.DT_SYMTAB, dynsym.Sym())
                if elf64 {
                        Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF64SYMSIZE)
                } else {
                        Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF32SYMSIZE)
                }
-               elfwritedynentsym(ctxt, dynamic, elf.DT_STRTAB, dynstr.Sym())
+               elfWriteDynEntSym(ctxt, dynamic, elf.DT_STRTAB, dynstr.Sym())
                elfwritedynentsymsize(ctxt, dynamic, elf.DT_STRSZ, dynstr.Sym())
                if elfRelType == ".rela" {
                        rela := ldr.LookupOrCreateSym(".rela", 0)
-                       elfwritedynentsym(ctxt, dynamic, elf.DT_RELA, rela)
+                       elfWriteDynEntSym(ctxt, dynamic, elf.DT_RELA, rela)
                        elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELASZ, rela)
                        Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELAENT, ELF64RELASIZE)
                } else {
                        rel := ldr.LookupOrCreateSym(".rel", 0)
-                       elfwritedynentsym(ctxt, dynamic, elf.DT_REL, rel)
+                       elfWriteDynEntSym(ctxt, dynamic, elf.DT_REL, rel)
                        elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELSZ, rel)
                        Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELENT, ELF32RELSIZE)
                }
@@ -1499,9 +1496,9 @@ func (ctxt *Link) doelf() {
                }
 
                if ctxt.IsPPC64() {
-                       elfwritedynentsym(ctxt, dynamic, elf.DT_PLTGOT, plt.Sym())
+                       elfWriteDynEntSym(ctxt, dynamic, elf.DT_PLTGOT, plt.Sym())
                } else {
-                       elfwritedynentsym(ctxt, dynamic, elf.DT_PLTGOT, gotplt.Sym())
+                       elfWriteDynEntSym(ctxt, dynamic, elf.DT_PLTGOT, gotplt.Sym())
                }
 
                if ctxt.IsPPC64() {
@@ -1749,7 +1746,7 @@ func asmbElf(ctxt *Link) {
                sh.Flags = uint64(elf.SHF_ALLOC)
                sh.Addralign = 1
 
-               if interpreter == "" && buildcfg.GO_LDSO != "" {
+               if interpreter == "" && buildcfg.GOOS == runtime.GOOS && buildcfg.GOARCH == runtime.GOARCH && buildcfg.GO_LDSO != "" {
                        interpreter = buildcfg.GO_LDSO
                }
 
@@ -2028,6 +2025,11 @@ func asmbElf(ctxt *Link) {
                ph := newElfPhdr()
                ph.Type = elf.PT_SUNWSTACK
                ph.Flags = elf.PF_W + elf.PF_R
+       } else if ctxt.HeadType == objabi.Hfreebsd {
+               ph := newElfPhdr()
+               ph.Type = elf.PT_GNU_STACK
+               ph.Flags = elf.PF_W + elf.PF_R
+               ph.Align = uint64(ctxt.Arch.RegSize)
        }
 
 elfobj:
index 3702a4d08f586f3674da2f083cbdc493a939586c..2d5a7add9d22d146660763eacf891d31151c4c3e 100644 (file)
@@ -5,6 +5,7 @@
 package ld
 
 import (
+       "bytes"
        "debug/pe"
        "fmt"
        "internal/testenv"
@@ -154,13 +155,22 @@ func TestLargeTextSectionSplitting(t *testing.T) {
        // is arbitrary; we just need something sufficiently large that uses
        // external linking.
        exe := filepath.Join(dir, "go.exe")
-       out, eerr := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "-ldflags=-linkmode=external -debugtextsize=1048576", "cmd/go").CombinedOutput()
-       if eerr != nil {
-               t.Fatalf("build failure: %s\n%s\n", eerr, string(out))
+       out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "-ldflags=-linkmode=external -debugtextsize=1048576", "cmd/go").CombinedOutput()
+       if err != nil {
+               t.Fatalf("build failure: %s\n%s\n", err, string(out))
+       }
+
+       // Check that we did split text sections.
+       out, err = exec.Command(testenv.GoToolPath(t), "tool", "nm", exe).CombinedOutput()
+       if err != nil {
+               t.Fatalf("nm failure: %s\n%s\n", err, string(out))
+       }
+       if !bytes.Contains(out, []byte("runtime.text.1")) {
+               t.Errorf("runtime.text.1 not found, text section not split?")
        }
 
        // Result should be runnable.
-       _, err := exec.Command(exe, "version").CombinedOutput()
+       _, err = exec.Command(exe, "version").CombinedOutput()
        if err != nil {
                t.Fatal(err)
        }
index d7e408669e7921900e7f2496a7b9f1e1b830eb67..4aca36db9866d97ffc8a92195c85f8fd8cdff58d 100644 (file)
@@ -144,21 +144,14 @@ func (ctxt *Link) setArchSyms() {
        ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
        ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
        ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
-       ctxt.mkArchSym("runtime.unreachableMethod", sym.SymVerABIInternal, &ctxt.unreachableMethod)
+       ctxt.mkArchSym("runtime.unreachableMethod", abiInternalVer, &ctxt.unreachableMethod)
 
        if ctxt.IsPPC64() {
                ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
 
-               // NB: note the +2 below for DotTOC2 compared to the +1 for
-               // DocTOC. This is because loadlibfull() creates an additional
-               // syms version during conversion of loader.Sym symbols to
-               // *sym.Symbol symbols. Symbols that are assigned this final
-               // version are not going to have TOC references, so it should
-               // be ok for them to inherit an invalid .TOC. symbol.
-               // TODO: revisit the +2, now that loadlibfull is gone.
-               ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+2)
+               ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1)
                for i := 0; i <= ctxt.MaxVersion(); i++ {
-                       if i >= 2 && i < sym.SymVerStatic { // these versions are not used currently
+                       if i >= sym.SymVerABICount && i < sym.SymVerStatic { // these versions are not used currently
                                continue
                        }
                        ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC)
@@ -288,6 +281,10 @@ const (
        MINFUNC = 16 // minimum size for a function
 )
 
+// Symbol version of ABIInternal symbols. It is sym.SymVerABIInternal if ABI wrappers
+// are used, 0 otherwise.
+var abiInternalVer = sym.SymVerABIInternal
+
 // DynlinkingGo reports whether we are producing Go code that can live
 // in separate shared libraries linked together at runtime.
 func (ctxt *Link) DynlinkingGo() bool {
@@ -323,7 +320,7 @@ var (
        HEADR   int32
 
        nerrors  int
-       liveness int64
+       liveness int64 // size of liveness data (funcdata), printed if -v
 
        // See -strictdups command line flag.
        checkStrictDups   int // 0=off 1=warning 2=error
@@ -388,6 +385,9 @@ func libinit(ctxt *Link) {
        } else if *flagMsan {
                suffixsep = "_"
                suffix = "msan"
+       } else if *flagAsan {
+               suffixsep = "_"
+               suffix = "asan"
        }
 
        Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
@@ -464,23 +464,24 @@ func loadinternal(ctxt *Link, name string) *sym.Library {
 }
 
 // extld returns the current external linker.
-func (ctxt *Link) extld() string {
-       if *flagExtld == "" {
-               *flagExtld = "gcc"
+func (ctxt *Link) extld() []string {
+       if len(flagExtld) == 0 {
+               flagExtld = []string{"gcc"}
        }
-       return *flagExtld
+       return flagExtld
 }
 
 // findLibPathCmd uses cmd command to find gcc library libname.
 // It returns library full path if found, or "none" if not found.
 func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
        extld := ctxt.extld()
-       args := hostlinkArchArgs(ctxt.Arch)
+       name, args := extld[0], extld[1:]
+       args = append(args, hostlinkArchArgs(ctxt.Arch)...)
        args = append(args, cmd)
        if ctxt.Debugvlog != 0 {
                ctxt.Logf("%s %v\n", extld, args)
        }
-       out, err := exec.Command(extld, args...).Output()
+       out, err := exec.Command(name, args...).Output()
        if err != nil {
                if ctxt.Debugvlog != 0 {
                        ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
@@ -506,10 +507,6 @@ func (ctxt *Link) loadlib() {
        default:
                log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
        }
-       if !buildcfg.Experiment.RegabiWrappers {
-               // Use ABI aliases if ABI wrappers are not used.
-               flags |= loader.FlagUseABIAlias
-       }
        elfsetstring1 := func(str string, off int) { elfsetstring(ctxt, 0, str, off) }
        ctxt.loader = loader.NewLoader(flags, elfsetstring1, &ctxt.ErrorReporter.ErrorReporter)
        ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
@@ -535,6 +532,9 @@ func (ctxt *Link) loadlib() {
        if *flagMsan {
                loadinternal(ctxt, "runtime/msan")
        }
+       if *flagAsan {
+               loadinternal(ctxt, "runtime/asan")
+       }
        loadinternal(ctxt, "runtime")
        for ; i < len(ctxt.Library); i++ {
                lib := ctxt.Library[i]
@@ -697,7 +697,9 @@ func (ctxt *Link) linksetup() {
                Peinit(ctxt)
        }
 
-       if ctxt.HeadType == objabi.Hdarwin && ctxt.LinkMode == LinkExternal {
+       if ctxt.LinkMode == LinkExternal {
+               // When external linking, we are creating an object file. The
+               // absolute address is irrelevant.
                *FlagTextAddr = 0
        }
 
@@ -773,7 +775,7 @@ func (ctxt *Link) linksetup() {
                // Set runtime.disableMemoryProfiling bool if
                // runtime.MemProfile is not retained in the binary after
                // deadcode (and we're not dynamically linking).
-               memProfile := ctxt.loader.Lookup("runtime.MemProfile", sym.SymVerABIInternal)
+               memProfile := ctxt.loader.Lookup("runtime.MemProfile", abiInternalVer)
                if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
                        memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
                        sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
@@ -1020,6 +1022,7 @@ var internalpkg = []string{
        "runtime/cgo",
        "runtime/race",
        "runtime/msan",
+       "runtime/asan",
 }
 
 func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType objabi.HeadType, f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
@@ -1241,7 +1244,7 @@ func (ctxt *Link) hostlink() {
        }
 
        var argv []string
-       argv = append(argv, ctxt.extld())
+       argv = append(argv, ctxt.extld()...)
        argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
 
        if *FlagS || debug_s {
@@ -1402,7 +1405,9 @@ func (ctxt *Link) hostlink() {
                        // If gold is not installed, gcc will silently switch
                        // back to ld.bfd. So we parse the version information
                        // and provide a useful error if gold is missing.
-                       cmd := exec.Command(*flagExtld, "-fuse-ld=gold", "-Wl,--version")
+                       name, args := flagExtld[0], flagExtld[1:]
+                       args = append(args, "-fuse-ld=gold", "-Wl,--version")
+                       cmd := exec.Command(name, args...)
                        if out, err := cmd.CombinedOutput(); err == nil {
                                if !bytes.Contains(out, []byte("GNU gold")) {
                                        log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out)
@@ -1415,7 +1420,9 @@ func (ctxt *Link) hostlink() {
                altLinker = "bfd"
 
                // Provide a useful error if ld.bfd is missing.
-               cmd := exec.Command(*flagExtld, "-fuse-ld=bfd", "-Wl,--version")
+               name, args := flagExtld[0], flagExtld[1:]
+               args = append(args, "-fuse-ld=bfd", "-Wl,--version")
+               cmd := exec.Command(name, args...)
                if out, err := cmd.CombinedOutput(); err == nil {
                        if !bytes.Contains(out, []byte("GNU ld")) {
                                log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
@@ -1483,10 +1490,11 @@ func (ctxt *Link) hostlink() {
                argv = append(argv, "/lib/crt0_64.o")
 
                extld := ctxt.extld()
+               name, args := extld[0], extld[1:]
                // Get starting files.
                getPathFile := func(file string) string {
-                       args := []string{"-maix64", "--print-file-name=" + file}
-                       out, err := exec.Command(extld, args...).CombinedOutput()
+                       args := append(args, "-maix64", "--print-file-name="+file)
+                       out, err := exec.Command(name, args...).CombinedOutput()
                        if err != nil {
                                log.Fatalf("running %s failed: %v\n%s", extld, err, out)
                        }
@@ -1568,14 +1576,18 @@ func (ctxt *Link) hostlink() {
                }
        }
 
-       for _, p := range strings.Fields(*flagExtldflags) {
+       for _, p := range flagExtldflags {
                argv = append(argv, p)
                checkStatic(p)
        }
        if ctxt.HeadType == objabi.Hwindows {
                // Determine which linker we're using. Add in the extldflags in
                // case used has specified "-fuse-ld=...".
-               cmd := exec.Command(*flagExtld, *flagExtldflags, "-Wl,--version")
+               extld := ctxt.extld()
+               name, args := extld[0], extld[1:]
+               args = append(args, flagExtldflags...)
+               args = append(args, "-Wl,--version")
+               cmd := exec.Command(name, args...)
                usingLLD := false
                if out, err := cmd.CombinedOutput(); err == nil {
                        if bytes.Contains(out, []byte("LLD ")) {
@@ -1640,13 +1652,31 @@ func (ctxt *Link) hostlink() {
        }
 
        if combineDwarf {
+               // Find "dsymutils" and "strip" tools using CC --print-prog-name.
+               var cc []string
+               cc = append(cc, ctxt.extld()...)
+               cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
+               cc = append(cc, "--print-prog-name", "dsymutil")
+               out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
+               if err != nil {
+                       Exitf("%s: finding dsymutil failed: %v\n%s", os.Args[0], err, out)
+               }
+               dsymutilCmd := strings.TrimSuffix(string(out), "\n")
+
+               cc[len(cc)-1] = "strip"
+               out, err = exec.Command(cc[0], cc[1:]...).CombinedOutput()
+               if err != nil {
+                       Exitf("%s: finding strip failed: %v\n%s", os.Args[0], err, out)
+               }
+               stripCmd := strings.TrimSuffix(string(out), "\n")
+
                dsym := filepath.Join(*flagTmpdir, "go.dwarf")
-               if out, err := exec.Command("xcrun", "dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
+               if out, err := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
                        Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
                }
                // Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
                // They contain temporary file paths and make the build not reproducible.
-               if out, err := exec.Command("xcrun", "strip", "-S", *flagOutfile).CombinedOutput(); err != nil {
+               if out, err := exec.Command(stripCmd, "-S", *flagOutfile).CombinedOutput(); err != nil {
                        Exitf("%s: running strip failed: %v\n%s", os.Args[0], err, out)
                }
                // Skip combining if `dsymutil` didn't generate a file. See #11994.
@@ -1719,8 +1749,7 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
        flags := hostlinkArchArgs(arch)
        keep := false
        skip := false
-       extldflags := strings.Fields(*flagExtldflags)
-       for _, f := range append(extldflags, ldflag...) {
+       for _, f := range append(flagExtldflags, ldflag...) {
                if keep {
                        flags = append(flags, f)
                        keep = false
@@ -2112,7 +2141,7 @@ func ldshlibsyms(ctxt *Link, shlib string) {
                ver := 0
                symname := elfsym.Name // (unmangled) symbol name
                if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type.") {
-                       ver = sym.SymVerABIInternal
+                       ver = abiInternalVer
                } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
                        // Demangle the ABI name. Keep in sync with symtab.go:mangleABIName.
                        if strings.HasSuffix(elfsym.Name, ".abiinternal") {
@@ -2153,19 +2182,6 @@ func ldshlibsyms(ctxt *Link, shlib string) {
                if symname != elfsym.Name {
                        l.SetSymExtname(s, elfsym.Name)
                }
-
-               // For function symbols, if ABI wrappers are not used, we don't
-               // know what ABI is available, so alias it under both ABIs.
-               if !buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
-                       alias := ctxt.loader.LookupOrCreateSym(symname, sym.SymVerABIInternal)
-                       if l.SymType(alias) != 0 {
-                               continue
-                       }
-                       su := l.MakeSymbolUpdater(alias)
-                       su.SetType(sym.SABIALIAS)
-                       r, _ := su.AddRel(0) // type doesn't matter
-                       r.SetSym(s)
-               }
        }
        ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
 }
@@ -2320,7 +2336,7 @@ func (sc *stkChk) check(up *chain, depth int) int {
        var ch1 chain
        pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
        ri := 0
-       for pcsp.Init(ldr.Data(info.Pcsp())); !pcsp.Done; pcsp.Next() {
+       for pcsp.Init(ldr.Data(ldr.Pcsp(s))); !pcsp.Done; pcsp.Next() {
                // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
 
                // Check stack size in effect for this span.
@@ -2481,7 +2497,7 @@ func (ctxt *Link) callgraph() {
                        if rs == 0 {
                                continue
                        }
-                       if r.Type().IsDirectCall() && (ldr.SymType(rs) == sym.STEXT || ldr.SymType(rs) == sym.SABIALIAS) {
+                       if r.Type().IsDirectCall() && ldr.SymType(rs) == sym.STEXT {
                                ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
                        }
                }
index 13618beff977a5a5aef902edd354bf6a644d7660..64d18bd62c0752ec012160f7a818d5a987d4af5f 100644 (file)
@@ -148,12 +148,18 @@ func (ctxt *Link) MaxVersion() int {
 }
 
 // generatorFunc is a convenience type.
-// Linker created symbols that are large, and shouldn't really live in the
-// heap can define a generator function, and their bytes can be generated
+// Some linker-created Symbols are large and shouldn't really live in the heap.
+// Such Symbols can define a generator function. Their bytes can be generated
 // directly in the output mmap.
 //
-// Generator symbols shouldn't grow the symbol size, and might be called in
-// parallel in the future.
+// Relocations are applied prior to emitting generator Symbol contents.
+// Generator Symbols that require relocations can be written in two passes.
+// The first pass, at Symbol creation time, adds only relocations.
+// The second pass, at content generation time, adds the rest.
+// See generateFunctab for an example.
+//
+// Generator functions shouldn't grow the Symbol size.
+// Generator functions must be safe for concurrent use.
 //
 // Generator Symbols have their Data set to the mmapped area when the
 // generator is called.
index 45a3971c33f5463ffc52094baedde2aa5e40696e..8633222ee332fbd9cb717a49acff6af2c15bb2cf 100644 (file)
@@ -7,7 +7,6 @@ package ld
 import (
        "bytes"
        "cmd/internal/codesign"
-       "cmd/internal/obj"
        "cmd/internal/objabi"
        "cmd/internal/sys"
        "cmd/link/internal/loader"
@@ -561,7 +560,7 @@ func (ctxt *Link) domacho() {
                        ver := 0
                        // _cgo_panic is a Go function, so it uses ABIInternal.
                        if name == "_cgo_panic" {
-                               ver = sym.ABIToVersion(obj.ABIInternal)
+                               ver = abiInternalVer
                        }
                        s := ctxt.loader.Lookup(name, ver)
                        if s != 0 {
@@ -898,6 +897,14 @@ func collectmachosyms(ctxt *Link) {
                if ldr.SymType(s) == sym.STEXT {
                        addsym(s)
                }
+               for n := range Segtext.Sections[1:] {
+                       s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
+                       if s != 0 {
+                               addsym(s)
+                       } else {
+                               break
+                       }
+               }
                s = ldr.Lookup("runtime.etext", 0)
                if ldr.SymType(s) == sym.STEXT {
                        addsym(s)
index cba0e3d81feaea6fafcba964c200b50d96e6d714..a1d86965e434bb99f6eb1e68522debd3fd07f0c1 100644 (file)
@@ -34,6 +34,7 @@ import (
        "bufio"
        "cmd/internal/goobj"
        "cmd/internal/objabi"
+       "cmd/internal/quoted"
        "cmd/internal/sys"
        "cmd/link/internal/benchmark"
        "flag"
@@ -53,6 +54,8 @@ var (
 
 func init() {
        flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
+       flag.Var(&flagExtld, "extld", "use `linker` when linking in external mode")
+       flag.Var(&flagExtldflags, "extldflags", "pass `flags` to external linker")
 }
 
 // Flags used by the linker. The exported flags are used by the architecture-specific packages.
@@ -66,14 +69,15 @@ var (
        flagDumpDep       = flag.Bool("dumpdep", false, "dump symbol dependency graph")
        flagRace          = flag.Bool("race", false, "enable race detector")
        flagMsan          = flag.Bool("msan", false, "enable MSan interface")
+       flagAsan          = flag.Bool("asan", false, "enable ASan interface")
        flagAslr          = flag.Bool("aslr", true, "enable ASLR for buildmode=c-shared on windows")
 
        flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
        flagLibGCC     = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
        flagTmpdir     = flag.String("tmpdir", "", "use `directory` for temporary files")
 
-       flagExtld      = flag.String("extld", "", "use `linker` when linking in external mode")
-       flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
+       flagExtld      quoted.Flag
+       flagExtldflags quoted.Flag
        flagExtar      = flag.String("extar", "", "archive program for buildmode=c-archive")
 
        flagA             = flag.Bool("a", false, "no-op (deprecated)")
@@ -170,6 +174,10 @@ func Main(arch *sys.Arch, theArch Arch) {
 
        checkStrictDups = *FlagStrictDups
 
+       if !buildcfg.Experiment.RegabiWrappers {
+               abiInternalVer = 0
+       }
+
        startProfile()
        if ctxt.BuildMode == BuildModeUnset {
                ctxt.BuildMode.Set("exe")
index 9444b6567e8b723b03560154e1271f65ae3c4907..b1ee3c56282d347111cfdf8afe33ea86780425c3 100644 (file)
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build darwin && go1.12
+// +build darwin,go1.12
+
 package ld
 
 import (
@@ -9,6 +12,10 @@ import (
        "unsafe"
 )
 
+// Implemented in the syscall package.
+//go:linkname fcntl syscall.fcntl
+func fcntl(fd int, cmd int, arg int) (int, error)
+
 func (out *OutBuf) fallocate(size uint64) error {
        stat, err := out.f.Stat()
        if err != nil {
@@ -29,12 +36,8 @@ func (out *OutBuf) fallocate(size uint64) error {
                Length:  int64(size - cursize),
        }
 
-       _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
-       if errno != 0 {
-               return errno
-       }
-
-       return nil
+       _, err = fcntl(int(out.f.Fd()), syscall.F_PREALLOCATE, int(uintptr(unsafe.Pointer(store))))
+       return err
 }
 
 func (out *OutBuf) purgeSignatureCache() {
index 6564bd54a3d1bcf27977493fedff76c829c34d0d..3bffe4543dd9bda905292e365cfda72b7113249c 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !darwin && !linux
-// +build !darwin,!linux
+//go:build (!darwin && !linux) || (darwin && !go1.12)
+// +build !darwin,!linux darwin,!go1.12
 
 package ld
 
index f9caa413e3c3c198a906d362e2a0e4aa7e5d8b99..85e64421a30f48064e54b581a8181871eafb79c2 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !darwin
-// +build !darwin
+//go:build !darwin || (darwin && !go1.12)
+// +build !darwin darwin,!go1.12
 
 package ld
 
index 70e3e1284b9a1ac621741d2c6f843511257fc126..b57e212794625735471f74af83baddeefc8da0f3 100644 (file)
@@ -14,13 +14,13 @@ import (
        "internal/buildcfg"
        "os"
        "path/filepath"
+       "strings"
 )
 
+const funcSize = 10 * 4 // funcSize is the size of the _func object in runtime/runtime2.go
+
 // pclntab holds the state needed for pclntab generation.
 type pclntab struct {
-       // The size of the func object in the runtime.
-       funcSize uint32
-
        // The first and last functions found.
        firstFunc, lastFunc loader.Sym
 
@@ -51,7 +51,7 @@ type pclntab struct {
 }
 
 // addGeneratedSym adds a generator symbol to pclntab, returning the new Sym.
-// It is the caller's responsibility to save they symbol in state.
+// It is the caller's responsibility to save the symbol in state.
 func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f generatorFunc) loader.Sym {
        size = Rnd(size, int64(ctxt.Arch.PtrSize))
        state.size += size
@@ -68,15 +68,10 @@ func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f gen
 // generate pclntab.
 func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.CompilationUnit, []loader.Sym) {
        ldr := ctxt.loader
-
-       state := &pclntab{
-               // This is the size of the _func object in runtime/runtime2.go.
-               funcSize: uint32(ctxt.Arch.PtrSize + 9*4),
-       }
+       state := new(pclntab)
 
        // Gather some basic stats and info.
        seenCUs := make(map[*sym.CompilationUnit]struct{})
-       prevSect := ldr.SymSect(ctxt.Textp[0])
        compUnits := []*sym.CompilationUnit{}
        funcs := []loader.Sym{}
 
@@ -90,16 +85,6 @@ func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.Compilat
                        state.firstFunc = s
                }
                state.lastFunc = s
-               ss := ldr.SymSect(s)
-               if ss != prevSect {
-                       // With multiple text sections, the external linker may
-                       // insert functions between the sections, which are not
-                       // known by Go. This leaves holes in the PC range covered
-                       // by the func table. We need to generate an entry to mark
-                       // the hole.
-                       state.nfunc++
-                       prevSect = ss
-               }
 
                // We need to keep track of all compilation units we see. Some symbols
                // (eg, go.buildid, _cgoexp_, etc) won't have a compilation unit.
@@ -147,13 +132,8 @@ func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
                                switch target.Arch.Family {
                                case sys.AMD64, sys.I386:
                                        deferreturn--
-                               case sys.PPC64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
+                               case sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64:
                                        // no change
-                               case sys.RISCV64:
-                                       // TODO(jsing): The JALR instruction is marked with
-                                       // R_CALLRISCV, whereas the actual reloc is currently
-                                       // one instruction earlier starting with the AUIPC.
-                                       deferreturn -= 4
                                case sys.S390X:
                                        deferreturn -= 2
                                default:
@@ -178,6 +158,7 @@ func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch
        // eventually switch the type back to SRODATA.
        inlTreeSym.SetType(sym.SGOFUNC)
        ldr.SetAttrReachable(its, true)
+       ldr.SetSymAlign(its, 4) // it has 32-bit fields
        ninl := fi.NumInlTree()
        for i := 0; i < int(ninl); i++ {
                call := fi.InlTree(i)
@@ -224,8 +205,10 @@ func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint
 // generatePCHeader creates the runtime.pcheader symbol, setting it up as a
 // generator to fill in its data later.
 func (state *pclntab) generatePCHeader(ctxt *Link) {
+       ldr := ctxt.loader
+       textStartOff := int64(8 + 2*ctxt.Arch.PtrSize)
+       size := int64(8 + 8*ctxt.Arch.PtrSize)
        writeHeader := func(ctxt *Link, s loader.Sym) {
-               ldr := ctxt.loader
                header := ctxt.loader.MakeSymbolUpdater(s)
 
                writeSymOffset := func(off int64, ws loader.Sym) int64 {
@@ -238,21 +221,30 @@ func (state *pclntab) generatePCHeader(ctxt *Link) {
                }
 
                // Write header.
-               // Keep in sync with runtime/symtab.go:pcHeader.
-               header.SetUint32(ctxt.Arch, 0, 0xfffffffa)
+               // Keep in sync with runtime/symtab.go:pcHeader and package debug/gosym.
+               header.SetUint32(ctxt.Arch, 0, 0xfffffff0)
                header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
                header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
                off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
                off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles))
+               if off != textStartOff {
+                       panic(fmt.Sprintf("pcHeader textStartOff: %d != %d", off, textStartOff))
+               }
+               off += int64(ctxt.Arch.PtrSize) // skip runtimeText relocation
                off = writeSymOffset(off, state.funcnametab)
                off = writeSymOffset(off, state.cutab)
                off = writeSymOffset(off, state.filetab)
                off = writeSymOffset(off, state.pctab)
                off = writeSymOffset(off, state.pclntab)
+               if off != size {
+                       panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
+               }
        }
 
-       size := int64(8 + 7*ctxt.Arch.PtrSize)
        state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
+       // Create the runtimeText relocation.
+       sb := ldr.MakeSymbolUpdater(state.pcheader)
+       sb.SetAddr(ctxt.Arch, textStartOff, ldr.Lookup("runtime.text", 0))
 }
 
 // walkFuncs iterates over the funcs, calling a function for each unique
@@ -286,11 +278,35 @@ func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
 func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
        nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
 
+       // The name used by the runtime is the concatenation of the 3 returned strings.
+       // For regular functions, only one returned string is nonempty.
+       // For generic functions, we use three parts so that we can print everything
+       // within the outermost "[]" as "...".
+       nameParts := func(name string) (string, string, string) {
+               i := strings.IndexByte(name, '[')
+               if i < 0 {
+                       return name, "", ""
+               }
+               // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
+               j := len(name) - 1
+               for j > i && name[j] != ']' {
+                       j--
+               }
+               if j <= i {
+                       return name, "", ""
+               }
+               return name[:i], "[...]", name[j+1:]
+       }
+
        // Write the null terminated strings.
        writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
                symtab := ctxt.loader.MakeSymbolUpdater(s)
                for s, off := range nameOffsets {
-                       symtab.AddStringAt(int64(off), ctxt.loader.SymName(s))
+                       a, b, c := nameParts(ctxt.loader.SymName(s))
+                       o := int64(off)
+                       o = symtab.AddStringAt(o, a)
+                       o = symtab.AddStringAt(o, b)
+                       _ = symtab.AddCStringAt(o, c)
                }
        }
 
@@ -298,7 +314,8 @@ func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[lo
        var size int64
        walkFuncs(ctxt, funcs, func(s loader.Sym) {
                nameOffsets[s] = uint32(size)
-               size += int64(ctxt.loader.SymNameLen(s)) + 1 // NULL terminate
+               a, b, c := nameParts(ctxt.loader.SymName(s))
+               size += int64(len(a) + len(b) + len(c) + 1) // NULL terminate
        })
 
        state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
@@ -459,22 +476,25 @@ func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
                        seen[pcSym] = struct{}{}
                }
        }
+       var pcsp, pcline, pcfile, pcinline loader.Sym
+       var pcdata []loader.Sym
        for _, s := range funcs {
                fi := ldr.FuncInfo(s)
                if !fi.Valid() {
                        continue
                }
                fi.Preload()
+               pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
 
-               pcSyms := []loader.Sym{fi.Pcsp(), fi.Pcfile(), fi.Pcline()}
+               pcSyms := []loader.Sym{pcsp, pcfile, pcline}
                for _, pcSym := range pcSyms {
                        saveOffset(pcSym)
                }
-               for _, pcSym := range fi.Pcdata() {
+               for _, pcSym := range pcdata {
                        saveOffset(pcSym)
                }
                if fi.NumInlTree() > 0 {
-                       saveOffset(fi.Pcinline())
+                       saveOffset(pcinline)
                }
        }
 
@@ -495,11 +515,11 @@ func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
 
 // numPCData returns the number of PCData syms for the FuncInfo.
 // NB: Preload must be called on valid FuncInfos before calling this function.
-func numPCData(fi loader.FuncInfo) uint32 {
+func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 {
        if !fi.Valid() {
                return 0
        }
-       numPCData := uint32(len(fi.Pcdata()))
+       numPCData := uint32(ldr.NumPcdata(s))
        if fi.NumInlTree() > 0 {
                if numPCData < objabi.PCDATA_InlTreeIndex+1 {
                        numPCData = objabi.PCDATA_InlTreeIndex + 1
@@ -508,119 +528,44 @@ func numPCData(fi loader.FuncInfo) uint32 {
        return numPCData
 }
 
-// Helper types for iterating pclntab.
-type pclnSetAddr func(*loader.SymbolBuilder, *sys.Arch, int64, loader.Sym, int64) int64
-type pclnSetUint func(*loader.SymbolBuilder, *sys.Arch, int64, uint64) int64
-
 // generateFunctab creates the runtime.functab
 //
 // runtime.functab contains two things:
 //
 //   - pc->func look up table.
 //   - array of func objects, interleaved with pcdata and funcdata
-//
-// Because of timing in the linker, generating this table takes two passes.
-// The first pass is executed early in the link, and it creates any needed
-// relocations to layout the data. The pieces that need relocations are:
-//   1) the PC->func table.
-//   2) The entry points in the func objects.
-//   3) The funcdata.
-// (1) and (2) are handled in walkPCToFunc. (3) is handled in walkFuncdata.
-//
-// After relocations, once we know where to write things in the output buffer,
-// we execute the second pass, which is actually writing the data.
 func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
        // Calculate the size of the table.
        size, startLocations := state.calculateFunctabSize(ctxt, funcs)
-
-       // If we are internally linking a static executable, the function addresses
-       // are known, so we can just use them instead of emitting relocations. For
-       // other cases we still need to emit relocations.
-       //
-       // This boolean just helps us figure out which callback to use.
-       useSymValue := ctxt.IsExe() && ctxt.IsInternal()
-
        writePcln := func(ctxt *Link, s loader.Sym) {
                ldr := ctxt.loader
                sb := ldr.MakeSymbolUpdater(s)
-
-               // Create our callbacks.
-               var setAddr pclnSetAddr
-               if useSymValue {
-                       // We need to write the offset.
-                       setAddr = func(s *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 {
-                               if v := ldr.SymValue(tgt); v != 0 {
-                                       s.SetUint(arch, off, uint64(v+add))
-                               }
-                               return 0
-                       }
-               } else {
-                       // We already wrote relocations.
-                       setAddr = func(s *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 { return 0 }
-               }
-
                // Write the data.
-               writePcToFunc(ctxt, sb, funcs, startLocations, setAddr, (*loader.SymbolBuilder).SetUint)
+               writePCToFunc(ctxt, sb, funcs, startLocations)
                writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
-               state.writeFuncData(ctxt, sb, funcs, inlSyms, startLocations, setAddr, (*loader.SymbolBuilder).SetUint)
        }
-
        state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
-
-       // Create the relocations we need.
-       ldr := ctxt.loader
-       sb := ldr.MakeSymbolUpdater(state.pclntab)
-
-       var setAddr pclnSetAddr
-       if useSymValue {
-               // If we should use the symbol value, and we don't have one, write a relocation.
-               setAddr = func(sb *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 {
-                       if v := ldr.SymValue(tgt); v == 0 {
-                               sb.SetAddrPlus(arch, off, tgt, add)
-                       }
-                       return 0
-               }
-       } else {
-               // If we're externally linking, write a relocation.
-               setAddr = (*loader.SymbolBuilder).SetAddrPlus
-       }
-       setUintNOP := func(*loader.SymbolBuilder, *sys.Arch, int64, uint64) int64 { return 0 }
-       writePcToFunc(ctxt, sb, funcs, startLocations, setAddr, setUintNOP)
-       if !useSymValue {
-               // Generate relocations for funcdata when externally linking.
-               state.writeFuncData(ctxt, sb, funcs, inlSyms, startLocations, setAddr, setUintNOP)
-               sb.SortRelocs()
-       }
 }
 
 // funcData returns the funcdata and offsets for the FuncInfo.
-// The funcdata and offsets are written into runtime.functab after each func
+// The funcdata are written into runtime.functab after each func
 // object. This is a helper function to make querying the FuncInfo object
 // cleaner.
 //
-// Note, the majority of fdOffsets are 0, meaning there is no offset between
-// the compiler's generated symbol, and what the runtime needs. They are
-// plumbed through for no loss of generality.
-//
 // NB: Preload must be called on the FuncInfo before calling.
-// NB: fdSyms and fdOffs are used as scratch space.
-func funcData(fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym, fdOffs []int64) ([]loader.Sym, []int64) {
-       fdSyms, fdOffs = fdSyms[:0], fdOffs[:0]
+// NB: fdSyms is used as scratch space.
+func funcData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym) []loader.Sym {
+       fdSyms = fdSyms[:0]
        if fi.Valid() {
-               numOffsets := int(fi.NumFuncdataoff())
-               for i := 0; i < numOffsets; i++ {
-                       fdOffs = append(fdOffs, fi.Funcdataoff(i))
-               }
-               fdSyms = fi.Funcdata(fdSyms)
+               fdSyms = ldr.Funcdata(s, fdSyms)
                if fi.NumInlTree() > 0 {
                        if len(fdSyms) < objabi.FUNCDATA_InlTree+1 {
                                fdSyms = append(fdSyms, make([]loader.Sym, objabi.FUNCDATA_InlTree+1-len(fdSyms))...)
-                               fdOffs = append(fdOffs, make([]int64, objabi.FUNCDATA_InlTree+1-len(fdOffs))...)
                        }
                        fdSyms[objabi.FUNCDATA_InlTree] = inlSym
                }
        }
-       return fdSyms, fdOffs
+       return fdSyms
 }
 
 // calculateFunctabSize calculates the size of the pclntab, and the offsets in
@@ -629,137 +574,88 @@ func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64
        ldr := ctxt.loader
        startLocations := make([]uint32, len(funcs))
 
-       // Allocate space for the pc->func table. This structure consists of a pc
+       // Allocate space for the pc->func table. This structure consists of a pc offset
        // and an offset to the func structure. After that, we have a single pc
        // value that marks the end of the last function in the binary.
-       size := int64(int(state.nfunc)*2*ctxt.Arch.PtrSize + ctxt.Arch.PtrSize)
+       size := int64(int(state.nfunc)*2*4 + 4)
 
        // Now find the space for the func objects. We do this in a running manner,
-       // so that we can find individual starting locations, and because funcdata
-       // requires alignment.
+       // so that we can find individual starting locations.
        for i, s := range funcs {
                size = Rnd(size, int64(ctxt.Arch.PtrSize))
                startLocations[i] = uint32(size)
                fi := ldr.FuncInfo(s)
-               size += int64(state.funcSize)
+               size += funcSize
                if fi.Valid() {
                        fi.Preload()
-                       numFuncData := int(fi.NumFuncdataoff())
+                       numFuncData := ldr.NumFuncdata(s)
                        if fi.NumInlTree() > 0 {
                                if numFuncData < objabi.FUNCDATA_InlTree+1 {
                                        numFuncData = objabi.FUNCDATA_InlTree + 1
                                }
                        }
-                       size += int64(numPCData(fi) * 4)
-                       if numFuncData > 0 { // Func data is aligned.
-                               size = Rnd(size, int64(ctxt.Arch.PtrSize))
-                       }
-                       size += int64(numFuncData * ctxt.Arch.PtrSize)
+                       size += int64(numPCData(ldr, s, fi) * 4)
+                       size += int64(numFuncData * 4)
                }
        }
 
        return size, startLocations
 }
 
-// writePcToFunc writes the PC->func lookup table.
-// This function walks the pc->func lookup table, executing callbacks
-// to generate relocations and writing the values for the table.
-func writePcToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32, setAddr pclnSetAddr, setUint pclnSetUint) {
+// writePCToFunc writes the PC->func lookup table.
+func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) {
        ldr := ctxt.loader
-       var prevFunc loader.Sym
-       prevSect := ldr.SymSect(funcs[0])
-       funcIndex := 0
-       for i, s := range funcs {
-               if thisSect := ldr.SymSect(s); thisSect != prevSect {
-                       // With multiple text sections, there may be a hole here in the
-                       // address space. We use an invalid funcoff value to mark the hole.
-                       // See also runtime/symtab.go:findfunc
-                       prevFuncSize := int64(ldr.SymSize(prevFunc))
-                       setAddr(sb, ctxt.Arch, int64(funcIndex*2*ctxt.Arch.PtrSize), prevFunc, prevFuncSize)
-                       setUint(sb, ctxt.Arch, int64((funcIndex*2+1)*ctxt.Arch.PtrSize), ^uint64(0))
-                       funcIndex++
-                       prevSect = thisSect
-               }
-               prevFunc = s
-               // TODO: We don't actually need these relocations, provided we go to a
-               // module->func look-up-table like we do for filenames. We could have a
-               // single relocation for the module, and have them all laid out as
-               // offsets from the beginning of that module.
-               setAddr(sb, ctxt.Arch, int64(funcIndex*2*ctxt.Arch.PtrSize), s, 0)
-               setUint(sb, ctxt.Arch, int64((funcIndex*2+1)*ctxt.Arch.PtrSize), uint64(startLocations[i]))
-               funcIndex++
-
-               // Write the entry location.
-               setAddr(sb, ctxt.Arch, int64(startLocations[i]), s, 0)
+       textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
+       pcOff := func(s loader.Sym) uint32 {
+               off := ldr.SymValue(s) - textStart
+               if off < 0 {
+                       panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
+               }
+               return uint32(off)
        }
-
-       // Final entry of table is just end pc.
-       setAddr(sb, ctxt.Arch, int64(funcIndex)*2*int64(ctxt.Arch.PtrSize), prevFunc, ldr.SymSize(prevFunc))
-}
-
-// writeFuncData writes the funcdata tables.
-//
-// This function executes a callback for each funcdata needed in
-// runtime.functab. It should be called once for internally linked static
-// binaries, or twice (once to generate the needed relocations) for other
-// build modes.
-//
-// Note the output of this function is interwoven with writeFuncs, but this is
-// a separate function, because it's needed in different passes in
-// generateFunctab.
-func (state *pclntab) writeFuncData(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations []uint32, setAddr pclnSetAddr, setUint pclnSetUint) {
-       ldr := ctxt.loader
-       funcdata, funcdataoff := []loader.Sym{}, []int64{}
        for i, s := range funcs {
-               fi := ldr.FuncInfo(s)
-               if !fi.Valid() {
-                       continue
-               }
-               fi.Preload()
-
-               // funcdata, must be pointer-aligned and we're only int32-aligned.
-               // Missing funcdata will be 0 (nil pointer).
-               funcdata, funcdataoff := funcData(fi, inlSyms[s], funcdata, funcdataoff)
-               if len(funcdata) > 0 {
-                       off := int64(startLocations[i] + state.funcSize + numPCData(fi)*4)
-                       off = Rnd(off, int64(ctxt.Arch.PtrSize))
-                       for j := range funcdata {
-                               dataoff := off + int64(ctxt.Arch.PtrSize*j)
-                               if funcdata[j] == 0 {
-                                       setUint(sb, ctxt.Arch, dataoff, uint64(funcdataoff[j]))
-                                       continue
-                               }
-                               // TODO: Does this need deduping?
-                               setAddr(sb, ctxt.Arch, dataoff, funcdata[j], funcdataoff[j])
-                       }
-               }
+               sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s))
+               sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i])
        }
+
+       // Final entry of table is just end pc offset.
+       lastFunc := funcs[len(funcs)-1]
+       sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, pcOff(lastFunc)+uint32(ldr.SymSize(lastFunc)))
 }
 
 // writeFuncs writes the func structures and pcdata to runtime.functab.
 func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
        ldr := ctxt.loader
-       deferReturnSym := ldr.Lookup("runtime.deferreturn", sym.SymVerABIInternal)
-       funcdata, funcdataoff := []loader.Sym{}, []int64{}
+       deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
+       gofunc := ldr.Lookup("go.func.*", 0)
+       gofuncBase := ldr.SymValue(gofunc)
+       textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
+       funcdata := []loader.Sym{}
+       var pcsp, pcfile, pcline, pcinline loader.Sym
+       var pcdata []loader.Sym
 
        // Write the individual func objects.
        for i, s := range funcs {
                fi := ldr.FuncInfo(s)
                if fi.Valid() {
                        fi.Preload()
+                       pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
                }
 
-               // Note we skip the space for the entry value -- that's handled inn
-               // walkPCToFunc. We don't write it here, because it might require a
-               // relocation.
-               off := startLocations[i] + uint32(ctxt.Arch.PtrSize) // entry
+               off := int64(startLocations[i])
+               // entry uintptr (offset of func entry PC from textStart)
+               entryOff := ldr.SymValue(s) - textStart
+               if entryOff < 0 {
+                       panic(fmt.Sprintf("expected func %s(%x) to be placed before or at textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
+               }
+               off = sb.SetUint32(ctxt.Arch, off, uint32(entryOff))
 
                // name int32
                nameoff, ok := nameOffsets[s]
                if !ok {
                        panic("couldn't find function name offset")
                }
-               off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(nameoff)))
+               off = sb.SetUint32(ctxt.Arch, off, uint32(nameoff))
 
                // args int32
                // TODO: Move into funcinfo.
@@ -767,57 +663,75 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
                if fi.Valid() {
                        args = uint32(fi.Args())
                }
-               off = uint32(sb.SetUint32(ctxt.Arch, int64(off), args))
+               off = sb.SetUint32(ctxt.Arch, off, args)
 
                // deferreturn
                deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
-               off = uint32(sb.SetUint32(ctxt.Arch, int64(off), deferreturn))
+               off = sb.SetUint32(ctxt.Arch, off, deferreturn)
 
                // pcdata
                if fi.Valid() {
-                       off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcsp()))))
-                       off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcfile()))))
-                       off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcline()))))
+                       off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcsp)))
+                       off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcfile)))
+                       off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcline)))
                } else {
                        off += 12
                }
-               off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(numPCData(fi))))
+               off = sb.SetUint32(ctxt.Arch, off, uint32(numPCData(ldr, s, fi)))
 
                // Store the offset to compilation unit's file table.
                cuIdx := ^uint32(0)
                if cu := ldr.SymUnit(s); cu != nil {
                        cuIdx = cuOffsets[cu.PclnIndex]
                }
-               off = uint32(sb.SetUint32(ctxt.Arch, int64(off), cuIdx))
+               off = sb.SetUint32(ctxt.Arch, off, cuIdx)
 
                // funcID uint8
                var funcID objabi.FuncID
                if fi.Valid() {
                        funcID = fi.FuncID()
                }
-               off = uint32(sb.SetUint8(ctxt.Arch, int64(off), uint8(funcID)))
+               off = sb.SetUint8(ctxt.Arch, off, uint8(funcID))
 
                // flag uint8
                var flag objabi.FuncFlag
                if fi.Valid() {
                        flag = fi.FuncFlag()
                }
-               off = uint32(sb.SetUint8(ctxt.Arch, int64(off), uint8(flag)))
+               off = sb.SetUint8(ctxt.Arch, off, uint8(flag))
 
                off += 1 // pad
 
                // nfuncdata must be the final entry.
-               funcdata, funcdataoff = funcData(fi, 0, funcdata, funcdataoff)
-               off = uint32(sb.SetUint8(ctxt.Arch, int64(off), uint8(len(funcdata))))
+               funcdata = funcData(ldr, s, fi, 0, funcdata)
+               off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata)))
 
                // Output the pcdata.
                if fi.Valid() {
-                       for j, pcSym := range fi.Pcdata() {
-                               sb.SetUint32(ctxt.Arch, int64(off+uint32(j*4)), uint32(ldr.SymValue(pcSym)))
+                       for j, pcSym := range pcdata {
+                               sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym)))
                        }
                        if fi.NumInlTree() > 0 {
-                               sb.SetUint32(ctxt.Arch, int64(off+objabi.PCDATA_InlTreeIndex*4), uint32(ldr.SymValue(fi.Pcinline())))
+                               sb.SetUint32(ctxt.Arch, off+objabi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline)))
+                       }
+               }
+
+               // Write funcdata refs as offsets from go.func.* and go.funcrel.*.
+               funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
+               // Missing funcdata will be ^0. See runtime/symtab.go:funcdata.
+               off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
+               for j := range funcdata {
+                       dataoff := off + int64(4*j)
+                       fdsym := funcdata[j]
+                       if fdsym == 0 {
+                               sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0)) // ^0 is a sentinel for "no value"
+                               continue
+                       }
+
+                       if outer := ldr.OuterSym(fdsym); outer != gofunc {
+                               panic(fmt.Sprintf("bad carrier sym for symbol %s (funcdata %s#%d), want go.func.* got %s", ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer)))
                        }
+                       sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase))
                }
        }
 }
index 8eb4231c3ab2895f095e2b1197e92d60659eb177..b7d413e9a9eb00a3886fbf39874ed840ee48bea4 100644 (file)
@@ -1061,6 +1061,8 @@ func Peinit(ctxt *Link) {
                // linker will honour that requirement.
                PESECTALIGN = 32
                PEFILEALIGN = 0
+               // We are creating an object file. The absolute address is irrelevant.
+               PEBASE = 0
        }
 
        var sh [16]pe.SectionHeader32
@@ -1512,7 +1514,6 @@ func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
                        continue
                }
                rs := r.Sym()
-               rs = ldr.ResolveABIAlias(rs)
                if rs == 0 {
                        continue
                }
index 1f5e333cfd54cd4848f139abf8113e65b825709f..720c03afd2a290d31ebd46037846041ce513ff87 100644 (file)
@@ -406,22 +406,21 @@ func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
                if sect.Name != ".text" {
                        break
                }
-               off = t.SetUint(ctxt.Arch, off, sect.Vaddr-textbase)
-               off = t.SetUint(ctxt.Arch, off, sect.Length)
-               if n == 0 {
-                       s := ldr.Lookup("runtime.text", 0)
-                       if s == 0 {
-                               ctxt.Errorf(s, "Unable to find symbol runtime.text\n")
-                       }
-                       off = t.SetAddr(ctxt.Arch, off, s)
-
-               } else {
-                       s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
-                       if s == 0 {
-                               ctxt.Errorf(s, "Unable to find symbol runtime.text.%d\n", n)
-                       }
-                       off = t.SetAddr(ctxt.Arch, off, s)
+               // The fields written should match runtime/symtab.go:textsect.
+               // They are designed to minimize runtime calculations.
+               vaddr := sect.Vaddr - textbase
+               off = t.SetUint(ctxt.Arch, off, vaddr) // field vaddr
+               end := vaddr + sect.Length
+               off = t.SetUint(ctxt.Arch, off, end) // field end
+               name := "runtime.text"
+               if n != 0 {
+                       name = fmt.Sprintf("runtime.text.%d", n)
+               }
+               s := ldr.Lookup(name, 0)
+               if s == 0 {
+                       ctxt.Errorf(s, "Unable to find symbol %s\n", name)
                }
+               off = t.SetAddr(ctxt.Arch, off, s) // field baseaddr
                n++
        }
        return t.Sym(), uint32(n)
@@ -507,13 +506,9 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
                symgcbits   = groupSym("runtime.gcbits.*", sym.SGCBITS)
        )
 
-       var symgofuncrel loader.Sym
-       if !ctxt.DynlinkingGo() {
-               if ctxt.UseRelro() {
-                       symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO)
-               } else {
-                       symgofuncrel = symgofunc
-               }
+       symgofuncrel := symgofunc
+       if ctxt.UseRelro() {
+               symgofuncrel = groupSym("go.funcrel.*", sym.SGOFUNCRELRO)
        }
 
        symt := ldr.CreateSymForUpdate("runtime.symtab", 0)
@@ -525,6 +520,8 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
        // within a type they sort by size, so the .* symbols
        // just defined above will be first.
        // hide the specific symbols.
+       // Some of these symbol section conditions are duplicated
+       // in cmd/internal/obj.contentHashSection.
        nsym := loader.Sym(ldr.NSym())
        symGroupType := make([]sym.SymKind, nsym)
        for s := loader.Sym(1); s < nsym; s++ {
@@ -537,33 +534,13 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
 
                name := ldr.SymName(s)
                switch {
-               case strings.HasPrefix(name, "type."):
-                       if !ctxt.DynlinkingGo() {
-                               ldr.SetAttrNotInSymbolTable(s, true)
-                       }
-                       if ctxt.UseRelro() {
-                               symGroupType[s] = sym.STYPERELRO
-                               if symtyperel != 0 {
-                                       ldr.SetCarrierSym(s, symtyperel)
-                               }
-                       } else {
-                               symGroupType[s] = sym.STYPE
-                               if symtyperel != 0 {
-                                       ldr.SetCarrierSym(s, symtype)
-                               }
-                       }
-
-               case strings.HasPrefix(name, "go.importpath.") && ctxt.UseRelro():
-                       // Keep go.importpath symbols in the same section as types and
-                       // names, as they can be referred to by a section offset.
-                       symGroupType[s] = sym.STYPERELRO
-
                case strings.HasPrefix(name, "go.string."):
                        symGroupType[s] = sym.SGOSTRING
                        ldr.SetAttrNotInSymbolTable(s, true)
                        ldr.SetCarrierSym(s, symgostring)
 
-               case strings.HasPrefix(name, "runtime.gcbits."):
+               case strings.HasPrefix(name, "runtime.gcbits."),
+                       strings.HasPrefix(name, "type..gcprog."):
                        symGroupType[s] = sym.SGCBITS
                        ldr.SetAttrNotInSymbolTable(s, true)
                        ldr.SetCarrierSym(s, symgcbits)
@@ -574,7 +551,7 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
                        }
                        if ctxt.UseRelro() {
                                symGroupType[s] = sym.SGOFUNCRELRO
-                               if symgofuncrel != 0 {
+                               if !ctxt.DynlinkingGo() {
                                        ldr.SetCarrierSym(s, symgofuncrel)
                                }
                        } else {
@@ -585,20 +562,39 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
                case strings.HasPrefix(name, "gcargs."),
                        strings.HasPrefix(name, "gclocals."),
                        strings.HasPrefix(name, "gclocals·"),
-                       ldr.SymType(s) == sym.SGOFUNC && s != symgofunc,
+                       ldr.SymType(s) == sym.SGOFUNC && s != symgofunc, // inltree, see pcln.go
                        strings.HasSuffix(name, ".opendefer"),
                        strings.HasSuffix(name, ".arginfo0"),
-                       strings.HasSuffix(name, ".arginfo1"):
-                       symGroupType[s] = sym.SGOFUNC
+                       strings.HasSuffix(name, ".arginfo1"),
+                       strings.HasSuffix(name, ".argliveinfo"),
+                       strings.HasSuffix(name, ".args_stackmap"),
+                       strings.HasSuffix(name, ".stkobj"):
                        ldr.SetAttrNotInSymbolTable(s, true)
+                       symGroupType[s] = sym.SGOFUNC
                        ldr.SetCarrierSym(s, symgofunc)
-                       align := int32(4)
-                       if a := ldr.SymAlign(s); a < align {
-                               ldr.SetSymAlign(s, align)
+                       if ctxt.Debugvlog != 0 {
+                               align := ldr.SymAlign(s)
+                               liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
+                       }
+
+               // Note: Check for "type." prefix after checking for .arginfo1 suffix.
+               // That way symbols like "type..eq.[2]interface {}.arginfo1" that belong
+               // in go.func.* end up there.
+               case strings.HasPrefix(name, "type."):
+                       if !ctxt.DynlinkingGo() {
+                               ldr.SetAttrNotInSymbolTable(s, true)
+                       }
+                       if ctxt.UseRelro() {
+                               symGroupType[s] = sym.STYPERELRO
+                               if symtyperel != 0 {
+                                       ldr.SetCarrierSym(s, symtyperel)
+                               }
                        } else {
-                               align = a
+                               symGroupType[s] = sym.STYPE
+                               if symtyperel != 0 {
+                                       ldr.SetCarrierSym(s, symtype)
+                               }
                        }
-                       liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
                }
        }
 
@@ -676,10 +672,12 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
        moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0))
        moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0))
        moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0))
+       moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.rodata", 0))
+       moduledata.AddAddr(ctxt.Arch, ldr.Lookup("go.func.*", 0))
 
        if ctxt.IsAIX() && ctxt.IsExternal() {
                // Add R_XCOFFREF relocation to prevent ld's garbage collection of
-               // runtime.rodata, runtime.erodata and runtime.epclntab.
+               // the following symbols. They might not be referenced in the program.
                addRef := func(name string) {
                        r, _ := moduledata.AddRel(objabi.R_XCOFFREF)
                        r.SetSym(ldr.Lookup(name, 0))
@@ -688,6 +686,12 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
                addRef("runtime.rodata")
                addRef("runtime.erodata")
                addRef("runtime.epclntab")
+               // As we use relative addressing for text symbols in functab, it is
+               // important that the offsets we computed stay unchanged by the external
+               // linker, i.e. all symbols in Textp should not be removed.
+               // Most of them are actually referenced (our deadcode pass ensures that),
+               // except go.buildid which is generated late and not used by the program.
+               addRef("go.buildid")
        }
 
        // text section information
index 12bd23f7e57e1d9410d3c2309ab1938c2b8d3bc9..aba6138c834adca7c09bb56d2f40cb94aba0edb1 100644 (file)
@@ -822,9 +822,12 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x loader.Sym) []xcoffSym {
                }
        }
 
+       name = ldr.SymExtname(x)
+       name = mangleABIName(ctxt, ldr, x, name)
+
        s := &XcoffSymEnt64{
                Nsclass: C_EXT,
-               Noffset: uint32(xfile.stringTable.add(ldr.SymExtname(x))),
+               Noffset: uint32(xfile.stringTable.add(name)),
                Nvalue:  uint64(ldr.SymValue(x)),
                Nscnum:  f.getXCOFFscnum(ldr.SymSect(x)),
                Ntype:   SYM_TYPE_FUNC,
@@ -1238,7 +1241,7 @@ func Xcoffadddynrel(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader
                sym:  s,
                roff: r.Off(),
        }
-       targ := ldr.ResolveABIAlias(r.Sym())
+       targ := r.Sym()
        var targType sym.SymKind
        if targ != 0 {
                targType = ldr.SymType(targ)
@@ -1333,7 +1336,7 @@ func (ctxt *Link) doxcoff() {
                                panic("cgo_export on static symbol")
                        }
 
-                       if ldr.SymType(s) == sym.STEXT || ldr.SymType(s) == sym.SABIALIAS {
+                       if ldr.SymType(s) == sym.STEXT {
                                // On AIX, a exported function must have two symbols:
                                // - a .text symbol which must start with a ".".
                                // - a .data symbol which is a function descriptor.
index 9d5319c31207887082b64f290b3e78de0e09044e..34c1c6a4c86c52a95e3f6aefcc1192e8ba4280ff 100644 (file)
@@ -307,7 +307,6 @@ type extSymPayload struct {
 const (
        // Loader.flags
        FlagStrictDups = 1 << iota
-       FlagUseABIAlias
 )
 
 func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
@@ -753,22 +752,6 @@ func (l *Loader) NReachableSym() int {
        return l.attrReachable.Count()
 }
 
-// SymNameLen returns the length of the symbol name, trying hard not to load
-// the name.
-func (l *Loader) SymNameLen(i Sym) int {
-       // Not much we can do about external symbols.
-       if l.IsExternal(i) {
-               return len(l.SymName(i))
-       }
-       r, li := l.toLocal(i)
-       le := r.Sym(li).NameLen(r.Reader)
-       if !r.NeedNameExpansion() {
-               return le
-       }
-       // Just load the symbol name. We don't know how expanded it'll be.
-       return len(l.SymName(i))
-}
-
 // Returns the raw (unpatched) name of the i-th symbol.
 func (l *Loader) RawSymName(i Sym) string {
        if l.IsExternal(i) {
@@ -1209,6 +1192,15 @@ func (l *Loader) IsItab(i Sym) bool {
        return r.Sym(li).IsItab()
 }
 
+// Returns whether this symbol is a dictionary symbol.
+func (l *Loader) IsDict(i Sym) bool {
+       if l.IsExternal(i) {
+               return false
+       }
+       r, li := l.toLocal(i)
+       return r.Sym(li).IsDict()
+}
+
 // Return whether this is a trampoline of a deferreturn call.
 func (l *Loader) IsDeferReturnTramp(i Sym) bool {
        return l.deferReturnTramp[i]
@@ -1540,27 +1532,7 @@ func (l *Loader) DynidSyms() []Sym {
 // approach would be to check for gotype during preload and copy the
 // results in to a map (might want to try this at some point and see
 // if it helps speed things up).
-func (l *Loader) SymGoType(i Sym) Sym {
-       var r *oReader
-       var auxs []goobj.Aux
-       if l.IsExternal(i) {
-               pp := l.getPayload(i)
-               r = l.objs[pp.objidx].r
-               auxs = pp.auxs
-       } else {
-               var li uint32
-               r, li = l.toLocal(i)
-               auxs = r.Auxs(li)
-       }
-       for j := range auxs {
-               a := &auxs[j]
-               switch a.Type() {
-               case goobj.AuxGotype:
-                       return l.resolve(r, a.Sym())
-               }
-       }
-       return 0
-}
+func (l *Loader) SymGoType(i Sym) Sym { return l.aux1(i, goobj.AuxGotype) }
 
 // SymUnit returns the compilation unit for a given symbol (which will
 // typically be nil for external or linker-manufactured symbols).
@@ -1898,12 +1870,98 @@ func (l *Loader) relocs(r *oReader, li uint32) Relocs {
        }
 }
 
+func (l *Loader) auxs(i Sym) (*oReader, []goobj.Aux) {
+       if l.IsExternal(i) {
+               pp := l.getPayload(i)
+               return l.objs[pp.objidx].r, pp.auxs
+       } else {
+               r, li := l.toLocal(i)
+               return r, r.Auxs(li)
+       }
+}
+
+// Returns a specific aux symbol of type t for symbol i.
+func (l *Loader) aux1(i Sym, t uint8) Sym {
+       r, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == t {
+                       return l.resolve(r, a.Sym())
+               }
+       }
+       return 0
+}
+
+func (l *Loader) Pcsp(i Sym) Sym { return l.aux1(i, goobj.AuxPcsp) }
+
+// Returns all aux symbols of per-PC data for symbol i.
+// tmp is a scratch space for the pcdata slice.
+func (l *Loader) PcdataAuxs(i Sym, tmp []Sym) (pcsp, pcfile, pcline, pcinline Sym, pcdata []Sym) {
+       pcdata = tmp[:0]
+       r, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               switch a.Type() {
+               case goobj.AuxPcsp:
+                       pcsp = l.resolve(r, a.Sym())
+               case goobj.AuxPcline:
+                       pcline = l.resolve(r, a.Sym())
+               case goobj.AuxPcfile:
+                       pcfile = l.resolve(r, a.Sym())
+               case goobj.AuxPcinline:
+                       pcinline = l.resolve(r, a.Sym())
+               case goobj.AuxPcdata:
+                       pcdata = append(pcdata, l.resolve(r, a.Sym()))
+               }
+       }
+       return
+}
+
+// Returns the number of pcdata for symbol i.
+func (l *Loader) NumPcdata(i Sym) int {
+       n := 0
+       _, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj.AuxPcdata {
+                       n++
+               }
+       }
+       return n
+}
+
+// Returns all funcdata symbols of symbol i.
+// tmp is a scratch space.
+func (l *Loader) Funcdata(i Sym, tmp []Sym) []Sym {
+       fd := tmp[:0]
+       r, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj.AuxFuncdata {
+                       fd = append(fd, l.resolve(r, a.Sym()))
+               }
+       }
+       return fd
+}
+
+// Returns the number of funcdata for symbol i.
+func (l *Loader) NumFuncdata(i Sym) int {
+       n := 0
+       _, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj.AuxFuncdata {
+                       n++
+               }
+       }
+       return n
+}
+
 // FuncInfo provides hooks to access goobj.FuncInfo in the objects.
 type FuncInfo struct {
        l       *Loader
        r       *oReader
        data    []byte
-       auxs    []goobj.Aux
        lengths goobj.FuncInfoLengths
 }
 
@@ -1925,76 +1983,12 @@ func (fi *FuncInfo) FuncFlag() objabi.FuncFlag {
        return (*goobj.FuncInfo)(nil).ReadFuncFlag(fi.data)
 }
 
-func (fi *FuncInfo) Pcsp() Sym {
-       sym := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
-       return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcfile() Sym {
-       sym := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
-       return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcline() Sym {
-       sym := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
-       return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcinline() Sym {
-       sym := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data)
-       return fi.l.resolve(fi.r, sym)
-}
-
 // Preload has to be called prior to invoking the various methods
 // below related to pcdata, funcdataoff, files, and inltree nodes.
 func (fi *FuncInfo) Preload() {
        fi.lengths = (*goobj.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
 }
 
-func (fi *FuncInfo) Pcdata() []Sym {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       syms := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data)
-       ret := make([]Sym, len(syms))
-       for i := range ret {
-               ret[i] = fi.l.resolve(fi.r, syms[i])
-       }
-       return ret
-}
-
-func (fi *FuncInfo) NumFuncdataoff() uint32 {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       return fi.lengths.NumFuncdataoff
-}
-
-func (fi *FuncInfo) Funcdataoff(k int) int64 {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       return (*goobj.FuncInfo)(nil).ReadFuncdataoff(fi.data, fi.lengths.FuncdataoffOff, uint32(k))
-}
-
-func (fi *FuncInfo) Funcdata(syms []Sym) []Sym {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       if int(fi.lengths.NumFuncdataoff) > cap(syms) {
-               syms = make([]Sym, 0, fi.lengths.NumFuncdataoff)
-       } else {
-               syms = syms[:0]
-       }
-       for j := range fi.auxs {
-               a := &fi.auxs[j]
-               if a.Type() == goobj.AuxFuncdata {
-                       syms = append(syms, fi.l.resolve(fi.r, a.Sym()))
-               }
-       }
-       return syms
-}
-
 func (fi *FuncInfo) NumFile() uint32 {
        if !fi.lengths.Initialized {
                panic("need to call Preload first")
@@ -2046,25 +2040,12 @@ func (fi *FuncInfo) InlTree(k int) InlTreeNode {
 }
 
 func (l *Loader) FuncInfo(i Sym) FuncInfo {
-       var r *oReader
-       var auxs []goobj.Aux
-       if l.IsExternal(i) {
-               pp := l.getPayload(i)
-               if pp.objidx == 0 {
-                       return FuncInfo{}
-               }
-               r = l.objs[pp.objidx].r
-               auxs = pp.auxs
-       } else {
-               var li uint32
-               r, li = l.toLocal(i)
-               auxs = r.Auxs(li)
-       }
+       r, auxs := l.auxs(i)
        for j := range auxs {
                a := &auxs[j]
                if a.Type() == goobj.AuxFuncInfo {
                        b := r.Data(a.Sym().SymIdx)
-                       return FuncInfo{l, r, b, auxs, goobj.FuncInfoLengths{}}
+                       return FuncInfo{l, r, b, goobj.FuncInfoLengths{}}
                }
        }
        return FuncInfo{}
@@ -2183,7 +2164,7 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
                }
                if strings.HasPrefix(name, "runtime.") ||
                        (loadingRuntimePkg && strings.HasPrefix(name, "type.")) {
-                       if bi := goobj.BuiltinIdx(name, v); bi != -1 {
+                       if bi := goobj.BuiltinIdx(name, int(osym.ABI())); bi != -1 {
                                // This is a definition of a builtin symbol. Record where it is.
                                l.builtinSyms[bi] = gi
                        }
@@ -2209,7 +2190,6 @@ func (l *Loader) LoadSyms(arch *sys.Arch) {
        // Index 0 is invalid for symbols.
        l.objSyms = make([]objSym, 1, symSize)
 
-       l.npkgsyms = l.NSym()
        st := loadState{
                l:            l,
                hashed64Syms: make(map[uint64]symAndSize, hashed64Size),
@@ -2219,6 +2199,7 @@ func (l *Loader) LoadSyms(arch *sys.Arch) {
        for _, o := range l.objs[goObjStart:] {
                st.preloadSyms(o.r, pkgDef)
        }
+       l.npkgsyms = l.NSym()
        for _, o := range l.objs[goObjStart:] {
                st.preloadSyms(o.r, hashed64Def)
                st.preloadSyms(o.r, hashedDef)
@@ -2288,27 +2269,6 @@ func abiToVer(abi uint16, localSymVersion int) int {
        return v
 }
 
-// ResolveABIAlias given a symbol returns the ABI alias target of that
-// symbol. If the sym in question is not an alias, the sym itself is
-// returned.
-func (l *Loader) ResolveABIAlias(s Sym) Sym {
-       if l.flags&FlagUseABIAlias == 0 {
-               return s
-       }
-       if s == 0 {
-               return 0
-       }
-       if l.SymType(s) != sym.SABIALIAS {
-               return s
-       }
-       relocs := l.Relocs(s)
-       target := relocs.At(0).Sym()
-       if l.SymType(target) == sym.SABIALIAS {
-               panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", l.SymName(s), l.SymName(target)))
-       }
-       return target
-}
-
 // TopLevelSym tests a symbol (by name and kind) to determine whether
 // the symbol first class sym (participating in the link) or is an
 // anonymous aux or sub-symbol containing some sub-part or payload of
@@ -2632,7 +2592,9 @@ type ErrorReporter struct {
 //
 func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
        if s != 0 && reporter.ldr.SymName(s) != "" {
-               format = reporter.ldr.SymName(s) + ": " + format
+               // Note: Replace is needed here because symbol names might have % in them,
+               // due to the use of LinkString for names of instantiating types.
+               format = strings.Replace(reporter.ldr.SymName(s), "%", "%%", -1) + ": " + format
        } else {
                format = fmt.Sprintf("sym %d: %s", s, format)
        }
index 204d04412dc24985fa3cb7a560989a840026170e..558c0a7dfffbdf3fd89d3f5a15254be41c8f08fc 100644 (file)
@@ -308,6 +308,16 @@ func (sb *SymbolBuilder) SetAddr(arch *sys.Arch, off int64, tgt Sym) int64 {
 }
 
 func (sb *SymbolBuilder) AddStringAt(off int64, str string) int64 {
+       strLen := int64(len(str))
+       if off+strLen > int64(len(sb.data)) {
+               panic("attempt to write past end of buffer")
+       }
+       copy(sb.data[off:off+strLen], str)
+       return off + strLen
+}
+
+// AddCStringAt adds str plus a null terminating byte.
+func (sb *SymbolBuilder) AddCStringAt(off int64, str string) int64 {
        strLen := int64(len(str))
        if off+strLen+1 > int64(len(sb.data)) {
                panic("attempt to write past end of buffer")
index 8505dc61093a6de0726f3f61b9947c8815e5b64a..5891d35888a8196e354eb084ab8f4b90b927bd46 100644 (file)
@@ -92,7 +92,6 @@ func applyrel(arch *sys.Arch, ldr *loader.Loader, rt objabi.RelocType, off int32
 
 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
        rs := r.Sym()
-       rs = ldr.ResolveABIAlias(rs)
        if target.IsExternal() {
                switch r.Type() {
                default:
index f7f91d1e8b2c8b98ed6eaf14f33c43eee4c1ec64..0e64af3e6ae194b4f61387b4c81d113ef1422325 100644 (file)
@@ -120,7 +120,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
        const isOk = true
        const noExtReloc = 0
        rs := r.Sym()
-       rs = ldr.ResolveABIAlias(rs)
        switch r.Type() {
        case objabi.R_ADDRMIPS,
                objabi.R_ADDRMIPSU:
index b877864b759beca3a1fe7eab405ed5459c1f7da8..62b319d19648d30a69410785dc3d00df58b6c991 100644 (file)
@@ -547,7 +547,7 @@ func symtoc(ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) int64 {
 // symbol address can be used directly.
 // This code is for AIX only.
 func archreloctoc(ldr *loader.Loader, target *ld.Target, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) int64 {
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        if target.IsLinux() {
                ldr.Errorf(s, "archrelocaddr called for %s relocation\n", ldr.SymName(rs))
        }
@@ -562,7 +562,7 @@ func archreloctoc(ldr *loader.Loader, target *ld.Target, syms *ld.ArchSyms, r lo
        var t int64
        useAddi := false
        relocs := ldr.Relocs(rs)
-       tarSym := ldr.ResolveABIAlias(relocs.At(0).Sym())
+       tarSym := relocs.At(0).Sym()
 
        if target.IsInternal() && tarSym != 0 && ldr.AttrReachable(tarSym) && ldr.SymSect(tarSym).Seg == &ld.Segdata {
                t = ldr.SymValue(tarSym) + r.Add() - ldr.SymValue(syms.TOC)
@@ -603,7 +603,7 @@ func archreloctoc(ldr *loader.Loader, target *ld.Target, syms *ld.ArchSyms, r lo
 // archrelocaddr relocates a symbol address.
 // This code is for AIX only.
 func archrelocaddr(ldr *loader.Loader, target *ld.Target, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) int64 {
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        if target.IsAIX() {
                ldr.Errorf(s, "archrelocaddr called for %s relocation\n", ldr.SymName(rs))
        }
@@ -802,7 +802,7 @@ func gentramp(ctxt *ld.Link, ldr *loader.Loader, tramp *loader.SymbolBuilder, ta
 }
 
 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (relocatedOffset int64, nExtReloc int, ok bool) {
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        if target.IsExternal() {
                // On AIX, relocations (except TLS ones) must be also done to the
                // value with the current addresses.
@@ -909,7 +909,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
 }
 
 func archrelocvariant(target *ld.Target, ldr *loader.Loader, r loader.Reloc, rv sym.RelocVariant, s loader.Sym, t int64, p []byte) (relocatedOffset int64) {
-       rs := ldr.ResolveABIAlias(r.Sym())
+       rs := r.Sym()
        switch rv & sym.RV_TYPE_MASK {
        default:
                ldr.Errorf(s, "unexpected relocation variant %d", rv)
@@ -1067,35 +1067,31 @@ func ensureglinkresolver(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuilde
                return glink
        }
 
-       // This is essentially the resolver from the ppc64 ELF ABI.
+       // This is essentially the resolver from the ppc64 ELFv2 ABI.
        // At entry, r12 holds the address of the symbol resolver stub
        // for the target routine and the argument registers hold the
        // arguments for the target routine.
        //
+       // PC-rel offsets are computed once the final codesize of the
+       // resolver is known.
+       //
        // This stub is PIC, so first get the PC of label 1 into r11.
-       // Other things will be relative to this.
        glink.AddUint32(ctxt.Arch, 0x7c0802a6) // mflr r0
        glink.AddUint32(ctxt.Arch, 0x429f0005) // bcl 20,31,1f
        glink.AddUint32(ctxt.Arch, 0x7d6802a6) // 1: mflr r11
-       glink.AddUint32(ctxt.Arch, 0x7c0803a6) // mtlf r0
+       glink.AddUint32(ctxt.Arch, 0x7c0803a6) // mtlr r0
 
-       // Compute the .plt array index from the entry point address.
-       // Because this is PIC, everything is relative to label 1b (in
-       // r11):
-       //   r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
-       glink.AddUint32(ctxt.Arch, 0x3800ffd0) // li r0,-(res_0-1b)=-48
+       // Compute the .plt array index from the entry point address
+       // into r0. This is computed relative to label 1 above.
+       glink.AddUint32(ctxt.Arch, 0x38000000) // li r0,-(res_0-1b)
        glink.AddUint32(ctxt.Arch, 0x7c006214) // add r0,r0,r12
        glink.AddUint32(ctxt.Arch, 0x7c0b0050) // sub r0,r0,r11
        glink.AddUint32(ctxt.Arch, 0x7800f082) // srdi r0,r0,2
 
-       // r11 = address of the first byte of the PLT
-       r, _ := glink.AddRel(objabi.R_ADDRPOWER)
-       r.SetSym(ctxt.PLT)
-       r.SetSiz(8)
-       r.SetOff(int32(glink.Size()))
-       r.SetAdd(0)
-       glink.AddUint32(ctxt.Arch, 0x3d600000) // addis r11,0,.plt@ha
-       glink.AddUint32(ctxt.Arch, 0x396b0000) // addi r11,r11,.plt@l
+       // Load the PC-rel offset of ".plt - 1b", and add it to 1b.
+       // This is stored after this stub and before the resolvers.
+       glink.AddUint32(ctxt.Arch, 0xe98b0000) // ld r12,res_0-1b-8(r11)
+       glink.AddUint32(ctxt.Arch, 0x7d6b6214) // add r11,r11,r12
 
        // Load r12 = dynamic resolver address and r11 = DSO
        // identifier from the first two doublewords of the PLT.
@@ -1106,6 +1102,19 @@ func ensureglinkresolver(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuilde
        glink.AddUint32(ctxt.Arch, 0x7d8903a6) // mtctr r12
        glink.AddUint32(ctxt.Arch, 0x4e800420) // bctr
 
+       // Store the PC-rel offset to the PLT
+       r, _ := glink.AddRel(objabi.R_PCREL)
+       r.SetSym(ctxt.PLT)
+       r.SetSiz(8)
+       r.SetOff(int32(glink.Size()))
+       r.SetAdd(glink.Size())        // Adjust the offset to be relative to label 1 above.
+       glink.AddUint64(ctxt.Arch, 0) // The offset to the PLT.
+
+       // Resolve PC-rel offsets above now the final size of the stub is known.
+       res0m1b := glink.Size() - 8 // res_0 - 1b
+       glink.SetUint32(ctxt.Arch, 16, 0x38000000|uint32(uint16(-res0m1b)))
+       glink.SetUint32(ctxt.Arch, 32, 0xe98b0000|uint32(uint16(res0m1b-8)))
+
        // The symbol resolvers must immediately follow.
        //   res_0:
 
index 6eace617dc0a94fea3b1157b308a72c59a1bad8d..cb53a605d7175947c9491243467800c83d540ccd 100644 (file)
@@ -96,10 +96,10 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
                }
                out.Write64(uint64(r.Xadd))
 
-       case objabi.R_CALLRISCV:
-               // Call relocations are currently handled via R_RISCV_PCREL_ITYPE.
-               // TODO(jsing): Consider generating elf.R_RISCV_CALL instead of a
-               // HI20/LO12_I pair.
+       case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
+               out.Write64(uint64(sectoff))
+               out.Write64(uint64(elf.R_RISCV_JAL) | uint64(elfsym)<<32)
+               out.Write64(uint64(r.Xadd))
 
        case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
                // Find the text symbol for the AUIPC instruction targeted
@@ -156,10 +156,38 @@ func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtRe
 }
 
 func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
+       rs := r.Sym()
+       pc := ldr.SymValue(s) + int64(r.Off())
+
+       // If the call points to a trampoline, see if we can reach the symbol
+       // directly. This situation can occur when the relocation symbol is
+       // not assigned an address until after the trampolines are generated.
+       if r.Type() == objabi.R_RISCV_CALL_TRAMP {
+               relocs := ldr.Relocs(rs)
+               if relocs.Count() != 1 {
+                       ldr.Errorf(s, "trampoline %v has %d relocations", ldr.SymName(rs), relocs.Count())
+               }
+               tr := relocs.At(0)
+               if tr.Type() != objabi.R_RISCV_PCREL_ITYPE {
+                       ldr.Errorf(s, "trampoline %v has unexpected relocation %v", ldr.SymName(rs), tr.Type())
+               }
+               trs := tr.Sym()
+               if ldr.SymValue(trs) != 0 && ldr.SymType(trs) != sym.SDYNIMPORT && ldr.SymType(trs) != sym.SUNDEFEXT {
+                       trsOff := ldr.SymValue(trs) + tr.Add() - pc
+                       if trsOff >= -(1<<20) && trsOff < (1<<20) {
+                               r.SetType(objabi.R_RISCV_CALL)
+                               r.SetSym(trs)
+                               r.SetAdd(tr.Add())
+                               rs = trs
+                       }
+               }
+
+       }
+
        if target.IsExternal() {
                switch r.Type() {
-               case objabi.R_CALLRISCV:
-                       return val, 0, true
+               case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
+                       return val, 1, true
 
                case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
                        return val, 2, true
@@ -168,11 +196,19 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
                return val, 0, false
        }
 
-       rs := ldr.ResolveABIAlias(r.Sym())
+       off := ldr.SymValue(rs) + r.Add() - pc
 
        switch r.Type() {
-       case objabi.R_CALLRISCV:
-               // Nothing to do.
+       case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
+               // Generate instruction immediates.
+               imm, err := riscv.EncodeJImmediate(off)
+               if err != nil {
+                       ldr.Errorf(s, "cannot encode R_RISCV_CALL relocation offset for %s: %v", ldr.SymName(rs), err)
+               }
+               immMask := int64(riscv.JTypeImmMask)
+
+               val = (val &^ immMask) | int64(imm)
+
                return val, 0, true
 
        case objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
@@ -186,13 +222,10 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
                return ebreakIns<<32 | ebreakIns, 0, true
 
        case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
-               pc := ldr.SymValue(s) + int64(r.Off())
-               off := ldr.SymValue(rs) + r.Add() - pc
-
                // Generate AUIPC and second instruction immediates.
                low, high, err := riscv.Split32BitImmediate(off)
                if err != nil {
-                       ldr.Errorf(s, "R_RISCV_PCREL_ relocation does not fit in 32-bits: %d", off)
+                       ldr.Errorf(s, "R_RISCV_PCREL_ relocation does not fit in 32 bits: %d", off)
                }
 
                auipcImm, err := riscv.EncodeUImmediate(high)
@@ -237,8 +270,92 @@ func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant
 
 func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
        switch r.Type() {
+       case objabi.R_RISCV_CALL, objabi.R_RISCV_CALL_TRAMP:
+               return ld.ExtrelocSimple(ldr, r), true
+
        case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
                return ld.ExtrelocViaOuterSym(ldr, r, s), true
        }
        return loader.ExtReloc{}, false
 }
+
+func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
+       relocs := ldr.Relocs(s)
+       r := relocs.At(ri)
+
+       switch r.Type() {
+       case objabi.R_RISCV_CALL:
+               pc := ldr.SymValue(s) + int64(r.Off())
+               off := ldr.SymValue(rs) + r.Add() - pc
+
+               // Relocation symbol has an address and is directly reachable,
+               // therefore there is no need for a trampoline.
+               if ldr.SymValue(rs) != 0 && off >= -(1<<20) && off < (1<<20) && (*ld.FlagDebugTramp <= 1 || ldr.SymPkg(s) == ldr.SymPkg(rs)) {
+                       break
+               }
+
+               // Relocation symbol is too far for a direct call or has not
+               // yet been given an address. See if an existing trampoline is
+               // reachable and if so, reuse it. Otherwise we need to create
+               // a new trampoline.
+               var tramp loader.Sym
+               for i := 0; ; i++ {
+                       oName := ldr.SymName(rs)
+                       name := fmt.Sprintf("%s-tramp%d", oName, i)
+                       if r.Add() != 0 {
+                               name = fmt.Sprintf("%s%+x-tramp%d", oName, r.Add(), i)
+                       }
+                       tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
+                       ldr.SetAttrReachable(tramp, true)
+                       if ldr.SymType(tramp) == sym.SDYNIMPORT {
+                               // Do not reuse trampoline defined in other module.
+                               continue
+                       }
+                       if oName == "runtime.deferreturn" {
+                               ldr.SetIsDeferReturnTramp(tramp, true)
+                       }
+                       if ldr.SymValue(tramp) == 0 {
+                               // Either trampoline does not exist or we found one
+                               // that does not have an address assigned and will be
+                               // laid down immediately after the current function.
+                               break
+                       }
+
+                       trampOff := ldr.SymValue(tramp) - (ldr.SymValue(s) + int64(r.Off()))
+                       if trampOff >= -(1<<20) && trampOff < (1<<20) {
+                               // An existing trampoline that is reachable.
+                               break
+                       }
+               }
+               if ldr.SymType(tramp) == 0 {
+                       trampb := ldr.MakeSymbolUpdater(tramp)
+                       ctxt.AddTramp(trampb)
+                       genCallTramp(ctxt.Arch, ctxt.LinkMode, ldr, trampb, rs, int64(r.Add()))
+               }
+               sb := ldr.MakeSymbolUpdater(s)
+               if ldr.SymValue(rs) == 0 {
+                       // In this case the target symbol has not yet been assigned an
+                       // address, so we have to assume a trampoline is required. Mark
+                       // this as a call via a trampoline so that we can potentially
+                       // switch to a direct call during relocation.
+                       sb.SetRelocType(ri, objabi.R_RISCV_CALL_TRAMP)
+               }
+               relocs := sb.Relocs()
+               r := relocs.At(ri)
+               r.SetSym(tramp)
+               r.SetAdd(0)
+
+       default:
+               ctxt.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
+       }
+}
+
+func genCallTramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
+       tramp.AddUint32(arch, 0x00000f97) // AUIPC      $0, X31
+       tramp.AddUint32(arch, 0x000f8067) // JALR               X0, (X31)
+
+       r, _ := tramp.AddRel(objabi.R_RISCV_PCREL_ITYPE)
+       r.SetSiz(8)
+       r.SetSym(target)
+       r.SetAdd(offset)
+}
index 917324d92238915584c73452b2eadcc639e108a6..557e8932c98b44dbee83682acf8a12ed37e622c9 100644 (file)
@@ -27,9 +27,17 @@ func Init() (*sys.Arch, ld.Arch) {
                Elfreloc1:        elfreloc1,
                ElfrelocSize:     24,
                Elfsetupplt:      elfsetupplt,
-               Gentext:          gentext,
-               GenSymsLate:      genSymsLate,
-               Machoreloc1:      machoreloc1,
+
+               // TrampLimit is set such that we always run the trampoline
+               // generation code. This is necessary since calls to external
+               // symbols require the use of trampolines, regardless of the
+               // text size.
+               TrampLimit: 1,
+               Trampoline: trampoline,
+
+               Gentext:     gentext,
+               GenSymsLate: genSymsLate,
+               Machoreloc1: machoreloc1,
 
                Linuxdynld: "/lib/ld.so.1",
 
index 70cf36a87ee9bed9ef6cb080fed71d2e99c4ae8d..2f2c839006f11d4fbd7b328af63f2d2a8d8def82 100644 (file)
@@ -6,11 +6,13 @@ package sym
 
 import (
        "cmd/internal/obj"
+       "internal/buildcfg"
 )
 
 const (
        SymVerABI0        = 0
        SymVerABIInternal = 1
+       SymVerABICount    = 2  // Number of internal ABIs
        SymVerStatic      = 10 // Minimum version used by static (file-local) syms
 )
 
@@ -19,6 +21,11 @@ func ABIToVersion(abi obj.ABI) int {
        case obj.ABI0:
                return SymVerABI0
        case obj.ABIInternal:
+               if !buildcfg.Experiment.RegabiWrappers {
+                       // If wrappers are not enabled, ABI0 and ABIInternal are actually same
+                       // so we normalize everything to ABI0.
+                       return SymVerABI0
+               }
                return SymVerABIInternal
        }
        return -1
index c176d5e208cb447d1387e90c04ba610aa76bfd48..0a0741f84bf402439649e6058237a2a5243d26b2 100644 (file)
@@ -30,6 +30,8 @@
 
 package sym
 
+import "cmd/internal/objabi"
+
 // A SymKind describes the kind of memory represented by a symbol.
 type SymKind uint8
 
@@ -118,33 +120,29 @@ const (
        SDWARFRANGE
        SDWARFLOC
        SDWARFLINES
-
-       // ABI aliases (these never appear in the output)
-       SABIALIAS
 )
 
 // AbiSymKindToSymKind maps values read from object files (which are
 // of type cmd/internal/objabi.SymKind) to values of type SymKind.
 var AbiSymKindToSymKind = [...]SymKind{
-       Sxxx,
-       STEXT,
-       SRODATA,
-       SNOPTRDATA,
-       SDATA,
-       SBSS,
-       SNOPTRBSS,
-       STLSBSS,
-       SDWARFCUINFO,
-       SDWARFCONST,
-       SDWARFFCN,
-       SDWARFABSFCN,
-       SDWARFTYPE,
-       SDWARFVAR,
-       SDWARFRANGE,
-       SDWARFLOC,
-       SDWARFLINES,
-       SABIALIAS,
-       SLIBFUZZER_EXTRA_COUNTER,
+       objabi.Sxxx:                     Sxxx,
+       objabi.STEXT:                    STEXT,
+       objabi.SRODATA:                  SRODATA,
+       objabi.SNOPTRDATA:               SNOPTRDATA,
+       objabi.SDATA:                    SDATA,
+       objabi.SBSS:                     SBSS,
+       objabi.SNOPTRBSS:                SNOPTRBSS,
+       objabi.STLSBSS:                  STLSBSS,
+       objabi.SDWARFCUINFO:             SDWARFCUINFO,
+       objabi.SDWARFCONST:              SDWARFCONST,
+       objabi.SDWARFFCN:                SDWARFFCN,
+       objabi.SDWARFABSFCN:             SDWARFABSFCN,
+       objabi.SDWARFTYPE:               SDWARFTYPE,
+       objabi.SDWARFVAR:                SDWARFVAR,
+       objabi.SDWARFRANGE:              SDWARFRANGE,
+       objabi.SDWARFLOC:                SDWARFLOC,
+       objabi.SDWARFLINES:              SDWARFLINES,
+       objabi.SLIBFUZZER_EXTRA_COUNTER: SLIBFUZZER_EXTRA_COUNTER,
 }
 
 // ReadOnly are the symbol kinds that form read-only sections. In some
index 34cb314bd5b05b0ae36f90e8da88a13b7b4d913d..bf8eda713ec847a8de27a0af78f3eb1aca8b5fed 100644 (file)
@@ -65,12 +65,11 @@ func _() {
        _ = x[SDWARFRANGE-54]
        _ = x[SDWARFLOC-55]
        _ = x[SDWARFLINES-56]
-       _ = x[SABIALIAS-57]
 }
 
-const _SymKind_name = "SxxxSTEXTSELFRXSECTSMACHOPLTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_EXTRA_COUNTERSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSABIALIAS"
+const _SymKind_name = "SxxxSTEXTSELFRXSECTSMACHOPLTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSFirstWritableSBUILDINFOSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSLIBFUZZER_EXTRA_COUNTERSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSDYNIMPORTSHOSTOBJSUNDEFEXTSDWARFSECTSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINES"
 
-var _SymKind_index = [...]uint16{0, 4, 9, 19, 28, 33, 40, 49, 56, 63, 70, 78, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 220, 230, 238, 244, 253, 261, 268, 278, 286, 291, 300, 304, 313, 337, 344, 349, 361, 373, 390, 407, 416, 426, 434, 443, 453, 465, 476, 485, 497, 507, 516, 527, 536, 547, 556}
+var _SymKind_index = [...]uint16{0, 4, 9, 19, 28, 33, 40, 49, 56, 63, 70, 78, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 220, 230, 238, 244, 253, 261, 268, 278, 286, 291, 300, 304, 313, 337, 344, 349, 361, 373, 390, 407, 416, 426, 434, 443, 453, 465, 476, 485, 497, 507, 516, 527, 536, 547}
 
 func (i SymKind) String() string {
        if i >= SymKind(len(_SymKind_index)-1) {
index 5bdfdbaee63e9bc42626d7057124dd18d108dd1c..01c500ed70e6dc3e0baed4176e4dab2073865ede 100644 (file)
@@ -173,7 +173,7 @@ func asmb2(ctxt *ld.Link, ldr *loader.Loader) {
                                }
                                wfn.Write(P[off:r.Off()])
                                off = r.Off()
-                               rs := ldr.ResolveABIAlias(r.Sym())
+                               rs := r.Sym()
                                switch r.Type() {
                                case objabi.R_ADDR:
                                        writeSleb128(wfn, ldr.SymValue(rs)+r.Add())
index fed9c7bc3fc433124055700ac063c898c7e43ed4..ad7658bb2577f0fb163b8854d63c47c26c470a7a 100644 (file)
@@ -282,8 +282,8 @@ func TestBuildForTvOS(t *testing.T) {
                "-isysroot", strings.TrimSpace(string(sdkPath)),
                "-mtvos-version-min=12.0",
                "-fembed-bitcode",
-               "-framework", "CoreFoundation",
        }
+       CGO_LDFLAGS := []string{"-framework", "CoreFoundation"}
        lib := filepath.Join("testdata", "testBuildFortvOS", "lib.go")
        tmpDir := t.TempDir()
 
@@ -295,12 +295,14 @@ func TestBuildForTvOS(t *testing.T) {
                "GOARCH=arm64",
                "CC="+strings.Join(CC, " "),
                "CGO_CFLAGS=", // ensure CGO_CFLAGS does not contain any flags. Issue #35459
+               "CGO_LDFLAGS="+strings.Join(CGO_LDFLAGS, " "),
        )
        if out, err := cmd.CombinedOutput(); err != nil {
                t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
        }
 
        link := exec.Command(CC[0], CC[1:]...)
+       link.Args = append(link.Args, CGO_LDFLAGS...)
        link.Args = append(link.Args, "-o", filepath.Join(tmpDir, "a.out")) // Avoid writing to package directory.
        link.Args = append(link.Args, ar, filepath.Join("testdata", "testBuildFortvOS", "main.m"))
        if out, err := link.CombinedOutput(); err != nil {
@@ -995,13 +997,31 @@ package main
 
 var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
 
+var addr = [...]*byte{
+       &x[1<<23-1],
+       &x[1<<23],
+       &x[1<<23+1],
+       &x[1<<24-1],
+       &x[1<<24],
+       &x[1<<24+1],
+}
+
 func main() {
+       // check relocations in instructions
        check(x[1<<23-1], 0)
        check(x[1<<23], 23)
        check(x[1<<23+1], 0)
        check(x[1<<24-1], 0)
        check(x[1<<24], 24)
        check(x[1<<24+1], 0)
+
+       // check absolute address relocations in data
+       check(*addr[0], 0)
+       check(*addr[1], 23)
+       check(*addr[2], 0)
+       check(*addr[3], 0)
+       check(*addr[4], 24)
+       check(*addr[5], 0)
 }
 
 func check(x, y byte) {
index 1544be041a8174eee4b2849d354ecd0274f8cb76..0c826738ec9baede10fca9dc8876826946db11cb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo
-// +build cgo
 
 package main
 
index f231a7c6e0e2e5c084cb162c1b6c3540d4677b85..ff4316103083ac6d35f3d47b13c46f43863b849b 100644 (file)
@@ -228,7 +228,7 @@ func testDisasm(t *testing.T, srcfname string, printCode bool, printGnuAsm bool,
                }
        }
 
-       if !ok {
+       if !ok || testing.Verbose() {
                t.Logf("full disassembly:\n%s", text)
        }
 }
index f46e934e0f3cf81d687799fd6d41bf621ef4d7f7..7ad712cd60b2cad80f4d0c65a794584e6c8f49f2 100644 (file)
@@ -6,9 +6,6 @@
 // that provides the readline functionality if possible.
 
 //go:build (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows) && !appengine && !android
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
-// +build !appengine
-// +build !android
 
 package main
 
index 9b45457436bda9966ec698eea03b55718a468f24..1c0dad56d849e6af89f30f5cf405e0598d72f967 100644 (file)
@@ -407,10 +407,7 @@ func (tasks allTasks) task(taskID uint64) *taskDesc {
                return t
        }
 
-       t = &taskDesc{
-               id:         taskID,
-               goroutines: make(map[uint64]struct{}),
-       }
+       t = newTaskDesc(taskID)
        tasks[taskID] = t
        return t
 }
index acd5693c7d5fea053190a80e9b7f174b21d60463..9f1c8e3b3b0e8e38c0ce93c53c732b81b7d1c1c2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package main
 
index f94586abf3da6cdcb40928d2ea09ccfc01fd5cae..3aeba223ee66d93fc35527cab7f9f3b0294ac490 100644 (file)
@@ -66,7 +66,7 @@ var (
 
 func main() {
        flag.Usage = func() {
-               fmt.Fprintln(os.Stderr, usageMessage)
+               fmt.Fprint(os.Stderr, usageMessage)
                os.Exit(2)
        }
        flag.Parse()
index 2b1a68d7f3d796ec7e454db3694caf1616783744..87fd3a3515c8f018906959644daf2dd9ef5c8054 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package main
 
index 8dc56a8c7be96c3fc93341b09c25eafd13ab875d..f35061ec63030506be56d1de0afe9b0df3d91611 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package main
 
index 24c48e649b8875ff0dd0f7fb753a4a8098456911..844c7a475d5174f803142f5d87a6449596d210bb 100644 (file)
@@ -76,7 +76,7 @@ func newLLVMSymbolizer(cmd, file string, base uint64, isData bool) (*llvmSymboli
        }
 
        j := &llvmSymbolizerJob{
-               cmd:     exec.Command(cmd, "-inlining", "-demangle=false"),
+               cmd:     exec.Command(cmd, "--inlining", "-demangle=false"),
                symType: "CODE",
        }
        if isData {
index 5ed8a1f9f1e3823c884a45c3bdb78055f86184dd..e920eeb2fa204331ec562b24e943e84a54a31df2 100644 (file)
@@ -525,6 +525,47 @@ type elfMapping struct {
        stextOffset *uint64
 }
 
+// findProgramHeader returns the program segment that matches the current
+// mapping and the given address, or an error if it cannot find a unique program
+// header.
+func (m *elfMapping) findProgramHeader(ef *elf.File, addr uint64) (*elf.ProgHeader, error) {
+       // For user space executables, we try to find the actual program segment that
+       // is associated with the given mapping. Skip this search if limit <= start.
+       // We cannot use just a check on the start address of the mapping to tell if
+       // it's a kernel / .ko module mapping, because with quipper address remapping
+       // enabled, the address would be in the lower half of the address space.
+
+       if m.stextOffset != nil || m.start >= m.limit || m.limit >= (uint64(1)<<63) {
+               // For the kernel, find the program segment that includes the .text section.
+               return elfexec.FindTextProgHeader(ef), nil
+       }
+
+       // Fetch all the loadable segments.
+       var phdrs []elf.ProgHeader
+       for i := range ef.Progs {
+               if ef.Progs[i].Type == elf.PT_LOAD {
+                       phdrs = append(phdrs, ef.Progs[i].ProgHeader)
+               }
+       }
+       // Some ELF files don't contain any loadable program segments, e.g. .ko
+       // kernel modules. It's not an error to have no header in such cases.
+       if len(phdrs) == 0 {
+               return nil, nil
+       }
+       // Get all program headers associated with the mapping.
+       headers := elfexec.ProgramHeadersForMapping(phdrs, m.offset, m.limit-m.start)
+       if len(headers) == 0 {
+               return nil, errors.New("no program header matches mapping info")
+       }
+       if len(headers) == 1 {
+               return headers[0], nil
+       }
+
+       // Use the file offset corresponding to the address to symbolize, to narrow
+       // down the header.
+       return elfexec.HeaderForFileOffset(headers, addr-m.start+m.offset)
+}
+
 // file implements the binutils.ObjFile interface.
 type file struct {
        b       *binrep
@@ -555,27 +596,9 @@ func (f *file) computeBase(addr uint64) error {
        }
        defer ef.Close()
 
-       var ph *elf.ProgHeader
-       // For user space executables, find the actual program segment that is
-       // associated with the given mapping. Skip this search if limit <= start.
-       // We cannot use just a check on the start address of the mapping to tell if
-       // it's a kernel / .ko module mapping, because with quipper address remapping
-       // enabled, the address would be in the lower half of the address space.
-       if f.m.stextOffset == nil && f.m.start < f.m.limit && f.m.limit < (uint64(1)<<63) {
-               // Get all program headers associated with the mapping.
-               headers, hasLoadables := elfexec.ProgramHeadersForMapping(ef, f.m.offset, f.m.limit-f.m.start)
-
-               // Some ELF files don't contain any loadable program segments, e.g. .ko
-               // kernel modules. It's not an error to have no header in such cases.
-               if hasLoadables {
-                       ph, err = matchUniqueHeader(headers, addr-f.m.start+f.m.offset)
-                       if err != nil {
-                               return fmt.Errorf("failed to find program header for file %q, ELF mapping %#v, address %x: %v", f.name, *f.m, addr, err)
-                       }
-               }
-       } else {
-               // For the kernel, find the program segment that includes the .text section.
-               ph = elfexec.FindTextProgHeader(ef)
+       ph, err := f.m.findProgramHeader(ef, addr)
+       if err != nil {
+               return fmt.Errorf("failed to find program header for file %q, ELF mapping %#v, address %x: %v", f.name, *f.m, addr, err)
        }
 
        base, err := elfexec.GetBase(&ef.FileHeader, ph, f.m.stextOffset, f.m.start, f.m.limit, f.m.offset)
@@ -587,38 +610,6 @@ func (f *file) computeBase(addr uint64) error {
        return nil
 }
 
-// matchUniqueHeader attempts to identify a unique header from the given list,
-// using the given file offset to disambiguate between multiple segments. It
-// returns an error if the header list is empty or if it cannot identify a
-// unique header.
-func matchUniqueHeader(headers []*elf.ProgHeader, fileOffset uint64) (*elf.ProgHeader, error) {
-       if len(headers) == 0 {
-               return nil, errors.New("no program header matches mapping info")
-       }
-       if len(headers) == 1 {
-               // Don't use the file offset if we already have a single header.
-               return headers[0], nil
-       }
-       // We have multiple input segments. Attempt to identify a unique one
-       // based on the given file offset.
-       var ph *elf.ProgHeader
-       for _, h := range headers {
-               if fileOffset >= h.Off && fileOffset < h.Off+h.Memsz {
-                       if ph != nil {
-                               // Assuming no other bugs, this can only happen if we have two or
-                               // more small program segments that fit on the same page, and a
-                               // segment other than the last one includes uninitialized data.
-                               return nil, fmt.Errorf("found second program header (%#v) that matches file offset %x, first program header is %#v. Does first program segment contain uninitialized data?", *h, fileOffset, *ph)
-                       }
-                       ph = h
-               }
-       }
-       if ph == nil {
-               return nil, fmt.Errorf("no program header matches file offset %x", fileOffset)
-       }
-       return ph, nil
-}
-
 func (f *file) Name() string {
        return f.name
 }
index 4397e253e0d0c751fb36a610b1b57baa92bb5c86..c9edf10bb43787815aa1b58fa8f2b65bfefab1b7 100644 (file)
@@ -189,6 +189,14 @@ var configHelp = map[string]string{
                "Drops functions above the highest matched frame.",
                "If set, all frames above the highest match are dropped from every sample.",
                "Matching includes the function name, filename or object name."),
+       "tagroot": helpText(
+               "Adds pseudo stack frames for labels key/value pairs at the callstack root.",
+               "A comma-separated list of label keys.",
+               "The first key creates frames at the new root."),
+       "tagleaf": helpText(
+               "Adds pseudo stack frames for labels key/value pairs at the callstack leaf.",
+               "A comma-separated list of label keys.",
+               "The last key creates frames at the new leaf."),
        "tagfocus": helpText(
                "Restricts to samples with tags in range or matched by regexp",
                "Use name=value syntax to limit the matching to a specific tag.",
index b3f82f22c9d94a58515fac4852df49a773ede5ef..9fcdd459b271fa89499815d20e77257aeb35faa4 100644 (file)
@@ -30,6 +30,10 @@ type config struct {
        Normalize           bool    `json:"normalize,omitempty"`
        Sort                string  `json:"sort,omitempty"`
 
+       // Label pseudo stack frame generation options
+       TagRoot string `json:"tagroot,omitempty"`
+       TagLeaf string `json:"tagleaf,omitempty"`
+
        // Filtering options
        DropNegative bool    `json:"drop_negative,omitempty"`
        NodeCount    int     `json:"nodecount,omitempty"`
index 3967a12d45affbb2ec4c818da69f7fa881382130..6a1e64c600e3399724bf3302da521acb593fabf6 100644 (file)
@@ -73,6 +73,10 @@ func generateRawReport(p *profile.Profile, cmd []string, cfg config, o *plugin.O
 
        cfg = applyCommandOverrides(cmd[0], c.format, cfg)
 
+       // Create label pseudo nodes before filtering, in case the filters use
+       // the generated nodes.
+       generateTagRootsLeaves(p, cfg, o.UI)
+
        // Delay focus after configuring report to get percentages on all samples.
        relative := cfg.RelativePercentages
        if relative {
@@ -208,6 +212,25 @@ func applyCommandOverrides(cmd string, outputFormat int, cfg config) config {
        return cfg
 }
 
+// generateTagRootsLeaves generates extra nodes from the tagroot and tagleaf options.
+func generateTagRootsLeaves(prof *profile.Profile, cfg config, ui plugin.UI) {
+       tagRootLabelKeys := dropEmptyStrings(strings.Split(cfg.TagRoot, ","))
+       tagLeafLabelKeys := dropEmptyStrings(strings.Split(cfg.TagLeaf, ","))
+       rootm, leafm := addLabelNodes(prof, tagRootLabelKeys, tagLeafLabelKeys, cfg.Unit)
+       warnNoMatches(cfg.TagRoot == "" || rootm, "TagRoot", ui)
+       warnNoMatches(cfg.TagLeaf == "" || leafm, "TagLeaf", ui)
+}
+
+// dropEmptyStrings filters a slice to only non-empty strings
+func dropEmptyStrings(in []string) (out []string) {
+       for _, s := range in {
+               if s != "" {
+                       out = append(out, s)
+               }
+       }
+       return
+}
+
 func aggregate(prof *profile.Profile, cfg config) error {
        var function, filename, linenumber, address bool
        inlines := !cfg.NoInlines
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/tagroot.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/tagroot.go
new file mode 100644 (file)
index 0000000..c2cdfa4
--- /dev/null
@@ -0,0 +1,124 @@
+package driver
+
+import (
+       "strings"
+
+       "github.com/google/pprof/internal/measurement"
+       "github.com/google/pprof/profile"
+)
+
+// addLabelNodes adds pseudo stack frames "label:value" to each Sample with
+// labels matching the supplied keys.
+//
+// rootKeys adds frames at the root of the callgraph (first key becomes new root).
+// leafKeys adds frames at the leaf of the callgraph (last key becomes new leaf).
+//
+// Returns whether there were matches found for the label keys.
+func addLabelNodes(p *profile.Profile, rootKeys, leafKeys []string, outputUnit string) (rootm, leafm bool) {
+       // Find where to insert the new locations and functions at the end of
+       // their ID spaces.
+       var maxLocID uint64
+       var maxFunctionID uint64
+       for _, loc := range p.Location {
+               if loc.ID > maxLocID {
+                       maxLocID = loc.ID
+               }
+       }
+       for _, f := range p.Function {
+               if f.ID > maxFunctionID {
+                       maxFunctionID = f.ID
+               }
+       }
+       nextLocID := maxLocID + 1
+       nextFuncID := maxFunctionID + 1
+
+       // Intern the new locations and functions we are generating.
+       type locKey struct {
+               functionName, fileName string
+       }
+       locs := map[locKey]*profile.Location{}
+
+       internLoc := func(locKey locKey) *profile.Location {
+               loc, found := locs[locKey]
+               if found {
+                       return loc
+               }
+
+               function := &profile.Function{
+                       ID:       nextFuncID,
+                       Name:     locKey.functionName,
+                       Filename: locKey.fileName,
+               }
+               nextFuncID++
+               p.Function = append(p.Function, function)
+
+               loc = &profile.Location{
+                       ID: nextLocID,
+                       Line: []profile.Line{
+                               {
+                                       Function: function,
+                               },
+                       },
+               }
+               nextLocID++
+               p.Location = append(p.Location, loc)
+               locs[locKey] = loc
+               return loc
+       }
+
+       makeLabelLocs := func(s *profile.Sample, keys []string) ([]*profile.Location, bool) {
+               var locs []*profile.Location
+               var match bool
+               for i := range keys {
+                       // Loop backwards, ensuring the first tag is closest to the root,
+                       // and the last tag is closest to the leaves.
+                       k := keys[len(keys)-1-i]
+                       values := formatLabelValues(s, k, outputUnit)
+                       if len(values) > 0 {
+                               match = true
+                       }
+                       locKey := locKey{
+                               functionName: strings.Join(values, ","),
+                               fileName:     k,
+                       }
+                       loc := internLoc(locKey)
+                       locs = append(locs, loc)
+               }
+               return locs, match
+       }
+
+       for _, s := range p.Sample {
+               rootsToAdd, sampleMatchedRoot := makeLabelLocs(s, rootKeys)
+               if sampleMatchedRoot {
+                       rootm = true
+               }
+               leavesToAdd, sampleMatchedLeaf := makeLabelLocs(s, leafKeys)
+               if sampleMatchedLeaf {
+                       leafm = true
+               }
+
+               var newLocs []*profile.Location
+               newLocs = append(newLocs, leavesToAdd...)
+               newLocs = append(newLocs, s.Location...)
+               newLocs = append(newLocs, rootsToAdd...)
+               s.Location = newLocs
+       }
+       return
+}
+
+// formatLabelValues returns all the string and numeric labels in Sample, with
+// the numeric labels formatted according to outputUnit.
+func formatLabelValues(s *profile.Sample, k string, outputUnit string) []string {
+       var values []string
+       values = append(values, s.Label[k]...)
+       numLabels := s.NumLabel[k]
+       numUnits := s.NumUnit[k]
+       if len(numLabels) != len(numUnits) {
+               return values
+       }
+       for i, numLabel := range numLabels {
+               unit := numUnits[i]
+               values = append(values, measurement.ScaledLabel(numLabel, unit, outputUnit))
+       }
+       return values
+}
index b8e8b50b94d63b9eb85ff381f7029c76523ce871..b9c73271b8c928783469546844e1b66b71144fd6 100644 (file)
@@ -132,6 +132,10 @@ a {
   align-items: center;
   justify-content: center;
 }
+.menu-name a {
+  text-decoration: none;
+  color: #212121;
+}
 .submenu {
   display: none;
   z-index: 1;
@@ -370,6 +374,12 @@ table tr td {
     </div>
   </div>
 
+  <div id="download" class="menu-item">
+    <div class="menu-name">
+      <a href="./download">Download</a>
+    </div>
+  </div>
+
   <div>
     <input id="search" type="text" placeholder="Search regexp" autocomplete="off" autocapitalize="none" size=40>
   </div>
index 52dc68809c7765712d4fa7810fafc86c359df74d..0f3e8bf93c44fbd9ead281a2bf3385928a1f7c22 100644 (file)
@@ -127,6 +127,11 @@ func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, d
                        "/flamegraph":   http.HandlerFunc(ui.flamegraph),
                        "/saveconfig":   http.HandlerFunc(ui.saveConfig),
                        "/deleteconfig": http.HandlerFunc(ui.deleteConfig),
+                       "/download": http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+                               w.Header().Set("Content-Type", "application/vnd.google.protobuf+gzip")
+                               w.Header().Set("Content-Disposition", "attachment;filename=profile.pb.gz")
+                               p.Write(w)
+                       }),
                },
        }
 
index 2638b2db2d9a95a5a74eb104a389127e59f1c97e..6447092d3d9978baeea75405fc441c0546d5c87e 100644 (file)
@@ -165,19 +165,61 @@ func GetBuildID(binary io.ReaderAt) ([]byte, error) {
        return nil, nil
 }
 
-// GetBase determines the base address to subtract from virtual
-// address to get symbol table address. For an executable, the base
-// is 0. Otherwise, it's a shared library, and the base is the
-// address where the mapping starts. The kernel is special, and may
-// use the address of the _stext symbol as the mmap start. _stext
-// offset can be obtained with `nm vmlinux | grep _stext`
-func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint64, start, limit, offset uint64) (uint64, error) {
+// kernelBase caluclates the base for kernel mappings, which usually require
+// special handling. For kernel mappings, tools (like perf) use the address of
+// the kernel relocation symbol (_text or _stext) as the mmap start. Additionaly,
+// for obfuscation, ChromeOS profiles have the kernel image remapped to the 0-th page.
+func kernelBase(loadSegment *elf.ProgHeader, stextOffset *uint64, start, limit, offset uint64) (uint64, bool) {
        const (
-               pageSize = 4096
                // PAGE_OFFSET for PowerPC64, see arch/powerpc/Kconfig in the kernel sources.
                pageOffsetPpc64 = 0xc000000000000000
+               pageSize        = 4096
        )
 
+       if loadSegment.Vaddr == start-offset {
+               return offset, true
+       }
+       if start == 0 && limit != 0 && stextOffset != nil {
+               // ChromeOS remaps its kernel to 0. Nothing else should come
+               // down this path. Empirical values:
+               //       VADDR=0xffffffff80200000
+               // stextOffset=0xffffffff80200198
+               return start - *stextOffset, true
+       }
+       if start >= loadSegment.Vaddr && limit > start && (offset == 0 || offset == pageOffsetPpc64 || offset == start) {
+               // Some kernels look like:
+               //       VADDR=0xffffffff80200000
+               // stextOffset=0xffffffff80200198
+               //       Start=0xffffffff83200000
+               //       Limit=0xffffffff84200000
+               //      Offset=0 (0xc000000000000000 for PowerPC64) (== Start for ASLR kernel)
+               // So the base should be:
+               if stextOffset != nil && (start%pageSize) == (*stextOffset%pageSize) {
+                       // perf uses the address of _stext as start. Some tools may
+                       // adjust for this before calling GetBase, in which case the page
+                       // alignment should be different from that of stextOffset.
+                       return start - *stextOffset, true
+               }
+
+               return start - loadSegment.Vaddr, true
+       }
+       if start%pageSize != 0 && stextOffset != nil && *stextOffset%pageSize == start%pageSize {
+               // ChromeOS remaps its kernel to 0 + start%pageSize. Nothing
+               // else should come down this path. Empirical values:
+               //       start=0x198 limit=0x2f9fffff offset=0
+               //       VADDR=0xffffffff81000000
+               // stextOffset=0xffffffff81000198
+               return start - *stextOffset, true
+       }
+       return 0, false
+}
+
+// GetBase determines the base address to subtract from virtual
+// address to get symbol table address. For an executable, the base
+// is 0. Otherwise, it's a shared library, and the base is the
+// address where the mapping starts. The kernel needs special hanldling.
+func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint64, start, limit, offset uint64) (uint64, error) {
+
        if start == 0 && offset == 0 && (limit == ^uint64(0) || limit == 0) {
                // Some tools may introduce a fake mapping that spans the entire
                // address space. Assume that the address has already been
@@ -202,43 +244,15 @@ func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint6
                        // the 64-bit address space.
                        return start - offset + loadSegment.Off - loadSegment.Vaddr, nil
                }
-               // Various kernel heuristics and cases follow.
-               if loadSegment.Vaddr == start-offset {
-                       return offset, nil
+               // Various kernel heuristics and cases are handled separately.
+               if base, match := kernelBase(loadSegment, stextOffset, start, limit, offset); match {
+                       return base, nil
                }
-               if start == 0 && limit != 0 {
-                       // ChromeOS remaps its kernel to 0. Nothing else should come
-                       // down this path. Empirical values:
-                       //       VADDR=0xffffffff80200000
-                       // stextOffset=0xffffffff80200198
-                       if stextOffset != nil {
-                               return -*stextOffset, nil
-                       }
-                       return -loadSegment.Vaddr, nil
-               }
-               if start >= loadSegment.Vaddr && limit > start && (offset == 0 || offset == pageOffsetPpc64 || offset == start) {
-                       // Some kernels look like:
-                       //       VADDR=0xffffffff80200000
-                       // stextOffset=0xffffffff80200198
-                       //       Start=0xffffffff83200000
-                       //       Limit=0xffffffff84200000
-                       //      Offset=0 (0xc000000000000000 for PowerPC64) (== Start for ASLR kernel)
-                       // So the base should be:
-                       if stextOffset != nil && (start%pageSize) == (*stextOffset%pageSize) {
-                               // perf uses the address of _stext as start. Some tools may
-                               // adjust for this before calling GetBase, in which case the page
-                               // alignment should be different from that of stextOffset.
-                               return start - *stextOffset, nil
-                       }
-
+               // ChromeOS can remap its kernel to 0, and the caller might have not found
+               // the _stext symbol. Split this case from kernelBase() above, since we don't
+               // want to apply it to an ET_DYN user-mode executable.
+               if start == 0 && limit != 0 && stextOffset == nil {
                        return start - loadSegment.Vaddr, nil
-               } else if start%pageSize != 0 && stextOffset != nil && *stextOffset%pageSize == start%pageSize {
-                       // ChromeOS remaps its kernel to 0 + start%pageSize. Nothing
-                       // else should come down this path. Empirical values:
-                       //       start=0x198 limit=0x2f9fffff offset=0
-                       //       VADDR=0xffffffff81000000
-                       // stextOffset=0xffffffff81000198
-                       return start - *stextOffset, nil
                }
 
                return 0, fmt.Errorf("don't know how to handle EXEC segment: %v start=0x%x limit=0x%x offset=0x%x", *loadSegment, start, limit, offset)
@@ -255,6 +269,11 @@ func GetBase(fh *elf.FileHeader, loadSegment *elf.ProgHeader, stextOffset *uint6
                if loadSegment == nil {
                        return start - offset, nil
                }
+               // Kernels compiled as PIE can be ET_DYN as well. Use heuristic, similar to
+               // the ET_EXEC case above.
+               if base, match := kernelBase(loadSegment, stextOffset, start, limit, offset); match {
+                       return base, nil
+               }
                // The program header, if not nil, indicates the offset in the file where
                // the executable segment is located (loadSegment.Off), and the base virtual
                // address where the first byte of the segment is loaded
@@ -284,10 +303,16 @@ func FindTextProgHeader(f *elf.File) *elf.ProgHeader {
        return nil
 }
 
-// ProgramHeadersForMapping returns the loadable program segment headers that
-// are fully contained in the runtime mapping with file offset pgoff and memory
-// size memsz, and if the binary includes any loadable segments.
-func ProgramHeadersForMapping(f *elf.File, pgoff, memsz uint64) ([]*elf.ProgHeader, bool) {
+// ProgramHeadersForMapping returns the program segment headers that overlap
+// the runtime mapping with file offset mapOff and memory size mapSz. We skip
+// over segments zero file size because their file offset values are unreliable.
+// Even if overlapping, a segment is not selected if its aligned file offset is
+// greater than the mapping file offset, or if the mapping includes the last
+// page of the segment, but not the full segment and the mapping includes
+// additional pages after the segment end.
+// The function returns a slice of pointers to the headers in the input
+// slice, which are valid only while phdrs is not modified or discarded.
+func ProgramHeadersForMapping(phdrs []elf.ProgHeader, mapOff, mapSz uint64) []*elf.ProgHeader {
        const (
                // pageSize defines the virtual memory page size used by the loader. This
                // value is dependent on the memory management unit of the CPU. The page
@@ -298,57 +323,61 @@ func ProgramHeadersForMapping(f *elf.File, pgoff, memsz uint64) ([]*elf.ProgHead
                // specified in the ELF file header.
                pageSize       = 4096
                pageOffsetMask = pageSize - 1
-               pageMask       = ^uint64(pageOffsetMask)
        )
+       mapLimit := mapOff + mapSz
        var headers []*elf.ProgHeader
-       hasLoadables := false
-       for _, p := range f.Progs {
-               // The segment must be fully included in the mapping.
-               if p.Type == elf.PT_LOAD && pgoff <= p.Off && p.Off+p.Memsz <= pgoff+memsz {
-                       alignedOffset := uint64(0)
+       for i := range phdrs {
+               p := &phdrs[i]
+               // Skip over segments with zero file size. Their file offsets can have
+               // arbitrary values, see b/195427553.
+               if p.Filesz == 0 {
+                       continue
+               }
+               segLimit := p.Off + p.Memsz
+               // The segment must overlap the mapping.
+               if p.Type == elf.PT_LOAD && mapOff < segLimit && p.Off < mapLimit {
+                       // If the mapping offset is strictly less than the page aligned segment
+                       // offset, then this mapping comes from a different segment, fixes
+                       // b/179920361.
+                       alignedSegOffset := uint64(0)
                        if p.Off > (p.Vaddr & pageOffsetMask) {
-                               alignedOffset = p.Off - (p.Vaddr & pageOffsetMask)
+                               alignedSegOffset = p.Off - (p.Vaddr & pageOffsetMask)
                        }
-                       if alignedOffset <= pgoff {
-                               headers = append(headers, &p.ProgHeader)
+                       if mapOff < alignedSegOffset {
+                               continue
                        }
+                       // If the mapping starts in the middle of the segment, it covers less than
+                       // one page of the segment, and it extends at least one page past the
+                       // segment, then this mapping comes from a different segment.
+                       if mapOff > p.Off && (segLimit < mapOff+pageSize) && (mapLimit >= segLimit+pageSize) {
+                               continue
+                       }
+                       headers = append(headers, p)
                }
-               if p.Type == elf.PT_LOAD {
-                       hasLoadables = true
-               }
-       }
-       if len(headers) < 2 {
-               return headers, hasLoadables
-       }
-
-       // If we have more than one matching segments, try a strict check on the
-       // segment memory size. We use a heuristic to compute the minimum mapping size
-       // required for a segment, assuming mappings are page aligned.
-       // The memory size based heuristic makes sense only if the mapping size is a
-       // multiple of page size.
-       if memsz%pageSize != 0 {
-               return headers, hasLoadables
        }
+       return headers
+}
 
-       // Return all found headers if we cannot narrow the selection to a single
-       // program segment.
+// HeaderForFileOffset attempts to identify a unique program header that
+// includes the given file offset. It returns an error if it cannot identify a
+// unique header.
+func HeaderForFileOffset(headers []*elf.ProgHeader, fileOffset uint64) (*elf.ProgHeader, error) {
        var ph *elf.ProgHeader
        for _, h := range headers {
-               wantSize := (h.Vaddr+h.Memsz+pageSize-1)&pageMask - (h.Vaddr & pageMask)
-               if wantSize != memsz {
-                       continue
-               }
-               if ph != nil {
-                       // Found a second program header matching, so return all previously
-                       // identified headers.
-                       return headers, hasLoadables
+               if fileOffset >= h.Off && fileOffset < h.Off+h.Memsz {
+                       if ph != nil {
+                               // Assuming no other bugs, this can only happen if we have two or
+                               // more small program segments that fit on the same page, and a
+                               // segment other than the last one includes uninitialized data, or
+                               // if the debug binary used for symbolization is stripped of some
+                               // sections, so segment file sizes are smaller than memory sizes.
+                               return nil, fmt.Errorf("found second program header (%#v) that matches file offset %x, first program header is %#v. Is this a stripped binary, or does the first program segment contain uninitialized data?", *h, fileOffset, *ph)
+                       }
+                       ph = h
                }
-               ph = h
        }
        if ph == nil {
-               // No matching header for the strict check. Return all previously identified
-               // headers.
-               return headers, hasLoadables
+               return nil, fmt.Errorf("no program header matches file offset %x", fileOffset)
        }
-       return []*elf.ProgHeader{ph}, hasLoadables
+       return ph, nil
 }
index 4a86554880132d11fa44384b1c95bfc88326d343..e2fb00314ca0ab437b6362891093bb0929c112c1 100644 (file)
@@ -432,6 +432,10 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e
                }
        }
 
+       if len(syms) == 0 {
+               return fmt.Errorf("no matches found for regexp: %s", o.Symbol)
+       }
+
        // Correlate the symbols from the binary with the profile samples.
        for _, s := range syms {
                sns := symNodes[s]
@@ -1054,6 +1058,7 @@ func printTree(w io.Writer, rpt *Report) error {
        var flatSum int64
 
        rx := rpt.options.Symbol
+       matched := 0
        for _, n := range g.Nodes {
                name, flat, cum := n.Info.PrintableName(), n.FlatValue(), n.CumValue()
 
@@ -1061,6 +1066,7 @@ func printTree(w io.Writer, rpt *Report) error {
                if rx != nil && !rx.MatchString(name) {
                        continue
                }
+               matched++
 
                fmt.Fprintln(w, separator)
                // Print incoming edges.
@@ -1098,6 +1104,9 @@ func printTree(w io.Writer, rpt *Report) error {
        if len(g.Nodes) > 0 {
                fmt.Fprintln(w, separator)
        }
+       if rx != nil && matched == 0 {
+               return fmt.Errorf("no matches found for regexp: %s", rx)
+       }
        return nil
 }
 
index 54245e5f9ea6a0f2848f6a0b4a063a52bffd03e3..33d04c591d9beba025eb1911f0cbb25be7fd4e67 100644 (file)
@@ -58,6 +58,10 @@ func printSource(w io.Writer, rpt *Report) error {
        }
        functions.Sort(graph.NameOrder)
 
+       if len(functionNodes) == 0 {
+               return fmt.Errorf("no matches found for regexp: %s", o.Symbol)
+       }
+
        sourcePath := o.SourcePath
        if sourcePath == "" {
                wd, err := os.Getwd()
@@ -206,6 +210,9 @@ func PrintWebList(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFiles int) er
                sourcePath = wd
        }
        sp := newSourcePrinter(rpt, obj, sourcePath)
+       if len(sp.interest) == 0 {
+               return fmt.Errorf("no matches found for regexp: %s", rpt.options.Symbol)
+       }
        sp.print(w, maxFiles, rpt)
        sp.close()
        return nil
@@ -299,7 +306,7 @@ func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourc
                                continue
                        }
 
-                       // Seach in inlined stack for a match.
+                       // Search in inlined stack for a match.
                        matchFile := (loc.Mapping != nil && sp.sym.MatchString(loc.Mapping.File))
                        for j, line := range loc.Line {
                                if (j == 0 && matchFile) || matches(line) {
index 17c9f6eb947c512a0a8f253cfa00f4b1eed94512..851693f1d0e6d717357d4c567b7108d7069f8ec0 100644 (file)
@@ -72,5 +72,4 @@ function pprof_toggle_asm(e) {
 
 const weblistPageClosing = `
 </body>
-</html>
-`
+</html>`
index ef3f94a63d7dd6cda1bea346c255a4d86380243a..2c01cae088fef3e867c2a8c37d19d60f8b277257 100644 (file)
@@ -1,3 +1,3 @@
 # github.com/ianlancetaylor/demangle
 
-A Go package that can be used to demangle C++ symbol names.
+A Go package that can be used to demangle C++ and Rust symbol names.
index ccbe5b355988b2786d30d4b2ff3b8930a6345dbf..7b9178f1bb09e0b2ad985a40a4758585f716506a 100644 (file)
@@ -11,6 +11,7 @@ import (
 
 // AST is an abstract syntax tree representing a C++ declaration.
 // This is sufficient for the demangler but is by no means a general C++ AST.
+// This abstract syntax tree is only used for C++ symbols, not Rust symbols.
 type AST interface {
        // Internal method to convert to demangled string.
        print(*printState)
@@ -37,21 +38,25 @@ type AST interface {
 // ASTToString returns the demangled name of the AST.
 func ASTToString(a AST, options ...Option) string {
        tparams := true
+       llvmStyle := false
        for _, o := range options {
                switch o {
                case NoTemplateParams:
                        tparams = false
+               case LLVMStyle:
+                       llvmStyle = true
                }
        }
 
-       ps := printState{tparams: tparams}
+       ps := printState{tparams: tparams, llvmStyle: llvmStyle}
        a.print(&ps)
        return ps.buf.String()
 }
 
 // The printState type holds information needed to print an AST.
 type printState struct {
-       tparams bool // whether to print template parameters
+       tparams   bool // whether to print template parameters
+       llvmStyle bool
 
        buf  strings.Builder
        last byte // Last byte written to buffer.
@@ -408,7 +413,11 @@ type LambdaAuto struct {
 func (la *LambdaAuto) print(ps *printState) {
        // We print the index plus 1 because that is what the standard
        // demangler does.
-       fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1)
+       if ps.llvmStyle {
+               ps.writeString("auto")
+       } else {
+               fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1)
+       }
 }
 
 func (la *LambdaAuto) Traverse(fn func(AST) bool) {
@@ -504,6 +513,9 @@ func (q *Qualifier) print(ps *printState) {
                ps.writeByte('(')
                first := true
                for _, e := range q.Exprs {
+                       if el, ok := e.(*ExprList); ok && len(el.Exprs) == 0 {
+                               continue
+                       }
                        if !first {
                                ps.writeString(", ")
                        }
@@ -715,7 +727,11 @@ type BuiltinType struct {
 }
 
 func (bt *BuiltinType) print(ps *printState) {
-       ps.writeString(bt.Name)
+       name := bt.Name
+       if ps.llvmStyle && name == "decltype(nullptr)" {
+               name = "std::nullptr_t"
+       }
+       ps.writeString(name)
 }
 
 func (bt *BuiltinType) Traverse(fn func(AST) bool) {
@@ -970,10 +986,15 @@ type VendorQualifier struct {
 }
 
 func (vq *VendorQualifier) print(ps *printState) {
-       ps.inner = append(ps.inner, vq)
-       ps.print(vq.Type)
-       if len(ps.inner) > 0 {
-               ps.printOneInner(nil)
+       if ps.llvmStyle {
+               ps.print(vq.Type)
+               vq.printInner(ps)
+       } else {
+               ps.inner = append(ps.inner, vq)
+               ps.print(vq.Type)
+               if len(ps.inner) > 0 {
+                       ps.printOneInner(nil)
+               }
        }
 }
 
@@ -1110,19 +1131,27 @@ func (at *ArrayType) goString(indent int, field string) string {
                at.Element.goString(indent+2, "Element: "))
 }
 
-// FunctionType is a function type.  The Return field may be nil for
-// cases where the return type is not part of the mangled name.
+// FunctionType is a function type.
 type FunctionType struct {
        Return AST
        Args   []AST
+
+       // The forLocalName field reports whether this FunctionType
+       // was created for a local name. With the default GNU demangling
+       // output we don't print the return type in that case.
+       ForLocalName bool
 }
 
 func (ft *FunctionType) print(ps *printState) {
-       if ft.Return != nil {
+       retType := ft.Return
+       if ft.ForLocalName && !ps.llvmStyle {
+               retType = nil
+       }
+       if retType != nil {
                // Pass the return type as an inner type in order to
                // print the arguments in the right location.
                ps.inner = append(ps.inner, ft)
-               ps.print(ft.Return)
+               ps.print(retType)
                if len(ps.inner) == 0 {
                        // Everything was printed.
                        return
@@ -1227,7 +1256,11 @@ func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
        if !changed {
                return fn(ft)
        }
-       ft = &FunctionType{Return: ret, Args: args}
+       ft = &FunctionType{
+               Return:       ret,
+               Args:         args,
+               ForLocalName: ft.ForLocalName,
+       }
        if r := fn(ft); r != nil {
                return r
        }
@@ -1239,6 +1272,10 @@ func (ft *FunctionType) GoString() string {
 }
 
 func (ft *FunctionType) goString(indent int, field string) string {
+       var forLocalName string
+       if ft.ForLocalName {
+               forLocalName = " ForLocalName: true"
+       }
        var r string
        if ft.Return == nil {
                r = fmt.Sprintf("%*sReturn: nil", indent+2, "")
@@ -1255,7 +1292,8 @@ func (ft *FunctionType) goString(indent int, field string) string {
                        args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
                }
        }
-       return fmt.Sprintf("%*s%sFunctionType:\n%s\n%s", indent, "", field, r, args)
+       return fmt.Sprintf("%*s%sFunctionType:%s\n%s\n%s", indent, "", field,
+               forLocalName, r, args)
 }
 
 // FunctionParam is a parameter of a function, used for last-specified
@@ -1267,6 +1305,12 @@ type FunctionParam struct {
 func (fp *FunctionParam) print(ps *printState) {
        if fp.Index == 0 {
                ps.writeString("this")
+       } else if ps.llvmStyle {
+               if fp.Index == 1 {
+                       ps.writeString("fp")
+               } else {
+                       fmt.Fprintf(&ps.buf, "fp%d", fp.Index-2)
+               }
        } else {
                fmt.Fprintf(&ps.buf, "{parm#%d}", fp.Index)
        }
@@ -1422,9 +1466,15 @@ func (vt *VectorType) print(ps *printState) {
 }
 
 func (vt *VectorType) printInner(ps *printState) {
-       ps.writeString(" __vector(")
+       end := byte(')')
+       if ps.llvmStyle {
+               ps.writeString(" vector[")
+               end = ']'
+       } else {
+               ps.writeString(" __vector(")
+       }
        ps.print(vt.Dimension)
-       ps.writeByte(')')
+       ps.writeByte(end)
 }
 
 func (vt *VectorType) Traverse(fn func(AST) bool) {
@@ -1466,13 +1516,59 @@ func (vt *VectorType) goString(indent int, field string) string {
                vt.Base.goString(indent+2, "Base: "))
 }
 
+// ElaboratedType is an elaborated struct/union/enum type.
+type ElaboratedType struct {
+       Kind string
+       Type AST
+}
+
+func (et *ElaboratedType) print(ps *printState) {
+       ps.writeString(et.Kind)
+       ps.writeString(" ")
+       et.Type.print(ps)
+}
+
+func (et *ElaboratedType) Traverse(fn func(AST) bool) {
+       if fn(et) {
+               et.Type.Traverse(fn)
+       }
+}
+
+func (et *ElaboratedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(et) {
+               return nil
+       }
+       typ := et.Type.Copy(fn, skip)
+       if typ == nil {
+               return fn(et)
+       }
+       et = &ElaboratedType{Kind: et.Kind, Type: typ}
+       if r := fn(et); r != nil {
+               return r
+       }
+       return et
+}
+
+func (et *ElaboratedType) GoString() string {
+       return et.goString(0, "")
+}
+
+func (et *ElaboratedType) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sElaboratedtype: Kind: %s\n%s", indent, "", field,
+               et.Kind, et.Type.goString(indent+2, "Expr: "))
+}
+
 // Decltype is the decltype operator.
 type Decltype struct {
        Expr AST
 }
 
 func (dt *Decltype) print(ps *printState) {
-       ps.writeString("decltype (")
+       ps.writeString("decltype")
+       if !ps.llvmStyle {
+               ps.writeString(" ")
+       }
+       ps.writeString("(")
        ps.print(dt.Expr)
        ps.writeByte(')')
 }
@@ -1544,15 +1640,20 @@ func (op *Operator) goString(indent int, field string) string {
 // Constructor is a constructor.
 type Constructor struct {
        Name AST
+       Base AST // base class of inheriting constructor
 }
 
 func (c *Constructor) print(ps *printState) {
        ps.print(c.Name)
+       // We don't include the base class in the demangled string.
 }
 
 func (c *Constructor) Traverse(fn func(AST) bool) {
        if fn(c) {
                c.Name.Traverse(fn)
+               if c.Base != nil {
+                       c.Base.Traverse(fn)
+               }
        }
 }
 
@@ -1561,10 +1662,20 @@ func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
                return nil
        }
        name := c.Name.Copy(fn, skip)
-       if name == nil {
+       var base AST
+       if c.Base != nil {
+               base = c.Base.Copy(fn, skip)
+       }
+       if name == nil && base == nil {
                return fn(c)
        }
-       c = &Constructor{Name: name}
+       if name == nil {
+               name = c.Name
+       }
+       if base == nil {
+               base = c.Base
+       }
+       c = &Constructor{Name: name, Base: base}
        if r := fn(c); r != nil {
                return r
        }
@@ -1576,7 +1687,13 @@ func (c *Constructor) GoString() string {
 }
 
 func (c *Constructor) goString(indent int, field string) string {
-       return fmt.Sprintf("%*s%sConstructor:\n%s", indent, "", field, c.Name.goString(indent+2, "Name: "))
+       var sb strings.Builder
+       fmt.Fprintf(&sb, "%*s%sConstructor:\n", indent, "", field)
+       if c.Base != nil {
+               fmt.Fprintf(&sb, "%s\n", c.Base.goString(indent+2, "Base: "))
+       }
+       fmt.Fprintf(&sb, "%s", c.Name.goString(indent+2, "Name: "))
+       return sb.String()
 }
 
 // Destructor is a destructor.
@@ -1727,8 +1844,12 @@ func (pe *PackExpansion) print(ps *printState) {
        // We normally only get here if the simplify function was
        // unable to locate and expand the pack.
        if pe.Pack == nil {
-               parenthesize(ps, pe.Base)
-               ps.writeString("...")
+               if ps.llvmStyle {
+                       ps.print(pe.Base)
+               } else {
+                       parenthesize(ps, pe.Base)
+                       ps.writeString("...")
+               }
        } else {
                ps.print(pe.Base)
        }
@@ -1834,7 +1955,13 @@ type SizeofPack struct {
 }
 
 func (sp *SizeofPack) print(ps *printState) {
-       ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
+       if ps.llvmStyle {
+               ps.writeString("sizeof...(")
+               ps.print(sp.Pack)
+               ps.writeByte(')')
+       } else {
+               ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
+       }
 }
 
 func (sp *SizeofPack) Traverse(fn func(AST) bool) {
@@ -1932,6 +2059,287 @@ func (sa *SizeofArgs) goString(indent int, field string) string {
        return fmt.Sprintf("%*s%sSizeofArgs:\n%s", indent, "", field, args)
 }
 
+// TemplateParamName is the name of a template parameter that the
+// demangler introduced for a lambda that has explicit template
+// parameters.  This is a prefix with an index.
+type TemplateParamName struct {
+       Prefix string
+       Index  int
+}
+
+func (tpn *TemplateParamName) print(ps *printState) {
+       ps.writeString(tpn.Prefix)
+       if tpn.Index > 0 {
+               ps.writeString(fmt.Sprintf("%d", tpn.Index-1))
+       }
+}
+
+func (tpn *TemplateParamName) Traverse(fn func(AST) bool) {
+       fn(tpn)
+}
+
+func (tpn *TemplateParamName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(tpn) {
+               return nil
+       }
+       return fn(tpn)
+}
+
+func (tpn *TemplateParamName) GoString() string {
+       return tpn.goString(0, "")
+}
+
+func (tpn *TemplateParamName) goString(indent int, field string) string {
+       name := tpn.Prefix
+       if tpn.Index > 0 {
+               name += fmt.Sprintf("%d", tpn.Index-1)
+       }
+       return fmt.Sprintf("%*s%sTemplateParamName: %s", indent, "", field, name)
+}
+
+// TypeTemplateParam is a type template parameter that appears in a
+// lambda with explicit template parameters.
+type TypeTemplateParam struct {
+       Name AST
+}
+
+func (ttp *TypeTemplateParam) print(ps *printState) {
+       ps.writeString("typename ")
+       ps.printInner(false)
+       ps.print(ttp.Name)
+}
+
+func (ttp *TypeTemplateParam) Traverse(fn func(AST) bool) {
+       if fn(ttp) {
+               ttp.Name.Traverse(fn)
+       }
+}
+
+func (ttp *TypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(ttp) {
+               return nil
+       }
+       name := ttp.Name.Copy(fn, skip)
+       if name == nil {
+               return fn(ttp)
+       }
+       ttp = &TypeTemplateParam{Name: name}
+       if r := fn(ttp); r != nil {
+               return r
+       }
+       return ttp
+}
+
+func (ttp *TypeTemplateParam) GoString() string {
+       return ttp.goString(0, "")
+}
+
+func (ttp *TypeTemplateParam) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sTypeTemplateParam:\n%s", indent, "", field,
+               ttp.Name.goString(indent+2, "Name"))
+}
+
+// NonTypeTemplateParam is a non-type template parameter that appears
+// in a lambda with explicit template parameters.
+type NonTypeTemplateParam struct {
+       Name AST
+       Type AST
+}
+
+func (nttp *NonTypeTemplateParam) print(ps *printState) {
+       ps.inner = append(ps.inner, nttp)
+       ps.print(nttp.Type)
+       if len(ps.inner) > 0 {
+               ps.writeByte(' ')
+               ps.print(nttp.Name)
+               ps.inner = ps.inner[:len(ps.inner)-1]
+       }
+}
+
+func (nttp *NonTypeTemplateParam) printInner(ps *printState) {
+       ps.print(nttp.Name)
+}
+
+func (nttp *NonTypeTemplateParam) Traverse(fn func(AST) bool) {
+       if fn(nttp) {
+               nttp.Name.Traverse(fn)
+               nttp.Type.Traverse(fn)
+       }
+}
+
+func (nttp *NonTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(nttp) {
+               return nil
+       }
+       name := nttp.Name.Copy(fn, skip)
+       typ := nttp.Type.Copy(fn, skip)
+       if name == nil && typ == nil {
+               return fn(nttp)
+       }
+       if name == nil {
+               name = nttp.Name
+       }
+       if typ == nil {
+               typ = nttp.Type
+       }
+       nttp = &NonTypeTemplateParam{Name: name, Type: typ}
+       if r := fn(nttp); r != nil {
+               return r
+       }
+       return nttp
+}
+
+func (nttp *NonTypeTemplateParam) GoString() string {
+       return nttp.goString(0, "")
+}
+
+func (nttp *NonTypeTemplateParam) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sNonTypeTemplateParam:\n%s\n%s", indent, "", field,
+               nttp.Name.goString(indent+2, "Name: "),
+               nttp.Type.goString(indent+2, "Type: "))
+}
+
+// TemplateTemplateParam is a template template parameter that appears
+// in a lambda with explicit template parameters.
+type TemplateTemplateParam struct {
+       Name   AST
+       Params []AST
+}
+
+func (ttp *TemplateTemplateParam) print(ps *printState) {
+       ps.writeString("template<")
+       for i, param := range ttp.Params {
+               if i > 0 {
+                       ps.writeString(", ")
+               }
+               ps.print(param)
+       }
+       ps.writeString("> typename ")
+       ps.print(ttp.Name)
+}
+
+func (ttp *TemplateTemplateParam) Traverse(fn func(AST) bool) {
+       if fn(ttp) {
+               ttp.Name.Traverse(fn)
+               for _, param := range ttp.Params {
+                       param.Traverse(fn)
+               }
+       }
+}
+
+func (ttp *TemplateTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(ttp) {
+               return nil
+       }
+
+       changed := false
+
+       name := ttp.Name.Copy(fn, skip)
+       if name == nil {
+               name = ttp.Name
+       } else {
+               changed = true
+       }
+
+       params := make([]AST, len(ttp.Params))
+       for i, p := range ttp.Params {
+               pc := p.Copy(fn, skip)
+               if pc == nil {
+                       params[i] = p
+               } else {
+                       params[i] = pc
+                       changed = true
+               }
+       }
+
+       if !changed {
+               return fn(ttp)
+       }
+
+       ttp = &TemplateTemplateParam{
+               Name:   name,
+               Params: params,
+       }
+       if r := fn(ttp); r != nil {
+               return r
+       }
+       return ttp
+}
+
+func (ttp *TemplateTemplateParam) GoString() string {
+       return ttp.goString(0, "")
+}
+
+func (ttp *TemplateTemplateParam) goString(indent int, field string) string {
+       var params strings.Builder
+       fmt.Fprintf(&params, "%*sParams:", indent+2, "")
+       for i, p := range ttp.Params {
+               params.WriteByte('\n')
+               params.WriteString(p.goString(indent+4, fmt.Sprintf("%d: ", i)))
+       }
+       return fmt.Sprintf("%*s%sTemplateTemplateParam:\n%s\n%s", indent, "", field,
+               ttp.Name.goString(indent+2, "Name: "),
+               params.String())
+}
+
+// TemplateParamPack is a template parameter pack that appears in a
+// lambda with explicit template parameters.
+type TemplateParamPack struct {
+       Param AST
+}
+
+func (tpp *TemplateParamPack) print(ps *printState) {
+       holdInner := ps.inner
+       defer func() { ps.inner = holdInner }()
+
+       ps.inner = []AST{tpp}
+       if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok {
+               ps.print(nttp.Type)
+       } else {
+               ps.print(tpp.Param)
+       }
+       if len(ps.inner) > 0 {
+               ps.writeString("...")
+       }
+}
+
+func (tpp *TemplateParamPack) printInner(ps *printState) {
+       ps.writeString("...")
+       if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok {
+               ps.print(nttp.Name)
+       }
+}
+
+func (tpp *TemplateParamPack) Traverse(fn func(AST) bool) {
+       if fn(tpp) {
+               tpp.Param.Traverse(fn)
+       }
+}
+
+func (tpp *TemplateParamPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(tpp) {
+               return nil
+       }
+       param := tpp.Param.Copy(fn, skip)
+       if param == nil {
+               return fn(tpp)
+       }
+       tpp = &TemplateParamPack{Param: param}
+       if r := fn(tpp); r != nil {
+               return r
+       }
+       return tpp
+}
+
+func (tpp *TemplateParamPack) GoString() string {
+       return tpp.goString(0, "")
+}
+
+func (tpp *TemplateParamPack) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sTemplateParamPack:\n%s", indent, "", field,
+               tpp.Param.goString(indent+2, "Param: "))
+}
+
 // Cast is a type cast.
 type Cast struct {
        To AST
@@ -1977,7 +2385,11 @@ func (c *Cast) goString(indent int, field string) string {
 func parenthesize(ps *printState, val AST) {
        paren := false
        switch v := val.(type) {
-       case *Name, *InitializerList, *FunctionParam:
+       case *Name, *InitializerList:
+       case *FunctionParam:
+               if ps.llvmStyle {
+                       paren = true
+               }
        case *Qualified:
                if v.LocalName {
                        paren = true
@@ -2047,14 +2459,17 @@ type Unary struct {
 }
 
 func (u *Unary) print(ps *printState) {
+       op, _ := u.Op.(*Operator)
        expr := u.Expr
 
        // Don't print the argument list when taking the address of a
        // function.
-       if op, ok := u.Op.(*Operator); ok && op.Name == "&" {
-               if t, ok := expr.(*Typed); ok {
-                       if _, ok := t.Type.(*FunctionType); ok {
-                               expr = t.Name
+       if !ps.llvmStyle {
+               if op != nil && op.Name == "&" {
+                       if t, ok := expr.(*Typed); ok {
+                               if _, ok := t.Type.(*FunctionType); ok {
+                                       expr = t.Name
+                               }
                        }
                }
        }
@@ -2063,8 +2478,11 @@ func (u *Unary) print(ps *printState) {
                parenthesize(ps, expr)
        }
 
-       if op, ok := u.Op.(*Operator); ok {
+       if op != nil {
                ps.writeString(op.Name)
+               if ps.llvmStyle && op.Name == "noexcept" {
+                       ps.writeByte(' ')
+               }
        } else if c, ok := u.Op.(*Cast); ok {
                ps.writeByte('(')
                ps.print(c.To)
@@ -2074,7 +2492,7 @@ func (u *Unary) print(ps *printState) {
        }
 
        if !u.Suffix {
-               if op, ok := u.Op.(*Operator); ok && op.Name == "::" {
+               if op != nil && op.Name == "::" {
                        // Don't use parentheses after ::.
                        ps.print(expr)
                } else if u.SizeofType {
@@ -2082,6 +2500,19 @@ func (u *Unary) print(ps *printState) {
                        ps.writeByte('(')
                        ps.print(expr)
                        ps.writeByte(')')
+               } else if op != nil && op.Name == "__alignof__" {
+                       // Always use parentheses for __alignof__ argument.
+                       ps.writeByte('(')
+                       ps.print(expr)
+                       ps.writeByte(')')
+               } else if ps.llvmStyle {
+                       if op == nil || op.Name != `operator"" ` {
+                               ps.writeByte('(')
+                       }
+                       ps.print(expr)
+                       if op == nil || op.Name != `operator"" ` {
+                               ps.writeByte(')')
+                       }
                } else {
                        parenthesize(ps, expr)
                }
@@ -2140,7 +2571,16 @@ func isDesignatedInitializer(x AST) bool {
        switch x := x.(type) {
        case *Binary:
                if op, ok := x.Op.(*Operator); ok {
-                       return op.Name == "=" || op.Name == "]="
+                       if op.Name == "]=" {
+                               return true
+                       }
+                       if op.Name != "=" {
+                               return false
+                       }
+                       if _, ok := x.Left.(*Literal); ok {
+                               return false
+                       }
+                       return true
                }
        case *Trinary:
                if op, ok := x.Op.(*Operator); ok {
@@ -2185,8 +2625,13 @@ func (b *Binary) print(ps *printState) {
                        // initializer chains.
                        ps.print(b.Right)
                } else {
-                       ps.writeByte('=')
-                       parenthesize(ps, b.Right)
+                       if ps.llvmStyle {
+                               ps.writeString(" = ")
+                               ps.print(b.Right)
+                       } else {
+                               ps.writeByte('=')
+                               parenthesize(ps, b.Right)
+                       }
                }
                return
        }
@@ -2200,9 +2645,19 @@ func (b *Binary) print(ps *printState) {
 
        left := b.Left
 
+       skipParens := false
+       skipBothParens := false
+       addSpaces := ps.llvmStyle
+       if ps.llvmStyle && op != nil {
+               switch op.Name {
+               case ".", "->":
+                       skipBothParens = true
+                       addSpaces = false
+               }
+       }
+
        // For a function call in an expression, don't print the types
        // of the arguments unless there is a return type.
-       skipParens := false
        if op != nil && op.Name == "()" {
                if ty, ok := b.Left.(*Typed); ok {
                        if ft, ok := ty.Type.(*FunctionType); ok {
@@ -2215,10 +2670,17 @@ func (b *Binary) print(ps *printState) {
                                left = ty.Name
                        }
                }
+               if ps.llvmStyle {
+                       skipParens = true
+               }
        }
 
-       if skipParens {
+       if skipParens || skipBothParens {
                ps.print(left)
+       } else if ps.llvmStyle {
+               ps.writeByte('(')
+               ps.print(left)
+               ps.writeByte(')')
        } else {
                parenthesize(ps, left)
        }
@@ -2232,13 +2694,27 @@ func (b *Binary) print(ps *printState) {
 
        if op != nil {
                if op.Name != "()" {
+                       if addSpaces {
+                               ps.writeByte(' ')
+                       }
                        ps.writeString(op.Name)
+                       if addSpaces {
+                               ps.writeByte(' ')
+                       }
                }
        } else {
                ps.print(b.Op)
        }
 
-       parenthesize(ps, b.Right)
+       if skipBothParens {
+               ps.print(b.Right)
+       } else if ps.llvmStyle {
+               ps.writeByte('(')
+               ps.print(b.Right)
+               ps.writeByte(')')
+       } else {
+               parenthesize(ps, b.Right)
+       }
 
        if op != nil && op.Name == ">" {
                ps.writeByte(')')
@@ -2310,14 +2786,23 @@ func (t *Trinary) print(ps *printState) {
                        // initializer chains.
                        ps.print(t.Third)
                } else {
-                       ps.writeByte('=')
-                       parenthesize(ps, t.Third)
+                       if ps.llvmStyle {
+                               ps.writeString(" = ")
+                               ps.print(t.Third)
+                       } else {
+                               ps.writeByte('=')
+                               parenthesize(ps, t.Third)
+                       }
                }
                return
        }
 
        parenthesize(ps, t.First)
-       ps.writeByte('?')
+       if ps.llvmStyle {
+               ps.writeString(" ? ")
+       } else {
+               ps.writeByte('?')
+       }
        parenthesize(ps, t.Second)
        ps.writeString(" : ")
        parenthesize(ps, t.Third)
@@ -2386,31 +2871,44 @@ func (f *Fold) print(ps *printState) {
        op, _ := f.Op.(*Operator)
        printOp := func() {
                if op != nil {
+                       if ps.llvmStyle {
+                               ps.writeByte(' ')
+                       }
                        ps.writeString(op.Name)
+                       if ps.llvmStyle {
+                               ps.writeByte(' ')
+                       }
                } else {
                        ps.print(f.Op)
                }
        }
+       foldParenthesize := func(a AST) {
+               if _, ok := a.(*ArgumentPack); ok || !ps.llvmStyle {
+                       parenthesize(ps, a)
+               } else {
+                       ps.print(a)
+               }
+       }
 
        if f.Arg2 == nil {
                if f.Left {
                        ps.writeString("(...")
                        printOp()
-                       parenthesize(ps, f.Arg1)
+                       foldParenthesize(f.Arg1)
                        ps.writeString(")")
                } else {
                        ps.writeString("(")
-                       parenthesize(ps, f.Arg1)
+                       foldParenthesize(f.Arg1)
                        printOp()
                        ps.writeString("...)")
                }
        } else {
                ps.writeString("(")
-               parenthesize(ps, f.Arg1)
+               foldParenthesize(f.Arg1)
                printOp()
                ps.writeString("...")
                printOp()
-               parenthesize(ps, f.Arg2)
+               foldParenthesize(f.Arg2)
                ps.writeString(")")
        }
 }
@@ -2471,6 +2969,143 @@ func (f *Fold) goString(indent int, field string) string {
        }
 }
 
+// Subobject is a a reference to an offset in an expression.  This is
+// used for C++20 manglings of class types used as the type of
+// non-type template arguments.
+//
+// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
+type Subobject struct {
+       Type      AST
+       SubExpr   AST
+       Offset    int
+       Selectors []int
+       PastEnd   bool
+}
+
+func (so *Subobject) print(ps *printState) {
+       ps.print(so.SubExpr)
+       ps.writeString(".<")
+       ps.print(so.Type)
+       ps.writeString(fmt.Sprintf(" at offset %d>", so.Offset))
+}
+
+func (so *Subobject) Traverse(fn func(AST) bool) {
+       if fn(so) {
+               so.Type.Traverse(fn)
+               so.SubExpr.Traverse(fn)
+       }
+}
+
+func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(so) {
+               return nil
+       }
+       typ := so.Type.Copy(fn, skip)
+       subExpr := so.SubExpr.Copy(fn, skip)
+       if typ == nil && subExpr == nil {
+               return nil
+       }
+       if typ == nil {
+               typ = so.Type
+       }
+       if subExpr == nil {
+               subExpr = so.SubExpr
+       }
+       so = &Subobject{
+               Type:      typ,
+               SubExpr:   subExpr,
+               Offset:    so.Offset,
+               Selectors: so.Selectors,
+               PastEnd:   so.PastEnd,
+       }
+       if r := fn(so); r != nil {
+               return r
+       }
+       return so
+}
+
+func (so *Subobject) GoString() string {
+       return so.goString(0, "")
+}
+
+func (so *Subobject) goString(indent int, field string) string {
+       var selectors string
+       for _, s := range so.Selectors {
+               selectors += fmt.Sprintf(" %d", s)
+       }
+       return fmt.Sprintf("%*s%sSubobject:\n%s\n%s\n%*sOffset: %d\n%*sSelectors:%s\n%*sPastEnd: %t",
+               indent, "", field,
+               so.Type.goString(indent+2, "Type: "),
+               so.SubExpr.goString(indent+2, "SubExpr: "),
+               indent+2, "", so.Offset,
+               indent+2, "", selectors,
+               indent+2, "", so.PastEnd)
+}
+
+// PtrMemCast is a conversion of an expression to a pointer-to-member
+// type.  This is used for C++20 manglings of class types used as the
+// type of non-type template arguments.
+//
+// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
+type PtrMemCast struct {
+       Type   AST
+       Expr   AST
+       Offset int
+}
+
+func (pmc *PtrMemCast) print(ps *printState) {
+       ps.writeString("(")
+       ps.print(pmc.Type)
+       ps.writeString(")(")
+       ps.print(pmc.Expr)
+       ps.writeString(")")
+}
+
+func (pmc *PtrMemCast) Traverse(fn func(AST) bool) {
+       if fn(pmc) {
+               pmc.Type.Traverse(fn)
+               pmc.Expr.Traverse(fn)
+       }
+}
+
+func (pmc *PtrMemCast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(pmc) {
+               return nil
+       }
+       typ := pmc.Type.Copy(fn, skip)
+       expr := pmc.Expr.Copy(fn, skip)
+       if typ == nil && expr == nil {
+               return nil
+       }
+       if typ == nil {
+               typ = pmc.Type
+       }
+       if expr == nil {
+               expr = pmc.Expr
+       }
+       pmc = &PtrMemCast{
+               Type:   typ,
+               Expr:   expr,
+               Offset: pmc.Offset,
+       }
+       if r := fn(pmc); r != nil {
+               return r
+       }
+       return pmc
+}
+
+func (pmc *PtrMemCast) GoString() string {
+       return pmc.goString(0, "")
+}
+
+func (pmc *PtrMemCast) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sPtrMemCast:\n%s\n%s\n%*sOffset: %d",
+               indent, "", field,
+               pmc.Type.goString(indent+2, "Type: "),
+               pmc.Expr.goString(indent+2, "Expr: "),
+               indent+2, "", pmc.Offset)
+}
+
 // New is a use of operator new in an expression.
 type New struct {
        Op    AST
@@ -2609,7 +3244,11 @@ func (l *Literal) print(ps *printState) {
                                return
                        }
                } else if b.Name == "decltype(nullptr)" && l.Val == "" {
-                       ps.print(l.Type)
+                       if ps.llvmStyle {
+                               ps.writeString("nullptr")
+                       } else {
+                               ps.print(l.Type)
+                       }
                        return
                } else {
                        isFloat = builtinTypeFloat[b.Name]
@@ -2667,6 +3306,90 @@ func (l *Literal) goString(indent int, field string) string {
                indent+2, "", l.Val)
 }
 
+// StringLiteral is a string literal.
+type StringLiteral struct {
+       Type AST
+}
+
+func (sl *StringLiteral) print(ps *printState) {
+       ps.writeString(`"<`)
+       sl.Type.print(ps)
+       ps.writeString(`>"`)
+}
+
+func (sl *StringLiteral) Traverse(fn func(AST) bool) {
+       if fn(sl) {
+               sl.Type.Traverse(fn)
+       }
+}
+
+func (sl *StringLiteral) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(sl) {
+               return nil
+       }
+       typ := sl.Type.Copy(fn, skip)
+       if typ == nil {
+               return fn(sl)
+       }
+       sl = &StringLiteral{Type: typ}
+       if r := fn(sl); r != nil {
+               return r
+       }
+       return sl
+}
+
+func (sl *StringLiteral) GoString() string {
+       return sl.goString(0, "")
+}
+
+func (sl *StringLiteral) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sStringLiteral:\n%s", indent, "", field,
+               sl.Type.goString(indent+2, ""))
+}
+
+// LambdaExpr is a literal that is a lambda expression.
+type LambdaExpr struct {
+       Type AST
+}
+
+func (le *LambdaExpr) print(ps *printState) {
+       ps.writeString("[]")
+       if cl, ok := le.Type.(*Closure); ok {
+               cl.printTypes(ps)
+       }
+       ps.writeString("{...}")
+}
+
+func (le *LambdaExpr) Traverse(fn func(AST) bool) {
+       if fn(le) {
+               le.Type.Traverse(fn)
+       }
+}
+
+func (le *LambdaExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(le) {
+               return nil
+       }
+       typ := le.Type.Copy(fn, skip)
+       if typ == nil {
+               return fn(le)
+       }
+       le = &LambdaExpr{Type: typ}
+       if r := fn(le); r != nil {
+               return r
+       }
+       return le
+}
+
+func (le *LambdaExpr) GoString() string {
+       return le.goString(0, "")
+}
+
+func (le *LambdaExpr) goString(indent int, field string) string {
+       return fmt.Sprintf("%*s%sLambdaExpr:\n%s", indent, "", field,
+               le.Type.goString(indent+2, ""))
+}
+
 // ExprList is a list of expressions, typically arguments to a
 // function call in an expression.
 type ExprList struct {
@@ -2803,7 +3526,9 @@ type DefaultArg struct {
 }
 
 func (da *DefaultArg) print(ps *printState) {
-       fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
+       if !ps.llvmStyle {
+               fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
+       }
        ps.print(da.Arg)
 }
 
@@ -2839,23 +3564,53 @@ func (da *DefaultArg) goString(indent int, field string) string {
 
 // Closure is a closure, or lambda expression.
 type Closure struct {
-       Types []AST
-       Num   int
+       TemplateArgs []AST
+       Types        []AST
+       Num          int
 }
 
 func (cl *Closure) print(ps *printState) {
-       ps.writeString("{lambda(")
+       if ps.llvmStyle {
+               if cl.Num == 0 {
+                       ps.writeString("'lambda'")
+               } else {
+                       ps.writeString(fmt.Sprintf("'lambda%d'", cl.Num-1))
+               }
+       } else {
+               ps.writeString("{lambda")
+       }
+       cl.printTypes(ps)
+       if !ps.llvmStyle {
+               ps.writeString(fmt.Sprintf("#%d}", cl.Num+1))
+       }
+}
+
+func (cl *Closure) printTypes(ps *printState) {
+       if len(cl.TemplateArgs) > 0 {
+               ps.writeString("<")
+               for i, a := range cl.TemplateArgs {
+                       if i > 0 {
+                               ps.writeString(", ")
+                       }
+                       ps.print(a)
+               }
+               ps.writeString(">")
+       }
+       ps.writeString("(")
        for i, t := range cl.Types {
                if i > 0 {
                        ps.writeString(", ")
                }
                ps.print(t)
        }
-       ps.writeString(fmt.Sprintf(")#%d}", cl.Num+1))
+       ps.writeString(")")
 }
 
 func (cl *Closure) Traverse(fn func(AST) bool) {
        if fn(cl) {
+               for _, a := range cl.TemplateArgs {
+                       a.Traverse(fn)
+               }
                for _, t := range cl.Types {
                        t.Traverse(fn)
                }
@@ -2866,8 +3621,20 @@ func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
        if skip(cl) {
                return nil
        }
-       types := make([]AST, len(cl.Types))
        changed := false
+
+       args := make([]AST, len(cl.TemplateArgs))
+       for i, a := range cl.TemplateArgs {
+               ac := a.Copy(fn, skip)
+               if ac == nil {
+                       args[i] = a
+               } else {
+                       args[i] = ac
+                       changed = true
+               }
+       }
+
+       types := make([]AST, len(cl.Types))
        for i, t := range cl.Types {
                tc := t.Copy(fn, skip)
                if tc == nil {
@@ -2877,10 +3644,11 @@ func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
                        changed = true
                }
        }
+
        if !changed {
                return fn(cl)
        }
-       cl = &Closure{Types: types, Num: cl.Num}
+       cl = &Closure{TemplateArgs: args, Types: types, Num: cl.Num}
        if r := fn(cl); r != nil {
                return r
        }
@@ -2892,6 +3660,16 @@ func (cl *Closure) GoString() string {
 }
 
 func (cl *Closure) goString(indent int, field string) string {
+       var args string
+       if len(cl.TemplateArgs) == 0 {
+               args = fmt.Sprintf("%*sTemplateArgs: nil", indent+2, "")
+       } else {
+               args = fmt.Sprintf("%*sTemplateArgs:", indent+2, "")
+               for i, a := range cl.TemplateArgs {
+                       args += "\n"
+                       args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+               }
+       }
        var types string
        if len(cl.Types) == 0 {
                types = fmt.Sprintf("%*sTypes: nil", indent+2, "")
@@ -2902,7 +3680,71 @@ func (cl *Closure) goString(indent int, field string) string {
                        types += t.goString(indent+4, fmt.Sprintf("%d: ", i))
                }
        }
-       return fmt.Sprintf("%*s%sClosure: Num: %d\n%s", indent, "", field, cl.Num, types)
+       return fmt.Sprintf("%*s%sClosure: Num: %d\n%s\n%s", indent, "", field,
+               cl.Num, args, types)
+}
+
+// StructuredBindings is a structured binding declaration.
+type StructuredBindings struct {
+       Bindings []AST
+}
+
+func (sb *StructuredBindings) print(ps *printState) {
+       ps.writeString("[")
+       for i, b := range sb.Bindings {
+               if i > 0 {
+                       ps.writeString(", ")
+               }
+               b.print(ps)
+       }
+       ps.writeString("]")
+}
+
+func (sb *StructuredBindings) Traverse(fn func(AST) bool) {
+       if fn(sb) {
+               for _, b := range sb.Bindings {
+                       b.Traverse(fn)
+               }
+       }
+}
+
+func (sb *StructuredBindings) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+       if skip(sb) {
+               return nil
+       }
+       changed := false
+       bindings := make([]AST, len(sb.Bindings))
+       for i, b := range sb.Bindings {
+               bc := b.Copy(fn, skip)
+               if bc == nil {
+                       bindings[i] = b
+               } else {
+                       bindings[i] = bc
+                       changed = true
+               }
+       }
+       if !changed {
+               return fn(sb)
+       }
+       sb = &StructuredBindings{Bindings: bindings}
+       if r := fn(sb); r != nil {
+               return r
+       }
+       return sb
+}
+
+func (sb *StructuredBindings) GoString() string {
+       return sb.goString(0, "")
+}
+
+func (sb *StructuredBindings) goString(indent int, field string) string {
+       var strb strings.Builder
+       fmt.Fprintf(&strb, "%*s%sStructuredBinding:", indent, "", field)
+       for _, b := range sb.Bindings {
+               strb.WriteByte('\n')
+               strb.WriteString(b.goString(indent+2, ""))
+       }
+       return strb.String()
 }
 
 // UnnamedType is an unnamed type, that just has an index.
@@ -2911,7 +3753,15 @@ type UnnamedType struct {
 }
 
 func (ut *UnnamedType) print(ps *printState) {
-       ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
+       if ps.llvmStyle {
+               if ut.Num == 0 {
+                       ps.writeString("'unnamed'")
+               } else {
+                       ps.writeString(fmt.Sprintf("'unnamed%d'", ut.Num-1))
+               }
+       } else {
+               ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
+       }
 }
 
 func (ut *UnnamedType) Traverse(fn func(AST) bool) {
@@ -2941,7 +3791,13 @@ type Clone struct {
 
 func (c *Clone) print(ps *printState) {
        ps.print(c.Base)
-       ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
+       if ps.llvmStyle {
+               ps.writeString(" (")
+               ps.writeString(c.Suffix)
+               ps.writeByte(')')
+       } else {
+               ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
+       }
 }
 
 func (c *Clone) Traverse(fn func(AST) bool) {
@@ -2982,7 +3838,16 @@ type Special struct {
 }
 
 func (s *Special) print(ps *printState) {
-       ps.writeString(s.Prefix)
+       prefix := s.Prefix
+       if ps.llvmStyle {
+               switch prefix {
+               case "TLS wrapper function for ":
+                       prefix = "thread-local wrapper routine for "
+               case "TLS init function for ":
+                       prefix = "thread-local initialization routine for "
+               }
+       }
+       ps.writeString(prefix)
        ps.print(s.Val)
 }
 
@@ -3194,7 +4059,12 @@ func (ps *printState) printOneInner(save *[]AST) {
 func (ps *printState) isEmpty(a AST) bool {
        switch a := a.(type) {
        case *ArgumentPack:
-               return len(a.Args) == 0
+               for _, a := range a.Args {
+                       if !ps.isEmpty(a) {
+                               return false
+                       }
+               }
+               return true
        case *ExprList:
                return len(a.Exprs) == 0
        case *PackExpansion:
index c2667446df07b34461bdb8b5ee4f99d37931ae9c..9eec0aa3c83921792418b06ed6513d95ee2e6502 100644 (file)
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package demangle defines functions that demangle GCC/LLVM C++ symbol names.
+// Package demangle defines functions that demangle GCC/LLVM
+// C++ and Rust symbol names.
 // This package recognizes names that were mangled according to the C++ ABI
-// defined at http://codesourcery.com/cxx-abi/.
+// defined at http://codesourcery.com/cxx-abi/ and the Rust ABI
+// defined at
+// https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html
 //
 // Most programs will want to call Filter or ToString.
 package demangle
@@ -17,7 +20,7 @@ import (
 
 // ErrNotMangledName is returned by CheckedDemangle if the string does
 // not appear to be a C++ symbol name.
-var ErrNotMangledName = errors.New("not a C++ mangled name")
+var ErrNotMangledName = errors.New("not a C++ or Rust mangled name")
 
 // Option is the type of demangler options.
 type Option int
@@ -33,11 +36,23 @@ const (
        // NoParams implies NoClones.
        NoClones
 
+       // The NoRust option disables demangling of old-style Rust
+       // mangled names, which can be confused with C++ style mangled
+       // names. New style Rust mangled names are still recognized.
+       NoRust
+
        // The Verbose option turns on more verbose demangling.
        Verbose
+
+       // LLVMStyle tries to translate an AST to a string in the
+       // style of the LLVM demangler. This does not affect
+       // the parsing of the AST, only the conversion of the AST
+       // to a string.
+       LLVMStyle
 )
 
-// Filter demangles a C++ symbol name, returning the human-readable C++ name.
+// Filter demangles a C++ or Rust symbol name,
+// returning the human-readable C++ or Rust name.
 // If any error occurs during demangling, the input string is returned.
 func Filter(name string, options ...Option) string {
        ret, err := ToString(name, options...)
@@ -47,11 +62,34 @@ func Filter(name string, options ...Option) string {
        return ret
 }
 
-// ToString demangles a C++ symbol name, returning a human-readable C++
-// name or an error.
-// If the name does not appear to be a C++ symbol name at all, the
-// error will be ErrNotMangledName.
+// ToString demangles a C++ or Rust symbol name,
+// returning a human-readable C++ or Rust name or an error.
+// If the name does not appear to be a C++ or Rust symbol name at all,
+// the error will be ErrNotMangledName.
 func ToString(name string, options ...Option) (string, error) {
+       if strings.HasPrefix(name, "_R") {
+               return rustToString(name, options)
+       }
+
+       // Check for an old-style Rust mangled name.
+       // It starts with _ZN and ends with "17h" followed by 16 hex digits
+       // followed by "E".
+       if strings.HasPrefix(name, "_ZN") && strings.HasSuffix(name, "E") && len(name) > 23 && name[len(name)-20:len(name)-17] == "17h" {
+               noRust := false
+               for _, o := range options {
+                       if o == NoRust {
+                               noRust = true
+                               break
+                       }
+               }
+               if !noRust {
+                       s, ok := oldRustToString(name, options)
+                       if ok {
+                               return s, nil
+                       }
+               }
+       }
+
        a, err := ToAST(name, options...)
        if err != nil {
                return "", err
@@ -65,12 +103,37 @@ func ToString(name string, options ...Option) (string, error) {
 // the parameter types are not demangled.
 // If the name does not appear to be a C++ symbol name at all, the
 // error will be ErrNotMangledName.
+// This function does not currently support Rust symbol names.
 func ToAST(name string, options ...Option) (AST, error) {
        if strings.HasPrefix(name, "_Z") {
                a, err := doDemangle(name[2:], options...)
                return a, adjustErr(err, 2)
        }
 
+       if strings.HasPrefix(name, "___Z") {
+               // clang extensions
+               block := strings.LastIndex(name, "_block_invoke")
+               if block == -1 {
+                       return nil, ErrNotMangledName
+               }
+               a, err := doDemangle(name[4:block], options...)
+               if err != nil {
+                       return a, adjustErr(err, 4)
+               }
+               name = strings.TrimPrefix(name[block:], "_block_invoke")
+               if len(name) > 0 && name[0] == '_' {
+                       name = name[1:]
+               }
+               for len(name) > 0 && isDigit(name[0]) {
+                       name = name[1:]
+               }
+               if len(name) > 0 && name[0] != '.' {
+                       return nil, errors.New("unparsed characters at end of mangled name")
+               }
+               a = &Special{Prefix: "invocation function for block in ", Val: a}
+               return a, nil
+       }
+
        const prefix = "_GLOBAL_"
        if strings.HasPrefix(name, prefix) {
                // The standard demangler ignores NoParams for global
@@ -150,12 +213,13 @@ func doDemangle(name string, options ...Option) (ret AST, err error) {
                case NoParams:
                        params = false
                        clones = false
-               case NoTemplateParams:
-               // This is a valid option but only affect printing of the AST.
                case NoClones:
                        clones = false
                case Verbose:
                        verbose = true
+               case NoTemplateParams, LLVMStyle:
+                       // These are valid options but only affect
+                       // printing of the AST.
                default:
                        return nil, fmt.Errorf("unrecognized demangler option %v", o)
                }
@@ -185,7 +249,16 @@ type state struct {
        off       int           // offset of str within original string
        subs      substitutions // substitutions
        templates []*Template   // templates being processed
-       inLambda  int           // number of lambdas being parsed
+
+       // The number of entries in templates when we started parsing
+       // a lambda, plus 1 so that 0 means not parsing a lambda.
+       lambdaTemplateLevel int
+
+       // Counts of template parameters without template arguments,
+       // for lambdas.
+       typeTemplateParamCount     int
+       nonTypeTemplateParamCount  int
+       templateTemplateParamCount int
 }
 
 // copy returns a copy of the current state.
@@ -308,35 +381,40 @@ func (st *state) encoding(params bool, local forLocalNameType) AST {
                return a
        }
 
-       check := a
-       mwq, _ := check.(*MethodWithQualifiers)
-       if mwq != nil {
-               check = mwq.Method
-       }
+       mwq, _ := a.(*MethodWithQualifiers)
 
-       var template *Template
-       switch check := check.(type) {
-       case *Template:
-               template = check
-       case *Qualified:
-               if check.LocalName {
-                       n := check.Name
-                       if nmwq, ok := n.(*MethodWithQualifiers); ok {
-                               n = nmwq.Method
+       var findTemplate func(AST) *Template
+       findTemplate = func(check AST) *Template {
+               switch check := check.(type) {
+               case *Template:
+                       return check
+               case *Qualified:
+                       if check.LocalName {
+                               return findTemplate(check.Name)
+                       } else if _, ok := check.Name.(*Constructor); ok {
+                               return findTemplate(check.Name)
+                       }
+               case *MethodWithQualifiers:
+                       return findTemplate(check.Method)
+               case *Constructor:
+                       if check.Base != nil {
+                               return findTemplate(check.Base)
                        }
-                       template, _ = n.(*Template)
                }
+               return nil
        }
-       var oldInLambda int
+
+       template := findTemplate(a)
+       var oldLambdaTemplateLevel int
        if template != nil {
                st.templates = append(st.templates, template)
-               oldInLambda = st.inLambda
-               st.inLambda = 0
+               oldLambdaTemplateLevel = st.lambdaTemplateLevel
+               st.lambdaTemplateLevel = 0
        }
 
        // Checking for the enable_if attribute here is what the LLVM
        // demangler does.  This is not very general but perhaps it is
-       // sufficent.
+       // sufficient.
        const enableIfPrefix = "Ua9enable_ifI"
        var enableIfArgs []AST
        if strings.HasPrefix(st.str, enableIfPrefix) {
@@ -348,7 +426,7 @@ func (st *state) encoding(params bool, local forLocalNameType) AST {
 
        if template != nil {
                st.templates = st.templates[:len(st.templates)-1]
-               st.inLambda = oldInLambda
+               st.lambdaTemplateLevel = oldLambdaTemplateLevel
        }
 
        ft = simplify(ft)
@@ -357,7 +435,7 @@ func (st *state) encoding(params bool, local forLocalNameType) AST {
        // doesn't get confused with the top level return type.
        if local == forLocalName {
                if functype, ok := ft.(*FunctionType); ok {
-                       functype.Return = nil
+                       functype.ForLocalName = true
                }
        }
 
@@ -573,7 +651,7 @@ func (st *state) prefix() AST {
                var next AST
 
                c := st.str[0]
-               if isDigit(c) || isLower(c) || c == 'U' || c == 'L' {
+               if isDigit(c) || isLower(c) || c == 'U' || c == 'L' || (c == 'D' && len(st.str) > 1 && st.str[1] == 'C') {
                        un, isUnCast := st.unqualifiedName()
                        next = un
                        if isUnCast {
@@ -595,10 +673,17 @@ func (st *state) prefix() AST {
                                        st.fail("constructor before name is seen")
                                }
                                st.advance(1)
+                               var base AST
                                if inheriting {
-                                       last = st.demangleType(false)
+                                       base = st.demangleType(false)
+                               }
+                               next = &Constructor{
+                                       Name: getLast(last),
+                                       Base: base,
+                               }
+                               if len(st.str) > 0 && st.str[0] == 'B' {
+                                       next = st.taggedName(next)
                                }
-                               next = &Constructor{Name: getLast(last)}
                        case 'D':
                                if len(st.str) > 1 && (st.str[1] == 'T' || st.str[1] == 't') {
                                        next = st.demangleType(false)
@@ -611,6 +696,9 @@ func (st *state) prefix() AST {
                                        }
                                        st.advance(2)
                                        next = &Destructor{Name: getLast(last)}
+                                       if len(st.str) > 0 && st.str[0] == 'B' {
+                                               next = st.taggedName(next)
+                                       }
                                }
                        case 'S':
                                next = st.substitution(true)
@@ -713,6 +801,18 @@ func (st *state) unqualifiedName() (r AST, isCast bool) {
                        n := st.sourceName()
                        a = &Unary{Op: op, Expr: n, Suffix: false, SizeofType: false}
                }
+       } else if c == 'D' && len(st.str) > 1 && st.str[1] == 'C' {
+               var bindings []AST
+               st.advance(2)
+               for {
+                       binding := st.sourceName()
+                       bindings = append(bindings, binding)
+                       if len(st.str) > 0 && st.str[0] == 'E' {
+                               st.advance(1)
+                               break
+                       }
+               }
+               a = &StructuredBindings{Bindings: bindings}
        } else {
                switch c {
                case 'C', 'D':
@@ -728,6 +828,10 @@ func (st *state) unqualifiedName() (r AST, isCast bool) {
                        }
                        c := st.str[1]
                        switch c {
+                       case 'b':
+                               st.advance(2)
+                               st.compactNumber()
+                               a = &Name{Name: "'block-literal'"}
                        case 'l':
                                a = st.closureTypeName()
                        case 't':
@@ -802,6 +906,42 @@ func (st *state) number() int {
        return val
 }
 
+// <seq-id> ::= <0-9A-Z>+
+//
+// We expect this to be followed by an underscore.
+func (st *state) seqID(eofOK bool) int {
+       if len(st.str) > 0 && st.str[0] == '_' {
+               st.advance(1)
+               return 0
+       }
+       id := 0
+       for {
+               if len(st.str) == 0 {
+                       if eofOK {
+                               return id + 1
+                       }
+                       st.fail("missing end to sequence ID")
+               }
+               // Don't overflow a 32-bit int.
+               if id >= 0x80000000/36-36 {
+                       st.fail("sequence ID overflow")
+               }
+               c := st.str[0]
+               if c == '_' {
+                       st.advance(1)
+                       return id + 1
+               }
+               if isDigit(c) {
+                       id = id*36 + int(c-'0')
+               } else if isUpper(c) {
+                       id = id*36 + int(c-'A') + 10
+               } else {
+                       st.fail("invalid character in sequence ID")
+               }
+               st.advance(1)
+       }
+}
+
 // An operator is the demangled name, and the number of arguments it
 // takes in an expression.
 type operator struct {
@@ -864,6 +1004,7 @@ var operators = map[string]operator{
        "ng": {"-", 1},
        "nt": {"!", 1},
        "nw": {"new", 3},
+       "nx": {"noexcept", 1},
        "oR": {"|=", 2},
        "oo": {"||", 2},
        "or": {"|", 2},
@@ -1094,8 +1235,8 @@ func (st *state) specialName() AST {
                        return &Special{Prefix: "guard variable for ", Val: n}
                case 'R':
                        n := st.name()
-                       i := st.number()
-                       return &Special{Prefix: fmt.Sprintf("reference temporary #%d for ", i), Val: n}
+                       st.seqID(true)
+                       return &Special{Prefix: "reference temporary for ", Val: n}
                case 'A':
                        v := st.encoding(true, notForLocalName)
                        return &Special{Prefix: "hidden alias for ", Val: v}
@@ -1257,6 +1398,23 @@ func (st *state) demangleType(isCast bool) AST {
        case 'M':
                ret = st.pointerToMemberType(isCast)
        case 'T':
+               if len(st.str) > 1 && (st.str[1] == 's' || st.str[1] == 'u' || st.str[1] == 'e') {
+                       c = st.str[1]
+                       st.advance(2)
+                       ret = st.name()
+                       var kind string
+                       switch c {
+                       case 's':
+                               kind = "struct"
+                       case 'u':
+                               kind = "union"
+                       case 'e':
+                               kind = "enum"
+                       }
+                       ret = &ElaboratedType{Kind: kind, Type: ret}
+                       break
+               }
+
                ret = st.templateParam()
                if len(st.str) > 0 && st.str[0] == 'I' {
                        // See the function comment to explain this.
@@ -1681,7 +1839,11 @@ func (st *state) bareFunctionType(hasReturnType bool) AST {
                returnType = st.demangleType(false)
        }
        types := st.parmlist()
-       return &FunctionType{Return: returnType, Args: types}
+       return &FunctionType{
+               Return:       returnType,
+               Args:         types,
+               ForLocalName: false, // may be set later in encoding
+       }
 }
 
 // <array-type> ::= A <(positive dimension) number> _ <(element) type>
@@ -1798,6 +1960,8 @@ func (st *state) compactNumber() int {
 
 // <template-param> ::= T_
 //                  ::= T <(parameter-2 non-negative) number> _
+//                  ::= TL <level-1> __
+//                  ::= TL <level-1> _ <parameter-2 non-negative number> _
 //
 // When a template parameter is a substitution candidate, any
 // reference to that substitution refers to the template parameter
@@ -1805,22 +1969,27 @@ func (st *state) compactNumber() int {
 // whatever the template parameter would be expanded to here.  We sort
 // this out in substitution and simplify.
 func (st *state) templateParam() AST {
-       if len(st.templates) == 0 && st.inLambda == 0 {
-               st.fail("template parameter not in scope of template")
-       }
        off := st.off
-
        st.checkChar('T')
+
+       level := 0
+       if len(st.str) > 0 && st.str[0] == 'L' {
+               st.advance(1)
+               level = st.compactNumber()
+       }
+
        n := st.compactNumber()
 
-       if st.inLambda > 0 {
-               // g++ mangles lambda auto params as template params.
-               // Apparently we can't encounter a template within a lambda.
-               // See https://gcc.gnu.org/PR78252.
-               return &LambdaAuto{Index: n}
+       if level >= len(st.templates) {
+               if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
+                       // Lambda auto params are mangled as template params.
+                       // See https://gcc.gnu.org/PR78252.
+                       return &LambdaAuto{Index: n}
+               }
+               st.failEarlier(fmt.Sprintf("template parameter is not in scope of template (level %d >= %d)", level, len(st.templates)), st.off-off)
        }
 
-       template := st.templates[len(st.templates)-1]
+       template := st.templates[level]
 
        if template == nil {
                // We are parsing a cast operator.  If the cast is
@@ -1830,6 +1999,11 @@ func (st *state) templateParam() AST {
        }
 
        if n >= len(template.Args) {
+               if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
+                       // Lambda auto params are mangled as template params.
+                       // See https://gcc.gnu.org/PR78252.
+                       return &LambdaAuto{Index: n}
+               }
                st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
        }
 
@@ -1968,9 +2142,11 @@ func (st *state) exprList(stop byte) AST {
 //              ::= dc <type> <expression>
 //              ::= sc <type> <expression>
 //              ::= cc <type> <expression>
+//              ::= mc <parameter type> <expr> [<offset number>] E
 //              ::= rc <type> <expression>
 //              ::= ti <type>
 //              ::= te <expression>
+//              ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
 //              ::= st <type>
 //              ::= sz <expression>
 //              ::= at <type>
@@ -1991,6 +2167,7 @@ func (st *state) exprList(stop byte) AST {
 //              ::= fR <binary operator-name> <expression> <expression>
 //              ::= tw <expression>
 //              ::= tr
+//              ::= u <source-name> <template-arg>* E
 //              ::= <unresolved-name>
 //              ::= <expr-primary>
 //
@@ -2013,6 +2190,9 @@ func (st *state) expression() AST {
                return st.exprPrimary()
        } else if st.str[0] == 'T' {
                return st.templateParam()
+       } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'o' {
+               st.advance(2)
+               return st.subobject()
        } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' {
                return st.unresolvedName()
        } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' {
@@ -2063,6 +2243,23 @@ func (st *state) expression() AST {
                st.cvQualifiers()
                index := st.compactNumber()
                return &FunctionParam{Index: index + 1}
+       } else if st.str[0] == 'm' && len(st.str) > 1 && st.str[1] == 'c' {
+               st.advance(2)
+               typ := st.demangleType(false)
+               expr := st.expression()
+               offset := 0
+               if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
+                       offset = st.number()
+               }
+               if len(st.str) == 0 || st.str[0] != 'E' {
+                       st.fail("expected E after pointer-to-member conversion")
+               }
+               st.advance(1)
+               return &PtrMemCast{
+                       Type:   typ,
+                       Expr:   expr,
+                       Offset: offset,
+               }
        } else if isDigit(st.str[0]) || (st.str[0] == 'o' && len(st.str) > 1 && st.str[1] == 'n') {
                if st.str[0] == 'o' {
                        // Skip operator function ID.
@@ -2088,6 +2285,50 @@ func (st *state) expression() AST {
                o, _ := st.operatorName(true)
                t := st.demangleType(false)
                return &Unary{Op: o, Expr: t, Suffix: false, SizeofType: true}
+       } else if st.str[0] == 'u' {
+               st.advance(1)
+               name := st.sourceName()
+               // Special case __uuidof followed by type or
+               // expression, as used by LLVM.
+               if n, ok := name.(*Name); ok && n.Name == "__uuidof" {
+                       if len(st.str) < 2 {
+                               st.fail("missing uuidof argument")
+                       }
+                       var operand AST
+                       if st.str[0] == 't' {
+                               st.advance(1)
+                               operand = st.demangleType(false)
+                       } else if st.str[0] == 'z' {
+                               st.advance(1)
+                               operand = st.expression()
+                       }
+                       if operand != nil {
+                               return &Binary{
+                                       Op:   &Operator{Name: "()"},
+                                       Left: name,
+                                       Right: &ExprList{
+                                               Exprs: []AST{operand},
+                                       },
+                               }
+                       }
+               }
+               var args []AST
+               for {
+                       if len(st.str) == 0 {
+                               st.fail("missing argument in vendor extended expressoin")
+                       }
+                       if st.str[0] == 'E' {
+                               st.advance(1)
+                               break
+                       }
+                       arg := st.templateArg()
+                       args = append(args, arg)
+               }
+               return &Binary{
+                       Op:    &Operator{Name: "()"},
+                       Left:  name,
+                       Right: &ExprList{Exprs: args},
+               }
        } else {
                if len(st.str) < 2 {
                        st.fail("missing operator code")
@@ -2185,6 +2426,42 @@ func (st *state) expression() AST {
        }
 }
 
+// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
+// <union-selector> ::= _ [<number>]
+func (st *state) subobject() AST {
+       typ := st.demangleType(false)
+       expr := st.expression()
+       offset := 0
+       if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
+               offset = st.number()
+       }
+       var selectors []int
+       for len(st.str) > 0 && st.str[0] == '_' {
+               st.advance(1)
+               selector := 0
+               if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
+                       selector = st.number()
+               }
+               selectors = append(selectors, selector)
+       }
+       pastEnd := false
+       if len(st.str) > 0 && st.str[0] == 'p' {
+               st.advance(1)
+               pastEnd = true
+       }
+       if len(st.str) == 0 || st.str[0] != 'E' {
+               st.fail("expected E after subobject")
+       }
+       st.advance(1)
+       return &Subobject{
+               Type:      typ,
+               SubExpr:   expr,
+               Offset:    offset,
+               Selectors: selectors,
+               PastEnd:   pastEnd,
+       }
+}
+
 // <unresolved-name> ::= [gs] <base-unresolved-name>
 //                   ::= sr <unresolved-type> <base-unresolved-name>
 //                   ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
@@ -2320,6 +2597,14 @@ func (st *state) exprPrimary() AST {
        } else {
                t := st.demangleType(false)
 
+               isArrayType := func(typ AST) bool {
+                       if twq, ok := typ.(*TypeWithQualifiers); ok {
+                               typ = twq.Base
+                       }
+                       _, ok := typ.(*ArrayType)
+                       return ok
+               }
+
                neg := false
                if len(st.str) > 0 && st.str[0] == 'n' {
                        neg = true
@@ -2331,6 +2616,13 @@ func (st *state) exprPrimary() AST {
                                // We accept one if present because GCC
                                // used to generate one.
                                // https://gcc.gnu.org/PR91979.
+                       } else if cl, ok := t.(*Closure); ok {
+                               // A closure doesn't have a value.
+                               st.advance(1)
+                               return &LambdaExpr{Type: cl}
+                       } else if isArrayType(t) {
+                               st.advance(1)
+                               return &StringLiteral{Type: t}
                        } else {
                                st.fail("missing literal value")
                        }
@@ -2354,6 +2646,15 @@ func (st *state) exprPrimary() AST {
 //                     __ <(non-negative) number> _ (when number >= 10)
 func (st *state) discriminator(a AST) AST {
        if len(st.str) == 0 || st.str[0] != '_' {
+               // clang can generate a discriminator at the end of
+               // the string with no underscore.
+               for i := 0; i < len(st.str); i++ {
+                       if !isDigit(st.str[i]) {
+                               return a
+                       }
+               }
+               // Skip the trailing digits.
+               st.advance(len(st.str))
                return a
        }
        off := st.off
@@ -2379,18 +2680,131 @@ func (st *state) discriminator(a AST) AST {
 }
 
 // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+// <lambda-sig> ::= <parameter type>+
 func (st *state) closureTypeName() AST {
        st.checkChar('U')
        st.checkChar('l')
-       st.inLambda++
+
+       oldLambdaTemplateLevel := st.lambdaTemplateLevel
+       st.lambdaTemplateLevel = len(st.templates) + 1
+
+       var templateArgs []AST
+       var template *Template
+       for len(st.str) > 1 && st.str[0] == 'T' {
+               arg, templateVal := st.templateParamDecl()
+               if arg == nil {
+                       break
+               }
+               templateArgs = append(templateArgs, arg)
+               if template == nil {
+                       template = &Template{
+                               Name: &Name{Name: "lambda"},
+                       }
+                       st.templates = append(st.templates, template)
+               }
+               template.Args = append(template.Args, templateVal)
+       }
+
        types := st.parmlist()
-       st.inLambda--
+
+       st.lambdaTemplateLevel = oldLambdaTemplateLevel
+
+       if template != nil {
+               st.templates = st.templates[:len(st.templates)-1]
+       }
+
        if len(st.str) == 0 || st.str[0] != 'E' {
                st.fail("expected E after closure type name")
        }
        st.advance(1)
        num := st.compactNumber()
-       return &Closure{Types: types, Num: num}
+       return &Closure{TemplateArgs: templateArgs, Types: types, Num: num}
+}
+
+// <template-param-decl> ::= Ty                          # type parameter
+//                       ::= Tn <type>                   # non-type parameter
+//                       ::= Tt <template-param-decl>* E # template parameter
+//                       ::= Tp <template-param-decl>    # parameter pack
+//
+// Returns the new AST to include in the AST we are building and the
+// new AST to add to the list of template parameters.
+//
+// Returns nil, nil if not looking at a template-param-decl.
+func (st *state) templateParamDecl() (AST, AST) {
+       if len(st.str) < 2 || st.str[0] != 'T' {
+               return nil, nil
+       }
+       mk := func(prefix string, p *int) AST {
+               idx := *p
+               (*p)++
+               return &TemplateParamName{
+                       Prefix: prefix,
+                       Index:  idx,
+               }
+       }
+       switch st.str[1] {
+       case 'y':
+               st.advance(2)
+               name := mk("$T", &st.typeTemplateParamCount)
+               tp := &TypeTemplateParam{
+                       Name: name,
+               }
+               return tp, name
+       case 'n':
+               st.advance(2)
+               name := mk("$N", &st.nonTypeTemplateParamCount)
+               typ := st.demangleType(false)
+               tp := &NonTypeTemplateParam{
+                       Name: name,
+                       Type: typ,
+               }
+               return tp, name
+       case 't':
+               st.advance(2)
+               name := mk("$TT", &st.templateTemplateParamCount)
+               var params []AST
+               var template *Template
+               for {
+                       if len(st.str) == 0 {
+                               st.fail("expected closure template parameter")
+                       }
+                       if st.str[0] == 'E' {
+                               st.advance(1)
+                               break
+                       }
+                       off := st.off
+                       param, templateVal := st.templateParamDecl()
+                       if param == nil {
+                               st.failEarlier("expected closure template parameter", st.off-off)
+                       }
+                       params = append(params, param)
+                       if template == nil {
+                               template = &Template{
+                                       Name: &Name{Name: "template_template"},
+                               }
+                               st.templates = append(st.templates, template)
+                       }
+                       template.Args = append(template.Args, templateVal)
+               }
+               if template != nil {
+                       st.templates = st.templates[:len(st.templates)-1]
+               }
+               tp := &TemplateTemplateParam{
+                       Name:   name,
+                       Params: params,
+               }
+               return tp, name
+       case 'p':
+               st.advance(2)
+               off := st.off
+               param, templateVal := st.templateParamDecl()
+               if param == nil {
+                       st.failEarlier("expected lambda template parameter", st.off-off)
+               }
+               return &TemplateParamPack{Param: param}, templateVal
+       default:
+               return nil, nil
+       }
 }
 
 // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
@@ -2504,36 +2918,11 @@ func (st *state) substitution(forPrefix bool) AST {
                st.fail("missing substitution index")
        }
        c := st.str[0]
-       st.advance(1)
-       dec := 1
+       off := st.off
        if c == '_' || isDigit(c) || isUpper(c) {
-               id := 0
-               if c != '_' {
-                       for c != '_' {
-                               // Don't overflow a 32-bit int.
-                               if id >= 0x80000000/36-36 {
-                                       st.fail("substitution index overflow")
-                               }
-                               if isDigit(c) {
-                                       id = id*36 + int(c-'0')
-                               } else if isUpper(c) {
-                                       id = id*36 + int(c-'A') + 10
-                               } else {
-                                       st.fail("invalid character in substitution index")
-                               }
-
-                               if len(st.str) == 0 {
-                                       st.fail("missing end to substitution index")
-                               }
-                               c = st.str[0]
-                               st.advance(1)
-                               dec++
-                       }
-                       id++
-               }
-
+               id := st.seqID(false)
                if id >= len(st.subs) {
-                       st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
+                       st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), st.off-off)
                }
 
                ret := st.subs[id]
@@ -2545,18 +2934,18 @@ func (st *state) substitution(forPrefix bool) AST {
                // When copying a Typed we may need to adjust
                // the templates.
                copyTemplates := st.templates
-               var oldInLambda []int
+               var oldLambdaTemplateLevel []int
 
                // pushTemplate is called from skip, popTemplate from copy.
                pushTemplate := func(template *Template) {
                        copyTemplates = append(copyTemplates, template)
-                       oldInLambda = append(oldInLambda, st.inLambda)
-                       st.inLambda = 0
+                       oldLambdaTemplateLevel = append(oldLambdaTemplateLevel, st.lambdaTemplateLevel)
+                       st.lambdaTemplateLevel = 0
                }
                popTemplate := func() {
                        copyTemplates = copyTemplates[:len(copyTemplates)-1]
-                       st.inLambda = oldInLambda[len(oldInLambda)-1]
-                       oldInLambda = oldInLambda[:len(oldInLambda)-1]
+                       st.lambdaTemplateLevel = oldLambdaTemplateLevel[len(oldLambdaTemplateLevel)-1]
+                       oldLambdaTemplateLevel = oldLambdaTemplateLevel[:len(oldLambdaTemplateLevel)-1]
                }
 
                copy := func(a AST) AST {
@@ -2569,8 +2958,9 @@ func (st *state) substitution(forPrefix bool) AST {
                                }
                                return nil
                        case *Closure:
-                               // Undo the decrement in skip.
-                               st.inLambda--
+                               // Undo the save in skip.
+                               st.lambdaTemplateLevel = oldLambdaTemplateLevel[len(oldLambdaTemplateLevel)-1]
+                               oldLambdaTemplateLevel = oldLambdaTemplateLevel[:len(oldLambdaTemplateLevel)-1]
                                return nil
                        case *TemplateParam:
                                index = a.Index
@@ -2582,7 +2972,7 @@ func (st *state) substitution(forPrefix bool) AST {
                        default:
                                return nil
                        }
-                       if st.inLambda > 0 {
+                       if st.lambdaTemplateLevel > 0 {
                                if _, ok := a.(*LambdaAuto); ok {
                                        return nil
                                }
@@ -2598,7 +2988,7 @@ func (st *state) substitution(forPrefix bool) AST {
                                // here.
                                template = rt
                        } else {
-                               st.failEarlier("substituted template parameter not in scope of template", dec)
+                               st.failEarlier("substituted template parameter not in scope of template", st.off-off)
                        }
                        if template == nil {
                                // This template parameter is within
@@ -2607,7 +2997,7 @@ func (st *state) substitution(forPrefix bool) AST {
                        }
 
                        if index >= len(template.Args) {
-                               st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", index, len(template.Args)), dec)
+                               st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", index, len(template.Args)), st.off-off)
                        }
 
                        return &TemplateParam{Index: index, Template: template}
@@ -2622,8 +3012,9 @@ func (st *state) substitution(forPrefix bool) AST {
                                }
                                return false
                        case *Closure:
-                               // This is decremented in copy.
-                               st.inLambda++
+                               // This is undone in copy.
+                               oldLambdaTemplateLevel = append(oldLambdaTemplateLevel, st.lambdaTemplateLevel)
+                               st.lambdaTemplateLevel = len(copyTemplates) + 1
                                return false
                        case *TemplateParam, *LambdaAuto:
                                return false
@@ -2643,6 +3034,7 @@ func (st *state) substitution(forPrefix bool) AST {
 
                return ret
        } else {
+               st.advance(1)
                m := subAST
                if st.verbose {
                        m = verboseAST
diff --git a/src/cmd/vendor/github.com/ianlancetaylor/demangle/rust.go b/src/cmd/vendor/github.com/ianlancetaylor/demangle/rust.go
new file mode 100644 (file)
index 0000000..140b631
--- /dev/null
@@ -0,0 +1,1069 @@
+// Copyright 2021 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 demangle
+
+import (
+       "fmt"
+       "math"
+       "math/bits"
+       "strings"
+       "unicode/utf8"
+)
+
+// rustToString demangles a Rust symbol.
+func rustToString(name string, options []Option) (ret string, err error) {
+       if !strings.HasPrefix(name, "_R") {
+               return "", ErrNotMangledName
+       }
+
+       // When the demangling routines encounter an error, they panic
+       // with a value of type demangleErr.
+       defer func() {
+               if r := recover(); r != nil {
+                       if de, ok := r.(demangleErr); ok {
+                               ret = ""
+                               err = de
+                               return
+                       }
+                       panic(r)
+               }
+       }()
+
+       suffix := ""
+       dot := strings.Index(name, ".")
+       if dot >= 0 {
+               suffix = name[dot:]
+               name = name[:dot]
+       }
+
+       name = name[2:]
+       rst := &rustState{orig: name, str: name}
+       rst.symbolName()
+
+       if len(rst.str) > 0 {
+               rst.fail("unparsed characters at end of mangled name")
+       }
+
+       if suffix != "" {
+               rst.skip = false
+               rst.writeString(" (")
+               rst.writeString(suffix)
+               rst.writeByte(')')
+       }
+
+       return rst.buf.String(), nil
+}
+
+// A rustState holds the current state of demangling a Rust string.
+type rustState struct {
+       orig      string          // the original string being demangled
+       str       string          // remainder of string to demangle
+       off       int             // offset of str within original string
+       buf       strings.Builder // demangled string being built
+       skip      bool            // don't print, just skip
+       lifetimes int64           // number of bound lifetimes
+       last      byte            // last byte written to buffer
+}
+
+// fail panics with demangleErr, to be caught in rustToString.
+func (rst *rustState) fail(err string) {
+       panic(demangleErr{err: err, off: rst.off})
+}
+
+// advance advances the current string offset.
+func (rst *rustState) advance(add int) {
+       if len(rst.str) < add {
+               panic("internal error")
+       }
+       rst.str = rst.str[add:]
+       rst.off += add
+}
+
+// checkChar requires that the next character in the string be c,
+// and advances past it.
+func (rst *rustState) checkChar(c byte) {
+       if len(rst.str) == 0 || rst.str[0] != c {
+               rst.fail("expected " + string(c))
+       }
+       rst.advance(1)
+}
+
+// writeByte writes a byte to the buffer.
+func (rst *rustState) writeByte(c byte) {
+       if rst.skip {
+               return
+       }
+       rst.last = c
+       rst.buf.WriteByte(c)
+}
+
+// writeString writes a string to the buffer.
+func (rst *rustState) writeString(s string) {
+       if rst.skip {
+               return
+       }
+       if len(s) > 0 {
+               rst.last = s[len(s)-1]
+               rst.buf.WriteString(s)
+       }
+}
+
+// <symbol-name> = "_R" [<decimal-number>] <path> [<instantiating-crate>]
+// <instantiating-crate> = <path>
+//
+// We've already skipped the "_R".
+func (rst *rustState) symbolName() {
+       if len(rst.str) < 1 {
+               rst.fail("expected symbol-name")
+       }
+
+       if isDigit(rst.str[0]) {
+               rst.fail("unsupported Rust encoding version")
+       }
+
+       rst.path(true)
+
+       if len(rst.str) > 0 {
+               rst.skip = true
+               rst.path(false)
+       }
+}
+
+// <path> = "C" <identifier>                    // crate root
+//        | "M" <impl-path> <type>              // <T> (inherent impl)
+//        | "X" <impl-path> <type> <path>       // <T as Trait> (trait impl)
+//        | "Y" <type> <path>                   // <T as Trait> (trait definition)
+//        | "N" <namespace> <path> <identifier> // ...::ident (nested path)
+//        | "I" <path> {<generic-arg>} "E"      // ...<T, U> (generic args)
+//        | <backref>
+// <namespace> = "C"      // closure
+//             | "S"      // shim
+//             | <A-Z>    // other special namespaces
+//             | <a-z>    // internal namespaces
+//
+// needsSeparator is true if we need to write out :: for a generic;
+// it is passed as false if we are in the middle of a type.
+func (rst *rustState) path(needsSeparator bool) {
+       if len(rst.str) < 1 {
+               rst.fail("expected path")
+       }
+       switch c := rst.str[0]; c {
+       case 'C':
+               rst.advance(1)
+               _, ident := rst.identifier()
+               rst.writeString(ident)
+       case 'M', 'X':
+               rst.advance(1)
+               rst.implPath()
+               rst.writeByte('<')
+               rst.demangleType()
+               if c == 'X' {
+                       rst.writeString(" as ")
+                       rst.path(false)
+               }
+               rst.writeByte('>')
+       case 'Y':
+               rst.advance(1)
+               rst.writeByte('<')
+               rst.demangleType()
+               rst.writeString(" as ")
+               rst.path(false)
+               rst.writeByte('>')
+       case 'N':
+               rst.advance(1)
+
+               if len(rst.str) < 1 {
+                       rst.fail("expected namespace")
+               }
+               ns := rst.str[0]
+               switch {
+               case ns >= 'a' && ns <= 'z':
+               case ns >= 'A' && ns <= 'Z':
+               default:
+                       rst.fail("invalid namespace character")
+               }
+               rst.advance(1)
+
+               rst.path(needsSeparator)
+
+               dis, ident := rst.identifier()
+
+               if ns >= 'A' && ns <= 'Z' {
+                       rst.writeString("::{")
+                       switch ns {
+                       case 'C':
+                               rst.writeString("closure")
+                       case 'S':
+                               rst.writeString("shim")
+                       default:
+                               rst.writeByte(ns)
+                       }
+                       if len(ident) > 0 {
+                               rst.writeByte(':')
+                               rst.writeString(ident)
+                       }
+                       if !rst.skip {
+                               fmt.Fprintf(&rst.buf, "#%d}", dis)
+                               rst.last = '}'
+                       }
+               } else {
+                       rst.writeString("::")
+                       rst.writeString(ident)
+               }
+       case 'I':
+               rst.advance(1)
+               rst.path(needsSeparator)
+               if needsSeparator {
+                       rst.writeString("::")
+               }
+               rst.writeByte('<')
+               first := true
+               for len(rst.str) > 0 && rst.str[0] != 'E' {
+                       if first {
+                               first = false
+                       } else {
+                               rst.writeString(", ")
+                       }
+                       rst.genericArg()
+               }
+               rst.writeByte('>')
+               rst.checkChar('E')
+       case 'B':
+               rst.backref(func() { rst.path(needsSeparator) })
+       default:
+               rst.fail("unrecognized letter in path")
+       }
+}
+
+// <impl-path> = [<disambiguator>] <path>
+func (rst *rustState) implPath() {
+       // This path is not part of the demangled string.
+       hold := rst.skip
+       rst.skip = true
+       defer func() {
+               rst.skip = hold
+       }()
+
+       rst.disambiguator()
+       rst.path(false)
+}
+
+// <identifier> = [<disambiguator>] <undisambiguated-identifier>
+// Returns the disambiguator and the identifier.
+func (rst *rustState) identifier() (int64, string) {
+       dis := rst.disambiguator()
+       ident := rst.undisambiguatedIdentifier()
+       return dis, ident
+}
+
+// <disambiguator> = "s" <base-62-number>
+// This is optional.
+func (rst *rustState) disambiguator() int64 {
+       if len(rst.str) == 0 || rst.str[0] != 's' {
+               return 0
+       }
+       rst.advance(1)
+       return rst.base62Number() + 1
+}
+
+// <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
+func (rst *rustState) undisambiguatedIdentifier() string {
+       punycode := false
+       if len(rst.str) > 0 && rst.str[0] == 'u' {
+               rst.advance(1)
+               punycode = true
+       }
+
+       val := rst.decimalNumber()
+
+       if len(rst.str) > 0 && rst.str[0] == '_' {
+               rst.advance(1)
+       }
+
+       if len(rst.str) < val {
+               rst.fail("not enough characters for identifier")
+       }
+       id := rst.str[:val]
+       rst.advance(val)
+
+       for i := 0; i < len(id); i++ {
+               c := id[i]
+               switch {
+               case c >= '0' && c <= '9':
+               case c >= 'A' && c <= 'Z':
+               case c >= 'a' && c <= 'z':
+               case c == '_':
+               default:
+                       rst.fail("invalid character in identifier")
+               }
+       }
+
+       if punycode {
+               id = rst.expandPunycode(id)
+       }
+
+       return id
+}
+
+// expandPunycode decodes the Rust version of punycode.
+// This algorithm is taken from RFC 3492 section 6.2.
+func (rst *rustState) expandPunycode(s string) string {
+       const (
+               base        = 36
+               tmin        = 1
+               tmax        = 26
+               skew        = 38
+               damp        = 700
+               initialBias = 72
+               initialN    = 128
+       )
+
+       idx := strings.LastIndex(s, "_")
+       if idx < 0 {
+               rst.fail("missing underscore in punycode string")
+       }
+
+       output := []rune(s[:idx])
+       encoding := s[idx+1:]
+
+       i := 0
+       n := initialN
+       bias := initialBias
+
+       pos := 0
+       for pos < len(encoding) {
+               oldI := i
+               w := 1
+               for k := base; ; k += base {
+                       if pos == len(encoding) {
+                               rst.fail("unterminated punycode")
+                       }
+
+                       var digit byte
+                       d := encoding[pos]
+                       pos++
+                       switch {
+                       case '0' <= d && d <= '9':
+                               digit = d - '0' + 26
+                       case 'A' <= d && d <= 'Z':
+                               digit = d - 'A'
+                       case 'a' <= d && d <= 'z':
+                               digit = d - 'a'
+                       default:
+                               rst.fail("invalid punycode digit")
+                       }
+
+                       i += int(digit) * w
+                       if i < 0 {
+                               rst.fail("punycode number overflow")
+                       }
+
+                       var t int
+                       if k <= bias {
+                               t = tmin
+                       } else if k > bias+tmax {
+                               t = tmax
+                       } else {
+                               t = k - bias
+                       }
+
+                       if int(digit) < t {
+                               break
+                       }
+
+                       if w >= math.MaxInt32/base {
+                               rst.fail("punycode number overflow")
+                       }
+                       w *= base - t
+               }
+
+               delta := i - oldI
+               numPoints := len(output) + 1
+               firstTime := oldI == 0
+               if firstTime {
+                       delta /= damp
+               } else {
+                       delta /= 2
+               }
+               delta += delta / numPoints
+               k := 0
+               for delta > ((base-tmin)*tmax)/2 {
+                       delta /= base - tmin
+                       k += base
+               }
+               bias = k + ((base-tmin+1)*delta)/(delta+skew)
+
+               n += i / (len(output) + 1)
+               if n > utf8.MaxRune {
+                       rst.fail("punycode rune overflow")
+               }
+               i %= len(output) + 1
+               output = append(output, 0)
+               copy(output[i+1:], output[i:])
+               output[i] = rune(n)
+               i++
+       }
+
+       return string(output)
+}
+
+// <generic-arg> = <lifetime>
+//               | <type>
+//               | "K" <const> // forward-compat for const generics
+// <lifetime> = "L" <base-62-number>
+func (rst *rustState) genericArg() {
+       if len(rst.str) < 1 {
+               rst.fail("expected generic-arg")
+       }
+       if rst.str[0] == 'L' {
+               rst.advance(1)
+               rst.writeLifetime(rst.base62Number())
+       } else if rst.str[0] == 'K' {
+               rst.advance(1)
+               rst.demangleConst()
+       } else {
+               rst.demangleType()
+       }
+}
+
+// <binder> = "G" <base-62-number>
+// This is optional.
+func (rst *rustState) binder() {
+       if len(rst.str) < 1 || rst.str[0] != 'G' {
+               return
+       }
+       rst.advance(1)
+
+       binderLifetimes := rst.base62Number() + 1
+
+       // Every bound lifetime should be referenced later.
+       if binderLifetimes >= int64(len(rst.str))-rst.lifetimes {
+               rst.fail("binder lifetimes overflow")
+       }
+
+       rst.writeString("for<")
+       for i := int64(0); i < binderLifetimes; i++ {
+               if i > 0 {
+                       rst.writeString(", ")
+               }
+               rst.lifetimes++
+               rst.writeLifetime(1)
+       }
+       rst.writeString("> ")
+}
+
+// <type> = <basic-type>
+//        | <path>                      // named type
+//        | "A" <type> <const>          // [T; N]
+//        | "S" <type>                  // [T]
+//        | "T" {<type>} "E"            // (T1, T2, T3, ...)
+//        | "R" [<lifetime>] <type>     // &T
+//        | "Q" [<lifetime>] <type>     // &mut T
+//        | "P" <type>                  // *const T
+//        | "O" <type>                  // *mut T
+//        | "F" <fn-sig>                // fn(...) -> ...
+//        | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
+//        | <backref>
+func (rst *rustState) demangleType() {
+       if len(rst.str) < 1 {
+               rst.fail("expected type")
+       }
+       c := rst.str[0]
+       if c >= 'a' && c <= 'z' {
+               rst.basicType()
+               return
+       }
+       switch c {
+       case 'C', 'M', 'X', 'Y', 'N', 'I':
+               rst.path(false)
+       case 'A', 'S':
+               rst.advance(1)
+               rst.writeByte('[')
+               rst.demangleType()
+               if c == 'A' {
+                       rst.writeString("; ")
+                       rst.demangleConst()
+               }
+               rst.writeByte(']')
+       case 'T':
+               rst.advance(1)
+               rst.writeByte('(')
+               c := 0
+               for len(rst.str) > 0 && rst.str[0] != 'E' {
+                       if c > 0 {
+                               rst.writeString(", ")
+                       }
+                       c++
+                       rst.demangleType()
+               }
+               if c == 1 {
+                       rst.writeByte(',')
+               }
+               rst.writeByte(')')
+               rst.checkChar('E')
+       case 'R', 'Q':
+               rst.advance(1)
+               rst.writeByte('&')
+               if len(rst.str) > 0 && rst.str[0] == 'L' {
+                       rst.advance(1)
+                       if lifetime := rst.base62Number(); lifetime > 0 {
+                               rst.writeLifetime(lifetime)
+                               rst.writeByte(' ')
+                       }
+               }
+               if c == 'Q' {
+                       rst.writeString("mut ")
+               }
+               rst.demangleType()
+       case 'P':
+               rst.advance(1)
+               rst.writeString("*const ")
+               rst.demangleType()
+       case 'O':
+               rst.advance(1)
+               rst.writeString("*mut ")
+               rst.demangleType()
+       case 'F':
+               rst.advance(1)
+               hold := rst.lifetimes
+               rst.fnSig()
+               rst.lifetimes = hold
+       case 'D':
+               rst.advance(1)
+               hold := rst.lifetimes
+               rst.dynBounds()
+               rst.lifetimes = hold
+               if len(rst.str) == 0 || rst.str[0] != 'L' {
+                       rst.fail("expected L")
+               }
+               rst.advance(1)
+               if lifetime := rst.base62Number(); lifetime > 0 {
+                       if rst.last != ' ' {
+                               rst.writeByte(' ')
+                       }
+                       rst.writeString("+ ")
+                       rst.writeLifetime(lifetime)
+               }
+       case 'B':
+               rst.backref(rst.demangleType)
+       default:
+               rst.fail("unrecognized character in type")
+       }
+}
+
+var rustBasicTypes = map[byte]string{
+       'a': "i8",
+       'b': "bool",
+       'c': "char",
+       'd': "f64",
+       'e': "str",
+       'f': "f32",
+       'h': "u8",
+       'i': "isize",
+       'j': "usize",
+       'l': "i32",
+       'm': "u32",
+       'n': "i128",
+       'o': "u128",
+       'p': "_",
+       's': "i16",
+       't': "u16",
+       'u': "()",
+       'v': "...",
+       'x': "i64",
+       'y': "u64",
+       'z': "!",
+}
+
+// <basic-type>
+func (rst *rustState) basicType() {
+       if len(rst.str) < 1 {
+               rst.fail("expected basic type")
+       }
+       str, ok := rustBasicTypes[rst.str[0]]
+       if !ok {
+               rst.fail("unrecognized basic type character")
+       }
+       rst.advance(1)
+       rst.writeString(str)
+}
+
+// <fn-sig> = [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
+// <abi> = "C"
+//       | <undisambiguated-identifier>
+func (rst *rustState) fnSig() {
+       rst.binder()
+       if len(rst.str) > 0 && rst.str[0] == 'U' {
+               rst.advance(1)
+               rst.writeString("unsafe ")
+       }
+       if len(rst.str) > 0 && rst.str[0] == 'K' {
+               rst.advance(1)
+               if len(rst.str) > 0 && rst.str[0] == 'C' {
+                       rst.advance(1)
+                       rst.writeString(`extern "C" `)
+               } else {
+                       rst.writeString(`extern "`)
+                       id := rst.undisambiguatedIdentifier()
+                       id = strings.ReplaceAll(id, "_", "-")
+                       rst.writeString(id)
+                       rst.writeString(`" `)
+               }
+       }
+       rst.writeString("fn(")
+       first := true
+       for len(rst.str) > 0 && rst.str[0] != 'E' {
+               if first {
+                       first = false
+               } else {
+                       rst.writeString(", ")
+               }
+               rst.demangleType()
+       }
+       rst.checkChar('E')
+       rst.writeByte(')')
+       if len(rst.str) > 0 && rst.str[0] == 'u' {
+               rst.advance(1)
+       } else {
+               rst.writeString(" -> ")
+               rst.demangleType()
+       }
+}
+
+// <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
+func (rst *rustState) dynBounds() {
+       rst.writeString("dyn ")
+       rst.binder()
+       first := true
+       for len(rst.str) > 0 && rst.str[0] != 'E' {
+               if first {
+                       first = false
+               } else {
+                       rst.writeString(" + ")
+               }
+               rst.dynTrait()
+       }
+       rst.checkChar('E')
+}
+
+// <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
+// <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
+func (rst *rustState) dynTrait() {
+       started := rst.pathStartGenerics()
+       for len(rst.str) > 0 && rst.str[0] == 'p' {
+               rst.advance(1)
+               if started {
+                       rst.writeString(", ")
+               } else {
+                       rst.writeByte('<')
+                       started = true
+               }
+               rst.writeString(rst.undisambiguatedIdentifier())
+               rst.writeString(" = ")
+               rst.demangleType()
+       }
+       if started {
+               rst.writeByte('>')
+       }
+}
+
+// pathStartGenerics is like path but if it sees an I to start generic
+// arguments it won't close them. It reports whether it started generics.
+func (rst *rustState) pathStartGenerics() bool {
+       if len(rst.str) < 1 {
+               rst.fail("expected path")
+       }
+       switch rst.str[0] {
+       case 'I':
+               rst.advance(1)
+               rst.path(false)
+               rst.writeByte('<')
+               first := true
+               for len(rst.str) > 0 && rst.str[0] != 'E' {
+                       if first {
+                               first = false
+                       } else {
+                               rst.writeString(", ")
+                       }
+                       rst.genericArg()
+               }
+               rst.checkChar('E')
+               return true
+       case 'B':
+               var started bool
+               rst.backref(func() { started = rst.pathStartGenerics() })
+               return started
+       default:
+               rst.path(false)
+               return false
+       }
+}
+
+// writeLifetime writes out a lifetime binding.
+func (rst *rustState) writeLifetime(lifetime int64) {
+       rst.writeByte('\'')
+       if lifetime == 0 {
+               rst.writeByte('_')
+               return
+       }
+       depth := rst.lifetimes - lifetime
+       if depth < 0 {
+               rst.fail("invalid lifetime")
+       } else if depth < 26 {
+               rst.writeByte('a' + byte(depth))
+       } else {
+               rst.writeByte('z')
+               if !rst.skip {
+                       fmt.Fprintf(&rst.buf, "%d", depth-26+1)
+                       rst.last = '0'
+               }
+       }
+}
+
+// <const> = <type> <const-data>
+//         | "p" // placeholder, shown as _
+//         | <backref>
+// <const-data> = ["n"] {<hex-digit>} "_"
+func (rst *rustState) demangleConst() {
+       if len(rst.str) < 1 {
+               rst.fail("expected constant")
+       }
+
+       if rst.str[0] == 'B' {
+               rst.backref(rst.demangleConst)
+               return
+       }
+
+       if rst.str[0] == 'p' {
+               rst.advance(1)
+               rst.writeByte('_')
+               return
+       }
+
+       typ := rst.str[0]
+
+       const (
+               invalid = iota
+               signedInt
+               unsignedInt
+               boolean
+               character
+       )
+
+       var kind int
+       switch typ {
+       case 'a', 's', 'l', 'x', 'n', 'i':
+               kind = signedInt
+       case 'h', 't', 'm', 'y', 'o', 'j':
+               kind = unsignedInt
+       case 'b':
+               kind = boolean
+       case 'c':
+               kind = character
+       default:
+               rst.fail("unrecognized constant type")
+       }
+
+       rst.advance(1)
+
+       if kind == signedInt && len(rst.str) > 0 && rst.str[0] == 'n' {
+               rst.advance(1)
+               rst.writeByte('-')
+       }
+
+       start := rst.str
+       digits := 0
+       val := uint64(0)
+digitLoop:
+       for len(rst.str) > 0 {
+               c := rst.str[0]
+               var digit uint64
+               switch {
+               case c >= '0' && c <= '9':
+                       digit = uint64(c - '0')
+               case c >= 'a' && c <= 'f':
+                       digit = uint64(c - 'a' + 10)
+               case c == '_':
+                       rst.advance(1)
+                       break digitLoop
+               default:
+                       rst.fail("expected hex digit or _")
+               }
+               rst.advance(1)
+               if val == 0 && digit == 0 && (len(rst.str) == 0 || rst.str[0] != '_') {
+                       rst.fail("invalid leading 0 in constant")
+               }
+               val *= 16
+               val += digit
+               digits++
+       }
+
+       if digits == 0 {
+               rst.fail("expected constant")
+       }
+
+       switch kind {
+       case signedInt, unsignedInt:
+               if digits > 16 {
+                       // Value too big, just write out the string.
+                       rst.writeString("0x")
+                       rst.writeString(start[:digits])
+               } else {
+                       if !rst.skip {
+                               fmt.Fprintf(&rst.buf, "%d", val)
+                               rst.last = '0'
+                       }
+               }
+       case boolean:
+               if digits > 1 {
+                       rst.fail("boolean value too large")
+               } else if val == 0 {
+                       rst.writeString("false")
+               } else if val == 1 {
+                       rst.writeString("true")
+               } else {
+                       rst.fail("invalid boolean value")
+               }
+       case character:
+               if digits > 6 {
+                       rst.fail("character value too large")
+               }
+               rst.writeByte('\'')
+               if val == '\t' {
+                       rst.writeString(`\t`)
+               } else if val == '\r' {
+                       rst.writeString(`\r`)
+               } else if val == '\n' {
+                       rst.writeString(`\n`)
+               } else if val == '\\' {
+                       rst.writeString(`\\`)
+               } else if val == '\'' {
+                       rst.writeString(`\'`)
+               } else if val >= ' ' && val <= '~' {
+                       // printable ASCII character
+                       rst.writeByte(byte(val))
+               } else {
+                       if !rst.skip {
+                               fmt.Fprintf(&rst.buf, `\u{%x}`, val)
+                               rst.last = '}'
+                       }
+               }
+               rst.writeByte('\'')
+       default:
+               panic("internal error")
+       }
+}
+
+// <base-62-number> = {<0-9a-zA-Z>} "_"
+func (rst *rustState) base62Number() int64 {
+       if len(rst.str) > 0 && rst.str[0] == '_' {
+               rst.advance(1)
+               return 0
+       }
+       val := int64(0)
+       for len(rst.str) > 0 {
+               c := rst.str[0]
+               rst.advance(1)
+               if c == '_' {
+                       return val + 1
+               }
+               val *= 62
+               if c >= '0' && c <= '9' {
+                       val += int64(c - '0')
+               } else if c >= 'a' && c <= 'z' {
+                       val += int64(c - 'a' + 10)
+               } else if c >= 'A' && c <= 'Z' {
+                       val += int64(c - 'A' + 36)
+               } else {
+                       rst.fail("invalid digit in base 62 number")
+               }
+       }
+       rst.fail("expected _ after base 62 number")
+       return 0
+}
+
+// <backref> = "B" <base-62-number>
+func (rst *rustState) backref(demangle func()) {
+       backoff := rst.off
+
+       rst.checkChar('B')
+       idx64 := rst.base62Number()
+
+       if rst.skip {
+               return
+       }
+
+       idx := int(idx64)
+       if int64(idx) != idx64 {
+               rst.fail("backref index overflow")
+       }
+       if idx < 0 || idx >= backoff {
+               rst.fail("invalid backref index")
+       }
+
+       holdStr := rst.str
+       holdOff := rst.off
+       rst.str = rst.orig[idx:backoff]
+       rst.off = idx
+       defer func() {
+               rst.str = holdStr
+               rst.off = holdOff
+       }()
+
+       demangle()
+}
+
+func (rst *rustState) decimalNumber() int {
+       if len(rst.str) == 0 {
+               rst.fail("expected number")
+       }
+
+       val := 0
+       for len(rst.str) > 0 && isDigit(rst.str[0]) {
+               add := int(rst.str[0] - '0')
+               if val >= math.MaxInt32/10-add {
+                       rst.fail("decimal number overflow")
+               }
+               val *= 10
+               val += add
+               rst.advance(1)
+       }
+       return val
+}
+
+// oldRustToString demangles a Rust symbol using the old demangling.
+// The second result reports whether this is a valid Rust mangled name.
+func oldRustToString(name string, options []Option) (string, bool) {
+       // We know that the string starts with _ZN.
+       name = name[3:]
+
+       hexDigit := func(c byte) (byte, bool) {
+               switch {
+               case c >= '0' && c <= '9':
+                       return c - '0', true
+               case c >= 'a' && c <= 'f':
+                       return c - 'a' + 10, true
+               default:
+                       return 0, false
+               }
+       }
+
+       // We know that the strings end with "17h" followed by 16 characters
+       // followed by "E". We check that the 16 characters are all hex digits.
+       // Also the hex digits must contain at least 5 distinct digits.
+       seen := uint16(0)
+       for i := len(name) - 17; i < len(name) - 1; i++ {
+               digit, ok := hexDigit(name[i])
+               if !ok {
+                       return "", false
+               }
+               seen |= 1 << digit
+       }
+       if bits.OnesCount16(seen) < 5 {
+               return "", false
+       }
+       name = name[:len(name)-20]
+
+       // The name is a sequence of length-preceded identifiers.
+       var sb strings.Builder
+       for len(name) > 0 {
+               if !isDigit(name[0]) {
+                       return "", false
+               }
+
+               val := 0
+               for len(name) > 0 && isDigit(name[0]) {
+                       add := int(name[0] - '0')
+                       if val >= math.MaxInt32/10-add {
+                               return "", false
+                       }
+                       val *= 10
+                       val += add
+                       name = name[1:]
+               }
+
+               // An optional trailing underscore can separate the
+               // length from the identifier.
+               if len(name) > 0 && name[0] == '_' {
+                       name = name[1:]
+                       val--
+               }
+
+               if len(name) < val {
+                       return "", false
+               }
+
+               id := name[:val]
+               name = name[val:]
+
+               if sb.Len() > 0 {
+                       sb.WriteString("::")
+               }
+
+               // Ignore leading underscores preceding escape sequences.
+               if strings.HasPrefix(id, "_$") {
+                       id = id[1:]
+               }
+
+               // The identifier can have escape sequences.
+       escape:
+               for len(id) > 0 {
+                       switch c := id[0]; c {
+                       case '$':
+                               codes := map[string]byte {
+                                       "SP": '@',
+                                       "BP": '*',
+                                       "RF": '&',
+                                       "LT": '<',
+                                       "GT": '>',
+                                       "LP": '(',
+                                       "RP": ')',
+                               }
+
+                               valid := true
+                               if len(id) > 2 && id[1] == 'C' && id[2] == '$' {
+                                       sb.WriteByte(',')
+                                       id = id[3:]
+                               } else if len(id) > 4 && id[1] == 'u' && id[4] == '$' {
+                                       dig1, ok1 := hexDigit(id[2])
+                                       dig2, ok2 := hexDigit(id[3])
+                                       val := (dig1 << 4) | dig2
+                                       if !ok1 || !ok2 || dig1 > 7 || val < ' ' {
+                                               valid = false
+                                       } else {
+                                               sb.WriteByte(val)
+                                               id = id[5:]
+                                       }
+                               } else if len(id) > 3 && id[3] == '$' {
+                                       if code, ok := codes[id[1:3]]; !ok {
+                                               valid = false
+                                       } else {
+                                               sb.WriteByte(code)
+                                               id = id[4:]
+                                       }
+                               } else {
+                                       valid = false
+                               }
+                               if !valid {
+                                       sb.WriteString(id)
+                                       break escape
+                               }
+                       case '.':
+                               if strings.HasPrefix(id, "..") {
+                                       sb.WriteString("::")
+                                       id = id[2:]
+                               } else {
+                                       sb.WriteByte(c)
+                                       id = id[1:]
+                               }
+                       default:
+                               sb.WriteByte(c)
+                               id = id[1:]
+                       }
+               }
+       }
+
+       return sb.String(), true
+}
index 3aaf0b2a3030cc33352116b6c94f579c931128db..f4eef8c0a77edde18d186705974e7ff264d9a358 100644 (file)
@@ -500,7 +500,7 @@ SHA256SU0
 SHA256SU1
 `)
 
-// floating point instrcutions without "F" prefix.
+// floating point instructions without "F" prefix.
 var fOpsWithoutFPrefix = map[Op]bool{
        LDP: true,
        STP: true,
index 78f83fa7144f0318379ebb0c4797540959c7b511..98211a450a2c5392e2bc8348cbb30cf60a21c4a5 100644 (file)
@@ -423,68 +423,12 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
                }
 
        case "replace":
-               arrow := 2
-               if len(args) >= 2 && args[1] == "=>" {
-                       arrow = 1
-               }
-               if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" {
-                       errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb)
-                       return
-               }
-               s, err := parseString(&args[0])
-               if err != nil {
-                       errorf("invalid quoted string: %v", err)
-                       return
-               }
-               pathMajor, err := modulePathMajor(s)
-               if err != nil {
-                       wrapModPathError(s, err)
-                       return
-               }
-               var v string
-               if arrow == 2 {
-                       v, err = parseVersion(verb, s, &args[1], fix)
-                       if err != nil {
-                               wrapError(err)
-                               return
-                       }
-                       if err := module.CheckPathMajor(v, pathMajor); err != nil {
-                               wrapModPathError(s, err)
-                               return
-                       }
-               }
-               ns, err := parseString(&args[arrow+1])
-               if err != nil {
-                       errorf("invalid quoted string: %v", err)
+               replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix)
+               if wrappederr != nil {
+                       *errs = append(*errs, *wrappederr)
                        return
                }
-               nv := ""
-               if len(args) == arrow+2 {
-                       if !IsDirectoryPath(ns) {
-                               errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)")
-                               return
-                       }
-                       if filepath.Separator == '/' && strings.Contains(ns, `\`) {
-                               errorf("replacement directory appears to be Windows path (on a non-windows system)")
-                               return
-                       }
-               }
-               if len(args) == arrow+3 {
-                       nv, err = parseVersion(verb, ns, &args[arrow+2], fix)
-                       if err != nil {
-                               wrapError(err)
-                               return
-                       }
-                       if IsDirectoryPath(ns) {
-                               errorf("replacement module directory path %q cannot have version", ns)
-                               return
-                       }
-               }
-               f.Replace = append(f.Replace, &Replace{
-                       Old:    module.Version{Path: s, Version: v},
-                       New:    module.Version{Path: ns, Version: nv},
-                       Syntax: line,
-               })
+               f.Replace = append(f.Replace, replace)
 
        case "retract":
                rationale := parseDirectiveComment(block, line)
@@ -515,6 +459,83 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
        }
 }
 
+func parseReplace(filename string, line *Line, verb string, args []string, fix VersionFixer) (*Replace, *Error) {
+       wrapModPathError := func(modPath string, err error) *Error {
+               return &Error{
+                       Filename: filename,
+                       Pos:      line.Start,
+                       ModPath:  modPath,
+                       Verb:     verb,
+                       Err:      err,
+               }
+       }
+       wrapError := func(err error) *Error {
+               return &Error{
+                       Filename: filename,
+                       Pos:      line.Start,
+                       Err:      err,
+               }
+       }
+       errorf := func(format string, args ...interface{}) *Error {
+               return wrapError(fmt.Errorf(format, args...))
+       }
+
+       arrow := 2
+       if len(args) >= 2 && args[1] == "=>" {
+               arrow = 1
+       }
+       if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" {
+               return nil, errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb)
+       }
+       s, err := parseString(&args[0])
+       if err != nil {
+               return nil, errorf("invalid quoted string: %v", err)
+       }
+       pathMajor, err := modulePathMajor(s)
+       if err != nil {
+               return nil, wrapModPathError(s, err)
+
+       }
+       var v string
+       if arrow == 2 {
+               v, err = parseVersion(verb, s, &args[1], fix)
+               if err != nil {
+                       return nil, wrapError(err)
+               }
+               if err := module.CheckPathMajor(v, pathMajor); err != nil {
+                       return nil, wrapModPathError(s, err)
+               }
+       }
+       ns, err := parseString(&args[arrow+1])
+       if err != nil {
+               return nil, errorf("invalid quoted string: %v", err)
+       }
+       nv := ""
+       if len(args) == arrow+2 {
+               if !IsDirectoryPath(ns) {
+                       return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)")
+               }
+               if filepath.Separator == '/' && strings.Contains(ns, `\`) {
+                       return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)")
+               }
+       }
+       if len(args) == arrow+3 {
+               nv, err = parseVersion(verb, ns, &args[arrow+2], fix)
+               if err != nil {
+                       return nil, wrapError(err)
+               }
+               if IsDirectoryPath(ns) {
+                       return nil, errorf("replacement module directory path %q cannot have version", ns)
+
+               }
+       }
+       return &Replace{
+               Old:    module.Version{Path: s, Version: v},
+               New:    module.Version{Path: ns, Version: nv},
+               Syntax: line,
+       }, nil
+}
+
 // fixRetract applies fix to each retract directive in f, appending any errors
 // to errs.
 //
@@ -556,6 +577,63 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) {
        }
 }
 
+func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, fix VersionFixer) {
+       wrapError := func(err error) {
+               *errs = append(*errs, Error{
+                       Filename: f.Syntax.Name,
+                       Pos:      line.Start,
+                       Err:      err,
+               })
+       }
+       errorf := func(format string, args ...interface{}) {
+               wrapError(fmt.Errorf(format, args...))
+       }
+
+       switch verb {
+       default:
+               errorf("unknown directive: %s", verb)
+
+       case "go":
+               if f.Go != nil {
+                       errorf("repeated go statement")
+                       return
+               }
+               if len(args) != 1 {
+                       errorf("go directive expects exactly one argument")
+                       return
+               } else if !GoVersionRE.MatchString(args[0]) {
+                       errorf("invalid go version '%s': must match format 1.23", args[0])
+                       return
+               }
+
+               f.Go = &Go{Syntax: line}
+               f.Go.Version = args[0]
+
+       case "directory":
+               if len(args) != 1 {
+                       errorf("usage: %s local/dir", verb)
+                       return
+               }
+               s, err := parseString(&args[0])
+               if err != nil {
+                       errorf("invalid quoted string: %v", err)
+                       return
+               }
+               f.Directory = append(f.Directory, &Directory{
+                       Path:   s,
+                       Syntax: line,
+               })
+
+       case "replace":
+               replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix)
+               if wrappederr != nil {
+                       *errs = append(*errs, *wrappederr)
+                       return
+               }
+               f.Replace = append(f.Replace, replace)
+       }
+}
+
 // IsDirectoryPath reports whether the given path should be interpreted
 // as a directory path. Just like on the go command line, relative paths
 // and rooted paths are directory paths; the rest are module paths.
@@ -956,170 +1034,217 @@ func (f *File) SetRequire(req []*Require) {
 
 // SetRequireSeparateIndirect updates the requirements of f to contain the given
 // requirements. Comment contents (except for 'indirect' markings) are retained
-// from the first existing requirement for each module path, and block structure
-// is maintained as long as the indirect markings match.
+// from the first existing requirement for each module path. Like SetRequire,
+// SetRequireSeparateIndirect adds requirements for new paths in req,
+// updates the version and "// indirect" comment on existing requirements,
+// and deletes requirements on paths not in req. Existing duplicate requirements
+// are deleted.
 //
-// Any requirements on paths not already present in the file are added. Direct
-// requirements are added to the last block containing *any* other direct
-// requirement. Indirect requirements are added to the last block containing
-// *only* other indirect requirements. If no suitable block exists, a new one is
-// added, with the last block containing a direct dependency (if any)
-// immediately before the first block containing only indirect dependencies.
+// As its name suggests, SetRequireSeparateIndirect puts direct and indirect
+// requirements into two separate blocks, one containing only direct
+// requirements, and the other containing only indirect requirements.
+// SetRequireSeparateIndirect may move requirements between these two blocks
+// when their indirect markings change. However, SetRequireSeparateIndirect
+// won't move requirements from other blocks, especially blocks with comments.
 //
-// The Syntax field is ignored for requirements in the given blocks.
+// If the file initially has one uncommented block of requirements,
+// SetRequireSeparateIndirect will split it into a direct-only and indirect-only
+// block. This aids in the transition to separate blocks.
 func (f *File) SetRequireSeparateIndirect(req []*Require) {
-       type modKey struct {
-               path     string
-               indirect bool
-       }
-       need := make(map[modKey]string)
-       for _, r := range req {
-               need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version
+       // hasComments returns whether a line or block has comments
+       // other than "indirect".
+       hasComments := func(c Comments) bool {
+               return len(c.Before) > 0 || len(c.After) > 0 || len(c.Suffix) > 1 ||
+                       (len(c.Suffix) == 1 &&
+                               strings.TrimSpace(strings.TrimPrefix(c.Suffix[0].Token, string(slashSlash))) != "indirect")
        }
 
-       comments := make(map[string]Comments)
-       for _, r := range f.Require {
-               v, ok := need[modKey{r.Mod.Path, r.Indirect}]
-               if !ok {
-                       if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok {
-                               if _, dup := comments[r.Mod.Path]; !dup {
-                                       comments[r.Mod.Path] = r.Syntax.Comments
-                               }
+       // moveReq adds r to block. If r was in another block, moveReq deletes
+       // it from that block and transfers its comments.
+       moveReq := func(r *Require, block *LineBlock) {
+               var line *Line
+               if r.Syntax == nil {
+                       line = &Line{Token: []string{AutoQuote(r.Mod.Path), r.Mod.Version}}
+                       r.Syntax = line
+                       if r.Indirect {
+                               r.setIndirect(true)
                        }
-                       r.markRemoved()
-                       continue
+               } else {
+                       line = new(Line)
+                       *line = *r.Syntax
+                       if !line.InBlock && len(line.Token) > 0 && line.Token[0] == "require" {
+                               line.Token = line.Token[1:]
+                       }
+                       r.Syntax.Token = nil // Cleanup will delete the old line.
+                       r.Syntax = line
                }
-               r.setVersion(v)
-               delete(need, modKey{r.Mod.Path, r.Indirect})
+               line.InBlock = true
+               block.Line = append(block.Line, line)
        }
 
+       // Examine existing require lines and blocks.
        var (
-               lastDirectOrMixedBlock Expr
-               firstIndirectOnlyBlock Expr
-               lastIndirectOnlyBlock  Expr
+               // We may insert new requirements into the last uncommented
+               // direct-only and indirect-only blocks. We may also move requirements
+               // to the opposite block if their indirect markings change.
+               lastDirectIndex   = -1
+               lastIndirectIndex = -1
+
+               // If there are no direct-only or indirect-only blocks, a new block may
+               // be inserted after the last require line or block.
+               lastRequireIndex = -1
+
+               // If there's only one require line or block, and it's uncommented,
+               // we'll move its requirements to the direct-only or indirect-only blocks.
+               requireLineOrBlockCount = 0
+
+               // Track the block each requirement belongs to (if any) so we can
+               // move them later.
+               lineToBlock = make(map[*Line]*LineBlock)
        )
-       for _, stmt := range f.Syntax.Stmt {
+       for i, stmt := range f.Syntax.Stmt {
                switch stmt := stmt.(type) {
                case *Line:
                        if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
                                continue
                        }
-                       if isIndirect(stmt) {
-                               lastIndirectOnlyBlock = stmt
-                       } else {
-                               lastDirectOrMixedBlock = stmt
+                       lastRequireIndex = i
+                       requireLineOrBlockCount++
+                       if !hasComments(stmt.Comments) {
+                               if isIndirect(stmt) {
+                                       lastIndirectIndex = i
+                               } else {
+                                       lastDirectIndex = i
+                               }
                        }
+
                case *LineBlock:
                        if len(stmt.Token) == 0 || stmt.Token[0] != "require" {
                                continue
                        }
-                       indirectOnly := true
+                       lastRequireIndex = i
+                       requireLineOrBlockCount++
+                       allDirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments)
+                       allIndirect := len(stmt.Line) > 0 && !hasComments(stmt.Comments)
                        for _, line := range stmt.Line {
-                               if len(line.Token) == 0 {
-                                       continue
-                               }
-                               if !isIndirect(line) {
-                                       indirectOnly = false
-                                       break
+                               lineToBlock[line] = stmt
+                               if hasComments(line.Comments) {
+                                       allDirect = false
+                                       allIndirect = false
+                               } else if isIndirect(line) {
+                                       allDirect = false
+                               } else {
+                                       allIndirect = false
                                }
                        }
-                       if indirectOnly {
-                               lastIndirectOnlyBlock = stmt
-                               if firstIndirectOnlyBlock == nil {
-                                       firstIndirectOnlyBlock = stmt
-                               }
-                       } else {
-                               lastDirectOrMixedBlock = stmt
+                       if allDirect {
+                               lastDirectIndex = i
+                       }
+                       if allIndirect {
+                               lastIndirectIndex = i
                        }
                }
        }
 
-       isOrContainsStmt := func(stmt Expr, target Expr) bool {
-               if stmt == target {
-                       return true
-               }
-               if stmt, ok := stmt.(*LineBlock); ok {
-                       if target, ok := target.(*Line); ok {
-                               for _, line := range stmt.Line {
-                                       if line == target {
-                                               return true
-                                       }
-                               }
+       oneFlatUncommentedBlock := requireLineOrBlockCount == 1 &&
+               !hasComments(*f.Syntax.Stmt[lastRequireIndex].Comment())
+
+       // Create direct and indirect blocks if needed. Convert lines into blocks
+       // if needed. If we end up with an empty block or a one-line block,
+       // Cleanup will delete it or convert it to a line later.
+       insertBlock := func(i int) *LineBlock {
+               block := &LineBlock{Token: []string{"require"}}
+               f.Syntax.Stmt = append(f.Syntax.Stmt, nil)
+               copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:])
+               f.Syntax.Stmt[i] = block
+               return block
+       }
+
+       ensureBlock := func(i int) *LineBlock {
+               switch stmt := f.Syntax.Stmt[i].(type) {
+               case *LineBlock:
+                       return stmt
+               case *Line:
+                       block := &LineBlock{
+                               Token: []string{"require"},
+                               Line:  []*Line{stmt},
                        }
+                       stmt.Token = stmt.Token[1:] // remove "require"
+                       stmt.InBlock = true
+                       f.Syntax.Stmt[i] = block
+                       return block
+               default:
+                       panic(fmt.Sprintf("unexpected statement: %v", stmt))
                }
-               return false
        }
 
-       addRequire := func(path, vers string, indirect bool, comments Comments) {
-               var line *Line
-               if indirect {
-                       if lastIndirectOnlyBlock != nil {
-                               line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers)
-                       } else {
-                               // Add a new require block after the last direct-only or mixed "require"
-                               // block (if any).
-                               //
-                               // (f.Syntax.addLine would add the line to an existing "require" block if
-                               // present, but here the existing "require" blocks are all direct-only, so
-                               // we know we need to add a new block instead.)
-                               line = &Line{Token: []string{"require", path, vers}}
-                               lastIndirectOnlyBlock = line
-                               firstIndirectOnlyBlock = line // only block implies first block
-                               if lastDirectOrMixedBlock == nil {
-                                       f.Syntax.Stmt = append(f.Syntax.Stmt, line)
-                               } else {
-                                       for i, stmt := range f.Syntax.Stmt {
-                                               if isOrContainsStmt(stmt, lastDirectOrMixedBlock) {
-                                                       f.Syntax.Stmt = append(f.Syntax.Stmt, nil)     // increase size
-                                                       copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up
-                                                       f.Syntax.Stmt[i+1] = line
-                                                       break
-                                               }
-                                       }
-                               }
-                       }
+       var lastDirectBlock *LineBlock
+       if lastDirectIndex < 0 {
+               if lastIndirectIndex >= 0 {
+                       lastDirectIndex = lastIndirectIndex
+                       lastIndirectIndex++
+               } else if lastRequireIndex >= 0 {
+                       lastDirectIndex = lastRequireIndex + 1
                } else {
-                       if lastDirectOrMixedBlock != nil {
-                               line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers)
-                       } else {
-                               // Add a new require block before the first indirect block (if any).
-                               //
-                               // That way if the file initially contains only indirect lines,
-                               // the direct lines still appear before it: we preserve existing
-                               // structure, but only to the extent that that structure already
-                               // reflects the direct/indirect split.
-                               line = &Line{Token: []string{"require", path, vers}}
-                               lastDirectOrMixedBlock = line
-                               if firstIndirectOnlyBlock == nil {
-                                       f.Syntax.Stmt = append(f.Syntax.Stmt, line)
-                               } else {
-                                       for i, stmt := range f.Syntax.Stmt {
-                                               if isOrContainsStmt(stmt, firstIndirectOnlyBlock) {
-                                                       f.Syntax.Stmt = append(f.Syntax.Stmt, nil)   // increase size
-                                                       copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up
-                                                       f.Syntax.Stmt[i] = line
-                                                       break
-                                               }
-                                       }
-                               }
-                       }
+                       lastDirectIndex = len(f.Syntax.Stmt)
                }
+               lastDirectBlock = insertBlock(lastDirectIndex)
+       } else {
+               lastDirectBlock = ensureBlock(lastDirectIndex)
+       }
 
-               line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before)
-               line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix)
+       var lastIndirectBlock *LineBlock
+       if lastIndirectIndex < 0 {
+               lastIndirectIndex = lastDirectIndex + 1
+               lastIndirectBlock = insertBlock(lastIndirectIndex)
+       } else {
+               lastIndirectBlock = ensureBlock(lastIndirectIndex)
+       }
 
-               r := &Require{
-                       Mod:      module.Version{Path: path, Version: vers},
-                       Indirect: indirect,
-                       Syntax:   line,
+       // Delete requirements we don't want anymore.
+       // Update versions and indirect comments on requirements we want to keep.
+       // If a requirement is in last{Direct,Indirect}Block with the wrong
+       // indirect marking after this, or if the requirement is in an single
+       // uncommented mixed block (oneFlatUncommentedBlock), move it to the
+       // correct block.
+       //
+       // Some blocks may be empty after this. Cleanup will remove them.
+       need := make(map[string]*Require)
+       for _, r := range req {
+               need[r.Mod.Path] = r
+       }
+       have := make(map[string]*Require)
+       for _, r := range f.Require {
+               path := r.Mod.Path
+               if need[path] == nil || have[path] != nil {
+                       // Requirement not needed, or duplicate requirement. Delete.
+                       r.markRemoved()
+                       continue
+               }
+               have[r.Mod.Path] = r
+               r.setVersion(need[path].Mod.Version)
+               r.setIndirect(need[path].Indirect)
+               if need[path].Indirect &&
+                       (oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastDirectBlock) {
+                       moveReq(r, lastIndirectBlock)
+               } else if !need[path].Indirect &&
+                       (oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastIndirectBlock) {
+                       moveReq(r, lastDirectBlock)
                }
-               r.setIndirect(indirect)
-               f.Require = append(f.Require, r)
        }
 
-       for k, vers := range need {
-               addRequire(k.path, vers, k.indirect, comments[k.path])
+       // Add new requirements.
+       for path, r := range need {
+               if have[path] == nil {
+                       if r.Indirect {
+                               moveReq(r, lastIndirectBlock)
+                       } else {
+                               moveReq(r, lastDirectBlock)
+                       }
+                       f.Require = append(f.Require, r)
+               }
        }
+
        f.SortBlocks()
 }
 
@@ -1165,6 +1290,10 @@ func (f *File) DropExclude(path, vers string) error {
 }
 
 func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
+       return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers)
+}
+
+func addReplace(syntax *FileSyntax, replace *[]*Replace, oldPath, oldVers, newPath, newVers string) error {
        need := true
        old := module.Version{Path: oldPath, Version: oldVers}
        new := module.Version{Path: newPath, Version: newVers}
@@ -1178,12 +1307,12 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
        }
 
        var hint *Line
-       for _, r := range f.Replace {
+       for _, r := range *replace {
                if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) {
                        if need {
                                // Found replacement for old; update to use new.
                                r.New = new
-                               f.Syntax.updateLine(r.Syntax, tokens...)
+                               syntax.updateLine(r.Syntax, tokens...)
                                need = false
                                continue
                        }
@@ -1196,7 +1325,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
                }
        }
        if need {
-               f.Replace = append(f.Replace, &Replace{Old: old, New: new, Syntax: f.Syntax.addLine(hint, tokens...)})
+               *replace = append(*replace, &Replace{Old: old, New: new, Syntax: syntax.addLine(hint, tokens...)})
        }
        return nil
 }
@@ -1282,30 +1411,36 @@ func (f *File) SortBlocks() {
 // retract directives are not de-duplicated since comments are
 // meaningful, and versions may be retracted multiple times.
 func (f *File) removeDups() {
+       removeDups(f.Syntax, &f.Exclude, &f.Replace)
+}
+
+func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace) {
        kill := make(map[*Line]bool)
 
        // Remove duplicate excludes.
-       haveExclude := make(map[module.Version]bool)
-       for _, x := range f.Exclude {
-               if haveExclude[x.Mod] {
-                       kill[x.Syntax] = true
-                       continue
+       if exclude != nil {
+               haveExclude := make(map[module.Version]bool)
+               for _, x := range *exclude {
+                       if haveExclude[x.Mod] {
+                               kill[x.Syntax] = true
+                               continue
+                       }
+                       haveExclude[x.Mod] = true
                }
-               haveExclude[x.Mod] = true
-       }
-       var excl []*Exclude
-       for _, x := range f.Exclude {
-               if !kill[x.Syntax] {
-                       excl = append(excl, x)
+               var excl []*Exclude
+               for _, x := range *exclude {
+                       if !kill[x.Syntax] {
+                               excl = append(excl, x)
+                       }
                }
+               *exclude = excl
        }
-       f.Exclude = excl
 
        // Remove duplicate replacements.
        // Later replacements take priority over earlier ones.
        haveReplace := make(map[module.Version]bool)
-       for i := len(f.Replace) - 1; i >= 0; i-- {
-               x := f.Replace[i]
+       for i := len(*replace) - 1; i >= 0; i-- {
+               x := (*replace)[i]
                if haveReplace[x.Old] {
                        kill[x.Syntax] = true
                        continue
@@ -1313,18 +1448,18 @@ func (f *File) removeDups() {
                haveReplace[x.Old] = true
        }
        var repl []*Replace
-       for _, x := range f.Replace {
+       for _, x := range *replace {
                if !kill[x.Syntax] {
                        repl = append(repl, x)
                }
        }
-       f.Replace = repl
+       *replace = repl
 
        // Duplicate require and retract directives are not removed.
 
        // Drop killed statements from the syntax tree.
        var stmts []Expr
-       for _, stmt := range f.Syntax.Stmt {
+       for _, stmt := range syntax.Stmt {
                switch stmt := stmt.(type) {
                case *Line:
                        if kill[stmt] {
@@ -1344,7 +1479,7 @@ func (f *File) removeDups() {
                }
                stmts = append(stmts, stmt)
        }
-       f.Syntax.Stmt = stmts
+       syntax.Stmt = stmts
 }
 
 // lineLess returns whether li should be sorted before lj. It sorts
diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/work.go b/src/cmd/vendor/golang.org/x/mod/modfile/work.go
new file mode 100644 (file)
index 0000000..b1fabff
--- /dev/null
@@ -0,0 +1,234 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfile
+
+import (
+       "fmt"
+       "sort"
+       "strings"
+)
+
+// A WorkFile is the parsed, interpreted form of a go.work file.
+type WorkFile struct {
+       Go        *Go
+       Directory []*Directory
+       Replace   []*Replace
+
+       Syntax *FileSyntax
+}
+
+// A Directory is a single directory statement.
+type Directory struct {
+       Path       string // Directory path of module.
+       ModulePath string // Module path in the comment.
+       Syntax     *Line
+}
+
+// ParseWork parses and returns a go.work file.
+//
+// file is the name of the file, used in positions and errors.
+//
+// data is the content of the file.
+//
+// fix is an optional function that canonicalizes module versions.
+// If fix is nil, all module versions must be canonical (module.CanonicalVersion
+// must return the same string).
+func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) {
+       fs, err := parse(file, data)
+       if err != nil {
+               return nil, err
+       }
+       f := &WorkFile{
+               Syntax: fs,
+       }
+       var errs ErrorList
+
+       for _, x := range fs.Stmt {
+               switch x := x.(type) {
+               case *Line:
+                       f.add(&errs, x, x.Token[0], x.Token[1:], fix)
+
+               case *LineBlock:
+                       if len(x.Token) > 1 {
+                               errs = append(errs, Error{
+                                       Filename: file,
+                                       Pos:      x.Start,
+                                       Err:      fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")),
+                               })
+                               continue
+                       }
+                       switch x.Token[0] {
+                       default:
+                               errs = append(errs, Error{
+                                       Filename: file,
+                                       Pos:      x.Start,
+                                       Err:      fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")),
+                               })
+                               continue
+                       case "directory", "replace":
+                               for _, l := range x.Line {
+                                       f.add(&errs, l, x.Token[0], l.Token, fix)
+                               }
+                       }
+               }
+       }
+
+       if len(errs) > 0 {
+               return nil, errs
+       }
+       return f, nil
+}
+
+// Cleanup cleans up the file f after any edit operations.
+// To avoid quadratic behavior, modifications like DropRequire
+// clear the entry but do not remove it from the slice.
+// Cleanup cleans out all the cleared entries.
+func (f *WorkFile) Cleanup() {
+       w := 0
+       for _, r := range f.Directory {
+               if r.Path != "" {
+                       f.Directory[w] = r
+                       w++
+               }
+       }
+       f.Directory = f.Directory[:w]
+
+       w = 0
+       for _, r := range f.Replace {
+               if r.Old.Path != "" {
+                       f.Replace[w] = r
+                       w++
+               }
+       }
+       f.Replace = f.Replace[:w]
+
+       f.Syntax.Cleanup()
+}
+
+func (f *WorkFile) AddGoStmt(version string) error {
+       if !GoVersionRE.MatchString(version) {
+               return fmt.Errorf("invalid language version string %q", version)
+       }
+       if f.Go == nil {
+               stmt := &Line{Token: []string{"go", version}}
+               f.Go = &Go{
+                       Version: version,
+                       Syntax:  stmt,
+               }
+               // Find the first non-comment-only block that's and add
+               // the go statement before it. That will keep file comments at the top.
+               i := 0
+               for i = 0; i < len(f.Syntax.Stmt); i++ {
+                       if _, ok := f.Syntax.Stmt[i].(*CommentBlock); !ok {
+                               break
+                       }
+               }
+               f.Syntax.Stmt = append(append(f.Syntax.Stmt[:i:i], stmt), f.Syntax.Stmt[i:]...)
+       } else {
+               f.Go.Version = version
+               f.Syntax.updateLine(f.Go.Syntax, "go", version)
+       }
+       return nil
+}
+
+func (f *WorkFile) AddDirectory(diskPath, modulePath string) error {
+       need := true
+       for _, d := range f.Directory {
+               if d.Path == diskPath {
+                       if need {
+                               d.ModulePath = modulePath
+                               f.Syntax.updateLine(d.Syntax, "directory", AutoQuote(diskPath))
+                               need = false
+                       } else {
+                               d.Syntax.markRemoved()
+                               *d = Directory{}
+                       }
+               }
+       }
+
+       if need {
+               f.AddNewDirectory(diskPath, modulePath)
+       }
+       return nil
+}
+
+func (f *WorkFile) AddNewDirectory(diskPath, modulePath string) {
+       line := f.Syntax.addLine(nil, "directory", AutoQuote(diskPath))
+       f.Directory = append(f.Directory, &Directory{Path: diskPath, ModulePath: modulePath, Syntax: line})
+}
+
+func (f *WorkFile) SetDirectory(dirs []*Directory) {
+       need := make(map[string]string)
+       for _, d := range dirs {
+               need[d.Path] = d.ModulePath
+       }
+
+       for _, d := range f.Directory {
+               if modulePath, ok := need[d.Path]; ok {
+                       d.ModulePath = modulePath
+               } else {
+                       d.Syntax.markRemoved()
+                       *d = Directory{}
+               }
+       }
+
+       // TODO(#45713): Add module path to comment.
+
+       for diskPath, modulePath := range need {
+               f.AddNewDirectory(diskPath, modulePath)
+       }
+       f.SortBlocks()
+}
+
+func (f *WorkFile) DropDirectory(path string) error {
+       for _, d := range f.Directory {
+               if d.Path == path {
+                       d.Syntax.markRemoved()
+                       *d = Directory{}
+               }
+       }
+       return nil
+}
+
+func (f *WorkFile) AddReplace(oldPath, oldVers, newPath, newVers string) error {
+       return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers)
+}
+
+func (f *WorkFile) DropReplace(oldPath, oldVers string) error {
+       for _, r := range f.Replace {
+               if r.Old.Path == oldPath && r.Old.Version == oldVers {
+                       r.Syntax.markRemoved()
+                       *r = Replace{}
+               }
+       }
+       return nil
+}
+
+func (f *WorkFile) SortBlocks() {
+       f.removeDups() // otherwise sorting is unsafe
+
+       for _, stmt := range f.Syntax.Stmt {
+               block, ok := stmt.(*LineBlock)
+               if !ok {
+                       continue
+               }
+               sort.SliceStable(block.Line, func(i, j int) bool {
+                       return lineLess(block.Line[i], block.Line[j])
+               })
+       }
+}
+
+// removeDups removes duplicate replace directives.
+//
+// Later replace directives take priority.
+//
+// require directives are not de-duplicated. That's left up to higher-level
+// logic (MVS).
+//
+// retract directives are not de-duplicated since comments are
+// meaningful, and versions may be retracted multiple times.
+func (f *WorkFile) removeDups() {
+       removeDups(f.Syntax, nil, &f.Replace)
+}
index ba97ac356e9cb34f73f6a756a9f65eedbdca25b0..89bd3ede2776f75bb5b99767c976c9dea45e6c56 100644 (file)
@@ -286,12 +286,7 @@ func fileNameOK(r rune) bool {
                if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
                        return true
                }
-               for i := 0; i < len(allowed); i++ {
-                       if rune(allowed[i]) == r {
-                               return true
-                       }
-               }
-               return false
+               return strings.ContainsRune(allowed, r)
        }
        // It may be OK to add more ASCII punctuation here, but only carefully.
        // For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
index 5b401ad4d8fb28fd4b19c076b0c1b06ddbae8567..ca0f7ad42f1819cf89908f04b10559110d102426 100644 (file)
@@ -53,6 +53,7 @@ import (
        "io"
        "io/ioutil"
        "os"
+       "os/exec"
        "path"
        "path/filepath"
        "strings"
@@ -192,8 +193,10 @@ func CheckFiles(files []File) (CheckedFiles, error) {
 }
 
 // checkFiles implements CheckFiles and also returns lists of valid files and
-// their sizes, corresponding to cf.Valid. These lists are used in Crewate to
-// avoid repeated calls to File.Lstat.
+// their sizes, corresponding to cf.Valid. It omits files in submodules, files
+// in vendored packages, symlinked files, and various other unwanted files.
+//
+// The lists returned are used in Create to avoid repeated calls to File.Lstat.
 func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes []int64) {
        errPaths := make(map[string]struct{})
        addError := func(path string, omitted bool, err error) {
@@ -254,10 +257,12 @@ func checkFiles(files []File) (cf CheckedFiles, validFiles []File, validSizes []
                        continue
                }
                if isVendoredPackage(p) {
+                       // Skip files in vendored packages.
                        addError(p, true, errVendored)
                        continue
                }
                if inSubmodule(p) {
+                       // Skip submodule files.
                        addError(p, true, errSubmoduleFile)
                        continue
                }
@@ -551,7 +556,7 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) {
                if zerr, ok := err.(*zipError); ok {
                        zerr.path = dir
                } else if err != nil {
-                       err = &zipError{verb: "create zip", path: dir, err: err}
+                       err = &zipError{verb: "create zip from directory", path: dir, err: err}
                }
        }()
 
@@ -563,6 +568,129 @@ func CreateFromDir(w io.Writer, m module.Version, dir string) (err error) {
        return Create(w, m, files)
 }
 
+// CreateFromVCS creates a module zip file for module m from the contents of a
+// VCS repository stored locally. The zip content is written to w.
+//
+// repoRoot must be an absolute path to the base of the repository, such as
+// "/Users/some-user/some-repo".
+//
+// revision is the revision of the repository to create the zip from. Examples
+// include HEAD or SHA sums for git repositories.
+//
+// subdir must be the relative path from the base of the repository, such as
+// "sub/dir". To create a zip from the base of the repository, pass an empty
+// string.
+//
+// If CreateFromVCS returns ErrUnrecognizedVCS, consider falling back to
+// CreateFromDir.
+func CreateFromVCS(w io.Writer, m module.Version, repoRoot, revision, subdir string) (err error) {
+       defer func() {
+               if zerr, ok := err.(*zipError); ok {
+                       zerr.path = repoRoot
+               } else if err != nil {
+                       err = &zipError{verb: "create zip from version control system", path: repoRoot, err: err}
+               }
+       }()
+
+       var filesToCreate []File
+
+       switch {
+       case isGitRepo(repoRoot):
+               files, err := filesInGitRepo(repoRoot, revision, subdir)
+               if err != nil {
+                       return err
+               }
+
+               filesToCreate = files
+       default:
+               return &UnrecognizedVCSError{RepoRoot: repoRoot}
+       }
+
+       return Create(w, m, filesToCreate)
+}
+
+// UnrecognizedVCSError indicates that no recognized version control system was
+// found in the given directory.
+type UnrecognizedVCSError struct {
+       RepoRoot string
+}
+
+func (e *UnrecognizedVCSError) Error() string {
+       return fmt.Sprintf("could not find a recognized version control system at %q", e.RepoRoot)
+}
+
+// filterGitIgnored filters out any files that are git ignored in the directory.
+func filesInGitRepo(dir, rev, subdir string) ([]File, error) {
+       stderr := bytes.Buffer{}
+       stdout := bytes.Buffer{}
+
+       // Incredibly, git produces different archives depending on whether
+       // it is running on a Windows system or not, in an attempt to normalize
+       // text file line endings. Setting -c core.autocrlf=input means only
+       // translate files on the way into the repo, not on the way out (archive).
+       // The -c core.eol=lf should be unnecessary but set it anyway.
+       //
+       // Note: We use git archive to understand which files are actually included,
+       // ignoring things like .gitignore'd files. We could also use other
+       // techniques like git ls-files, but this approach most closely matches what
+       // the Go command does, which is beneficial.
+       //
+       // Note: some of this code copied from https://go.googlesource.com/go/+/refs/tags/go1.16.5/src/cmd/go/internal/modfetch/codehost/git.go#826.
+       cmd := exec.Command("git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", rev)
+       if subdir != "" {
+               cmd.Args = append(cmd.Args, subdir)
+       }
+       cmd.Dir = dir
+       cmd.Stdout = &stdout
+       cmd.Stderr = &stderr
+       if err := cmd.Run(); err != nil {
+               return nil, fmt.Errorf("error running `git archive`: %w, %s", err, stderr.String())
+       }
+
+       rawReader := bytes.NewReader(stdout.Bytes())
+       zipReader, err := zip.NewReader(rawReader, int64(stdout.Len()))
+       if err != nil {
+               return nil, err
+       }
+
+       var fs []File
+       for _, zf := range zipReader.File {
+               if !strings.HasPrefix(zf.Name, subdir) || strings.HasSuffix(zf.Name, "/") {
+                       continue
+               }
+
+               n := strings.TrimPrefix(zf.Name, subdir)
+               if n == "" {
+                       continue
+               }
+               n = strings.TrimPrefix(n, string(filepath.Separator))
+
+               fs = append(fs, zipFile{
+                       name: n,
+                       f:    zf,
+               })
+       }
+
+       return fs, nil
+}
+
+// isGitRepo reports whether the given directory is a git repo.
+func isGitRepo(dir string) bool {
+       stdout := &bytes.Buffer{}
+       cmd := exec.Command("git", "rev-parse", "--git-dir")
+       cmd.Dir = dir
+       cmd.Stdout = stdout
+       if err := cmd.Run(); err != nil {
+               return false
+       }
+       gitDir := strings.TrimSpace(string(stdout.Bytes()))
+       if !filepath.IsAbs(gitDir) {
+               gitDir = filepath.Join(dir, gitDir)
+       }
+       wantDir := filepath.Join(dir, ".git")
+       return wantDir == gitDir
+}
+
 type dirFile struct {
        filePath, slashPath string
        info                os.FileInfo
@@ -572,6 +700,15 @@ func (f dirFile) Path() string                 { return f.slashPath }
 func (f dirFile) Lstat() (os.FileInfo, error)  { return f.info, nil }
 func (f dirFile) Open() (io.ReadCloser, error) { return os.Open(f.filePath) }
 
+type zipFile struct {
+       name string
+       f    *zip.File
+}
+
+func (f zipFile) Path() string                 { return f.name }
+func (f zipFile) Lstat() (os.FileInfo, error)  { return f.f.FileInfo(), nil }
+func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() }
+
 // isVendoredPackage attempts to report whether the given filename is contained
 // in a package whose import path contains (but does not end with) the component
 // "vendor".
diff --git a/src/cmd/vendor/golang.org/x/sync/AUTHORS b/src/cmd/vendor/golang.org/x/sync/AUTHORS
new file mode 100644 (file)
index 0000000..15167cd
--- /dev/null
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/src/cmd/vendor/golang.org/x/sync/CONTRIBUTORS b/src/cmd/vendor/golang.org/x/sync/CONTRIBUTORS
new file mode 100644 (file)
index 0000000..1c4577e
--- /dev/null
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/src/cmd/vendor/golang.org/x/sync/LICENSE b/src/cmd/vendor/golang.org/x/sync/LICENSE
new file mode 100644 (file)
index 0000000..6a66aea
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/cmd/vendor/golang.org/x/sync/PATENTS b/src/cmd/vendor/golang.org/x/sync/PATENTS
new file mode 100644 (file)
index 0000000..7330990
--- /dev/null
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go.  This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation.  If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go b/src/cmd/vendor/golang.org/x/sync/semaphore/semaphore.go
new file mode 100644 (file)
index 0000000..30f632c
--- /dev/null
@@ -0,0 +1,136 @@
+// 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 semaphore provides a weighted semaphore implementation.
+package semaphore // import "golang.org/x/sync/semaphore"
+
+import (
+       "container/list"
+       "context"
+       "sync"
+)
+
+type waiter struct {
+       n     int64
+       ready chan<- struct{} // Closed when semaphore acquired.
+}
+
+// NewWeighted creates a new weighted semaphore with the given
+// maximum combined weight for concurrent access.
+func NewWeighted(n int64) *Weighted {
+       w := &Weighted{size: n}
+       return w
+}
+
+// Weighted provides a way to bound concurrent access to a resource.
+// The callers can request access with a given weight.
+type Weighted struct {
+       size    int64
+       cur     int64
+       mu      sync.Mutex
+       waiters list.List
+}
+
+// Acquire acquires the semaphore with a weight of n, blocking until resources
+// are available or ctx is done. On success, returns nil. On failure, returns
+// ctx.Err() and leaves the semaphore unchanged.
+//
+// If ctx is already done, Acquire may still succeed without blocking.
+func (s *Weighted) Acquire(ctx context.Context, n int64) error {
+       s.mu.Lock()
+       if s.size-s.cur >= n && s.waiters.Len() == 0 {
+               s.cur += n
+               s.mu.Unlock()
+               return nil
+       }
+
+       if n > s.size {
+               // Don't make other Acquire calls block on one that's doomed to fail.
+               s.mu.Unlock()
+               <-ctx.Done()
+               return ctx.Err()
+       }
+
+       ready := make(chan struct{})
+       w := waiter{n: n, ready: ready}
+       elem := s.waiters.PushBack(w)
+       s.mu.Unlock()
+
+       select {
+       case <-ctx.Done():
+               err := ctx.Err()
+               s.mu.Lock()
+               select {
+               case <-ready:
+                       // Acquired the semaphore after we were canceled.  Rather than trying to
+                       // fix up the queue, just pretend we didn't notice the cancelation.
+                       err = nil
+               default:
+                       isFront := s.waiters.Front() == elem
+                       s.waiters.Remove(elem)
+                       // If we're at the front and there're extra tokens left, notify other waiters.
+                       if isFront && s.size > s.cur {
+                               s.notifyWaiters()
+                       }
+               }
+               s.mu.Unlock()
+               return err
+
+       case <-ready:
+               return nil
+       }
+}
+
+// TryAcquire acquires the semaphore with a weight of n without blocking.
+// On success, returns true. On failure, returns false and leaves the semaphore unchanged.
+func (s *Weighted) TryAcquire(n int64) bool {
+       s.mu.Lock()
+       success := s.size-s.cur >= n && s.waiters.Len() == 0
+       if success {
+               s.cur += n
+       }
+       s.mu.Unlock()
+       return success
+}
+
+// Release releases the semaphore with a weight of n.
+func (s *Weighted) Release(n int64) {
+       s.mu.Lock()
+       s.cur -= n
+       if s.cur < 0 {
+               s.mu.Unlock()
+               panic("semaphore: released more than held")
+       }
+       s.notifyWaiters()
+       s.mu.Unlock()
+}
+
+func (s *Weighted) notifyWaiters() {
+       for {
+               next := s.waiters.Front()
+               if next == nil {
+                       break // No more waiters blocked.
+               }
+
+               w := next.Value.(waiter)
+               if s.size-s.cur < w.n {
+                       // Not enough tokens for the next waiter.  We could keep going (to try to
+                       // find a waiter with a smaller request), but under load that could cause
+                       // starvation for large requests; instead, we leave all remaining waiters
+                       // blocked.
+                       //
+                       // Consider a semaphore used as a read-write lock, with N tokens, N
+                       // readers, and one writer.  Each reader can Acquire(1) to obtain a read
+                       // lock.  The writer can Acquire(N) to obtain a write lock, excluding all
+                       // of the readers.  If we allow the readers to jump ahead in the queue,
+                       // the writer will starve — there is always one token available for every
+                       // reader.
+                       break
+               }
+
+               s.cur += w.n
+               s.waiters.Remove(next)
+               close(w.ready)
+       }
+}
index 579d2d73557fb5a9c78c542af11c81a9c67f3faf..474efad0e03c7813ef066a928e60628a20a3dc57 100644 (file)
@@ -76,7 +76,7 @@ arguments can be passed to the kernel. The third is for low-level use by the
 ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
 let it know that a system call is running.
 
-When porting Go to an new architecture/OS, this file must be implemented for
+When porting Go to a new architecture/OS, this file must be implemented for
 each GOOS/GOARCH pair.
 
 ### mksysnum
@@ -107,7 +107,7 @@ prototype can be exported (capitalized) or not.
 Adding a new syscall often just requires adding a new `//sys` function prototype
 with the desired arguments and a capitalized name so it is exported. However, if
 you want the interface to the syscall to be different, often one will make an
-unexported `//sys` prototype, an then write a custom wrapper in
+unexported `//sys` prototype, and then write a custom wrapper in
 `syscall_${GOOS}.go`.
 
 ### types files
@@ -137,7 +137,7 @@ some `#if/#elif` macros in your include statements.
 
 This script is used to generate the system's various constants. This doesn't
 just include the error numbers and error strings, but also the signal numbers
-an a wide variety of miscellaneous constants. The constants come from the list
+and a wide variety of miscellaneous constants. The constants come from the list
 of include files in the `includes_${uname}` variable. A regex then picks out
 the desired `#define` statements, and generates the corresponding Go constants.
 The error numbers and strings are generated from `#include <errno.h>`, and the
index 7f29275fa000d810cea70b59c9c9fe7f24ea115f..e0fcd9b3deec595ed3b327d134de1913aa0242ae 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (darwin || freebsd || netbsd || openbsd) && gc
-// +build darwin freebsd netbsd openbsd
+//go:build (freebsd || netbsd || openbsd) && gc
+// +build freebsd netbsd openbsd
 // +build gc
 
 #include "textflag.h"
index 98ebfad9d512f1dcd4ce6ce00bdfa99e49bb3663..d702d4adc77d770ceb4f09f22c616a5878c0aa4b 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (darwin || freebsd || netbsd || openbsd) && gc
-// +build darwin freebsd netbsd openbsd
+//go:build (freebsd || netbsd || openbsd) && gc
+// +build freebsd netbsd openbsd
 // +build gc
 
 #include "textflag.h"
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ifreq_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/ifreq_linux.go
new file mode 100644 (file)
index 0000000..934af31
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2021 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:build linux
+// +build linux
+
+package unix
+
+import (
+       "bytes"
+       "unsafe"
+)
+
+// Helpers for dealing with ifreq since it contains a union and thus requires a
+// lot of unsafe.Pointer casts to use properly.
+
+// An Ifreq is a type-safe wrapper around the raw ifreq struct. An Ifreq
+// contains an interface name and a union of arbitrary data which can be
+// accessed using the Ifreq's methods. To create an Ifreq, use the NewIfreq
+// function.
+//
+// Use the Name method to access the stored interface name. The union data
+// fields can be get and set using the following methods:
+//   - Uint16/SetUint16: flags
+//   - Uint32/SetUint32: ifindex, metric, mtu
+type Ifreq struct{ raw ifreq }
+
+// NewIfreq creates an Ifreq with the input network interface name after
+// validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
+// bytes.
+func NewIfreq(name string) (*Ifreq, error) {
+       // Leave room for terminating NULL byte.
+       if len(name) >= IFNAMSIZ {
+               return nil, EINVAL
+       }
+
+       var ifr ifreq
+       copy(ifr.Ifrn[:], name)
+
+       return &Ifreq{raw: ifr}, nil
+}
+
+// TODO(mdlayher): get/set methods for hardware address sockaddr, char array, etc.
+
+// Name returns the interface name associated with the Ifreq.
+func (ifr *Ifreq) Name() string {
+       // BytePtrToString requires a NULL terminator or the program may crash. If
+       // one is not present, just return the empty string.
+       if !bytes.Contains(ifr.raw.Ifrn[:], []byte{0x00}) {
+               return ""
+       }
+
+       return BytePtrToString(&ifr.raw.Ifrn[0])
+}
+
+// According to netdevice(7), only AF_INET addresses are returned for numerous
+// sockaddr ioctls. For convenience, we expose these as Inet4Addr since the Port
+// field and other data is always empty.
+
+// Inet4Addr returns the Ifreq union data from an embedded sockaddr as a C
+// in_addr/Go []byte (4-byte IPv4 address) value. If the sockaddr family is not
+// AF_INET, an error is returned.
+func (ifr *Ifreq) Inet4Addr() ([]byte, error) {
+       raw := *(*RawSockaddrInet4)(unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]))
+       if raw.Family != AF_INET {
+               // Cannot safely interpret raw.Addr bytes as an IPv4 address.
+               return nil, EINVAL
+       }
+
+       return raw.Addr[:], nil
+}
+
+// SetInet4Addr sets a C in_addr/Go []byte (4-byte IPv4 address) value in an
+// embedded sockaddr within the Ifreq's union data. v must be 4 bytes in length
+// or an error will be returned.
+func (ifr *Ifreq) SetInet4Addr(v []byte) error {
+       if len(v) != 4 {
+               return EINVAL
+       }
+
+       var addr [4]byte
+       copy(addr[:], v)
+
+       ifr.clear()
+       *(*RawSockaddrInet4)(
+               unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]),
+       ) = RawSockaddrInet4{
+               // Always set IP family as ioctls would require it anyway.
+               Family: AF_INET,
+               Addr:   addr,
+       }
+
+       return nil
+}
+
+// Uint16 returns the Ifreq union data as a C short/Go uint16 value.
+func (ifr *Ifreq) Uint16() uint16 {
+       return *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0]))
+}
+
+// SetUint16 sets a C short/Go uint16 value as the Ifreq's union data.
+func (ifr *Ifreq) SetUint16(v uint16) {
+       ifr.clear()
+       *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0])) = v
+}
+
+// Uint32 returns the Ifreq union data as a C int/Go uint32 value.
+func (ifr *Ifreq) Uint32() uint32 {
+       return *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0]))
+}
+
+// SetUint32 sets a C int/Go uint32 value as the Ifreq's union data.
+func (ifr *Ifreq) SetUint32(v uint32) {
+       ifr.clear()
+       *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0])) = v
+}
+
+// clear zeroes the ifreq's union field to prevent trailing garbage data from
+// being sent to the kernel if an ifreq is reused.
+func (ifr *Ifreq) clear() {
+       for i := range ifr.raw.Ifru {
+               ifr.raw.Ifru[i] = 0
+       }
+}
+
+// TODO(mdlayher): export as IfreqData? For now we can provide helpers such as
+// IoctlGetEthtoolDrvinfo which use these APIs under the hood.
+
+// An ifreqData is an Ifreq which carries pointer data. To produce an ifreqData,
+// use the Ifreq.withData method.
+type ifreqData struct {
+       name [IFNAMSIZ]byte
+       // A type separate from ifreq is required in order to comply with the
+       // unsafe.Pointer rules since the "pointer-ness" of data would not be
+       // preserved if it were cast into the byte array of a raw ifreq.
+       data unsafe.Pointer
+       // Pad to the same size as ifreq.
+       _ [len(ifreq{}.Ifru) - SizeofPtr]byte
+}
+
+// withData produces an ifreqData with the pointer p set for ioctls which require
+// arbitrary pointer data.
+func (ifr Ifreq) withData(p unsafe.Pointer) ifreqData {
+       return ifreqData{
+               name: ifr.raw.Ifrn,
+               data: p,
+       }
+}
index 48773f730ac63ccc09db548c59131b7c658f5317..1dadead21e6d6a1ea5b7edebdbdcdec773dec1c6 100644 (file)
@@ -5,7 +5,6 @@
 package unix
 
 import (
-       "runtime"
        "unsafe"
 )
 
@@ -22,56 +21,42 @@ func IoctlRetInt(fd int, req uint) (int, error) {
 
 func IoctlGetUint32(fd int, req uint) (uint32, error) {
        var value uint32
-       err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+       err := ioctlPtr(fd, req, unsafe.Pointer(&value))
        return value, err
 }
 
 func IoctlGetRTCTime(fd int) (*RTCTime, error) {
        var value RTCTime
-       err := ioctl(fd, RTC_RD_TIME, uintptr(unsafe.Pointer(&value)))
+       err := ioctlPtr(fd, RTC_RD_TIME, unsafe.Pointer(&value))
        return &value, err
 }
 
 func IoctlSetRTCTime(fd int, value *RTCTime) error {
-       err := ioctl(fd, RTC_SET_TIME, uintptr(unsafe.Pointer(value)))
-       runtime.KeepAlive(value)
-       return err
+       return ioctlPtr(fd, RTC_SET_TIME, unsafe.Pointer(value))
 }
 
 func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
        var value RTCWkAlrm
-       err := ioctl(fd, RTC_WKALM_RD, uintptr(unsafe.Pointer(&value)))
+       err := ioctlPtr(fd, RTC_WKALM_RD, unsafe.Pointer(&value))
        return &value, err
 }
 
 func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
-       err := ioctl(fd, RTC_WKALM_SET, uintptr(unsafe.Pointer(value)))
-       runtime.KeepAlive(value)
-       return err
-}
-
-type ifreqEthtool struct {
-       name [IFNAMSIZ]byte
-       data unsafe.Pointer
+       return ioctlPtr(fd, RTC_WKALM_SET, unsafe.Pointer(value))
 }
 
 // IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
 // device specified by ifname.
 func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
-       // Leave room for terminating NULL byte.
-       if len(ifname) >= IFNAMSIZ {
-               return nil, EINVAL
+       ifr, err := NewIfreq(ifname)
+       if err != nil {
+               return nil, err
        }
 
-       value := EthtoolDrvinfo{
-               Cmd: ETHTOOL_GDRVINFO,
-       }
-       ifreq := ifreqEthtool{
-               data: unsafe.Pointer(&value),
-       }
-       copy(ifreq.name[:], ifname)
-       err := ioctl(fd, SIOCETHTOOL, uintptr(unsafe.Pointer(&ifreq)))
-       runtime.KeepAlive(ifreq)
+       value := EthtoolDrvinfo{Cmd: ETHTOOL_GDRVINFO}
+       ifrd := ifr.withData(unsafe.Pointer(&value))
+
+       err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
        return &value, err
 }
 
@@ -80,7 +65,7 @@ func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
 // https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
 func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) {
        var value WatchdogInfo
-       err := ioctl(fd, WDIOC_GETSUPPORT, uintptr(unsafe.Pointer(&value)))
+       err := ioctlPtr(fd, WDIOC_GETSUPPORT, unsafe.Pointer(&value))
        return &value, err
 }
 
@@ -88,6 +73,7 @@ func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) {
 // more information, see:
 // https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
 func IoctlWatchdogKeepalive(fd int) error {
+       // arg is ignored and not a pointer, so ioctl is fine instead of ioctlPtr.
        return ioctl(fd, WDIOC_KEEPALIVE, 0)
 }
 
@@ -95,9 +81,7 @@ func IoctlWatchdogKeepalive(fd int) error {
 // range of data conveyed in value to the file associated with the file
 // descriptor destFd. See the ioctl_ficlonerange(2) man page for details.
 func IoctlFileCloneRange(destFd int, value *FileCloneRange) error {
-       err := ioctl(destFd, FICLONERANGE, uintptr(unsafe.Pointer(value)))
-       runtime.KeepAlive(value)
-       return err
+       return ioctlPtr(destFd, FICLONERANGE, unsafe.Pointer(value))
 }
 
 // IoctlFileClone performs an FICLONE ioctl operation to clone the entire file
@@ -148,7 +132,7 @@ func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error {
                rawinfo.Reserved = value.Info[i].Reserved
        }
 
-       err := ioctl(srcFd, FIDEDUPERANGE, uintptr(unsafe.Pointer(&buf[0])))
+       err := ioctlPtr(srcFd, FIDEDUPERANGE, unsafe.Pointer(&buf[0]))
 
        // Output
        for i := range value.Info {
@@ -166,31 +150,47 @@ func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error {
 }
 
 func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error {
-       err := ioctl(fd, HIDIOCGRDESC, uintptr(unsafe.Pointer(value)))
-       runtime.KeepAlive(value)
-       return err
+       return ioctlPtr(fd, HIDIOCGRDESC, unsafe.Pointer(value))
 }
 
 func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) {
        var value HIDRawDevInfo
-       err := ioctl(fd, HIDIOCGRAWINFO, uintptr(unsafe.Pointer(&value)))
+       err := ioctlPtr(fd, HIDIOCGRAWINFO, unsafe.Pointer(&value))
        return &value, err
 }
 
 func IoctlHIDGetRawName(fd int) (string, error) {
        var value [_HIDIOCGRAWNAME_LEN]byte
-       err := ioctl(fd, _HIDIOCGRAWNAME, uintptr(unsafe.Pointer(&value[0])))
+       err := ioctlPtr(fd, _HIDIOCGRAWNAME, unsafe.Pointer(&value[0]))
        return ByteSliceToString(value[:]), err
 }
 
 func IoctlHIDGetRawPhys(fd int) (string, error) {
        var value [_HIDIOCGRAWPHYS_LEN]byte
-       err := ioctl(fd, _HIDIOCGRAWPHYS, uintptr(unsafe.Pointer(&value[0])))
+       err := ioctlPtr(fd, _HIDIOCGRAWPHYS, unsafe.Pointer(&value[0]))
        return ByteSliceToString(value[:]), err
 }
 
 func IoctlHIDGetRawUniq(fd int) (string, error) {
        var value [_HIDIOCGRAWUNIQ_LEN]byte
-       err := ioctl(fd, _HIDIOCGRAWUNIQ, uintptr(unsafe.Pointer(&value[0])))
+       err := ioctlPtr(fd, _HIDIOCGRAWUNIQ, unsafe.Pointer(&value[0]))
        return ByteSliceToString(value[:]), err
 }
+
+// IoctlIfreq performs an ioctl using an Ifreq structure for input and/or
+// output. See the netdevice(7) man page for details.
+func IoctlIfreq(fd int, req uint, value *Ifreq) error {
+       // It is possible we will add more fields to *Ifreq itself later to prevent
+       // misuse, so pass the raw *ifreq directly.
+       return ioctlPtr(fd, req, unsafe.Pointer(&value.raw))
+}
+
+// TODO(mdlayher): export if and when IfreqData is exported.
+
+// ioctlIfreqData performs an ioctl using an ifreqData structure for input
+// and/or output. See the netdevice(7) man page for details.
+func ioctlIfreqData(fd int, req uint, value *ifreqData) error {
+       // The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are
+       // identical so pass *IfreqData directly.
+       return ioctlPtr(fd, req, unsafe.Pointer(value))
+}
index 007358af8fc18789e1384d52c1657a10eba5c089..a74ef58f8c62d289b36f68eb29737e0f6fe8cd4d 100644 (file)
@@ -54,7 +54,7 @@ includes_AIX='
 
 includes_Darwin='
 #define _DARWIN_C_SOURCE
-#define KERNEL
+#define KERNEL 1
 #define _DARWIN_USE_64_BIT_INODE
 #define __APPLE_USE_RFC_3542
 #include <stdint.h>
@@ -75,6 +75,7 @@ includes_Darwin='
 #include <sys/utsname.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
+#include <sys/vsock.h>
 #include <net/bpf.h>
 #include <net/if.h>
 #include <net/if_types.h>
@@ -82,6 +83,9 @@ includes_Darwin='
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <termios.h>
+
+// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk.
+#define TIOCREMOTE 0x80047469
 '
 
 includes_DragonFly='
@@ -217,8 +221,6 @@ struct ltchars {
 #include <linux/genetlink.h>
 #include <linux/hdreg.h>
 #include <linux/hidraw.h>
-#include <linux/icmp.h>
-#include <linux/icmpv6.h>
 #include <linux/if.h>
 #include <linux/if_addr.h>
 #include <linux/if_alg.h>
@@ -231,6 +233,7 @@ struct ltchars {
 #include <linux/input.h>
 #include <linux/kexec.h>
 #include <linux/keyctl.h>
+#include <linux/landlock.h>
 #include <linux/loop.h>
 #include <linux/lwtunnel.h>
 #include <linux/magic.h>
@@ -239,6 +242,7 @@ struct ltchars {
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netlink.h>
 #include <linux/net_namespace.h>
+#include <linux/nfc.h>
 #include <linux/nsfs.h>
 #include <linux/perf_event.h>
 #include <linux/pps.h>
@@ -258,6 +262,7 @@ struct ltchars {
 #include <linux/watchdog.h>
 
 #include <mtd/ubi-user.h>
+#include <mtd/mtd-user.h>
 #include <net/route.h>
 
 #if defined(__sparc__)
@@ -465,7 +470,6 @@ ccflags="$@"
                $2 !~ /^EQUIV_/ &&
                $2 !~ /^EXPR_/ &&
                $2 !~ /^EVIOC/ &&
-               $2 !~ /^EV_/ &&
                $2 ~ /^E[A-Z0-9_]+$/ ||
                $2 ~ /^B[0-9_]+$/ ||
                $2 ~ /^(OLD|NEW)DEV$/ ||
@@ -497,10 +501,14 @@ ccflags="$@"
                $2 ~ /^O?XTABS$/ ||
                $2 ~ /^TC[IO](ON|OFF)$/ ||
                $2 ~ /^IN_/ ||
+               $2 ~ /^LANDLOCK_/ ||
                $2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
                $2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
                $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
-               $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL)_/ ||
+               $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT)_/ ||
+               $2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
+               $2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
+               $2 ~ /^RAW_PAYLOAD_/ ||
                $2 ~ /^TP_STATUS_/ ||
                $2 ~ /^FALLOC_/ ||
                $2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
@@ -558,6 +566,7 @@ ccflags="$@"
                $2 ~ /^KEYCTL_/ ||
                $2 ~ /^PERF_/ ||
                $2 ~ /^SECCOMP_MODE_/ ||
+               $2 ~ /^SEEK_/ ||
                $2 ~ /^SPLICE_/ ||
                $2 ~ /^SYNC_FILE_RANGE_/ ||
                $2 !~ /^AUDIT_RECORD_MAGIC/ &&
@@ -593,6 +602,9 @@ ccflags="$@"
                $2 == "HID_MAX_DESCRIPTOR_SIZE" ||
                $2 ~ /^_?HIDIOC/ ||
                $2 ~ /^BUS_(USB|HIL|BLUETOOTH|VIRTUAL)$/ ||
+               $2 ~ /^MTD/ ||
+               $2 ~ /^OTP/ ||
+               $2 ~ /^MEM/ ||
                $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
                $2 ~ /^__WCOREFLAG$/ {next}
                $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
index 9945e5f9655ad0318ce8f14c80fb2a8a4e617a95..a8c13317d75d55c781ebaed986eea1b0fcf0e716 100644 (file)
@@ -13,6 +13,7 @@
 package unix
 
 import (
+       "fmt"
        "runtime"
        "syscall"
        "unsafe"
@@ -47,6 +48,30 @@ func (sa *SockaddrCtl) sockaddr() (unsafe.Pointer, _Socklen, error) {
        return unsafe.Pointer(&sa.raw), SizeofSockaddrCtl, nil
 }
 
+// SockaddrVM implements the Sockaddr interface for AF_VSOCK type sockets.
+// SockaddrVM provides access to Darwin VM sockets: a mechanism that enables
+// bidirectional communication between a hypervisor and its guest virtual
+// machines.
+type SockaddrVM struct {
+       // CID and Port specify a context ID and port address for a VM socket.
+       // Guests have a unique CID, and hosts may have a well-known CID of:
+       //  - VMADDR_CID_HYPERVISOR: refers to the hypervisor process.
+       //  - VMADDR_CID_LOCAL: refers to local communication (loopback).
+       //  - VMADDR_CID_HOST: refers to other processes on the host.
+       CID  uint32
+       Port uint32
+       raw  RawSockaddrVM
+}
+
+func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) {
+       sa.raw.Len = SizeofSockaddrVM
+       sa.raw.Family = AF_VSOCK
+       sa.raw.Port = sa.Port
+       sa.raw.Cid = sa.CID
+
+       return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil
+}
+
 func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
        switch rsa.Addr.Family {
        case AF_SYSTEM:
@@ -57,6 +82,13 @@ func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
                        sa.Unit = pp.Sc_unit
                        return sa, nil
                }
+       case AF_VSOCK:
+               pp := (*RawSockaddrVM)(unsafe.Pointer(rsa))
+               sa := &SockaddrVM{
+                       CID:  pp.Cid,
+                       Port: pp.Port,
+               }
+               return sa, nil
        }
        return nil, EAFNOSUPPORT
 }
@@ -398,8 +430,45 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) {
        return x, err
 }
 
+func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) {
+       mib, err := sysctlmib(name)
+       if err != nil {
+               return nil, err
+       }
+
+       // Find size.
+       n := uintptr(0)
+       if err := sysctl(mib, nil, &n, nil, 0); err != nil {
+               return nil, err
+       }
+       if n == 0 {
+               return nil, nil
+       }
+       if n%SizeofKinfoProc != 0 {
+               return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc)
+       }
+
+       // Read into buffer of that size.
+       buf := make([]KinfoProc, n/SizeofKinfoProc)
+       if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil {
+               return nil, err
+       }
+       if n%SizeofKinfoProc != 0 {
+               return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc)
+       }
+
+       // The actual call may return less than the original reported required
+       // size so ensure we deal with that.
+       return buf[:n/SizeofKinfoProc], nil
+}
+
 //sys  sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
 
+//sys  shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
+//sys  shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error)
+//sys  shmdt(addr uintptr) (err error)
+//sys  shmget(key int, size int, flag int) (id int, err error)
+
 /*
  * Exposed directly
  */
@@ -557,10 +626,6 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) {
 // Msgget
 // Msgsnd
 // Msgrcv
-// Shmat
-// Shmctl
-// Shmdt
-// Shmget
 // Shm_open
 // Shm_unlink
 // Sem_open
index 8c535768352743581bf0de05566e7a84c8480de6..8d5f294c425047719923573422cc5e4f6c383b98 100644 (file)
@@ -162,6 +162,14 @@ func (l *Lifreq) GetLifruInt() int {
        return *(*int)(unsafe.Pointer(&l.Lifru[0]))
 }
 
+func (l *Lifreq) SetLifruUint(d uint) {
+       *(*uint)(unsafe.Pointer(&l.Lifru[0])) = d
+}
+
+func (l *Lifreq) GetLifruUint() uint {
+       return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
+}
+
 func IoctlLifreq(fd int, req uint, l *Lifreq) error {
        return ioctl(fd, req, uintptr(unsafe.Pointer(l)))
 }
index 2dd7c8e34a940fd17e902c321e8c898b94f86d4b..fff38a84c9c4dafc06c469b77d77186778bb9e02 100644 (file)
@@ -13,7 +13,6 @@ package unix
 
 import (
        "encoding/binary"
-       "runtime"
        "syscall"
        "unsafe"
 )
@@ -38,6 +37,13 @@ func Creat(path string, mode uint32) (fd int, err error) {
        return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
 }
 
+func EpollCreate(size int) (fd int, err error) {
+       if size <= 0 {
+               return -1, EINVAL
+       }
+       return EpollCreate1(0)
+}
+
 //sys  FanotifyInit(flags uint, event_f_flags uint) (fd int, err error)
 //sys  fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error)
 
@@ -66,11 +72,22 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
        return fchmodat(dirfd, path, mode)
 }
 
-//sys  ioctl(fd int, req uint, arg uintptr) (err error)
+func InotifyInit() (fd int, err error) {
+       return InotifyInit1(0)
+}
 
-// ioctl itself should not be exposed directly, but additional get/set
-// functions for specific types are permissible.
-// These are defined in ioctl.go and ioctl_linux.go.
+//sys  ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL
+//sys  ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
+
+// ioctl itself should not be exposed directly, but additional get/set functions
+// for specific types are permissible. These are defined in ioctl.go and
+// ioctl_linux.go.
+//
+// The third argument to ioctl is often a pointer but sometimes an integer.
+// Callers should use ioctlPtr when the third argument is a pointer and ioctl
+// when the third argument is an integer.
+//
+// TODO: some existing code incorrectly uses ioctl when it should use ioctlPtr.
 
 //sys  Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
 
@@ -102,6 +119,23 @@ func Openat2(dirfd int, path string, how *OpenHow) (fd int, err error) {
        return openat2(dirfd, path, how, SizeofOpenHow)
 }
 
+func Pipe(p []int) error {
+       return Pipe2(p, 0)
+}
+
+//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) error {
+       if len(p) != 2 {
+               return EINVAL
+       }
+       var pp [2]_C_int
+       err := pipe2(&pp, flags)
+       p[0] = int(pp[0])
+       p[1] = int(pp[1])
+       return err
+}
+
 //sys  ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error)
 
 func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
@@ -111,6 +145,15 @@ func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error
        return ppoll(&fds[0], len(fds), timeout, sigmask)
 }
 
+func Poll(fds []PollFd, timeout int) (n int, err error) {
+       var ts *Timespec
+       if timeout >= 0 {
+               ts = new(Timespec)
+               *ts = NsecToTimespec(int64(timeout) * 1e6)
+       }
+       return Ppoll(fds, ts, nil)
+}
+
 //sys  Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
 
 func Readlink(path string, buf []byte) (n int, err error) {
@@ -161,27 +204,7 @@ func Utimes(path string, tv []Timeval) error {
 //sys  utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
 
 func UtimesNano(path string, ts []Timespec) error {
-       if ts == nil {
-               err := utimensat(AT_FDCWD, path, nil, 0)
-               if err != ENOSYS {
-                       return err
-               }
-               return utimes(path, nil)
-       }
-       if len(ts) != 2 {
-               return EINVAL
-       }
-       err := utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
-       if err != ENOSYS {
-               return err
-       }
-       // If the utimensat syscall isn't available (utimensat was added to Linux
-       // in 2.6.22, Released, 8 July 2007) then fall back to utimes
-       var tv [2]Timeval
-       for i := 0; i < 2; i++ {
-               tv[i] = NsecToTimeval(TimespecToNsec(ts[i]))
-       }
-       return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+       return UtimesNanoAt(AT_FDCWD, path, ts, 0)
 }
 
 func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
@@ -904,6 +927,46 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
        return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil
 }
 
+type SockaddrNFC struct {
+       DeviceIdx   uint32
+       TargetIdx   uint32
+       NFCProtocol uint32
+       raw         RawSockaddrNFC
+}
+
+func (sa *SockaddrNFC) sockaddr() (unsafe.Pointer, _Socklen, error) {
+       sa.raw.Sa_family = AF_NFC
+       sa.raw.Dev_idx = sa.DeviceIdx
+       sa.raw.Target_idx = sa.TargetIdx
+       sa.raw.Nfc_protocol = sa.NFCProtocol
+       return unsafe.Pointer(&sa.raw), SizeofSockaddrNFC, nil
+}
+
+type SockaddrNFCLLCP struct {
+       DeviceIdx      uint32
+       TargetIdx      uint32
+       NFCProtocol    uint32
+       DestinationSAP uint8
+       SourceSAP      uint8
+       ServiceName    string
+       raw            RawSockaddrNFCLLCP
+}
+
+func (sa *SockaddrNFCLLCP) sockaddr() (unsafe.Pointer, _Socklen, error) {
+       sa.raw.Sa_family = AF_NFC
+       sa.raw.Dev_idx = sa.DeviceIdx
+       sa.raw.Target_idx = sa.TargetIdx
+       sa.raw.Nfc_protocol = sa.NFCProtocol
+       sa.raw.Dsap = sa.DestinationSAP
+       sa.raw.Ssap = sa.SourceSAP
+       if len(sa.ServiceName) > len(sa.raw.Service_name) {
+               return nil, 0, EINVAL
+       }
+       copy(sa.raw.Service_name[:], sa.ServiceName)
+       sa.raw.SetServiceNameLen(len(sa.ServiceName))
+       return unsafe.Pointer(&sa.raw), SizeofSockaddrNFCLLCP, nil
+}
+
 var socketProtocol = func(fd int) (int, error) {
        return GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
 }
@@ -1144,6 +1207,37 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
                        }
                        return sa, nil
                }
+       case AF_NFC:
+               proto, err := socketProtocol(fd)
+               if err != nil {
+                       return nil, err
+               }
+               switch proto {
+               case NFC_SOCKPROTO_RAW:
+                       pp := (*RawSockaddrNFC)(unsafe.Pointer(rsa))
+                       sa := &SockaddrNFC{
+                               DeviceIdx:   pp.Dev_idx,
+                               TargetIdx:   pp.Target_idx,
+                               NFCProtocol: pp.Nfc_protocol,
+                       }
+                       return sa, nil
+               case NFC_SOCKPROTO_LLCP:
+                       pp := (*RawSockaddrNFCLLCP)(unsafe.Pointer(rsa))
+                       if uint64(pp.Service_name_len) > uint64(len(pp.Service_name)) {
+                               return nil, EINVAL
+                       }
+                       sa := &SockaddrNFCLLCP{
+                               DeviceIdx:      pp.Dev_idx,
+                               TargetIdx:      pp.Target_idx,
+                               NFCProtocol:    pp.Nfc_protocol,
+                               DestinationSAP: pp.Dsap,
+                               SourceSAP:      pp.Ssap,
+                               ServiceName:    string(pp.Service_name[:pp.Service_name_len]),
+                       }
+                       return sa, nil
+               default:
+                       return nil, EINVAL
+               }
        }
        return nil, EAFNOSUPPORT
 }
@@ -1151,11 +1245,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
 func Accept(fd int) (nfd int, sa Sockaddr, err error) {
        var rsa RawSockaddrAny
        var len _Socklen = SizeofSockaddrAny
-       // Try accept4 first for Android, then try accept for kernel older than 2.6.28
        nfd, err = accept4(fd, &rsa, &len, 0)
-       if err == ENOSYS {
-               nfd, err = accept(fd, &rsa, &len)
-       }
        if err != nil {
                return
        }
@@ -1277,6 +1367,13 @@ func SetsockoptTpacketReq3(fd, level, opt int, tp *TpacketReq3) error {
        return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
 }
 
+func SetsockoptTCPRepairOpt(fd, level, opt int, o []TCPRepairOpt) (err error) {
+       if len(o) == 0 {
+               return EINVAL
+       }
+       return setsockopt(fd, level, opt, unsafe.Pointer(&o[0]), uintptr(SizeofTCPRepairOpt*len(o)))
+}
+
 // Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
 
 // KeyctlInt calls keyctl commands in which each argument is an int.
@@ -1731,11 +1828,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 //sys  Dup(oldfd int) (fd int, err error)
 
 func Dup2(oldfd, newfd int) error {
-       // Android O and newer blocks dup2; riscv and arm64 don't implement dup2.
-       if runtime.GOOS == "android" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "arm64" {
-               return Dup3(oldfd, newfd, 0)
-       }
-       return dup2(oldfd, newfd)
+       return Dup3(oldfd, newfd, 0)
 }
 
 //sys  Dup3(oldfd int, newfd int, flags int) (err error)
@@ -1788,7 +1881,7 @@ func Getpgrp() (pid int) {
 //sys  Nanosleep(time *Timespec, leftover *Timespec) (err error)
 //sys  PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error)
 //sys  PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
-//sysnb        prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64
+//sysnb        Prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64
 //sys  Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error)
 //sys  Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6
 //sys  read(fd int, p []byte) (n int, err error)
@@ -2223,6 +2316,14 @@ type RemoteIovec struct {
 //sys  ProcessVMReadv(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) = SYS_PROCESS_VM_READV
 //sys  ProcessVMWritev(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) = SYS_PROCESS_VM_WRITEV
 
+//sys  PidfdOpen(pid int, flags int) (fd int, err error) = SYS_PIDFD_OPEN
+//sys  PidfdGetfd(pidfd int, targetfd int, flags int) (fd int, err error) = SYS_PIDFD_GETFD
+
+//sys  shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
+//sys  shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error)
+//sys  shmdt(addr uintptr) (err error)
+//sys  shmget(key int, size int, flag int) (id int, err error)
+
 /*
  * Unimplemented
  */
@@ -2304,10 +2405,6 @@ type RemoteIovec struct {
 // SetRobustList
 // SetThreadArea
 // SetTidAddress
-// Shmat
-// Shmctl
-// Shmdt
-// Shmget
 // Sigaltstack
 // Swapoff
 // Swapon
index 7b52e5d8a40a9275989a128ee4baa60be0cffde6..5f757e8aa770632541210c36ba7dd9e1f600924a 100644 (file)
@@ -19,36 +19,8 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: int32(sec), Usec: int32(usec)}
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 // 64-bit file system and 32-bit uid calls
 // (386 default is 32-bit file system and 16-bit uid).
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64
 //sys  Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
@@ -59,7 +31,6 @@ func Pipe2(p []int, flags int) (err error) {
 //sysnb        Geteuid() (euid int) = SYS_GETEUID32
 //sysnb        Getgid() (gid int) = SYS_GETGID32
 //sysnb        Getuid() (uid int) = SYS_GETUID32
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Ioperm(from int, num int, on int) (err error)
 //sys  Iopl(level int) (err error)
 //sys  Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
@@ -105,7 +76,7 @@ const rlimInf32 = ^uint32(0)
 const rlimInf64 = ^uint64(0)
 
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, nil, rlim)
+       err = Prlimit(0, resource, nil, rlim)
        if err != ENOSYS {
                return err
        }
@@ -133,7 +104,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
 //sysnb        setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
 
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, rlim, nil)
+       err = Prlimit(0, resource, rlim, nil)
        if err != ENOSYS {
                return err
        }
@@ -378,11 +349,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint32(length)
 }
 
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint32(length)
 }
index 28b76411522f9a3f5d18ee91989f60b32c942ae4..4299125aa7cca0af1a6a33b2e4596a2b6008ec58 100644 (file)
@@ -7,8 +7,6 @@
 
 package unix
 
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -21,17 +19,6 @@ package unix
 //sysnb        Getgid() (gid int)
 //sysnb        Getrlimit(resource int, rlim *Rlimit) (err error)
 //sysnb        Getuid() (uid int)
-//sysnb        inotifyInit() (fd int, err error)
-
-func InotifyInit() (fd int, err error) {
-       // First try inotify_init1, because Android's seccomp policy blocks the latter.
-       fd, err = InotifyInit1(0)
-       if err == ENOSYS {
-               fd, err = inotifyInit()
-       }
-       return
-}
-
 //sys  Ioperm(from int, num int, on int) (err error)
 //sys  Iopl(level int) (err error)
 //sys  Lchown(path string, uid int, gid int) (err error)
@@ -126,32 +113,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func (r *PtraceRegs) PC() uint64 { return r.Rip }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
@@ -172,13 +133,8 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
 }
 
 //sys  kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
index 68877728ec60c92d00388fd1297ee74643bf5303..79edeb9cb14a5723c613901a13744acdf0a5daa2 100644 (file)
@@ -19,36 +19,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: int32(sec), Usec: int32(usec)}
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       // Try pipe2 first for Android O, then try pipe for kernel 2.6.23.
-       err = pipe2(&pp, 0)
-       if err == ENOSYS {
-               err = pipe(&pp)
-       }
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
        newoffset, errno := seek(fd, offset, whence)
        if errno != 0 {
@@ -76,8 +46,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 
 // 64-bit file system and 32-bit uid calls
 // (16-bit uid calls are not always supported in newer kernels)
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
 //sys  Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
@@ -86,7 +54,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 //sysnb        Geteuid() (euid int) = SYS_GETEUID32
 //sysnb        Getgid() (gid int) = SYS_GETGID32
 //sysnb        Getuid() (uid int) = SYS_GETUID32
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
 //sys  Listen(s int, n int) (err error)
 //sys  Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
@@ -184,7 +151,7 @@ const rlimInf32 = ^uint32(0)
 const rlimInf64 = ^uint64(0)
 
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, nil, rlim)
+       err = Prlimit(0, resource, nil, rlim)
        if err != ENOSYS {
                return err
        }
@@ -212,7 +179,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
 //sysnb        setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
 
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, rlim, nil)
+       err = Prlimit(0, resource, rlim, nil)
        if err != ENOSYS {
                return err
        }
@@ -256,13 +223,8 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint32(length)
 }
 
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint32(length)
 }
 
 //sys  armSyncFileRange(fd int, flags int, off int64, n int64) (err error) = SYS_ARM_SYNC_FILE_RANGE
index 7ed7034761c51585c413aebe6ca9e76e3aaa15ac..862890de29bf224582a6c89fa46fd67f4942e238 100644 (file)
@@ -9,13 +9,6 @@ package unix
 
 import "unsafe"
 
-func EpollCreate(size int) (fd int, err error) {
-       if size <= 0 {
-               return -1, EINVAL
-       }
-       return EpollCreate1(0)
-}
-
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -145,33 +138,9 @@ func utimes(path string, tv *[2]Timeval) (err error) {
        return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 // Getrlimit prefers the prlimit64 system call. See issue 38604.
 func Getrlimit(resource int, rlim *Rlimit) error {
-       err := prlimit(0, resource, nil, rlim)
+       err := Prlimit(0, resource, nil, rlim)
        if err != ENOSYS {
                return err
        }
@@ -180,7 +149,7 @@ func Getrlimit(resource int, rlim *Rlimit) error {
 
 // Setrlimit prefers the prlimit64 system call. See issue 38604.
 func Setrlimit(resource int, rlim *Rlimit) error {
-       err := prlimit(0, resource, rlim, nil)
+       err := Prlimit(0, resource, rlim, nil)
        if err != ENOSYS {
                return err
        }
@@ -207,31 +176,15 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
-func InotifyInit() (fd int, err error) {
-       return InotifyInit1(0)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
 }
 
-// dup2 exists because func Dup3 in syscall_linux.go references
-// it in an unreachable path. dup2 isn't available on arm64.
-func dup2(oldfd int, newfd int) error
-
 func Pause() error {
        _, err := ppoll(nil, 0, nil, nil)
        return err
 }
 
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       var ts *Timespec
-       if timeout >= 0 {
-               ts = new(Timespec)
-               *ts = NsecToTimespec(int64(timeout) * 1e6)
-       }
-       if len(fds) == 0 {
-               return ppoll(nil, 0, ts, nil)
-       }
-       return ppoll(&fds[0], len(fds), ts, nil)
-}
-
 //sys  kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
 
 func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
index 06dec06fa194b43d23a23c20a67cb48e86b634c5..8932e34ad2ad7ddc811c2eee83624a782fd5d659 100644 (file)
@@ -8,8 +8,6 @@
 
 package unix
 
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -94,30 +92,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func Ioperm(from int, num int, on int) (err error) {
        return ENOSYS
 }
@@ -217,15 +191,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
-func InotifyInit() (fd int, err error) {
-       return InotifyInit1(0)
-}
-
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
 }
index 8f0d0a5b592a3e723b982f7902b27e8aa5e5655e..7821c25d9f778fce7fc6452bef05193ed6ecd38d 100644 (file)
@@ -15,8 +15,6 @@ import (
 
 func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
 
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -60,7 +58,6 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
 //sys  recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
 //sys  sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
 
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Ioperm(from int, num int, on int) (err error)
 //sys  Iopl(level int) (err error)
 
@@ -113,29 +110,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: int32(sec), Usec: int32(usec)}
 }
 
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe() (p1 int, p2 int, err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       p[0], p[1], err = pipe()
-       return
-}
-
 //sys  mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
 
 func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
@@ -157,7 +131,7 @@ type rlimit32 struct {
 //sysnb        getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT
 
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, nil, rlim)
+       err = Prlimit(0, resource, nil, rlim)
        if err != ENOSYS {
                return err
        }
@@ -185,7 +159,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
 //sysnb        setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
 
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, rlim, nil)
+       err = Prlimit(0, resource, rlim, nil)
        if err != ENOSYS {
                return err
        }
@@ -229,11 +203,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint32(length)
 }
 
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint32(length)
 }
index 7e65e088d29b03163701061f5652ffcfc30b1592..c5053a0f03fdc5414803a2cfc473b313bc379548 100644 (file)
@@ -3,8 +3,7 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && ppc
-// +build linux
-// +build ppc
+// +build linux,ppc
 
 package unix
 
@@ -13,8 +12,6 @@ import (
        "unsafe"
 )
 
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fchown(fd int, uid int, gid int) (err error)
 //sys  Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
@@ -24,7 +21,6 @@ import (
 //sysnb        Geteuid() (euid int)
 //sysnb        Getgid() (gid int)
 //sysnb        Getuid() (uid int)
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Ioperm(from int, num int, on int) (err error)
 //sys  Iopl(level int) (err error)
 //sys  Lchown(path string, uid int, gid int) (err error)
@@ -143,7 +139,7 @@ const rlimInf32 = ^uint32(0)
 const rlimInf64 = ^uint64(0)
 
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, nil, rlim)
+       err = Prlimit(0, resource, nil, rlim)
        if err != ENOSYS {
                return err
        }
@@ -171,7 +167,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
 //sysnb        setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
 
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
-       err = prlimit(0, resource, rlim, nil)
+       err = Prlimit(0, resource, rlim, nil)
        if err != ENOSYS {
                return err
        }
@@ -215,39 +211,8 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint32(length)
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint32(length)
 }
 
 //sys  syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2
index 0b1f0d6da5799b66db6462c16469059c634b9f7b..25786c4216b514abcda12d9d46d3040324da3b06 100644 (file)
@@ -8,8 +8,6 @@
 
 package unix
 
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -22,7 +20,6 @@ package unix
 //sysnb        Getgid() (gid int)
 //sysnb        Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_UGETRLIMIT
 //sysnb        Getuid() (uid int)
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Ioperm(from int, num int, on int) (err error)
 //sys  Iopl(level int) (err error)
 //sys  Lchown(path string, uid int, gid int) (err error)
@@ -100,39 +97,8 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
 }
 
 //sys  syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2
index ce9bcd31717ab2de5424f195d3a922dbdb80e0f4..6f9f710414f0672420d101ee43f2e3dd43847828 100644 (file)
@@ -9,13 +9,6 @@ package unix
 
 import "unsafe"
 
-func EpollCreate(size int) (fd int, err error) {
-       if size <= 0 {
-               return -1, EINVAL
-       }
-       return EpollCreate1(0)
-}
-
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -144,30 +137,6 @@ func utimes(path string, tv *[2]Timeval) (err error) {
        return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func (r *PtraceRegs) PC() uint64 { return r.Pc }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc }
@@ -188,8 +157,8 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
-func InotifyInit() (fd int, err error) {
-       return InotifyInit1(0)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
 }
 
 func Pause() error {
@@ -197,18 +166,6 @@ func Pause() error {
        return err
 }
 
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       var ts *Timespec
-       if timeout >= 0 {
-               ts = new(Timespec)
-               *ts = NsecToTimespec(int64(timeout) * 1e6)
-       }
-       if len(fds) == 0 {
-               return ppoll(nil, 0, ts, nil)
-       }
-       return ppoll(&fds[0], len(fds), ts, nil)
-}
-
 func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
        return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0)
 }
@@ -225,7 +182,3 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error
        }
        return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
 }
-
-// dup2 exists because func Dup3 in syscall_linux.go references
-// it in an unreachable path. dup2 isn't available on arm64.
-func dup2(oldfd int, newfd int) error
index a1e45694b441b4b11c7816aff0c5ca5ea6ff3724..6aa59cb270db00b3c7a79cecaab6e37c47c87f56 100644 (file)
@@ -11,8 +11,6 @@ import (
        "unsafe"
 )
 
-//sys  dup2(oldfd int, newfd int) (err error)
-//sysnb        EpollCreate(size int) (fd int, err error)
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys  Fchown(fd int, uid int, gid int) (err error)
@@ -25,7 +23,6 @@ import (
 //sysnb        Getgid() (gid int)
 //sysnb        Getrlimit(resource int, rlim *Rlimit) (err error)
 //sysnb        Getuid() (uid int)
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Lchown(path string, uid int, gid int) (err error)
 //sys  Lstat(path string, stat *Stat_t) (err error)
 //sys  Pause() (err error)
@@ -77,30 +74,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0) // pipe2 is the same as pipe when flags are set to 0.
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func Ioperm(from int, num int, on int) (err error) {
        return ENOSYS
 }
@@ -129,6 +102,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
+}
+
 // Linux on s390x uses the old mmap interface, which requires arguments to be passed in a struct.
 // mmap2 also requires arguments to be passed in a struct; it is currently not exposed in <asm/unistd.h>.
 func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
@@ -320,15 +297,6 @@ func Shutdown(s, how int) error {
        return nil
 }
 
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
-}
-
 //sys  kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
 
 func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
index 49055a3cf51bfa17e818ba0f0075894928cc11ba..bbe8d174f8c12ebbe0eb87a77b70ed73fcc49336 100644 (file)
@@ -9,7 +9,6 @@ package unix
 
 //sys  EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
 //sys  Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
-//sys  dup2(oldfd int, newfd int) (err error)
 //sys  Fchown(fd int, uid int, gid int) (err error)
 //sys  Fstat(fd int, stat *Stat_t) (err error)
 //sys  Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
@@ -20,7 +19,6 @@ package unix
 //sysnb        Getgid() (gid int)
 //sysnb        Getrlimit(resource int, rlim *Rlimit) (err error)
 //sysnb        Getuid() (uid int)
-//sysnb        InotifyInit() (fd int, err error)
 //sys  Lchown(path string, uid int, gid int) (err error)
 //sys  Listen(s int, n int) (err error)
 //sys  Lstat(path string, stat *Stat_t) (err error)
@@ -116,37 +114,6 @@ func (cmsg *Cmsghdr) SetLen(length int) {
        cmsg.Len = uint64(length)
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb        pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sys  poll(fds *PollFd, nfds int, timeout int) (n int, err error)
-
-func Poll(fds []PollFd, timeout int) (n int, err error) {
-       if len(fds) == 0 {
-               return poll(nil, 0, timeout)
-       }
-       return poll(&fds[0], len(fds), timeout)
+func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) {
+       rsa.Service_name_len = uint64(length)
 }
index 77fcde7c180a282a3295d9ba61d753fc95dca12d..d2a6495c7e35e837d69f4ff9171a5bdad7bae856 100644 (file)
 package unix
 
 import (
+       "fmt"
+       "os"
        "runtime"
+       "sync"
        "syscall"
        "unsafe"
 )
@@ -744,3 +747,240 @@ func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, e
 func Munmap(b []byte) (err error) {
        return mapper.Munmap(b)
 }
+
+// Event Ports
+
+type fileObjCookie struct {
+       fobj   *fileObj
+       cookie interface{}
+}
+
+// EventPort provides a safe abstraction on top of Solaris/illumos Event Ports.
+type EventPort struct {
+       port  int
+       mu    sync.Mutex
+       fds   map[uintptr]interface{}
+       paths map[string]*fileObjCookie
+}
+
+// PortEvent is an abstraction of the port_event C struct.
+// Compare Source against PORT_SOURCE_FILE or PORT_SOURCE_FD
+// to see if Path or Fd was the event source. The other will be
+// uninitialized.
+type PortEvent struct {
+       Cookie interface{}
+       Events int32
+       Fd     uintptr
+       Path   string
+       Source uint16
+       fobj   *fileObj
+}
+
+// NewEventPort creates a new EventPort including the
+// underlying call to port_create(3c).
+func NewEventPort() (*EventPort, error) {
+       port, err := port_create()
+       if err != nil {
+               return nil, err
+       }
+       e := &EventPort{
+               port:  port,
+               fds:   make(map[uintptr]interface{}),
+               paths: make(map[string]*fileObjCookie),
+       }
+       return e, nil
+}
+
+//sys  port_create() (n int, err error)
+//sys  port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error)
+//sys  port_dissociate(port int, source int, object uintptr) (n int, err error)
+//sys  port_get(port int, pe *portEvent, timeout *Timespec) (n int, err error)
+//sys  port_getn(port int, pe *portEvent, max uint32, nget *uint32, timeout *Timespec) (n int, err error)
+
+// Close closes the event port.
+func (e *EventPort) Close() error {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       e.fds = nil
+       e.paths = nil
+       return Close(e.port)
+}
+
+// PathIsWatched checks to see if path is associated with this EventPort.
+func (e *EventPort) PathIsWatched(path string) bool {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       _, found := e.paths[path]
+       return found
+}
+
+// FdIsWatched checks to see if fd is associated with this EventPort.
+func (e *EventPort) FdIsWatched(fd uintptr) bool {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       _, found := e.fds[fd]
+       return found
+}
+
+// AssociatePath wraps port_associate(3c) for a filesystem path including
+// creating the necessary file_obj from the provided stat information.
+func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, cookie interface{}) error {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       if _, found := e.paths[path]; found {
+               return fmt.Errorf("%v is already associated with this Event Port", path)
+       }
+       fobj, err := createFileObj(path, stat)
+       if err != nil {
+               return err
+       }
+       fCookie := &fileObjCookie{fobj, cookie}
+       _, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fobj)), events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
+       if err != nil {
+               return err
+       }
+       e.paths[path] = fCookie
+       return nil
+}
+
+// DissociatePath wraps port_dissociate(3c) for a filesystem path.
+func (e *EventPort) DissociatePath(path string) error {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       f, ok := e.paths[path]
+       if !ok {
+               return fmt.Errorf("%v is not associated with this Event Port", path)
+       }
+       _, err := port_dissociate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f.fobj)))
+       if err != nil {
+               return err
+       }
+       delete(e.paths, path)
+       return nil
+}
+
+// AssociateFd wraps calls to port_associate(3c) on file descriptors.
+func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) error {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       if _, found := e.fds[fd]; found {
+               return fmt.Errorf("%v is already associated with this Event Port", fd)
+       }
+       pcookie := &cookie
+       _, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(pcookie)))
+       if err != nil {
+               return err
+       }
+       e.fds[fd] = pcookie
+       return nil
+}
+
+// DissociateFd wraps calls to port_dissociate(3c) on file descriptors.
+func (e *EventPort) DissociateFd(fd uintptr) error {
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       _, ok := e.fds[fd]
+       if !ok {
+               return fmt.Errorf("%v is not associated with this Event Port", fd)
+       }
+       _, err := port_dissociate(e.port, PORT_SOURCE_FD, fd)
+       if err != nil {
+               return err
+       }
+       delete(e.fds, fd)
+       return nil
+}
+
+func createFileObj(name string, stat os.FileInfo) (*fileObj, error) {
+       fobj := new(fileObj)
+       bs, err := ByteSliceFromString(name)
+       if err != nil {
+               return nil, err
+       }
+       fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
+       s := stat.Sys().(*syscall.Stat_t)
+       fobj.Atim.Sec = s.Atim.Sec
+       fobj.Atim.Nsec = s.Atim.Nsec
+       fobj.Mtim.Sec = s.Mtim.Sec
+       fobj.Mtim.Nsec = s.Mtim.Nsec
+       fobj.Ctim.Sec = s.Ctim.Sec
+       fobj.Ctim.Nsec = s.Ctim.Nsec
+       return fobj, nil
+}
+
+// GetOne wraps port_get(3c) and returns a single PortEvent.
+func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
+       pe := new(portEvent)
+       _, err := port_get(e.port, pe, t)
+       if err != nil {
+               return nil, err
+       }
+       p := new(PortEvent)
+       p.Events = pe.Events
+       p.Source = pe.Source
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       switch pe.Source {
+       case PORT_SOURCE_FD:
+               p.Fd = uintptr(pe.Object)
+               cookie := (*interface{})(unsafe.Pointer(pe.User))
+               p.Cookie = *cookie
+               delete(e.fds, p.Fd)
+       case PORT_SOURCE_FILE:
+               p.fobj = (*fileObj)(unsafe.Pointer(uintptr(pe.Object)))
+               p.Path = BytePtrToString((*byte)(unsafe.Pointer(p.fobj.Name)))
+               cookie := (*interface{})(unsafe.Pointer(pe.User))
+               p.Cookie = *cookie
+               delete(e.paths, p.Path)
+       }
+       return p, nil
+}
+
+// Pending wraps port_getn(3c) and returns how many events are pending.
+func (e *EventPort) Pending() (int, error) {
+       var n uint32 = 0
+       _, err := port_getn(e.port, nil, 0, &n, nil)
+       return int(n), err
+}
+
+// Get wraps port_getn(3c) and fills a slice of PortEvent.
+// It will block until either min events have been received
+// or the timeout has been exceeded. It will return how many
+// events were actually received along with any error information.
+func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error) {
+       if min == 0 {
+               return 0, fmt.Errorf("need to request at least one event or use Pending() instead")
+       }
+       if len(s) < min {
+               return 0, fmt.Errorf("len(s) (%d) is less than min events requested (%d)", len(s), min)
+       }
+       got := uint32(min)
+       max := uint32(len(s))
+       var err error
+       ps := make([]portEvent, max, max)
+       _, err = port_getn(e.port, &ps[0], max, &got, timeout)
+       // got will be trustworthy with ETIME, but not any other error.
+       if err != nil && err != ETIME {
+               return 0, err
+       }
+       e.mu.Lock()
+       defer e.mu.Unlock()
+       for i := 0; i < int(got); i++ {
+               s[i].Events = ps[i].Events
+               s[i].Source = ps[i].Source
+               switch ps[i].Source {
+               case PORT_SOURCE_FD:
+                       s[i].Fd = uintptr(ps[i].Object)
+                       cookie := (*interface{})(unsafe.Pointer(ps[i].User))
+                       s[i].Cookie = *cookie
+                       delete(e.fds, s[i].Fd)
+               case PORT_SOURCE_FILE:
+                       s[i].fobj = (*fileObj)(unsafe.Pointer(uintptr(ps[i].Object)))
+                       s[i].Path = BytePtrToString((*byte)(unsafe.Pointer(s[i].fobj.Name)))
+                       cookie := (*interface{})(unsafe.Pointer(ps[i].User))
+                       s[i].Cookie = *cookie
+                       delete(e.paths, s[i].Path)
+               }
+       }
+       return int(got), err
+}
index a7618ceb55e360d9c94a5ca7ee02b15c7bfdfc38..cf296a2433a93ea811d939654fe90eb861bb5603 100644 (file)
@@ -313,6 +313,10 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
        return
 }
 
+func Send(s int, buf []byte, flags int) (err error) {
+       return sendto(s, buf, flags, nil, 0)
+}
+
 func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
        ptr, n, err := to.sockaddr()
        if err != nil {
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/sysvshm_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/sysvshm_linux.go
new file mode 100644 (file)
index 0000000..2c3a443
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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:build linux
+// +build linux
+
+package unix
+
+import "runtime"
+
+// SysvShmCtl performs control operations on the shared memory segment
+// specified by id.
+func SysvShmCtl(id, cmd int, desc *SysvShmDesc) (result int, err error) {
+       if runtime.GOARCH == "arm" ||
+               runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" {
+               cmd |= ipc_64
+       }
+
+       return shmctl(id, cmd, desc)
+}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/sysvshm_unix.go b/src/cmd/vendor/golang.org/x/sys/unix/sysvshm_unix.go
new file mode 100644 (file)
index 0000000..0bb4c8d
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2021 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:build (darwin && !ios) || linux
+// +build darwin,!ios linux
+
+package unix
+
+import (
+       "unsafe"
+
+       "golang.org/x/sys/internal/unsafeheader"
+)
+
+// SysvShmAttach attaches the Sysv shared memory segment associated with the
+// shared memory identifier id.
+func SysvShmAttach(id int, addr uintptr, flag int) ([]byte, error) {
+       addr, errno := shmat(id, addr, flag)
+       if errno != nil {
+               return nil, errno
+       }
+
+       // Retrieve the size of the shared memory to enable slice creation
+       var info SysvShmDesc
+
+       _, err := SysvShmCtl(id, IPC_STAT, &info)
+       if err != nil {
+               // release the shared memory if we can't find the size
+
+               // ignoring error from shmdt as there's nothing sensible to return here
+               shmdt(addr)
+               return nil, err
+       }
+
+       // Use unsafe to convert addr into a []byte.
+       // TODO: convert to unsafe.Slice once we can assume Go 1.17
+       var b []byte
+       hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
+       hdr.Data = unsafe.Pointer(addr)
+       hdr.Cap = int(info.Segsz)
+       hdr.Len = int(info.Segsz)
+       return b, nil
+}
+
+// SysvShmDetach unmaps the shared memory slice returned from SysvShmAttach.
+//
+// It is not safe to use the slice after calling this function.
+func SysvShmDetach(data []byte) error {
+       if len(data) == 0 {
+               return EINVAL
+       }
+
+       return shmdt(uintptr(unsafe.Pointer(&data[0])))
+}
+
+// SysvShmGet returns the Sysv shared memory identifier associated with key.
+// If the IPC_CREAT flag is specified a new segment is created.
+func SysvShmGet(key, size, flag int) (id int, err error) {
+       return shmget(key, size, flag)
+}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/sysvshm_unix_other.go b/src/cmd/vendor/golang.org/x/sys/unix/sysvshm_unix_other.go
new file mode 100644 (file)
index 0000000..71bddef
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2021 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:build darwin && !ios
+// +build darwin,!ios
+
+package unix
+
+// SysvShmCtl performs control operations on the shared memory segment
+// specified by id.
+func SysvShmCtl(id, cmd int, desc *SysvShmDesc) (result int, err error) {
+       return shmctl(id, cmd, desc)
+}
index 991996b60911e4e7c9e894d8b6b7815d404c1fd7..476a1c7e77c52814aced93d4bf22f50bd36431d3 100644 (file)
@@ -12,1550 +12,1582 @@ package unix
 import "syscall"
 
 const (
-       AF_APPLETALK                      = 0x10
-       AF_CCITT                          = 0xa
-       AF_CHAOS                          = 0x5
-       AF_CNT                            = 0x15
-       AF_COIP                           = 0x14
-       AF_DATAKIT                        = 0x9
-       AF_DECnet                         = 0xc
-       AF_DLI                            = 0xd
-       AF_E164                           = 0x1c
-       AF_ECMA                           = 0x8
-       AF_HYLINK                         = 0xf
-       AF_IEEE80211                      = 0x25
-       AF_IMPLINK                        = 0x3
-       AF_INET                           = 0x2
-       AF_INET6                          = 0x1e
-       AF_IPX                            = 0x17
-       AF_ISDN                           = 0x1c
-       AF_ISO                            = 0x7
-       AF_LAT                            = 0xe
-       AF_LINK                           = 0x12
-       AF_LOCAL                          = 0x1
-       AF_MAX                            = 0x29
-       AF_NATM                           = 0x1f
-       AF_NDRV                           = 0x1b
-       AF_NETBIOS                        = 0x21
-       AF_NS                             = 0x6
-       AF_OSI                            = 0x7
-       AF_PPP                            = 0x22
-       AF_PUP                            = 0x4
-       AF_RESERVED_36                    = 0x24
-       AF_ROUTE                          = 0x11
-       AF_SIP                            = 0x18
-       AF_SNA                            = 0xb
-       AF_SYSTEM                         = 0x20
-       AF_SYS_CONTROL                    = 0x2
-       AF_UNIX                           = 0x1
-       AF_UNSPEC                         = 0x0
-       AF_UTUN                           = 0x26
-       AF_VSOCK                          = 0x28
-       ALTWERASE                         = 0x200
-       ATTR_BIT_MAP_COUNT                = 0x5
-       ATTR_CMN_ACCESSMASK               = 0x20000
-       ATTR_CMN_ACCTIME                  = 0x1000
-       ATTR_CMN_ADDEDTIME                = 0x10000000
-       ATTR_CMN_BKUPTIME                 = 0x2000
-       ATTR_CMN_CHGTIME                  = 0x800
-       ATTR_CMN_CRTIME                   = 0x200
-       ATTR_CMN_DATA_PROTECT_FLAGS       = 0x40000000
-       ATTR_CMN_DEVID                    = 0x2
-       ATTR_CMN_DOCUMENT_ID              = 0x100000
-       ATTR_CMN_ERROR                    = 0x20000000
-       ATTR_CMN_EXTENDED_SECURITY        = 0x400000
-       ATTR_CMN_FILEID                   = 0x2000000
-       ATTR_CMN_FLAGS                    = 0x40000
-       ATTR_CMN_FNDRINFO                 = 0x4000
-       ATTR_CMN_FSID                     = 0x4
-       ATTR_CMN_FULLPATH                 = 0x8000000
-       ATTR_CMN_GEN_COUNT                = 0x80000
-       ATTR_CMN_GRPID                    = 0x10000
-       ATTR_CMN_GRPUUID                  = 0x1000000
-       ATTR_CMN_MODTIME                  = 0x400
-       ATTR_CMN_NAME                     = 0x1
-       ATTR_CMN_NAMEDATTRCOUNT           = 0x80000
-       ATTR_CMN_NAMEDATTRLIST            = 0x100000
-       ATTR_CMN_OBJID                    = 0x20
-       ATTR_CMN_OBJPERMANENTID           = 0x40
-       ATTR_CMN_OBJTAG                   = 0x10
-       ATTR_CMN_OBJTYPE                  = 0x8
-       ATTR_CMN_OWNERID                  = 0x8000
-       ATTR_CMN_PARENTID                 = 0x4000000
-       ATTR_CMN_PAROBJID                 = 0x80
-       ATTR_CMN_RETURNED_ATTRS           = 0x80000000
-       ATTR_CMN_SCRIPT                   = 0x100
-       ATTR_CMN_SETMASK                  = 0x51c7ff00
-       ATTR_CMN_USERACCESS               = 0x200000
-       ATTR_CMN_UUID                     = 0x800000
-       ATTR_CMN_VALIDMASK                = 0xffffffff
-       ATTR_CMN_VOLSETMASK               = 0x6700
-       ATTR_FILE_ALLOCSIZE               = 0x4
-       ATTR_FILE_CLUMPSIZE               = 0x10
-       ATTR_FILE_DATAALLOCSIZE           = 0x400
-       ATTR_FILE_DATAEXTENTS             = 0x800
-       ATTR_FILE_DATALENGTH              = 0x200
-       ATTR_FILE_DEVTYPE                 = 0x20
-       ATTR_FILE_FILETYPE                = 0x40
-       ATTR_FILE_FORKCOUNT               = 0x80
-       ATTR_FILE_FORKLIST                = 0x100
-       ATTR_FILE_IOBLOCKSIZE             = 0x8
-       ATTR_FILE_LINKCOUNT               = 0x1
-       ATTR_FILE_RSRCALLOCSIZE           = 0x2000
-       ATTR_FILE_RSRCEXTENTS             = 0x4000
-       ATTR_FILE_RSRCLENGTH              = 0x1000
-       ATTR_FILE_SETMASK                 = 0x20
-       ATTR_FILE_TOTALSIZE               = 0x2
-       ATTR_FILE_VALIDMASK               = 0x37ff
-       ATTR_VOL_ALLOCATIONCLUMP          = 0x40
-       ATTR_VOL_ATTRIBUTES               = 0x40000000
-       ATTR_VOL_CAPABILITIES             = 0x20000
-       ATTR_VOL_DIRCOUNT                 = 0x400
-       ATTR_VOL_ENCODINGSUSED            = 0x10000
-       ATTR_VOL_FILECOUNT                = 0x200
-       ATTR_VOL_FSTYPE                   = 0x1
-       ATTR_VOL_INFO                     = 0x80000000
-       ATTR_VOL_IOBLOCKSIZE              = 0x80
-       ATTR_VOL_MAXOBJCOUNT              = 0x800
-       ATTR_VOL_MINALLOCATION            = 0x20
-       ATTR_VOL_MOUNTEDDEVICE            = 0x8000
-       ATTR_VOL_MOUNTFLAGS               = 0x4000
-       ATTR_VOL_MOUNTPOINT               = 0x1000
-       ATTR_VOL_NAME                     = 0x2000
-       ATTR_VOL_OBJCOUNT                 = 0x100
-       ATTR_VOL_QUOTA_SIZE               = 0x10000000
-       ATTR_VOL_RESERVED_SIZE            = 0x20000000
-       ATTR_VOL_SETMASK                  = 0x80002000
-       ATTR_VOL_SIGNATURE                = 0x2
-       ATTR_VOL_SIZE                     = 0x4
-       ATTR_VOL_SPACEAVAIL               = 0x10
-       ATTR_VOL_SPACEFREE                = 0x8
-       ATTR_VOL_UUID                     = 0x40000
-       ATTR_VOL_VALIDMASK                = 0xf007ffff
-       B0                                = 0x0
-       B110                              = 0x6e
-       B115200                           = 0x1c200
-       B1200                             = 0x4b0
-       B134                              = 0x86
-       B14400                            = 0x3840
-       B150                              = 0x96
-       B1800                             = 0x708
-       B19200                            = 0x4b00
-       B200                              = 0xc8
-       B230400                           = 0x38400
-       B2400                             = 0x960
-       B28800                            = 0x7080
-       B300                              = 0x12c
-       B38400                            = 0x9600
-       B4800                             = 0x12c0
-       B50                               = 0x32
-       B57600                            = 0xe100
-       B600                              = 0x258
-       B7200                             = 0x1c20
-       B75                               = 0x4b
-       B76800                            = 0x12c00
-       B9600                             = 0x2580
-       BIOCFLUSH                         = 0x20004268
-       BIOCGBLEN                         = 0x40044266
-       BIOCGDLT                          = 0x4004426a
-       BIOCGDLTLIST                      = 0xc00c4279
-       BIOCGETIF                         = 0x4020426b
-       BIOCGHDRCMPLT                     = 0x40044274
-       BIOCGRSIG                         = 0x40044272
-       BIOCGRTIMEOUT                     = 0x4010426e
-       BIOCGSEESENT                      = 0x40044276
-       BIOCGSTATS                        = 0x4008426f
-       BIOCIMMEDIATE                     = 0x80044270
-       BIOCPROMISC                       = 0x20004269
-       BIOCSBLEN                         = 0xc0044266
-       BIOCSDLT                          = 0x80044278
-       BIOCSETF                          = 0x80104267
-       BIOCSETFNR                        = 0x8010427e
-       BIOCSETIF                         = 0x8020426c
-       BIOCSHDRCMPLT                     = 0x80044275
-       BIOCSRSIG                         = 0x80044273
-       BIOCSRTIMEOUT                     = 0x8010426d
-       BIOCSSEESENT                      = 0x80044277
-       BIOCVERSION                       = 0x40044271
-       BPF_A                             = 0x10
-       BPF_ABS                           = 0x20
-       BPF_ADD                           = 0x0
-       BPF_ALIGNMENT                     = 0x4
-       BPF_ALU                           = 0x4
-       BPF_AND                           = 0x50
-       BPF_B                             = 0x10
-       BPF_DIV                           = 0x30
-       BPF_H                             = 0x8
-       BPF_IMM                           = 0x0
-       BPF_IND                           = 0x40
-       BPF_JA                            = 0x0
-       BPF_JEQ                           = 0x10
-       BPF_JGE                           = 0x30
-       BPF_JGT                           = 0x20
-       BPF_JMP                           = 0x5
-       BPF_JSET                          = 0x40
-       BPF_K                             = 0x0
-       BPF_LD                            = 0x0
-       BPF_LDX                           = 0x1
-       BPF_LEN                           = 0x80
-       BPF_LSH                           = 0x60
-       BPF_MAJOR_VERSION                 = 0x1
-       BPF_MAXBUFSIZE                    = 0x80000
-       BPF_MAXINSNS                      = 0x200
-       BPF_MEM                           = 0x60
-       BPF_MEMWORDS                      = 0x10
-       BPF_MINBUFSIZE                    = 0x20
-       BPF_MINOR_VERSION                 = 0x1
-       BPF_MISC                          = 0x7
-       BPF_MSH                           = 0xa0
-       BPF_MUL                           = 0x20
-       BPF_NEG                           = 0x80
-       BPF_OR                            = 0x40
-       BPF_RELEASE                       = 0x30bb6
-       BPF_RET                           = 0x6
-       BPF_RSH                           = 0x70
-       BPF_ST                            = 0x2
-       BPF_STX                           = 0x3
-       BPF_SUB                           = 0x10
-       BPF_TAX                           = 0x0
-       BPF_TXA                           = 0x80
-       BPF_W                             = 0x0
-       BPF_X                             = 0x8
-       BRKINT                            = 0x2
-       BS0                               = 0x0
-       BS1                               = 0x8000
-       BSDLY                             = 0x8000
-       CFLUSH                            = 0xf
-       CLOCAL                            = 0x8000
-       CLOCK_MONOTONIC                   = 0x6
-       CLOCK_MONOTONIC_RAW               = 0x4
-       CLOCK_MONOTONIC_RAW_APPROX        = 0x5
-       CLOCK_PROCESS_CPUTIME_ID          = 0xc
-       CLOCK_REALTIME                    = 0x0
-       CLOCK_THREAD_CPUTIME_ID           = 0x10
-       CLOCK_UPTIME_RAW                  = 0x8
-       CLOCK_UPTIME_RAW_APPROX           = 0x9
-       CLONE_NOFOLLOW                    = 0x1
-       CLONE_NOOWNERCOPY                 = 0x2
-       CR0                               = 0x0
-       CR1                               = 0x1000
-       CR2                               = 0x2000
-       CR3                               = 0x3000
-       CRDLY                             = 0x3000
-       CREAD                             = 0x800
-       CRTSCTS                           = 0x30000
-       CS5                               = 0x0
-       CS6                               = 0x100
-       CS7                               = 0x200
-       CS8                               = 0x300
-       CSIZE                             = 0x300
-       CSTART                            = 0x11
-       CSTATUS                           = 0x14
-       CSTOP                             = 0x13
-       CSTOPB                            = 0x400
-       CSUSP                             = 0x1a
-       CTLIOCGINFO                       = 0xc0644e03
-       CTL_HW                            = 0x6
-       CTL_KERN                          = 0x1
-       CTL_MAXNAME                       = 0xc
-       CTL_NET                           = 0x4
-       DLT_A429                          = 0xb8
-       DLT_A653_ICM                      = 0xb9
-       DLT_AIRONET_HEADER                = 0x78
-       DLT_AOS                           = 0xde
-       DLT_APPLE_IP_OVER_IEEE1394        = 0x8a
-       DLT_ARCNET                        = 0x7
-       DLT_ARCNET_LINUX                  = 0x81
-       DLT_ATM_CLIP                      = 0x13
-       DLT_ATM_RFC1483                   = 0xb
-       DLT_AURORA                        = 0x7e
-       DLT_AX25                          = 0x3
-       DLT_AX25_KISS                     = 0xca
-       DLT_BACNET_MS_TP                  = 0xa5
-       DLT_BLUETOOTH_HCI_H4              = 0xbb
-       DLT_BLUETOOTH_HCI_H4_WITH_PHDR    = 0xc9
-       DLT_CAN20B                        = 0xbe
-       DLT_CAN_SOCKETCAN                 = 0xe3
-       DLT_CHAOS                         = 0x5
-       DLT_CHDLC                         = 0x68
-       DLT_CISCO_IOS                     = 0x76
-       DLT_C_HDLC                        = 0x68
-       DLT_C_HDLC_WITH_DIR               = 0xcd
-       DLT_DBUS                          = 0xe7
-       DLT_DECT                          = 0xdd
-       DLT_DOCSIS                        = 0x8f
-       DLT_DVB_CI                        = 0xeb
-       DLT_ECONET                        = 0x73
-       DLT_EN10MB                        = 0x1
-       DLT_EN3MB                         = 0x2
-       DLT_ENC                           = 0x6d
-       DLT_ERF                           = 0xc5
-       DLT_ERF_ETH                       = 0xaf
-       DLT_ERF_POS                       = 0xb0
-       DLT_FC_2                          = 0xe0
-       DLT_FC_2_WITH_FRAME_DELIMS        = 0xe1
-       DLT_FDDI                          = 0xa
-       DLT_FLEXRAY                       = 0xd2
-       DLT_FRELAY                        = 0x6b
-       DLT_FRELAY_WITH_DIR               = 0xce
-       DLT_GCOM_SERIAL                   = 0xad
-       DLT_GCOM_T1E1                     = 0xac
-       DLT_GPF_F                         = 0xab
-       DLT_GPF_T                         = 0xaa
-       DLT_GPRS_LLC                      = 0xa9
-       DLT_GSMTAP_ABIS                   = 0xda
-       DLT_GSMTAP_UM                     = 0xd9
-       DLT_HHDLC                         = 0x79
-       DLT_IBM_SN                        = 0x92
-       DLT_IBM_SP                        = 0x91
-       DLT_IEEE802                       = 0x6
-       DLT_IEEE802_11                    = 0x69
-       DLT_IEEE802_11_RADIO              = 0x7f
-       DLT_IEEE802_11_RADIO_AVS          = 0xa3
-       DLT_IEEE802_15_4                  = 0xc3
-       DLT_IEEE802_15_4_LINUX            = 0xbf
-       DLT_IEEE802_15_4_NOFCS            = 0xe6
-       DLT_IEEE802_15_4_NONASK_PHY       = 0xd7
-       DLT_IEEE802_16_MAC_CPS            = 0xbc
-       DLT_IEEE802_16_MAC_CPS_RADIO      = 0xc1
-       DLT_IPFILTER                      = 0x74
-       DLT_IPMB                          = 0xc7
-       DLT_IPMB_LINUX                    = 0xd1
-       DLT_IPNET                         = 0xe2
-       DLT_IPOIB                         = 0xf2
-       DLT_IPV4                          = 0xe4
-       DLT_IPV6                          = 0xe5
-       DLT_IP_OVER_FC                    = 0x7a
-       DLT_JUNIPER_ATM1                  = 0x89
-       DLT_JUNIPER_ATM2                  = 0x87
-       DLT_JUNIPER_ATM_CEMIC             = 0xee
-       DLT_JUNIPER_CHDLC                 = 0xb5
-       DLT_JUNIPER_ES                    = 0x84
-       DLT_JUNIPER_ETHER                 = 0xb2
-       DLT_JUNIPER_FIBRECHANNEL          = 0xea
-       DLT_JUNIPER_FRELAY                = 0xb4
-       DLT_JUNIPER_GGSN                  = 0x85
-       DLT_JUNIPER_ISM                   = 0xc2
-       DLT_JUNIPER_MFR                   = 0x86
-       DLT_JUNIPER_MLFR                  = 0x83
-       DLT_JUNIPER_MLPPP                 = 0x82
-       DLT_JUNIPER_MONITOR               = 0xa4
-       DLT_JUNIPER_PIC_PEER              = 0xae
-       DLT_JUNIPER_PPP                   = 0xb3
-       DLT_JUNIPER_PPPOE                 = 0xa7
-       DLT_JUNIPER_PPPOE_ATM             = 0xa8
-       DLT_JUNIPER_SERVICES              = 0x88
-       DLT_JUNIPER_SRX_E2E               = 0xe9
-       DLT_JUNIPER_ST                    = 0xc8
-       DLT_JUNIPER_VP                    = 0xb7
-       DLT_JUNIPER_VS                    = 0xe8
-       DLT_LAPB_WITH_DIR                 = 0xcf
-       DLT_LAPD                          = 0xcb
-       DLT_LIN                           = 0xd4
-       DLT_LINUX_EVDEV                   = 0xd8
-       DLT_LINUX_IRDA                    = 0x90
-       DLT_LINUX_LAPD                    = 0xb1
-       DLT_LINUX_PPP_WITHDIRECTION       = 0xa6
-       DLT_LINUX_SLL                     = 0x71
-       DLT_LOOP                          = 0x6c
-       DLT_LTALK                         = 0x72
-       DLT_MATCHING_MAX                  = 0x10a
-       DLT_MATCHING_MIN                  = 0x68
-       DLT_MFR                           = 0xb6
-       DLT_MOST                          = 0xd3
-       DLT_MPEG_2_TS                     = 0xf3
-       DLT_MPLS                          = 0xdb
-       DLT_MTP2                          = 0x8c
-       DLT_MTP2_WITH_PHDR                = 0x8b
-       DLT_MTP3                          = 0x8d
-       DLT_MUX27010                      = 0xec
-       DLT_NETANALYZER                   = 0xf0
-       DLT_NETANALYZER_TRANSPARENT       = 0xf1
-       DLT_NFC_LLCP                      = 0xf5
-       DLT_NFLOG                         = 0xef
-       DLT_NG40                          = 0xf4
-       DLT_NULL                          = 0x0
-       DLT_PCI_EXP                       = 0x7d
-       DLT_PFLOG                         = 0x75
-       DLT_PFSYNC                        = 0x12
-       DLT_PPI                           = 0xc0
-       DLT_PPP                           = 0x9
-       DLT_PPP_BSDOS                     = 0x10
-       DLT_PPP_ETHER                     = 0x33
-       DLT_PPP_PPPD                      = 0xa6
-       DLT_PPP_SERIAL                    = 0x32
-       DLT_PPP_WITH_DIR                  = 0xcc
-       DLT_PPP_WITH_DIRECTION            = 0xa6
-       DLT_PRISM_HEADER                  = 0x77
-       DLT_PRONET                        = 0x4
-       DLT_RAIF1                         = 0xc6
-       DLT_RAW                           = 0xc
-       DLT_RIO                           = 0x7c
-       DLT_SCCP                          = 0x8e
-       DLT_SITA                          = 0xc4
-       DLT_SLIP                          = 0x8
-       DLT_SLIP_BSDOS                    = 0xf
-       DLT_STANAG_5066_D_PDU             = 0xed
-       DLT_SUNATM                        = 0x7b
-       DLT_SYMANTEC_FIREWALL             = 0x63
-       DLT_TZSP                          = 0x80
-       DLT_USB                           = 0xba
-       DLT_USB_DARWIN                    = 0x10a
-       DLT_USB_LINUX                     = 0xbd
-       DLT_USB_LINUX_MMAPPED             = 0xdc
-       DLT_USER0                         = 0x93
-       DLT_USER1                         = 0x94
-       DLT_USER10                        = 0x9d
-       DLT_USER11                        = 0x9e
-       DLT_USER12                        = 0x9f
-       DLT_USER13                        = 0xa0
-       DLT_USER14                        = 0xa1
-       DLT_USER15                        = 0xa2
-       DLT_USER2                         = 0x95
-       DLT_USER3                         = 0x96
-       DLT_USER4                         = 0x97
-       DLT_USER5                         = 0x98
-       DLT_USER6                         = 0x99
-       DLT_USER7                         = 0x9a
-       DLT_USER8                         = 0x9b
-       DLT_USER9                         = 0x9c
-       DLT_WIHART                        = 0xdf
-       DLT_X2E_SERIAL                    = 0xd5
-       DLT_X2E_XORAYA                    = 0xd6
-       DT_BLK                            = 0x6
-       DT_CHR                            = 0x2
-       DT_DIR                            = 0x4
-       DT_FIFO                           = 0x1
-       DT_LNK                            = 0xa
-       DT_REG                            = 0x8
-       DT_SOCK                           = 0xc
-       DT_UNKNOWN                        = 0x0
-       DT_WHT                            = 0xe
-       ECHO                              = 0x8
-       ECHOCTL                           = 0x40
-       ECHOE                             = 0x2
-       ECHOK                             = 0x4
-       ECHOKE                            = 0x1
-       ECHONL                            = 0x10
-       ECHOPRT                           = 0x20
-       EVFILT_AIO                        = -0x3
-       EVFILT_EXCEPT                     = -0xf
-       EVFILT_FS                         = -0x9
-       EVFILT_MACHPORT                   = -0x8
-       EVFILT_PROC                       = -0x5
-       EVFILT_READ                       = -0x1
-       EVFILT_SIGNAL                     = -0x6
-       EVFILT_SYSCOUNT                   = 0x11
-       EVFILT_THREADMARKER               = 0x11
-       EVFILT_TIMER                      = -0x7
-       EVFILT_USER                       = -0xa
-       EVFILT_VM                         = -0xc
-       EVFILT_VNODE                      = -0x4
-       EVFILT_WRITE                      = -0x2
-       EV_ADD                            = 0x1
-       EV_CLEAR                          = 0x20
-       EV_DELETE                         = 0x2
-       EV_DISABLE                        = 0x8
-       EV_DISPATCH                       = 0x80
-       EV_DISPATCH2                      = 0x180
-       EV_ENABLE                         = 0x4
-       EV_EOF                            = 0x8000
-       EV_ERROR                          = 0x4000
-       EV_FLAG0                          = 0x1000
-       EV_FLAG1                          = 0x2000
-       EV_ONESHOT                        = 0x10
-       EV_OOBAND                         = 0x2000
-       EV_POLL                           = 0x1000
-       EV_RECEIPT                        = 0x40
-       EV_SYSFLAGS                       = 0xf000
-       EV_UDATA_SPECIFIC                 = 0x100
-       EV_VANISHED                       = 0x200
-       EXTA                              = 0x4b00
-       EXTB                              = 0x9600
-       EXTPROC                           = 0x800
-       FD_CLOEXEC                        = 0x1
-       FD_SETSIZE                        = 0x400
-       FF0                               = 0x0
-       FF1                               = 0x4000
-       FFDLY                             = 0x4000
-       FLUSHO                            = 0x800000
-       FSOPT_ATTR_CMN_EXTENDED           = 0x20
-       FSOPT_NOFOLLOW                    = 0x1
-       FSOPT_NOINMEMUPDATE               = 0x2
-       FSOPT_PACK_INVAL_ATTRS            = 0x8
-       FSOPT_REPORT_FULLSIZE             = 0x4
-       FSOPT_RETURN_REALDEV              = 0x200
-       F_ADDFILESIGS                     = 0x3d
-       F_ADDFILESIGS_FOR_DYLD_SIM        = 0x53
-       F_ADDFILESIGS_INFO                = 0x67
-       F_ADDFILESIGS_RETURN              = 0x61
-       F_ADDFILESUPPL                    = 0x68
-       F_ADDSIGS                         = 0x3b
-       F_ALLOCATEALL                     = 0x4
-       F_ALLOCATECONTIG                  = 0x2
-       F_BARRIERFSYNC                    = 0x55
-       F_CHECK_LV                        = 0x62
-       F_CHKCLEAN                        = 0x29
-       F_DUPFD                           = 0x0
-       F_DUPFD_CLOEXEC                   = 0x43
-       F_FINDSIGS                        = 0x4e
-       F_FLUSH_DATA                      = 0x28
-       F_FREEZE_FS                       = 0x35
-       F_FULLFSYNC                       = 0x33
-       F_GETCODEDIR                      = 0x48
-       F_GETFD                           = 0x1
-       F_GETFL                           = 0x3
-       F_GETLK                           = 0x7
-       F_GETLKPID                        = 0x42
-       F_GETNOSIGPIPE                    = 0x4a
-       F_GETOWN                          = 0x5
-       F_GETPATH                         = 0x32
-       F_GETPATH_MTMINFO                 = 0x47
-       F_GETPATH_NOFIRMLINK              = 0x66
-       F_GETPROTECTIONCLASS              = 0x3f
-       F_GETPROTECTIONLEVEL              = 0x4d
-       F_GETSIGSINFO                     = 0x69
-       F_GLOBAL_NOCACHE                  = 0x37
-       F_LOG2PHYS                        = 0x31
-       F_LOG2PHYS_EXT                    = 0x41
-       F_NOCACHE                         = 0x30
-       F_NODIRECT                        = 0x3e
-       F_OK                              = 0x0
-       F_PATHPKG_CHECK                   = 0x34
-       F_PEOFPOSMODE                     = 0x3
-       F_PREALLOCATE                     = 0x2a
-       F_PUNCHHOLE                       = 0x63
-       F_RDADVISE                        = 0x2c
-       F_RDAHEAD                         = 0x2d
-       F_RDLCK                           = 0x1
-       F_SETBACKINGSTORE                 = 0x46
-       F_SETFD                           = 0x2
-       F_SETFL                           = 0x4
-       F_SETLK                           = 0x8
-       F_SETLKW                          = 0x9
-       F_SETLKWTIMEOUT                   = 0xa
-       F_SETNOSIGPIPE                    = 0x49
-       F_SETOWN                          = 0x6
-       F_SETPROTECTIONCLASS              = 0x40
-       F_SETSIZE                         = 0x2b
-       F_SINGLE_WRITER                   = 0x4c
-       F_SPECULATIVE_READ                = 0x65
-       F_THAW_FS                         = 0x36
-       F_TRANSCODEKEY                    = 0x4b
-       F_TRIM_ACTIVE_FILE                = 0x64
-       F_UNLCK                           = 0x2
-       F_VOLPOSMODE                      = 0x4
-       F_WRLCK                           = 0x3
-       HUPCL                             = 0x4000
-       HW_MACHINE                        = 0x1
-       ICANON                            = 0x100
-       ICMP6_FILTER                      = 0x12
-       ICRNL                             = 0x100
-       IEXTEN                            = 0x400
-       IFF_ALLMULTI                      = 0x200
-       IFF_ALTPHYS                       = 0x4000
-       IFF_BROADCAST                     = 0x2
-       IFF_DEBUG                         = 0x4
-       IFF_LINK0                         = 0x1000
-       IFF_LINK1                         = 0x2000
-       IFF_LINK2                         = 0x4000
-       IFF_LOOPBACK                      = 0x8
-       IFF_MULTICAST                     = 0x8000
-       IFF_NOARP                         = 0x80
-       IFF_NOTRAILERS                    = 0x20
-       IFF_OACTIVE                       = 0x400
-       IFF_POINTOPOINT                   = 0x10
-       IFF_PROMISC                       = 0x100
-       IFF_RUNNING                       = 0x40
-       IFF_SIMPLEX                       = 0x800
-       IFF_UP                            = 0x1
-       IFNAMSIZ                          = 0x10
-       IFT_1822                          = 0x2
-       IFT_6LOWPAN                       = 0x40
-       IFT_AAL5                          = 0x31
-       IFT_ARCNET                        = 0x23
-       IFT_ARCNETPLUS                    = 0x24
-       IFT_ATM                           = 0x25
-       IFT_BRIDGE                        = 0xd1
-       IFT_CARP                          = 0xf8
-       IFT_CELLULAR                      = 0xff
-       IFT_CEPT                          = 0x13
-       IFT_DS3                           = 0x1e
-       IFT_ENC                           = 0xf4
-       IFT_EON                           = 0x19
-       IFT_ETHER                         = 0x6
-       IFT_FAITH                         = 0x38
-       IFT_FDDI                          = 0xf
-       IFT_FRELAY                        = 0x20
-       IFT_FRELAYDCE                     = 0x2c
-       IFT_GIF                           = 0x37
-       IFT_HDH1822                       = 0x3
-       IFT_HIPPI                         = 0x2f
-       IFT_HSSI                          = 0x2e
-       IFT_HY                            = 0xe
-       IFT_IEEE1394                      = 0x90
-       IFT_IEEE8023ADLAG                 = 0x88
-       IFT_ISDNBASIC                     = 0x14
-       IFT_ISDNPRIMARY                   = 0x15
-       IFT_ISO88022LLC                   = 0x29
-       IFT_ISO88023                      = 0x7
-       IFT_ISO88024                      = 0x8
-       IFT_ISO88025                      = 0x9
-       IFT_ISO88026                      = 0xa
-       IFT_L2VLAN                        = 0x87
-       IFT_LAPB                          = 0x10
-       IFT_LOCALTALK                     = 0x2a
-       IFT_LOOP                          = 0x18
-       IFT_MIOX25                        = 0x26
-       IFT_MODEM                         = 0x30
-       IFT_NSIP                          = 0x1b
-       IFT_OTHER                         = 0x1
-       IFT_P10                           = 0xc
-       IFT_P80                           = 0xd
-       IFT_PARA                          = 0x22
-       IFT_PDP                           = 0xff
-       IFT_PFLOG                         = 0xf5
-       IFT_PFSYNC                        = 0xf6
-       IFT_PKTAP                         = 0xfe
-       IFT_PPP                           = 0x17
-       IFT_PROPMUX                       = 0x36
-       IFT_PROPVIRTUAL                   = 0x35
-       IFT_PTPSERIAL                     = 0x16
-       IFT_RS232                         = 0x21
-       IFT_SDLC                          = 0x11
-       IFT_SIP                           = 0x1f
-       IFT_SLIP                          = 0x1c
-       IFT_SMDSDXI                       = 0x2b
-       IFT_SMDSICIP                      = 0x34
-       IFT_SONET                         = 0x27
-       IFT_SONETPATH                     = 0x32
-       IFT_SONETVT                       = 0x33
-       IFT_STARLAN                       = 0xb
-       IFT_STF                           = 0x39
-       IFT_T1                            = 0x12
-       IFT_ULTRA                         = 0x1d
-       IFT_V35                           = 0x2d
-       IFT_X25                           = 0x5
-       IFT_X25DDN                        = 0x4
-       IFT_X25PLE                        = 0x28
-       IFT_XETHER                        = 0x1a
-       IGNBRK                            = 0x1
-       IGNCR                             = 0x80
-       IGNPAR                            = 0x4
-       IMAXBEL                           = 0x2000
-       INLCR                             = 0x40
-       INPCK                             = 0x10
-       IN_CLASSA_HOST                    = 0xffffff
-       IN_CLASSA_MAX                     = 0x80
-       IN_CLASSA_NET                     = 0xff000000
-       IN_CLASSA_NSHIFT                  = 0x18
-       IN_CLASSB_HOST                    = 0xffff
-       IN_CLASSB_MAX                     = 0x10000
-       IN_CLASSB_NET                     = 0xffff0000
-       IN_CLASSB_NSHIFT                  = 0x10
-       IN_CLASSC_HOST                    = 0xff
-       IN_CLASSC_NET                     = 0xffffff00
-       IN_CLASSC_NSHIFT                  = 0x8
-       IN_CLASSD_HOST                    = 0xfffffff
-       IN_CLASSD_NET                     = 0xf0000000
-       IN_CLASSD_NSHIFT                  = 0x1c
-       IN_LINKLOCALNETNUM                = 0xa9fe0000
-       IN_LOOPBACKNET                    = 0x7f
-       IPPROTO_3PC                       = 0x22
-       IPPROTO_ADFS                      = 0x44
-       IPPROTO_AH                        = 0x33
-       IPPROTO_AHIP                      = 0x3d
-       IPPROTO_APES                      = 0x63
-       IPPROTO_ARGUS                     = 0xd
-       IPPROTO_AX25                      = 0x5d
-       IPPROTO_BHA                       = 0x31
-       IPPROTO_BLT                       = 0x1e
-       IPPROTO_BRSATMON                  = 0x4c
-       IPPROTO_CFTP                      = 0x3e
-       IPPROTO_CHAOS                     = 0x10
-       IPPROTO_CMTP                      = 0x26
-       IPPROTO_CPHB                      = 0x49
-       IPPROTO_CPNX                      = 0x48
-       IPPROTO_DDP                       = 0x25
-       IPPROTO_DGP                       = 0x56
-       IPPROTO_DIVERT                    = 0xfe
-       IPPROTO_DONE                      = 0x101
-       IPPROTO_DSTOPTS                   = 0x3c
-       IPPROTO_EGP                       = 0x8
-       IPPROTO_EMCON                     = 0xe
-       IPPROTO_ENCAP                     = 0x62
-       IPPROTO_EON                       = 0x50
-       IPPROTO_ESP                       = 0x32
-       IPPROTO_ETHERIP                   = 0x61
-       IPPROTO_FRAGMENT                  = 0x2c
-       IPPROTO_GGP                       = 0x3
-       IPPROTO_GMTP                      = 0x64
-       IPPROTO_GRE                       = 0x2f
-       IPPROTO_HELLO                     = 0x3f
-       IPPROTO_HMP                       = 0x14
-       IPPROTO_HOPOPTS                   = 0x0
-       IPPROTO_ICMP                      = 0x1
-       IPPROTO_ICMPV6                    = 0x3a
-       IPPROTO_IDP                       = 0x16
-       IPPROTO_IDPR                      = 0x23
-       IPPROTO_IDRP                      = 0x2d
-       IPPROTO_IGMP                      = 0x2
-       IPPROTO_IGP                       = 0x55
-       IPPROTO_IGRP                      = 0x58
-       IPPROTO_IL                        = 0x28
-       IPPROTO_INLSP                     = 0x34
-       IPPROTO_INP                       = 0x20
-       IPPROTO_IP                        = 0x0
-       IPPROTO_IPCOMP                    = 0x6c
-       IPPROTO_IPCV                      = 0x47
-       IPPROTO_IPEIP                     = 0x5e
-       IPPROTO_IPIP                      = 0x4
-       IPPROTO_IPPC                      = 0x43
-       IPPROTO_IPV4                      = 0x4
-       IPPROTO_IPV6                      = 0x29
-       IPPROTO_IRTP                      = 0x1c
-       IPPROTO_KRYPTOLAN                 = 0x41
-       IPPROTO_LARP                      = 0x5b
-       IPPROTO_LEAF1                     = 0x19
-       IPPROTO_LEAF2                     = 0x1a
-       IPPROTO_MAX                       = 0x100
-       IPPROTO_MAXID                     = 0x34
-       IPPROTO_MEAS                      = 0x13
-       IPPROTO_MHRP                      = 0x30
-       IPPROTO_MICP                      = 0x5f
-       IPPROTO_MTP                       = 0x5c
-       IPPROTO_MUX                       = 0x12
-       IPPROTO_ND                        = 0x4d
-       IPPROTO_NHRP                      = 0x36
-       IPPROTO_NONE                      = 0x3b
-       IPPROTO_NSP                       = 0x1f
-       IPPROTO_NVPII                     = 0xb
-       IPPROTO_OSPFIGP                   = 0x59
-       IPPROTO_PGM                       = 0x71
-       IPPROTO_PIGP                      = 0x9
-       IPPROTO_PIM                       = 0x67
-       IPPROTO_PRM                       = 0x15
-       IPPROTO_PUP                       = 0xc
-       IPPROTO_PVP                       = 0x4b
-       IPPROTO_RAW                       = 0xff
-       IPPROTO_RCCMON                    = 0xa
-       IPPROTO_RDP                       = 0x1b
-       IPPROTO_ROUTING                   = 0x2b
-       IPPROTO_RSVP                      = 0x2e
-       IPPROTO_RVD                       = 0x42
-       IPPROTO_SATEXPAK                  = 0x40
-       IPPROTO_SATMON                    = 0x45
-       IPPROTO_SCCSP                     = 0x60
-       IPPROTO_SCTP                      = 0x84
-       IPPROTO_SDRP                      = 0x2a
-       IPPROTO_SEP                       = 0x21
-       IPPROTO_SRPC                      = 0x5a
-       IPPROTO_ST                        = 0x7
-       IPPROTO_SVMTP                     = 0x52
-       IPPROTO_SWIPE                     = 0x35
-       IPPROTO_TCF                       = 0x57
-       IPPROTO_TCP                       = 0x6
-       IPPROTO_TP                        = 0x1d
-       IPPROTO_TPXX                      = 0x27
-       IPPROTO_TRUNK1                    = 0x17
-       IPPROTO_TRUNK2                    = 0x18
-       IPPROTO_TTP                       = 0x54
-       IPPROTO_UDP                       = 0x11
-       IPPROTO_VINES                     = 0x53
-       IPPROTO_VISA                      = 0x46
-       IPPROTO_VMTP                      = 0x51
-       IPPROTO_WBEXPAK                   = 0x4f
-       IPPROTO_WBMON                     = 0x4e
-       IPPROTO_WSN                       = 0x4a
-       IPPROTO_XNET                      = 0xf
-       IPPROTO_XTP                       = 0x24
-       IPV6_2292DSTOPTS                  = 0x17
-       IPV6_2292HOPLIMIT                 = 0x14
-       IPV6_2292HOPOPTS                  = 0x16
-       IPV6_2292NEXTHOP                  = 0x15
-       IPV6_2292PKTINFO                  = 0x13
-       IPV6_2292PKTOPTIONS               = 0x19
-       IPV6_2292RTHDR                    = 0x18
-       IPV6_3542DSTOPTS                  = 0x32
-       IPV6_3542HOPLIMIT                 = 0x2f
-       IPV6_3542HOPOPTS                  = 0x31
-       IPV6_3542NEXTHOP                  = 0x30
-       IPV6_3542PKTINFO                  = 0x2e
-       IPV6_3542RTHDR                    = 0x33
-       IPV6_ADDR_MC_FLAGS_PREFIX         = 0x20
-       IPV6_ADDR_MC_FLAGS_TRANSIENT      = 0x10
-       IPV6_ADDR_MC_FLAGS_UNICAST_BASED  = 0x30
-       IPV6_AUTOFLOWLABEL                = 0x3b
-       IPV6_BINDV6ONLY                   = 0x1b
-       IPV6_BOUND_IF                     = 0x7d
-       IPV6_CHECKSUM                     = 0x1a
-       IPV6_DEFAULT_MULTICAST_HOPS       = 0x1
-       IPV6_DEFAULT_MULTICAST_LOOP       = 0x1
-       IPV6_DEFHLIM                      = 0x40
-       IPV6_DONTFRAG                     = 0x3e
-       IPV6_DSTOPTS                      = 0x32
-       IPV6_FAITH                        = 0x1d
-       IPV6_FLOWINFO_MASK                = 0xffffff0f
-       IPV6_FLOWLABEL_MASK               = 0xffff0f00
-       IPV6_FLOW_ECN_MASK                = 0x3000
-       IPV6_FRAGTTL                      = 0x3c
-       IPV6_FW_ADD                       = 0x1e
-       IPV6_FW_DEL                       = 0x1f
-       IPV6_FW_FLUSH                     = 0x20
-       IPV6_FW_GET                       = 0x22
-       IPV6_FW_ZERO                      = 0x21
-       IPV6_HLIMDEC                      = 0x1
-       IPV6_HOPLIMIT                     = 0x2f
-       IPV6_HOPOPTS                      = 0x31
-       IPV6_IPSEC_POLICY                 = 0x1c
-       IPV6_JOIN_GROUP                   = 0xc
-       IPV6_LEAVE_GROUP                  = 0xd
-       IPV6_MAXHLIM                      = 0xff
-       IPV6_MAXOPTHDR                    = 0x800
-       IPV6_MAXPACKET                    = 0xffff
-       IPV6_MAX_GROUP_SRC_FILTER         = 0x200
-       IPV6_MAX_MEMBERSHIPS              = 0xfff
-       IPV6_MAX_SOCK_SRC_FILTER          = 0x80
-       IPV6_MIN_MEMBERSHIPS              = 0x1f
-       IPV6_MMTU                         = 0x500
-       IPV6_MSFILTER                     = 0x4a
-       IPV6_MULTICAST_HOPS               = 0xa
-       IPV6_MULTICAST_IF                 = 0x9
-       IPV6_MULTICAST_LOOP               = 0xb
-       IPV6_NEXTHOP                      = 0x30
-       IPV6_PATHMTU                      = 0x2c
-       IPV6_PKTINFO                      = 0x2e
-       IPV6_PORTRANGE                    = 0xe
-       IPV6_PORTRANGE_DEFAULT            = 0x0
-       IPV6_PORTRANGE_HIGH               = 0x1
-       IPV6_PORTRANGE_LOW                = 0x2
-       IPV6_PREFER_TEMPADDR              = 0x3f
-       IPV6_RECVDSTOPTS                  = 0x28
-       IPV6_RECVHOPLIMIT                 = 0x25
-       IPV6_RECVHOPOPTS                  = 0x27
-       IPV6_RECVPATHMTU                  = 0x2b
-       IPV6_RECVPKTINFO                  = 0x3d
-       IPV6_RECVRTHDR                    = 0x26
-       IPV6_RECVTCLASS                   = 0x23
-       IPV6_RTHDR                        = 0x33
-       IPV6_RTHDRDSTOPTS                 = 0x39
-       IPV6_RTHDR_LOOSE                  = 0x0
-       IPV6_RTHDR_STRICT                 = 0x1
-       IPV6_RTHDR_TYPE_0                 = 0x0
-       IPV6_SOCKOPT_RESERVED1            = 0x3
-       IPV6_TCLASS                       = 0x24
-       IPV6_UNICAST_HOPS                 = 0x4
-       IPV6_USE_MIN_MTU                  = 0x2a
-       IPV6_V6ONLY                       = 0x1b
-       IPV6_VERSION                      = 0x60
-       IPV6_VERSION_MASK                 = 0xf0
-       IP_ADD_MEMBERSHIP                 = 0xc
-       IP_ADD_SOURCE_MEMBERSHIP          = 0x46
-       IP_BLOCK_SOURCE                   = 0x48
-       IP_BOUND_IF                       = 0x19
-       IP_DEFAULT_MULTICAST_LOOP         = 0x1
-       IP_DEFAULT_MULTICAST_TTL          = 0x1
-       IP_DF                             = 0x4000
-       IP_DONTFRAG                       = 0x1c
-       IP_DROP_MEMBERSHIP                = 0xd
-       IP_DROP_SOURCE_MEMBERSHIP         = 0x47
-       IP_DUMMYNET_CONFIGURE             = 0x3c
-       IP_DUMMYNET_DEL                   = 0x3d
-       IP_DUMMYNET_FLUSH                 = 0x3e
-       IP_DUMMYNET_GET                   = 0x40
-       IP_FAITH                          = 0x16
-       IP_FW_ADD                         = 0x28
-       IP_FW_DEL                         = 0x29
-       IP_FW_FLUSH                       = 0x2a
-       IP_FW_GET                         = 0x2c
-       IP_FW_RESETLOG                    = 0x2d
-       IP_FW_ZERO                        = 0x2b
-       IP_HDRINCL                        = 0x2
-       IP_IPSEC_POLICY                   = 0x15
-       IP_MAXPACKET                      = 0xffff
-       IP_MAX_GROUP_SRC_FILTER           = 0x200
-       IP_MAX_MEMBERSHIPS                = 0xfff
-       IP_MAX_SOCK_MUTE_FILTER           = 0x80
-       IP_MAX_SOCK_SRC_FILTER            = 0x80
-       IP_MF                             = 0x2000
-       IP_MIN_MEMBERSHIPS                = 0x1f
-       IP_MSFILTER                       = 0x4a
-       IP_MSS                            = 0x240
-       IP_MULTICAST_IF                   = 0x9
-       IP_MULTICAST_IFINDEX              = 0x42
-       IP_MULTICAST_LOOP                 = 0xb
-       IP_MULTICAST_TTL                  = 0xa
-       IP_MULTICAST_VIF                  = 0xe
-       IP_NAT__XXX                       = 0x37
-       IP_OFFMASK                        = 0x1fff
-       IP_OLD_FW_ADD                     = 0x32
-       IP_OLD_FW_DEL                     = 0x33
-       IP_OLD_FW_FLUSH                   = 0x34
-       IP_OLD_FW_GET                     = 0x36
-       IP_OLD_FW_RESETLOG                = 0x38
-       IP_OLD_FW_ZERO                    = 0x35
-       IP_OPTIONS                        = 0x1
-       IP_PKTINFO                        = 0x1a
-       IP_PORTRANGE                      = 0x13
-       IP_PORTRANGE_DEFAULT              = 0x0
-       IP_PORTRANGE_HIGH                 = 0x1
-       IP_PORTRANGE_LOW                  = 0x2
-       IP_RECVDSTADDR                    = 0x7
-       IP_RECVIF                         = 0x14
-       IP_RECVOPTS                       = 0x5
-       IP_RECVPKTINFO                    = 0x1a
-       IP_RECVRETOPTS                    = 0x6
-       IP_RECVTOS                        = 0x1b
-       IP_RECVTTL                        = 0x18
-       IP_RETOPTS                        = 0x8
-       IP_RF                             = 0x8000
-       IP_RSVP_OFF                       = 0x10
-       IP_RSVP_ON                        = 0xf
-       IP_RSVP_VIF_OFF                   = 0x12
-       IP_RSVP_VIF_ON                    = 0x11
-       IP_STRIPHDR                       = 0x17
-       IP_TOS                            = 0x3
-       IP_TRAFFIC_MGT_BACKGROUND         = 0x41
-       IP_TTL                            = 0x4
-       IP_UNBLOCK_SOURCE                 = 0x49
-       ISIG                              = 0x80
-       ISTRIP                            = 0x20
-       IUTF8                             = 0x4000
-       IXANY                             = 0x800
-       IXOFF                             = 0x400
-       IXON                              = 0x200
-       KERN_HOSTNAME                     = 0xa
-       KERN_OSRELEASE                    = 0x2
-       KERN_OSTYPE                       = 0x1
-       KERN_VERSION                      = 0x4
-       LOCAL_PEERCRED                    = 0x1
-       LOCAL_PEEREPID                    = 0x3
-       LOCAL_PEEREUUID                   = 0x5
-       LOCAL_PEERPID                     = 0x2
-       LOCAL_PEERTOKEN                   = 0x6
-       LOCAL_PEERUUID                    = 0x4
-       LOCK_EX                           = 0x2
-       LOCK_NB                           = 0x4
-       LOCK_SH                           = 0x1
-       LOCK_UN                           = 0x8
-       MADV_CAN_REUSE                    = 0x9
-       MADV_DONTNEED                     = 0x4
-       MADV_FREE                         = 0x5
-       MADV_FREE_REUSABLE                = 0x7
-       MADV_FREE_REUSE                   = 0x8
-       MADV_NORMAL                       = 0x0
-       MADV_PAGEOUT                      = 0xa
-       MADV_RANDOM                       = 0x1
-       MADV_SEQUENTIAL                   = 0x2
-       MADV_WILLNEED                     = 0x3
-       MADV_ZERO_WIRED_PAGES             = 0x6
-       MAP_32BIT                         = 0x8000
-       MAP_ANON                          = 0x1000
-       MAP_ANONYMOUS                     = 0x1000
-       MAP_COPY                          = 0x2
-       MAP_FILE                          = 0x0
-       MAP_FIXED                         = 0x10
-       MAP_HASSEMAPHORE                  = 0x200
-       MAP_JIT                           = 0x800
-       MAP_NOCACHE                       = 0x400
-       MAP_NOEXTEND                      = 0x100
-       MAP_NORESERVE                     = 0x40
-       MAP_PRIVATE                       = 0x2
-       MAP_RENAME                        = 0x20
-       MAP_RESERVED0080                  = 0x80
-       MAP_RESILIENT_CODESIGN            = 0x2000
-       MAP_RESILIENT_MEDIA               = 0x4000
-       MAP_SHARED                        = 0x1
-       MAP_TRANSLATED_ALLOW_EXECUTE      = 0x20000
-       MAP_UNIX03                        = 0x40000
-       MCAST_BLOCK_SOURCE                = 0x54
-       MCAST_EXCLUDE                     = 0x2
-       MCAST_INCLUDE                     = 0x1
-       MCAST_JOIN_GROUP                  = 0x50
-       MCAST_JOIN_SOURCE_GROUP           = 0x52
-       MCAST_LEAVE_GROUP                 = 0x51
-       MCAST_LEAVE_SOURCE_GROUP          = 0x53
-       MCAST_UNBLOCK_SOURCE              = 0x55
-       MCAST_UNDEFINED                   = 0x0
-       MCL_CURRENT                       = 0x1
-       MCL_FUTURE                        = 0x2
-       MNT_ASYNC                         = 0x40
-       MNT_AUTOMOUNTED                   = 0x400000
-       MNT_CMDFLAGS                      = 0xf0000
-       MNT_CPROTECT                      = 0x80
-       MNT_DEFWRITE                      = 0x2000000
-       MNT_DONTBROWSE                    = 0x100000
-       MNT_DOVOLFS                       = 0x8000
-       MNT_DWAIT                         = 0x4
-       MNT_EXPORTED                      = 0x100
-       MNT_EXT_ROOT_DATA_VOL             = 0x1
-       MNT_FORCE                         = 0x80000
-       MNT_IGNORE_OWNERSHIP              = 0x200000
-       MNT_JOURNALED                     = 0x800000
-       MNT_LOCAL                         = 0x1000
-       MNT_MULTILABEL                    = 0x4000000
-       MNT_NOATIME                       = 0x10000000
-       MNT_NOBLOCK                       = 0x20000
-       MNT_NODEV                         = 0x10
-       MNT_NOEXEC                        = 0x4
-       MNT_NOSUID                        = 0x8
-       MNT_NOUSERXATTR                   = 0x1000000
-       MNT_NOWAIT                        = 0x2
-       MNT_QUARANTINE                    = 0x400
-       MNT_QUOTA                         = 0x2000
-       MNT_RDONLY                        = 0x1
-       MNT_RELOAD                        = 0x40000
-       MNT_REMOVABLE                     = 0x200
-       MNT_ROOTFS                        = 0x4000
-       MNT_SNAPSHOT                      = 0x40000000
-       MNT_STRICTATIME                   = 0x80000000
-       MNT_SYNCHRONOUS                   = 0x2
-       MNT_UNION                         = 0x20
-       MNT_UNKNOWNPERMISSIONS            = 0x200000
-       MNT_UPDATE                        = 0x10000
-       MNT_VISFLAGMASK                   = 0xd7f0f7ff
-       MNT_WAIT                          = 0x1
-       MSG_CTRUNC                        = 0x20
-       MSG_DONTROUTE                     = 0x4
-       MSG_DONTWAIT                      = 0x80
-       MSG_EOF                           = 0x100
-       MSG_EOR                           = 0x8
-       MSG_FLUSH                         = 0x400
-       MSG_HAVEMORE                      = 0x2000
-       MSG_HOLD                          = 0x800
-       MSG_NEEDSA                        = 0x10000
-       MSG_NOSIGNAL                      = 0x80000
-       MSG_OOB                           = 0x1
-       MSG_PEEK                          = 0x2
-       MSG_RCVMORE                       = 0x4000
-       MSG_SEND                          = 0x1000
-       MSG_TRUNC                         = 0x10
-       MSG_WAITALL                       = 0x40
-       MSG_WAITSTREAM                    = 0x200
-       MS_ASYNC                          = 0x1
-       MS_DEACTIVATE                     = 0x8
-       MS_INVALIDATE                     = 0x2
-       MS_KILLPAGES                      = 0x4
-       MS_SYNC                           = 0x10
-       NAME_MAX                          = 0xff
-       NET_RT_DUMP                       = 0x1
-       NET_RT_DUMP2                      = 0x7
-       NET_RT_FLAGS                      = 0x2
-       NET_RT_FLAGS_PRIV                 = 0xa
-       NET_RT_IFLIST                     = 0x3
-       NET_RT_IFLIST2                    = 0x6
-       NET_RT_MAXID                      = 0xb
-       NET_RT_STAT                       = 0x4
-       NET_RT_TRASH                      = 0x5
-       NFDBITS                           = 0x20
-       NL0                               = 0x0
-       NL1                               = 0x100
-       NL2                               = 0x200
-       NL3                               = 0x300
-       NLDLY                             = 0x300
-       NOFLSH                            = 0x80000000
-       NOKERNINFO                        = 0x2000000
-       NOTE_ABSOLUTE                     = 0x8
-       NOTE_ATTRIB                       = 0x8
-       NOTE_BACKGROUND                   = 0x40
-       NOTE_CHILD                        = 0x4
-       NOTE_CRITICAL                     = 0x20
-       NOTE_DELETE                       = 0x1
-       NOTE_EXEC                         = 0x20000000
-       NOTE_EXIT                         = 0x80000000
-       NOTE_EXITSTATUS                   = 0x4000000
-       NOTE_EXIT_CSERROR                 = 0x40000
-       NOTE_EXIT_DECRYPTFAIL             = 0x10000
-       NOTE_EXIT_DETAIL                  = 0x2000000
-       NOTE_EXIT_DETAIL_MASK             = 0x70000
-       NOTE_EXIT_MEMORY                  = 0x20000
-       NOTE_EXIT_REPARENTED              = 0x80000
-       NOTE_EXTEND                       = 0x4
-       NOTE_FFAND                        = 0x40000000
-       NOTE_FFCOPY                       = 0xc0000000
-       NOTE_FFCTRLMASK                   = 0xc0000000
-       NOTE_FFLAGSMASK                   = 0xffffff
-       NOTE_FFNOP                        = 0x0
-       NOTE_FFOR                         = 0x80000000
-       NOTE_FORK                         = 0x40000000
-       NOTE_FUNLOCK                      = 0x100
-       NOTE_LEEWAY                       = 0x10
-       NOTE_LINK                         = 0x10
-       NOTE_LOWAT                        = 0x1
-       NOTE_MACHTIME                     = 0x100
-       NOTE_MACH_CONTINUOUS_TIME         = 0x80
-       NOTE_NONE                         = 0x80
-       NOTE_NSECONDS                     = 0x4
-       NOTE_OOB                          = 0x2
-       NOTE_PCTRLMASK                    = -0x100000
-       NOTE_PDATAMASK                    = 0xfffff
-       NOTE_REAP                         = 0x10000000
-       NOTE_RENAME                       = 0x20
-       NOTE_REVOKE                       = 0x40
-       NOTE_SECONDS                      = 0x1
-       NOTE_SIGNAL                       = 0x8000000
-       NOTE_TRACK                        = 0x1
-       NOTE_TRACKERR                     = 0x2
-       NOTE_TRIGGER                      = 0x1000000
-       NOTE_USECONDS                     = 0x2
-       NOTE_VM_ERROR                     = 0x10000000
-       NOTE_VM_PRESSURE                  = 0x80000000
-       NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000
-       NOTE_VM_PRESSURE_TERMINATE        = 0x40000000
-       NOTE_WRITE                        = 0x2
-       OCRNL                             = 0x10
-       OFDEL                             = 0x20000
-       OFILL                             = 0x80
-       ONLCR                             = 0x2
-       ONLRET                            = 0x40
-       ONOCR                             = 0x20
-       ONOEOT                            = 0x8
-       OPOST                             = 0x1
-       OXTABS                            = 0x4
-       O_ACCMODE                         = 0x3
-       O_ALERT                           = 0x20000000
-       O_APPEND                          = 0x8
-       O_ASYNC                           = 0x40
-       O_CLOEXEC                         = 0x1000000
-       O_CREAT                           = 0x200
-       O_DIRECTORY                       = 0x100000
-       O_DP_GETRAWENCRYPTED              = 0x1
-       O_DP_GETRAWUNENCRYPTED            = 0x2
-       O_DSYNC                           = 0x400000
-       O_EVTONLY                         = 0x8000
-       O_EXCL                            = 0x800
-       O_EXLOCK                          = 0x20
-       O_FSYNC                           = 0x80
-       O_NDELAY                          = 0x4
-       O_NOCTTY                          = 0x20000
-       O_NOFOLLOW                        = 0x100
-       O_NOFOLLOW_ANY                    = 0x20000000
-       O_NONBLOCK                        = 0x4
-       O_POPUP                           = 0x80000000
-       O_RDONLY                          = 0x0
-       O_RDWR                            = 0x2
-       O_SHLOCK                          = 0x10
-       O_SYMLINK                         = 0x200000
-       O_SYNC                            = 0x80
-       O_TRUNC                           = 0x400
-       O_WRONLY                          = 0x1
-       PARENB                            = 0x1000
-       PARMRK                            = 0x8
-       PARODD                            = 0x2000
-       PENDIN                            = 0x20000000
-       PRIO_PGRP                         = 0x1
-       PRIO_PROCESS                      = 0x0
-       PRIO_USER                         = 0x2
-       PROT_EXEC                         = 0x4
-       PROT_NONE                         = 0x0
-       PROT_READ                         = 0x1
-       PROT_WRITE                        = 0x2
-       PT_ATTACH                         = 0xa
-       PT_ATTACHEXC                      = 0xe
-       PT_CONTINUE                       = 0x7
-       PT_DENY_ATTACH                    = 0x1f
-       PT_DETACH                         = 0xb
-       PT_FIRSTMACH                      = 0x20
-       PT_FORCEQUOTA                     = 0x1e
-       PT_KILL                           = 0x8
-       PT_READ_D                         = 0x2
-       PT_READ_I                         = 0x1
-       PT_READ_U                         = 0x3
-       PT_SIGEXC                         = 0xc
-       PT_STEP                           = 0x9
-       PT_THUPDATE                       = 0xd
-       PT_TRACE_ME                       = 0x0
-       PT_WRITE_D                        = 0x5
-       PT_WRITE_I                        = 0x4
-       PT_WRITE_U                        = 0x6
-       RLIMIT_AS                         = 0x5
-       RLIMIT_CORE                       = 0x4
-       RLIMIT_CPU                        = 0x0
-       RLIMIT_CPU_USAGE_MONITOR          = 0x2
-       RLIMIT_DATA                       = 0x2
-       RLIMIT_FSIZE                      = 0x1
-       RLIMIT_MEMLOCK                    = 0x6
-       RLIMIT_NOFILE                     = 0x8
-       RLIMIT_NPROC                      = 0x7
-       RLIMIT_RSS                        = 0x5
-       RLIMIT_STACK                      = 0x3
-       RLIM_INFINITY                     = 0x7fffffffffffffff
-       RTAX_AUTHOR                       = 0x6
-       RTAX_BRD                          = 0x7
-       RTAX_DST                          = 0x0
-       RTAX_GATEWAY                      = 0x1
-       RTAX_GENMASK                      = 0x3
-       RTAX_IFA                          = 0x5
-       RTAX_IFP                          = 0x4
-       RTAX_MAX                          = 0x8
-       RTAX_NETMASK                      = 0x2
-       RTA_AUTHOR                        = 0x40
-       RTA_BRD                           = 0x80
-       RTA_DST                           = 0x1
-       RTA_GATEWAY                       = 0x2
-       RTA_GENMASK                       = 0x8
-       RTA_IFA                           = 0x20
-       RTA_IFP                           = 0x10
-       RTA_NETMASK                       = 0x4
-       RTF_BLACKHOLE                     = 0x1000
-       RTF_BROADCAST                     = 0x400000
-       RTF_CLONING                       = 0x100
-       RTF_CONDEMNED                     = 0x2000000
-       RTF_DEAD                          = 0x20000000
-       RTF_DELCLONE                      = 0x80
-       RTF_DONE                          = 0x40
-       RTF_DYNAMIC                       = 0x10
-       RTF_GATEWAY                       = 0x2
-       RTF_HOST                          = 0x4
-       RTF_IFREF                         = 0x4000000
-       RTF_IFSCOPE                       = 0x1000000
-       RTF_LLDATA                        = 0x400
-       RTF_LLINFO                        = 0x400
-       RTF_LOCAL                         = 0x200000
-       RTF_MODIFIED                      = 0x20
-       RTF_MULTICAST                     = 0x800000
-       RTF_NOIFREF                       = 0x2000
-       RTF_PINNED                        = 0x100000
-       RTF_PRCLONING                     = 0x10000
-       RTF_PROTO1                        = 0x8000
-       RTF_PROTO2                        = 0x4000
-       RTF_PROTO3                        = 0x40000
-       RTF_PROXY                         = 0x8000000
-       RTF_REJECT                        = 0x8
-       RTF_ROUTER                        = 0x10000000
-       RTF_STATIC                        = 0x800
-       RTF_UP                            = 0x1
-       RTF_WASCLONED                     = 0x20000
-       RTF_XRESOLVE                      = 0x200
-       RTM_ADD                           = 0x1
-       RTM_CHANGE                        = 0x3
-       RTM_DELADDR                       = 0xd
-       RTM_DELETE                        = 0x2
-       RTM_DELMADDR                      = 0x10
-       RTM_GET                           = 0x4
-       RTM_GET2                          = 0x14
-       RTM_IFINFO                        = 0xe
-       RTM_IFINFO2                       = 0x12
-       RTM_LOCK                          = 0x8
-       RTM_LOSING                        = 0x5
-       RTM_MISS                          = 0x7
-       RTM_NEWADDR                       = 0xc
-       RTM_NEWMADDR                      = 0xf
-       RTM_NEWMADDR2                     = 0x13
-       RTM_OLDADD                        = 0x9
-       RTM_OLDDEL                        = 0xa
-       RTM_REDIRECT                      = 0x6
-       RTM_RESOLVE                       = 0xb
-       RTM_RTTUNIT                       = 0xf4240
-       RTM_VERSION                       = 0x5
-       RTV_EXPIRE                        = 0x4
-       RTV_HOPCOUNT                      = 0x2
-       RTV_MTU                           = 0x1
-       RTV_RPIPE                         = 0x8
-       RTV_RTT                           = 0x40
-       RTV_RTTVAR                        = 0x80
-       RTV_SPIPE                         = 0x10
-       RTV_SSTHRESH                      = 0x20
-       RUSAGE_CHILDREN                   = -0x1
-       RUSAGE_SELF                       = 0x0
-       SCM_CREDS                         = 0x3
-       SCM_RIGHTS                        = 0x1
-       SCM_TIMESTAMP                     = 0x2
-       SCM_TIMESTAMP_MONOTONIC           = 0x4
-       SHUT_RD                           = 0x0
-       SHUT_RDWR                         = 0x2
-       SHUT_WR                           = 0x1
-       SIOCADDMULTI                      = 0x80206931
-       SIOCAIFADDR                       = 0x8040691a
-       SIOCARPIPLL                       = 0xc0206928
-       SIOCATMARK                        = 0x40047307
-       SIOCAUTOADDR                      = 0xc0206926
-       SIOCAUTONETMASK                   = 0x80206927
-       SIOCDELMULTI                      = 0x80206932
-       SIOCDIFADDR                       = 0x80206919
-       SIOCDIFPHYADDR                    = 0x80206941
-       SIOCGDRVSPEC                      = 0xc028697b
-       SIOCGETVLAN                       = 0xc020697f
-       SIOCGHIWAT                        = 0x40047301
-       SIOCGIF6LOWPAN                    = 0xc02069c5
-       SIOCGIFADDR                       = 0xc0206921
-       SIOCGIFALTMTU                     = 0xc0206948
-       SIOCGIFASYNCMAP                   = 0xc020697c
-       SIOCGIFBOND                       = 0xc0206947
-       SIOCGIFBRDADDR                    = 0xc0206923
-       SIOCGIFCAP                        = 0xc020695b
-       SIOCGIFCONF                       = 0xc00c6924
-       SIOCGIFDEVMTU                     = 0xc0206944
-       SIOCGIFDSTADDR                    = 0xc0206922
-       SIOCGIFFLAGS                      = 0xc0206911
-       SIOCGIFFUNCTIONALTYPE             = 0xc02069ad
-       SIOCGIFGENERIC                    = 0xc020693a
-       SIOCGIFKPI                        = 0xc0206987
-       SIOCGIFMAC                        = 0xc0206982
-       SIOCGIFMEDIA                      = 0xc02c6938
-       SIOCGIFMETRIC                     = 0xc0206917
-       SIOCGIFMTU                        = 0xc0206933
-       SIOCGIFNETMASK                    = 0xc0206925
-       SIOCGIFPDSTADDR                   = 0xc0206940
-       SIOCGIFPHYS                       = 0xc0206935
-       SIOCGIFPSRCADDR                   = 0xc020693f
-       SIOCGIFSTATUS                     = 0xc331693d
-       SIOCGIFVLAN                       = 0xc020697f
-       SIOCGIFWAKEFLAGS                  = 0xc0206988
-       SIOCGIFXMEDIA                     = 0xc02c6948
-       SIOCGLOWAT                        = 0x40047303
-       SIOCGPGRP                         = 0x40047309
-       SIOCIFCREATE                      = 0xc0206978
-       SIOCIFCREATE2                     = 0xc020697a
-       SIOCIFDESTROY                     = 0x80206979
-       SIOCIFGCLONERS                    = 0xc0106981
-       SIOCRSLVMULTI                     = 0xc010693b
-       SIOCSDRVSPEC                      = 0x8028697b
-       SIOCSETVLAN                       = 0x8020697e
-       SIOCSHIWAT                        = 0x80047300
-       SIOCSIF6LOWPAN                    = 0x802069c4
-       SIOCSIFADDR                       = 0x8020690c
-       SIOCSIFALTMTU                     = 0x80206945
-       SIOCSIFASYNCMAP                   = 0x8020697d
-       SIOCSIFBOND                       = 0x80206946
-       SIOCSIFBRDADDR                    = 0x80206913
-       SIOCSIFCAP                        = 0x8020695a
-       SIOCSIFDSTADDR                    = 0x8020690e
-       SIOCSIFFLAGS                      = 0x80206910
-       SIOCSIFGENERIC                    = 0x80206939
-       SIOCSIFKPI                        = 0x80206986
-       SIOCSIFLLADDR                     = 0x8020693c
-       SIOCSIFMAC                        = 0x80206983
-       SIOCSIFMEDIA                      = 0xc0206937
-       SIOCSIFMETRIC                     = 0x80206918
-       SIOCSIFMTU                        = 0x80206934
-       SIOCSIFNETMASK                    = 0x80206916
-       SIOCSIFPHYADDR                    = 0x8040693e
-       SIOCSIFPHYS                       = 0x80206936
-       SIOCSIFVLAN                       = 0x8020697e
-       SIOCSLOWAT                        = 0x80047302
-       SIOCSPGRP                         = 0x80047308
-       SOCK_DGRAM                        = 0x2
-       SOCK_MAXADDRLEN                   = 0xff
-       SOCK_RAW                          = 0x3
-       SOCK_RDM                          = 0x4
-       SOCK_SEQPACKET                    = 0x5
-       SOCK_STREAM                       = 0x1
-       SOL_LOCAL                         = 0x0
-       SOL_SOCKET                        = 0xffff
-       SOMAXCONN                         = 0x80
-       SO_ACCEPTCONN                     = 0x2
-       SO_BROADCAST                      = 0x20
-       SO_DEBUG                          = 0x1
-       SO_DONTROUTE                      = 0x10
-       SO_DONTTRUNC                      = 0x2000
-       SO_ERROR                          = 0x1007
-       SO_KEEPALIVE                      = 0x8
-       SO_LABEL                          = 0x1010
-       SO_LINGER                         = 0x80
-       SO_LINGER_SEC                     = 0x1080
-       SO_NETSVC_MARKING_LEVEL           = 0x1119
-       SO_NET_SERVICE_TYPE               = 0x1116
-       SO_NKE                            = 0x1021
-       SO_NOADDRERR                      = 0x1023
-       SO_NOSIGPIPE                      = 0x1022
-       SO_NOTIFYCONFLICT                 = 0x1026
-       SO_NP_EXTENSIONS                  = 0x1083
-       SO_NREAD                          = 0x1020
-       SO_NUMRCVPKT                      = 0x1112
-       SO_NWRITE                         = 0x1024
-       SO_OOBINLINE                      = 0x100
-       SO_PEERLABEL                      = 0x1011
-       SO_RANDOMPORT                     = 0x1082
-       SO_RCVBUF                         = 0x1002
-       SO_RCVLOWAT                       = 0x1004
-       SO_RCVTIMEO                       = 0x1006
-       SO_REUSEADDR                      = 0x4
-       SO_REUSEPORT                      = 0x200
-       SO_REUSESHAREUID                  = 0x1025
-       SO_SNDBUF                         = 0x1001
-       SO_SNDLOWAT                       = 0x1003
-       SO_SNDTIMEO                       = 0x1005
-       SO_TIMESTAMP                      = 0x400
-       SO_TIMESTAMP_MONOTONIC            = 0x800
-       SO_TYPE                           = 0x1008
-       SO_UPCALLCLOSEWAIT                = 0x1027
-       SO_USELOOPBACK                    = 0x40
-       SO_WANTMORE                       = 0x4000
-       SO_WANTOOBFLAG                    = 0x8000
-       S_IEXEC                           = 0x40
-       S_IFBLK                           = 0x6000
-       S_IFCHR                           = 0x2000
-       S_IFDIR                           = 0x4000
-       S_IFIFO                           = 0x1000
-       S_IFLNK                           = 0xa000
-       S_IFMT                            = 0xf000
-       S_IFREG                           = 0x8000
-       S_IFSOCK                          = 0xc000
-       S_IFWHT                           = 0xe000
-       S_IREAD                           = 0x100
-       S_IRGRP                           = 0x20
-       S_IROTH                           = 0x4
-       S_IRUSR                           = 0x100
-       S_IRWXG                           = 0x38
-       S_IRWXO                           = 0x7
-       S_IRWXU                           = 0x1c0
-       S_ISGID                           = 0x400
-       S_ISTXT                           = 0x200
-       S_ISUID                           = 0x800
-       S_ISVTX                           = 0x200
-       S_IWGRP                           = 0x10
-       S_IWOTH                           = 0x2
-       S_IWRITE                          = 0x80
-       S_IWUSR                           = 0x80
-       S_IXGRP                           = 0x8
-       S_IXOTH                           = 0x1
-       S_IXUSR                           = 0x40
-       TAB0                              = 0x0
-       TAB1                              = 0x400
-       TAB2                              = 0x800
-       TAB3                              = 0x4
-       TABDLY                            = 0xc04
-       TCIFLUSH                          = 0x1
-       TCIOFF                            = 0x3
-       TCIOFLUSH                         = 0x3
-       TCION                             = 0x4
-       TCOFLUSH                          = 0x2
-       TCOOFF                            = 0x1
-       TCOON                             = 0x2
-       TCP_CONNECTIONTIMEOUT             = 0x20
-       TCP_CONNECTION_INFO               = 0x106
-       TCP_ENABLE_ECN                    = 0x104
-       TCP_FASTOPEN                      = 0x105
-       TCP_KEEPALIVE                     = 0x10
-       TCP_KEEPCNT                       = 0x102
-       TCP_KEEPINTVL                     = 0x101
-       TCP_MAXHLEN                       = 0x3c
-       TCP_MAXOLEN                       = 0x28
-       TCP_MAXSEG                        = 0x2
-       TCP_MAXWIN                        = 0xffff
-       TCP_MAX_SACK                      = 0x4
-       TCP_MAX_WINSHIFT                  = 0xe
-       TCP_MINMSS                        = 0xd8
-       TCP_MSS                           = 0x200
-       TCP_NODELAY                       = 0x1
-       TCP_NOOPT                         = 0x8
-       TCP_NOPUSH                        = 0x4
-       TCP_NOTSENT_LOWAT                 = 0x201
-       TCP_RXT_CONNDROPTIME              = 0x80
-       TCP_RXT_FINDROP                   = 0x100
-       TCP_SENDMOREACKS                  = 0x103
-       TCSAFLUSH                         = 0x2
-       TIOCCBRK                          = 0x2000747a
-       TIOCCDTR                          = 0x20007478
-       TIOCCONS                          = 0x80047462
-       TIOCDCDTIMESTAMP                  = 0x40107458
-       TIOCDRAIN                         = 0x2000745e
-       TIOCDSIMICROCODE                  = 0x20007455
-       TIOCEXCL                          = 0x2000740d
-       TIOCEXT                           = 0x80047460
-       TIOCFLUSH                         = 0x80047410
-       TIOCGDRAINWAIT                    = 0x40047456
-       TIOCGETA                          = 0x40487413
-       TIOCGETD                          = 0x4004741a
-       TIOCGPGRP                         = 0x40047477
-       TIOCGWINSZ                        = 0x40087468
-       TIOCIXOFF                         = 0x20007480
-       TIOCIXON                          = 0x20007481
-       TIOCMBIC                          = 0x8004746b
-       TIOCMBIS                          = 0x8004746c
-       TIOCMGDTRWAIT                     = 0x4004745a
-       TIOCMGET                          = 0x4004746a
-       TIOCMODG                          = 0x40047403
-       TIOCMODS                          = 0x80047404
-       TIOCMSDTRWAIT                     = 0x8004745b
-       TIOCMSET                          = 0x8004746d
-       TIOCM_CAR                         = 0x40
-       TIOCM_CD                          = 0x40
-       TIOCM_CTS                         = 0x20
-       TIOCM_DSR                         = 0x100
-       TIOCM_DTR                         = 0x2
-       TIOCM_LE                          = 0x1
-       TIOCM_RI                          = 0x80
-       TIOCM_RNG                         = 0x80
-       TIOCM_RTS                         = 0x4
-       TIOCM_SR                          = 0x10
-       TIOCM_ST                          = 0x8
-       TIOCNOTTY                         = 0x20007471
-       TIOCNXCL                          = 0x2000740e
-       TIOCOUTQ                          = 0x40047473
-       TIOCPKT                           = 0x80047470
-       TIOCPKT_DATA                      = 0x0
-       TIOCPKT_DOSTOP                    = 0x20
-       TIOCPKT_FLUSHREAD                 = 0x1
-       TIOCPKT_FLUSHWRITE                = 0x2
-       TIOCPKT_IOCTL                     = 0x40
-       TIOCPKT_NOSTOP                    = 0x10
-       TIOCPKT_START                     = 0x8
-       TIOCPKT_STOP                      = 0x4
-       TIOCPTYGNAME                      = 0x40807453
-       TIOCPTYGRANT                      = 0x20007454
-       TIOCPTYUNLK                       = 0x20007452
-       TIOCREMOTE                        = 0x80047469
-       TIOCSBRK                          = 0x2000747b
-       TIOCSCONS                         = 0x20007463
-       TIOCSCTTY                         = 0x20007461
-       TIOCSDRAINWAIT                    = 0x80047457
-       TIOCSDTR                          = 0x20007479
-       TIOCSETA                          = 0x80487414
-       TIOCSETAF                         = 0x80487416
-       TIOCSETAW                         = 0x80487415
-       TIOCSETD                          = 0x8004741b
-       TIOCSIG                           = 0x2000745f
-       TIOCSPGRP                         = 0x80047476
-       TIOCSTART                         = 0x2000746e
-       TIOCSTAT                          = 0x20007465
-       TIOCSTI                           = 0x80017472
-       TIOCSTOP                          = 0x2000746f
-       TIOCSWINSZ                        = 0x80087467
-       TIOCTIMESTAMP                     = 0x40107459
-       TIOCUCNTL                         = 0x80047466
-       TOSTOP                            = 0x400000
-       VDISCARD                          = 0xf
-       VDSUSP                            = 0xb
-       VEOF                              = 0x0
-       VEOL                              = 0x1
-       VEOL2                             = 0x2
-       VERASE                            = 0x3
-       VINTR                             = 0x8
-       VKILL                             = 0x5
-       VLNEXT                            = 0xe
-       VMIN                              = 0x10
-       VM_LOADAVG                        = 0x2
-       VM_MACHFACTOR                     = 0x4
-       VM_MAXID                          = 0x6
-       VM_METER                          = 0x1
-       VM_SWAPUSAGE                      = 0x5
-       VQUIT                             = 0x9
-       VREPRINT                          = 0x6
-       VSTART                            = 0xc
-       VSTATUS                           = 0x12
-       VSTOP                             = 0xd
-       VSUSP                             = 0xa
-       VT0                               = 0x0
-       VT1                               = 0x10000
-       VTDLY                             = 0x10000
-       VTIME                             = 0x11
-       VWERASE                           = 0x4
-       WCONTINUED                        = 0x10
-       WCOREFLAG                         = 0x80
-       WEXITED                           = 0x4
-       WNOHANG                           = 0x1
-       WNOWAIT                           = 0x20
-       WORDSIZE                          = 0x40
-       WSTOPPED                          = 0x8
-       WUNTRACED                         = 0x2
-       XATTR_CREATE                      = 0x2
-       XATTR_NODEFAULT                   = 0x10
-       XATTR_NOFOLLOW                    = 0x1
-       XATTR_NOSECURITY                  = 0x8
-       XATTR_REPLACE                     = 0x4
-       XATTR_SHOWCOMPRESSION             = 0x20
+       AF_APPLETALK                            = 0x10
+       AF_CCITT                                = 0xa
+       AF_CHAOS                                = 0x5
+       AF_CNT                                  = 0x15
+       AF_COIP                                 = 0x14
+       AF_DATAKIT                              = 0x9
+       AF_DECnet                               = 0xc
+       AF_DLI                                  = 0xd
+       AF_E164                                 = 0x1c
+       AF_ECMA                                 = 0x8
+       AF_HYLINK                               = 0xf
+       AF_IEEE80211                            = 0x25
+       AF_IMPLINK                              = 0x3
+       AF_INET                                 = 0x2
+       AF_INET6                                = 0x1e
+       AF_IPX                                  = 0x17
+       AF_ISDN                                 = 0x1c
+       AF_ISO                                  = 0x7
+       AF_LAT                                  = 0xe
+       AF_LINK                                 = 0x12
+       AF_LOCAL                                = 0x1
+       AF_MAX                                  = 0x29
+       AF_NATM                                 = 0x1f
+       AF_NDRV                                 = 0x1b
+       AF_NETBIOS                              = 0x21
+       AF_NS                                   = 0x6
+       AF_OSI                                  = 0x7
+       AF_PPP                                  = 0x22
+       AF_PUP                                  = 0x4
+       AF_RESERVED_36                          = 0x24
+       AF_ROUTE                                = 0x11
+       AF_SIP                                  = 0x18
+       AF_SNA                                  = 0xb
+       AF_SYSTEM                               = 0x20
+       AF_SYS_CONTROL                          = 0x2
+       AF_UNIX                                 = 0x1
+       AF_UNSPEC                               = 0x0
+       AF_UTUN                                 = 0x26
+       AF_VSOCK                                = 0x28
+       ALTWERASE                               = 0x200
+       ATTR_BIT_MAP_COUNT                      = 0x5
+       ATTR_CMN_ACCESSMASK                     = 0x20000
+       ATTR_CMN_ACCTIME                        = 0x1000
+       ATTR_CMN_ADDEDTIME                      = 0x10000000
+       ATTR_CMN_BKUPTIME                       = 0x2000
+       ATTR_CMN_CHGTIME                        = 0x800
+       ATTR_CMN_CRTIME                         = 0x200
+       ATTR_CMN_DATA_PROTECT_FLAGS             = 0x40000000
+       ATTR_CMN_DEVID                          = 0x2
+       ATTR_CMN_DOCUMENT_ID                    = 0x100000
+       ATTR_CMN_ERROR                          = 0x20000000
+       ATTR_CMN_EXTENDED_SECURITY              = 0x400000
+       ATTR_CMN_FILEID                         = 0x2000000
+       ATTR_CMN_FLAGS                          = 0x40000
+       ATTR_CMN_FNDRINFO                       = 0x4000
+       ATTR_CMN_FSID                           = 0x4
+       ATTR_CMN_FULLPATH                       = 0x8000000
+       ATTR_CMN_GEN_COUNT                      = 0x80000
+       ATTR_CMN_GRPID                          = 0x10000
+       ATTR_CMN_GRPUUID                        = 0x1000000
+       ATTR_CMN_MODTIME                        = 0x400
+       ATTR_CMN_NAME                           = 0x1
+       ATTR_CMN_NAMEDATTRCOUNT                 = 0x80000
+       ATTR_CMN_NAMEDATTRLIST                  = 0x100000
+       ATTR_CMN_OBJID                          = 0x20
+       ATTR_CMN_OBJPERMANENTID                 = 0x40
+       ATTR_CMN_OBJTAG                         = 0x10
+       ATTR_CMN_OBJTYPE                        = 0x8
+       ATTR_CMN_OWNERID                        = 0x8000
+       ATTR_CMN_PARENTID                       = 0x4000000
+       ATTR_CMN_PAROBJID                       = 0x80
+       ATTR_CMN_RETURNED_ATTRS                 = 0x80000000
+       ATTR_CMN_SCRIPT                         = 0x100
+       ATTR_CMN_SETMASK                        = 0x51c7ff00
+       ATTR_CMN_USERACCESS                     = 0x200000
+       ATTR_CMN_UUID                           = 0x800000
+       ATTR_CMN_VALIDMASK                      = 0xffffffff
+       ATTR_CMN_VOLSETMASK                     = 0x6700
+       ATTR_FILE_ALLOCSIZE                     = 0x4
+       ATTR_FILE_CLUMPSIZE                     = 0x10
+       ATTR_FILE_DATAALLOCSIZE                 = 0x400
+       ATTR_FILE_DATAEXTENTS                   = 0x800
+       ATTR_FILE_DATALENGTH                    = 0x200
+       ATTR_FILE_DEVTYPE                       = 0x20
+       ATTR_FILE_FILETYPE                      = 0x40
+       ATTR_FILE_FORKCOUNT                     = 0x80
+       ATTR_FILE_FORKLIST                      = 0x100
+       ATTR_FILE_IOBLOCKSIZE                   = 0x8
+       ATTR_FILE_LINKCOUNT                     = 0x1
+       ATTR_FILE_RSRCALLOCSIZE                 = 0x2000
+       ATTR_FILE_RSRCEXTENTS                   = 0x4000
+       ATTR_FILE_RSRCLENGTH                    = 0x1000
+       ATTR_FILE_SETMASK                       = 0x20
+       ATTR_FILE_TOTALSIZE                     = 0x2
+       ATTR_FILE_VALIDMASK                     = 0x37ff
+       ATTR_VOL_ALLOCATIONCLUMP                = 0x40
+       ATTR_VOL_ATTRIBUTES                     = 0x40000000
+       ATTR_VOL_CAPABILITIES                   = 0x20000
+       ATTR_VOL_DIRCOUNT                       = 0x400
+       ATTR_VOL_ENCODINGSUSED                  = 0x10000
+       ATTR_VOL_FILECOUNT                      = 0x200
+       ATTR_VOL_FSTYPE                         = 0x1
+       ATTR_VOL_INFO                           = 0x80000000
+       ATTR_VOL_IOBLOCKSIZE                    = 0x80
+       ATTR_VOL_MAXOBJCOUNT                    = 0x800
+       ATTR_VOL_MINALLOCATION                  = 0x20
+       ATTR_VOL_MOUNTEDDEVICE                  = 0x8000
+       ATTR_VOL_MOUNTFLAGS                     = 0x4000
+       ATTR_VOL_MOUNTPOINT                     = 0x1000
+       ATTR_VOL_NAME                           = 0x2000
+       ATTR_VOL_OBJCOUNT                       = 0x100
+       ATTR_VOL_QUOTA_SIZE                     = 0x10000000
+       ATTR_VOL_RESERVED_SIZE                  = 0x20000000
+       ATTR_VOL_SETMASK                        = 0x80002000
+       ATTR_VOL_SIGNATURE                      = 0x2
+       ATTR_VOL_SIZE                           = 0x4
+       ATTR_VOL_SPACEAVAIL                     = 0x10
+       ATTR_VOL_SPACEFREE                      = 0x8
+       ATTR_VOL_SPACEUSED                      = 0x800000
+       ATTR_VOL_UUID                           = 0x40000
+       ATTR_VOL_VALIDMASK                      = 0xf087ffff
+       B0                                      = 0x0
+       B110                                    = 0x6e
+       B115200                                 = 0x1c200
+       B1200                                   = 0x4b0
+       B134                                    = 0x86
+       B14400                                  = 0x3840
+       B150                                    = 0x96
+       B1800                                   = 0x708
+       B19200                                  = 0x4b00
+       B200                                    = 0xc8
+       B230400                                 = 0x38400
+       B2400                                   = 0x960
+       B28800                                  = 0x7080
+       B300                                    = 0x12c
+       B38400                                  = 0x9600
+       B4800                                   = 0x12c0
+       B50                                     = 0x32
+       B57600                                  = 0xe100
+       B600                                    = 0x258
+       B7200                                   = 0x1c20
+       B75                                     = 0x4b
+       B76800                                  = 0x12c00
+       B9600                                   = 0x2580
+       BIOCFLUSH                               = 0x20004268
+       BIOCGBLEN                               = 0x40044266
+       BIOCGDLT                                = 0x4004426a
+       BIOCGDLTLIST                            = 0xc00c4279
+       BIOCGETIF                               = 0x4020426b
+       BIOCGHDRCMPLT                           = 0x40044274
+       BIOCGRSIG                               = 0x40044272
+       BIOCGRTIMEOUT                           = 0x4010426e
+       BIOCGSEESENT                            = 0x40044276
+       BIOCGSTATS                              = 0x4008426f
+       BIOCIMMEDIATE                           = 0x80044270
+       BIOCPROMISC                             = 0x20004269
+       BIOCSBLEN                               = 0xc0044266
+       BIOCSDLT                                = 0x80044278
+       BIOCSETF                                = 0x80104267
+       BIOCSETFNR                              = 0x8010427e
+       BIOCSETIF                               = 0x8020426c
+       BIOCSHDRCMPLT                           = 0x80044275
+       BIOCSRSIG                               = 0x80044273
+       BIOCSRTIMEOUT                           = 0x8010426d
+       BIOCSSEESENT                            = 0x80044277
+       BIOCVERSION                             = 0x40044271
+       BPF_A                                   = 0x10
+       BPF_ABS                                 = 0x20
+       BPF_ADD                                 = 0x0
+       BPF_ALIGNMENT                           = 0x4
+       BPF_ALU                                 = 0x4
+       BPF_AND                                 = 0x50
+       BPF_B                                   = 0x10
+       BPF_DIV                                 = 0x30
+       BPF_H                                   = 0x8
+       BPF_IMM                                 = 0x0
+       BPF_IND                                 = 0x40
+       BPF_JA                                  = 0x0
+       BPF_JEQ                                 = 0x10
+       BPF_JGE                                 = 0x30
+       BPF_JGT                                 = 0x20
+       BPF_JMP                                 = 0x5
+       BPF_JSET                                = 0x40
+       BPF_K                                   = 0x0
+       BPF_LD                                  = 0x0
+       BPF_LDX                                 = 0x1
+       BPF_LEN                                 = 0x80
+       BPF_LSH                                 = 0x60
+       BPF_MAJOR_VERSION                       = 0x1
+       BPF_MAXBUFSIZE                          = 0x80000
+       BPF_MAXINSNS                            = 0x200
+       BPF_MEM                                 = 0x60
+       BPF_MEMWORDS                            = 0x10
+       BPF_MINBUFSIZE                          = 0x20
+       BPF_MINOR_VERSION                       = 0x1
+       BPF_MISC                                = 0x7
+       BPF_MSH                                 = 0xa0
+       BPF_MUL                                 = 0x20
+       BPF_NEG                                 = 0x80
+       BPF_OR                                  = 0x40
+       BPF_RELEASE                             = 0x30bb6
+       BPF_RET                                 = 0x6
+       BPF_RSH                                 = 0x70
+       BPF_ST                                  = 0x2
+       BPF_STX                                 = 0x3
+       BPF_SUB                                 = 0x10
+       BPF_TAX                                 = 0x0
+       BPF_TXA                                 = 0x80
+       BPF_W                                   = 0x0
+       BPF_X                                   = 0x8
+       BRKINT                                  = 0x2
+       BS0                                     = 0x0
+       BS1                                     = 0x8000
+       BSDLY                                   = 0x8000
+       CFLUSH                                  = 0xf
+       CLOCAL                                  = 0x8000
+       CLOCK_MONOTONIC                         = 0x6
+       CLOCK_MONOTONIC_RAW                     = 0x4
+       CLOCK_MONOTONIC_RAW_APPROX              = 0x5
+       CLOCK_PROCESS_CPUTIME_ID                = 0xc
+       CLOCK_REALTIME                          = 0x0
+       CLOCK_THREAD_CPUTIME_ID                 = 0x10
+       CLOCK_UPTIME_RAW                        = 0x8
+       CLOCK_UPTIME_RAW_APPROX                 = 0x9
+       CLONE_NOFOLLOW                          = 0x1
+       CLONE_NOOWNERCOPY                       = 0x2
+       CR0                                     = 0x0
+       CR1                                     = 0x1000
+       CR2                                     = 0x2000
+       CR3                                     = 0x3000
+       CRDLY                                   = 0x3000
+       CREAD                                   = 0x800
+       CRTSCTS                                 = 0x30000
+       CS5                                     = 0x0
+       CS6                                     = 0x100
+       CS7                                     = 0x200
+       CS8                                     = 0x300
+       CSIZE                                   = 0x300
+       CSTART                                  = 0x11
+       CSTATUS                                 = 0x14
+       CSTOP                                   = 0x13
+       CSTOPB                                  = 0x400
+       CSUSP                                   = 0x1a
+       CTLIOCGINFO                             = 0xc0644e03
+       CTL_HW                                  = 0x6
+       CTL_KERN                                = 0x1
+       CTL_MAXNAME                             = 0xc
+       CTL_NET                                 = 0x4
+       DLT_A429                                = 0xb8
+       DLT_A653_ICM                            = 0xb9
+       DLT_AIRONET_HEADER                      = 0x78
+       DLT_AOS                                 = 0xde
+       DLT_APPLE_IP_OVER_IEEE1394              = 0x8a
+       DLT_ARCNET                              = 0x7
+       DLT_ARCNET_LINUX                        = 0x81
+       DLT_ATM_CLIP                            = 0x13
+       DLT_ATM_RFC1483                         = 0xb
+       DLT_AURORA                              = 0x7e
+       DLT_AX25                                = 0x3
+       DLT_AX25_KISS                           = 0xca
+       DLT_BACNET_MS_TP                        = 0xa5
+       DLT_BLUETOOTH_HCI_H4                    = 0xbb
+       DLT_BLUETOOTH_HCI_H4_WITH_PHDR          = 0xc9
+       DLT_CAN20B                              = 0xbe
+       DLT_CAN_SOCKETCAN                       = 0xe3
+       DLT_CHAOS                               = 0x5
+       DLT_CHDLC                               = 0x68
+       DLT_CISCO_IOS                           = 0x76
+       DLT_C_HDLC                              = 0x68
+       DLT_C_HDLC_WITH_DIR                     = 0xcd
+       DLT_DBUS                                = 0xe7
+       DLT_DECT                                = 0xdd
+       DLT_DOCSIS                              = 0x8f
+       DLT_DVB_CI                              = 0xeb
+       DLT_ECONET                              = 0x73
+       DLT_EN10MB                              = 0x1
+       DLT_EN3MB                               = 0x2
+       DLT_ENC                                 = 0x6d
+       DLT_ERF                                 = 0xc5
+       DLT_ERF_ETH                             = 0xaf
+       DLT_ERF_POS                             = 0xb0
+       DLT_FC_2                                = 0xe0
+       DLT_FC_2_WITH_FRAME_DELIMS              = 0xe1
+       DLT_FDDI                                = 0xa
+       DLT_FLEXRAY                             = 0xd2
+       DLT_FRELAY                              = 0x6b
+       DLT_FRELAY_WITH_DIR                     = 0xce
+       DLT_GCOM_SERIAL                         = 0xad
+       DLT_GCOM_T1E1                           = 0xac
+       DLT_GPF_F                               = 0xab
+       DLT_GPF_T                               = 0xaa
+       DLT_GPRS_LLC                            = 0xa9
+       DLT_GSMTAP_ABIS                         = 0xda
+       DLT_GSMTAP_UM                           = 0xd9
+       DLT_HHDLC                               = 0x79
+       DLT_IBM_SN                              = 0x92
+       DLT_IBM_SP                              = 0x91
+       DLT_IEEE802                             = 0x6
+       DLT_IEEE802_11                          = 0x69
+       DLT_IEEE802_11_RADIO                    = 0x7f
+       DLT_IEEE802_11_RADIO_AVS                = 0xa3
+       DLT_IEEE802_15_4                        = 0xc3
+       DLT_IEEE802_15_4_LINUX                  = 0xbf
+       DLT_IEEE802_15_4_NOFCS                  = 0xe6
+       DLT_IEEE802_15_4_NONASK_PHY             = 0xd7
+       DLT_IEEE802_16_MAC_CPS                  = 0xbc
+       DLT_IEEE802_16_MAC_CPS_RADIO            = 0xc1
+       DLT_IPFILTER                            = 0x74
+       DLT_IPMB                                = 0xc7
+       DLT_IPMB_LINUX                          = 0xd1
+       DLT_IPNET                               = 0xe2
+       DLT_IPOIB                               = 0xf2
+       DLT_IPV4                                = 0xe4
+       DLT_IPV6                                = 0xe5
+       DLT_IP_OVER_FC                          = 0x7a
+       DLT_JUNIPER_ATM1                        = 0x89
+       DLT_JUNIPER_ATM2                        = 0x87
+       DLT_JUNIPER_ATM_CEMIC                   = 0xee
+       DLT_JUNIPER_CHDLC                       = 0xb5
+       DLT_JUNIPER_ES                          = 0x84
+       DLT_JUNIPER_ETHER                       = 0xb2
+       DLT_JUNIPER_FIBRECHANNEL                = 0xea
+       DLT_JUNIPER_FRELAY                      = 0xb4
+       DLT_JUNIPER_GGSN                        = 0x85
+       DLT_JUNIPER_ISM                         = 0xc2
+       DLT_JUNIPER_MFR                         = 0x86
+       DLT_JUNIPER_MLFR                        = 0x83
+       DLT_JUNIPER_MLPPP                       = 0x82
+       DLT_JUNIPER_MONITOR                     = 0xa4
+       DLT_JUNIPER_PIC_PEER                    = 0xae
+       DLT_JUNIPER_PPP                         = 0xb3
+       DLT_JUNIPER_PPPOE                       = 0xa7
+       DLT_JUNIPER_PPPOE_ATM                   = 0xa8
+       DLT_JUNIPER_SERVICES                    = 0x88
+       DLT_JUNIPER_SRX_E2E                     = 0xe9
+       DLT_JUNIPER_ST                          = 0xc8
+       DLT_JUNIPER_VP                          = 0xb7
+       DLT_JUNIPER_VS                          = 0xe8
+       DLT_LAPB_WITH_DIR                       = 0xcf
+       DLT_LAPD                                = 0xcb
+       DLT_LIN                                 = 0xd4
+       DLT_LINUX_EVDEV                         = 0xd8
+       DLT_LINUX_IRDA                          = 0x90
+       DLT_LINUX_LAPD                          = 0xb1
+       DLT_LINUX_PPP_WITHDIRECTION             = 0xa6
+       DLT_LINUX_SLL                           = 0x71
+       DLT_LOOP                                = 0x6c
+       DLT_LTALK                               = 0x72
+       DLT_MATCHING_MAX                        = 0x10a
+       DLT_MATCHING_MIN                        = 0x68
+       DLT_MFR                                 = 0xb6
+       DLT_MOST                                = 0xd3
+       DLT_MPEG_2_TS                           = 0xf3
+       DLT_MPLS                                = 0xdb
+       DLT_MTP2                                = 0x8c
+       DLT_MTP2_WITH_PHDR                      = 0x8b
+       DLT_MTP3                                = 0x8d
+       DLT_MUX27010                            = 0xec
+       DLT_NETANALYZER                         = 0xf0
+       DLT_NETANALYZER_TRANSPARENT             = 0xf1
+       DLT_NFC_LLCP                            = 0xf5
+       DLT_NFLOG                               = 0xef
+       DLT_NG40                                = 0xf4
+       DLT_NULL                                = 0x0
+       DLT_PCI_EXP                             = 0x7d
+       DLT_PFLOG                               = 0x75
+       DLT_PFSYNC                              = 0x12
+       DLT_PPI                                 = 0xc0
+       DLT_PPP                                 = 0x9
+       DLT_PPP_BSDOS                           = 0x10
+       DLT_PPP_ETHER                           = 0x33
+       DLT_PPP_PPPD                            = 0xa6
+       DLT_PPP_SERIAL                          = 0x32
+       DLT_PPP_WITH_DIR                        = 0xcc
+       DLT_PPP_WITH_DIRECTION                  = 0xa6
+       DLT_PRISM_HEADER                        = 0x77
+       DLT_PRONET                              = 0x4
+       DLT_RAIF1                               = 0xc6
+       DLT_RAW                                 = 0xc
+       DLT_RIO                                 = 0x7c
+       DLT_SCCP                                = 0x8e
+       DLT_SITA                                = 0xc4
+       DLT_SLIP                                = 0x8
+       DLT_SLIP_BSDOS                          = 0xf
+       DLT_STANAG_5066_D_PDU                   = 0xed
+       DLT_SUNATM                              = 0x7b
+       DLT_SYMANTEC_FIREWALL                   = 0x63
+       DLT_TZSP                                = 0x80
+       DLT_USB                                 = 0xba
+       DLT_USB_DARWIN                          = 0x10a
+       DLT_USB_LINUX                           = 0xbd
+       DLT_USB_LINUX_MMAPPED                   = 0xdc
+       DLT_USER0                               = 0x93
+       DLT_USER1                               = 0x94
+       DLT_USER10                              = 0x9d
+       DLT_USER11                              = 0x9e
+       DLT_USER12                              = 0x9f
+       DLT_USER13                              = 0xa0
+       DLT_USER14                              = 0xa1
+       DLT_USER15                              = 0xa2
+       DLT_USER2                               = 0x95
+       DLT_USER3                               = 0x96
+       DLT_USER4                               = 0x97
+       DLT_USER5                               = 0x98
+       DLT_USER6                               = 0x99
+       DLT_USER7                               = 0x9a
+       DLT_USER8                               = 0x9b
+       DLT_USER9                               = 0x9c
+       DLT_WIHART                              = 0xdf
+       DLT_X2E_SERIAL                          = 0xd5
+       DLT_X2E_XORAYA                          = 0xd6
+       DT_BLK                                  = 0x6
+       DT_CHR                                  = 0x2
+       DT_DIR                                  = 0x4
+       DT_FIFO                                 = 0x1
+       DT_LNK                                  = 0xa
+       DT_REG                                  = 0x8
+       DT_SOCK                                 = 0xc
+       DT_UNKNOWN                              = 0x0
+       DT_WHT                                  = 0xe
+       ECHO                                    = 0x8
+       ECHOCTL                                 = 0x40
+       ECHOE                                   = 0x2
+       ECHOK                                   = 0x4
+       ECHOKE                                  = 0x1
+       ECHONL                                  = 0x10
+       ECHOPRT                                 = 0x20
+       EVFILT_AIO                              = -0x3
+       EVFILT_EXCEPT                           = -0xf
+       EVFILT_FS                               = -0x9
+       EVFILT_MACHPORT                         = -0x8
+       EVFILT_PROC                             = -0x5
+       EVFILT_READ                             = -0x1
+       EVFILT_SIGNAL                           = -0x6
+       EVFILT_SYSCOUNT                         = 0x11
+       EVFILT_THREADMARKER                     = 0x11
+       EVFILT_TIMER                            = -0x7
+       EVFILT_USER                             = -0xa
+       EVFILT_VM                               = -0xc
+       EVFILT_VNODE                            = -0x4
+       EVFILT_WRITE                            = -0x2
+       EV_ADD                                  = 0x1
+       EV_CLEAR                                = 0x20
+       EV_DELETE                               = 0x2
+       EV_DISABLE                              = 0x8
+       EV_DISPATCH                             = 0x80
+       EV_DISPATCH2                            = 0x180
+       EV_ENABLE                               = 0x4
+       EV_EOF                                  = 0x8000
+       EV_ERROR                                = 0x4000
+       EV_FLAG0                                = 0x1000
+       EV_FLAG1                                = 0x2000
+       EV_ONESHOT                              = 0x10
+       EV_OOBAND                               = 0x2000
+       EV_POLL                                 = 0x1000
+       EV_RECEIPT                              = 0x40
+       EV_SYSFLAGS                             = 0xf000
+       EV_UDATA_SPECIFIC                       = 0x100
+       EV_VANISHED                             = 0x200
+       EXTA                                    = 0x4b00
+       EXTB                                    = 0x9600
+       EXTPROC                                 = 0x800
+       FD_CLOEXEC                              = 0x1
+       FD_SETSIZE                              = 0x400
+       FF0                                     = 0x0
+       FF1                                     = 0x4000
+       FFDLY                                   = 0x4000
+       FLUSHO                                  = 0x800000
+       FSOPT_ATTR_CMN_EXTENDED                 = 0x20
+       FSOPT_NOFOLLOW                          = 0x1
+       FSOPT_NOINMEMUPDATE                     = 0x2
+       FSOPT_PACK_INVAL_ATTRS                  = 0x8
+       FSOPT_REPORT_FULLSIZE                   = 0x4
+       FSOPT_RETURN_REALDEV                    = 0x200
+       F_ADDFILESIGS                           = 0x3d
+       F_ADDFILESIGS_FOR_DYLD_SIM              = 0x53
+       F_ADDFILESIGS_INFO                      = 0x67
+       F_ADDFILESIGS_RETURN                    = 0x61
+       F_ADDFILESUPPL                          = 0x68
+       F_ADDSIGS                               = 0x3b
+       F_ALLOCATEALL                           = 0x4
+       F_ALLOCATECONTIG                        = 0x2
+       F_BARRIERFSYNC                          = 0x55
+       F_CHECK_LV                              = 0x62
+       F_CHKCLEAN                              = 0x29
+       F_DUPFD                                 = 0x0
+       F_DUPFD_CLOEXEC                         = 0x43
+       F_FINDSIGS                              = 0x4e
+       F_FLUSH_DATA                            = 0x28
+       F_FREEZE_FS                             = 0x35
+       F_FULLFSYNC                             = 0x33
+       F_GETCODEDIR                            = 0x48
+       F_GETFD                                 = 0x1
+       F_GETFL                                 = 0x3
+       F_GETLK                                 = 0x7
+       F_GETLKPID                              = 0x42
+       F_GETNOSIGPIPE                          = 0x4a
+       F_GETOWN                                = 0x5
+       F_GETPATH                               = 0x32
+       F_GETPATH_MTMINFO                       = 0x47
+       F_GETPATH_NOFIRMLINK                    = 0x66
+       F_GETPROTECTIONCLASS                    = 0x3f
+       F_GETPROTECTIONLEVEL                    = 0x4d
+       F_GETSIGSINFO                           = 0x69
+       F_GLOBAL_NOCACHE                        = 0x37
+       F_LOG2PHYS                              = 0x31
+       F_LOG2PHYS_EXT                          = 0x41
+       F_NOCACHE                               = 0x30
+       F_NODIRECT                              = 0x3e
+       F_OK                                    = 0x0
+       F_PATHPKG_CHECK                         = 0x34
+       F_PEOFPOSMODE                           = 0x3
+       F_PREALLOCATE                           = 0x2a
+       F_PUNCHHOLE                             = 0x63
+       F_RDADVISE                              = 0x2c
+       F_RDAHEAD                               = 0x2d
+       F_RDLCK                                 = 0x1
+       F_SETBACKINGSTORE                       = 0x46
+       F_SETFD                                 = 0x2
+       F_SETFL                                 = 0x4
+       F_SETLK                                 = 0x8
+       F_SETLKW                                = 0x9
+       F_SETLKWTIMEOUT                         = 0xa
+       F_SETNOSIGPIPE                          = 0x49
+       F_SETOWN                                = 0x6
+       F_SETPROTECTIONCLASS                    = 0x40
+       F_SETSIZE                               = 0x2b
+       F_SINGLE_WRITER                         = 0x4c
+       F_SPECULATIVE_READ                      = 0x65
+       F_THAW_FS                               = 0x36
+       F_TRANSCODEKEY                          = 0x4b
+       F_TRIM_ACTIVE_FILE                      = 0x64
+       F_UNLCK                                 = 0x2
+       F_VOLPOSMODE                            = 0x4
+       F_WRLCK                                 = 0x3
+       HUPCL                                   = 0x4000
+       HW_MACHINE                              = 0x1
+       ICANON                                  = 0x100
+       ICMP6_FILTER                            = 0x12
+       ICRNL                                   = 0x100
+       IEXTEN                                  = 0x400
+       IFF_ALLMULTI                            = 0x200
+       IFF_ALTPHYS                             = 0x4000
+       IFF_BROADCAST                           = 0x2
+       IFF_DEBUG                               = 0x4
+       IFF_LINK0                               = 0x1000
+       IFF_LINK1                               = 0x2000
+       IFF_LINK2                               = 0x4000
+       IFF_LOOPBACK                            = 0x8
+       IFF_MULTICAST                           = 0x8000
+       IFF_NOARP                               = 0x80
+       IFF_NOTRAILERS                          = 0x20
+       IFF_OACTIVE                             = 0x400
+       IFF_POINTOPOINT                         = 0x10
+       IFF_PROMISC                             = 0x100
+       IFF_RUNNING                             = 0x40
+       IFF_SIMPLEX                             = 0x800
+       IFF_UP                                  = 0x1
+       IFNAMSIZ                                = 0x10
+       IFT_1822                                = 0x2
+       IFT_6LOWPAN                             = 0x40
+       IFT_AAL5                                = 0x31
+       IFT_ARCNET                              = 0x23
+       IFT_ARCNETPLUS                          = 0x24
+       IFT_ATM                                 = 0x25
+       IFT_BRIDGE                              = 0xd1
+       IFT_CARP                                = 0xf8
+       IFT_CELLULAR                            = 0xff
+       IFT_CEPT                                = 0x13
+       IFT_DS3                                 = 0x1e
+       IFT_ENC                                 = 0xf4
+       IFT_EON                                 = 0x19
+       IFT_ETHER                               = 0x6
+       IFT_FAITH                               = 0x38
+       IFT_FDDI                                = 0xf
+       IFT_FRELAY                              = 0x20
+       IFT_FRELAYDCE                           = 0x2c
+       IFT_GIF                                 = 0x37
+       IFT_HDH1822                             = 0x3
+       IFT_HIPPI                               = 0x2f
+       IFT_HSSI                                = 0x2e
+       IFT_HY                                  = 0xe
+       IFT_IEEE1394                            = 0x90
+       IFT_IEEE8023ADLAG                       = 0x88
+       IFT_ISDNBASIC                           = 0x14
+       IFT_ISDNPRIMARY                         = 0x15
+       IFT_ISO88022LLC                         = 0x29
+       IFT_ISO88023                            = 0x7
+       IFT_ISO88024                            = 0x8
+       IFT_ISO88025                            = 0x9
+       IFT_ISO88026                            = 0xa
+       IFT_L2VLAN                              = 0x87
+       IFT_LAPB                                = 0x10
+       IFT_LOCALTALK                           = 0x2a
+       IFT_LOOP                                = 0x18
+       IFT_MIOX25                              = 0x26
+       IFT_MODEM                               = 0x30
+       IFT_NSIP                                = 0x1b
+       IFT_OTHER                               = 0x1
+       IFT_P10                                 = 0xc
+       IFT_P80                                 = 0xd
+       IFT_PARA                                = 0x22
+       IFT_PDP                                 = 0xff
+       IFT_PFLOG                               = 0xf5
+       IFT_PFSYNC                              = 0xf6
+       IFT_PKTAP                               = 0xfe
+       IFT_PPP                                 = 0x17
+       IFT_PROPMUX                             = 0x36
+       IFT_PROPVIRTUAL                         = 0x35
+       IFT_PTPSERIAL                           = 0x16
+       IFT_RS232                               = 0x21
+       IFT_SDLC                                = 0x11
+       IFT_SIP                                 = 0x1f
+       IFT_SLIP                                = 0x1c
+       IFT_SMDSDXI                             = 0x2b
+       IFT_SMDSICIP                            = 0x34
+       IFT_SONET                               = 0x27
+       IFT_SONETPATH                           = 0x32
+       IFT_SONETVT                             = 0x33
+       IFT_STARLAN                             = 0xb
+       IFT_STF                                 = 0x39
+       IFT_T1                                  = 0x12
+       IFT_ULTRA                               = 0x1d
+       IFT_V35                                 = 0x2d
+       IFT_X25                                 = 0x5
+       IFT_X25DDN                              = 0x4
+       IFT_X25PLE                              = 0x28
+       IFT_XETHER                              = 0x1a
+       IGNBRK                                  = 0x1
+       IGNCR                                   = 0x80
+       IGNPAR                                  = 0x4
+       IMAXBEL                                 = 0x2000
+       INLCR                                   = 0x40
+       INPCK                                   = 0x10
+       IN_CLASSA_HOST                          = 0xffffff
+       IN_CLASSA_MAX                           = 0x80
+       IN_CLASSA_NET                           = 0xff000000
+       IN_CLASSA_NSHIFT                        = 0x18
+       IN_CLASSB_HOST                          = 0xffff
+       IN_CLASSB_MAX                           = 0x10000
+       IN_CLASSB_NET                           = 0xffff0000
+       IN_CLASSB_NSHIFT                        = 0x10
+       IN_CLASSC_HOST                          = 0xff
+       IN_CLASSC_NET                           = 0xffffff00
+       IN_CLASSC_NSHIFT                        = 0x8
+       IN_CLASSD_HOST                          = 0xfffffff
+       IN_CLASSD_NET                           = 0xf0000000
+       IN_CLASSD_NSHIFT                        = 0x1c
+       IN_LINKLOCALNETNUM                      = 0xa9fe0000
+       IN_LOOPBACKNET                          = 0x7f
+       IOCTL_VM_SOCKETS_GET_LOCAL_CID          = 0x400473d1
+       IPPROTO_3PC                             = 0x22
+       IPPROTO_ADFS                            = 0x44
+       IPPROTO_AH                              = 0x33
+       IPPROTO_AHIP                            = 0x3d
+       IPPROTO_APES                            = 0x63
+       IPPROTO_ARGUS                           = 0xd
+       IPPROTO_AX25                            = 0x5d
+       IPPROTO_BHA                             = 0x31
+       IPPROTO_BLT                             = 0x1e
+       IPPROTO_BRSATMON                        = 0x4c
+       IPPROTO_CFTP                            = 0x3e
+       IPPROTO_CHAOS                           = 0x10
+       IPPROTO_CMTP                            = 0x26
+       IPPROTO_CPHB                            = 0x49
+       IPPROTO_CPNX                            = 0x48
+       IPPROTO_DDP                             = 0x25
+       IPPROTO_DGP                             = 0x56
+       IPPROTO_DIVERT                          = 0xfe
+       IPPROTO_DONE                            = 0x101
+       IPPROTO_DSTOPTS                         = 0x3c
+       IPPROTO_EGP                             = 0x8
+       IPPROTO_EMCON                           = 0xe
+       IPPROTO_ENCAP                           = 0x62
+       IPPROTO_EON                             = 0x50
+       IPPROTO_ESP                             = 0x32
+       IPPROTO_ETHERIP                         = 0x61
+       IPPROTO_FRAGMENT                        = 0x2c
+       IPPROTO_GGP                             = 0x3
+       IPPROTO_GMTP                            = 0x64
+       IPPROTO_GRE                             = 0x2f
+       IPPROTO_HELLO                           = 0x3f
+       IPPROTO_HMP                             = 0x14
+       IPPROTO_HOPOPTS                         = 0x0
+       IPPROTO_ICMP                            = 0x1
+       IPPROTO_ICMPV6                          = 0x3a
+       IPPROTO_IDP                             = 0x16
+       IPPROTO_IDPR                            = 0x23
+       IPPROTO_IDRP                            = 0x2d
+       IPPROTO_IGMP                            = 0x2
+       IPPROTO_IGP                             = 0x55
+       IPPROTO_IGRP                            = 0x58
+       IPPROTO_IL                              = 0x28
+       IPPROTO_INLSP                           = 0x34
+       IPPROTO_INP                             = 0x20
+       IPPROTO_IP                              = 0x0
+       IPPROTO_IPCOMP                          = 0x6c
+       IPPROTO_IPCV                            = 0x47
+       IPPROTO_IPEIP                           = 0x5e
+       IPPROTO_IPIP                            = 0x4
+       IPPROTO_IPPC                            = 0x43
+       IPPROTO_IPV4                            = 0x4
+       IPPROTO_IPV6                            = 0x29
+       IPPROTO_IRTP                            = 0x1c
+       IPPROTO_KRYPTOLAN                       = 0x41
+       IPPROTO_LARP                            = 0x5b
+       IPPROTO_LEAF1                           = 0x19
+       IPPROTO_LEAF2                           = 0x1a
+       IPPROTO_MAX                             = 0x100
+       IPPROTO_MAXID                           = 0x34
+       IPPROTO_MEAS                            = 0x13
+       IPPROTO_MHRP                            = 0x30
+       IPPROTO_MICP                            = 0x5f
+       IPPROTO_MTP                             = 0x5c
+       IPPROTO_MUX                             = 0x12
+       IPPROTO_ND                              = 0x4d
+       IPPROTO_NHRP                            = 0x36
+       IPPROTO_NONE                            = 0x3b
+       IPPROTO_NSP                             = 0x1f
+       IPPROTO_NVPII                           = 0xb
+       IPPROTO_OSPFIGP                         = 0x59
+       IPPROTO_PGM                             = 0x71
+       IPPROTO_PIGP                            = 0x9
+       IPPROTO_PIM                             = 0x67
+       IPPROTO_PRM                             = 0x15
+       IPPROTO_PUP                             = 0xc
+       IPPROTO_PVP                             = 0x4b
+       IPPROTO_RAW                             = 0xff
+       IPPROTO_RCCMON                          = 0xa
+       IPPROTO_RDP                             = 0x1b
+       IPPROTO_ROUTING                         = 0x2b
+       IPPROTO_RSVP                            = 0x2e
+       IPPROTO_RVD                             = 0x42
+       IPPROTO_SATEXPAK                        = 0x40
+       IPPROTO_SATMON                          = 0x45
+       IPPROTO_SCCSP                           = 0x60
+       IPPROTO_SCTP                            = 0x84
+       IPPROTO_SDRP                            = 0x2a
+       IPPROTO_SEP                             = 0x21
+       IPPROTO_SRPC                            = 0x5a
+       IPPROTO_ST                              = 0x7
+       IPPROTO_SVMTP                           = 0x52
+       IPPROTO_SWIPE                           = 0x35
+       IPPROTO_TCF                             = 0x57
+       IPPROTO_TCP                             = 0x6
+       IPPROTO_TP                              = 0x1d
+       IPPROTO_TPXX                            = 0x27
+       IPPROTO_TRUNK1                          = 0x17
+       IPPROTO_TRUNK2                          = 0x18
+       IPPROTO_TTP                             = 0x54
+       IPPROTO_UDP                             = 0x11
+       IPPROTO_VINES                           = 0x53
+       IPPROTO_VISA                            = 0x46
+       IPPROTO_VMTP                            = 0x51
+       IPPROTO_WBEXPAK                         = 0x4f
+       IPPROTO_WBMON                           = 0x4e
+       IPPROTO_WSN                             = 0x4a
+       IPPROTO_XNET                            = 0xf
+       IPPROTO_XTP                             = 0x24
+       IPV6_2292DSTOPTS                        = 0x17
+       IPV6_2292HOPLIMIT                       = 0x14
+       IPV6_2292HOPOPTS                        = 0x16
+       IPV6_2292NEXTHOP                        = 0x15
+       IPV6_2292PKTINFO                        = 0x13
+       IPV6_2292PKTOPTIONS                     = 0x19
+       IPV6_2292RTHDR                          = 0x18
+       IPV6_3542DSTOPTS                        = 0x32
+       IPV6_3542HOPLIMIT                       = 0x2f
+       IPV6_3542HOPOPTS                        = 0x31
+       IPV6_3542NEXTHOP                        = 0x30
+       IPV6_3542PKTINFO                        = 0x2e
+       IPV6_3542RTHDR                          = 0x33
+       IPV6_ADDR_MC_FLAGS_PREFIX               = 0x20
+       IPV6_ADDR_MC_FLAGS_TRANSIENT            = 0x10
+       IPV6_ADDR_MC_FLAGS_UNICAST_BASED        = 0x30
+       IPV6_AUTOFLOWLABEL                      = 0x3b
+       IPV6_BINDV6ONLY                         = 0x1b
+       IPV6_BOUND_IF                           = 0x7d
+       IPV6_CHECKSUM                           = 0x1a
+       IPV6_DEFAULT_MULTICAST_HOPS             = 0x1
+       IPV6_DEFAULT_MULTICAST_LOOP             = 0x1
+       IPV6_DEFHLIM                            = 0x40
+       IPV6_DONTFRAG                           = 0x3e
+       IPV6_DSTOPTS                            = 0x32
+       IPV6_FAITH                              = 0x1d
+       IPV6_FLOWINFO_MASK                      = 0xffffff0f
+       IPV6_FLOWLABEL_MASK                     = 0xffff0f00
+       IPV6_FLOW_ECN_MASK                      = 0x3000
+       IPV6_FRAGTTL                            = 0x3c
+       IPV6_FW_ADD                             = 0x1e
+       IPV6_FW_DEL                             = 0x1f
+       IPV6_FW_FLUSH                           = 0x20
+       IPV6_FW_GET                             = 0x22
+       IPV6_FW_ZERO                            = 0x21
+       IPV6_HLIMDEC                            = 0x1
+       IPV6_HOPLIMIT                           = 0x2f
+       IPV6_HOPOPTS                            = 0x31
+       IPV6_IPSEC_POLICY                       = 0x1c
+       IPV6_JOIN_GROUP                         = 0xc
+       IPV6_LEAVE_GROUP                        = 0xd
+       IPV6_MAXHLIM                            = 0xff
+       IPV6_MAXOPTHDR                          = 0x800
+       IPV6_MAXPACKET                          = 0xffff
+       IPV6_MAX_GROUP_SRC_FILTER               = 0x200
+       IPV6_MAX_MEMBERSHIPS                    = 0xfff
+       IPV6_MAX_SOCK_SRC_FILTER                = 0x80
+       IPV6_MIN_MEMBERSHIPS                    = 0x1f
+       IPV6_MMTU                               = 0x500
+       IPV6_MSFILTER                           = 0x4a
+       IPV6_MULTICAST_HOPS                     = 0xa
+       IPV6_MULTICAST_IF                       = 0x9
+       IPV6_MULTICAST_LOOP                     = 0xb
+       IPV6_NEXTHOP                            = 0x30
+       IPV6_PATHMTU                            = 0x2c
+       IPV6_PKTINFO                            = 0x2e
+       IPV6_PORTRANGE                          = 0xe
+       IPV6_PORTRANGE_DEFAULT                  = 0x0
+       IPV6_PORTRANGE_HIGH                     = 0x1
+       IPV6_PORTRANGE_LOW                      = 0x2
+       IPV6_PREFER_TEMPADDR                    = 0x3f
+       IPV6_RECVDSTOPTS                        = 0x28
+       IPV6_RECVHOPLIMIT                       = 0x25
+       IPV6_RECVHOPOPTS                        = 0x27
+       IPV6_RECVPATHMTU                        = 0x2b
+       IPV6_RECVPKTINFO                        = 0x3d
+       IPV6_RECVRTHDR                          = 0x26
+       IPV6_RECVTCLASS                         = 0x23
+       IPV6_RTHDR                              = 0x33
+       IPV6_RTHDRDSTOPTS                       = 0x39
+       IPV6_RTHDR_LOOSE                        = 0x0
+       IPV6_RTHDR_STRICT                       = 0x1
+       IPV6_RTHDR_TYPE_0                       = 0x0
+       IPV6_SOCKOPT_RESERVED1                  = 0x3
+       IPV6_TCLASS                             = 0x24
+       IPV6_UNICAST_HOPS                       = 0x4
+       IPV6_USE_MIN_MTU                        = 0x2a
+       IPV6_V6ONLY                             = 0x1b
+       IPV6_VERSION                            = 0x60
+       IPV6_VERSION_MASK                       = 0xf0
+       IP_ADD_MEMBERSHIP                       = 0xc
+       IP_ADD_SOURCE_MEMBERSHIP                = 0x46
+       IP_BLOCK_SOURCE                         = 0x48
+       IP_BOUND_IF                             = 0x19
+       IP_DEFAULT_MULTICAST_LOOP               = 0x1
+       IP_DEFAULT_MULTICAST_TTL                = 0x1
+       IP_DF                                   = 0x4000
+       IP_DONTFRAG                             = 0x1c
+       IP_DROP_MEMBERSHIP                      = 0xd
+       IP_DROP_SOURCE_MEMBERSHIP               = 0x47
+       IP_DUMMYNET_CONFIGURE                   = 0x3c
+       IP_DUMMYNET_DEL                         = 0x3d
+       IP_DUMMYNET_FLUSH                       = 0x3e
+       IP_DUMMYNET_GET                         = 0x40
+       IP_FAITH                                = 0x16
+       IP_FW_ADD                               = 0x28
+       IP_FW_DEL                               = 0x29
+       IP_FW_FLUSH                             = 0x2a
+       IP_FW_GET                               = 0x2c
+       IP_FW_RESETLOG                          = 0x2d
+       IP_FW_ZERO                              = 0x2b
+       IP_HDRINCL                              = 0x2
+       IP_IPSEC_POLICY                         = 0x15
+       IP_MAXPACKET                            = 0xffff
+       IP_MAX_GROUP_SRC_FILTER                 = 0x200
+       IP_MAX_MEMBERSHIPS                      = 0xfff
+       IP_MAX_SOCK_MUTE_FILTER                 = 0x80
+       IP_MAX_SOCK_SRC_FILTER                  = 0x80
+       IP_MF                                   = 0x2000
+       IP_MIN_MEMBERSHIPS                      = 0x1f
+       IP_MSFILTER                             = 0x4a
+       IP_MSS                                  = 0x240
+       IP_MULTICAST_IF                         = 0x9
+       IP_MULTICAST_IFINDEX                    = 0x42
+       IP_MULTICAST_LOOP                       = 0xb
+       IP_MULTICAST_TTL                        = 0xa
+       IP_MULTICAST_VIF                        = 0xe
+       IP_NAT__XXX                             = 0x37
+       IP_OFFMASK                              = 0x1fff
+       IP_OLD_FW_ADD                           = 0x32
+       IP_OLD_FW_DEL                           = 0x33
+       IP_OLD_FW_FLUSH                         = 0x34
+       IP_OLD_FW_GET                           = 0x36
+       IP_OLD_FW_RESETLOG                      = 0x38
+       IP_OLD_FW_ZERO                          = 0x35
+       IP_OPTIONS                              = 0x1
+       IP_PKTINFO                              = 0x1a
+       IP_PORTRANGE                            = 0x13
+       IP_PORTRANGE_DEFAULT                    = 0x0
+       IP_PORTRANGE_HIGH                       = 0x1
+       IP_PORTRANGE_LOW                        = 0x2
+       IP_RECVDSTADDR                          = 0x7
+       IP_RECVIF                               = 0x14
+       IP_RECVOPTS                             = 0x5
+       IP_RECVPKTINFO                          = 0x1a
+       IP_RECVRETOPTS                          = 0x6
+       IP_RECVTOS                              = 0x1b
+       IP_RECVTTL                              = 0x18
+       IP_RETOPTS                              = 0x8
+       IP_RF                                   = 0x8000
+       IP_RSVP_OFF                             = 0x10
+       IP_RSVP_ON                              = 0xf
+       IP_RSVP_VIF_OFF                         = 0x12
+       IP_RSVP_VIF_ON                          = 0x11
+       IP_STRIPHDR                             = 0x17
+       IP_TOS                                  = 0x3
+       IP_TRAFFIC_MGT_BACKGROUND               = 0x41
+       IP_TTL                                  = 0x4
+       IP_UNBLOCK_SOURCE                       = 0x49
+       ISIG                                    = 0x80
+       ISTRIP                                  = 0x20
+       IUTF8                                   = 0x4000
+       IXANY                                   = 0x800
+       IXOFF                                   = 0x400
+       IXON                                    = 0x200
+       KERN_HOSTNAME                           = 0xa
+       KERN_OSRELEASE                          = 0x2
+       KERN_OSTYPE                             = 0x1
+       KERN_VERSION                            = 0x4
+       LOCAL_PEERCRED                          = 0x1
+       LOCAL_PEEREPID                          = 0x3
+       LOCAL_PEEREUUID                         = 0x5
+       LOCAL_PEERPID                           = 0x2
+       LOCAL_PEERTOKEN                         = 0x6
+       LOCAL_PEERUUID                          = 0x4
+       LOCK_EX                                 = 0x2
+       LOCK_NB                                 = 0x4
+       LOCK_SH                                 = 0x1
+       LOCK_UN                                 = 0x8
+       MADV_CAN_REUSE                          = 0x9
+       MADV_DONTNEED                           = 0x4
+       MADV_FREE                               = 0x5
+       MADV_FREE_REUSABLE                      = 0x7
+       MADV_FREE_REUSE                         = 0x8
+       MADV_NORMAL                             = 0x0
+       MADV_PAGEOUT                            = 0xa
+       MADV_RANDOM                             = 0x1
+       MADV_SEQUENTIAL                         = 0x2
+       MADV_WILLNEED                           = 0x3
+       MADV_ZERO_WIRED_PAGES                   = 0x6
+       MAP_32BIT                               = 0x8000
+       MAP_ANON                                = 0x1000
+       MAP_ANONYMOUS                           = 0x1000
+       MAP_COPY                                = 0x2
+       MAP_FILE                                = 0x0
+       MAP_FIXED                               = 0x10
+       MAP_HASSEMAPHORE                        = 0x200
+       MAP_JIT                                 = 0x800
+       MAP_NOCACHE                             = 0x400
+       MAP_NOEXTEND                            = 0x100
+       MAP_NORESERVE                           = 0x40
+       MAP_PRIVATE                             = 0x2
+       MAP_RENAME                              = 0x20
+       MAP_RESERVED0080                        = 0x80
+       MAP_RESILIENT_CODESIGN                  = 0x2000
+       MAP_RESILIENT_MEDIA                     = 0x4000
+       MAP_SHARED                              = 0x1
+       MAP_TRANSLATED_ALLOW_EXECUTE            = 0x20000
+       MAP_UNIX03                              = 0x40000
+       MCAST_BLOCK_SOURCE                      = 0x54
+       MCAST_EXCLUDE                           = 0x2
+       MCAST_INCLUDE                           = 0x1
+       MCAST_JOIN_GROUP                        = 0x50
+       MCAST_JOIN_SOURCE_GROUP                 = 0x52
+       MCAST_LEAVE_GROUP                       = 0x51
+       MCAST_LEAVE_SOURCE_GROUP                = 0x53
+       MCAST_UNBLOCK_SOURCE                    = 0x55
+       MCAST_UNDEFINED                         = 0x0
+       MCL_CURRENT                             = 0x1
+       MCL_FUTURE                              = 0x2
+       MNT_ASYNC                               = 0x40
+       MNT_AUTOMOUNTED                         = 0x400000
+       MNT_CMDFLAGS                            = 0xf0000
+       MNT_CPROTECT                            = 0x80
+       MNT_DEFWRITE                            = 0x2000000
+       MNT_DONTBROWSE                          = 0x100000
+       MNT_DOVOLFS                             = 0x8000
+       MNT_DWAIT                               = 0x4
+       MNT_EXPORTED                            = 0x100
+       MNT_EXT_ROOT_DATA_VOL                   = 0x1
+       MNT_FORCE                               = 0x80000
+       MNT_IGNORE_OWNERSHIP                    = 0x200000
+       MNT_JOURNALED                           = 0x800000
+       MNT_LOCAL                               = 0x1000
+       MNT_MULTILABEL                          = 0x4000000
+       MNT_NOATIME                             = 0x10000000
+       MNT_NOBLOCK                             = 0x20000
+       MNT_NODEV                               = 0x10
+       MNT_NOEXEC                              = 0x4
+       MNT_NOSUID                              = 0x8
+       MNT_NOUSERXATTR                         = 0x1000000
+       MNT_NOWAIT                              = 0x2
+       MNT_QUARANTINE                          = 0x400
+       MNT_QUOTA                               = 0x2000
+       MNT_RDONLY                              = 0x1
+       MNT_RELOAD                              = 0x40000
+       MNT_REMOVABLE                           = 0x200
+       MNT_ROOTFS                              = 0x4000
+       MNT_SNAPSHOT                            = 0x40000000
+       MNT_STRICTATIME                         = 0x80000000
+       MNT_SYNCHRONOUS                         = 0x2
+       MNT_UNION                               = 0x20
+       MNT_UNKNOWNPERMISSIONS                  = 0x200000
+       MNT_UPDATE                              = 0x10000
+       MNT_VISFLAGMASK                         = 0xd7f0f7ff
+       MNT_WAIT                                = 0x1
+       MSG_CTRUNC                              = 0x20
+       MSG_DONTROUTE                           = 0x4
+       MSG_DONTWAIT                            = 0x80
+       MSG_EOF                                 = 0x100
+       MSG_EOR                                 = 0x8
+       MSG_FLUSH                               = 0x400
+       MSG_HAVEMORE                            = 0x2000
+       MSG_HOLD                                = 0x800
+       MSG_NEEDSA                              = 0x10000
+       MSG_NOSIGNAL                            = 0x80000
+       MSG_OOB                                 = 0x1
+       MSG_PEEK                                = 0x2
+       MSG_RCVMORE                             = 0x4000
+       MSG_SEND                                = 0x1000
+       MSG_TRUNC                               = 0x10
+       MSG_WAITALL                             = 0x40
+       MSG_WAITSTREAM                          = 0x200
+       MS_ASYNC                                = 0x1
+       MS_DEACTIVATE                           = 0x8
+       MS_INVALIDATE                           = 0x2
+       MS_KILLPAGES                            = 0x4
+       MS_SYNC                                 = 0x10
+       NAME_MAX                                = 0xff
+       NET_RT_DUMP                             = 0x1
+       NET_RT_DUMP2                            = 0x7
+       NET_RT_FLAGS                            = 0x2
+       NET_RT_FLAGS_PRIV                       = 0xa
+       NET_RT_IFLIST                           = 0x3
+       NET_RT_IFLIST2                          = 0x6
+       NET_RT_MAXID                            = 0xb
+       NET_RT_STAT                             = 0x4
+       NET_RT_TRASH                            = 0x5
+       NFDBITS                                 = 0x20
+       NL0                                     = 0x0
+       NL1                                     = 0x100
+       NL2                                     = 0x200
+       NL3                                     = 0x300
+       NLDLY                                   = 0x300
+       NOFLSH                                  = 0x80000000
+       NOKERNINFO                              = 0x2000000
+       NOTE_ABSOLUTE                           = 0x8
+       NOTE_ATTRIB                             = 0x8
+       NOTE_BACKGROUND                         = 0x40
+       NOTE_CHILD                              = 0x4
+       NOTE_CRITICAL                           = 0x20
+       NOTE_DELETE                             = 0x1
+       NOTE_EXEC                               = 0x20000000
+       NOTE_EXIT                               = 0x80000000
+       NOTE_EXITSTATUS                         = 0x4000000
+       NOTE_EXIT_CSERROR                       = 0x40000
+       NOTE_EXIT_DECRYPTFAIL                   = 0x10000
+       NOTE_EXIT_DETAIL                        = 0x2000000
+       NOTE_EXIT_DETAIL_MASK                   = 0x70000
+       NOTE_EXIT_MEMORY                        = 0x20000
+       NOTE_EXIT_REPARENTED                    = 0x80000
+       NOTE_EXTEND                             = 0x4
+       NOTE_FFAND                              = 0x40000000
+       NOTE_FFCOPY                             = 0xc0000000
+       NOTE_FFCTRLMASK                         = 0xc0000000
+       NOTE_FFLAGSMASK                         = 0xffffff
+       NOTE_FFNOP                              = 0x0
+       NOTE_FFOR                               = 0x80000000
+       NOTE_FORK                               = 0x40000000
+       NOTE_FUNLOCK                            = 0x100
+       NOTE_LEEWAY                             = 0x10
+       NOTE_LINK                               = 0x10
+       NOTE_LOWAT                              = 0x1
+       NOTE_MACHTIME                           = 0x100
+       NOTE_MACH_CONTINUOUS_TIME               = 0x80
+       NOTE_NONE                               = 0x80
+       NOTE_NSECONDS                           = 0x4
+       NOTE_OOB                                = 0x2
+       NOTE_PCTRLMASK                          = -0x100000
+       NOTE_PDATAMASK                          = 0xfffff
+       NOTE_REAP                               = 0x10000000
+       NOTE_RENAME                             = 0x20
+       NOTE_REVOKE                             = 0x40
+       NOTE_SECONDS                            = 0x1
+       NOTE_SIGNAL                             = 0x8000000
+       NOTE_TRACK                              = 0x1
+       NOTE_TRACKERR                           = 0x2
+       NOTE_TRIGGER                            = 0x1000000
+       NOTE_USECONDS                           = 0x2
+       NOTE_VM_ERROR                           = 0x10000000
+       NOTE_VM_PRESSURE                        = 0x80000000
+       NOTE_VM_PRESSURE_SUDDEN_TERMINATE       = 0x20000000
+       NOTE_VM_PRESSURE_TERMINATE              = 0x40000000
+       NOTE_WRITE                              = 0x2
+       OCRNL                                   = 0x10
+       OFDEL                                   = 0x20000
+       OFILL                                   = 0x80
+       ONLCR                                   = 0x2
+       ONLRET                                  = 0x40
+       ONOCR                                   = 0x20
+       ONOEOT                                  = 0x8
+       OPOST                                   = 0x1
+       OXTABS                                  = 0x4
+       O_ACCMODE                               = 0x3
+       O_ALERT                                 = 0x20000000
+       O_APPEND                                = 0x8
+       O_ASYNC                                 = 0x40
+       O_CLOEXEC                               = 0x1000000
+       O_CREAT                                 = 0x200
+       O_DIRECTORY                             = 0x100000
+       O_DP_GETRAWENCRYPTED                    = 0x1
+       O_DP_GETRAWUNENCRYPTED                  = 0x2
+       O_DSYNC                                 = 0x400000
+       O_EVTONLY                               = 0x8000
+       O_EXCL                                  = 0x800
+       O_EXLOCK                                = 0x20
+       O_FSYNC                                 = 0x80
+       O_NDELAY                                = 0x4
+       O_NOCTTY                                = 0x20000
+       O_NOFOLLOW                              = 0x100
+       O_NOFOLLOW_ANY                          = 0x20000000
+       O_NONBLOCK                              = 0x4
+       O_POPUP                                 = 0x80000000
+       O_RDONLY                                = 0x0
+       O_RDWR                                  = 0x2
+       O_SHLOCK                                = 0x10
+       O_SYMLINK                               = 0x200000
+       O_SYNC                                  = 0x80
+       O_TRUNC                                 = 0x400
+       O_WRONLY                                = 0x1
+       PARENB                                  = 0x1000
+       PARMRK                                  = 0x8
+       PARODD                                  = 0x2000
+       PENDIN                                  = 0x20000000
+       PRIO_PGRP                               = 0x1
+       PRIO_PROCESS                            = 0x0
+       PRIO_USER                               = 0x2
+       PROT_EXEC                               = 0x4
+       PROT_NONE                               = 0x0
+       PROT_READ                               = 0x1
+       PROT_WRITE                              = 0x2
+       PT_ATTACH                               = 0xa
+       PT_ATTACHEXC                            = 0xe
+       PT_CONTINUE                             = 0x7
+       PT_DENY_ATTACH                          = 0x1f
+       PT_DETACH                               = 0xb
+       PT_FIRSTMACH                            = 0x20
+       PT_FORCEQUOTA                           = 0x1e
+       PT_KILL                                 = 0x8
+       PT_READ_D                               = 0x2
+       PT_READ_I                               = 0x1
+       PT_READ_U                               = 0x3
+       PT_SIGEXC                               = 0xc
+       PT_STEP                                 = 0x9
+       PT_THUPDATE                             = 0xd
+       PT_TRACE_ME                             = 0x0
+       PT_WRITE_D                              = 0x5
+       PT_WRITE_I                              = 0x4
+       PT_WRITE_U                              = 0x6
+       RLIMIT_AS                               = 0x5
+       RLIMIT_CORE                             = 0x4
+       RLIMIT_CPU                              = 0x0
+       RLIMIT_CPU_USAGE_MONITOR                = 0x2
+       RLIMIT_DATA                             = 0x2
+       RLIMIT_FSIZE                            = 0x1
+       RLIMIT_MEMLOCK                          = 0x6
+       RLIMIT_NOFILE                           = 0x8
+       RLIMIT_NPROC                            = 0x7
+       RLIMIT_RSS                              = 0x5
+       RLIMIT_STACK                            = 0x3
+       RLIM_INFINITY                           = 0x7fffffffffffffff
+       RTAX_AUTHOR                             = 0x6
+       RTAX_BRD                                = 0x7
+       RTAX_DST                                = 0x0
+       RTAX_GATEWAY                            = 0x1
+       RTAX_GENMASK                            = 0x3
+       RTAX_IFA                                = 0x5
+       RTAX_IFP                                = 0x4
+       RTAX_MAX                                = 0x8
+       RTAX_NETMASK                            = 0x2
+       RTA_AUTHOR                              = 0x40
+       RTA_BRD                                 = 0x80
+       RTA_DST                                 = 0x1
+       RTA_GATEWAY                             = 0x2
+       RTA_GENMASK                             = 0x8
+       RTA_IFA                                 = 0x20
+       RTA_IFP                                 = 0x10
+       RTA_NETMASK                             = 0x4
+       RTF_BLACKHOLE                           = 0x1000
+       RTF_BROADCAST                           = 0x400000
+       RTF_CLONING                             = 0x100
+       RTF_CONDEMNED                           = 0x2000000
+       RTF_DEAD                                = 0x20000000
+       RTF_DELCLONE                            = 0x80
+       RTF_DONE                                = 0x40
+       RTF_DYNAMIC                             = 0x10
+       RTF_GATEWAY                             = 0x2
+       RTF_GLOBAL                              = 0x40000000
+       RTF_HOST                                = 0x4
+       RTF_IFREF                               = 0x4000000
+       RTF_IFSCOPE                             = 0x1000000
+       RTF_LLDATA                              = 0x400
+       RTF_LLINFO                              = 0x400
+       RTF_LOCAL                               = 0x200000
+       RTF_MODIFIED                            = 0x20
+       RTF_MULTICAST                           = 0x800000
+       RTF_NOIFREF                             = 0x2000
+       RTF_PINNED                              = 0x100000
+       RTF_PRCLONING                           = 0x10000
+       RTF_PROTO1                              = 0x8000
+       RTF_PROTO2                              = 0x4000
+       RTF_PROTO3                              = 0x40000
+       RTF_PROXY                               = 0x8000000
+       RTF_REJECT                              = 0x8
+       RTF_ROUTER                              = 0x10000000
+       RTF_STATIC                              = 0x800
+       RTF_UP                                  = 0x1
+       RTF_WASCLONED                           = 0x20000
+       RTF_XRESOLVE                            = 0x200
+       RTM_ADD                                 = 0x1
+       RTM_CHANGE                              = 0x3
+       RTM_DELADDR                             = 0xd
+       RTM_DELETE                              = 0x2
+       RTM_DELMADDR                            = 0x10
+       RTM_GET                                 = 0x4
+       RTM_GET2                                = 0x14
+       RTM_IFINFO                              = 0xe
+       RTM_IFINFO2                             = 0x12
+       RTM_LOCK                                = 0x8
+       RTM_LOSING                              = 0x5
+       RTM_MISS                                = 0x7
+       RTM_NEWADDR                             = 0xc
+       RTM_NEWMADDR                            = 0xf
+       RTM_NEWMADDR2                           = 0x13
+       RTM_OLDADD                              = 0x9
+       RTM_OLDDEL                              = 0xa
+       RTM_REDIRECT                            = 0x6
+       RTM_RESOLVE                             = 0xb
+       RTM_RTTUNIT                             = 0xf4240
+       RTM_VERSION                             = 0x5
+       RTV_EXPIRE                              = 0x4
+       RTV_HOPCOUNT                            = 0x2
+       RTV_MTU                                 = 0x1
+       RTV_RPIPE                               = 0x8
+       RTV_RTT                                 = 0x40
+       RTV_RTTVAR                              = 0x80
+       RTV_SPIPE                               = 0x10
+       RTV_SSTHRESH                            = 0x20
+       RUSAGE_CHILDREN                         = -0x1
+       RUSAGE_SELF                             = 0x0
+       SCM_CREDS                               = 0x3
+       SCM_RIGHTS                              = 0x1
+       SCM_TIMESTAMP                           = 0x2
+       SCM_TIMESTAMP_MONOTONIC                 = 0x4
+       SEEK_CUR                                = 0x1
+       SEEK_DATA                               = 0x4
+       SEEK_END                                = 0x2
+       SEEK_HOLE                               = 0x3
+       SEEK_SET                                = 0x0
+       SHUT_RD                                 = 0x0
+       SHUT_RDWR                               = 0x2
+       SHUT_WR                                 = 0x1
+       SIOCADDMULTI                            = 0x80206931
+       SIOCAIFADDR                             = 0x8040691a
+       SIOCARPIPLL                             = 0xc0206928
+       SIOCATMARK                              = 0x40047307
+       SIOCAUTOADDR                            = 0xc0206926
+       SIOCAUTONETMASK                         = 0x80206927
+       SIOCDELMULTI                            = 0x80206932
+       SIOCDIFADDR                             = 0x80206919
+       SIOCDIFPHYADDR                          = 0x80206941
+       SIOCGDRVSPEC                            = 0xc028697b
+       SIOCGETVLAN                             = 0xc020697f
+       SIOCGHIWAT                              = 0x40047301
+       SIOCGIF6LOWPAN                          = 0xc02069c5
+       SIOCGIFADDR                             = 0xc0206921
+       SIOCGIFALTMTU                           = 0xc0206948
+       SIOCGIFASYNCMAP                         = 0xc020697c
+       SIOCGIFBOND                             = 0xc0206947
+       SIOCGIFBRDADDR                          = 0xc0206923
+       SIOCGIFCAP                              = 0xc020695b
+       SIOCGIFCONF                             = 0xc00c6924
+       SIOCGIFDEVMTU                           = 0xc0206944
+       SIOCGIFDSTADDR                          = 0xc0206922
+       SIOCGIFFLAGS                            = 0xc0206911
+       SIOCGIFFUNCTIONALTYPE                   = 0xc02069ad
+       SIOCGIFGENERIC                          = 0xc020693a
+       SIOCGIFKPI                              = 0xc0206987
+       SIOCGIFMAC                              = 0xc0206982
+       SIOCGIFMEDIA                            = 0xc02c6938
+       SIOCGIFMETRIC                           = 0xc0206917
+       SIOCGIFMTU                              = 0xc0206933
+       SIOCGIFNETMASK                          = 0xc0206925
+       SIOCGIFPDSTADDR                         = 0xc0206940
+       SIOCGIFPHYS                             = 0xc0206935
+       SIOCGIFPSRCADDR                         = 0xc020693f
+       SIOCGIFSTATUS                           = 0xc331693d
+       SIOCGIFVLAN                             = 0xc020697f
+       SIOCGIFWAKEFLAGS                        = 0xc0206988
+       SIOCGIFXMEDIA                           = 0xc02c6948
+       SIOCGLOWAT                              = 0x40047303
+       SIOCGPGRP                               = 0x40047309
+       SIOCIFCREATE                            = 0xc0206978
+       SIOCIFCREATE2                           = 0xc020697a
+       SIOCIFDESTROY                           = 0x80206979
+       SIOCIFGCLONERS                          = 0xc0106981
+       SIOCRSLVMULTI                           = 0xc010693b
+       SIOCSDRVSPEC                            = 0x8028697b
+       SIOCSETVLAN                             = 0x8020697e
+       SIOCSHIWAT                              = 0x80047300
+       SIOCSIF6LOWPAN                          = 0x802069c4
+       SIOCSIFADDR                             = 0x8020690c
+       SIOCSIFALTMTU                           = 0x80206945
+       SIOCSIFASYNCMAP                         = 0x8020697d
+       SIOCSIFBOND                             = 0x80206946
+       SIOCSIFBRDADDR                          = 0x80206913
+       SIOCSIFCAP                              = 0x8020695a
+       SIOCSIFDSTADDR                          = 0x8020690e
+       SIOCSIFFLAGS                            = 0x80206910
+       SIOCSIFGENERIC                          = 0x80206939
+       SIOCSIFKPI                              = 0x80206986
+       SIOCSIFLLADDR                           = 0x8020693c
+       SIOCSIFMAC                              = 0x80206983
+       SIOCSIFMEDIA                            = 0xc0206937
+       SIOCSIFMETRIC                           = 0x80206918
+       SIOCSIFMTU                              = 0x80206934
+       SIOCSIFNETMASK                          = 0x80206916
+       SIOCSIFPHYADDR                          = 0x8040693e
+       SIOCSIFPHYS                             = 0x80206936
+       SIOCSIFVLAN                             = 0x8020697e
+       SIOCSLOWAT                              = 0x80047302
+       SIOCSPGRP                               = 0x80047308
+       SOCK_DGRAM                              = 0x2
+       SOCK_MAXADDRLEN                         = 0xff
+       SOCK_RAW                                = 0x3
+       SOCK_RDM                                = 0x4
+       SOCK_SEQPACKET                          = 0x5
+       SOCK_STREAM                             = 0x1
+       SOL_LOCAL                               = 0x0
+       SOL_SOCKET                              = 0xffff
+       SOMAXCONN                               = 0x80
+       SO_ACCEPTCONN                           = 0x2
+       SO_BROADCAST                            = 0x20
+       SO_DEBUG                                = 0x1
+       SO_DONTROUTE                            = 0x10
+       SO_DONTTRUNC                            = 0x2000
+       SO_ERROR                                = 0x1007
+       SO_KEEPALIVE                            = 0x8
+       SO_LABEL                                = 0x1010
+       SO_LINGER                               = 0x80
+       SO_LINGER_SEC                           = 0x1080
+       SO_NETSVC_MARKING_LEVEL                 = 0x1119
+       SO_NET_SERVICE_TYPE                     = 0x1116
+       SO_NKE                                  = 0x1021
+       SO_NOADDRERR                            = 0x1023
+       SO_NOSIGPIPE                            = 0x1022
+       SO_NOTIFYCONFLICT                       = 0x1026
+       SO_NP_EXTENSIONS                        = 0x1083
+       SO_NREAD                                = 0x1020
+       SO_NUMRCVPKT                            = 0x1112
+       SO_NWRITE                               = 0x1024
+       SO_OOBINLINE                            = 0x100
+       SO_PEERLABEL                            = 0x1011
+       SO_RANDOMPORT                           = 0x1082
+       SO_RCVBUF                               = 0x1002
+       SO_RCVLOWAT                             = 0x1004
+       SO_RCVTIMEO                             = 0x1006
+       SO_REUSEADDR                            = 0x4
+       SO_REUSEPORT                            = 0x200
+       SO_REUSESHAREUID                        = 0x1025
+       SO_SNDBUF                               = 0x1001
+       SO_SNDLOWAT                             = 0x1003
+       SO_SNDTIMEO                             = 0x1005
+       SO_TIMESTAMP                            = 0x400
+       SO_TIMESTAMP_MONOTONIC                  = 0x800
+       SO_TRACKER_ATTRIBUTE_FLAGS_APP_APPROVED = 0x1
+       SO_TRACKER_ATTRIBUTE_FLAGS_DOMAIN_SHORT = 0x4
+       SO_TRACKER_ATTRIBUTE_FLAGS_TRACKER      = 0x2
+       SO_TRACKER_TRANSPARENCY_VERSION         = 0x3
+       SO_TYPE                                 = 0x1008
+       SO_UPCALLCLOSEWAIT                      = 0x1027
+       SO_USELOOPBACK                          = 0x40
+       SO_WANTMORE                             = 0x4000
+       SO_WANTOOBFLAG                          = 0x8000
+       S_IEXEC                                 = 0x40
+       S_IFBLK                                 = 0x6000
+       S_IFCHR                                 = 0x2000
+       S_IFDIR                                 = 0x4000
+       S_IFIFO                                 = 0x1000
+       S_IFLNK                                 = 0xa000
+       S_IFMT                                  = 0xf000
+       S_IFREG                                 = 0x8000
+       S_IFSOCK                                = 0xc000
+       S_IFWHT                                 = 0xe000
+       S_IREAD                                 = 0x100
+       S_IRGRP                                 = 0x20
+       S_IROTH                                 = 0x4
+       S_IRUSR                                 = 0x100
+       S_IRWXG                                 = 0x38
+       S_IRWXO                                 = 0x7
+       S_IRWXU                                 = 0x1c0
+       S_ISGID                                 = 0x400
+       S_ISTXT                                 = 0x200
+       S_ISUID                                 = 0x800
+       S_ISVTX                                 = 0x200
+       S_IWGRP                                 = 0x10
+       S_IWOTH                                 = 0x2
+       S_IWRITE                                = 0x80
+       S_IWUSR                                 = 0x80
+       S_IXGRP                                 = 0x8
+       S_IXOTH                                 = 0x1
+       S_IXUSR                                 = 0x40
+       TAB0                                    = 0x0
+       TAB1                                    = 0x400
+       TAB2                                    = 0x800
+       TAB3                                    = 0x4
+       TABDLY                                  = 0xc04
+       TCIFLUSH                                = 0x1
+       TCIOFF                                  = 0x3
+       TCIOFLUSH                               = 0x3
+       TCION                                   = 0x4
+       TCOFLUSH                                = 0x2
+       TCOOFF                                  = 0x1
+       TCOON                                   = 0x2
+       TCPOPT_CC                               = 0xb
+       TCPOPT_CCECHO                           = 0xd
+       TCPOPT_CCNEW                            = 0xc
+       TCPOPT_EOL                              = 0x0
+       TCPOPT_FASTOPEN                         = 0x22
+       TCPOPT_MAXSEG                           = 0x2
+       TCPOPT_NOP                              = 0x1
+       TCPOPT_SACK                             = 0x5
+       TCPOPT_SACK_HDR                         = 0x1010500
+       TCPOPT_SACK_PERMITTED                   = 0x4
+       TCPOPT_SACK_PERMIT_HDR                  = 0x1010402
+       TCPOPT_SIGNATURE                        = 0x13
+       TCPOPT_TIMESTAMP                        = 0x8
+       TCPOPT_TSTAMP_HDR                       = 0x101080a
+       TCPOPT_WINDOW                           = 0x3
+       TCP_CONNECTIONTIMEOUT                   = 0x20
+       TCP_CONNECTION_INFO                     = 0x106
+       TCP_ENABLE_ECN                          = 0x104
+       TCP_FASTOPEN                            = 0x105
+       TCP_KEEPALIVE                           = 0x10
+       TCP_KEEPCNT                             = 0x102
+       TCP_KEEPINTVL                           = 0x101
+       TCP_MAXHLEN                             = 0x3c
+       TCP_MAXOLEN                             = 0x28
+       TCP_MAXSEG                              = 0x2
+       TCP_MAXWIN                              = 0xffff
+       TCP_MAX_SACK                            = 0x4
+       TCP_MAX_WINSHIFT                        = 0xe
+       TCP_MINMSS                              = 0xd8
+       TCP_MSS                                 = 0x200
+       TCP_NODELAY                             = 0x1
+       TCP_NOOPT                               = 0x8
+       TCP_NOPUSH                              = 0x4
+       TCP_NOTSENT_LOWAT                       = 0x201
+       TCP_RXT_CONNDROPTIME                    = 0x80
+       TCP_RXT_FINDROP                         = 0x100
+       TCP_SENDMOREACKS                        = 0x103
+       TCSAFLUSH                               = 0x2
+       TIOCCBRK                                = 0x2000747a
+       TIOCCDTR                                = 0x20007478
+       TIOCCONS                                = 0x80047462
+       TIOCDCDTIMESTAMP                        = 0x40107458
+       TIOCDRAIN                               = 0x2000745e
+       TIOCDSIMICROCODE                        = 0x20007455
+       TIOCEXCL                                = 0x2000740d
+       TIOCEXT                                 = 0x80047460
+       TIOCFLUSH                               = 0x80047410
+       TIOCGDRAINWAIT                          = 0x40047456
+       TIOCGETA                                = 0x40487413
+       TIOCGETD                                = 0x4004741a
+       TIOCGPGRP                               = 0x40047477
+       TIOCGWINSZ                              = 0x40087468
+       TIOCIXOFF                               = 0x20007480
+       TIOCIXON                                = 0x20007481
+       TIOCMBIC                                = 0x8004746b
+       TIOCMBIS                                = 0x8004746c
+       TIOCMGDTRWAIT                           = 0x4004745a
+       TIOCMGET                                = 0x4004746a
+       TIOCMODG                                = 0x40047403
+       TIOCMODS                                = 0x80047404
+       TIOCMSDTRWAIT                           = 0x8004745b
+       TIOCMSET                                = 0x8004746d
+       TIOCM_CAR                               = 0x40
+       TIOCM_CD                                = 0x40
+       TIOCM_CTS                               = 0x20
+       TIOCM_DSR                               = 0x100
+       TIOCM_DTR                               = 0x2
+       TIOCM_LE                                = 0x1
+       TIOCM_RI                                = 0x80
+       TIOCM_RNG                               = 0x80
+       TIOCM_RTS                               = 0x4
+       TIOCM_SR                                = 0x10
+       TIOCM_ST                                = 0x8
+       TIOCNOTTY                               = 0x20007471
+       TIOCNXCL                                = 0x2000740e
+       TIOCOUTQ                                = 0x40047473
+       TIOCPKT                                 = 0x80047470
+       TIOCPKT_DATA                            = 0x0
+       TIOCPKT_DOSTOP                          = 0x20
+       TIOCPKT_FLUSHREAD                       = 0x1
+       TIOCPKT_FLUSHWRITE                      = 0x2
+       TIOCPKT_IOCTL                           = 0x40
+       TIOCPKT_NOSTOP                          = 0x10
+       TIOCPKT_START                           = 0x8
+       TIOCPKT_STOP                            = 0x4
+       TIOCPTYGNAME                            = 0x40807453
+       TIOCPTYGRANT                            = 0x20007454
+       TIOCPTYUNLK                             = 0x20007452
+       TIOCREMOTE                              = 0x80047469
+       TIOCSBRK                                = 0x2000747b
+       TIOCSCONS                               = 0x20007463
+       TIOCSCTTY                               = 0x20007461
+       TIOCSDRAINWAIT                          = 0x80047457
+       TIOCSDTR                                = 0x20007479
+       TIOCSETA                                = 0x80487414
+       TIOCSETAF                               = 0x80487416
+       TIOCSETAW                               = 0x80487415
+       TIOCSETD                                = 0x8004741b
+       TIOCSIG                                 = 0x2000745f
+       TIOCSPGRP                               = 0x80047476
+       TIOCSTART                               = 0x2000746e
+       TIOCSTAT                                = 0x20007465
+       TIOCSTI                                 = 0x80017472
+       TIOCSTOP                                = 0x2000746f
+       TIOCSWINSZ                              = 0x80087467
+       TIOCTIMESTAMP                           = 0x40107459
+       TIOCUCNTL                               = 0x80047466
+       TOSTOP                                  = 0x400000
+       VDISCARD                                = 0xf
+       VDSUSP                                  = 0xb
+       VEOF                                    = 0x0
+       VEOL                                    = 0x1
+       VEOL2                                   = 0x2
+       VERASE                                  = 0x3
+       VINTR                                   = 0x8
+       VKILL                                   = 0x5
+       VLNEXT                                  = 0xe
+       VMADDR_CID_ANY                          = 0xffffffff
+       VMADDR_CID_HOST                         = 0x2
+       VMADDR_CID_HYPERVISOR                   = 0x0
+       VMADDR_CID_RESERVED                     = 0x1
+       VMADDR_PORT_ANY                         = 0xffffffff
+       VMIN                                    = 0x10
+       VM_LOADAVG                              = 0x2
+       VM_MACHFACTOR                           = 0x4
+       VM_MAXID                                = 0x6
+       VM_METER                                = 0x1
+       VM_SWAPUSAGE                            = 0x5
+       VQUIT                                   = 0x9
+       VREPRINT                                = 0x6
+       VSTART                                  = 0xc
+       VSTATUS                                 = 0x12
+       VSTOP                                   = 0xd
+       VSUSP                                   = 0xa
+       VT0                                     = 0x0
+       VT1                                     = 0x10000
+       VTDLY                                   = 0x10000
+       VTIME                                   = 0x11
+       VWERASE                                 = 0x4
+       WCONTINUED                              = 0x10
+       WCOREFLAG                               = 0x80
+       WEXITED                                 = 0x4
+       WNOHANG                                 = 0x1
+       WNOWAIT                                 = 0x20
+       WORDSIZE                                = 0x40
+       WSTOPPED                                = 0x8
+       WUNTRACED                               = 0x2
+       XATTR_CREATE                            = 0x2
+       XATTR_NODEFAULT                         = 0x10
+       XATTR_NOFOLLOW                          = 0x1
+       XATTR_NOSECURITY                        = 0x8
+       XATTR_REPLACE                           = 0x4
+       XATTR_SHOWCOMPRESSION                   = 0x20
 )
 
 // Errors
index e644eaf5e757e0f7856c722151b76acb03783071..e36f5178d60089f88323a37a6e73d3e26593daf9 100644 (file)
@@ -12,1550 +12,1582 @@ package unix
 import "syscall"
 
 const (
-       AF_APPLETALK                      = 0x10
-       AF_CCITT                          = 0xa
-       AF_CHAOS                          = 0x5
-       AF_CNT                            = 0x15
-       AF_COIP                           = 0x14
-       AF_DATAKIT                        = 0x9
-       AF_DECnet                         = 0xc
-       AF_DLI                            = 0xd
-       AF_E164                           = 0x1c
-       AF_ECMA                           = 0x8
-       AF_HYLINK                         = 0xf
-       AF_IEEE80211                      = 0x25
-       AF_IMPLINK                        = 0x3
-       AF_INET                           = 0x2
-       AF_INET6                          = 0x1e
-       AF_IPX                            = 0x17
-       AF_ISDN                           = 0x1c
-       AF_ISO                            = 0x7
-       AF_LAT                            = 0xe
-       AF_LINK                           = 0x12
-       AF_LOCAL                          = 0x1
-       AF_MAX                            = 0x29
-       AF_NATM                           = 0x1f
-       AF_NDRV                           = 0x1b
-       AF_NETBIOS                        = 0x21
-       AF_NS                             = 0x6
-       AF_OSI                            = 0x7
-       AF_PPP                            = 0x22
-       AF_PUP                            = 0x4
-       AF_RESERVED_36                    = 0x24
-       AF_ROUTE                          = 0x11
-       AF_SIP                            = 0x18
-       AF_SNA                            = 0xb
-       AF_SYSTEM                         = 0x20
-       AF_SYS_CONTROL                    = 0x2
-       AF_UNIX                           = 0x1
-       AF_UNSPEC                         = 0x0
-       AF_UTUN                           = 0x26
-       AF_VSOCK                          = 0x28
-       ALTWERASE                         = 0x200
-       ATTR_BIT_MAP_COUNT                = 0x5
-       ATTR_CMN_ACCESSMASK               = 0x20000
-       ATTR_CMN_ACCTIME                  = 0x1000
-       ATTR_CMN_ADDEDTIME                = 0x10000000
-       ATTR_CMN_BKUPTIME                 = 0x2000
-       ATTR_CMN_CHGTIME                  = 0x800
-       ATTR_CMN_CRTIME                   = 0x200
-       ATTR_CMN_DATA_PROTECT_FLAGS       = 0x40000000
-       ATTR_CMN_DEVID                    = 0x2
-       ATTR_CMN_DOCUMENT_ID              = 0x100000
-       ATTR_CMN_ERROR                    = 0x20000000
-       ATTR_CMN_EXTENDED_SECURITY        = 0x400000
-       ATTR_CMN_FILEID                   = 0x2000000
-       ATTR_CMN_FLAGS                    = 0x40000
-       ATTR_CMN_FNDRINFO                 = 0x4000
-       ATTR_CMN_FSID                     = 0x4
-       ATTR_CMN_FULLPATH                 = 0x8000000
-       ATTR_CMN_GEN_COUNT                = 0x80000
-       ATTR_CMN_GRPID                    = 0x10000
-       ATTR_CMN_GRPUUID                  = 0x1000000
-       ATTR_CMN_MODTIME                  = 0x400
-       ATTR_CMN_NAME                     = 0x1
-       ATTR_CMN_NAMEDATTRCOUNT           = 0x80000
-       ATTR_CMN_NAMEDATTRLIST            = 0x100000
-       ATTR_CMN_OBJID                    = 0x20
-       ATTR_CMN_OBJPERMANENTID           = 0x40
-       ATTR_CMN_OBJTAG                   = 0x10
-       ATTR_CMN_OBJTYPE                  = 0x8
-       ATTR_CMN_OWNERID                  = 0x8000
-       ATTR_CMN_PARENTID                 = 0x4000000
-       ATTR_CMN_PAROBJID                 = 0x80
-       ATTR_CMN_RETURNED_ATTRS           = 0x80000000
-       ATTR_CMN_SCRIPT                   = 0x100
-       ATTR_CMN_SETMASK                  = 0x51c7ff00
-       ATTR_CMN_USERACCESS               = 0x200000
-       ATTR_CMN_UUID                     = 0x800000
-       ATTR_CMN_VALIDMASK                = 0xffffffff
-       ATTR_CMN_VOLSETMASK               = 0x6700
-       ATTR_FILE_ALLOCSIZE               = 0x4
-       ATTR_FILE_CLUMPSIZE               = 0x10
-       ATTR_FILE_DATAALLOCSIZE           = 0x400
-       ATTR_FILE_DATAEXTENTS             = 0x800
-       ATTR_FILE_DATALENGTH              = 0x200
-       ATTR_FILE_DEVTYPE                 = 0x20
-       ATTR_FILE_FILETYPE                = 0x40
-       ATTR_FILE_FORKCOUNT               = 0x80
-       ATTR_FILE_FORKLIST                = 0x100
-       ATTR_FILE_IOBLOCKSIZE             = 0x8
-       ATTR_FILE_LINKCOUNT               = 0x1
-       ATTR_FILE_RSRCALLOCSIZE           = 0x2000
-       ATTR_FILE_RSRCEXTENTS             = 0x4000
-       ATTR_FILE_RSRCLENGTH              = 0x1000
-       ATTR_FILE_SETMASK                 = 0x20
-       ATTR_FILE_TOTALSIZE               = 0x2
-       ATTR_FILE_VALIDMASK               = 0x37ff
-       ATTR_VOL_ALLOCATIONCLUMP          = 0x40
-       ATTR_VOL_ATTRIBUTES               = 0x40000000
-       ATTR_VOL_CAPABILITIES             = 0x20000
-       ATTR_VOL_DIRCOUNT                 = 0x400
-       ATTR_VOL_ENCODINGSUSED            = 0x10000
-       ATTR_VOL_FILECOUNT                = 0x200
-       ATTR_VOL_FSTYPE                   = 0x1
-       ATTR_VOL_INFO                     = 0x80000000
-       ATTR_VOL_IOBLOCKSIZE              = 0x80
-       ATTR_VOL_MAXOBJCOUNT              = 0x800
-       ATTR_VOL_MINALLOCATION            = 0x20
-       ATTR_VOL_MOUNTEDDEVICE            = 0x8000
-       ATTR_VOL_MOUNTFLAGS               = 0x4000
-       ATTR_VOL_MOUNTPOINT               = 0x1000
-       ATTR_VOL_NAME                     = 0x2000
-       ATTR_VOL_OBJCOUNT                 = 0x100
-       ATTR_VOL_QUOTA_SIZE               = 0x10000000
-       ATTR_VOL_RESERVED_SIZE            = 0x20000000
-       ATTR_VOL_SETMASK                  = 0x80002000
-       ATTR_VOL_SIGNATURE                = 0x2
-       ATTR_VOL_SIZE                     = 0x4
-       ATTR_VOL_SPACEAVAIL               = 0x10
-       ATTR_VOL_SPACEFREE                = 0x8
-       ATTR_VOL_UUID                     = 0x40000
-       ATTR_VOL_VALIDMASK                = 0xf007ffff
-       B0                                = 0x0
-       B110                              = 0x6e
-       B115200                           = 0x1c200
-       B1200                             = 0x4b0
-       B134                              = 0x86
-       B14400                            = 0x3840
-       B150                              = 0x96
-       B1800                             = 0x708
-       B19200                            = 0x4b00
-       B200                              = 0xc8
-       B230400                           = 0x38400
-       B2400                             = 0x960
-       B28800                            = 0x7080
-       B300                              = 0x12c
-       B38400                            = 0x9600
-       B4800                             = 0x12c0
-       B50                               = 0x32
-       B57600                            = 0xe100
-       B600                              = 0x258
-       B7200                             = 0x1c20
-       B75                               = 0x4b
-       B76800                            = 0x12c00
-       B9600                             = 0x2580
-       BIOCFLUSH                         = 0x20004268
-       BIOCGBLEN                         = 0x40044266
-       BIOCGDLT                          = 0x4004426a
-       BIOCGDLTLIST                      = 0xc00c4279
-       BIOCGETIF                         = 0x4020426b
-       BIOCGHDRCMPLT                     = 0x40044274
-       BIOCGRSIG                         = 0x40044272
-       BIOCGRTIMEOUT                     = 0x4010426e
-       BIOCGSEESENT                      = 0x40044276
-       BIOCGSTATS                        = 0x4008426f
-       BIOCIMMEDIATE                     = 0x80044270
-       BIOCPROMISC                       = 0x20004269
-       BIOCSBLEN                         = 0xc0044266
-       BIOCSDLT                          = 0x80044278
-       BIOCSETF                          = 0x80104267
-       BIOCSETFNR                        = 0x8010427e
-       BIOCSETIF                         = 0x8020426c
-       BIOCSHDRCMPLT                     = 0x80044275
-       BIOCSRSIG                         = 0x80044273
-       BIOCSRTIMEOUT                     = 0x8010426d
-       BIOCSSEESENT                      = 0x80044277
-       BIOCVERSION                       = 0x40044271
-       BPF_A                             = 0x10
-       BPF_ABS                           = 0x20
-       BPF_ADD                           = 0x0
-       BPF_ALIGNMENT                     = 0x4
-       BPF_ALU                           = 0x4
-       BPF_AND                           = 0x50
-       BPF_B                             = 0x10
-       BPF_DIV                           = 0x30
-       BPF_H                             = 0x8
-       BPF_IMM                           = 0x0
-       BPF_IND                           = 0x40
-       BPF_JA                            = 0x0
-       BPF_JEQ                           = 0x10
-       BPF_JGE                           = 0x30
-       BPF_JGT                           = 0x20
-       BPF_JMP                           = 0x5
-       BPF_JSET                          = 0x40
-       BPF_K                             = 0x0
-       BPF_LD                            = 0x0
-       BPF_LDX                           = 0x1
-       BPF_LEN                           = 0x80
-       BPF_LSH                           = 0x60
-       BPF_MAJOR_VERSION                 = 0x1
-       BPF_MAXBUFSIZE                    = 0x80000
-       BPF_MAXINSNS                      = 0x200
-       BPF_MEM                           = 0x60
-       BPF_MEMWORDS                      = 0x10
-       BPF_MINBUFSIZE                    = 0x20
-       BPF_MINOR_VERSION                 = 0x1
-       BPF_MISC                          = 0x7
-       BPF_MSH                           = 0xa0
-       BPF_MUL                           = 0x20
-       BPF_NEG                           = 0x80
-       BPF_OR                            = 0x40
-       BPF_RELEASE                       = 0x30bb6
-       BPF_RET                           = 0x6
-       BPF_RSH                           = 0x70
-       BPF_ST                            = 0x2
-       BPF_STX                           = 0x3
-       BPF_SUB                           = 0x10
-       BPF_TAX                           = 0x0
-       BPF_TXA                           = 0x80
-       BPF_W                             = 0x0
-       BPF_X                             = 0x8
-       BRKINT                            = 0x2
-       BS0                               = 0x0
-       BS1                               = 0x8000
-       BSDLY                             = 0x8000
-       CFLUSH                            = 0xf
-       CLOCAL                            = 0x8000
-       CLOCK_MONOTONIC                   = 0x6
-       CLOCK_MONOTONIC_RAW               = 0x4
-       CLOCK_MONOTONIC_RAW_APPROX        = 0x5
-       CLOCK_PROCESS_CPUTIME_ID          = 0xc
-       CLOCK_REALTIME                    = 0x0
-       CLOCK_THREAD_CPUTIME_ID           = 0x10
-       CLOCK_UPTIME_RAW                  = 0x8
-       CLOCK_UPTIME_RAW_APPROX           = 0x9
-       CLONE_NOFOLLOW                    = 0x1
-       CLONE_NOOWNERCOPY                 = 0x2
-       CR0                               = 0x0
-       CR1                               = 0x1000
-       CR2                               = 0x2000
-       CR3                               = 0x3000
-       CRDLY                             = 0x3000
-       CREAD                             = 0x800
-       CRTSCTS                           = 0x30000
-       CS5                               = 0x0
-       CS6                               = 0x100
-       CS7                               = 0x200
-       CS8                               = 0x300
-       CSIZE                             = 0x300
-       CSTART                            = 0x11
-       CSTATUS                           = 0x14
-       CSTOP                             = 0x13
-       CSTOPB                            = 0x400
-       CSUSP                             = 0x1a
-       CTLIOCGINFO                       = 0xc0644e03
-       CTL_HW                            = 0x6
-       CTL_KERN                          = 0x1
-       CTL_MAXNAME                       = 0xc
-       CTL_NET                           = 0x4
-       DLT_A429                          = 0xb8
-       DLT_A653_ICM                      = 0xb9
-       DLT_AIRONET_HEADER                = 0x78
-       DLT_AOS                           = 0xde
-       DLT_APPLE_IP_OVER_IEEE1394        = 0x8a
-       DLT_ARCNET                        = 0x7
-       DLT_ARCNET_LINUX                  = 0x81
-       DLT_ATM_CLIP                      = 0x13
-       DLT_ATM_RFC1483                   = 0xb
-       DLT_AURORA                        = 0x7e
-       DLT_AX25                          = 0x3
-       DLT_AX25_KISS                     = 0xca
-       DLT_BACNET_MS_TP                  = 0xa5
-       DLT_BLUETOOTH_HCI_H4              = 0xbb
-       DLT_BLUETOOTH_HCI_H4_WITH_PHDR    = 0xc9
-       DLT_CAN20B                        = 0xbe
-       DLT_CAN_SOCKETCAN                 = 0xe3
-       DLT_CHAOS                         = 0x5
-       DLT_CHDLC                         = 0x68
-       DLT_CISCO_IOS                     = 0x76
-       DLT_C_HDLC                        = 0x68
-       DLT_C_HDLC_WITH_DIR               = 0xcd
-       DLT_DBUS                          = 0xe7
-       DLT_DECT                          = 0xdd
-       DLT_DOCSIS                        = 0x8f
-       DLT_DVB_CI                        = 0xeb
-       DLT_ECONET                        = 0x73
-       DLT_EN10MB                        = 0x1
-       DLT_EN3MB                         = 0x2
-       DLT_ENC                           = 0x6d
-       DLT_ERF                           = 0xc5
-       DLT_ERF_ETH                       = 0xaf
-       DLT_ERF_POS                       = 0xb0
-       DLT_FC_2                          = 0xe0
-       DLT_FC_2_WITH_FRAME_DELIMS        = 0xe1
-       DLT_FDDI                          = 0xa
-       DLT_FLEXRAY                       = 0xd2
-       DLT_FRELAY                        = 0x6b
-       DLT_FRELAY_WITH_DIR               = 0xce
-       DLT_GCOM_SERIAL                   = 0xad
-       DLT_GCOM_T1E1                     = 0xac
-       DLT_GPF_F                         = 0xab
-       DLT_GPF_T                         = 0xaa
-       DLT_GPRS_LLC                      = 0xa9
-       DLT_GSMTAP_ABIS                   = 0xda
-       DLT_GSMTAP_UM                     = 0xd9
-       DLT_HHDLC                         = 0x79
-       DLT_IBM_SN                        = 0x92
-       DLT_IBM_SP                        = 0x91
-       DLT_IEEE802                       = 0x6
-       DLT_IEEE802_11                    = 0x69
-       DLT_IEEE802_11_RADIO              = 0x7f
-       DLT_IEEE802_11_RADIO_AVS          = 0xa3
-       DLT_IEEE802_15_4                  = 0xc3
-       DLT_IEEE802_15_4_LINUX            = 0xbf
-       DLT_IEEE802_15_4_NOFCS            = 0xe6
-       DLT_IEEE802_15_4_NONASK_PHY       = 0xd7
-       DLT_IEEE802_16_MAC_CPS            = 0xbc
-       DLT_IEEE802_16_MAC_CPS_RADIO      = 0xc1
-       DLT_IPFILTER                      = 0x74
-       DLT_IPMB                          = 0xc7
-       DLT_IPMB_LINUX                    = 0xd1
-       DLT_IPNET                         = 0xe2
-       DLT_IPOIB                         = 0xf2
-       DLT_IPV4                          = 0xe4
-       DLT_IPV6                          = 0xe5
-       DLT_IP_OVER_FC                    = 0x7a
-       DLT_JUNIPER_ATM1                  = 0x89
-       DLT_JUNIPER_ATM2                  = 0x87
-       DLT_JUNIPER_ATM_CEMIC             = 0xee
-       DLT_JUNIPER_CHDLC                 = 0xb5
-       DLT_JUNIPER_ES                    = 0x84
-       DLT_JUNIPER_ETHER                 = 0xb2
-       DLT_JUNIPER_FIBRECHANNEL          = 0xea
-       DLT_JUNIPER_FRELAY                = 0xb4
-       DLT_JUNIPER_GGSN                  = 0x85
-       DLT_JUNIPER_ISM                   = 0xc2
-       DLT_JUNIPER_MFR                   = 0x86
-       DLT_JUNIPER_MLFR                  = 0x83
-       DLT_JUNIPER_MLPPP                 = 0x82
-       DLT_JUNIPER_MONITOR               = 0xa4
-       DLT_JUNIPER_PIC_PEER              = 0xae
-       DLT_JUNIPER_PPP                   = 0xb3
-       DLT_JUNIPER_PPPOE                 = 0xa7
-       DLT_JUNIPER_PPPOE_ATM             = 0xa8
-       DLT_JUNIPER_SERVICES              = 0x88
-       DLT_JUNIPER_SRX_E2E               = 0xe9
-       DLT_JUNIPER_ST                    = 0xc8
-       DLT_JUNIPER_VP                    = 0xb7
-       DLT_JUNIPER_VS                    = 0xe8
-       DLT_LAPB_WITH_DIR                 = 0xcf
-       DLT_LAPD                          = 0xcb
-       DLT_LIN                           = 0xd4
-       DLT_LINUX_EVDEV                   = 0xd8
-       DLT_LINUX_IRDA                    = 0x90
-       DLT_LINUX_LAPD                    = 0xb1
-       DLT_LINUX_PPP_WITHDIRECTION       = 0xa6
-       DLT_LINUX_SLL                     = 0x71
-       DLT_LOOP                          = 0x6c
-       DLT_LTALK                         = 0x72
-       DLT_MATCHING_MAX                  = 0x10a
-       DLT_MATCHING_MIN                  = 0x68
-       DLT_MFR                           = 0xb6
-       DLT_MOST                          = 0xd3
-       DLT_MPEG_2_TS                     = 0xf3
-       DLT_MPLS                          = 0xdb
-       DLT_MTP2                          = 0x8c
-       DLT_MTP2_WITH_PHDR                = 0x8b
-       DLT_MTP3                          = 0x8d
-       DLT_MUX27010                      = 0xec
-       DLT_NETANALYZER                   = 0xf0
-       DLT_NETANALYZER_TRANSPARENT       = 0xf1
-       DLT_NFC_LLCP                      = 0xf5
-       DLT_NFLOG                         = 0xef
-       DLT_NG40                          = 0xf4
-       DLT_NULL                          = 0x0
-       DLT_PCI_EXP                       = 0x7d
-       DLT_PFLOG                         = 0x75
-       DLT_PFSYNC                        = 0x12
-       DLT_PPI                           = 0xc0
-       DLT_PPP                           = 0x9
-       DLT_PPP_BSDOS                     = 0x10
-       DLT_PPP_ETHER                     = 0x33
-       DLT_PPP_PPPD                      = 0xa6
-       DLT_PPP_SERIAL                    = 0x32
-       DLT_PPP_WITH_DIR                  = 0xcc
-       DLT_PPP_WITH_DIRECTION            = 0xa6
-       DLT_PRISM_HEADER                  = 0x77
-       DLT_PRONET                        = 0x4
-       DLT_RAIF1                         = 0xc6
-       DLT_RAW                           = 0xc
-       DLT_RIO                           = 0x7c
-       DLT_SCCP                          = 0x8e
-       DLT_SITA                          = 0xc4
-       DLT_SLIP                          = 0x8
-       DLT_SLIP_BSDOS                    = 0xf
-       DLT_STANAG_5066_D_PDU             = 0xed
-       DLT_SUNATM                        = 0x7b
-       DLT_SYMANTEC_FIREWALL             = 0x63
-       DLT_TZSP                          = 0x80
-       DLT_USB                           = 0xba
-       DLT_USB_DARWIN                    = 0x10a
-       DLT_USB_LINUX                     = 0xbd
-       DLT_USB_LINUX_MMAPPED             = 0xdc
-       DLT_USER0                         = 0x93
-       DLT_USER1                         = 0x94
-       DLT_USER10                        = 0x9d
-       DLT_USER11                        = 0x9e
-       DLT_USER12                        = 0x9f
-       DLT_USER13                        = 0xa0
-       DLT_USER14                        = 0xa1
-       DLT_USER15                        = 0xa2
-       DLT_USER2                         = 0x95
-       DLT_USER3                         = 0x96
-       DLT_USER4                         = 0x97
-       DLT_USER5                         = 0x98
-       DLT_USER6                         = 0x99
-       DLT_USER7                         = 0x9a
-       DLT_USER8                         = 0x9b
-       DLT_USER9                         = 0x9c
-       DLT_WIHART                        = 0xdf
-       DLT_X2E_SERIAL                    = 0xd5
-       DLT_X2E_XORAYA                    = 0xd6
-       DT_BLK                            = 0x6
-       DT_CHR                            = 0x2
-       DT_DIR                            = 0x4
-       DT_FIFO                           = 0x1
-       DT_LNK                            = 0xa
-       DT_REG                            = 0x8
-       DT_SOCK                           = 0xc
-       DT_UNKNOWN                        = 0x0
-       DT_WHT                            = 0xe
-       ECHO                              = 0x8
-       ECHOCTL                           = 0x40
-       ECHOE                             = 0x2
-       ECHOK                             = 0x4
-       ECHOKE                            = 0x1
-       ECHONL                            = 0x10
-       ECHOPRT                           = 0x20
-       EVFILT_AIO                        = -0x3
-       EVFILT_EXCEPT                     = -0xf
-       EVFILT_FS                         = -0x9
-       EVFILT_MACHPORT                   = -0x8
-       EVFILT_PROC                       = -0x5
-       EVFILT_READ                       = -0x1
-       EVFILT_SIGNAL                     = -0x6
-       EVFILT_SYSCOUNT                   = 0x11
-       EVFILT_THREADMARKER               = 0x11
-       EVFILT_TIMER                      = -0x7
-       EVFILT_USER                       = -0xa
-       EVFILT_VM                         = -0xc
-       EVFILT_VNODE                      = -0x4
-       EVFILT_WRITE                      = -0x2
-       EV_ADD                            = 0x1
-       EV_CLEAR                          = 0x20
-       EV_DELETE                         = 0x2
-       EV_DISABLE                        = 0x8
-       EV_DISPATCH                       = 0x80
-       EV_DISPATCH2                      = 0x180
-       EV_ENABLE                         = 0x4
-       EV_EOF                            = 0x8000
-       EV_ERROR                          = 0x4000
-       EV_FLAG0                          = 0x1000
-       EV_FLAG1                          = 0x2000
-       EV_ONESHOT                        = 0x10
-       EV_OOBAND                         = 0x2000
-       EV_POLL                           = 0x1000
-       EV_RECEIPT                        = 0x40
-       EV_SYSFLAGS                       = 0xf000
-       EV_UDATA_SPECIFIC                 = 0x100
-       EV_VANISHED                       = 0x200
-       EXTA                              = 0x4b00
-       EXTB                              = 0x9600
-       EXTPROC                           = 0x800
-       FD_CLOEXEC                        = 0x1
-       FD_SETSIZE                        = 0x400
-       FF0                               = 0x0
-       FF1                               = 0x4000
-       FFDLY                             = 0x4000
-       FLUSHO                            = 0x800000
-       FSOPT_ATTR_CMN_EXTENDED           = 0x20
-       FSOPT_NOFOLLOW                    = 0x1
-       FSOPT_NOINMEMUPDATE               = 0x2
-       FSOPT_PACK_INVAL_ATTRS            = 0x8
-       FSOPT_REPORT_FULLSIZE             = 0x4
-       FSOPT_RETURN_REALDEV              = 0x200
-       F_ADDFILESIGS                     = 0x3d
-       F_ADDFILESIGS_FOR_DYLD_SIM        = 0x53
-       F_ADDFILESIGS_INFO                = 0x67
-       F_ADDFILESIGS_RETURN              = 0x61
-       F_ADDFILESUPPL                    = 0x68
-       F_ADDSIGS                         = 0x3b
-       F_ALLOCATEALL                     = 0x4
-       F_ALLOCATECONTIG                  = 0x2
-       F_BARRIERFSYNC                    = 0x55
-       F_CHECK_LV                        = 0x62
-       F_CHKCLEAN                        = 0x29
-       F_DUPFD                           = 0x0
-       F_DUPFD_CLOEXEC                   = 0x43
-       F_FINDSIGS                        = 0x4e
-       F_FLUSH_DATA                      = 0x28
-       F_FREEZE_FS                       = 0x35
-       F_FULLFSYNC                       = 0x33
-       F_GETCODEDIR                      = 0x48
-       F_GETFD                           = 0x1
-       F_GETFL                           = 0x3
-       F_GETLK                           = 0x7
-       F_GETLKPID                        = 0x42
-       F_GETNOSIGPIPE                    = 0x4a
-       F_GETOWN                          = 0x5
-       F_GETPATH                         = 0x32
-       F_GETPATH_MTMINFO                 = 0x47
-       F_GETPATH_NOFIRMLINK              = 0x66
-       F_GETPROTECTIONCLASS              = 0x3f
-       F_GETPROTECTIONLEVEL              = 0x4d
-       F_GETSIGSINFO                     = 0x69
-       F_GLOBAL_NOCACHE                  = 0x37
-       F_LOG2PHYS                        = 0x31
-       F_LOG2PHYS_EXT                    = 0x41
-       F_NOCACHE                         = 0x30
-       F_NODIRECT                        = 0x3e
-       F_OK                              = 0x0
-       F_PATHPKG_CHECK                   = 0x34
-       F_PEOFPOSMODE                     = 0x3
-       F_PREALLOCATE                     = 0x2a
-       F_PUNCHHOLE                       = 0x63
-       F_RDADVISE                        = 0x2c
-       F_RDAHEAD                         = 0x2d
-       F_RDLCK                           = 0x1
-       F_SETBACKINGSTORE                 = 0x46
-       F_SETFD                           = 0x2
-       F_SETFL                           = 0x4
-       F_SETLK                           = 0x8
-       F_SETLKW                          = 0x9
-       F_SETLKWTIMEOUT                   = 0xa
-       F_SETNOSIGPIPE                    = 0x49
-       F_SETOWN                          = 0x6
-       F_SETPROTECTIONCLASS              = 0x40
-       F_SETSIZE                         = 0x2b
-       F_SINGLE_WRITER                   = 0x4c
-       F_SPECULATIVE_READ                = 0x65
-       F_THAW_FS                         = 0x36
-       F_TRANSCODEKEY                    = 0x4b
-       F_TRIM_ACTIVE_FILE                = 0x64
-       F_UNLCK                           = 0x2
-       F_VOLPOSMODE                      = 0x4
-       F_WRLCK                           = 0x3
-       HUPCL                             = 0x4000
-       HW_MACHINE                        = 0x1
-       ICANON                            = 0x100
-       ICMP6_FILTER                      = 0x12
-       ICRNL                             = 0x100
-       IEXTEN                            = 0x400
-       IFF_ALLMULTI                      = 0x200
-       IFF_ALTPHYS                       = 0x4000
-       IFF_BROADCAST                     = 0x2
-       IFF_DEBUG                         = 0x4
-       IFF_LINK0                         = 0x1000
-       IFF_LINK1                         = 0x2000
-       IFF_LINK2                         = 0x4000
-       IFF_LOOPBACK                      = 0x8
-       IFF_MULTICAST                     = 0x8000
-       IFF_NOARP                         = 0x80
-       IFF_NOTRAILERS                    = 0x20
-       IFF_OACTIVE                       = 0x400
-       IFF_POINTOPOINT                   = 0x10
-       IFF_PROMISC                       = 0x100
-       IFF_RUNNING                       = 0x40
-       IFF_SIMPLEX                       = 0x800
-       IFF_UP                            = 0x1
-       IFNAMSIZ                          = 0x10
-       IFT_1822                          = 0x2
-       IFT_6LOWPAN                       = 0x40
-       IFT_AAL5                          = 0x31
-       IFT_ARCNET                        = 0x23
-       IFT_ARCNETPLUS                    = 0x24
-       IFT_ATM                           = 0x25
-       IFT_BRIDGE                        = 0xd1
-       IFT_CARP                          = 0xf8
-       IFT_CELLULAR                      = 0xff
-       IFT_CEPT                          = 0x13
-       IFT_DS3                           = 0x1e
-       IFT_ENC                           = 0xf4
-       IFT_EON                           = 0x19
-       IFT_ETHER                         = 0x6
-       IFT_FAITH                         = 0x38
-       IFT_FDDI                          = 0xf
-       IFT_FRELAY                        = 0x20
-       IFT_FRELAYDCE                     = 0x2c
-       IFT_GIF                           = 0x37
-       IFT_HDH1822                       = 0x3
-       IFT_HIPPI                         = 0x2f
-       IFT_HSSI                          = 0x2e
-       IFT_HY                            = 0xe
-       IFT_IEEE1394                      = 0x90
-       IFT_IEEE8023ADLAG                 = 0x88
-       IFT_ISDNBASIC                     = 0x14
-       IFT_ISDNPRIMARY                   = 0x15
-       IFT_ISO88022LLC                   = 0x29
-       IFT_ISO88023                      = 0x7
-       IFT_ISO88024                      = 0x8
-       IFT_ISO88025                      = 0x9
-       IFT_ISO88026                      = 0xa
-       IFT_L2VLAN                        = 0x87
-       IFT_LAPB                          = 0x10
-       IFT_LOCALTALK                     = 0x2a
-       IFT_LOOP                          = 0x18
-       IFT_MIOX25                        = 0x26
-       IFT_MODEM                         = 0x30
-       IFT_NSIP                          = 0x1b
-       IFT_OTHER                         = 0x1
-       IFT_P10                           = 0xc
-       IFT_P80                           = 0xd
-       IFT_PARA                          = 0x22
-       IFT_PDP                           = 0xff
-       IFT_PFLOG                         = 0xf5
-       IFT_PFSYNC                        = 0xf6
-       IFT_PKTAP                         = 0xfe
-       IFT_PPP                           = 0x17
-       IFT_PROPMUX                       = 0x36
-       IFT_PROPVIRTUAL                   = 0x35
-       IFT_PTPSERIAL                     = 0x16
-       IFT_RS232                         = 0x21
-       IFT_SDLC                          = 0x11
-       IFT_SIP                           = 0x1f
-       IFT_SLIP                          = 0x1c
-       IFT_SMDSDXI                       = 0x2b
-       IFT_SMDSICIP                      = 0x34
-       IFT_SONET                         = 0x27
-       IFT_SONETPATH                     = 0x32
-       IFT_SONETVT                       = 0x33
-       IFT_STARLAN                       = 0xb
-       IFT_STF                           = 0x39
-       IFT_T1                            = 0x12
-       IFT_ULTRA                         = 0x1d
-       IFT_V35                           = 0x2d
-       IFT_X25                           = 0x5
-       IFT_X25DDN                        = 0x4
-       IFT_X25PLE                        = 0x28
-       IFT_XETHER                        = 0x1a
-       IGNBRK                            = 0x1
-       IGNCR                             = 0x80
-       IGNPAR                            = 0x4
-       IMAXBEL                           = 0x2000
-       INLCR                             = 0x40
-       INPCK                             = 0x10
-       IN_CLASSA_HOST                    = 0xffffff
-       IN_CLASSA_MAX                     = 0x80
-       IN_CLASSA_NET                     = 0xff000000
-       IN_CLASSA_NSHIFT                  = 0x18
-       IN_CLASSB_HOST                    = 0xffff
-       IN_CLASSB_MAX                     = 0x10000
-       IN_CLASSB_NET                     = 0xffff0000
-       IN_CLASSB_NSHIFT                  = 0x10
-       IN_CLASSC_HOST                    = 0xff
-       IN_CLASSC_NET                     = 0xffffff00
-       IN_CLASSC_NSHIFT                  = 0x8
-       IN_CLASSD_HOST                    = 0xfffffff
-       IN_CLASSD_NET                     = 0xf0000000
-       IN_CLASSD_NSHIFT                  = 0x1c
-       IN_LINKLOCALNETNUM                = 0xa9fe0000
-       IN_LOOPBACKNET                    = 0x7f
-       IPPROTO_3PC                       = 0x22
-       IPPROTO_ADFS                      = 0x44
-       IPPROTO_AH                        = 0x33
-       IPPROTO_AHIP                      = 0x3d
-       IPPROTO_APES                      = 0x63
-       IPPROTO_ARGUS                     = 0xd
-       IPPROTO_AX25                      = 0x5d
-       IPPROTO_BHA                       = 0x31
-       IPPROTO_BLT                       = 0x1e
-       IPPROTO_BRSATMON                  = 0x4c
-       IPPROTO_CFTP                      = 0x3e
-       IPPROTO_CHAOS                     = 0x10
-       IPPROTO_CMTP                      = 0x26
-       IPPROTO_CPHB                      = 0x49
-       IPPROTO_CPNX                      = 0x48
-       IPPROTO_DDP                       = 0x25
-       IPPROTO_DGP                       = 0x56
-       IPPROTO_DIVERT                    = 0xfe
-       IPPROTO_DONE                      = 0x101
-       IPPROTO_DSTOPTS                   = 0x3c
-       IPPROTO_EGP                       = 0x8
-       IPPROTO_EMCON                     = 0xe
-       IPPROTO_ENCAP                     = 0x62
-       IPPROTO_EON                       = 0x50
-       IPPROTO_ESP                       = 0x32
-       IPPROTO_ETHERIP                   = 0x61
-       IPPROTO_FRAGMENT                  = 0x2c
-       IPPROTO_GGP                       = 0x3
-       IPPROTO_GMTP                      = 0x64
-       IPPROTO_GRE                       = 0x2f
-       IPPROTO_HELLO                     = 0x3f
-       IPPROTO_HMP                       = 0x14
-       IPPROTO_HOPOPTS                   = 0x0
-       IPPROTO_ICMP                      = 0x1
-       IPPROTO_ICMPV6                    = 0x3a
-       IPPROTO_IDP                       = 0x16
-       IPPROTO_IDPR                      = 0x23
-       IPPROTO_IDRP                      = 0x2d
-       IPPROTO_IGMP                      = 0x2
-       IPPROTO_IGP                       = 0x55
-       IPPROTO_IGRP                      = 0x58
-       IPPROTO_IL                        = 0x28
-       IPPROTO_INLSP                     = 0x34
-       IPPROTO_INP                       = 0x20
-       IPPROTO_IP                        = 0x0
-       IPPROTO_IPCOMP                    = 0x6c
-       IPPROTO_IPCV                      = 0x47
-       IPPROTO_IPEIP                     = 0x5e
-       IPPROTO_IPIP                      = 0x4
-       IPPROTO_IPPC                      = 0x43
-       IPPROTO_IPV4                      = 0x4
-       IPPROTO_IPV6                      = 0x29
-       IPPROTO_IRTP                      = 0x1c
-       IPPROTO_KRYPTOLAN                 = 0x41
-       IPPROTO_LARP                      = 0x5b
-       IPPROTO_LEAF1                     = 0x19
-       IPPROTO_LEAF2                     = 0x1a
-       IPPROTO_MAX                       = 0x100
-       IPPROTO_MAXID                     = 0x34
-       IPPROTO_MEAS                      = 0x13
-       IPPROTO_MHRP                      = 0x30
-       IPPROTO_MICP                      = 0x5f
-       IPPROTO_MTP                       = 0x5c
-       IPPROTO_MUX                       = 0x12
-       IPPROTO_ND                        = 0x4d
-       IPPROTO_NHRP                      = 0x36
-       IPPROTO_NONE                      = 0x3b
-       IPPROTO_NSP                       = 0x1f
-       IPPROTO_NVPII                     = 0xb
-       IPPROTO_OSPFIGP                   = 0x59
-       IPPROTO_PGM                       = 0x71
-       IPPROTO_PIGP                      = 0x9
-       IPPROTO_PIM                       = 0x67
-       IPPROTO_PRM                       = 0x15
-       IPPROTO_PUP                       = 0xc
-       IPPROTO_PVP                       = 0x4b
-       IPPROTO_RAW                       = 0xff
-       IPPROTO_RCCMON                    = 0xa
-       IPPROTO_RDP                       = 0x1b
-       IPPROTO_ROUTING                   = 0x2b
-       IPPROTO_RSVP                      = 0x2e
-       IPPROTO_RVD                       = 0x42
-       IPPROTO_SATEXPAK                  = 0x40
-       IPPROTO_SATMON                    = 0x45
-       IPPROTO_SCCSP                     = 0x60
-       IPPROTO_SCTP                      = 0x84
-       IPPROTO_SDRP                      = 0x2a
-       IPPROTO_SEP                       = 0x21
-       IPPROTO_SRPC                      = 0x5a
-       IPPROTO_ST                        = 0x7
-       IPPROTO_SVMTP                     = 0x52
-       IPPROTO_SWIPE                     = 0x35
-       IPPROTO_TCF                       = 0x57
-       IPPROTO_TCP                       = 0x6
-       IPPROTO_TP                        = 0x1d
-       IPPROTO_TPXX                      = 0x27
-       IPPROTO_TRUNK1                    = 0x17
-       IPPROTO_TRUNK2                    = 0x18
-       IPPROTO_TTP                       = 0x54
-       IPPROTO_UDP                       = 0x11
-       IPPROTO_VINES                     = 0x53
-       IPPROTO_VISA                      = 0x46
-       IPPROTO_VMTP                      = 0x51
-       IPPROTO_WBEXPAK                   = 0x4f
-       IPPROTO_WBMON                     = 0x4e
-       IPPROTO_WSN                       = 0x4a
-       IPPROTO_XNET                      = 0xf
-       IPPROTO_XTP                       = 0x24
-       IPV6_2292DSTOPTS                  = 0x17
-       IPV6_2292HOPLIMIT                 = 0x14
-       IPV6_2292HOPOPTS                  = 0x16
-       IPV6_2292NEXTHOP                  = 0x15
-       IPV6_2292PKTINFO                  = 0x13
-       IPV6_2292PKTOPTIONS               = 0x19
-       IPV6_2292RTHDR                    = 0x18
-       IPV6_3542DSTOPTS                  = 0x32
-       IPV6_3542HOPLIMIT                 = 0x2f
-       IPV6_3542HOPOPTS                  = 0x31
-       IPV6_3542NEXTHOP                  = 0x30
-       IPV6_3542PKTINFO                  = 0x2e
-       IPV6_3542RTHDR                    = 0x33
-       IPV6_ADDR_MC_FLAGS_PREFIX         = 0x20
-       IPV6_ADDR_MC_FLAGS_TRANSIENT      = 0x10
-       IPV6_ADDR_MC_FLAGS_UNICAST_BASED  = 0x30
-       IPV6_AUTOFLOWLABEL                = 0x3b
-       IPV6_BINDV6ONLY                   = 0x1b
-       IPV6_BOUND_IF                     = 0x7d
-       IPV6_CHECKSUM                     = 0x1a
-       IPV6_DEFAULT_MULTICAST_HOPS       = 0x1
-       IPV6_DEFAULT_MULTICAST_LOOP       = 0x1
-       IPV6_DEFHLIM                      = 0x40
-       IPV6_DONTFRAG                     = 0x3e
-       IPV6_DSTOPTS                      = 0x32
-       IPV6_FAITH                        = 0x1d
-       IPV6_FLOWINFO_MASK                = 0xffffff0f
-       IPV6_FLOWLABEL_MASK               = 0xffff0f00
-       IPV6_FLOW_ECN_MASK                = 0x3000
-       IPV6_FRAGTTL                      = 0x3c
-       IPV6_FW_ADD                       = 0x1e
-       IPV6_FW_DEL                       = 0x1f
-       IPV6_FW_FLUSH                     = 0x20
-       IPV6_FW_GET                       = 0x22
-       IPV6_FW_ZERO                      = 0x21
-       IPV6_HLIMDEC                      = 0x1
-       IPV6_HOPLIMIT                     = 0x2f
-       IPV6_HOPOPTS                      = 0x31
-       IPV6_IPSEC_POLICY                 = 0x1c
-       IPV6_JOIN_GROUP                   = 0xc
-       IPV6_LEAVE_GROUP                  = 0xd
-       IPV6_MAXHLIM                      = 0xff
-       IPV6_MAXOPTHDR                    = 0x800
-       IPV6_MAXPACKET                    = 0xffff
-       IPV6_MAX_GROUP_SRC_FILTER         = 0x200
-       IPV6_MAX_MEMBERSHIPS              = 0xfff
-       IPV6_MAX_SOCK_SRC_FILTER          = 0x80
-       IPV6_MIN_MEMBERSHIPS              = 0x1f
-       IPV6_MMTU                         = 0x500
-       IPV6_MSFILTER                     = 0x4a
-       IPV6_MULTICAST_HOPS               = 0xa
-       IPV6_MULTICAST_IF                 = 0x9
-       IPV6_MULTICAST_LOOP               = 0xb
-       IPV6_NEXTHOP                      = 0x30
-       IPV6_PATHMTU                      = 0x2c
-       IPV6_PKTINFO                      = 0x2e
-       IPV6_PORTRANGE                    = 0xe
-       IPV6_PORTRANGE_DEFAULT            = 0x0
-       IPV6_PORTRANGE_HIGH               = 0x1
-       IPV6_PORTRANGE_LOW                = 0x2
-       IPV6_PREFER_TEMPADDR              = 0x3f
-       IPV6_RECVDSTOPTS                  = 0x28
-       IPV6_RECVHOPLIMIT                 = 0x25
-       IPV6_RECVHOPOPTS                  = 0x27
-       IPV6_RECVPATHMTU                  = 0x2b
-       IPV6_RECVPKTINFO                  = 0x3d
-       IPV6_RECVRTHDR                    = 0x26
-       IPV6_RECVTCLASS                   = 0x23
-       IPV6_RTHDR                        = 0x33
-       IPV6_RTHDRDSTOPTS                 = 0x39
-       IPV6_RTHDR_LOOSE                  = 0x0
-       IPV6_RTHDR_STRICT                 = 0x1
-       IPV6_RTHDR_TYPE_0                 = 0x0
-       IPV6_SOCKOPT_RESERVED1            = 0x3
-       IPV6_TCLASS                       = 0x24
-       IPV6_UNICAST_HOPS                 = 0x4
-       IPV6_USE_MIN_MTU                  = 0x2a
-       IPV6_V6ONLY                       = 0x1b
-       IPV6_VERSION                      = 0x60
-       IPV6_VERSION_MASK                 = 0xf0
-       IP_ADD_MEMBERSHIP                 = 0xc
-       IP_ADD_SOURCE_MEMBERSHIP          = 0x46
-       IP_BLOCK_SOURCE                   = 0x48
-       IP_BOUND_IF                       = 0x19
-       IP_DEFAULT_MULTICAST_LOOP         = 0x1
-       IP_DEFAULT_MULTICAST_TTL          = 0x1
-       IP_DF                             = 0x4000
-       IP_DONTFRAG                       = 0x1c
-       IP_DROP_MEMBERSHIP                = 0xd
-       IP_DROP_SOURCE_MEMBERSHIP         = 0x47
-       IP_DUMMYNET_CONFIGURE             = 0x3c
-       IP_DUMMYNET_DEL                   = 0x3d
-       IP_DUMMYNET_FLUSH                 = 0x3e
-       IP_DUMMYNET_GET                   = 0x40
-       IP_FAITH                          = 0x16
-       IP_FW_ADD                         = 0x28
-       IP_FW_DEL                         = 0x29
-       IP_FW_FLUSH                       = 0x2a
-       IP_FW_GET                         = 0x2c
-       IP_FW_RESETLOG                    = 0x2d
-       IP_FW_ZERO                        = 0x2b
-       IP_HDRINCL                        = 0x2
-       IP_IPSEC_POLICY                   = 0x15
-       IP_MAXPACKET                      = 0xffff
-       IP_MAX_GROUP_SRC_FILTER           = 0x200
-       IP_MAX_MEMBERSHIPS                = 0xfff
-       IP_MAX_SOCK_MUTE_FILTER           = 0x80
-       IP_MAX_SOCK_SRC_FILTER            = 0x80
-       IP_MF                             = 0x2000
-       IP_MIN_MEMBERSHIPS                = 0x1f
-       IP_MSFILTER                       = 0x4a
-       IP_MSS                            = 0x240
-       IP_MULTICAST_IF                   = 0x9
-       IP_MULTICAST_IFINDEX              = 0x42
-       IP_MULTICAST_LOOP                 = 0xb
-       IP_MULTICAST_TTL                  = 0xa
-       IP_MULTICAST_VIF                  = 0xe
-       IP_NAT__XXX                       = 0x37
-       IP_OFFMASK                        = 0x1fff
-       IP_OLD_FW_ADD                     = 0x32
-       IP_OLD_FW_DEL                     = 0x33
-       IP_OLD_FW_FLUSH                   = 0x34
-       IP_OLD_FW_GET                     = 0x36
-       IP_OLD_FW_RESETLOG                = 0x38
-       IP_OLD_FW_ZERO                    = 0x35
-       IP_OPTIONS                        = 0x1
-       IP_PKTINFO                        = 0x1a
-       IP_PORTRANGE                      = 0x13
-       IP_PORTRANGE_DEFAULT              = 0x0
-       IP_PORTRANGE_HIGH                 = 0x1
-       IP_PORTRANGE_LOW                  = 0x2
-       IP_RECVDSTADDR                    = 0x7
-       IP_RECVIF                         = 0x14
-       IP_RECVOPTS                       = 0x5
-       IP_RECVPKTINFO                    = 0x1a
-       IP_RECVRETOPTS                    = 0x6
-       IP_RECVTOS                        = 0x1b
-       IP_RECVTTL                        = 0x18
-       IP_RETOPTS                        = 0x8
-       IP_RF                             = 0x8000
-       IP_RSVP_OFF                       = 0x10
-       IP_RSVP_ON                        = 0xf
-       IP_RSVP_VIF_OFF                   = 0x12
-       IP_RSVP_VIF_ON                    = 0x11
-       IP_STRIPHDR                       = 0x17
-       IP_TOS                            = 0x3
-       IP_TRAFFIC_MGT_BACKGROUND         = 0x41
-       IP_TTL                            = 0x4
-       IP_UNBLOCK_SOURCE                 = 0x49
-       ISIG                              = 0x80
-       ISTRIP                            = 0x20
-       IUTF8                             = 0x4000
-       IXANY                             = 0x800
-       IXOFF                             = 0x400
-       IXON                              = 0x200
-       KERN_HOSTNAME                     = 0xa
-       KERN_OSRELEASE                    = 0x2
-       KERN_OSTYPE                       = 0x1
-       KERN_VERSION                      = 0x4
-       LOCAL_PEERCRED                    = 0x1
-       LOCAL_PEEREPID                    = 0x3
-       LOCAL_PEEREUUID                   = 0x5
-       LOCAL_PEERPID                     = 0x2
-       LOCAL_PEERTOKEN                   = 0x6
-       LOCAL_PEERUUID                    = 0x4
-       LOCK_EX                           = 0x2
-       LOCK_NB                           = 0x4
-       LOCK_SH                           = 0x1
-       LOCK_UN                           = 0x8
-       MADV_CAN_REUSE                    = 0x9
-       MADV_DONTNEED                     = 0x4
-       MADV_FREE                         = 0x5
-       MADV_FREE_REUSABLE                = 0x7
-       MADV_FREE_REUSE                   = 0x8
-       MADV_NORMAL                       = 0x0
-       MADV_PAGEOUT                      = 0xa
-       MADV_RANDOM                       = 0x1
-       MADV_SEQUENTIAL                   = 0x2
-       MADV_WILLNEED                     = 0x3
-       MADV_ZERO_WIRED_PAGES             = 0x6
-       MAP_32BIT                         = 0x8000
-       MAP_ANON                          = 0x1000
-       MAP_ANONYMOUS                     = 0x1000
-       MAP_COPY                          = 0x2
-       MAP_FILE                          = 0x0
-       MAP_FIXED                         = 0x10
-       MAP_HASSEMAPHORE                  = 0x200
-       MAP_JIT                           = 0x800
-       MAP_NOCACHE                       = 0x400
-       MAP_NOEXTEND                      = 0x100
-       MAP_NORESERVE                     = 0x40
-       MAP_PRIVATE                       = 0x2
-       MAP_RENAME                        = 0x20
-       MAP_RESERVED0080                  = 0x80
-       MAP_RESILIENT_CODESIGN            = 0x2000
-       MAP_RESILIENT_MEDIA               = 0x4000
-       MAP_SHARED                        = 0x1
-       MAP_TRANSLATED_ALLOW_EXECUTE      = 0x20000
-       MAP_UNIX03                        = 0x40000
-       MCAST_BLOCK_SOURCE                = 0x54
-       MCAST_EXCLUDE                     = 0x2
-       MCAST_INCLUDE                     = 0x1
-       MCAST_JOIN_GROUP                  = 0x50
-       MCAST_JOIN_SOURCE_GROUP           = 0x52
-       MCAST_LEAVE_GROUP                 = 0x51
-       MCAST_LEAVE_SOURCE_GROUP          = 0x53
-       MCAST_UNBLOCK_SOURCE              = 0x55
-       MCAST_UNDEFINED                   = 0x0
-       MCL_CURRENT                       = 0x1
-       MCL_FUTURE                        = 0x2
-       MNT_ASYNC                         = 0x40
-       MNT_AUTOMOUNTED                   = 0x400000
-       MNT_CMDFLAGS                      = 0xf0000
-       MNT_CPROTECT                      = 0x80
-       MNT_DEFWRITE                      = 0x2000000
-       MNT_DONTBROWSE                    = 0x100000
-       MNT_DOVOLFS                       = 0x8000
-       MNT_DWAIT                         = 0x4
-       MNT_EXPORTED                      = 0x100
-       MNT_EXT_ROOT_DATA_VOL             = 0x1
-       MNT_FORCE                         = 0x80000
-       MNT_IGNORE_OWNERSHIP              = 0x200000
-       MNT_JOURNALED                     = 0x800000
-       MNT_LOCAL                         = 0x1000
-       MNT_MULTILABEL                    = 0x4000000
-       MNT_NOATIME                       = 0x10000000
-       MNT_NOBLOCK                       = 0x20000
-       MNT_NODEV                         = 0x10
-       MNT_NOEXEC                        = 0x4
-       MNT_NOSUID                        = 0x8
-       MNT_NOUSERXATTR                   = 0x1000000
-       MNT_NOWAIT                        = 0x2
-       MNT_QUARANTINE                    = 0x400
-       MNT_QUOTA                         = 0x2000
-       MNT_RDONLY                        = 0x1
-       MNT_RELOAD                        = 0x40000
-       MNT_REMOVABLE                     = 0x200
-       MNT_ROOTFS                        = 0x4000
-       MNT_SNAPSHOT                      = 0x40000000
-       MNT_STRICTATIME                   = 0x80000000
-       MNT_SYNCHRONOUS                   = 0x2
-       MNT_UNION                         = 0x20
-       MNT_UNKNOWNPERMISSIONS            = 0x200000
-       MNT_UPDATE                        = 0x10000
-       MNT_VISFLAGMASK                   = 0xd7f0f7ff
-       MNT_WAIT                          = 0x1
-       MSG_CTRUNC                        = 0x20
-       MSG_DONTROUTE                     = 0x4
-       MSG_DONTWAIT                      = 0x80
-       MSG_EOF                           = 0x100
-       MSG_EOR                           = 0x8
-       MSG_FLUSH                         = 0x400
-       MSG_HAVEMORE                      = 0x2000
-       MSG_HOLD                          = 0x800
-       MSG_NEEDSA                        = 0x10000
-       MSG_NOSIGNAL                      = 0x80000
-       MSG_OOB                           = 0x1
-       MSG_PEEK                          = 0x2
-       MSG_RCVMORE                       = 0x4000
-       MSG_SEND                          = 0x1000
-       MSG_TRUNC                         = 0x10
-       MSG_WAITALL                       = 0x40
-       MSG_WAITSTREAM                    = 0x200
-       MS_ASYNC                          = 0x1
-       MS_DEACTIVATE                     = 0x8
-       MS_INVALIDATE                     = 0x2
-       MS_KILLPAGES                      = 0x4
-       MS_SYNC                           = 0x10
-       NAME_MAX                          = 0xff
-       NET_RT_DUMP                       = 0x1
-       NET_RT_DUMP2                      = 0x7
-       NET_RT_FLAGS                      = 0x2
-       NET_RT_FLAGS_PRIV                 = 0xa
-       NET_RT_IFLIST                     = 0x3
-       NET_RT_IFLIST2                    = 0x6
-       NET_RT_MAXID                      = 0xb
-       NET_RT_STAT                       = 0x4
-       NET_RT_TRASH                      = 0x5
-       NFDBITS                           = 0x20
-       NL0                               = 0x0
-       NL1                               = 0x100
-       NL2                               = 0x200
-       NL3                               = 0x300
-       NLDLY                             = 0x300
-       NOFLSH                            = 0x80000000
-       NOKERNINFO                        = 0x2000000
-       NOTE_ABSOLUTE                     = 0x8
-       NOTE_ATTRIB                       = 0x8
-       NOTE_BACKGROUND                   = 0x40
-       NOTE_CHILD                        = 0x4
-       NOTE_CRITICAL                     = 0x20
-       NOTE_DELETE                       = 0x1
-       NOTE_EXEC                         = 0x20000000
-       NOTE_EXIT                         = 0x80000000
-       NOTE_EXITSTATUS                   = 0x4000000
-       NOTE_EXIT_CSERROR                 = 0x40000
-       NOTE_EXIT_DECRYPTFAIL             = 0x10000
-       NOTE_EXIT_DETAIL                  = 0x2000000
-       NOTE_EXIT_DETAIL_MASK             = 0x70000
-       NOTE_EXIT_MEMORY                  = 0x20000
-       NOTE_EXIT_REPARENTED              = 0x80000
-       NOTE_EXTEND                       = 0x4
-       NOTE_FFAND                        = 0x40000000
-       NOTE_FFCOPY                       = 0xc0000000
-       NOTE_FFCTRLMASK                   = 0xc0000000
-       NOTE_FFLAGSMASK                   = 0xffffff
-       NOTE_FFNOP                        = 0x0
-       NOTE_FFOR                         = 0x80000000
-       NOTE_FORK                         = 0x40000000
-       NOTE_FUNLOCK                      = 0x100
-       NOTE_LEEWAY                       = 0x10
-       NOTE_LINK                         = 0x10
-       NOTE_LOWAT                        = 0x1
-       NOTE_MACHTIME                     = 0x100
-       NOTE_MACH_CONTINUOUS_TIME         = 0x80
-       NOTE_NONE                         = 0x80
-       NOTE_NSECONDS                     = 0x4
-       NOTE_OOB                          = 0x2
-       NOTE_PCTRLMASK                    = -0x100000
-       NOTE_PDATAMASK                    = 0xfffff
-       NOTE_REAP                         = 0x10000000
-       NOTE_RENAME                       = 0x20
-       NOTE_REVOKE                       = 0x40
-       NOTE_SECONDS                      = 0x1
-       NOTE_SIGNAL                       = 0x8000000
-       NOTE_TRACK                        = 0x1
-       NOTE_TRACKERR                     = 0x2
-       NOTE_TRIGGER                      = 0x1000000
-       NOTE_USECONDS                     = 0x2
-       NOTE_VM_ERROR                     = 0x10000000
-       NOTE_VM_PRESSURE                  = 0x80000000
-       NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000
-       NOTE_VM_PRESSURE_TERMINATE        = 0x40000000
-       NOTE_WRITE                        = 0x2
-       OCRNL                             = 0x10
-       OFDEL                             = 0x20000
-       OFILL                             = 0x80
-       ONLCR                             = 0x2
-       ONLRET                            = 0x40
-       ONOCR                             = 0x20
-       ONOEOT                            = 0x8
-       OPOST                             = 0x1
-       OXTABS                            = 0x4
-       O_ACCMODE                         = 0x3
-       O_ALERT                           = 0x20000000
-       O_APPEND                          = 0x8
-       O_ASYNC                           = 0x40
-       O_CLOEXEC                         = 0x1000000
-       O_CREAT                           = 0x200
-       O_DIRECTORY                       = 0x100000
-       O_DP_GETRAWENCRYPTED              = 0x1
-       O_DP_GETRAWUNENCRYPTED            = 0x2
-       O_DSYNC                           = 0x400000
-       O_EVTONLY                         = 0x8000
-       O_EXCL                            = 0x800
-       O_EXLOCK                          = 0x20
-       O_FSYNC                           = 0x80
-       O_NDELAY                          = 0x4
-       O_NOCTTY                          = 0x20000
-       O_NOFOLLOW                        = 0x100
-       O_NOFOLLOW_ANY                    = 0x20000000
-       O_NONBLOCK                        = 0x4
-       O_POPUP                           = 0x80000000
-       O_RDONLY                          = 0x0
-       O_RDWR                            = 0x2
-       O_SHLOCK                          = 0x10
-       O_SYMLINK                         = 0x200000
-       O_SYNC                            = 0x80
-       O_TRUNC                           = 0x400
-       O_WRONLY                          = 0x1
-       PARENB                            = 0x1000
-       PARMRK                            = 0x8
-       PARODD                            = 0x2000
-       PENDIN                            = 0x20000000
-       PRIO_PGRP                         = 0x1
-       PRIO_PROCESS                      = 0x0
-       PRIO_USER                         = 0x2
-       PROT_EXEC                         = 0x4
-       PROT_NONE                         = 0x0
-       PROT_READ                         = 0x1
-       PROT_WRITE                        = 0x2
-       PT_ATTACH                         = 0xa
-       PT_ATTACHEXC                      = 0xe
-       PT_CONTINUE                       = 0x7
-       PT_DENY_ATTACH                    = 0x1f
-       PT_DETACH                         = 0xb
-       PT_FIRSTMACH                      = 0x20
-       PT_FORCEQUOTA                     = 0x1e
-       PT_KILL                           = 0x8
-       PT_READ_D                         = 0x2
-       PT_READ_I                         = 0x1
-       PT_READ_U                         = 0x3
-       PT_SIGEXC                         = 0xc
-       PT_STEP                           = 0x9
-       PT_THUPDATE                       = 0xd
-       PT_TRACE_ME                       = 0x0
-       PT_WRITE_D                        = 0x5
-       PT_WRITE_I                        = 0x4
-       PT_WRITE_U                        = 0x6
-       RLIMIT_AS                         = 0x5
-       RLIMIT_CORE                       = 0x4
-       RLIMIT_CPU                        = 0x0
-       RLIMIT_CPU_USAGE_MONITOR          = 0x2
-       RLIMIT_DATA                       = 0x2
-       RLIMIT_FSIZE                      = 0x1
-       RLIMIT_MEMLOCK                    = 0x6
-       RLIMIT_NOFILE                     = 0x8
-       RLIMIT_NPROC                      = 0x7
-       RLIMIT_RSS                        = 0x5
-       RLIMIT_STACK                      = 0x3
-       RLIM_INFINITY                     = 0x7fffffffffffffff
-       RTAX_AUTHOR                       = 0x6
-       RTAX_BRD                          = 0x7
-       RTAX_DST                          = 0x0
-       RTAX_GATEWAY                      = 0x1
-       RTAX_GENMASK                      = 0x3
-       RTAX_IFA                          = 0x5
-       RTAX_IFP                          = 0x4
-       RTAX_MAX                          = 0x8
-       RTAX_NETMASK                      = 0x2
-       RTA_AUTHOR                        = 0x40
-       RTA_BRD                           = 0x80
-       RTA_DST                           = 0x1
-       RTA_GATEWAY                       = 0x2
-       RTA_GENMASK                       = 0x8
-       RTA_IFA                           = 0x20
-       RTA_IFP                           = 0x10
-       RTA_NETMASK                       = 0x4
-       RTF_BLACKHOLE                     = 0x1000
-       RTF_BROADCAST                     = 0x400000
-       RTF_CLONING                       = 0x100
-       RTF_CONDEMNED                     = 0x2000000
-       RTF_DEAD                          = 0x20000000
-       RTF_DELCLONE                      = 0x80
-       RTF_DONE                          = 0x40
-       RTF_DYNAMIC                       = 0x10
-       RTF_GATEWAY                       = 0x2
-       RTF_HOST                          = 0x4
-       RTF_IFREF                         = 0x4000000
-       RTF_IFSCOPE                       = 0x1000000
-       RTF_LLDATA                        = 0x400
-       RTF_LLINFO                        = 0x400
-       RTF_LOCAL                         = 0x200000
-       RTF_MODIFIED                      = 0x20
-       RTF_MULTICAST                     = 0x800000
-       RTF_NOIFREF                       = 0x2000
-       RTF_PINNED                        = 0x100000
-       RTF_PRCLONING                     = 0x10000
-       RTF_PROTO1                        = 0x8000
-       RTF_PROTO2                        = 0x4000
-       RTF_PROTO3                        = 0x40000
-       RTF_PROXY                         = 0x8000000
-       RTF_REJECT                        = 0x8
-       RTF_ROUTER                        = 0x10000000
-       RTF_STATIC                        = 0x800
-       RTF_UP                            = 0x1
-       RTF_WASCLONED                     = 0x20000
-       RTF_XRESOLVE                      = 0x200
-       RTM_ADD                           = 0x1
-       RTM_CHANGE                        = 0x3
-       RTM_DELADDR                       = 0xd
-       RTM_DELETE                        = 0x2
-       RTM_DELMADDR                      = 0x10
-       RTM_GET                           = 0x4
-       RTM_GET2                          = 0x14
-       RTM_IFINFO                        = 0xe
-       RTM_IFINFO2                       = 0x12
-       RTM_LOCK                          = 0x8
-       RTM_LOSING                        = 0x5
-       RTM_MISS                          = 0x7
-       RTM_NEWADDR                       = 0xc
-       RTM_NEWMADDR                      = 0xf
-       RTM_NEWMADDR2                     = 0x13
-       RTM_OLDADD                        = 0x9
-       RTM_OLDDEL                        = 0xa
-       RTM_REDIRECT                      = 0x6
-       RTM_RESOLVE                       = 0xb
-       RTM_RTTUNIT                       = 0xf4240
-       RTM_VERSION                       = 0x5
-       RTV_EXPIRE                        = 0x4
-       RTV_HOPCOUNT                      = 0x2
-       RTV_MTU                           = 0x1
-       RTV_RPIPE                         = 0x8
-       RTV_RTT                           = 0x40
-       RTV_RTTVAR                        = 0x80
-       RTV_SPIPE                         = 0x10
-       RTV_SSTHRESH                      = 0x20
-       RUSAGE_CHILDREN                   = -0x1
-       RUSAGE_SELF                       = 0x0
-       SCM_CREDS                         = 0x3
-       SCM_RIGHTS                        = 0x1
-       SCM_TIMESTAMP                     = 0x2
-       SCM_TIMESTAMP_MONOTONIC           = 0x4
-       SHUT_RD                           = 0x0
-       SHUT_RDWR                         = 0x2
-       SHUT_WR                           = 0x1
-       SIOCADDMULTI                      = 0x80206931
-       SIOCAIFADDR                       = 0x8040691a
-       SIOCARPIPLL                       = 0xc0206928
-       SIOCATMARK                        = 0x40047307
-       SIOCAUTOADDR                      = 0xc0206926
-       SIOCAUTONETMASK                   = 0x80206927
-       SIOCDELMULTI                      = 0x80206932
-       SIOCDIFADDR                       = 0x80206919
-       SIOCDIFPHYADDR                    = 0x80206941
-       SIOCGDRVSPEC                      = 0xc028697b
-       SIOCGETVLAN                       = 0xc020697f
-       SIOCGHIWAT                        = 0x40047301
-       SIOCGIF6LOWPAN                    = 0xc02069c5
-       SIOCGIFADDR                       = 0xc0206921
-       SIOCGIFALTMTU                     = 0xc0206948
-       SIOCGIFASYNCMAP                   = 0xc020697c
-       SIOCGIFBOND                       = 0xc0206947
-       SIOCGIFBRDADDR                    = 0xc0206923
-       SIOCGIFCAP                        = 0xc020695b
-       SIOCGIFCONF                       = 0xc00c6924
-       SIOCGIFDEVMTU                     = 0xc0206944
-       SIOCGIFDSTADDR                    = 0xc0206922
-       SIOCGIFFLAGS                      = 0xc0206911
-       SIOCGIFFUNCTIONALTYPE             = 0xc02069ad
-       SIOCGIFGENERIC                    = 0xc020693a
-       SIOCGIFKPI                        = 0xc0206987
-       SIOCGIFMAC                        = 0xc0206982
-       SIOCGIFMEDIA                      = 0xc02c6938
-       SIOCGIFMETRIC                     = 0xc0206917
-       SIOCGIFMTU                        = 0xc0206933
-       SIOCGIFNETMASK                    = 0xc0206925
-       SIOCGIFPDSTADDR                   = 0xc0206940
-       SIOCGIFPHYS                       = 0xc0206935
-       SIOCGIFPSRCADDR                   = 0xc020693f
-       SIOCGIFSTATUS                     = 0xc331693d
-       SIOCGIFVLAN                       = 0xc020697f
-       SIOCGIFWAKEFLAGS                  = 0xc0206988
-       SIOCGIFXMEDIA                     = 0xc02c6948
-       SIOCGLOWAT                        = 0x40047303
-       SIOCGPGRP                         = 0x40047309
-       SIOCIFCREATE                      = 0xc0206978
-       SIOCIFCREATE2                     = 0xc020697a
-       SIOCIFDESTROY                     = 0x80206979
-       SIOCIFGCLONERS                    = 0xc0106981
-       SIOCRSLVMULTI                     = 0xc010693b
-       SIOCSDRVSPEC                      = 0x8028697b
-       SIOCSETVLAN                       = 0x8020697e
-       SIOCSHIWAT                        = 0x80047300
-       SIOCSIF6LOWPAN                    = 0x802069c4
-       SIOCSIFADDR                       = 0x8020690c
-       SIOCSIFALTMTU                     = 0x80206945
-       SIOCSIFASYNCMAP                   = 0x8020697d
-       SIOCSIFBOND                       = 0x80206946
-       SIOCSIFBRDADDR                    = 0x80206913
-       SIOCSIFCAP                        = 0x8020695a
-       SIOCSIFDSTADDR                    = 0x8020690e
-       SIOCSIFFLAGS                      = 0x80206910
-       SIOCSIFGENERIC                    = 0x80206939
-       SIOCSIFKPI                        = 0x80206986
-       SIOCSIFLLADDR                     = 0x8020693c
-       SIOCSIFMAC                        = 0x80206983
-       SIOCSIFMEDIA                      = 0xc0206937
-       SIOCSIFMETRIC                     = 0x80206918
-       SIOCSIFMTU                        = 0x80206934
-       SIOCSIFNETMASK                    = 0x80206916
-       SIOCSIFPHYADDR                    = 0x8040693e
-       SIOCSIFPHYS                       = 0x80206936
-       SIOCSIFVLAN                       = 0x8020697e
-       SIOCSLOWAT                        = 0x80047302
-       SIOCSPGRP                         = 0x80047308
-       SOCK_DGRAM                        = 0x2
-       SOCK_MAXADDRLEN                   = 0xff
-       SOCK_RAW                          = 0x3
-       SOCK_RDM                          = 0x4
-       SOCK_SEQPACKET                    = 0x5
-       SOCK_STREAM                       = 0x1
-       SOL_LOCAL                         = 0x0
-       SOL_SOCKET                        = 0xffff
-       SOMAXCONN                         = 0x80
-       SO_ACCEPTCONN                     = 0x2
-       SO_BROADCAST                      = 0x20
-       SO_DEBUG                          = 0x1
-       SO_DONTROUTE                      = 0x10
-       SO_DONTTRUNC                      = 0x2000
-       SO_ERROR                          = 0x1007
-       SO_KEEPALIVE                      = 0x8
-       SO_LABEL                          = 0x1010
-       SO_LINGER                         = 0x80
-       SO_LINGER_SEC                     = 0x1080
-       SO_NETSVC_MARKING_LEVEL           = 0x1119
-       SO_NET_SERVICE_TYPE               = 0x1116
-       SO_NKE                            = 0x1021
-       SO_NOADDRERR                      = 0x1023
-       SO_NOSIGPIPE                      = 0x1022
-       SO_NOTIFYCONFLICT                 = 0x1026
-       SO_NP_EXTENSIONS                  = 0x1083
-       SO_NREAD                          = 0x1020
-       SO_NUMRCVPKT                      = 0x1112
-       SO_NWRITE                         = 0x1024
-       SO_OOBINLINE                      = 0x100
-       SO_PEERLABEL                      = 0x1011
-       SO_RANDOMPORT                     = 0x1082
-       SO_RCVBUF                         = 0x1002
-       SO_RCVLOWAT                       = 0x1004
-       SO_RCVTIMEO                       = 0x1006
-       SO_REUSEADDR                      = 0x4
-       SO_REUSEPORT                      = 0x200
-       SO_REUSESHAREUID                  = 0x1025
-       SO_SNDBUF                         = 0x1001
-       SO_SNDLOWAT                       = 0x1003
-       SO_SNDTIMEO                       = 0x1005
-       SO_TIMESTAMP                      = 0x400
-       SO_TIMESTAMP_MONOTONIC            = 0x800
-       SO_TYPE                           = 0x1008
-       SO_UPCALLCLOSEWAIT                = 0x1027
-       SO_USELOOPBACK                    = 0x40
-       SO_WANTMORE                       = 0x4000
-       SO_WANTOOBFLAG                    = 0x8000
-       S_IEXEC                           = 0x40
-       S_IFBLK                           = 0x6000
-       S_IFCHR                           = 0x2000
-       S_IFDIR                           = 0x4000
-       S_IFIFO                           = 0x1000
-       S_IFLNK                           = 0xa000
-       S_IFMT                            = 0xf000
-       S_IFREG                           = 0x8000
-       S_IFSOCK                          = 0xc000
-       S_IFWHT                           = 0xe000
-       S_IREAD                           = 0x100
-       S_IRGRP                           = 0x20
-       S_IROTH                           = 0x4
-       S_IRUSR                           = 0x100
-       S_IRWXG                           = 0x38
-       S_IRWXO                           = 0x7
-       S_IRWXU                           = 0x1c0
-       S_ISGID                           = 0x400
-       S_ISTXT                           = 0x200
-       S_ISUID                           = 0x800
-       S_ISVTX                           = 0x200
-       S_IWGRP                           = 0x10
-       S_IWOTH                           = 0x2
-       S_IWRITE                          = 0x80
-       S_IWUSR                           = 0x80
-       S_IXGRP                           = 0x8
-       S_IXOTH                           = 0x1
-       S_IXUSR                           = 0x40
-       TAB0                              = 0x0
-       TAB1                              = 0x400
-       TAB2                              = 0x800
-       TAB3                              = 0x4
-       TABDLY                            = 0xc04
-       TCIFLUSH                          = 0x1
-       TCIOFF                            = 0x3
-       TCIOFLUSH                         = 0x3
-       TCION                             = 0x4
-       TCOFLUSH                          = 0x2
-       TCOOFF                            = 0x1
-       TCOON                             = 0x2
-       TCP_CONNECTIONTIMEOUT             = 0x20
-       TCP_CONNECTION_INFO               = 0x106
-       TCP_ENABLE_ECN                    = 0x104
-       TCP_FASTOPEN                      = 0x105
-       TCP_KEEPALIVE                     = 0x10
-       TCP_KEEPCNT                       = 0x102
-       TCP_KEEPINTVL                     = 0x101
-       TCP_MAXHLEN                       = 0x3c
-       TCP_MAXOLEN                       = 0x28
-       TCP_MAXSEG                        = 0x2
-       TCP_MAXWIN                        = 0xffff
-       TCP_MAX_SACK                      = 0x4
-       TCP_MAX_WINSHIFT                  = 0xe
-       TCP_MINMSS                        = 0xd8
-       TCP_MSS                           = 0x200
-       TCP_NODELAY                       = 0x1
-       TCP_NOOPT                         = 0x8
-       TCP_NOPUSH                        = 0x4
-       TCP_NOTSENT_LOWAT                 = 0x201
-       TCP_RXT_CONNDROPTIME              = 0x80
-       TCP_RXT_FINDROP                   = 0x100
-       TCP_SENDMOREACKS                  = 0x103
-       TCSAFLUSH                         = 0x2
-       TIOCCBRK                          = 0x2000747a
-       TIOCCDTR                          = 0x20007478
-       TIOCCONS                          = 0x80047462
-       TIOCDCDTIMESTAMP                  = 0x40107458
-       TIOCDRAIN                         = 0x2000745e
-       TIOCDSIMICROCODE                  = 0x20007455
-       TIOCEXCL                          = 0x2000740d
-       TIOCEXT                           = 0x80047460
-       TIOCFLUSH                         = 0x80047410
-       TIOCGDRAINWAIT                    = 0x40047456
-       TIOCGETA                          = 0x40487413
-       TIOCGETD                          = 0x4004741a
-       TIOCGPGRP                         = 0x40047477
-       TIOCGWINSZ                        = 0x40087468
-       TIOCIXOFF                         = 0x20007480
-       TIOCIXON                          = 0x20007481
-       TIOCMBIC                          = 0x8004746b
-       TIOCMBIS                          = 0x8004746c
-       TIOCMGDTRWAIT                     = 0x4004745a
-       TIOCMGET                          = 0x4004746a
-       TIOCMODG                          = 0x40047403
-       TIOCMODS                          = 0x80047404
-       TIOCMSDTRWAIT                     = 0x8004745b
-       TIOCMSET                          = 0x8004746d
-       TIOCM_CAR                         = 0x40
-       TIOCM_CD                          = 0x40
-       TIOCM_CTS                         = 0x20
-       TIOCM_DSR                         = 0x100
-       TIOCM_DTR                         = 0x2
-       TIOCM_LE                          = 0x1
-       TIOCM_RI                          = 0x80
-       TIOCM_RNG                         = 0x80
-       TIOCM_RTS                         = 0x4
-       TIOCM_SR                          = 0x10
-       TIOCM_ST                          = 0x8
-       TIOCNOTTY                         = 0x20007471
-       TIOCNXCL                          = 0x2000740e
-       TIOCOUTQ                          = 0x40047473
-       TIOCPKT                           = 0x80047470
-       TIOCPKT_DATA                      = 0x0
-       TIOCPKT_DOSTOP                    = 0x20
-       TIOCPKT_FLUSHREAD                 = 0x1
-       TIOCPKT_FLUSHWRITE                = 0x2
-       TIOCPKT_IOCTL                     = 0x40
-       TIOCPKT_NOSTOP                    = 0x10
-       TIOCPKT_START                     = 0x8
-       TIOCPKT_STOP                      = 0x4
-       TIOCPTYGNAME                      = 0x40807453
-       TIOCPTYGRANT                      = 0x20007454
-       TIOCPTYUNLK                       = 0x20007452
-       TIOCREMOTE                        = 0x80047469
-       TIOCSBRK                          = 0x2000747b
-       TIOCSCONS                         = 0x20007463
-       TIOCSCTTY                         = 0x20007461
-       TIOCSDRAINWAIT                    = 0x80047457
-       TIOCSDTR                          = 0x20007479
-       TIOCSETA                          = 0x80487414
-       TIOCSETAF                         = 0x80487416
-       TIOCSETAW                         = 0x80487415
-       TIOCSETD                          = 0x8004741b
-       TIOCSIG                           = 0x2000745f
-       TIOCSPGRP                         = 0x80047476
-       TIOCSTART                         = 0x2000746e
-       TIOCSTAT                          = 0x20007465
-       TIOCSTI                           = 0x80017472
-       TIOCSTOP                          = 0x2000746f
-       TIOCSWINSZ                        = 0x80087467
-       TIOCTIMESTAMP                     = 0x40107459
-       TIOCUCNTL                         = 0x80047466
-       TOSTOP                            = 0x400000
-       VDISCARD                          = 0xf
-       VDSUSP                            = 0xb
-       VEOF                              = 0x0
-       VEOL                              = 0x1
-       VEOL2                             = 0x2
-       VERASE                            = 0x3
-       VINTR                             = 0x8
-       VKILL                             = 0x5
-       VLNEXT                            = 0xe
-       VMIN                              = 0x10
-       VM_LOADAVG                        = 0x2
-       VM_MACHFACTOR                     = 0x4
-       VM_MAXID                          = 0x6
-       VM_METER                          = 0x1
-       VM_SWAPUSAGE                      = 0x5
-       VQUIT                             = 0x9
-       VREPRINT                          = 0x6
-       VSTART                            = 0xc
-       VSTATUS                           = 0x12
-       VSTOP                             = 0xd
-       VSUSP                             = 0xa
-       VT0                               = 0x0
-       VT1                               = 0x10000
-       VTDLY                             = 0x10000
-       VTIME                             = 0x11
-       VWERASE                           = 0x4
-       WCONTINUED                        = 0x10
-       WCOREFLAG                         = 0x80
-       WEXITED                           = 0x4
-       WNOHANG                           = 0x1
-       WNOWAIT                           = 0x20
-       WORDSIZE                          = 0x40
-       WSTOPPED                          = 0x8
-       WUNTRACED                         = 0x2
-       XATTR_CREATE                      = 0x2
-       XATTR_NODEFAULT                   = 0x10
-       XATTR_NOFOLLOW                    = 0x1
-       XATTR_NOSECURITY                  = 0x8
-       XATTR_REPLACE                     = 0x4
-       XATTR_SHOWCOMPRESSION             = 0x20
+       AF_APPLETALK                            = 0x10
+       AF_CCITT                                = 0xa
+       AF_CHAOS                                = 0x5
+       AF_CNT                                  = 0x15
+       AF_COIP                                 = 0x14
+       AF_DATAKIT                              = 0x9
+       AF_DECnet                               = 0xc
+       AF_DLI                                  = 0xd
+       AF_E164                                 = 0x1c
+       AF_ECMA                                 = 0x8
+       AF_HYLINK                               = 0xf
+       AF_IEEE80211                            = 0x25
+       AF_IMPLINK                              = 0x3
+       AF_INET                                 = 0x2
+       AF_INET6                                = 0x1e
+       AF_IPX                                  = 0x17
+       AF_ISDN                                 = 0x1c
+       AF_ISO                                  = 0x7
+       AF_LAT                                  = 0xe
+       AF_LINK                                 = 0x12
+       AF_LOCAL                                = 0x1
+       AF_MAX                                  = 0x29
+       AF_NATM                                 = 0x1f
+       AF_NDRV                                 = 0x1b
+       AF_NETBIOS                              = 0x21
+       AF_NS                                   = 0x6
+       AF_OSI                                  = 0x7
+       AF_PPP                                  = 0x22
+       AF_PUP                                  = 0x4
+       AF_RESERVED_36                          = 0x24
+       AF_ROUTE                                = 0x11
+       AF_SIP                                  = 0x18
+       AF_SNA                                  = 0xb
+       AF_SYSTEM                               = 0x20
+       AF_SYS_CONTROL                          = 0x2
+       AF_UNIX                                 = 0x1
+       AF_UNSPEC                               = 0x0
+       AF_UTUN                                 = 0x26
+       AF_VSOCK                                = 0x28
+       ALTWERASE                               = 0x200
+       ATTR_BIT_MAP_COUNT                      = 0x5
+       ATTR_CMN_ACCESSMASK                     = 0x20000
+       ATTR_CMN_ACCTIME                        = 0x1000
+       ATTR_CMN_ADDEDTIME                      = 0x10000000
+       ATTR_CMN_BKUPTIME                       = 0x2000
+       ATTR_CMN_CHGTIME                        = 0x800
+       ATTR_CMN_CRTIME                         = 0x200
+       ATTR_CMN_DATA_PROTECT_FLAGS             = 0x40000000
+       ATTR_CMN_DEVID                          = 0x2
+       ATTR_CMN_DOCUMENT_ID                    = 0x100000
+       ATTR_CMN_ERROR                          = 0x20000000
+       ATTR_CMN_EXTENDED_SECURITY              = 0x400000
+       ATTR_CMN_FILEID                         = 0x2000000
+       ATTR_CMN_FLAGS                          = 0x40000
+       ATTR_CMN_FNDRINFO                       = 0x4000
+       ATTR_CMN_FSID                           = 0x4
+       ATTR_CMN_FULLPATH                       = 0x8000000
+       ATTR_CMN_GEN_COUNT                      = 0x80000
+       ATTR_CMN_GRPID                          = 0x10000
+       ATTR_CMN_GRPUUID                        = 0x1000000
+       ATTR_CMN_MODTIME                        = 0x400
+       ATTR_CMN_NAME                           = 0x1
+       ATTR_CMN_NAMEDATTRCOUNT                 = 0x80000
+       ATTR_CMN_NAMEDATTRLIST                  = 0x100000
+       ATTR_CMN_OBJID                          = 0x20
+       ATTR_CMN_OBJPERMANENTID                 = 0x40
+       ATTR_CMN_OBJTAG                         = 0x10
+       ATTR_CMN_OBJTYPE                        = 0x8
+       ATTR_CMN_OWNERID                        = 0x8000
+       ATTR_CMN_PARENTID                       = 0x4000000
+       ATTR_CMN_PAROBJID                       = 0x80
+       ATTR_CMN_RETURNED_ATTRS                 = 0x80000000
+       ATTR_CMN_SCRIPT                         = 0x100
+       ATTR_CMN_SETMASK                        = 0x51c7ff00
+       ATTR_CMN_USERACCESS                     = 0x200000
+       ATTR_CMN_UUID                           = 0x800000
+       ATTR_CMN_VALIDMASK                      = 0xffffffff
+       ATTR_CMN_VOLSETMASK                     = 0x6700
+       ATTR_FILE_ALLOCSIZE                     = 0x4
+       ATTR_FILE_CLUMPSIZE                     = 0x10
+       ATTR_FILE_DATAALLOCSIZE                 = 0x400
+       ATTR_FILE_DATAEXTENTS                   = 0x800
+       ATTR_FILE_DATALENGTH                    = 0x200
+       ATTR_FILE_DEVTYPE                       = 0x20
+       ATTR_FILE_FILETYPE                      = 0x40
+       ATTR_FILE_FORKCOUNT                     = 0x80
+       ATTR_FILE_FORKLIST                      = 0x100
+       ATTR_FILE_IOBLOCKSIZE                   = 0x8
+       ATTR_FILE_LINKCOUNT                     = 0x1
+       ATTR_FILE_RSRCALLOCSIZE                 = 0x2000
+       ATTR_FILE_RSRCEXTENTS                   = 0x4000
+       ATTR_FILE_RSRCLENGTH                    = 0x1000
+       ATTR_FILE_SETMASK                       = 0x20
+       ATTR_FILE_TOTALSIZE                     = 0x2
+       ATTR_FILE_VALIDMASK                     = 0x37ff
+       ATTR_VOL_ALLOCATIONCLUMP                = 0x40
+       ATTR_VOL_ATTRIBUTES                     = 0x40000000
+       ATTR_VOL_CAPABILITIES                   = 0x20000
+       ATTR_VOL_DIRCOUNT                       = 0x400
+       ATTR_VOL_ENCODINGSUSED                  = 0x10000
+       ATTR_VOL_FILECOUNT                      = 0x200
+       ATTR_VOL_FSTYPE                         = 0x1
+       ATTR_VOL_INFO                           = 0x80000000
+       ATTR_VOL_IOBLOCKSIZE                    = 0x80
+       ATTR_VOL_MAXOBJCOUNT                    = 0x800
+       ATTR_VOL_MINALLOCATION                  = 0x20
+       ATTR_VOL_MOUNTEDDEVICE                  = 0x8000
+       ATTR_VOL_MOUNTFLAGS                     = 0x4000
+       ATTR_VOL_MOUNTPOINT                     = 0x1000
+       ATTR_VOL_NAME                           = 0x2000
+       ATTR_VOL_OBJCOUNT                       = 0x100
+       ATTR_VOL_QUOTA_SIZE                     = 0x10000000
+       ATTR_VOL_RESERVED_SIZE                  = 0x20000000
+       ATTR_VOL_SETMASK                        = 0x80002000
+       ATTR_VOL_SIGNATURE                      = 0x2
+       ATTR_VOL_SIZE                           = 0x4
+       ATTR_VOL_SPACEAVAIL                     = 0x10
+       ATTR_VOL_SPACEFREE                      = 0x8
+       ATTR_VOL_SPACEUSED                      = 0x800000
+       ATTR_VOL_UUID                           = 0x40000
+       ATTR_VOL_VALIDMASK                      = 0xf087ffff
+       B0                                      = 0x0
+       B110                                    = 0x6e
+       B115200                                 = 0x1c200
+       B1200                                   = 0x4b0
+       B134                                    = 0x86
+       B14400                                  = 0x3840
+       B150                                    = 0x96
+       B1800                                   = 0x708
+       B19200                                  = 0x4b00
+       B200                                    = 0xc8
+       B230400                                 = 0x38400
+       B2400                                   = 0x960
+       B28800                                  = 0x7080
+       B300                                    = 0x12c
+       B38400                                  = 0x9600
+       B4800                                   = 0x12c0
+       B50                                     = 0x32
+       B57600                                  = 0xe100
+       B600                                    = 0x258
+       B7200                                   = 0x1c20
+       B75                                     = 0x4b
+       B76800                                  = 0x12c00
+       B9600                                   = 0x2580
+       BIOCFLUSH                               = 0x20004268
+       BIOCGBLEN                               = 0x40044266
+       BIOCGDLT                                = 0x4004426a
+       BIOCGDLTLIST                            = 0xc00c4279
+       BIOCGETIF                               = 0x4020426b
+       BIOCGHDRCMPLT                           = 0x40044274
+       BIOCGRSIG                               = 0x40044272
+       BIOCGRTIMEOUT                           = 0x4010426e
+       BIOCGSEESENT                            = 0x40044276
+       BIOCGSTATS                              = 0x4008426f
+       BIOCIMMEDIATE                           = 0x80044270
+       BIOCPROMISC                             = 0x20004269
+       BIOCSBLEN                               = 0xc0044266
+       BIOCSDLT                                = 0x80044278
+       BIOCSETF                                = 0x80104267
+       BIOCSETFNR                              = 0x8010427e
+       BIOCSETIF                               = 0x8020426c
+       BIOCSHDRCMPLT                           = 0x80044275
+       BIOCSRSIG                               = 0x80044273
+       BIOCSRTIMEOUT                           = 0x8010426d
+       BIOCSSEESENT                            = 0x80044277
+       BIOCVERSION                             = 0x40044271
+       BPF_A                                   = 0x10
+       BPF_ABS                                 = 0x20
+       BPF_ADD                                 = 0x0
+       BPF_ALIGNMENT                           = 0x4
+       BPF_ALU                                 = 0x4
+       BPF_AND                                 = 0x50
+       BPF_B                                   = 0x10
+       BPF_DIV                                 = 0x30
+       BPF_H                                   = 0x8
+       BPF_IMM                                 = 0x0
+       BPF_IND                                 = 0x40
+       BPF_JA                                  = 0x0
+       BPF_JEQ                                 = 0x10
+       BPF_JGE                                 = 0x30
+       BPF_JGT                                 = 0x20
+       BPF_JMP                                 = 0x5
+       BPF_JSET                                = 0x40
+       BPF_K                                   = 0x0
+       BPF_LD                                  = 0x0
+       BPF_LDX                                 = 0x1
+       BPF_LEN                                 = 0x80
+       BPF_LSH                                 = 0x60
+       BPF_MAJOR_VERSION                       = 0x1
+       BPF_MAXBUFSIZE                          = 0x80000
+       BPF_MAXINSNS                            = 0x200
+       BPF_MEM                                 = 0x60
+       BPF_MEMWORDS                            = 0x10
+       BPF_MINBUFSIZE                          = 0x20
+       BPF_MINOR_VERSION                       = 0x1
+       BPF_MISC                                = 0x7
+       BPF_MSH                                 = 0xa0
+       BPF_MUL                                 = 0x20
+       BPF_NEG                                 = 0x80
+       BPF_OR                                  = 0x40
+       BPF_RELEASE                             = 0x30bb6
+       BPF_RET                                 = 0x6
+       BPF_RSH                                 = 0x70
+       BPF_ST                                  = 0x2
+       BPF_STX                                 = 0x3
+       BPF_SUB                                 = 0x10
+       BPF_TAX                                 = 0x0
+       BPF_TXA                                 = 0x80
+       BPF_W                                   = 0x0
+       BPF_X                                   = 0x8
+       BRKINT                                  = 0x2
+       BS0                                     = 0x0
+       BS1                                     = 0x8000
+       BSDLY                                   = 0x8000
+       CFLUSH                                  = 0xf
+       CLOCAL                                  = 0x8000
+       CLOCK_MONOTONIC                         = 0x6
+       CLOCK_MONOTONIC_RAW                     = 0x4
+       CLOCK_MONOTONIC_RAW_APPROX              = 0x5
+       CLOCK_PROCESS_CPUTIME_ID                = 0xc
+       CLOCK_REALTIME                          = 0x0
+       CLOCK_THREAD_CPUTIME_ID                 = 0x10
+       CLOCK_UPTIME_RAW                        = 0x8
+       CLOCK_UPTIME_RAW_APPROX                 = 0x9
+       CLONE_NOFOLLOW                          = 0x1
+       CLONE_NOOWNERCOPY                       = 0x2
+       CR0                                     = 0x0
+       CR1                                     = 0x1000
+       CR2                                     = 0x2000
+       CR3                                     = 0x3000
+       CRDLY                                   = 0x3000
+       CREAD                                   = 0x800
+       CRTSCTS                                 = 0x30000
+       CS5                                     = 0x0
+       CS6                                     = 0x100
+       CS7                                     = 0x200
+       CS8                                     = 0x300
+       CSIZE                                   = 0x300
+       CSTART                                  = 0x11
+       CSTATUS                                 = 0x14
+       CSTOP                                   = 0x13
+       CSTOPB                                  = 0x400
+       CSUSP                                   = 0x1a
+       CTLIOCGINFO                             = 0xc0644e03
+       CTL_HW                                  = 0x6
+       CTL_KERN                                = 0x1
+       CTL_MAXNAME                             = 0xc
+       CTL_NET                                 = 0x4
+       DLT_A429                                = 0xb8
+       DLT_A653_ICM                            = 0xb9
+       DLT_AIRONET_HEADER                      = 0x78
+       DLT_AOS                                 = 0xde
+       DLT_APPLE_IP_OVER_IEEE1394              = 0x8a
+       DLT_ARCNET                              = 0x7
+       DLT_ARCNET_LINUX                        = 0x81
+       DLT_ATM_CLIP                            = 0x13
+       DLT_ATM_RFC1483                         = 0xb
+       DLT_AURORA                              = 0x7e
+       DLT_AX25                                = 0x3
+       DLT_AX25_KISS                           = 0xca
+       DLT_BACNET_MS_TP                        = 0xa5
+       DLT_BLUETOOTH_HCI_H4                    = 0xbb
+       DLT_BLUETOOTH_HCI_H4_WITH_PHDR          = 0xc9
+       DLT_CAN20B                              = 0xbe
+       DLT_CAN_SOCKETCAN                       = 0xe3
+       DLT_CHAOS                               = 0x5
+       DLT_CHDLC                               = 0x68
+       DLT_CISCO_IOS                           = 0x76
+       DLT_C_HDLC                              = 0x68
+       DLT_C_HDLC_WITH_DIR                     = 0xcd
+       DLT_DBUS                                = 0xe7
+       DLT_DECT                                = 0xdd
+       DLT_DOCSIS                              = 0x8f
+       DLT_DVB_CI                              = 0xeb
+       DLT_ECONET                              = 0x73
+       DLT_EN10MB                              = 0x1
+       DLT_EN3MB                               = 0x2
+       DLT_ENC                                 = 0x6d
+       DLT_ERF                                 = 0xc5
+       DLT_ERF_ETH                             = 0xaf
+       DLT_ERF_POS                             = 0xb0
+       DLT_FC_2                                = 0xe0
+       DLT_FC_2_WITH_FRAME_DELIMS              = 0xe1
+       DLT_FDDI                                = 0xa
+       DLT_FLEXRAY                             = 0xd2
+       DLT_FRELAY                              = 0x6b
+       DLT_FRELAY_WITH_DIR                     = 0xce
+       DLT_GCOM_SERIAL                         = 0xad
+       DLT_GCOM_T1E1                           = 0xac
+       DLT_GPF_F                               = 0xab
+       DLT_GPF_T                               = 0xaa
+       DLT_GPRS_LLC                            = 0xa9
+       DLT_GSMTAP_ABIS                         = 0xda
+       DLT_GSMTAP_UM                           = 0xd9
+       DLT_HHDLC                               = 0x79
+       DLT_IBM_SN                              = 0x92
+       DLT_IBM_SP                              = 0x91
+       DLT_IEEE802                             = 0x6
+       DLT_IEEE802_11                          = 0x69
+       DLT_IEEE802_11_RADIO                    = 0x7f
+       DLT_IEEE802_11_RADIO_AVS                = 0xa3
+       DLT_IEEE802_15_4                        = 0xc3
+       DLT_IEEE802_15_4_LINUX                  = 0xbf
+       DLT_IEEE802_15_4_NOFCS                  = 0xe6
+       DLT_IEEE802_15_4_NONASK_PHY             = 0xd7
+       DLT_IEEE802_16_MAC_CPS                  = 0xbc
+       DLT_IEEE802_16_MAC_CPS_RADIO            = 0xc1
+       DLT_IPFILTER                            = 0x74
+       DLT_IPMB                                = 0xc7
+       DLT_IPMB_LINUX                          = 0xd1
+       DLT_IPNET                               = 0xe2
+       DLT_IPOIB                               = 0xf2
+       DLT_IPV4                                = 0xe4
+       DLT_IPV6                                = 0xe5
+       DLT_IP_OVER_FC                          = 0x7a
+       DLT_JUNIPER_ATM1                        = 0x89
+       DLT_JUNIPER_ATM2                        = 0x87
+       DLT_JUNIPER_ATM_CEMIC                   = 0xee
+       DLT_JUNIPER_CHDLC                       = 0xb5
+       DLT_JUNIPER_ES                          = 0x84
+       DLT_JUNIPER_ETHER                       = 0xb2
+       DLT_JUNIPER_FIBRECHANNEL                = 0xea
+       DLT_JUNIPER_FRELAY                      = 0xb4
+       DLT_JUNIPER_GGSN                        = 0x85
+       DLT_JUNIPER_ISM                         = 0xc2
+       DLT_JUNIPER_MFR                         = 0x86
+       DLT_JUNIPER_MLFR                        = 0x83
+       DLT_JUNIPER_MLPPP                       = 0x82
+       DLT_JUNIPER_MONITOR                     = 0xa4
+       DLT_JUNIPER_PIC_PEER                    = 0xae
+       DLT_JUNIPER_PPP                         = 0xb3
+       DLT_JUNIPER_PPPOE                       = 0xa7
+       DLT_JUNIPER_PPPOE_ATM                   = 0xa8
+       DLT_JUNIPER_SERVICES                    = 0x88
+       DLT_JUNIPER_SRX_E2E                     = 0xe9
+       DLT_JUNIPER_ST                          = 0xc8
+       DLT_JUNIPER_VP                          = 0xb7
+       DLT_JUNIPER_VS                          = 0xe8
+       DLT_LAPB_WITH_DIR                       = 0xcf
+       DLT_LAPD                                = 0xcb
+       DLT_LIN                                 = 0xd4
+       DLT_LINUX_EVDEV                         = 0xd8
+       DLT_LINUX_IRDA                          = 0x90
+       DLT_LINUX_LAPD                          = 0xb1
+       DLT_LINUX_PPP_WITHDIRECTION             = 0xa6
+       DLT_LINUX_SLL                           = 0x71
+       DLT_LOOP                                = 0x6c
+       DLT_LTALK                               = 0x72
+       DLT_MATCHING_MAX                        = 0x10a
+       DLT_MATCHING_MIN                        = 0x68
+       DLT_MFR                                 = 0xb6
+       DLT_MOST                                = 0xd3
+       DLT_MPEG_2_TS                           = 0xf3
+       DLT_MPLS                                = 0xdb
+       DLT_MTP2                                = 0x8c
+       DLT_MTP2_WITH_PHDR                      = 0x8b
+       DLT_MTP3                                = 0x8d
+       DLT_MUX27010                            = 0xec
+       DLT_NETANALYZER                         = 0xf0
+       DLT_NETANALYZER_TRANSPARENT             = 0xf1
+       DLT_NFC_LLCP                            = 0xf5
+       DLT_NFLOG                               = 0xef
+       DLT_NG40                                = 0xf4
+       DLT_NULL                                = 0x0
+       DLT_PCI_EXP                             = 0x7d
+       DLT_PFLOG                               = 0x75
+       DLT_PFSYNC                              = 0x12
+       DLT_PPI                                 = 0xc0
+       DLT_PPP                                 = 0x9
+       DLT_PPP_BSDOS                           = 0x10
+       DLT_PPP_ETHER                           = 0x33
+       DLT_PPP_PPPD                            = 0xa6
+       DLT_PPP_SERIAL                          = 0x32
+       DLT_PPP_WITH_DIR                        = 0xcc
+       DLT_PPP_WITH_DIRECTION                  = 0xa6
+       DLT_PRISM_HEADER                        = 0x77
+       DLT_PRONET                              = 0x4
+       DLT_RAIF1                               = 0xc6
+       DLT_RAW                                 = 0xc
+       DLT_RIO                                 = 0x7c
+       DLT_SCCP                                = 0x8e
+       DLT_SITA                                = 0xc4
+       DLT_SLIP                                = 0x8
+       DLT_SLIP_BSDOS                          = 0xf
+       DLT_STANAG_5066_D_PDU                   = 0xed
+       DLT_SUNATM                              = 0x7b
+       DLT_SYMANTEC_FIREWALL                   = 0x63
+       DLT_TZSP                                = 0x80
+       DLT_USB                                 = 0xba
+       DLT_USB_DARWIN                          = 0x10a
+       DLT_USB_LINUX                           = 0xbd
+       DLT_USB_LINUX_MMAPPED                   = 0xdc
+       DLT_USER0                               = 0x93
+       DLT_USER1                               = 0x94
+       DLT_USER10                              = 0x9d
+       DLT_USER11                              = 0x9e
+       DLT_USER12                              = 0x9f
+       DLT_USER13                              = 0xa0
+       DLT_USER14                              = 0xa1
+       DLT_USER15                              = 0xa2
+       DLT_USER2                               = 0x95
+       DLT_USER3                               = 0x96
+       DLT_USER4                               = 0x97
+       DLT_USER5                               = 0x98
+       DLT_USER6                               = 0x99
+       DLT_USER7                               = 0x9a
+       DLT_USER8                               = 0x9b
+       DLT_USER9                               = 0x9c
+       DLT_WIHART                              = 0xdf
+       DLT_X2E_SERIAL                          = 0xd5
+       DLT_X2E_XORAYA                          = 0xd6
+       DT_BLK                                  = 0x6
+       DT_CHR                                  = 0x2
+       DT_DIR                                  = 0x4
+       DT_FIFO                                 = 0x1
+       DT_LNK                                  = 0xa
+       DT_REG                                  = 0x8
+       DT_SOCK                                 = 0xc
+       DT_UNKNOWN                              = 0x0
+       DT_WHT                                  = 0xe
+       ECHO                                    = 0x8
+       ECHOCTL                                 = 0x40
+       ECHOE                                   = 0x2
+       ECHOK                                   = 0x4
+       ECHOKE                                  = 0x1
+       ECHONL                                  = 0x10
+       ECHOPRT                                 = 0x20
+       EVFILT_AIO                              = -0x3
+       EVFILT_EXCEPT                           = -0xf
+       EVFILT_FS                               = -0x9
+       EVFILT_MACHPORT                         = -0x8
+       EVFILT_PROC                             = -0x5
+       EVFILT_READ                             = -0x1
+       EVFILT_SIGNAL                           = -0x6
+       EVFILT_SYSCOUNT                         = 0x11
+       EVFILT_THREADMARKER                     = 0x11
+       EVFILT_TIMER                            = -0x7
+       EVFILT_USER                             = -0xa
+       EVFILT_VM                               = -0xc
+       EVFILT_VNODE                            = -0x4
+       EVFILT_WRITE                            = -0x2
+       EV_ADD                                  = 0x1
+       EV_CLEAR                                = 0x20
+       EV_DELETE                               = 0x2
+       EV_DISABLE                              = 0x8
+       EV_DISPATCH                             = 0x80
+       EV_DISPATCH2                            = 0x180
+       EV_ENABLE                               = 0x4
+       EV_EOF                                  = 0x8000
+       EV_ERROR                                = 0x4000
+       EV_FLAG0                                = 0x1000
+       EV_FLAG1                                = 0x2000
+       EV_ONESHOT                              = 0x10
+       EV_OOBAND                               = 0x2000
+       EV_POLL                                 = 0x1000
+       EV_RECEIPT                              = 0x40
+       EV_SYSFLAGS                             = 0xf000
+       EV_UDATA_SPECIFIC                       = 0x100
+       EV_VANISHED                             = 0x200
+       EXTA                                    = 0x4b00
+       EXTB                                    = 0x9600
+       EXTPROC                                 = 0x800
+       FD_CLOEXEC                              = 0x1
+       FD_SETSIZE                              = 0x400
+       FF0                                     = 0x0
+       FF1                                     = 0x4000
+       FFDLY                                   = 0x4000
+       FLUSHO                                  = 0x800000
+       FSOPT_ATTR_CMN_EXTENDED                 = 0x20
+       FSOPT_NOFOLLOW                          = 0x1
+       FSOPT_NOINMEMUPDATE                     = 0x2
+       FSOPT_PACK_INVAL_ATTRS                  = 0x8
+       FSOPT_REPORT_FULLSIZE                   = 0x4
+       FSOPT_RETURN_REALDEV                    = 0x200
+       F_ADDFILESIGS                           = 0x3d
+       F_ADDFILESIGS_FOR_DYLD_SIM              = 0x53
+       F_ADDFILESIGS_INFO                      = 0x67
+       F_ADDFILESIGS_RETURN                    = 0x61
+       F_ADDFILESUPPL                          = 0x68
+       F_ADDSIGS                               = 0x3b
+       F_ALLOCATEALL                           = 0x4
+       F_ALLOCATECONTIG                        = 0x2
+       F_BARRIERFSYNC                          = 0x55
+       F_CHECK_LV                              = 0x62
+       F_CHKCLEAN                              = 0x29
+       F_DUPFD                                 = 0x0
+       F_DUPFD_CLOEXEC                         = 0x43
+       F_FINDSIGS                              = 0x4e
+       F_FLUSH_DATA                            = 0x28
+       F_FREEZE_FS                             = 0x35
+       F_FULLFSYNC                             = 0x33
+       F_GETCODEDIR                            = 0x48
+       F_GETFD                                 = 0x1
+       F_GETFL                                 = 0x3
+       F_GETLK                                 = 0x7
+       F_GETLKPID                              = 0x42
+       F_GETNOSIGPIPE                          = 0x4a
+       F_GETOWN                                = 0x5
+       F_GETPATH                               = 0x32
+       F_GETPATH_MTMINFO                       = 0x47
+       F_GETPATH_NOFIRMLINK                    = 0x66
+       F_GETPROTECTIONCLASS                    = 0x3f
+       F_GETPROTECTIONLEVEL                    = 0x4d
+       F_GETSIGSINFO                           = 0x69
+       F_GLOBAL_NOCACHE                        = 0x37
+       F_LOG2PHYS                              = 0x31
+       F_LOG2PHYS_EXT                          = 0x41
+       F_NOCACHE                               = 0x30
+       F_NODIRECT                              = 0x3e
+       F_OK                                    = 0x0
+       F_PATHPKG_CHECK                         = 0x34
+       F_PEOFPOSMODE                           = 0x3
+       F_PREALLOCATE                           = 0x2a
+       F_PUNCHHOLE                             = 0x63
+       F_RDADVISE                              = 0x2c
+       F_RDAHEAD                               = 0x2d
+       F_RDLCK                                 = 0x1
+       F_SETBACKINGSTORE                       = 0x46
+       F_SETFD                                 = 0x2
+       F_SETFL                                 = 0x4
+       F_SETLK                                 = 0x8
+       F_SETLKW                                = 0x9
+       F_SETLKWTIMEOUT                         = 0xa
+       F_SETNOSIGPIPE                          = 0x49
+       F_SETOWN                                = 0x6
+       F_SETPROTECTIONCLASS                    = 0x40
+       F_SETSIZE                               = 0x2b
+       F_SINGLE_WRITER                         = 0x4c
+       F_SPECULATIVE_READ                      = 0x65
+       F_THAW_FS                               = 0x36
+       F_TRANSCODEKEY                          = 0x4b
+       F_TRIM_ACTIVE_FILE                      = 0x64
+       F_UNLCK                                 = 0x2
+       F_VOLPOSMODE                            = 0x4
+       F_WRLCK                                 = 0x3
+       HUPCL                                   = 0x4000
+       HW_MACHINE                              = 0x1
+       ICANON                                  = 0x100
+       ICMP6_FILTER                            = 0x12
+       ICRNL                                   = 0x100
+       IEXTEN                                  = 0x400
+       IFF_ALLMULTI                            = 0x200
+       IFF_ALTPHYS                             = 0x4000
+       IFF_BROADCAST                           = 0x2
+       IFF_DEBUG                               = 0x4
+       IFF_LINK0                               = 0x1000
+       IFF_LINK1                               = 0x2000
+       IFF_LINK2                               = 0x4000
+       IFF_LOOPBACK                            = 0x8
+       IFF_MULTICAST                           = 0x8000
+       IFF_NOARP                               = 0x80
+       IFF_NOTRAILERS                          = 0x20
+       IFF_OACTIVE                             = 0x400
+       IFF_POINTOPOINT                         = 0x10
+       IFF_PROMISC                             = 0x100
+       IFF_RUNNING                             = 0x40
+       IFF_SIMPLEX                             = 0x800
+       IFF_UP                                  = 0x1
+       IFNAMSIZ                                = 0x10
+       IFT_1822                                = 0x2
+       IFT_6LOWPAN                             = 0x40
+       IFT_AAL5                                = 0x31
+       IFT_ARCNET                              = 0x23
+       IFT_ARCNETPLUS                          = 0x24
+       IFT_ATM                                 = 0x25
+       IFT_BRIDGE                              = 0xd1
+       IFT_CARP                                = 0xf8
+       IFT_CELLULAR                            = 0xff
+       IFT_CEPT                                = 0x13
+       IFT_DS3                                 = 0x1e
+       IFT_ENC                                 = 0xf4
+       IFT_EON                                 = 0x19
+       IFT_ETHER                               = 0x6
+       IFT_FAITH                               = 0x38
+       IFT_FDDI                                = 0xf
+       IFT_FRELAY                              = 0x20
+       IFT_FRELAYDCE                           = 0x2c
+       IFT_GIF                                 = 0x37
+       IFT_HDH1822                             = 0x3
+       IFT_HIPPI                               = 0x2f
+       IFT_HSSI                                = 0x2e
+       IFT_HY                                  = 0xe
+       IFT_IEEE1394                            = 0x90
+       IFT_IEEE8023ADLAG                       = 0x88
+       IFT_ISDNBASIC                           = 0x14
+       IFT_ISDNPRIMARY                         = 0x15
+       IFT_ISO88022LLC                         = 0x29
+       IFT_ISO88023                            = 0x7
+       IFT_ISO88024                            = 0x8
+       IFT_ISO88025                            = 0x9
+       IFT_ISO88026                            = 0xa
+       IFT_L2VLAN                              = 0x87
+       IFT_LAPB                                = 0x10
+       IFT_LOCALTALK                           = 0x2a
+       IFT_LOOP                                = 0x18
+       IFT_MIOX25                              = 0x26
+       IFT_MODEM                               = 0x30
+       IFT_NSIP                                = 0x1b
+       IFT_OTHER                               = 0x1
+       IFT_P10                                 = 0xc
+       IFT_P80                                 = 0xd
+       IFT_PARA                                = 0x22
+       IFT_PDP                                 = 0xff
+       IFT_PFLOG                               = 0xf5
+       IFT_PFSYNC                              = 0xf6
+       IFT_PKTAP                               = 0xfe
+       IFT_PPP                                 = 0x17
+       IFT_PROPMUX                             = 0x36
+       IFT_PROPVIRTUAL                         = 0x35
+       IFT_PTPSERIAL                           = 0x16
+       IFT_RS232                               = 0x21
+       IFT_SDLC                                = 0x11
+       IFT_SIP                                 = 0x1f
+       IFT_SLIP                                = 0x1c
+       IFT_SMDSDXI                             = 0x2b
+       IFT_SMDSICIP                            = 0x34
+       IFT_SONET                               = 0x27
+       IFT_SONETPATH                           = 0x32
+       IFT_SONETVT                             = 0x33
+       IFT_STARLAN                             = 0xb
+       IFT_STF                                 = 0x39
+       IFT_T1                                  = 0x12
+       IFT_ULTRA                               = 0x1d
+       IFT_V35                                 = 0x2d
+       IFT_X25                                 = 0x5
+       IFT_X25DDN                              = 0x4
+       IFT_X25PLE                              = 0x28
+       IFT_XETHER                              = 0x1a
+       IGNBRK                                  = 0x1
+       IGNCR                                   = 0x80
+       IGNPAR                                  = 0x4
+       IMAXBEL                                 = 0x2000
+       INLCR                                   = 0x40
+       INPCK                                   = 0x10
+       IN_CLASSA_HOST                          = 0xffffff
+       IN_CLASSA_MAX                           = 0x80
+       IN_CLASSA_NET                           = 0xff000000
+       IN_CLASSA_NSHIFT                        = 0x18
+       IN_CLASSB_HOST                          = 0xffff
+       IN_CLASSB_MAX                           = 0x10000
+       IN_CLASSB_NET                           = 0xffff0000
+       IN_CLASSB_NSHIFT                        = 0x10
+       IN_CLASSC_HOST                          = 0xff
+       IN_CLASSC_NET                           = 0xffffff00
+       IN_CLASSC_NSHIFT                        = 0x8
+       IN_CLASSD_HOST                          = 0xfffffff
+       IN_CLASSD_NET                           = 0xf0000000
+       IN_CLASSD_NSHIFT                        = 0x1c
+       IN_LINKLOCALNETNUM                      = 0xa9fe0000
+       IN_LOOPBACKNET                          = 0x7f
+       IOCTL_VM_SOCKETS_GET_LOCAL_CID          = 0x400473d1
+       IPPROTO_3PC                             = 0x22
+       IPPROTO_ADFS                            = 0x44
+       IPPROTO_AH                              = 0x33
+       IPPROTO_AHIP                            = 0x3d
+       IPPROTO_APES                            = 0x63
+       IPPROTO_ARGUS                           = 0xd
+       IPPROTO_AX25                            = 0x5d
+       IPPROTO_BHA                             = 0x31
+       IPPROTO_BLT                             = 0x1e
+       IPPROTO_BRSATMON                        = 0x4c
+       IPPROTO_CFTP                            = 0x3e
+       IPPROTO_CHAOS                           = 0x10
+       IPPROTO_CMTP                            = 0x26
+       IPPROTO_CPHB                            = 0x49
+       IPPROTO_CPNX                            = 0x48
+       IPPROTO_DDP                             = 0x25
+       IPPROTO_DGP                             = 0x56
+       IPPROTO_DIVERT                          = 0xfe
+       IPPROTO_DONE                            = 0x101
+       IPPROTO_DSTOPTS                         = 0x3c
+       IPPROTO_EGP                             = 0x8
+       IPPROTO_EMCON                           = 0xe
+       IPPROTO_ENCAP                           = 0x62
+       IPPROTO_EON                             = 0x50
+       IPPROTO_ESP                             = 0x32
+       IPPROTO_ETHERIP                         = 0x61
+       IPPROTO_FRAGMENT                        = 0x2c
+       IPPROTO_GGP                             = 0x3
+       IPPROTO_GMTP                            = 0x64
+       IPPROTO_GRE                             = 0x2f
+       IPPROTO_HELLO                           = 0x3f
+       IPPROTO_HMP                             = 0x14
+       IPPROTO_HOPOPTS                         = 0x0
+       IPPROTO_ICMP                            = 0x1
+       IPPROTO_ICMPV6                          = 0x3a
+       IPPROTO_IDP                             = 0x16
+       IPPROTO_IDPR                            = 0x23
+       IPPROTO_IDRP                            = 0x2d
+       IPPROTO_IGMP                            = 0x2
+       IPPROTO_IGP                             = 0x55
+       IPPROTO_IGRP                            = 0x58
+       IPPROTO_IL                              = 0x28
+       IPPROTO_INLSP                           = 0x34
+       IPPROTO_INP                             = 0x20
+       IPPROTO_IP                              = 0x0
+       IPPROTO_IPCOMP                          = 0x6c
+       IPPROTO_IPCV                            = 0x47
+       IPPROTO_IPEIP                           = 0x5e
+       IPPROTO_IPIP                            = 0x4
+       IPPROTO_IPPC                            = 0x43
+       IPPROTO_IPV4                            = 0x4
+       IPPROTO_IPV6                            = 0x29
+       IPPROTO_IRTP                            = 0x1c
+       IPPROTO_KRYPTOLAN                       = 0x41
+       IPPROTO_LARP                            = 0x5b
+       IPPROTO_LEAF1                           = 0x19
+       IPPROTO_LEAF2                           = 0x1a
+       IPPROTO_MAX                             = 0x100
+       IPPROTO_MAXID                           = 0x34
+       IPPROTO_MEAS                            = 0x13
+       IPPROTO_MHRP                            = 0x30
+       IPPROTO_MICP                            = 0x5f
+       IPPROTO_MTP                             = 0x5c
+       IPPROTO_MUX                             = 0x12
+       IPPROTO_ND                              = 0x4d
+       IPPROTO_NHRP                            = 0x36
+       IPPROTO_NONE                            = 0x3b
+       IPPROTO_NSP                             = 0x1f
+       IPPROTO_NVPII                           = 0xb
+       IPPROTO_OSPFIGP                         = 0x59
+       IPPROTO_PGM                             = 0x71
+       IPPROTO_PIGP                            = 0x9
+       IPPROTO_PIM                             = 0x67
+       IPPROTO_PRM                             = 0x15
+       IPPROTO_PUP                             = 0xc
+       IPPROTO_PVP                             = 0x4b
+       IPPROTO_RAW                             = 0xff
+       IPPROTO_RCCMON                          = 0xa
+       IPPROTO_RDP                             = 0x1b
+       IPPROTO_ROUTING                         = 0x2b
+       IPPROTO_RSVP                            = 0x2e
+       IPPROTO_RVD                             = 0x42
+       IPPROTO_SATEXPAK                        = 0x40
+       IPPROTO_SATMON                          = 0x45
+       IPPROTO_SCCSP                           = 0x60
+       IPPROTO_SCTP                            = 0x84
+       IPPROTO_SDRP                            = 0x2a
+       IPPROTO_SEP                             = 0x21
+       IPPROTO_SRPC                            = 0x5a
+       IPPROTO_ST                              = 0x7
+       IPPROTO_SVMTP                           = 0x52
+       IPPROTO_SWIPE                           = 0x35
+       IPPROTO_TCF                             = 0x57
+       IPPROTO_TCP                             = 0x6
+       IPPROTO_TP                              = 0x1d
+       IPPROTO_TPXX                            = 0x27
+       IPPROTO_TRUNK1                          = 0x17
+       IPPROTO_TRUNK2                          = 0x18
+       IPPROTO_TTP                             = 0x54
+       IPPROTO_UDP                             = 0x11
+       IPPROTO_VINES                           = 0x53
+       IPPROTO_VISA                            = 0x46
+       IPPROTO_VMTP                            = 0x51
+       IPPROTO_WBEXPAK                         = 0x4f
+       IPPROTO_WBMON                           = 0x4e
+       IPPROTO_WSN                             = 0x4a
+       IPPROTO_XNET                            = 0xf
+       IPPROTO_XTP                             = 0x24
+       IPV6_2292DSTOPTS                        = 0x17
+       IPV6_2292HOPLIMIT                       = 0x14
+       IPV6_2292HOPOPTS                        = 0x16
+       IPV6_2292NEXTHOP                        = 0x15
+       IPV6_2292PKTINFO                        = 0x13
+       IPV6_2292PKTOPTIONS                     = 0x19
+       IPV6_2292RTHDR                          = 0x18
+       IPV6_3542DSTOPTS                        = 0x32
+       IPV6_3542HOPLIMIT                       = 0x2f
+       IPV6_3542HOPOPTS                        = 0x31
+       IPV6_3542NEXTHOP                        = 0x30
+       IPV6_3542PKTINFO                        = 0x2e
+       IPV6_3542RTHDR                          = 0x33
+       IPV6_ADDR_MC_FLAGS_PREFIX               = 0x20
+       IPV6_ADDR_MC_FLAGS_TRANSIENT            = 0x10
+       IPV6_ADDR_MC_FLAGS_UNICAST_BASED        = 0x30
+       IPV6_AUTOFLOWLABEL                      = 0x3b
+       IPV6_BINDV6ONLY                         = 0x1b
+       IPV6_BOUND_IF                           = 0x7d
+       IPV6_CHECKSUM                           = 0x1a
+       IPV6_DEFAULT_MULTICAST_HOPS             = 0x1
+       IPV6_DEFAULT_MULTICAST_LOOP             = 0x1
+       IPV6_DEFHLIM                            = 0x40
+       IPV6_DONTFRAG                           = 0x3e
+       IPV6_DSTOPTS                            = 0x32
+       IPV6_FAITH                              = 0x1d
+       IPV6_FLOWINFO_MASK                      = 0xffffff0f
+       IPV6_FLOWLABEL_MASK                     = 0xffff0f00
+       IPV6_FLOW_ECN_MASK                      = 0x3000
+       IPV6_FRAGTTL                            = 0x3c
+       IPV6_FW_ADD                             = 0x1e
+       IPV6_FW_DEL                             = 0x1f
+       IPV6_FW_FLUSH                           = 0x20
+       IPV6_FW_GET                             = 0x22
+       IPV6_FW_ZERO                            = 0x21
+       IPV6_HLIMDEC                            = 0x1
+       IPV6_HOPLIMIT                           = 0x2f
+       IPV6_HOPOPTS                            = 0x31
+       IPV6_IPSEC_POLICY                       = 0x1c
+       IPV6_JOIN_GROUP                         = 0xc
+       IPV6_LEAVE_GROUP                        = 0xd
+       IPV6_MAXHLIM                            = 0xff
+       IPV6_MAXOPTHDR                          = 0x800
+       IPV6_MAXPACKET                          = 0xffff
+       IPV6_MAX_GROUP_SRC_FILTER               = 0x200
+       IPV6_MAX_MEMBERSHIPS                    = 0xfff
+       IPV6_MAX_SOCK_SRC_FILTER                = 0x80
+       IPV6_MIN_MEMBERSHIPS                    = 0x1f
+       IPV6_MMTU                               = 0x500
+       IPV6_MSFILTER                           = 0x4a
+       IPV6_MULTICAST_HOPS                     = 0xa
+       IPV6_MULTICAST_IF                       = 0x9
+       IPV6_MULTICAST_LOOP                     = 0xb
+       IPV6_NEXTHOP                            = 0x30
+       IPV6_PATHMTU                            = 0x2c
+       IPV6_PKTINFO                            = 0x2e
+       IPV6_PORTRANGE                          = 0xe
+       IPV6_PORTRANGE_DEFAULT                  = 0x0
+       IPV6_PORTRANGE_HIGH                     = 0x1
+       IPV6_PORTRANGE_LOW                      = 0x2
+       IPV6_PREFER_TEMPADDR                    = 0x3f
+       IPV6_RECVDSTOPTS                        = 0x28
+       IPV6_RECVHOPLIMIT                       = 0x25
+       IPV6_RECVHOPOPTS                        = 0x27
+       IPV6_RECVPATHMTU                        = 0x2b
+       IPV6_RECVPKTINFO                        = 0x3d
+       IPV6_RECVRTHDR                          = 0x26
+       IPV6_RECVTCLASS                         = 0x23
+       IPV6_RTHDR                              = 0x33
+       IPV6_RTHDRDSTOPTS                       = 0x39
+       IPV6_RTHDR_LOOSE                        = 0x0
+       IPV6_RTHDR_STRICT                       = 0x1
+       IPV6_RTHDR_TYPE_0                       = 0x0
+       IPV6_SOCKOPT_RESERVED1                  = 0x3
+       IPV6_TCLASS                             = 0x24
+       IPV6_UNICAST_HOPS                       = 0x4
+       IPV6_USE_MIN_MTU                        = 0x2a
+       IPV6_V6ONLY                             = 0x1b
+       IPV6_VERSION                            = 0x60
+       IPV6_VERSION_MASK                       = 0xf0
+       IP_ADD_MEMBERSHIP                       = 0xc
+       IP_ADD_SOURCE_MEMBERSHIP                = 0x46
+       IP_BLOCK_SOURCE                         = 0x48
+       IP_BOUND_IF                             = 0x19
+       IP_DEFAULT_MULTICAST_LOOP               = 0x1
+       IP_DEFAULT_MULTICAST_TTL                = 0x1
+       IP_DF                                   = 0x4000
+       IP_DONTFRAG                             = 0x1c
+       IP_DROP_MEMBERSHIP                      = 0xd
+       IP_DROP_SOURCE_MEMBERSHIP               = 0x47
+       IP_DUMMYNET_CONFIGURE                   = 0x3c
+       IP_DUMMYNET_DEL                         = 0x3d
+       IP_DUMMYNET_FLUSH                       = 0x3e
+       IP_DUMMYNET_GET                         = 0x40
+       IP_FAITH                                = 0x16
+       IP_FW_ADD                               = 0x28
+       IP_FW_DEL                               = 0x29
+       IP_FW_FLUSH                             = 0x2a
+       IP_FW_GET                               = 0x2c
+       IP_FW_RESETLOG                          = 0x2d
+       IP_FW_ZERO                              = 0x2b
+       IP_HDRINCL                              = 0x2
+       IP_IPSEC_POLICY                         = 0x15
+       IP_MAXPACKET                            = 0xffff
+       IP_MAX_GROUP_SRC_FILTER                 = 0x200
+       IP_MAX_MEMBERSHIPS                      = 0xfff
+       IP_MAX_SOCK_MUTE_FILTER                 = 0x80
+       IP_MAX_SOCK_SRC_FILTER                  = 0x80
+       IP_MF                                   = 0x2000
+       IP_MIN_MEMBERSHIPS                      = 0x1f
+       IP_MSFILTER                             = 0x4a
+       IP_MSS                                  = 0x240
+       IP_MULTICAST_IF                         = 0x9
+       IP_MULTICAST_IFINDEX                    = 0x42
+       IP_MULTICAST_LOOP                       = 0xb
+       IP_MULTICAST_TTL                        = 0xa
+       IP_MULTICAST_VIF                        = 0xe
+       IP_NAT__XXX                             = 0x37
+       IP_OFFMASK                              = 0x1fff
+       IP_OLD_FW_ADD                           = 0x32
+       IP_OLD_FW_DEL                           = 0x33
+       IP_OLD_FW_FLUSH                         = 0x34
+       IP_OLD_FW_GET                           = 0x36
+       IP_OLD_FW_RESETLOG                      = 0x38
+       IP_OLD_FW_ZERO                          = 0x35
+       IP_OPTIONS                              = 0x1
+       IP_PKTINFO                              = 0x1a
+       IP_PORTRANGE                            = 0x13
+       IP_PORTRANGE_DEFAULT                    = 0x0
+       IP_PORTRANGE_HIGH                       = 0x1
+       IP_PORTRANGE_LOW                        = 0x2
+       IP_RECVDSTADDR                          = 0x7
+       IP_RECVIF                               = 0x14
+       IP_RECVOPTS                             = 0x5
+       IP_RECVPKTINFO                          = 0x1a
+       IP_RECVRETOPTS                          = 0x6
+       IP_RECVTOS                              = 0x1b
+       IP_RECVTTL                              = 0x18
+       IP_RETOPTS                              = 0x8
+       IP_RF                                   = 0x8000
+       IP_RSVP_OFF                             = 0x10
+       IP_RSVP_ON                              = 0xf
+       IP_RSVP_VIF_OFF                         = 0x12
+       IP_RSVP_VIF_ON                          = 0x11
+       IP_STRIPHDR                             = 0x17
+       IP_TOS                                  = 0x3
+       IP_TRAFFIC_MGT_BACKGROUND               = 0x41
+       IP_TTL                                  = 0x4
+       IP_UNBLOCK_SOURCE                       = 0x49
+       ISIG                                    = 0x80
+       ISTRIP                                  = 0x20
+       IUTF8                                   = 0x4000
+       IXANY                                   = 0x800
+       IXOFF                                   = 0x400
+       IXON                                    = 0x200
+       KERN_HOSTNAME                           = 0xa
+       KERN_OSRELEASE                          = 0x2
+       KERN_OSTYPE                             = 0x1
+       KERN_VERSION                            = 0x4
+       LOCAL_PEERCRED                          = 0x1
+       LOCAL_PEEREPID                          = 0x3
+       LOCAL_PEEREUUID                         = 0x5
+       LOCAL_PEERPID                           = 0x2
+       LOCAL_PEERTOKEN                         = 0x6
+       LOCAL_PEERUUID                          = 0x4
+       LOCK_EX                                 = 0x2
+       LOCK_NB                                 = 0x4
+       LOCK_SH                                 = 0x1
+       LOCK_UN                                 = 0x8
+       MADV_CAN_REUSE                          = 0x9
+       MADV_DONTNEED                           = 0x4
+       MADV_FREE                               = 0x5
+       MADV_FREE_REUSABLE                      = 0x7
+       MADV_FREE_REUSE                         = 0x8
+       MADV_NORMAL                             = 0x0
+       MADV_PAGEOUT                            = 0xa
+       MADV_RANDOM                             = 0x1
+       MADV_SEQUENTIAL                         = 0x2
+       MADV_WILLNEED                           = 0x3
+       MADV_ZERO_WIRED_PAGES                   = 0x6
+       MAP_32BIT                               = 0x8000
+       MAP_ANON                                = 0x1000
+       MAP_ANONYMOUS                           = 0x1000
+       MAP_COPY                                = 0x2
+       MAP_FILE                                = 0x0
+       MAP_FIXED                               = 0x10
+       MAP_HASSEMAPHORE                        = 0x200
+       MAP_JIT                                 = 0x800
+       MAP_NOCACHE                             = 0x400
+       MAP_NOEXTEND                            = 0x100
+       MAP_NORESERVE                           = 0x40
+       MAP_PRIVATE                             = 0x2
+       MAP_RENAME                              = 0x20
+       MAP_RESERVED0080                        = 0x80
+       MAP_RESILIENT_CODESIGN                  = 0x2000
+       MAP_RESILIENT_MEDIA                     = 0x4000
+       MAP_SHARED                              = 0x1
+       MAP_TRANSLATED_ALLOW_EXECUTE            = 0x20000
+       MAP_UNIX03                              = 0x40000
+       MCAST_BLOCK_SOURCE                      = 0x54
+       MCAST_EXCLUDE                           = 0x2
+       MCAST_INCLUDE                           = 0x1
+       MCAST_JOIN_GROUP                        = 0x50
+       MCAST_JOIN_SOURCE_GROUP                 = 0x52
+       MCAST_LEAVE_GROUP                       = 0x51
+       MCAST_LEAVE_SOURCE_GROUP                = 0x53
+       MCAST_UNBLOCK_SOURCE                    = 0x55
+       MCAST_UNDEFINED                         = 0x0
+       MCL_CURRENT                             = 0x1
+       MCL_FUTURE                              = 0x2
+       MNT_ASYNC                               = 0x40
+       MNT_AUTOMOUNTED                         = 0x400000
+       MNT_CMDFLAGS                            = 0xf0000
+       MNT_CPROTECT                            = 0x80
+       MNT_DEFWRITE                            = 0x2000000
+       MNT_DONTBROWSE                          = 0x100000
+       MNT_DOVOLFS                             = 0x8000
+       MNT_DWAIT                               = 0x4
+       MNT_EXPORTED                            = 0x100
+       MNT_EXT_ROOT_DATA_VOL                   = 0x1
+       MNT_FORCE                               = 0x80000
+       MNT_IGNORE_OWNERSHIP                    = 0x200000
+       MNT_JOURNALED                           = 0x800000
+       MNT_LOCAL                               = 0x1000
+       MNT_MULTILABEL                          = 0x4000000
+       MNT_NOATIME                             = 0x10000000
+       MNT_NOBLOCK                             = 0x20000
+       MNT_NODEV                               = 0x10
+       MNT_NOEXEC                              = 0x4
+       MNT_NOSUID                              = 0x8
+       MNT_NOUSERXATTR                         = 0x1000000
+       MNT_NOWAIT                              = 0x2
+       MNT_QUARANTINE                          = 0x400
+       MNT_QUOTA                               = 0x2000
+       MNT_RDONLY                              = 0x1
+       MNT_RELOAD                              = 0x40000
+       MNT_REMOVABLE                           = 0x200
+       MNT_ROOTFS                              = 0x4000
+       MNT_SNAPSHOT                            = 0x40000000
+       MNT_STRICTATIME                         = 0x80000000
+       MNT_SYNCHRONOUS                         = 0x2
+       MNT_UNION                               = 0x20
+       MNT_UNKNOWNPERMISSIONS                  = 0x200000
+       MNT_UPDATE                              = 0x10000
+       MNT_VISFLAGMASK                         = 0xd7f0f7ff
+       MNT_WAIT                                = 0x1
+       MSG_CTRUNC                              = 0x20
+       MSG_DONTROUTE                           = 0x4
+       MSG_DONTWAIT                            = 0x80
+       MSG_EOF                                 = 0x100
+       MSG_EOR                                 = 0x8
+       MSG_FLUSH                               = 0x400
+       MSG_HAVEMORE                            = 0x2000
+       MSG_HOLD                                = 0x800
+       MSG_NEEDSA                              = 0x10000
+       MSG_NOSIGNAL                            = 0x80000
+       MSG_OOB                                 = 0x1
+       MSG_PEEK                                = 0x2
+       MSG_RCVMORE                             = 0x4000
+       MSG_SEND                                = 0x1000
+       MSG_TRUNC                               = 0x10
+       MSG_WAITALL                             = 0x40
+       MSG_WAITSTREAM                          = 0x200
+       MS_ASYNC                                = 0x1
+       MS_DEACTIVATE                           = 0x8
+       MS_INVALIDATE                           = 0x2
+       MS_KILLPAGES                            = 0x4
+       MS_SYNC                                 = 0x10
+       NAME_MAX                                = 0xff
+       NET_RT_DUMP                             = 0x1
+       NET_RT_DUMP2                            = 0x7
+       NET_RT_FLAGS                            = 0x2
+       NET_RT_FLAGS_PRIV                       = 0xa
+       NET_RT_IFLIST                           = 0x3
+       NET_RT_IFLIST2                          = 0x6
+       NET_RT_MAXID                            = 0xb
+       NET_RT_STAT                             = 0x4
+       NET_RT_TRASH                            = 0x5
+       NFDBITS                                 = 0x20
+       NL0                                     = 0x0
+       NL1                                     = 0x100
+       NL2                                     = 0x200
+       NL3                                     = 0x300
+       NLDLY                                   = 0x300
+       NOFLSH                                  = 0x80000000
+       NOKERNINFO                              = 0x2000000
+       NOTE_ABSOLUTE                           = 0x8
+       NOTE_ATTRIB                             = 0x8
+       NOTE_BACKGROUND                         = 0x40
+       NOTE_CHILD                              = 0x4
+       NOTE_CRITICAL                           = 0x20
+       NOTE_DELETE                             = 0x1
+       NOTE_EXEC                               = 0x20000000
+       NOTE_EXIT                               = 0x80000000
+       NOTE_EXITSTATUS                         = 0x4000000
+       NOTE_EXIT_CSERROR                       = 0x40000
+       NOTE_EXIT_DECRYPTFAIL                   = 0x10000
+       NOTE_EXIT_DETAIL                        = 0x2000000
+       NOTE_EXIT_DETAIL_MASK                   = 0x70000
+       NOTE_EXIT_MEMORY                        = 0x20000
+       NOTE_EXIT_REPARENTED                    = 0x80000
+       NOTE_EXTEND                             = 0x4
+       NOTE_FFAND                              = 0x40000000
+       NOTE_FFCOPY                             = 0xc0000000
+       NOTE_FFCTRLMASK                         = 0xc0000000
+       NOTE_FFLAGSMASK                         = 0xffffff
+       NOTE_FFNOP                              = 0x0
+       NOTE_FFOR                               = 0x80000000
+       NOTE_FORK                               = 0x40000000
+       NOTE_FUNLOCK                            = 0x100
+       NOTE_LEEWAY                             = 0x10
+       NOTE_LINK                               = 0x10
+       NOTE_LOWAT                              = 0x1
+       NOTE_MACHTIME                           = 0x100
+       NOTE_MACH_CONTINUOUS_TIME               = 0x80
+       NOTE_NONE                               = 0x80
+       NOTE_NSECONDS                           = 0x4
+       NOTE_OOB                                = 0x2
+       NOTE_PCTRLMASK                          = -0x100000
+       NOTE_PDATAMASK                          = 0xfffff
+       NOTE_REAP                               = 0x10000000
+       NOTE_RENAME                             = 0x20
+       NOTE_REVOKE                             = 0x40
+       NOTE_SECONDS                            = 0x1
+       NOTE_SIGNAL                             = 0x8000000
+       NOTE_TRACK                              = 0x1
+       NOTE_TRACKERR                           = 0x2
+       NOTE_TRIGGER                            = 0x1000000
+       NOTE_USECONDS                           = 0x2
+       NOTE_VM_ERROR                           = 0x10000000
+       NOTE_VM_PRESSURE                        = 0x80000000
+       NOTE_VM_PRESSURE_SUDDEN_TERMINATE       = 0x20000000
+       NOTE_VM_PRESSURE_TERMINATE              = 0x40000000
+       NOTE_WRITE                              = 0x2
+       OCRNL                                   = 0x10
+       OFDEL                                   = 0x20000
+       OFILL                                   = 0x80
+       ONLCR                                   = 0x2
+       ONLRET                                  = 0x40
+       ONOCR                                   = 0x20
+       ONOEOT                                  = 0x8
+       OPOST                                   = 0x1
+       OXTABS                                  = 0x4
+       O_ACCMODE                               = 0x3
+       O_ALERT                                 = 0x20000000
+       O_APPEND                                = 0x8
+       O_ASYNC                                 = 0x40
+       O_CLOEXEC                               = 0x1000000
+       O_CREAT                                 = 0x200
+       O_DIRECTORY                             = 0x100000
+       O_DP_GETRAWENCRYPTED                    = 0x1
+       O_DP_GETRAWUNENCRYPTED                  = 0x2
+       O_DSYNC                                 = 0x400000
+       O_EVTONLY                               = 0x8000
+       O_EXCL                                  = 0x800
+       O_EXLOCK                                = 0x20
+       O_FSYNC                                 = 0x80
+       O_NDELAY                                = 0x4
+       O_NOCTTY                                = 0x20000
+       O_NOFOLLOW                              = 0x100
+       O_NOFOLLOW_ANY                          = 0x20000000
+       O_NONBLOCK                              = 0x4
+       O_POPUP                                 = 0x80000000
+       O_RDONLY                                = 0x0
+       O_RDWR                                  = 0x2
+       O_SHLOCK                                = 0x10
+       O_SYMLINK                               = 0x200000
+       O_SYNC                                  = 0x80
+       O_TRUNC                                 = 0x400
+       O_WRONLY                                = 0x1
+       PARENB                                  = 0x1000
+       PARMRK                                  = 0x8
+       PARODD                                  = 0x2000
+       PENDIN                                  = 0x20000000
+       PRIO_PGRP                               = 0x1
+       PRIO_PROCESS                            = 0x0
+       PRIO_USER                               = 0x2
+       PROT_EXEC                               = 0x4
+       PROT_NONE                               = 0x0
+       PROT_READ                               = 0x1
+       PROT_WRITE                              = 0x2
+       PT_ATTACH                               = 0xa
+       PT_ATTACHEXC                            = 0xe
+       PT_CONTINUE                             = 0x7
+       PT_DENY_ATTACH                          = 0x1f
+       PT_DETACH                               = 0xb
+       PT_FIRSTMACH                            = 0x20
+       PT_FORCEQUOTA                           = 0x1e
+       PT_KILL                                 = 0x8
+       PT_READ_D                               = 0x2
+       PT_READ_I                               = 0x1
+       PT_READ_U                               = 0x3
+       PT_SIGEXC                               = 0xc
+       PT_STEP                                 = 0x9
+       PT_THUPDATE                             = 0xd
+       PT_TRACE_ME                             = 0x0
+       PT_WRITE_D                              = 0x5
+       PT_WRITE_I                              = 0x4
+       PT_WRITE_U                              = 0x6
+       RLIMIT_AS                               = 0x5
+       RLIMIT_CORE                             = 0x4
+       RLIMIT_CPU                              = 0x0
+       RLIMIT_CPU_USAGE_MONITOR                = 0x2
+       RLIMIT_DATA                             = 0x2
+       RLIMIT_FSIZE                            = 0x1
+       RLIMIT_MEMLOCK                          = 0x6
+       RLIMIT_NOFILE                           = 0x8
+       RLIMIT_NPROC                            = 0x7
+       RLIMIT_RSS                              = 0x5
+       RLIMIT_STACK                            = 0x3
+       RLIM_INFINITY                           = 0x7fffffffffffffff
+       RTAX_AUTHOR                             = 0x6
+       RTAX_BRD                                = 0x7
+       RTAX_DST                                = 0x0
+       RTAX_GATEWAY                            = 0x1
+       RTAX_GENMASK                            = 0x3
+       RTAX_IFA                                = 0x5
+       RTAX_IFP                                = 0x4
+       RTAX_MAX                                = 0x8
+       RTAX_NETMASK                            = 0x2
+       RTA_AUTHOR                              = 0x40
+       RTA_BRD                                 = 0x80
+       RTA_DST                                 = 0x1
+       RTA_GATEWAY                             = 0x2
+       RTA_GENMASK                             = 0x8
+       RTA_IFA                                 = 0x20
+       RTA_IFP                                 = 0x10
+       RTA_NETMASK                             = 0x4
+       RTF_BLACKHOLE                           = 0x1000
+       RTF_BROADCAST                           = 0x400000
+       RTF_CLONING                             = 0x100
+       RTF_CONDEMNED                           = 0x2000000
+       RTF_DEAD                                = 0x20000000
+       RTF_DELCLONE                            = 0x80
+       RTF_DONE                                = 0x40
+       RTF_DYNAMIC                             = 0x10
+       RTF_GATEWAY                             = 0x2
+       RTF_GLOBAL                              = 0x40000000
+       RTF_HOST                                = 0x4
+       RTF_IFREF                               = 0x4000000
+       RTF_IFSCOPE                             = 0x1000000
+       RTF_LLDATA                              = 0x400
+       RTF_LLINFO                              = 0x400
+       RTF_LOCAL                               = 0x200000
+       RTF_MODIFIED                            = 0x20
+       RTF_MULTICAST                           = 0x800000
+       RTF_NOIFREF                             = 0x2000
+       RTF_PINNED                              = 0x100000
+       RTF_PRCLONING                           = 0x10000
+       RTF_PROTO1                              = 0x8000
+       RTF_PROTO2                              = 0x4000
+       RTF_PROTO3                              = 0x40000
+       RTF_PROXY                               = 0x8000000
+       RTF_REJECT                              = 0x8
+       RTF_ROUTER                              = 0x10000000
+       RTF_STATIC                              = 0x800
+       RTF_UP                                  = 0x1
+       RTF_WASCLONED                           = 0x20000
+       RTF_XRESOLVE                            = 0x200
+       RTM_ADD                                 = 0x1
+       RTM_CHANGE                              = 0x3
+       RTM_DELADDR                             = 0xd
+       RTM_DELETE                              = 0x2
+       RTM_DELMADDR                            = 0x10
+       RTM_GET                                 = 0x4
+       RTM_GET2                                = 0x14
+       RTM_IFINFO                              = 0xe
+       RTM_IFINFO2                             = 0x12
+       RTM_LOCK                                = 0x8
+       RTM_LOSING                              = 0x5
+       RTM_MISS                                = 0x7
+       RTM_NEWADDR                             = 0xc
+       RTM_NEWMADDR                            = 0xf
+       RTM_NEWMADDR2                           = 0x13
+       RTM_OLDADD                              = 0x9
+       RTM_OLDDEL                              = 0xa
+       RTM_REDIRECT                            = 0x6
+       RTM_RESOLVE                             = 0xb
+       RTM_RTTUNIT                             = 0xf4240
+       RTM_VERSION                             = 0x5
+       RTV_EXPIRE                              = 0x4
+       RTV_HOPCOUNT                            = 0x2
+       RTV_MTU                                 = 0x1
+       RTV_RPIPE                               = 0x8
+       RTV_RTT                                 = 0x40
+       RTV_RTTVAR                              = 0x80
+       RTV_SPIPE                               = 0x10
+       RTV_SSTHRESH                            = 0x20
+       RUSAGE_CHILDREN                         = -0x1
+       RUSAGE_SELF                             = 0x0
+       SCM_CREDS                               = 0x3
+       SCM_RIGHTS                              = 0x1
+       SCM_TIMESTAMP                           = 0x2
+       SCM_TIMESTAMP_MONOTONIC                 = 0x4
+       SEEK_CUR                                = 0x1
+       SEEK_DATA                               = 0x4
+       SEEK_END                                = 0x2
+       SEEK_HOLE                               = 0x3
+       SEEK_SET                                = 0x0
+       SHUT_RD                                 = 0x0
+       SHUT_RDWR                               = 0x2
+       SHUT_WR                                 = 0x1
+       SIOCADDMULTI                            = 0x80206931
+       SIOCAIFADDR                             = 0x8040691a
+       SIOCARPIPLL                             = 0xc0206928
+       SIOCATMARK                              = 0x40047307
+       SIOCAUTOADDR                            = 0xc0206926
+       SIOCAUTONETMASK                         = 0x80206927
+       SIOCDELMULTI                            = 0x80206932
+       SIOCDIFADDR                             = 0x80206919
+       SIOCDIFPHYADDR                          = 0x80206941
+       SIOCGDRVSPEC                            = 0xc028697b
+       SIOCGETVLAN                             = 0xc020697f
+       SIOCGHIWAT                              = 0x40047301
+       SIOCGIF6LOWPAN                          = 0xc02069c5
+       SIOCGIFADDR                             = 0xc0206921
+       SIOCGIFALTMTU                           = 0xc0206948
+       SIOCGIFASYNCMAP                         = 0xc020697c
+       SIOCGIFBOND                             = 0xc0206947
+       SIOCGIFBRDADDR                          = 0xc0206923
+       SIOCGIFCAP                              = 0xc020695b
+       SIOCGIFCONF                             = 0xc00c6924
+       SIOCGIFDEVMTU                           = 0xc0206944
+       SIOCGIFDSTADDR                          = 0xc0206922
+       SIOCGIFFLAGS                            = 0xc0206911
+       SIOCGIFFUNCTIONALTYPE                   = 0xc02069ad
+       SIOCGIFGENERIC                          = 0xc020693a
+       SIOCGIFKPI                              = 0xc0206987
+       SIOCGIFMAC                              = 0xc0206982
+       SIOCGIFMEDIA                            = 0xc02c6938
+       SIOCGIFMETRIC                           = 0xc0206917
+       SIOCGIFMTU                              = 0xc0206933
+       SIOCGIFNETMASK                          = 0xc0206925
+       SIOCGIFPDSTADDR                         = 0xc0206940
+       SIOCGIFPHYS                             = 0xc0206935
+       SIOCGIFPSRCADDR                         = 0xc020693f
+       SIOCGIFSTATUS                           = 0xc331693d
+       SIOCGIFVLAN                             = 0xc020697f
+       SIOCGIFWAKEFLAGS                        = 0xc0206988
+       SIOCGIFXMEDIA                           = 0xc02c6948
+       SIOCGLOWAT                              = 0x40047303
+       SIOCGPGRP                               = 0x40047309
+       SIOCIFCREATE                            = 0xc0206978
+       SIOCIFCREATE2                           = 0xc020697a
+       SIOCIFDESTROY                           = 0x80206979
+       SIOCIFGCLONERS                          = 0xc0106981
+       SIOCRSLVMULTI                           = 0xc010693b
+       SIOCSDRVSPEC                            = 0x8028697b
+       SIOCSETVLAN                             = 0x8020697e
+       SIOCSHIWAT                              = 0x80047300
+       SIOCSIF6LOWPAN                          = 0x802069c4
+       SIOCSIFADDR                             = 0x8020690c
+       SIOCSIFALTMTU                           = 0x80206945
+       SIOCSIFASYNCMAP                         = 0x8020697d
+       SIOCSIFBOND                             = 0x80206946
+       SIOCSIFBRDADDR                          = 0x80206913
+       SIOCSIFCAP                              = 0x8020695a
+       SIOCSIFDSTADDR                          = 0x8020690e
+       SIOCSIFFLAGS                            = 0x80206910
+       SIOCSIFGENERIC                          = 0x80206939
+       SIOCSIFKPI                              = 0x80206986
+       SIOCSIFLLADDR                           = 0x8020693c
+       SIOCSIFMAC                              = 0x80206983
+       SIOCSIFMEDIA                            = 0xc0206937
+       SIOCSIFMETRIC                           = 0x80206918
+       SIOCSIFMTU                              = 0x80206934
+       SIOCSIFNETMASK                          = 0x80206916
+       SIOCSIFPHYADDR                          = 0x8040693e
+       SIOCSIFPHYS                             = 0x80206936
+       SIOCSIFVLAN                             = 0x8020697e
+       SIOCSLOWAT                              = 0x80047302
+       SIOCSPGRP                               = 0x80047308
+       SOCK_DGRAM                              = 0x2
+       SOCK_MAXADDRLEN                         = 0xff
+       SOCK_RAW                                = 0x3
+       SOCK_RDM                                = 0x4
+       SOCK_SEQPACKET                          = 0x5
+       SOCK_STREAM                             = 0x1
+       SOL_LOCAL                               = 0x0
+       SOL_SOCKET                              = 0xffff
+       SOMAXCONN                               = 0x80
+       SO_ACCEPTCONN                           = 0x2
+       SO_BROADCAST                            = 0x20
+       SO_DEBUG                                = 0x1
+       SO_DONTROUTE                            = 0x10
+       SO_DONTTRUNC                            = 0x2000
+       SO_ERROR                                = 0x1007
+       SO_KEEPALIVE                            = 0x8
+       SO_LABEL                                = 0x1010
+       SO_LINGER                               = 0x80
+       SO_LINGER_SEC                           = 0x1080
+       SO_NETSVC_MARKING_LEVEL                 = 0x1119
+       SO_NET_SERVICE_TYPE                     = 0x1116
+       SO_NKE                                  = 0x1021
+       SO_NOADDRERR                            = 0x1023
+       SO_NOSIGPIPE                            = 0x1022
+       SO_NOTIFYCONFLICT                       = 0x1026
+       SO_NP_EXTENSIONS                        = 0x1083
+       SO_NREAD                                = 0x1020
+       SO_NUMRCVPKT                            = 0x1112
+       SO_NWRITE                               = 0x1024
+       SO_OOBINLINE                            = 0x100
+       SO_PEERLABEL                            = 0x1011
+       SO_RANDOMPORT                           = 0x1082
+       SO_RCVBUF                               = 0x1002
+       SO_RCVLOWAT                             = 0x1004
+       SO_RCVTIMEO                             = 0x1006
+       SO_REUSEADDR                            = 0x4
+       SO_REUSEPORT                            = 0x200
+       SO_REUSESHAREUID                        = 0x1025
+       SO_SNDBUF                               = 0x1001
+       SO_SNDLOWAT                             = 0x1003
+       SO_SNDTIMEO                             = 0x1005
+       SO_TIMESTAMP                            = 0x400
+       SO_TIMESTAMP_MONOTONIC                  = 0x800
+       SO_TRACKER_ATTRIBUTE_FLAGS_APP_APPROVED = 0x1
+       SO_TRACKER_ATTRIBUTE_FLAGS_DOMAIN_SHORT = 0x4
+       SO_TRACKER_ATTRIBUTE_FLAGS_TRACKER      = 0x2
+       SO_TRACKER_TRANSPARENCY_VERSION         = 0x3
+       SO_TYPE                                 = 0x1008
+       SO_UPCALLCLOSEWAIT                      = 0x1027
+       SO_USELOOPBACK                          = 0x40
+       SO_WANTMORE                             = 0x4000
+       SO_WANTOOBFLAG                          = 0x8000
+       S_IEXEC                                 = 0x40
+       S_IFBLK                                 = 0x6000
+       S_IFCHR                                 = 0x2000
+       S_IFDIR                                 = 0x4000
+       S_IFIFO                                 = 0x1000
+       S_IFLNK                                 = 0xa000
+       S_IFMT                                  = 0xf000
+       S_IFREG                                 = 0x8000
+       S_IFSOCK                                = 0xc000
+       S_IFWHT                                 = 0xe000
+       S_IREAD                                 = 0x100
+       S_IRGRP                                 = 0x20
+       S_IROTH                                 = 0x4
+       S_IRUSR                                 = 0x100
+       S_IRWXG                                 = 0x38
+       S_IRWXO                                 = 0x7
+       S_IRWXU                                 = 0x1c0
+       S_ISGID                                 = 0x400
+       S_ISTXT                                 = 0x200
+       S_ISUID                                 = 0x800
+       S_ISVTX                                 = 0x200
+       S_IWGRP                                 = 0x10
+       S_IWOTH                                 = 0x2
+       S_IWRITE                                = 0x80
+       S_IWUSR                                 = 0x80
+       S_IXGRP                                 = 0x8
+       S_IXOTH                                 = 0x1
+       S_IXUSR                                 = 0x40
+       TAB0                                    = 0x0
+       TAB1                                    = 0x400
+       TAB2                                    = 0x800
+       TAB3                                    = 0x4
+       TABDLY                                  = 0xc04
+       TCIFLUSH                                = 0x1
+       TCIOFF                                  = 0x3
+       TCIOFLUSH                               = 0x3
+       TCION                                   = 0x4
+       TCOFLUSH                                = 0x2
+       TCOOFF                                  = 0x1
+       TCOON                                   = 0x2
+       TCPOPT_CC                               = 0xb
+       TCPOPT_CCECHO                           = 0xd
+       TCPOPT_CCNEW                            = 0xc
+       TCPOPT_EOL                              = 0x0
+       TCPOPT_FASTOPEN                         = 0x22
+       TCPOPT_MAXSEG                           = 0x2
+       TCPOPT_NOP                              = 0x1
+       TCPOPT_SACK                             = 0x5
+       TCPOPT_SACK_HDR                         = 0x1010500
+       TCPOPT_SACK_PERMITTED                   = 0x4
+       TCPOPT_SACK_PERMIT_HDR                  = 0x1010402
+       TCPOPT_SIGNATURE                        = 0x13
+       TCPOPT_TIMESTAMP                        = 0x8
+       TCPOPT_TSTAMP_HDR                       = 0x101080a
+       TCPOPT_WINDOW                           = 0x3
+       TCP_CONNECTIONTIMEOUT                   = 0x20
+       TCP_CONNECTION_INFO                     = 0x106
+       TCP_ENABLE_ECN                          = 0x104
+       TCP_FASTOPEN                            = 0x105
+       TCP_KEEPALIVE                           = 0x10
+       TCP_KEEPCNT                             = 0x102
+       TCP_KEEPINTVL                           = 0x101
+       TCP_MAXHLEN                             = 0x3c
+       TCP_MAXOLEN                             = 0x28
+       TCP_MAXSEG                              = 0x2
+       TCP_MAXWIN                              = 0xffff
+       TCP_MAX_SACK                            = 0x4
+       TCP_MAX_WINSHIFT                        = 0xe
+       TCP_MINMSS                              = 0xd8
+       TCP_MSS                                 = 0x200
+       TCP_NODELAY                             = 0x1
+       TCP_NOOPT                               = 0x8
+       TCP_NOPUSH                              = 0x4
+       TCP_NOTSENT_LOWAT                       = 0x201
+       TCP_RXT_CONNDROPTIME                    = 0x80
+       TCP_RXT_FINDROP                         = 0x100
+       TCP_SENDMOREACKS                        = 0x103
+       TCSAFLUSH                               = 0x2
+       TIOCCBRK                                = 0x2000747a
+       TIOCCDTR                                = 0x20007478
+       TIOCCONS                                = 0x80047462
+       TIOCDCDTIMESTAMP                        = 0x40107458
+       TIOCDRAIN                               = 0x2000745e
+       TIOCDSIMICROCODE                        = 0x20007455
+       TIOCEXCL                                = 0x2000740d
+       TIOCEXT                                 = 0x80047460
+       TIOCFLUSH                               = 0x80047410
+       TIOCGDRAINWAIT                          = 0x40047456
+       TIOCGETA                                = 0x40487413
+       TIOCGETD                                = 0x4004741a
+       TIOCGPGRP                               = 0x40047477
+       TIOCGWINSZ                              = 0x40087468
+       TIOCIXOFF                               = 0x20007480
+       TIOCIXON                                = 0x20007481
+       TIOCMBIC                                = 0x8004746b
+       TIOCMBIS                                = 0x8004746c
+       TIOCMGDTRWAIT                           = 0x4004745a
+       TIOCMGET                                = 0x4004746a
+       TIOCMODG                                = 0x40047403
+       TIOCMODS                                = 0x80047404
+       TIOCMSDTRWAIT                           = 0x8004745b
+       TIOCMSET                                = 0x8004746d
+       TIOCM_CAR                               = 0x40
+       TIOCM_CD                                = 0x40
+       TIOCM_CTS                               = 0x20
+       TIOCM_DSR                               = 0x100
+       TIOCM_DTR                               = 0x2
+       TIOCM_LE                                = 0x1
+       TIOCM_RI                                = 0x80
+       TIOCM_RNG                               = 0x80
+       TIOCM_RTS                               = 0x4
+       TIOCM_SR                                = 0x10
+       TIOCM_ST                                = 0x8
+       TIOCNOTTY                               = 0x20007471
+       TIOCNXCL                                = 0x2000740e
+       TIOCOUTQ                                = 0x40047473
+       TIOCPKT                                 = 0x80047470
+       TIOCPKT_DATA                            = 0x0
+       TIOCPKT_DOSTOP                          = 0x20
+       TIOCPKT_FLUSHREAD                       = 0x1
+       TIOCPKT_FLUSHWRITE                      = 0x2
+       TIOCPKT_IOCTL                           = 0x40
+       TIOCPKT_NOSTOP                          = 0x10
+       TIOCPKT_START                           = 0x8
+       TIOCPKT_STOP                            = 0x4
+       TIOCPTYGNAME                            = 0x40807453
+       TIOCPTYGRANT                            = 0x20007454
+       TIOCPTYUNLK                             = 0x20007452
+       TIOCREMOTE                              = 0x80047469
+       TIOCSBRK                                = 0x2000747b
+       TIOCSCONS                               = 0x20007463
+       TIOCSCTTY                               = 0x20007461
+       TIOCSDRAINWAIT                          = 0x80047457
+       TIOCSDTR                                = 0x20007479
+       TIOCSETA                                = 0x80487414
+       TIOCSETAF                               = 0x80487416
+       TIOCSETAW                               = 0x80487415
+       TIOCSETD                                = 0x8004741b
+       TIOCSIG                                 = 0x2000745f
+       TIOCSPGRP                               = 0x80047476
+       TIOCSTART                               = 0x2000746e
+       TIOCSTAT                                = 0x20007465
+       TIOCSTI                                 = 0x80017472
+       TIOCSTOP                                = 0x2000746f
+       TIOCSWINSZ                              = 0x80087467
+       TIOCTIMESTAMP                           = 0x40107459
+       TIOCUCNTL                               = 0x80047466
+       TOSTOP                                  = 0x400000
+       VDISCARD                                = 0xf
+       VDSUSP                                  = 0xb
+       VEOF                                    = 0x0
+       VEOL                                    = 0x1
+       VEOL2                                   = 0x2
+       VERASE                                  = 0x3
+       VINTR                                   = 0x8
+       VKILL                                   = 0x5
+       VLNEXT                                  = 0xe
+       VMADDR_CID_ANY                          = 0xffffffff
+       VMADDR_CID_HOST                         = 0x2
+       VMADDR_CID_HYPERVISOR                   = 0x0
+       VMADDR_CID_RESERVED                     = 0x1
+       VMADDR_PORT_ANY                         = 0xffffffff
+       VMIN                                    = 0x10
+       VM_LOADAVG                              = 0x2
+       VM_MACHFACTOR                           = 0x4
+       VM_MAXID                                = 0x6
+       VM_METER                                = 0x1
+       VM_SWAPUSAGE                            = 0x5
+       VQUIT                                   = 0x9
+       VREPRINT                                = 0x6
+       VSTART                                  = 0xc
+       VSTATUS                                 = 0x12
+       VSTOP                                   = 0xd
+       VSUSP                                   = 0xa
+       VT0                                     = 0x0
+       VT1                                     = 0x10000
+       VTDLY                                   = 0x10000
+       VTIME                                   = 0x11
+       VWERASE                                 = 0x4
+       WCONTINUED                              = 0x10
+       WCOREFLAG                               = 0x80
+       WEXITED                                 = 0x4
+       WNOHANG                                 = 0x1
+       WNOWAIT                                 = 0x20
+       WORDSIZE                                = 0x40
+       WSTOPPED                                = 0x8
+       WUNTRACED                               = 0x2
+       XATTR_CREATE                            = 0x2
+       XATTR_NODEFAULT                         = 0x10
+       XATTR_NOFOLLOW                          = 0x1
+       XATTR_NOSECURITY                        = 0x8
+       XATTR_REPLACE                           = 0x4
+       XATTR_SHOWCOMPRESSION                   = 0x20
 )
 
 // Errors
index 9c7c5e1654643dd289cc2b78e739fd3d8c67b0b7..440900112cd42098c79710f8a691ffb20e35e3f1 100644 (file)
@@ -1297,6 +1297,11 @@ const (
        SCM_RIGHTS                     = 0x1
        SCM_TIMESTAMP                  = 0x2
        SCM_TIME_INFO                  = 0x7
+       SEEK_CUR                       = 0x1
+       SEEK_DATA                      = 0x3
+       SEEK_END                       = 0x2
+       SEEK_HOLE                      = 0x4
+       SEEK_SET                       = 0x0
        SHUT_RD                        = 0x0
        SHUT_RDWR                      = 0x2
        SHUT_WR                        = 0x1
index b265abb25f89036eb36292ed74baf83f47e3d8c5..64520d31226b94632d384575d93f8ed4e05ad4bd 100644 (file)
@@ -1298,6 +1298,11 @@ const (
        SCM_RIGHTS                     = 0x1
        SCM_TIMESTAMP                  = 0x2
        SCM_TIME_INFO                  = 0x7
+       SEEK_CUR                       = 0x1
+       SEEK_DATA                      = 0x3
+       SEEK_END                       = 0x2
+       SEEK_HOLE                      = 0x4
+       SEEK_SET                       = 0x0
        SHUT_RD                        = 0x0
        SHUT_RDWR                      = 0x2
        SHUT_WR                        = 0x1
index 3df99f285f14edb9366a758b18f5e7317d851ca3..99e9a0e06e95f785edf015ae06ebea1d5e313a4c 100644 (file)
@@ -1276,6 +1276,11 @@ const (
        SCM_CREDS                      = 0x3
        SCM_RIGHTS                     = 0x1
        SCM_TIMESTAMP                  = 0x2
+       SEEK_CUR                       = 0x1
+       SEEK_DATA                      = 0x3
+       SEEK_END                       = 0x2
+       SEEK_HOLE                      = 0x4
+       SEEK_SET                       = 0x0
        SHUT_RD                        = 0x0
        SHUT_RDWR                      = 0x2
        SHUT_WR                        = 0x1
index 218d39906da6c4d51726629d904876a4bac747be..4c837711493ff1bc346f749e9ea163a860abb16e 100644 (file)
@@ -1298,6 +1298,11 @@ const (
        SCM_RIGHTS                     = 0x1
        SCM_TIMESTAMP                  = 0x2
        SCM_TIME_INFO                  = 0x7
+       SEEK_CUR                       = 0x1
+       SEEK_DATA                      = 0x3
+       SEEK_END                       = 0x2
+       SEEK_HOLE                      = 0x4
+       SEEK_SET                       = 0x0
        SHUT_RD                        = 0x0
        SHUT_RDWR                      = 0x2
        SHUT_WR                        = 0x1
index 47572aaa690f28311c9014e402f98ee6296f6b14..78d4b85ece50f6ec967661e9bbde11dbd7628d31 100644 (file)
@@ -228,7 +228,11 @@ const (
        BPF_OR                                      = 0x40
        BPF_PSEUDO_BTF_ID                           = 0x3
        BPF_PSEUDO_CALL                             = 0x1
+       BPF_PSEUDO_FUNC                             = 0x4
+       BPF_PSEUDO_KFUNC_CALL                       = 0x2
        BPF_PSEUDO_MAP_FD                           = 0x1
+       BPF_PSEUDO_MAP_IDX                          = 0x5
+       BPF_PSEUDO_MAP_IDX_VALUE                    = 0x6
        BPF_PSEUDO_MAP_VALUE                        = 0x2
        BPF_RET                                     = 0x6
        BPF_RSH                                     = 0x70
@@ -475,6 +479,8 @@ const (
        DM_LIST_VERSIONS                            = 0xc138fd0d
        DM_MAX_TYPE_NAME                            = 0x10
        DM_NAME_LEN                                 = 0x80
+       DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID          = 0x2
+       DM_NAME_LIST_FLAG_HAS_UUID                  = 0x1
        DM_NOFLUSH_FLAG                             = 0x800
        DM_PERSISTENT_DEV_FLAG                      = 0x8
        DM_QUERY_INACTIVE_TABLE_FLAG                = 0x1000
@@ -494,9 +500,9 @@ const (
        DM_UUID_FLAG                                = 0x4000
        DM_UUID_LEN                                 = 0x81
        DM_VERSION                                  = 0xc138fd00
-       DM_VERSION_EXTRA                            = "-ioctl (2021-02-01)"
+       DM_VERSION_EXTRA                            = "-ioctl (2021-03-22)"
        DM_VERSION_MAJOR                            = 0x4
-       DM_VERSION_MINOR                            = 0x2c
+       DM_VERSION_MINOR                            = 0x2d
        DM_VERSION_PATCHLEVEL                       = 0x0
        DT_BLK                                      = 0x6
        DT_CHR                                      = 0x2
@@ -981,12 +987,6 @@ const (
        HPFS_SUPER_MAGIC                            = 0xf995e849
        HUGETLBFS_MAGIC                             = 0x958458f6
        IBSHIFT                                     = 0x10
-       ICMPV6_FILTER                               = 0x1
-       ICMPV6_FILTER_BLOCK                         = 0x1
-       ICMPV6_FILTER_BLOCKOTHERS                   = 0x3
-       ICMPV6_FILTER_PASS                          = 0x2
-       ICMPV6_FILTER_PASSONLY                      = 0x4
-       ICMP_FILTER                                 = 0x1
        ICRNL                                       = 0x100
        IFA_F_DADFAILED                             = 0x8
        IFA_F_DEPRECATED                            = 0x20
@@ -1257,6 +1257,7 @@ const (
        KEXEC_ARCH_PARISC                           = 0xf0000
        KEXEC_ARCH_PPC                              = 0x140000
        KEXEC_ARCH_PPC64                            = 0x150000
+       KEXEC_ARCH_RISCV                            = 0xf30000
        KEXEC_ARCH_S390                             = 0x160000
        KEXEC_ARCH_SH                               = 0x2a0000
        KEXEC_ARCH_X86_64                           = 0x3e0000
@@ -1332,6 +1333,20 @@ const (
        KEY_SPEC_THREAD_KEYRING                     = -0x1
        KEY_SPEC_USER_KEYRING                       = -0x4
        KEY_SPEC_USER_SESSION_KEYRING               = -0x5
+       LANDLOCK_ACCESS_FS_EXECUTE                  = 0x1
+       LANDLOCK_ACCESS_FS_MAKE_BLOCK               = 0x800
+       LANDLOCK_ACCESS_FS_MAKE_CHAR                = 0x40
+       LANDLOCK_ACCESS_FS_MAKE_DIR                 = 0x80
+       LANDLOCK_ACCESS_FS_MAKE_FIFO                = 0x400
+       LANDLOCK_ACCESS_FS_MAKE_REG                 = 0x100
+       LANDLOCK_ACCESS_FS_MAKE_SOCK                = 0x200
+       LANDLOCK_ACCESS_FS_MAKE_SYM                 = 0x1000
+       LANDLOCK_ACCESS_FS_READ_DIR                 = 0x8
+       LANDLOCK_ACCESS_FS_READ_FILE                = 0x4
+       LANDLOCK_ACCESS_FS_REMOVE_DIR               = 0x10
+       LANDLOCK_ACCESS_FS_REMOVE_FILE              = 0x20
+       LANDLOCK_ACCESS_FS_WRITE_FILE               = 0x2
+       LANDLOCK_CREATE_RULESET_VERSION             = 0x1
        LINUX_REBOOT_CMD_CAD_OFF                    = 0x0
        LINUX_REBOOT_CMD_CAD_ON                     = 0x89abcdef
        LINUX_REBOOT_CMD_HALT                       = 0xcdef0123
@@ -1382,6 +1397,8 @@ const (
        MADV_NOHUGEPAGE                             = 0xf
        MADV_NORMAL                                 = 0x0
        MADV_PAGEOUT                                = 0x15
+       MADV_POPULATE_READ                          = 0x16
+       MADV_POPULATE_WRITE                         = 0x17
        MADV_RANDOM                                 = 0x1
        MADV_REMOVE                                 = 0x9
        MADV_SEQUENTIAL                             = 0x2
@@ -1406,6 +1423,10 @@ const (
        MCAST_LEAVE_SOURCE_GROUP                    = 0x2f
        MCAST_MSFILTER                              = 0x30
        MCAST_UNBLOCK_SOURCE                        = 0x2c
+       MEMGETREGIONINFO                            = 0xc0104d08
+       MEMREADOOB64                                = 0xc0184d16
+       MEMWRITE                                    = 0xc0304d18
+       MEMWRITEOOB64                               = 0xc0184d15
        MFD_ALLOW_SEALING                           = 0x2
        MFD_CLOEXEC                                 = 0x1
        MFD_HUGETLB                                 = 0x4
@@ -1494,7 +1515,35 @@ const (
        MS_SYNCHRONOUS                              = 0x10
        MS_UNBINDABLE                               = 0x20000
        MS_VERBOSE                                  = 0x8000
+       MTD_ABSENT                                  = 0x0
+       MTD_BIT_WRITEABLE                           = 0x800
+       MTD_CAP_NANDFLASH                           = 0x400
+       MTD_CAP_NORFLASH                            = 0xc00
+       MTD_CAP_NVRAM                               = 0x1c00
+       MTD_CAP_RAM                                 = 0x1c00
+       MTD_CAP_ROM                                 = 0x0
+       MTD_DATAFLASH                               = 0x6
        MTD_INODE_FS_MAGIC                          = 0x11307854
+       MTD_MAX_ECCPOS_ENTRIES                      = 0x40
+       MTD_MAX_OOBFREE_ENTRIES                     = 0x8
+       MTD_MLCNANDFLASH                            = 0x8
+       MTD_NANDECC_AUTOPLACE                       = 0x2
+       MTD_NANDECC_AUTOPL_USR                      = 0x4
+       MTD_NANDECC_OFF                             = 0x0
+       MTD_NANDECC_PLACE                           = 0x1
+       MTD_NANDECC_PLACEONLY                       = 0x3
+       MTD_NANDFLASH                               = 0x4
+       MTD_NORFLASH                                = 0x3
+       MTD_NO_ERASE                                = 0x1000
+       MTD_OTP_FACTORY                             = 0x1
+       MTD_OTP_OFF                                 = 0x0
+       MTD_OTP_USER                                = 0x2
+       MTD_POWERUP_LOCK                            = 0x2000
+       MTD_RAM                                     = 0x1
+       MTD_ROM                                     = 0x2
+       MTD_SLC_ON_MLC_EMULATION                    = 0x4000
+       MTD_UBIVOLUME                               = 0x7
+       MTD_WRITEABLE                               = 0x400
        NAME_MAX                                    = 0xff
        NCP_SUPER_MAGIC                             = 0x564c
        NETLINK_ADD_MEMBERSHIP                      = 0x1
@@ -1534,6 +1583,59 @@ const (
        NETLINK_XFRM                                = 0x6
        NETNSA_MAX                                  = 0x5
        NETNSA_NSID_NOT_ASSIGNED                    = -0x1
+       NFC_ATR_REQ_GB_MAXSIZE                      = 0x30
+       NFC_ATR_REQ_MAXSIZE                         = 0x40
+       NFC_ATR_RES_GB_MAXSIZE                      = 0x2f
+       NFC_ATR_RES_MAXSIZE                         = 0x40
+       NFC_COMM_ACTIVE                             = 0x0
+       NFC_COMM_PASSIVE                            = 0x1
+       NFC_DEVICE_NAME_MAXSIZE                     = 0x8
+       NFC_DIRECTION_RX                            = 0x0
+       NFC_DIRECTION_TX                            = 0x1
+       NFC_FIRMWARE_NAME_MAXSIZE                   = 0x20
+       NFC_GB_MAXSIZE                              = 0x30
+       NFC_GENL_MCAST_EVENT_NAME                   = "events"
+       NFC_GENL_NAME                               = "nfc"
+       NFC_GENL_VERSION                            = 0x1
+       NFC_HEADER_SIZE                             = 0x1
+       NFC_ISO15693_UID_MAXSIZE                    = 0x8
+       NFC_LLCP_MAX_SERVICE_NAME                   = 0x3f
+       NFC_LLCP_MIUX                               = 0x1
+       NFC_LLCP_REMOTE_LTO                         = 0x3
+       NFC_LLCP_REMOTE_MIU                         = 0x2
+       NFC_LLCP_REMOTE_RW                          = 0x4
+       NFC_LLCP_RW                                 = 0x0
+       NFC_NFCID1_MAXSIZE                          = 0xa
+       NFC_NFCID2_MAXSIZE                          = 0x8
+       NFC_NFCID3_MAXSIZE                          = 0xa
+       NFC_PROTO_FELICA                            = 0x3
+       NFC_PROTO_FELICA_MASK                       = 0x8
+       NFC_PROTO_ISO14443                          = 0x4
+       NFC_PROTO_ISO14443_B                        = 0x6
+       NFC_PROTO_ISO14443_B_MASK                   = 0x40
+       NFC_PROTO_ISO14443_MASK                     = 0x10
+       NFC_PROTO_ISO15693                          = 0x7
+       NFC_PROTO_ISO15693_MASK                     = 0x80
+       NFC_PROTO_JEWEL                             = 0x1
+       NFC_PROTO_JEWEL_MASK                        = 0x2
+       NFC_PROTO_MAX                               = 0x8
+       NFC_PROTO_MIFARE                            = 0x2
+       NFC_PROTO_MIFARE_MASK                       = 0x4
+       NFC_PROTO_NFC_DEP                           = 0x5
+       NFC_PROTO_NFC_DEP_MASK                      = 0x20
+       NFC_RAW_HEADER_SIZE                         = 0x2
+       NFC_RF_INITIATOR                            = 0x0
+       NFC_RF_NONE                                 = 0x2
+       NFC_RF_TARGET                               = 0x1
+       NFC_SENSB_RES_MAXSIZE                       = 0xc
+       NFC_SENSF_RES_MAXSIZE                       = 0x12
+       NFC_SE_DISABLED                             = 0x0
+       NFC_SE_EMBEDDED                             = 0x2
+       NFC_SE_ENABLED                              = 0x1
+       NFC_SE_UICC                                 = 0x1
+       NFC_SOCKPROTO_LLCP                          = 0x1
+       NFC_SOCKPROTO_MAX                           = 0x2
+       NFC_SOCKPROTO_RAW                           = 0x0
        NFNETLINK_V0                                = 0x0
        NFNLGRP_ACCT_QUOTA                          = 0x8
        NFNLGRP_CONNTRACK_DESTROY                   = 0x3
@@ -1551,11 +1653,12 @@ const (
        NFNL_MSG_BATCH_END                          = 0x11
        NFNL_NFA_NEST                               = 0x8000
        NFNL_SUBSYS_ACCT                            = 0x7
-       NFNL_SUBSYS_COUNT                           = 0xc
+       NFNL_SUBSYS_COUNT                           = 0xd
        NFNL_SUBSYS_CTHELPER                        = 0x9
        NFNL_SUBSYS_CTNETLINK                       = 0x1
        NFNL_SUBSYS_CTNETLINK_EXP                   = 0x2
        NFNL_SUBSYS_CTNETLINK_TIMEOUT               = 0x8
+       NFNL_SUBSYS_HOOK                            = 0xc
        NFNL_SUBSYS_IPSET                           = 0x6
        NFNL_SUBSYS_NFTABLES                        = 0xa
        NFNL_SUBSYS_NFT_COMPAT                      = 0xb
@@ -1671,14 +1774,19 @@ const (
        PERF_ATTR_SIZE_VER4                         = 0x68
        PERF_ATTR_SIZE_VER5                         = 0x70
        PERF_ATTR_SIZE_VER6                         = 0x78
+       PERF_ATTR_SIZE_VER7                         = 0x80
        PERF_AUX_FLAG_COLLISION                     = 0x8
+       PERF_AUX_FLAG_CORESIGHT_FORMAT_CORESIGHT    = 0x0
+       PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW          = 0x100
        PERF_AUX_FLAG_OVERWRITE                     = 0x2
        PERF_AUX_FLAG_PARTIAL                       = 0x4
+       PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK          = 0xff00
        PERF_AUX_FLAG_TRUNCATED                     = 0x1
        PERF_FLAG_FD_CLOEXEC                        = 0x8
        PERF_FLAG_FD_NO_GROUP                       = 0x1
        PERF_FLAG_FD_OUTPUT                         = 0x2
        PERF_FLAG_PID_CGROUP                        = 0x4
+       PERF_HW_EVENT_MASK                          = 0xffffffff
        PERF_MAX_CONTEXTS_PER_STACK                 = 0x8
        PERF_MAX_STACK_DEPTH                        = 0x7f
        PERF_MEM_BLK_ADDR                           = 0x4
@@ -1737,6 +1845,7 @@ const (
        PERF_MEM_TLB_OS                             = 0x40
        PERF_MEM_TLB_SHIFT                          = 0x1a
        PERF_MEM_TLB_WK                             = 0x20
+       PERF_PMU_TYPE_SHIFT                         = 0x20
        PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER        = 0x1
        PERF_RECORD_MISC_COMM_EXEC                  = 0x2000
        PERF_RECORD_MISC_CPUMODE_MASK               = 0x7
@@ -1836,7 +1945,15 @@ const (
        PR_PAC_APGAKEY                              = 0x10
        PR_PAC_APIAKEY                              = 0x1
        PR_PAC_APIBKEY                              = 0x2
+       PR_PAC_GET_ENABLED_KEYS                     = 0x3d
        PR_PAC_RESET_KEYS                           = 0x36
+       PR_PAC_SET_ENABLED_KEYS                     = 0x3c
+       PR_SCHED_CORE                               = 0x3e
+       PR_SCHED_CORE_CREATE                        = 0x1
+       PR_SCHED_CORE_GET                           = 0x0
+       PR_SCHED_CORE_MAX                           = 0x4
+       PR_SCHED_CORE_SHARE_FROM                    = 0x3
+       PR_SCHED_CORE_SHARE_TO                      = 0x2
        PR_SET_CHILD_SUBREAPER                      = 0x24
        PR_SET_DUMPABLE                             = 0x4
        PR_SET_ENDIAN                               = 0x14
@@ -1918,6 +2035,7 @@ const (
        PTRACE_GETREGSET                            = 0x4204
        PTRACE_GETSIGINFO                           = 0x4202
        PTRACE_GETSIGMASK                           = 0x420a
+       PTRACE_GET_RSEQ_CONFIGURATION               = 0x420f
        PTRACE_GET_SYSCALL_INFO                     = 0x420e
        PTRACE_INTERRUPT                            = 0x4207
        PTRACE_KILL                                 = 0x8
@@ -1959,6 +2077,11 @@ const (
        QNX4_SUPER_MAGIC                            = 0x2f
        QNX6_SUPER_MAGIC                            = 0x68191122
        RAMFS_MAGIC                                 = 0x858458f6
+       RAW_PAYLOAD_DIGITAL                         = 0x3
+       RAW_PAYLOAD_HCI                             = 0x2
+       RAW_PAYLOAD_LLCP                            = 0x0
+       RAW_PAYLOAD_NCI                             = 0x1
+       RAW_PAYLOAD_PROPRIETARY                     = 0x4
        RDTGROUP_SUPER_MAGIC                        = 0x7655821
        REISERFS_SUPER_MAGIC                        = 0x52654973
        RENAME_EXCHANGE                             = 0x2
@@ -2073,6 +2196,7 @@ const (
        RTM_DELNEIGH                                = 0x1d
        RTM_DELNETCONF                              = 0x51
        RTM_DELNEXTHOP                              = 0x69
+       RTM_DELNEXTHOPBUCKET                        = 0x75
        RTM_DELNSID                                 = 0x59
        RTM_DELQDISC                                = 0x25
        RTM_DELROUTE                                = 0x19
@@ -2103,6 +2227,7 @@ const (
        RTM_GETNEIGHTBL                             = 0x42
        RTM_GETNETCONF                              = 0x52
        RTM_GETNEXTHOP                              = 0x6a
+       RTM_GETNEXTHOPBUCKET                        = 0x76
        RTM_GETNSID                                 = 0x5a
        RTM_GETQDISC                                = 0x26
        RTM_GETROUTE                                = 0x1a
@@ -2111,7 +2236,7 @@ const (
        RTM_GETTCLASS                               = 0x2a
        RTM_GETTFILTER                              = 0x2e
        RTM_GETVLAN                                 = 0x72
-       RTM_MAX                                     = 0x73
+       RTM_MAX                                     = 0x77
        RTM_NEWACTION                               = 0x30
        RTM_NEWADDR                                 = 0x14
        RTM_NEWADDRLABEL                            = 0x48
@@ -2125,6 +2250,7 @@ const (
        RTM_NEWNEIGHTBL                             = 0x40
        RTM_NEWNETCONF                              = 0x50
        RTM_NEWNEXTHOP                              = 0x68
+       RTM_NEWNEXTHOPBUCKET                        = 0x74
        RTM_NEWNSID                                 = 0x58
        RTM_NEWNVLAN                                = 0x70
        RTM_NEWPREFIX                               = 0x34
@@ -2134,8 +2260,8 @@ const (
        RTM_NEWSTATS                                = 0x5c
        RTM_NEWTCLASS                               = 0x28
        RTM_NEWTFILTER                              = 0x2c
-       RTM_NR_FAMILIES                             = 0x19
-       RTM_NR_MSGTYPES                             = 0x64
+       RTM_NR_FAMILIES                             = 0x1a
+       RTM_NR_MSGTYPES                             = 0x68
        RTM_SETDCB                                  = 0x4f
        RTM_SETLINK                                 = 0x13
        RTM_SETNEIGHTBL                             = 0x43
@@ -2163,6 +2289,7 @@ const (
        RTPROT_MROUTED                              = 0x11
        RTPROT_MRT                                  = 0xa
        RTPROT_NTK                                  = 0xf
+       RTPROT_OPENR                                = 0x63
        RTPROT_OSPF                                 = 0xbc
        RTPROT_RA                                   = 0x9
        RTPROT_REDIRECT                             = 0x1
@@ -2193,7 +2320,14 @@ const (
        SECCOMP_MODE_DISABLED                       = 0x0
        SECCOMP_MODE_FILTER                         = 0x2
        SECCOMP_MODE_STRICT                         = 0x1
+       SECRETMEM_MAGIC                             = 0x5345434d
        SECURITYFS_MAGIC                            = 0x73636673
+       SEEK_CUR                                    = 0x1
+       SEEK_DATA                                   = 0x3
+       SEEK_END                                    = 0x2
+       SEEK_HOLE                                   = 0x4
+       SEEK_MAX                                    = 0x4
+       SEEK_SET                                    = 0x0
        SELINUX_MAGIC                               = 0xf97cff8c
        SHUT_RD                                     = 0x0
        SHUT_RDWR                                   = 0x2
@@ -2440,6 +2574,14 @@ const (
        TCOFLUSH                                    = 0x1
        TCOOFF                                      = 0x0
        TCOON                                       = 0x1
+       TCPOPT_EOL                                  = 0x0
+       TCPOPT_MAXSEG                               = 0x2
+       TCPOPT_NOP                                  = 0x1
+       TCPOPT_SACK                                 = 0x5
+       TCPOPT_SACK_PERMITTED                       = 0x4
+       TCPOPT_TIMESTAMP                            = 0x8
+       TCPOPT_TSTAMP_HDR                           = 0x101080a
+       TCPOPT_WINDOW                               = 0x3
        TCP_CC_INFO                                 = 0x1a
        TCP_CM_INQ                                  = 0x24
        TCP_CONGESTION                              = 0xd
index e91a1a95792b2eeb40672794529fbf96d6320746..697811a460082b6857fade29c77667db87ec45ae 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x81484d11
+       ECCGETSTATS                      = 0x80104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -123,6 +125,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x40084d02
+       MEMERASE64                       = 0x40104d14
+       MEMGETBADBLOCK                   = 0x40084d0b
+       MEMGETINFO                       = 0x80204d01
+       MEMGETOOBSEL                     = 0x80c84d0a
+       MEMGETREGIONCOUNT                = 0x80044d07
+       MEMISLOCKED                      = 0x80084d17
+       MEMLOCK                          = 0x40084d05
+       MEMREADOOB                       = 0xc00c4d04
+       MEMSETBADBLOCK                   = 0x40084d0c
+       MEMUNLOCK                        = 0x40084d06
+       MEMWRITEOOB                      = 0xc00c4d03
+       MTDFILEMODE                      = 0x4d13
        NFDBITS                          = 0x20
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -132,6 +147,11 @@ const (
        NS_GET_USERNS                    = 0xb701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x400c4d19
+       OTPGETREGIONCOUNT                = 0x40044d0e
+       OTPGETREGIONINFO                 = 0x400c4d0f
+       OTPLOCK                          = 0x800c4d10
+       OTPSELECT                        = 0x80044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -289,6 +309,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x10
index a9cbac64439e3ae6836aaed2b09d0aec99c43877..7d8d93bfc4b0b5c0d2ed8b5461293ea12b6fcc4f 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x81484d11
+       ECCGETSTATS                      = 0x80104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -123,6 +125,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x40084d02
+       MEMERASE64                       = 0x40104d14
+       MEMGETBADBLOCK                   = 0x40084d0b
+       MEMGETINFO                       = 0x80204d01
+       MEMGETOOBSEL                     = 0x80c84d0a
+       MEMGETREGIONCOUNT                = 0x80044d07
+       MEMISLOCKED                      = 0x80084d17
+       MEMLOCK                          = 0x40084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x40084d0c
+       MEMUNLOCK                        = 0x40084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x4d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -132,6 +147,11 @@ const (
        NS_GET_USERNS                    = 0xb701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x400c4d19
+       OTPGETREGIONCOUNT                = 0x40044d0e
+       OTPGETREGIONINFO                 = 0x400c4d0f
+       OTPLOCK                          = 0x800c4d10
+       OTPSELECT                        = 0x80044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -290,6 +310,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x10
index d74f3c15a1d8366c7a088c9665d83bb31db4696e..f707d508941d4804268b8acea029b7ac6e1a1c5b 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x81484d11
+       ECCGETSTATS                      = 0x80104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x40084d02
+       MEMERASE64                       = 0x40104d14
+       MEMGETBADBLOCK                   = 0x40084d0b
+       MEMGETINFO                       = 0x80204d01
+       MEMGETOOBSEL                     = 0x80c84d0a
+       MEMGETREGIONCOUNT                = 0x80044d07
+       MEMISLOCKED                      = 0x80084d17
+       MEMLOCK                          = 0x40084d05
+       MEMREADOOB                       = 0xc00c4d04
+       MEMSETBADBLOCK                   = 0x40084d0c
+       MEMUNLOCK                        = 0x40084d06
+       MEMWRITEOOB                      = 0xc00c4d03
+       MTDFILEMODE                      = 0x4d13
        NFDBITS                          = 0x20
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0xb701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x400c4d19
+       OTPGETREGIONCOUNT                = 0x40044d0e
+       OTPGETREGIONINFO                 = 0x400c4d0f
+       OTPLOCK                          = 0x800c4d10
+       OTPSELECT                        = 0x80044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -296,6 +316,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x10
index e1538995b49d1446ee1f91b8d3da3ac87eed93c0..3a67a9c85211645970d4ed7427baf021b99ba040 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x81484d11
+       ECCGETSTATS                      = 0x80104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -124,6 +126,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x40084d02
+       MEMERASE64                       = 0x40104d14
+       MEMGETBADBLOCK                   = 0x40084d0b
+       MEMGETINFO                       = 0x80204d01
+       MEMGETOOBSEL                     = 0x80c84d0a
+       MEMGETREGIONCOUNT                = 0x80044d07
+       MEMISLOCKED                      = 0x80084d17
+       MEMLOCK                          = 0x40084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x40084d0c
+       MEMUNLOCK                        = 0x40084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x4d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -133,6 +148,11 @@ const (
        NS_GET_USERNS                    = 0xb701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x400c4d19
+       OTPGETREGIONCOUNT                = 0x40044d0e
+       OTPGETREGIONINFO                 = 0x400c4d0f
+       OTPLOCK                          = 0x800c4d10
+       OTPSELECT                        = 0x80044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -286,6 +306,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x10
index 5e8e71ff863547eac670ea1dc62ad9e8f5d5ba11..a7ccef56c52a9ce93de57f3096176c9f941326d4 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc00c4d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc00c4d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x20
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x8
        O_ASYNC                          = 0x1000
        O_CLOEXEC                        = 0x80000
@@ -289,6 +309,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0x100
        SO_PASSCRED                      = 0x11
index e670ee148140522bbbdf03836a1c143d982ff2c5..f7b7cec910f00295ec484bcd6f12e7c843ac3ed8 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x8
        O_ASYNC                          = 0x1000
        O_CLOEXEC                        = 0x80000
@@ -289,6 +309,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0x100
        SO_PASSCRED                      = 0x11
index dd11eacb81e0b5b0e09dbe818f7bd37445e0dcd6..4fcacf95849be5362c4a08913470102a0492a177 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x8
        O_ASYNC                          = 0x1000
        O_CLOEXEC                        = 0x80000
@@ -289,6 +309,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0x100
        SO_PASSCRED                      = 0x11
index a0a5b22ae93a734c1a13f00b34b45f32d475a84f..6f6c223a2cb667db5c0e474de3f21225c2303336 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc00c4d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc00c4d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x20
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x8
        O_ASYNC                          = 0x1000
        O_CLOEXEC                        = 0x80000
@@ -289,6 +309,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0x100
        SO_PASSCRED                      = 0x11
index d9530e5fbfbc93b654d1d991c5da7aa14d0a4cc0..59e522bcf4e05e28820ab462a354ca96cdf5a1f5 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x300
        CSIZE                            = 0x300
        CSTOPB                           = 0x400
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x40
        ECHOE                            = 0x2
        ECHOK                            = 0x4
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x2000
        MCL_FUTURE                       = 0x4000
        MCL_ONFAULT                      = 0x8000
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc00c4d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc00c4d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x20
        NL2                              = 0x200
        NL3                              = 0x300
@@ -132,6 +147,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x4
        ONLCR                            = 0x2
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -344,6 +364,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x14
index e60102f6a92add70bc84f17a87be1305e5e5d372..d4264a0f73e7832e0e1f742116d031cb92e95ce2 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x300
        CSIZE                            = 0x300
        CSTOPB                           = 0x400
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x40
        ECHOE                            = 0x2
        ECHOK                            = 0x4
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x2000
        MCL_FUTURE                       = 0x4000
        MCL_ONFAULT                      = 0x8000
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x40
        NL2                              = 0x200
        NL3                              = 0x300
@@ -132,6 +147,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x4
        ONLCR                            = 0x2
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -348,6 +368,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x14
index 838ff4ea6d069d1ad6733e48883f26bcdc34b097..21cbec1dd35f5d1004a2a931e2f07e94be9a6347 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x300
        CSIZE                            = 0x300
        CSTOPB                           = 0x400
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x40
        ECHOE                            = 0x2
        ECHOK                            = 0x4
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x2000
        MCL_FUTURE                       = 0x4000
        MCL_ONFAULT                      = 0x8000
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x40
        NL2                              = 0x200
        NL3                              = 0x300
@@ -132,6 +147,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x4
        ONLCR                            = 0x2
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -348,6 +368,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x14
index 7cc98f09c3ed1e24dc6ffa4732fe1f6eb2dae89d..9b05bf12fc34a852aaa03f18a0716a6753f5001e 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x81484d11
+       ECCGETSTATS                      = 0x80104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x40084d02
+       MEMERASE64                       = 0x40104d14
+       MEMGETBADBLOCK                   = 0x40084d0b
+       MEMGETINFO                       = 0x80204d01
+       MEMGETOOBSEL                     = 0x80c84d0a
+       MEMGETREGIONCOUNT                = 0x80044d07
+       MEMISLOCKED                      = 0x80084d17
+       MEMLOCK                          = 0x40084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x40084d0c
+       MEMUNLOCK                        = 0x40084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x4d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0xb701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x400c4d19
+       OTPGETREGIONCOUNT                = 0x40044d0e
+       OTPGETREGIONINFO                 = 0x400c4d0f
+       OTPLOCK                          = 0x800c4d10
+       OTPSELECT                        = 0x80044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -277,6 +297,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x10
index 6d30e6fd846ae378e1dd4c94ce3c78876947cc9e..bd82ace09a579df1b276b8850bfd4089bab3dfbc 100644 (file)
@@ -60,6 +60,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x81484d11
+       ECCGETSTATS                      = 0x80104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -121,6 +123,19 @@ const (
        MCL_CURRENT                      = 0x1
        MCL_FUTURE                       = 0x2
        MCL_ONFAULT                      = 0x4
+       MEMERASE                         = 0x40084d02
+       MEMERASE64                       = 0x40104d14
+       MEMGETBADBLOCK                   = 0x40084d0b
+       MEMGETINFO                       = 0x80204d01
+       MEMGETOOBSEL                     = 0x80c84d0a
+       MEMGETREGIONCOUNT                = 0x80044d07
+       MEMISLOCKED                      = 0x80084d17
+       MEMLOCK                          = 0x40084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x40084d0c
+       MEMUNLOCK                        = 0x40084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x4d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -130,6 +145,11 @@ const (
        NS_GET_USERNS                    = 0xb701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x400c4d19
+       OTPGETREGIONCOUNT                = 0x40044d0e
+       OTPGETREGIONINFO                 = 0x400c4d0f
+       OTPLOCK                          = 0x800c4d10
+       OTPSELECT                        = 0x80044d0d
        O_APPEND                         = 0x400
        O_ASYNC                          = 0x2000
        O_CLOEXEC                        = 0x80000
@@ -352,6 +372,7 @@ const (
        SO_MARK                          = 0x24
        SO_MAX_PACING_RATE               = 0x2f
        SO_MEMINFO                       = 0x37
+       SO_NETNS_COOKIE                  = 0x47
        SO_NOFCS                         = 0x2b
        SO_OOBINLINE                     = 0xa
        SO_PASSCRED                      = 0x10
index d5e2dc94faa4d057530366c3a81595f77964ffb7..1f8bded56bbc1f1c32abc99f853583d378bf501b 100644 (file)
@@ -63,6 +63,8 @@ const (
        CS8                              = 0x30
        CSIZE                            = 0x30
        CSTOPB                           = 0x40
+       ECCGETLAYOUT                     = 0x41484d11
+       ECCGETSTATS                      = 0x40104d12
        ECHOCTL                          = 0x200
        ECHOE                            = 0x10
        ECHOK                            = 0x20
@@ -126,6 +128,19 @@ const (
        MCL_CURRENT                      = 0x2000
        MCL_FUTURE                       = 0x4000
        MCL_ONFAULT                      = 0x8000
+       MEMERASE                         = 0x80084d02
+       MEMERASE64                       = 0x80104d14
+       MEMGETBADBLOCK                   = 0x80084d0b
+       MEMGETINFO                       = 0x40204d01
+       MEMGETOOBSEL                     = 0x40c84d0a
+       MEMGETREGIONCOUNT                = 0x40044d07
+       MEMISLOCKED                      = 0x40084d17
+       MEMLOCK                          = 0x80084d05
+       MEMREADOOB                       = 0xc0104d04
+       MEMSETBADBLOCK                   = 0x80084d0c
+       MEMUNLOCK                        = 0x80084d06
+       MEMWRITEOOB                      = 0xc0104d03
+       MTDFILEMODE                      = 0x20004d13
        NFDBITS                          = 0x40
        NLDLY                            = 0x100
        NOFLSH                           = 0x80
@@ -135,6 +150,11 @@ const (
        NS_GET_USERNS                    = 0x2000b701
        OLCUC                            = 0x2
        ONLCR                            = 0x4
+       OTPERASE                         = 0x800c4d19
+       OTPGETREGIONCOUNT                = 0x80044d0e
+       OTPGETREGIONINFO                 = 0x800c4d0f
+       OTPLOCK                          = 0x400c4d10
+       OTPSELECT                        = 0x40044d0d
        O_APPEND                         = 0x8
        O_ASYNC                          = 0x40
        O_CLOEXEC                        = 0x400000
@@ -343,6 +363,7 @@ const (
        SO_MARK                          = 0x22
        SO_MAX_PACING_RATE               = 0x31
        SO_MEMINFO                       = 0x39
+       SO_NETNS_COOKIE                  = 0x50
        SO_NOFCS                         = 0x27
        SO_OOBINLINE                     = 0x100
        SO_PASSCRED                      = 0x2
index 593cc0feffa01b490e6445699a4493da13f0d04c..6d56edc05ac3cdb8181e5a56d95486b71f1e7fcf 100644 (file)
@@ -1020,7 +1020,10 @@ const (
        RLIMIT_CPU                        = 0x0
        RLIMIT_DATA                       = 0x2
        RLIMIT_FSIZE                      = 0x1
+       RLIMIT_MEMLOCK                    = 0x6
        RLIMIT_NOFILE                     = 0x8
+       RLIMIT_NPROC                      = 0x7
+       RLIMIT_RSS                        = 0x5
        RLIMIT_STACK                      = 0x3
        RLIM_INFINITY                     = 0x7fffffffffffffff
        RTAX_AUTHOR                       = 0x6
index a4e4c22314e0a635d4d5d4538aaaeb24d9e83428..aef6c085609ab445c491cb095e9f253b4ea24d33 100644 (file)
@@ -1020,7 +1020,10 @@ const (
        RLIMIT_CPU                        = 0x0
        RLIMIT_DATA                       = 0x2
        RLIMIT_FSIZE                      = 0x1
+       RLIMIT_MEMLOCK                    = 0x6
        RLIMIT_NOFILE                     = 0x8
+       RLIMIT_NPROC                      = 0x7
+       RLIMIT_RSS                        = 0x5
        RLIMIT_STACK                      = 0x3
        RLIM_INFINITY                     = 0x7fffffffffffffff
        RTAX_AUTHOR                       = 0x6
index d4efe8d457aca1e22cb810498a40af10c34dcce3..0ae0ed4cb8af7d2e6a6afa387efd4df0354dd3a5 100644 (file)
@@ -734,6 +734,65 @@ var libc_sendfile_trampoline_addr uintptr
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func shmat(id int, addr uintptr, flag int) (ret uintptr, err error) {
+       r0, _, e1 := syscall_syscall(libc_shmat_trampoline_addr, uintptr(id), uintptr(addr), uintptr(flag))
+       ret = uintptr(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmat_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmat shmat "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) {
+       r0, _, e1 := syscall_syscall(libc_shmctl_trampoline_addr, uintptr(id), uintptr(cmd), uintptr(unsafe.Pointer(buf)))
+       result = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmctl_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmctl shmctl "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmdt(addr uintptr) (err error) {
+       _, _, e1 := syscall_syscall(libc_shmdt_trampoline_addr, uintptr(addr), 0, 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmdt_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmdt shmdt "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmget(key int, size int, flag int) (id int, err error) {
+       r0, _, e1 := syscall_syscall(libc_shmget_trampoline_addr, uintptr(key), uintptr(size), uintptr(flag))
+       id = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmget_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmget shmget "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
index bc169c2ab9ca8d3526b1970fba3a97f81cf07f24..eac6ca806f4d5c65ff3c9f564a6f3c7de73063d7 100644 (file)
@@ -264,6 +264,30 @@ TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0
 GLOBL  ·libc_sendfile_trampoline_addr(SB), RODATA, $8
 DATA   ·libc_sendfile_trampoline_addr(SB)/8, $libc_sendfile_trampoline<>(SB)
 
+TEXT libc_shmat_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmat(SB)
+
+GLOBL  ·libc_shmat_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmat_trampoline_addr(SB)/8, $libc_shmat_trampoline<>(SB)
+
+TEXT libc_shmctl_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmctl(SB)
+
+GLOBL  ·libc_shmctl_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmctl_trampoline_addr(SB)/8, $libc_shmctl_trampoline<>(SB)
+
+TEXT libc_shmdt_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmdt(SB)
+
+GLOBL  ·libc_shmdt_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmdt_trampoline_addr(SB)/8, $libc_shmdt_trampoline<>(SB)
+
+TEXT libc_shmget_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmget(SB)
+
+GLOBL  ·libc_shmget_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmget_trampoline_addr(SB)/8, $libc_shmget_trampoline<>(SB)
+
 TEXT libc_access_trampoline<>(SB),NOSPLIT,$0-0
        JMP     libc_access(SB)
 
index f2ee2bd33b93f2b31b65ea8f5d0263884f690d8d..cf71be3edb3b34c33cbadcb9b883a158b7cb795d 100644 (file)
@@ -734,6 +734,65 @@ var libc_sendfile_trampoline_addr uintptr
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func shmat(id int, addr uintptr, flag int) (ret uintptr, err error) {
+       r0, _, e1 := syscall_syscall(libc_shmat_trampoline_addr, uintptr(id), uintptr(addr), uintptr(flag))
+       ret = uintptr(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmat_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmat shmat "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) {
+       r0, _, e1 := syscall_syscall(libc_shmctl_trampoline_addr, uintptr(id), uintptr(cmd), uintptr(unsafe.Pointer(buf)))
+       result = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmctl_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmctl shmctl "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmdt(addr uintptr) (err error) {
+       _, _, e1 := syscall_syscall(libc_shmdt_trampoline_addr, uintptr(addr), 0, 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmdt_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmdt shmdt "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmget(key int, size int, flag int) (id int, err error) {
+       r0, _, e1 := syscall_syscall(libc_shmget_trampoline_addr, uintptr(key), uintptr(size), uintptr(flag))
+       id = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+var libc_shmget_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_shmget shmget "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
index 33e19776db4e2bd22f4311ca68090a51ce3a0ad4..4ebcf217585403cd63c424c65b67b83379e51dc2 100644 (file)
@@ -264,6 +264,30 @@ TEXT libc_sendfile_trampoline<>(SB),NOSPLIT,$0-0
 GLOBL  ·libc_sendfile_trampoline_addr(SB), RODATA, $8
 DATA   ·libc_sendfile_trampoline_addr(SB)/8, $libc_sendfile_trampoline<>(SB)
 
+TEXT libc_shmat_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmat(SB)
+
+GLOBL  ·libc_shmat_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmat_trampoline_addr(SB)/8, $libc_shmat_trampoline<>(SB)
+
+TEXT libc_shmctl_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmctl(SB)
+
+GLOBL  ·libc_shmctl_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmctl_trampoline_addr(SB)/8, $libc_shmctl_trampoline<>(SB)
+
+TEXT libc_shmdt_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmdt(SB)
+
+GLOBL  ·libc_shmdt_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmdt_trampoline_addr(SB)/8, $libc_shmdt_trampoline<>(SB)
+
+TEXT libc_shmget_trampoline<>(SB),NOSPLIT,$0-0
+       JMP     libc_shmget(SB)
+
+GLOBL  ·libc_shmget_trampoline_addr(SB), RODATA, $8
+DATA   ·libc_shmget_trampoline_addr(SB)/8, $libc_shmget_trampoline<>(SB)
+
 TEXT libc_access_trampoline<>(SB),NOSPLIT,$0-0
        JMP     libc_access(SB)
 
index 7305cc915b7a77e75b2b88a24de7d057eb312313..4f5da1f54f80983ca163b679b4e4f93705f66e4e 100644 (file)
@@ -48,6 +48,16 @@ func ioctl(fd int, req uint, arg uintptr) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
+       _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(oldpath)
@@ -100,6 +110,16 @@ func openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err e
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
        r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0)
        n = int(r0)
@@ -1201,7 +1221,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+func Prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
        _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
        if e1 != 0 {
                err = errnoErr(e1)
@@ -1935,8 +1955,63 @@ func ProcessVMWritev(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags u
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+func PidfdOpen(pid int, flags int) (fd int, err error) {
+       r0, _, e1 := Syscall(SYS_PIDFD_OPEN, uintptr(pid), uintptr(flags), 0)
+       fd = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func PidfdGetfd(pidfd int, targetfd int, flags int) (fd int, err error) {
+       r0, _, e1 := Syscall(SYS_PIDFD_GETFD, uintptr(pidfd), uintptr(targetfd), uintptr(flags))
+       fd = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmat(id int, addr uintptr, flag int) (ret uintptr, err error) {
+       r0, _, e1 := Syscall(SYS_SHMAT, uintptr(id), uintptr(addr), uintptr(flag))
+       ret = uintptr(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) {
+       r0, _, e1 := Syscall(SYS_SHMCTL, uintptr(id), uintptr(cmd), uintptr(unsafe.Pointer(buf)))
+       result = int(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmdt(addr uintptr) (err error) {
+       _, _, e1 := Syscall(SYS_SHMDT, uintptr(addr), 0, 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func shmget(key int, size int, flag int) (id int, err error) {
+       r0, _, e1 := Syscall(SYS_SHMGET, uintptr(key), uintptr(size), uintptr(flag))
+       id = int(r0)
        if e1 != 0 {
                err = errnoErr(e1)
        }
index e37096e4deccb9e6dbde1e97c74d31cb5ff223dd..ff90c81e7300eb19641ea5c9b7eb273fde949121 100644 (file)
@@ -46,37 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -181,17 +150,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -566,14 +524,3 @@ func utimes(path string, times *[2]Timeval) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index 9919d8486d41b95ba98830c3b4ce1feb35f7fec4..fa7d3dbe4e94d5ec4912d851cb2acee633c52473 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -191,17 +170,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func inotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -711,27 +679,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(cmdline)
index 076754d48d1d8fa194ce1ad0c41d45b1e79f45ad..654f91530f6950860dfdbbc443cf0fa4111c38ea 100644 (file)
@@ -46,16 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
        r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
        fd = int(r0)
@@ -235,27 +225,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -340,17 +309,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Lchown(path string, uid int, gid int) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -681,17 +639,6 @@ func setrlimit(resource int, rlim *rlimit32) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func armSyncFileRange(fd int, flags int, off int64, n int64) (err error) {
        _, _, e1 := Syscall6(SYS_ARM_SYNC_FILE_RANGE, uintptr(fd), uintptr(flags), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32))
        if e1 != 0 {
index 4703cf3c3385b8d58531e908eaa2da0c5c98e6af..6d1552885314b402c1462928dfa6b2de62eb2bb0 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -544,17 +523,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -706,18 +674,6 @@ func Pause() (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe() (p1 int, p2 int, err error) {
-       r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
-       p1 = int(r0)
-       p2 = int(r1)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
        r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
        xaddr = uintptr(r0)
@@ -746,14 +702,3 @@ func setrlimit(resource int, rlim *rlimit32) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index a134f9a4d2e06bd3416b247cb9c3a0138204840a..1e20d72df21ec3a4e57d272f9c57ace9ee495c29 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -717,14 +696,3 @@ func stat(path string, st *stat_t) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index b1fff2d946a225f91ffeacebfcebe78f6d34559a..82b5e2d9eda459f5f669f442b2cd948b41bd0f9b 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -717,14 +696,3 @@ func stat(path string, st *stat_t) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index d13d6da01ef899f932f2cd1f4d33de6a3e124e3a..a0440c1d43be3b9757038590a819bc9dfa6f85f4 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -544,17 +523,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -706,18 +674,6 @@ func Pause() (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe() (p1 int, p2 int, err error) {
-       r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
-       p1 = int(r0)
-       p2 = int(r1)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
        r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
        xaddr = uintptr(r0)
@@ -746,14 +702,3 @@ func setrlimit(resource int, rlim *rlimit32) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index 927cf1a00f0d72b6a8b6b2fc7c18c8a6bf7a1f9e..5864b9ca64903564e0122568d12beff0760b19e8 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -161,17 +140,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -717,27 +685,6 @@ func setrlimit(resource int, rlim *rlimit32) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func syncFileRange2(fd int, flags int, off int64, n int64) (err error) {
        _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off>>32), uintptr(off), uintptr(n>>32), uintptr(n))
        if e1 != 0 {
index da8ec0396665bdae6808bac03e444691d9d0b950..beeb49e34217a8623d54fb97c96ad0ceaee09c4b 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -191,17 +170,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -763,27 +731,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func syncFileRange2(fd int, flags int, off int64, n int64) (err error) {
        _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off), uintptr(n), 0, 0)
        if e1 != 0 {
index 083f493bb6f473f1e8f7df4ae0d3f328c734d94c..53139b82c7be1a49e803ab9ff1697d099316c04d 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -191,17 +170,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
        _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
        if e1 != 0 {
@@ -763,27 +731,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func syncFileRange2(fd int, flags int, off int64, n int64) (err error) {
        _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off), uintptr(n), 0, 0)
        if e1 != 0 {
index bb347407d3d476cb80148854ae30679c49aed5ea..202add37d10a544127ce0a5c6387204207e0a5a8 100644 (file)
@@ -46,27 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func EpollCreate(size int) (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
        var _p0 unsafe.Pointer
        if len(events) > 0 {
@@ -191,17 +170,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Lchown(path string, uid int, gid int) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -553,17 +521,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(cmdline)
index 8edc517e1e65c0ea38b95acdfb38f8eee28390bc..2ab268c3435930fc51b6e5efe36b958845552ffe 100644 (file)
@@ -73,16 +73,6 @@ func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func dup2(oldfd int, newfd int) (err error) {
-       _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Fchown(fd int, uid int, gid int) (err error) {
        _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
        if e1 != 0 {
@@ -180,17 +170,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-       r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-       fd = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Lchown(path string, uid int, gid int) (err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -718,24 +697,3 @@ func utimes(path string, times *[2]Timeval) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
-       r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout))
-       n = int(r0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index 4e18d5c99fd361fb7ffa828f04b22b390a14626f..b5f926cee2a995e9e109ac2ccfc5c87ab7d87317 100644 (file)
@@ -141,6 +141,11 @@ import (
 //go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so"
 //go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
 //go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so"
+//go:cgo_import_dynamic libc_port_create port_create "libc.so"
+//go:cgo_import_dynamic libc_port_associate port_associate "libc.so"
+//go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so"
+//go:cgo_import_dynamic libc_port_get port_get "libc.so"
+//go:cgo_import_dynamic libc_port_getn port_getn "libc.so"
 
 //go:linkname procpipe libc_pipe
 //go:linkname procpipe2 libc_pipe2
@@ -272,6 +277,11 @@ import (
 //go:linkname procgetpeername libc_getpeername
 //go:linkname procsetsockopt libc_setsockopt
 //go:linkname procrecvfrom libc_recvfrom
+//go:linkname procport_create libc_port_create
+//go:linkname procport_associate libc_port_associate
+//go:linkname procport_dissociate libc_port_dissociate
+//go:linkname procport_get libc_port_get
+//go:linkname procport_getn libc_port_getn
 
 var (
        procpipe,
@@ -403,7 +413,12 @@ var (
        proc__xnet_getsockopt,
        procgetpeername,
        procsetsockopt,
-       procrecvfrom syscallFunc
+       procrecvfrom,
+       procport_create,
+       procport_associate,
+       procport_dissociate,
+       procport_get,
+       procport_getn syscallFunc
 )
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
@@ -1981,3 +1996,58 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
        }
        return
 }
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func port_create() (n int, err error) {
+       r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_create)), 0, 0, 0, 0, 0, 0, 0)
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error) {
+       r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_associate)), 5, uintptr(port), uintptr(source), uintptr(object), uintptr(events), uintptr(unsafe.Pointer(user)), 0)
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func port_dissociate(port int, source int, object uintptr) (n int, err error) {
+       r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_dissociate)), 3, uintptr(port), uintptr(source), uintptr(object), 0, 0, 0)
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func port_get(port int, pe *portEvent, timeout *Timespec) (n int, err error) {
+       r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_get)), 3, uintptr(port), uintptr(unsafe.Pointer(pe)), uintptr(unsafe.Pointer(timeout)), 0, 0, 0)
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func port_getn(port int, pe *portEvent, max uint32, nget *uint32, timeout *Timespec) (n int, err error) {
+       r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_getn)), 5, uintptr(port), uintptr(unsafe.Pointer(pe)), uintptr(max), uintptr(unsafe.Pointer(nget)), uintptr(unsafe.Pointer(timeout)), 0)
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
index fbc59b7fdd25a2a88ccee4d1dd1305599bd81a93..aa7ce85d1550a2c9d1708b0e7d74f26d98da8f3b 100644 (file)
@@ -439,4 +439,9 @@ const (
        SYS_PROCESS_MADVISE              = 440
        SYS_EPOLL_PWAIT2                 = 441
        SYS_MOUNT_SETATTR                = 442
+       SYS_QUOTACTL_FD                  = 443
+       SYS_LANDLOCK_CREATE_RULESET      = 444
+       SYS_LANDLOCK_ADD_RULE            = 445
+       SYS_LANDLOCK_RESTRICT_SELF       = 446
+       SYS_MEMFD_SECRET                 = 447
 )
index 04d16d771ef78caf3cc2d2f1408a7d95e769f218..b830326386cd217702874690df2958f6cceeb574 100644 (file)
 package unix
 
 const (
-       SYS_READ                   = 0
-       SYS_WRITE                  = 1
-       SYS_OPEN                   = 2
-       SYS_CLOSE                  = 3
-       SYS_STAT                   = 4
-       SYS_FSTAT                  = 5
-       SYS_LSTAT                  = 6
-       SYS_POLL                   = 7
-       SYS_LSEEK                  = 8
-       SYS_MMAP                   = 9
-       SYS_MPROTECT               = 10
-       SYS_MUNMAP                 = 11
-       SYS_BRK                    = 12
-       SYS_RT_SIGACTION           = 13
-       SYS_RT_SIGPROCMASK         = 14
-       SYS_RT_SIGRETURN           = 15
-       SYS_IOCTL                  = 16
-       SYS_PREAD64                = 17
-       SYS_PWRITE64               = 18
-       SYS_READV                  = 19
-       SYS_WRITEV                 = 20
-       SYS_ACCESS                 = 21
-       SYS_PIPE                   = 22
-       SYS_SELECT                 = 23
-       SYS_SCHED_YIELD            = 24
-       SYS_MREMAP                 = 25
-       SYS_MSYNC                  = 26
-       SYS_MINCORE                = 27
-       SYS_MADVISE                = 28
-       SYS_SHMGET                 = 29
-       SYS_SHMAT                  = 30
-       SYS_SHMCTL                 = 31
-       SYS_DUP                    = 32
-       SYS_DUP2                   = 33
-       SYS_PAUSE                  = 34
-       SYS_NANOSLEEP              = 35
-       SYS_GETITIMER              = 36
-       SYS_ALARM                  = 37
-       SYS_SETITIMER              = 38
-       SYS_GETPID                 = 39
-       SYS_SENDFILE               = 40
-       SYS_SOCKET                 = 41
-       SYS_CONNECT                = 42
-       SYS_ACCEPT                 = 43
-       SYS_SENDTO                 = 44
-       SYS_RECVFROM               = 45
-       SYS_SENDMSG                = 46
-       SYS_RECVMSG                = 47
-       SYS_SHUTDOWN               = 48
-       SYS_BIND                   = 49
-       SYS_LISTEN                 = 50
-       SYS_GETSOCKNAME            = 51
-       SYS_GETPEERNAME            = 52
-       SYS_SOCKETPAIR             = 53
-       SYS_SETSOCKOPT             = 54
-       SYS_GETSOCKOPT             = 55
-       SYS_CLONE                  = 56
-       SYS_FORK                   = 57
-       SYS_VFORK                  = 58
-       SYS_EXECVE                 = 59
-       SYS_EXIT                   = 60
-       SYS_WAIT4                  = 61
-       SYS_KILL                   = 62
-       SYS_UNAME                  = 63
-       SYS_SEMGET                 = 64
-       SYS_SEMOP                  = 65
-       SYS_SEMCTL                 = 66
-       SYS_SHMDT                  = 67
-       SYS_MSGGET                 = 68
-       SYS_MSGSND                 = 69
-       SYS_MSGRCV                 = 70
-       SYS_MSGCTL                 = 71
-       SYS_FCNTL                  = 72
-       SYS_FLOCK                  = 73
-       SYS_FSYNC                  = 74
-       SYS_FDATASYNC              = 75
-       SYS_TRUNCATE               = 76
-       SYS_FTRUNCATE              = 77
-       SYS_GETDENTS               = 78
-       SYS_GETCWD                 = 79
-       SYS_CHDIR                  = 80
-       SYS_FCHDIR                 = 81
-       SYS_RENAME                 = 82
-       SYS_MKDIR                  = 83
-       SYS_RMDIR                  = 84
-       SYS_CREAT                  = 85
-       SYS_LINK                   = 86
-       SYS_UNLINK                 = 87
-       SYS_SYMLINK                = 88
-       SYS_READLINK               = 89
-       SYS_CHMOD                  = 90
-       SYS_FCHMOD                 = 91
-       SYS_CHOWN                  = 92
-       SYS_FCHOWN                 = 93
-       SYS_LCHOWN                 = 94
-       SYS_UMASK                  = 95
-       SYS_GETTIMEOFDAY           = 96
-       SYS_GETRLIMIT              = 97
-       SYS_GETRUSAGE              = 98
-       SYS_SYSINFO                = 99
-       SYS_TIMES                  = 100
-       SYS_PTRACE                 = 101
-       SYS_GETUID                 = 102
-       SYS_SYSLOG                 = 103
-       SYS_GETGID                 = 104
-       SYS_SETUID                 = 105
-       SYS_SETGID                 = 106
-       SYS_GETEUID                = 107
-       SYS_GETEGID                = 108
-       SYS_SETPGID                = 109
-       SYS_GETPPID                = 110
-       SYS_GETPGRP                = 111
-       SYS_SETSID                 = 112
-       SYS_SETREUID               = 113
-       SYS_SETREGID               = 114
-       SYS_GETGROUPS              = 115
-       SYS_SETGROUPS              = 116
-       SYS_SETRESUID              = 117
-       SYS_GETRESUID              = 118
-       SYS_SETRESGID              = 119
-       SYS_GETRESGID              = 120
-       SYS_GETPGID                = 121
-       SYS_SETFSUID               = 122
-       SYS_SETFSGID               = 123
-       SYS_GETSID                 = 124
-       SYS_CAPGET                 = 125
-       SYS_CAPSET                 = 126
-       SYS_RT_SIGPENDING          = 127
-       SYS_RT_SIGTIMEDWAIT        = 128
-       SYS_RT_SIGQUEUEINFO        = 129
-       SYS_RT_SIGSUSPEND          = 130
-       SYS_SIGALTSTACK            = 131
-       SYS_UTIME                  = 132
-       SYS_MKNOD                  = 133
-       SYS_USELIB                 = 134
-       SYS_PERSONALITY            = 135
-       SYS_USTAT                  = 136
-       SYS_STATFS                 = 137
-       SYS_FSTATFS                = 138
-       SYS_SYSFS                  = 139
-       SYS_GETPRIORITY            = 140
-       SYS_SETPRIORITY            = 141
-       SYS_SCHED_SETPARAM         = 142
-       SYS_SCHED_GETPARAM         = 143
-       SYS_SCHED_SETSCHEDULER     = 144
-       SYS_SCHED_GETSCHEDULER     = 145
-       SYS_SCHED_GET_PRIORITY_MAX = 146
-       SYS_SCHED_GET_PRIORITY_MIN = 147
-       SYS_SCHED_RR_GET_INTERVAL  = 148
-       SYS_MLOCK                  = 149
-       SYS_MUNLOCK                = 150
-       SYS_MLOCKALL               = 151
-       SYS_MUNLOCKALL             = 152
-       SYS_VHANGUP                = 153
-       SYS_MODIFY_LDT             = 154
-       SYS_PIVOT_ROOT             = 155
-       SYS__SYSCTL                = 156
-       SYS_PRCTL                  = 157
-       SYS_ARCH_PRCTL             = 158
-       SYS_ADJTIMEX               = 159
-       SYS_SETRLIMIT              = 160
-       SYS_CHROOT                 = 161
-       SYS_SYNC                   = 162
-       SYS_ACCT                   = 163
-       SYS_SETTIMEOFDAY           = 164
-       SYS_MOUNT                  = 165
-       SYS_UMOUNT2                = 166
-       SYS_SWAPON                 = 167
-       SYS_SWAPOFF                = 168
-       SYS_REBOOT                 = 169
-       SYS_SETHOSTNAME            = 170
-       SYS_SETDOMAINNAME          = 171
-       SYS_IOPL                   = 172
-       SYS_IOPERM                 = 173
-       SYS_CREATE_MODULE          = 174
-       SYS_INIT_MODULE            = 175
-       SYS_DELETE_MODULE          = 176
-       SYS_GET_KERNEL_SYMS        = 177
-       SYS_QUERY_MODULE           = 178
-       SYS_QUOTACTL               = 179
-       SYS_NFSSERVCTL             = 180
-       SYS_GETPMSG                = 181
-       SYS_PUTPMSG                = 182
-       SYS_AFS_SYSCALL            = 183
-       SYS_TUXCALL                = 184
-       SYS_SECURITY               = 185
-       SYS_GETTID                 = 186
-       SYS_READAHEAD              = 187
-       SYS_SETXATTR               = 188
-       SYS_LSETXATTR              = 189
-       SYS_FSETXATTR              = 190
-       SYS_GETXATTR               = 191
-       SYS_LGETXATTR              = 192
-       SYS_FGETXATTR              = 193
-       SYS_LISTXATTR              = 194
-       SYS_LLISTXATTR             = 195
-       SYS_FLISTXATTR             = 196
-       SYS_REMOVEXATTR            = 197
-       SYS_LREMOVEXATTR           = 198
-       SYS_FREMOVEXATTR           = 199
-       SYS_TKILL                  = 200
-       SYS_TIME                   = 201
-       SYS_FUTEX                  = 202
-       SYS_SCHED_SETAFFINITY      = 203
-       SYS_SCHED_GETAFFINITY      = 204
-       SYS_SET_THREAD_AREA        = 205
-       SYS_IO_SETUP               = 206
-       SYS_IO_DESTROY             = 207
-       SYS_IO_GETEVENTS           = 208
-       SYS_IO_SUBMIT              = 209
-       SYS_IO_CANCEL              = 210
-       SYS_GET_THREAD_AREA        = 211
-       SYS_LOOKUP_DCOOKIE         = 212
-       SYS_EPOLL_CREATE           = 213
-       SYS_EPOLL_CTL_OLD          = 214
-       SYS_EPOLL_WAIT_OLD         = 215
-       SYS_REMAP_FILE_PAGES       = 216
-       SYS_GETDENTS64             = 217
-       SYS_SET_TID_ADDRESS        = 218
-       SYS_RESTART_SYSCALL        = 219
-       SYS_SEMTIMEDOP             = 220
-       SYS_FADVISE64              = 221
-       SYS_TIMER_CREATE           = 222
-       SYS_TIMER_SETTIME          = 223
-       SYS_TIMER_GETTIME          = 224
-       SYS_TIMER_GETOVERRUN       = 225
-       SYS_TIMER_DELETE           = 226
-       SYS_CLOCK_SETTIME          = 227
-       SYS_CLOCK_GETTIME          = 228
-       SYS_CLOCK_GETRES           = 229
-       SYS_CLOCK_NANOSLEEP        = 230
-       SYS_EXIT_GROUP             = 231
-       SYS_EPOLL_WAIT             = 232
-       SYS_EPOLL_CTL              = 233
-       SYS_TGKILL                 = 234
-       SYS_UTIMES                 = 235
-       SYS_VSERVER                = 236
-       SYS_MBIND                  = 237
-       SYS_SET_MEMPOLICY          = 238
-       SYS_GET_MEMPOLICY          = 239
-       SYS_MQ_OPEN                = 240
-       SYS_MQ_UNLINK              = 241
-       SYS_MQ_TIMEDSEND           = 242
-       SYS_MQ_TIMEDRECEIVE        = 243
-       SYS_MQ_NOTIFY              = 244
-       SYS_MQ_GETSETATTR          = 245
-       SYS_KEXEC_LOAD             = 246
-       SYS_WAITID                 = 247
-       SYS_ADD_KEY                = 248
-       SYS_REQUEST_KEY            = 249
-       SYS_KEYCTL                 = 250
-       SYS_IOPRIO_SET             = 251
-       SYS_IOPRIO_GET             = 252
-       SYS_INOTIFY_INIT           = 253
-       SYS_INOTIFY_ADD_WATCH      = 254
-       SYS_INOTIFY_RM_WATCH       = 255
-       SYS_MIGRATE_PAGES          = 256
-       SYS_OPENAT                 = 257
-       SYS_MKDIRAT                = 258
-       SYS_MKNODAT                = 259
-       SYS_FCHOWNAT               = 260
-       SYS_FUTIMESAT              = 261
-       SYS_NEWFSTATAT             = 262
-       SYS_UNLINKAT               = 263
-       SYS_RENAMEAT               = 264
-       SYS_LINKAT                 = 265
-       SYS_SYMLINKAT              = 266
-       SYS_READLINKAT             = 267
-       SYS_FCHMODAT               = 268
-       SYS_FACCESSAT              = 269
-       SYS_PSELECT6               = 270
-       SYS_PPOLL                  = 271
-       SYS_UNSHARE                = 272
-       SYS_SET_ROBUST_LIST        = 273
-       SYS_GET_ROBUST_LIST        = 274
-       SYS_SPLICE                 = 275
-       SYS_TEE                    = 276
-       SYS_SYNC_FILE_RANGE        = 277
-       SYS_VMSPLICE               = 278
-       SYS_MOVE_PAGES             = 279
-       SYS_UTIMENSAT              = 280
-       SYS_EPOLL_PWAIT            = 281
-       SYS_SIGNALFD               = 282
-       SYS_TIMERFD_CREATE         = 283
-       SYS_EVENTFD                = 284
-       SYS_FALLOCATE              = 285
-       SYS_TIMERFD_SETTIME        = 286
-       SYS_TIMERFD_GETTIME        = 287
-       SYS_ACCEPT4                = 288
-       SYS_SIGNALFD4              = 289
-       SYS_EVENTFD2               = 290
-       SYS_EPOLL_CREATE1          = 291
-       SYS_DUP3                   = 292
-       SYS_PIPE2                  = 293
-       SYS_INOTIFY_INIT1          = 294
-       SYS_PREADV                 = 295
-       SYS_PWRITEV                = 296
-       SYS_RT_TGSIGQUEUEINFO      = 297
-       SYS_PERF_EVENT_OPEN        = 298
-       SYS_RECVMMSG               = 299
-       SYS_FANOTIFY_INIT          = 300
-       SYS_FANOTIFY_MARK          = 301
-       SYS_PRLIMIT64              = 302
-       SYS_NAME_TO_HANDLE_AT      = 303
-       SYS_OPEN_BY_HANDLE_AT      = 304
-       SYS_CLOCK_ADJTIME          = 305
-       SYS_SYNCFS                 = 306
-       SYS_SENDMMSG               = 307
-       SYS_SETNS                  = 308
-       SYS_GETCPU                 = 309
-       SYS_PROCESS_VM_READV       = 310
-       SYS_PROCESS_VM_WRITEV      = 311
-       SYS_KCMP                   = 312
-       SYS_FINIT_MODULE           = 313
-       SYS_SCHED_SETATTR          = 314
-       SYS_SCHED_GETATTR          = 315
-       SYS_RENAMEAT2              = 316
-       SYS_SECCOMP                = 317
-       SYS_GETRANDOM              = 318
-       SYS_MEMFD_CREATE           = 319
-       SYS_KEXEC_FILE_LOAD        = 320
-       SYS_BPF                    = 321
-       SYS_EXECVEAT               = 322
-       SYS_USERFAULTFD            = 323
-       SYS_MEMBARRIER             = 324
-       SYS_MLOCK2                 = 325
-       SYS_COPY_FILE_RANGE        = 326
-       SYS_PREADV2                = 327
-       SYS_PWRITEV2               = 328
-       SYS_PKEY_MPROTECT          = 329
-       SYS_PKEY_ALLOC             = 330
-       SYS_PKEY_FREE              = 331
-       SYS_STATX                  = 332
-       SYS_IO_PGETEVENTS          = 333
-       SYS_RSEQ                   = 334
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLONE3                 = 435
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_READ                    = 0
+       SYS_WRITE                   = 1
+       SYS_OPEN                    = 2
+       SYS_CLOSE                   = 3
+       SYS_STAT                    = 4
+       SYS_FSTAT                   = 5
+       SYS_LSTAT                   = 6
+       SYS_POLL                    = 7
+       SYS_LSEEK                   = 8
+       SYS_MMAP                    = 9
+       SYS_MPROTECT                = 10
+       SYS_MUNMAP                  = 11
+       SYS_BRK                     = 12
+       SYS_RT_SIGACTION            = 13
+       SYS_RT_SIGPROCMASK          = 14
+       SYS_RT_SIGRETURN            = 15
+       SYS_IOCTL                   = 16
+       SYS_PREAD64                 = 17
+       SYS_PWRITE64                = 18
+       SYS_READV                   = 19
+       SYS_WRITEV                  = 20
+       SYS_ACCESS                  = 21
+       SYS_PIPE                    = 22
+       SYS_SELECT                  = 23
+       SYS_SCHED_YIELD             = 24
+       SYS_MREMAP                  = 25
+       SYS_MSYNC                   = 26
+       SYS_MINCORE                 = 27
+       SYS_MADVISE                 = 28
+       SYS_SHMGET                  = 29
+       SYS_SHMAT                   = 30
+       SYS_SHMCTL                  = 31
+       SYS_DUP                     = 32
+       SYS_DUP2                    = 33
+       SYS_PAUSE                   = 34
+       SYS_NANOSLEEP               = 35
+       SYS_GETITIMER               = 36
+       SYS_ALARM                   = 37
+       SYS_SETITIMER               = 38
+       SYS_GETPID                  = 39
+       SYS_SENDFILE                = 40
+       SYS_SOCKET                  = 41
+       SYS_CONNECT                 = 42
+       SYS_ACCEPT                  = 43
+       SYS_SENDTO                  = 44
+       SYS_RECVFROM                = 45
+       SYS_SENDMSG                 = 46
+       SYS_RECVMSG                 = 47
+       SYS_SHUTDOWN                = 48
+       SYS_BIND                    = 49
+       SYS_LISTEN                  = 50
+       SYS_GETSOCKNAME             = 51
+       SYS_GETPEERNAME             = 52
+       SYS_SOCKETPAIR              = 53
+       SYS_SETSOCKOPT              = 54
+       SYS_GETSOCKOPT              = 55
+       SYS_CLONE                   = 56
+       SYS_FORK                    = 57
+       SYS_VFORK                   = 58
+       SYS_EXECVE                  = 59
+       SYS_EXIT                    = 60
+       SYS_WAIT4                   = 61
+       SYS_KILL                    = 62
+       SYS_UNAME                   = 63
+       SYS_SEMGET                  = 64
+       SYS_SEMOP                   = 65
+       SYS_SEMCTL                  = 66
+       SYS_SHMDT                   = 67
+       SYS_MSGGET                  = 68
+       SYS_MSGSND                  = 69
+       SYS_MSGRCV                  = 70
+       SYS_MSGCTL                  = 71
+       SYS_FCNTL                   = 72
+       SYS_FLOCK                   = 73
+       SYS_FSYNC                   = 74
+       SYS_FDATASYNC               = 75
+       SYS_TRUNCATE                = 76
+       SYS_FTRUNCATE               = 77
+       SYS_GETDENTS                = 78
+       SYS_GETCWD                  = 79
+       SYS_CHDIR                   = 80
+       SYS_FCHDIR                  = 81
+       SYS_RENAME                  = 82
+       SYS_MKDIR                   = 83
+       SYS_RMDIR                   = 84
+       SYS_CREAT                   = 85
+       SYS_LINK                    = 86
+       SYS_UNLINK                  = 87
+       SYS_SYMLINK                 = 88
+       SYS_READLINK                = 89
+       SYS_CHMOD                   = 90
+       SYS_FCHMOD                  = 91
+       SYS_CHOWN                   = 92
+       SYS_FCHOWN                  = 93
+       SYS_LCHOWN                  = 94
+       SYS_UMASK                   = 95
+       SYS_GETTIMEOFDAY            = 96
+       SYS_GETRLIMIT               = 97
+       SYS_GETRUSAGE               = 98
+       SYS_SYSINFO                 = 99
+       SYS_TIMES                   = 100
+       SYS_PTRACE                  = 101
+       SYS_GETUID                  = 102
+       SYS_SYSLOG                  = 103
+       SYS_GETGID                  = 104
+       SYS_SETUID                  = 105
+       SYS_SETGID                  = 106
+       SYS_GETEUID                 = 107
+       SYS_GETEGID                 = 108
+       SYS_SETPGID                 = 109
+       SYS_GETPPID                 = 110
+       SYS_GETPGRP                 = 111
+       SYS_SETSID                  = 112
+       SYS_SETREUID                = 113
+       SYS_SETREGID                = 114
+       SYS_GETGROUPS               = 115
+       SYS_SETGROUPS               = 116
+       SYS_SETRESUID               = 117
+       SYS_GETRESUID               = 118
+       SYS_SETRESGID               = 119
+       SYS_GETRESGID               = 120
+       SYS_GETPGID                 = 121
+       SYS_SETFSUID                = 122
+       SYS_SETFSGID                = 123
+       SYS_GETSID                  = 124
+       SYS_CAPGET                  = 125
+       SYS_CAPSET                  = 126
+       SYS_RT_SIGPENDING           = 127
+       SYS_RT_SIGTIMEDWAIT         = 128
+       SYS_RT_SIGQUEUEINFO         = 129
+       SYS_RT_SIGSUSPEND           = 130
+       SYS_SIGALTSTACK             = 131
+       SYS_UTIME                   = 132
+       SYS_MKNOD                   = 133
+       SYS_USELIB                  = 134
+       SYS_PERSONALITY             = 135
+       SYS_USTAT                   = 136
+       SYS_STATFS                  = 137
+       SYS_FSTATFS                 = 138
+       SYS_SYSFS                   = 139
+       SYS_GETPRIORITY             = 140
+       SYS_SETPRIORITY             = 141
+       SYS_SCHED_SETPARAM          = 142
+       SYS_SCHED_GETPARAM          = 143
+       SYS_SCHED_SETSCHEDULER      = 144
+       SYS_SCHED_GETSCHEDULER      = 145
+       SYS_SCHED_GET_PRIORITY_MAX  = 146
+       SYS_SCHED_GET_PRIORITY_MIN  = 147
+       SYS_SCHED_RR_GET_INTERVAL   = 148
+       SYS_MLOCK                   = 149
+       SYS_MUNLOCK                 = 150
+       SYS_MLOCKALL                = 151
+       SYS_MUNLOCKALL              = 152
+       SYS_VHANGUP                 = 153
+       SYS_MODIFY_LDT              = 154
+       SYS_PIVOT_ROOT              = 155
+       SYS__SYSCTL                 = 156
+       SYS_PRCTL                   = 157
+       SYS_ARCH_PRCTL              = 158
+       SYS_ADJTIMEX                = 159
+       SYS_SETRLIMIT               = 160
+       SYS_CHROOT                  = 161
+       SYS_SYNC                    = 162
+       SYS_ACCT                    = 163
+       SYS_SETTIMEOFDAY            = 164
+       SYS_MOUNT                   = 165
+       SYS_UMOUNT2                 = 166
+       SYS_SWAPON                  = 167
+       SYS_SWAPOFF                 = 168
+       SYS_REBOOT                  = 169
+       SYS_SETHOSTNAME             = 170
+       SYS_SETDOMAINNAME           = 171
+       SYS_IOPL                    = 172
+       SYS_IOPERM                  = 173
+       SYS_CREATE_MODULE           = 174
+       SYS_INIT_MODULE             = 175
+       SYS_DELETE_MODULE           = 176
+       SYS_GET_KERNEL_SYMS         = 177
+       SYS_QUERY_MODULE            = 178
+       SYS_QUOTACTL                = 179
+       SYS_NFSSERVCTL              = 180
+       SYS_GETPMSG                 = 181
+       SYS_PUTPMSG                 = 182
+       SYS_AFS_SYSCALL             = 183
+       SYS_TUXCALL                 = 184
+       SYS_SECURITY                = 185
+       SYS_GETTID                  = 186
+       SYS_READAHEAD               = 187
+       SYS_SETXATTR                = 188
+       SYS_LSETXATTR               = 189
+       SYS_FSETXATTR               = 190
+       SYS_GETXATTR                = 191
+       SYS_LGETXATTR               = 192
+       SYS_FGETXATTR               = 193
+       SYS_LISTXATTR               = 194
+       SYS_LLISTXATTR              = 195
+       SYS_FLISTXATTR              = 196
+       SYS_REMOVEXATTR             = 197
+       SYS_LREMOVEXATTR            = 198
+       SYS_FREMOVEXATTR            = 199
+       SYS_TKILL                   = 200
+       SYS_TIME                    = 201
+       SYS_FUTEX                   = 202
+       SYS_SCHED_SETAFFINITY       = 203
+       SYS_SCHED_GETAFFINITY       = 204
+       SYS_SET_THREAD_AREA         = 205
+       SYS_IO_SETUP                = 206
+       SYS_IO_DESTROY              = 207
+       SYS_IO_GETEVENTS            = 208
+       SYS_IO_SUBMIT               = 209
+       SYS_IO_CANCEL               = 210
+       SYS_GET_THREAD_AREA         = 211
+       SYS_LOOKUP_DCOOKIE          = 212
+       SYS_EPOLL_CREATE            = 213
+       SYS_EPOLL_CTL_OLD           = 214
+       SYS_EPOLL_WAIT_OLD          = 215
+       SYS_REMAP_FILE_PAGES        = 216
+       SYS_GETDENTS64              = 217
+       SYS_SET_TID_ADDRESS         = 218
+       SYS_RESTART_SYSCALL         = 219
+       SYS_SEMTIMEDOP              = 220
+       SYS_FADVISE64               = 221
+       SYS_TIMER_CREATE            = 222
+       SYS_TIMER_SETTIME           = 223
+       SYS_TIMER_GETTIME           = 224
+       SYS_TIMER_GETOVERRUN        = 225
+       SYS_TIMER_DELETE            = 226
+       SYS_CLOCK_SETTIME           = 227
+       SYS_CLOCK_GETTIME           = 228
+       SYS_CLOCK_GETRES            = 229
+       SYS_CLOCK_NANOSLEEP         = 230
+       SYS_EXIT_GROUP              = 231
+       SYS_EPOLL_WAIT              = 232
+       SYS_EPOLL_CTL               = 233
+       SYS_TGKILL                  = 234
+       SYS_UTIMES                  = 235
+       SYS_VSERVER                 = 236
+       SYS_MBIND                   = 237
+       SYS_SET_MEMPOLICY           = 238
+       SYS_GET_MEMPOLICY           = 239
+       SYS_MQ_OPEN                 = 240
+       SYS_MQ_UNLINK               = 241
+       SYS_MQ_TIMEDSEND            = 242
+       SYS_MQ_TIMEDRECEIVE         = 243
+       SYS_MQ_NOTIFY               = 244
+       SYS_MQ_GETSETATTR           = 245
+       SYS_KEXEC_LOAD              = 246
+       SYS_WAITID                  = 247
+       SYS_ADD_KEY                 = 248
+       SYS_REQUEST_KEY             = 249
+       SYS_KEYCTL                  = 250
+       SYS_IOPRIO_SET              = 251
+       SYS_IOPRIO_GET              = 252
+       SYS_INOTIFY_INIT            = 253
+       SYS_INOTIFY_ADD_WATCH       = 254
+       SYS_INOTIFY_RM_WATCH        = 255
+       SYS_MIGRATE_PAGES           = 256
+       SYS_OPENAT                  = 257
+       SYS_MKDIRAT                 = 258
+       SYS_MKNODAT                 = 259
+       SYS_FCHOWNAT                = 260
+       SYS_FUTIMESAT               = 261
+       SYS_NEWFSTATAT              = 262
+       SYS_UNLINKAT                = 263
+       SYS_RENAMEAT                = 264
+       SYS_LINKAT                  = 265
+       SYS_SYMLINKAT               = 266
+       SYS_READLINKAT              = 267
+       SYS_FCHMODAT                = 268
+       SYS_FACCESSAT               = 269
+       SYS_PSELECT6                = 270
+       SYS_PPOLL                   = 271
+       SYS_UNSHARE                 = 272
+       SYS_SET_ROBUST_LIST         = 273
+       SYS_GET_ROBUST_LIST         = 274
+       SYS_SPLICE                  = 275
+       SYS_TEE                     = 276
+       SYS_SYNC_FILE_RANGE         = 277
+       SYS_VMSPLICE                = 278
+       SYS_MOVE_PAGES              = 279
+       SYS_UTIMENSAT               = 280
+       SYS_EPOLL_PWAIT             = 281
+       SYS_SIGNALFD                = 282
+       SYS_TIMERFD_CREATE          = 283
+       SYS_EVENTFD                 = 284
+       SYS_FALLOCATE               = 285
+       SYS_TIMERFD_SETTIME         = 286
+       SYS_TIMERFD_GETTIME         = 287
+       SYS_ACCEPT4                 = 288
+       SYS_SIGNALFD4               = 289
+       SYS_EVENTFD2                = 290
+       SYS_EPOLL_CREATE1           = 291
+       SYS_DUP3                    = 292
+       SYS_PIPE2                   = 293
+       SYS_INOTIFY_INIT1           = 294
+       SYS_PREADV                  = 295
+       SYS_PWRITEV                 = 296
+       SYS_RT_TGSIGQUEUEINFO       = 297
+       SYS_PERF_EVENT_OPEN         = 298
+       SYS_RECVMMSG                = 299
+       SYS_FANOTIFY_INIT           = 300
+       SYS_FANOTIFY_MARK           = 301
+       SYS_PRLIMIT64               = 302
+       SYS_NAME_TO_HANDLE_AT       = 303
+       SYS_OPEN_BY_HANDLE_AT       = 304
+       SYS_CLOCK_ADJTIME           = 305
+       SYS_SYNCFS                  = 306
+       SYS_SENDMMSG                = 307
+       SYS_SETNS                   = 308
+       SYS_GETCPU                  = 309
+       SYS_PROCESS_VM_READV        = 310
+       SYS_PROCESS_VM_WRITEV       = 311
+       SYS_KCMP                    = 312
+       SYS_FINIT_MODULE            = 313
+       SYS_SCHED_SETATTR           = 314
+       SYS_SCHED_GETATTR           = 315
+       SYS_RENAMEAT2               = 316
+       SYS_SECCOMP                 = 317
+       SYS_GETRANDOM               = 318
+       SYS_MEMFD_CREATE            = 319
+       SYS_KEXEC_FILE_LOAD         = 320
+       SYS_BPF                     = 321
+       SYS_EXECVEAT                = 322
+       SYS_USERFAULTFD             = 323
+       SYS_MEMBARRIER              = 324
+       SYS_MLOCK2                  = 325
+       SYS_COPY_FILE_RANGE         = 326
+       SYS_PREADV2                 = 327
+       SYS_PWRITEV2                = 328
+       SYS_PKEY_MPROTECT           = 329
+       SYS_PKEY_ALLOC              = 330
+       SYS_PKEY_FREE               = 331
+       SYS_STATX                   = 332
+       SYS_IO_PGETEVENTS           = 333
+       SYS_RSEQ                    = 334
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLONE3                  = 435
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
+       SYS_MEMFD_SECRET            = 447
 )
index 3b1c105137368fa3f450433d1abf6d198a12aab6..d75f65a0aa701caa36fc267da4e8f4d8cfa70951 100644 (file)
@@ -403,4 +403,8 @@ const (
        SYS_PROCESS_MADVISE              = 440
        SYS_EPOLL_PWAIT2                 = 441
        SYS_MOUNT_SETATTR                = 442
+       SYS_QUOTACTL_FD                  = 443
+       SYS_LANDLOCK_CREATE_RULESET      = 444
+       SYS_LANDLOCK_ADD_RULE            = 445
+       SYS_LANDLOCK_RESTRICT_SELF       = 446
 )
index 3198adcf77a12293da9d3f7c36953e9b89f42df1..8b02f09e9b5cd240a2dfeb5887cf4ee90caab954 100644 (file)
 package unix
 
 const (
-       SYS_IO_SETUP               = 0
-       SYS_IO_DESTROY             = 1
-       SYS_IO_SUBMIT              = 2
-       SYS_IO_CANCEL              = 3
-       SYS_IO_GETEVENTS           = 4
-       SYS_SETXATTR               = 5
-       SYS_LSETXATTR              = 6
-       SYS_FSETXATTR              = 7
-       SYS_GETXATTR               = 8
-       SYS_LGETXATTR              = 9
-       SYS_FGETXATTR              = 10
-       SYS_LISTXATTR              = 11
-       SYS_LLISTXATTR             = 12
-       SYS_FLISTXATTR             = 13
-       SYS_REMOVEXATTR            = 14
-       SYS_LREMOVEXATTR           = 15
-       SYS_FREMOVEXATTR           = 16
-       SYS_GETCWD                 = 17
-       SYS_LOOKUP_DCOOKIE         = 18
-       SYS_EVENTFD2               = 19
-       SYS_EPOLL_CREATE1          = 20
-       SYS_EPOLL_CTL              = 21
-       SYS_EPOLL_PWAIT            = 22
-       SYS_DUP                    = 23
-       SYS_DUP3                   = 24
-       SYS_FCNTL                  = 25
-       SYS_INOTIFY_INIT1          = 26
-       SYS_INOTIFY_ADD_WATCH      = 27
-       SYS_INOTIFY_RM_WATCH       = 28
-       SYS_IOCTL                  = 29
-       SYS_IOPRIO_SET             = 30
-       SYS_IOPRIO_GET             = 31
-       SYS_FLOCK                  = 32
-       SYS_MKNODAT                = 33
-       SYS_MKDIRAT                = 34
-       SYS_UNLINKAT               = 35
-       SYS_SYMLINKAT              = 36
-       SYS_LINKAT                 = 37
-       SYS_RENAMEAT               = 38
-       SYS_UMOUNT2                = 39
-       SYS_MOUNT                  = 40
-       SYS_PIVOT_ROOT             = 41
-       SYS_NFSSERVCTL             = 42
-       SYS_STATFS                 = 43
-       SYS_FSTATFS                = 44
-       SYS_TRUNCATE               = 45
-       SYS_FTRUNCATE              = 46
-       SYS_FALLOCATE              = 47
-       SYS_FACCESSAT              = 48
-       SYS_CHDIR                  = 49
-       SYS_FCHDIR                 = 50
-       SYS_CHROOT                 = 51
-       SYS_FCHMOD                 = 52
-       SYS_FCHMODAT               = 53
-       SYS_FCHOWNAT               = 54
-       SYS_FCHOWN                 = 55
-       SYS_OPENAT                 = 56
-       SYS_CLOSE                  = 57
-       SYS_VHANGUP                = 58
-       SYS_PIPE2                  = 59
-       SYS_QUOTACTL               = 60
-       SYS_GETDENTS64             = 61
-       SYS_LSEEK                  = 62
-       SYS_READ                   = 63
-       SYS_WRITE                  = 64
-       SYS_READV                  = 65
-       SYS_WRITEV                 = 66
-       SYS_PREAD64                = 67
-       SYS_PWRITE64               = 68
-       SYS_PREADV                 = 69
-       SYS_PWRITEV                = 70
-       SYS_SENDFILE               = 71
-       SYS_PSELECT6               = 72
-       SYS_PPOLL                  = 73
-       SYS_SIGNALFD4              = 74
-       SYS_VMSPLICE               = 75
-       SYS_SPLICE                 = 76
-       SYS_TEE                    = 77
-       SYS_READLINKAT             = 78
-       SYS_FSTATAT                = 79
-       SYS_FSTAT                  = 80
-       SYS_SYNC                   = 81
-       SYS_FSYNC                  = 82
-       SYS_FDATASYNC              = 83
-       SYS_SYNC_FILE_RANGE        = 84
-       SYS_TIMERFD_CREATE         = 85
-       SYS_TIMERFD_SETTIME        = 86
-       SYS_TIMERFD_GETTIME        = 87
-       SYS_UTIMENSAT              = 88
-       SYS_ACCT                   = 89
-       SYS_CAPGET                 = 90
-       SYS_CAPSET                 = 91
-       SYS_PERSONALITY            = 92
-       SYS_EXIT                   = 93
-       SYS_EXIT_GROUP             = 94
-       SYS_WAITID                 = 95
-       SYS_SET_TID_ADDRESS        = 96
-       SYS_UNSHARE                = 97
-       SYS_FUTEX                  = 98
-       SYS_SET_ROBUST_LIST        = 99
-       SYS_GET_ROBUST_LIST        = 100
-       SYS_NANOSLEEP              = 101
-       SYS_GETITIMER              = 102
-       SYS_SETITIMER              = 103
-       SYS_KEXEC_LOAD             = 104
-       SYS_INIT_MODULE            = 105
-       SYS_DELETE_MODULE          = 106
-       SYS_TIMER_CREATE           = 107
-       SYS_TIMER_GETTIME          = 108
-       SYS_TIMER_GETOVERRUN       = 109
-       SYS_TIMER_SETTIME          = 110
-       SYS_TIMER_DELETE           = 111
-       SYS_CLOCK_SETTIME          = 112
-       SYS_CLOCK_GETTIME          = 113
-       SYS_CLOCK_GETRES           = 114
-       SYS_CLOCK_NANOSLEEP        = 115
-       SYS_SYSLOG                 = 116
-       SYS_PTRACE                 = 117
-       SYS_SCHED_SETPARAM         = 118
-       SYS_SCHED_SETSCHEDULER     = 119
-       SYS_SCHED_GETSCHEDULER     = 120
-       SYS_SCHED_GETPARAM         = 121
-       SYS_SCHED_SETAFFINITY      = 122
-       SYS_SCHED_GETAFFINITY      = 123
-       SYS_SCHED_YIELD            = 124
-       SYS_SCHED_GET_PRIORITY_MAX = 125
-       SYS_SCHED_GET_PRIORITY_MIN = 126
-       SYS_SCHED_RR_GET_INTERVAL  = 127
-       SYS_RESTART_SYSCALL        = 128
-       SYS_KILL                   = 129
-       SYS_TKILL                  = 130
-       SYS_TGKILL                 = 131
-       SYS_SIGALTSTACK            = 132
-       SYS_RT_SIGSUSPEND          = 133
-       SYS_RT_SIGACTION           = 134
-       SYS_RT_SIGPROCMASK         = 135
-       SYS_RT_SIGPENDING          = 136
-       SYS_RT_SIGTIMEDWAIT        = 137
-       SYS_RT_SIGQUEUEINFO        = 138
-       SYS_RT_SIGRETURN           = 139
-       SYS_SETPRIORITY            = 140
-       SYS_GETPRIORITY            = 141
-       SYS_REBOOT                 = 142
-       SYS_SETREGID               = 143
-       SYS_SETGID                 = 144
-       SYS_SETREUID               = 145
-       SYS_SETUID                 = 146
-       SYS_SETRESUID              = 147
-       SYS_GETRESUID              = 148
-       SYS_SETRESGID              = 149
-       SYS_GETRESGID              = 150
-       SYS_SETFSUID               = 151
-       SYS_SETFSGID               = 152
-       SYS_TIMES                  = 153
-       SYS_SETPGID                = 154
-       SYS_GETPGID                = 155
-       SYS_GETSID                 = 156
-       SYS_SETSID                 = 157
-       SYS_GETGROUPS              = 158
-       SYS_SETGROUPS              = 159
-       SYS_UNAME                  = 160
-       SYS_SETHOSTNAME            = 161
-       SYS_SETDOMAINNAME          = 162
-       SYS_GETRLIMIT              = 163
-       SYS_SETRLIMIT              = 164
-       SYS_GETRUSAGE              = 165
-       SYS_UMASK                  = 166
-       SYS_PRCTL                  = 167
-       SYS_GETCPU                 = 168
-       SYS_GETTIMEOFDAY           = 169
-       SYS_SETTIMEOFDAY           = 170
-       SYS_ADJTIMEX               = 171
-       SYS_GETPID                 = 172
-       SYS_GETPPID                = 173
-       SYS_GETUID                 = 174
-       SYS_GETEUID                = 175
-       SYS_GETGID                 = 176
-       SYS_GETEGID                = 177
-       SYS_GETTID                 = 178
-       SYS_SYSINFO                = 179
-       SYS_MQ_OPEN                = 180
-       SYS_MQ_UNLINK              = 181
-       SYS_MQ_TIMEDSEND           = 182
-       SYS_MQ_TIMEDRECEIVE        = 183
-       SYS_MQ_NOTIFY              = 184
-       SYS_MQ_GETSETATTR          = 185
-       SYS_MSGGET                 = 186
-       SYS_MSGCTL                 = 187
-       SYS_MSGRCV                 = 188
-       SYS_MSGSND                 = 189
-       SYS_SEMGET                 = 190
-       SYS_SEMCTL                 = 191
-       SYS_SEMTIMEDOP             = 192
-       SYS_SEMOP                  = 193
-       SYS_SHMGET                 = 194
-       SYS_SHMCTL                 = 195
-       SYS_SHMAT                  = 196
-       SYS_SHMDT                  = 197
-       SYS_SOCKET                 = 198
-       SYS_SOCKETPAIR             = 199
-       SYS_BIND                   = 200
-       SYS_LISTEN                 = 201
-       SYS_ACCEPT                 = 202
-       SYS_CONNECT                = 203
-       SYS_GETSOCKNAME            = 204
-       SYS_GETPEERNAME            = 205
-       SYS_SENDTO                 = 206
-       SYS_RECVFROM               = 207
-       SYS_SETSOCKOPT             = 208
-       SYS_GETSOCKOPT             = 209
-       SYS_SHUTDOWN               = 210
-       SYS_SENDMSG                = 211
-       SYS_RECVMSG                = 212
-       SYS_READAHEAD              = 213
-       SYS_BRK                    = 214
-       SYS_MUNMAP                 = 215
-       SYS_MREMAP                 = 216
-       SYS_ADD_KEY                = 217
-       SYS_REQUEST_KEY            = 218
-       SYS_KEYCTL                 = 219
-       SYS_CLONE                  = 220
-       SYS_EXECVE                 = 221
-       SYS_MMAP                   = 222
-       SYS_FADVISE64              = 223
-       SYS_SWAPON                 = 224
-       SYS_SWAPOFF                = 225
-       SYS_MPROTECT               = 226
-       SYS_MSYNC                  = 227
-       SYS_MLOCK                  = 228
-       SYS_MUNLOCK                = 229
-       SYS_MLOCKALL               = 230
-       SYS_MUNLOCKALL             = 231
-       SYS_MINCORE                = 232
-       SYS_MADVISE                = 233
-       SYS_REMAP_FILE_PAGES       = 234
-       SYS_MBIND                  = 235
-       SYS_GET_MEMPOLICY          = 236
-       SYS_SET_MEMPOLICY          = 237
-       SYS_MIGRATE_PAGES          = 238
-       SYS_MOVE_PAGES             = 239
-       SYS_RT_TGSIGQUEUEINFO      = 240
-       SYS_PERF_EVENT_OPEN        = 241
-       SYS_ACCEPT4                = 242
-       SYS_RECVMMSG               = 243
-       SYS_ARCH_SPECIFIC_SYSCALL  = 244
-       SYS_WAIT4                  = 260
-       SYS_PRLIMIT64              = 261
-       SYS_FANOTIFY_INIT          = 262
-       SYS_FANOTIFY_MARK          = 263
-       SYS_NAME_TO_HANDLE_AT      = 264
-       SYS_OPEN_BY_HANDLE_AT      = 265
-       SYS_CLOCK_ADJTIME          = 266
-       SYS_SYNCFS                 = 267
-       SYS_SETNS                  = 268
-       SYS_SENDMMSG               = 269
-       SYS_PROCESS_VM_READV       = 270
-       SYS_PROCESS_VM_WRITEV      = 271
-       SYS_KCMP                   = 272
-       SYS_FINIT_MODULE           = 273
-       SYS_SCHED_SETATTR          = 274
-       SYS_SCHED_GETATTR          = 275
-       SYS_RENAMEAT2              = 276
-       SYS_SECCOMP                = 277
-       SYS_GETRANDOM              = 278
-       SYS_MEMFD_CREATE           = 279
-       SYS_BPF                    = 280
-       SYS_EXECVEAT               = 281
-       SYS_USERFAULTFD            = 282
-       SYS_MEMBARRIER             = 283
-       SYS_MLOCK2                 = 284
-       SYS_COPY_FILE_RANGE        = 285
-       SYS_PREADV2                = 286
-       SYS_PWRITEV2               = 287
-       SYS_PKEY_MPROTECT          = 288
-       SYS_PKEY_ALLOC             = 289
-       SYS_PKEY_FREE              = 290
-       SYS_STATX                  = 291
-       SYS_IO_PGETEVENTS          = 292
-       SYS_RSEQ                   = 293
-       SYS_KEXEC_FILE_LOAD        = 294
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLONE3                 = 435
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_IO_SETUP                = 0
+       SYS_IO_DESTROY              = 1
+       SYS_IO_SUBMIT               = 2
+       SYS_IO_CANCEL               = 3
+       SYS_IO_GETEVENTS            = 4
+       SYS_SETXATTR                = 5
+       SYS_LSETXATTR               = 6
+       SYS_FSETXATTR               = 7
+       SYS_GETXATTR                = 8
+       SYS_LGETXATTR               = 9
+       SYS_FGETXATTR               = 10
+       SYS_LISTXATTR               = 11
+       SYS_LLISTXATTR              = 12
+       SYS_FLISTXATTR              = 13
+       SYS_REMOVEXATTR             = 14
+       SYS_LREMOVEXATTR            = 15
+       SYS_FREMOVEXATTR            = 16
+       SYS_GETCWD                  = 17
+       SYS_LOOKUP_DCOOKIE          = 18
+       SYS_EVENTFD2                = 19
+       SYS_EPOLL_CREATE1           = 20
+       SYS_EPOLL_CTL               = 21
+       SYS_EPOLL_PWAIT             = 22
+       SYS_DUP                     = 23
+       SYS_DUP3                    = 24
+       SYS_FCNTL                   = 25
+       SYS_INOTIFY_INIT1           = 26
+       SYS_INOTIFY_ADD_WATCH       = 27
+       SYS_INOTIFY_RM_WATCH        = 28
+       SYS_IOCTL                   = 29
+       SYS_IOPRIO_SET              = 30
+       SYS_IOPRIO_GET              = 31
+       SYS_FLOCK                   = 32
+       SYS_MKNODAT                 = 33
+       SYS_MKDIRAT                 = 34
+       SYS_UNLINKAT                = 35
+       SYS_SYMLINKAT               = 36
+       SYS_LINKAT                  = 37
+       SYS_RENAMEAT                = 38
+       SYS_UMOUNT2                 = 39
+       SYS_MOUNT                   = 40
+       SYS_PIVOT_ROOT              = 41
+       SYS_NFSSERVCTL              = 42
+       SYS_STATFS                  = 43
+       SYS_FSTATFS                 = 44
+       SYS_TRUNCATE                = 45
+       SYS_FTRUNCATE               = 46
+       SYS_FALLOCATE               = 47
+       SYS_FACCESSAT               = 48
+       SYS_CHDIR                   = 49
+       SYS_FCHDIR                  = 50
+       SYS_CHROOT                  = 51
+       SYS_FCHMOD                  = 52
+       SYS_FCHMODAT                = 53
+       SYS_FCHOWNAT                = 54
+       SYS_FCHOWN                  = 55
+       SYS_OPENAT                  = 56
+       SYS_CLOSE                   = 57
+       SYS_VHANGUP                 = 58
+       SYS_PIPE2                   = 59
+       SYS_QUOTACTL                = 60
+       SYS_GETDENTS64              = 61
+       SYS_LSEEK                   = 62
+       SYS_READ                    = 63
+       SYS_WRITE                   = 64
+       SYS_READV                   = 65
+       SYS_WRITEV                  = 66
+       SYS_PREAD64                 = 67
+       SYS_PWRITE64                = 68
+       SYS_PREADV                  = 69
+       SYS_PWRITEV                 = 70
+       SYS_SENDFILE                = 71
+       SYS_PSELECT6                = 72
+       SYS_PPOLL                   = 73
+       SYS_SIGNALFD4               = 74
+       SYS_VMSPLICE                = 75
+       SYS_SPLICE                  = 76
+       SYS_TEE                     = 77
+       SYS_READLINKAT              = 78
+       SYS_FSTATAT                 = 79
+       SYS_FSTAT                   = 80
+       SYS_SYNC                    = 81
+       SYS_FSYNC                   = 82
+       SYS_FDATASYNC               = 83
+       SYS_SYNC_FILE_RANGE         = 84
+       SYS_TIMERFD_CREATE          = 85
+       SYS_TIMERFD_SETTIME         = 86
+       SYS_TIMERFD_GETTIME         = 87
+       SYS_UTIMENSAT               = 88
+       SYS_ACCT                    = 89
+       SYS_CAPGET                  = 90
+       SYS_CAPSET                  = 91
+       SYS_PERSONALITY             = 92
+       SYS_EXIT                    = 93
+       SYS_EXIT_GROUP              = 94
+       SYS_WAITID                  = 95
+       SYS_SET_TID_ADDRESS         = 96
+       SYS_UNSHARE                 = 97
+       SYS_FUTEX                   = 98
+       SYS_SET_ROBUST_LIST         = 99
+       SYS_GET_ROBUST_LIST         = 100
+       SYS_NANOSLEEP               = 101
+       SYS_GETITIMER               = 102
+       SYS_SETITIMER               = 103
+       SYS_KEXEC_LOAD              = 104
+       SYS_INIT_MODULE             = 105
+       SYS_DELETE_MODULE           = 106
+       SYS_TIMER_CREATE            = 107
+       SYS_TIMER_GETTIME           = 108
+       SYS_TIMER_GETOVERRUN        = 109
+       SYS_TIMER_SETTIME           = 110
+       SYS_TIMER_DELETE            = 111
+       SYS_CLOCK_SETTIME           = 112
+       SYS_CLOCK_GETTIME           = 113
+       SYS_CLOCK_GETRES            = 114
+       SYS_CLOCK_NANOSLEEP         = 115
+       SYS_SYSLOG                  = 116
+       SYS_PTRACE                  = 117
+       SYS_SCHED_SETPARAM          = 118
+       SYS_SCHED_SETSCHEDULER      = 119
+       SYS_SCHED_GETSCHEDULER      = 120
+       SYS_SCHED_GETPARAM          = 121
+       SYS_SCHED_SETAFFINITY       = 122
+       SYS_SCHED_GETAFFINITY       = 123
+       SYS_SCHED_YIELD             = 124
+       SYS_SCHED_GET_PRIORITY_MAX  = 125
+       SYS_SCHED_GET_PRIORITY_MIN  = 126
+       SYS_SCHED_RR_GET_INTERVAL   = 127
+       SYS_RESTART_SYSCALL         = 128
+       SYS_KILL                    = 129
+       SYS_TKILL                   = 130
+       SYS_TGKILL                  = 131
+       SYS_SIGALTSTACK             = 132
+       SYS_RT_SIGSUSPEND           = 133
+       SYS_RT_SIGACTION            = 134
+       SYS_RT_SIGPROCMASK          = 135
+       SYS_RT_SIGPENDING           = 136
+       SYS_RT_SIGTIMEDWAIT         = 137
+       SYS_RT_SIGQUEUEINFO         = 138
+       SYS_RT_SIGRETURN            = 139
+       SYS_SETPRIORITY             = 140
+       SYS_GETPRIORITY             = 141
+       SYS_REBOOT                  = 142
+       SYS_SETREGID                = 143
+       SYS_SETGID                  = 144
+       SYS_SETREUID                = 145
+       SYS_SETUID                  = 146
+       SYS_SETRESUID               = 147
+       SYS_GETRESUID               = 148
+       SYS_SETRESGID               = 149
+       SYS_GETRESGID               = 150
+       SYS_SETFSUID                = 151
+       SYS_SETFSGID                = 152
+       SYS_TIMES                   = 153
+       SYS_SETPGID                 = 154
+       SYS_GETPGID                 = 155
+       SYS_GETSID                  = 156
+       SYS_SETSID                  = 157
+       SYS_GETGROUPS               = 158
+       SYS_SETGROUPS               = 159
+       SYS_UNAME                   = 160
+       SYS_SETHOSTNAME             = 161
+       SYS_SETDOMAINNAME           = 162
+       SYS_GETRLIMIT               = 163
+       SYS_SETRLIMIT               = 164
+       SYS_GETRUSAGE               = 165
+       SYS_UMASK                   = 166
+       SYS_PRCTL                   = 167
+       SYS_GETCPU                  = 168
+       SYS_GETTIMEOFDAY            = 169
+       SYS_SETTIMEOFDAY            = 170
+       SYS_ADJTIMEX                = 171
+       SYS_GETPID                  = 172
+       SYS_GETPPID                 = 173
+       SYS_GETUID                  = 174
+       SYS_GETEUID                 = 175
+       SYS_GETGID                  = 176
+       SYS_GETEGID                 = 177
+       SYS_GETTID                  = 178
+       SYS_SYSINFO                 = 179
+       SYS_MQ_OPEN                 = 180
+       SYS_MQ_UNLINK               = 181
+       SYS_MQ_TIMEDSEND            = 182
+       SYS_MQ_TIMEDRECEIVE         = 183
+       SYS_MQ_NOTIFY               = 184
+       SYS_MQ_GETSETATTR           = 185
+       SYS_MSGGET                  = 186
+       SYS_MSGCTL                  = 187
+       SYS_MSGRCV                  = 188
+       SYS_MSGSND                  = 189
+       SYS_SEMGET                  = 190
+       SYS_SEMCTL                  = 191
+       SYS_SEMTIMEDOP              = 192
+       SYS_SEMOP                   = 193
+       SYS_SHMGET                  = 194
+       SYS_SHMCTL                  = 195
+       SYS_SHMAT                   = 196
+       SYS_SHMDT                   = 197
+       SYS_SOCKET                  = 198
+       SYS_SOCKETPAIR              = 199
+       SYS_BIND                    = 200
+       SYS_LISTEN                  = 201
+       SYS_ACCEPT                  = 202
+       SYS_CONNECT                 = 203
+       SYS_GETSOCKNAME             = 204
+       SYS_GETPEERNAME             = 205
+       SYS_SENDTO                  = 206
+       SYS_RECVFROM                = 207
+       SYS_SETSOCKOPT              = 208
+       SYS_GETSOCKOPT              = 209
+       SYS_SHUTDOWN                = 210
+       SYS_SENDMSG                 = 211
+       SYS_RECVMSG                 = 212
+       SYS_READAHEAD               = 213
+       SYS_BRK                     = 214
+       SYS_MUNMAP                  = 215
+       SYS_MREMAP                  = 216
+       SYS_ADD_KEY                 = 217
+       SYS_REQUEST_KEY             = 218
+       SYS_KEYCTL                  = 219
+       SYS_CLONE                   = 220
+       SYS_EXECVE                  = 221
+       SYS_MMAP                    = 222
+       SYS_FADVISE64               = 223
+       SYS_SWAPON                  = 224
+       SYS_SWAPOFF                 = 225
+       SYS_MPROTECT                = 226
+       SYS_MSYNC                   = 227
+       SYS_MLOCK                   = 228
+       SYS_MUNLOCK                 = 229
+       SYS_MLOCKALL                = 230
+       SYS_MUNLOCKALL              = 231
+       SYS_MINCORE                 = 232
+       SYS_MADVISE                 = 233
+       SYS_REMAP_FILE_PAGES        = 234
+       SYS_MBIND                   = 235
+       SYS_GET_MEMPOLICY           = 236
+       SYS_SET_MEMPOLICY           = 237
+       SYS_MIGRATE_PAGES           = 238
+       SYS_MOVE_PAGES              = 239
+       SYS_RT_TGSIGQUEUEINFO       = 240
+       SYS_PERF_EVENT_OPEN         = 241
+       SYS_ACCEPT4                 = 242
+       SYS_RECVMMSG                = 243
+       SYS_ARCH_SPECIFIC_SYSCALL   = 244
+       SYS_WAIT4                   = 260
+       SYS_PRLIMIT64               = 261
+       SYS_FANOTIFY_INIT           = 262
+       SYS_FANOTIFY_MARK           = 263
+       SYS_NAME_TO_HANDLE_AT       = 264
+       SYS_OPEN_BY_HANDLE_AT       = 265
+       SYS_CLOCK_ADJTIME           = 266
+       SYS_SYNCFS                  = 267
+       SYS_SETNS                   = 268
+       SYS_SENDMMSG                = 269
+       SYS_PROCESS_VM_READV        = 270
+       SYS_PROCESS_VM_WRITEV       = 271
+       SYS_KCMP                    = 272
+       SYS_FINIT_MODULE            = 273
+       SYS_SCHED_SETATTR           = 274
+       SYS_SCHED_GETATTR           = 275
+       SYS_RENAMEAT2               = 276
+       SYS_SECCOMP                 = 277
+       SYS_GETRANDOM               = 278
+       SYS_MEMFD_CREATE            = 279
+       SYS_BPF                     = 280
+       SYS_EXECVEAT                = 281
+       SYS_USERFAULTFD             = 282
+       SYS_MEMBARRIER              = 283
+       SYS_MLOCK2                  = 284
+       SYS_COPY_FILE_RANGE         = 285
+       SYS_PREADV2                 = 286
+       SYS_PWRITEV2                = 287
+       SYS_PKEY_MPROTECT           = 288
+       SYS_PKEY_ALLOC              = 289
+       SYS_PKEY_FREE               = 290
+       SYS_STATX                   = 291
+       SYS_IO_PGETEVENTS           = 292
+       SYS_RSEQ                    = 293
+       SYS_KEXEC_FILE_LOAD         = 294
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLONE3                  = 435
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
+       SYS_MEMFD_SECRET            = 447
 )
index c877ec6e682141bb281bb7ca70da999c07633960..026695abb1a7ea4a9f39263a6adba0f63c24c2ad 100644 (file)
@@ -424,4 +424,8 @@ const (
        SYS_PROCESS_MADVISE              = 4440
        SYS_EPOLL_PWAIT2                 = 4441
        SYS_MOUNT_SETATTR                = 4442
+       SYS_QUOTACTL_FD                  = 4443
+       SYS_LANDLOCK_CREATE_RULESET      = 4444
+       SYS_LANDLOCK_ADD_RULE            = 4445
+       SYS_LANDLOCK_RESTRICT_SELF       = 4446
 )
index b5f29037299aced96b2934dddd1e1dabd5cb6fa0..7320ba95833a6897988ceb97280c3b0cf1d22d0d 100644 (file)
 package unix
 
 const (
-       SYS_READ                   = 5000
-       SYS_WRITE                  = 5001
-       SYS_OPEN                   = 5002
-       SYS_CLOSE                  = 5003
-       SYS_STAT                   = 5004
-       SYS_FSTAT                  = 5005
-       SYS_LSTAT                  = 5006
-       SYS_POLL                   = 5007
-       SYS_LSEEK                  = 5008
-       SYS_MMAP                   = 5009
-       SYS_MPROTECT               = 5010
-       SYS_MUNMAP                 = 5011
-       SYS_BRK                    = 5012
-       SYS_RT_SIGACTION           = 5013
-       SYS_RT_SIGPROCMASK         = 5014
-       SYS_IOCTL                  = 5015
-       SYS_PREAD64                = 5016
-       SYS_PWRITE64               = 5017
-       SYS_READV                  = 5018
-       SYS_WRITEV                 = 5019
-       SYS_ACCESS                 = 5020
-       SYS_PIPE                   = 5021
-       SYS__NEWSELECT             = 5022
-       SYS_SCHED_YIELD            = 5023
-       SYS_MREMAP                 = 5024
-       SYS_MSYNC                  = 5025
-       SYS_MINCORE                = 5026
-       SYS_MADVISE                = 5027
-       SYS_SHMGET                 = 5028
-       SYS_SHMAT                  = 5029
-       SYS_SHMCTL                 = 5030
-       SYS_DUP                    = 5031
-       SYS_DUP2                   = 5032
-       SYS_PAUSE                  = 5033
-       SYS_NANOSLEEP              = 5034
-       SYS_GETITIMER              = 5035
-       SYS_SETITIMER              = 5036
-       SYS_ALARM                  = 5037
-       SYS_GETPID                 = 5038
-       SYS_SENDFILE               = 5039
-       SYS_SOCKET                 = 5040
-       SYS_CONNECT                = 5041
-       SYS_ACCEPT                 = 5042
-       SYS_SENDTO                 = 5043
-       SYS_RECVFROM               = 5044
-       SYS_SENDMSG                = 5045
-       SYS_RECVMSG                = 5046
-       SYS_SHUTDOWN               = 5047
-       SYS_BIND                   = 5048
-       SYS_LISTEN                 = 5049
-       SYS_GETSOCKNAME            = 5050
-       SYS_GETPEERNAME            = 5051
-       SYS_SOCKETPAIR             = 5052
-       SYS_SETSOCKOPT             = 5053
-       SYS_GETSOCKOPT             = 5054
-       SYS_CLONE                  = 5055
-       SYS_FORK                   = 5056
-       SYS_EXECVE                 = 5057
-       SYS_EXIT                   = 5058
-       SYS_WAIT4                  = 5059
-       SYS_KILL                   = 5060
-       SYS_UNAME                  = 5061
-       SYS_SEMGET                 = 5062
-       SYS_SEMOP                  = 5063
-       SYS_SEMCTL                 = 5064
-       SYS_SHMDT                  = 5065
-       SYS_MSGGET                 = 5066
-       SYS_MSGSND                 = 5067
-       SYS_MSGRCV                 = 5068
-       SYS_MSGCTL                 = 5069
-       SYS_FCNTL                  = 5070
-       SYS_FLOCK                  = 5071
-       SYS_FSYNC                  = 5072
-       SYS_FDATASYNC              = 5073
-       SYS_TRUNCATE               = 5074
-       SYS_FTRUNCATE              = 5075
-       SYS_GETDENTS               = 5076
-       SYS_GETCWD                 = 5077
-       SYS_CHDIR                  = 5078
-       SYS_FCHDIR                 = 5079
-       SYS_RENAME                 = 5080
-       SYS_MKDIR                  = 5081
-       SYS_RMDIR                  = 5082
-       SYS_CREAT                  = 5083
-       SYS_LINK                   = 5084
-       SYS_UNLINK                 = 5085
-       SYS_SYMLINK                = 5086
-       SYS_READLINK               = 5087
-       SYS_CHMOD                  = 5088
-       SYS_FCHMOD                 = 5089
-       SYS_CHOWN                  = 5090
-       SYS_FCHOWN                 = 5091
-       SYS_LCHOWN                 = 5092
-       SYS_UMASK                  = 5093
-       SYS_GETTIMEOFDAY           = 5094
-       SYS_GETRLIMIT              = 5095
-       SYS_GETRUSAGE              = 5096
-       SYS_SYSINFO                = 5097
-       SYS_TIMES                  = 5098
-       SYS_PTRACE                 = 5099
-       SYS_GETUID                 = 5100
-       SYS_SYSLOG                 = 5101
-       SYS_GETGID                 = 5102
-       SYS_SETUID                 = 5103
-       SYS_SETGID                 = 5104
-       SYS_GETEUID                = 5105
-       SYS_GETEGID                = 5106
-       SYS_SETPGID                = 5107
-       SYS_GETPPID                = 5108
-       SYS_GETPGRP                = 5109
-       SYS_SETSID                 = 5110
-       SYS_SETREUID               = 5111
-       SYS_SETREGID               = 5112
-       SYS_GETGROUPS              = 5113
-       SYS_SETGROUPS              = 5114
-       SYS_SETRESUID              = 5115
-       SYS_GETRESUID              = 5116
-       SYS_SETRESGID              = 5117
-       SYS_GETRESGID              = 5118
-       SYS_GETPGID                = 5119
-       SYS_SETFSUID               = 5120
-       SYS_SETFSGID               = 5121
-       SYS_GETSID                 = 5122
-       SYS_CAPGET                 = 5123
-       SYS_CAPSET                 = 5124
-       SYS_RT_SIGPENDING          = 5125
-       SYS_RT_SIGTIMEDWAIT        = 5126
-       SYS_RT_SIGQUEUEINFO        = 5127
-       SYS_RT_SIGSUSPEND          = 5128
-       SYS_SIGALTSTACK            = 5129
-       SYS_UTIME                  = 5130
-       SYS_MKNOD                  = 5131
-       SYS_PERSONALITY            = 5132
-       SYS_USTAT                  = 5133
-       SYS_STATFS                 = 5134
-       SYS_FSTATFS                = 5135
-       SYS_SYSFS                  = 5136
-       SYS_GETPRIORITY            = 5137
-       SYS_SETPRIORITY            = 5138
-       SYS_SCHED_SETPARAM         = 5139
-       SYS_SCHED_GETPARAM         = 5140
-       SYS_SCHED_SETSCHEDULER     = 5141
-       SYS_SCHED_GETSCHEDULER     = 5142
-       SYS_SCHED_GET_PRIORITY_MAX = 5143
-       SYS_SCHED_GET_PRIORITY_MIN = 5144
-       SYS_SCHED_RR_GET_INTERVAL  = 5145
-       SYS_MLOCK                  = 5146
-       SYS_MUNLOCK                = 5147
-       SYS_MLOCKALL               = 5148
-       SYS_MUNLOCKALL             = 5149
-       SYS_VHANGUP                = 5150
-       SYS_PIVOT_ROOT             = 5151
-       SYS__SYSCTL                = 5152
-       SYS_PRCTL                  = 5153
-       SYS_ADJTIMEX               = 5154
-       SYS_SETRLIMIT              = 5155
-       SYS_CHROOT                 = 5156
-       SYS_SYNC                   = 5157
-       SYS_ACCT                   = 5158
-       SYS_SETTIMEOFDAY           = 5159
-       SYS_MOUNT                  = 5160
-       SYS_UMOUNT2                = 5161
-       SYS_SWAPON                 = 5162
-       SYS_SWAPOFF                = 5163
-       SYS_REBOOT                 = 5164
-       SYS_SETHOSTNAME            = 5165
-       SYS_SETDOMAINNAME          = 5166
-       SYS_CREATE_MODULE          = 5167
-       SYS_INIT_MODULE            = 5168
-       SYS_DELETE_MODULE          = 5169
-       SYS_GET_KERNEL_SYMS        = 5170
-       SYS_QUERY_MODULE           = 5171
-       SYS_QUOTACTL               = 5172
-       SYS_NFSSERVCTL             = 5173
-       SYS_GETPMSG                = 5174
-       SYS_PUTPMSG                = 5175
-       SYS_AFS_SYSCALL            = 5176
-       SYS_RESERVED177            = 5177
-       SYS_GETTID                 = 5178
-       SYS_READAHEAD              = 5179
-       SYS_SETXATTR               = 5180
-       SYS_LSETXATTR              = 5181
-       SYS_FSETXATTR              = 5182
-       SYS_GETXATTR               = 5183
-       SYS_LGETXATTR              = 5184
-       SYS_FGETXATTR              = 5185
-       SYS_LISTXATTR              = 5186
-       SYS_LLISTXATTR             = 5187
-       SYS_FLISTXATTR             = 5188
-       SYS_REMOVEXATTR            = 5189
-       SYS_LREMOVEXATTR           = 5190
-       SYS_FREMOVEXATTR           = 5191
-       SYS_TKILL                  = 5192
-       SYS_RESERVED193            = 5193
-       SYS_FUTEX                  = 5194
-       SYS_SCHED_SETAFFINITY      = 5195
-       SYS_SCHED_GETAFFINITY      = 5196
-       SYS_CACHEFLUSH             = 5197
-       SYS_CACHECTL               = 5198
-       SYS_SYSMIPS                = 5199
-       SYS_IO_SETUP               = 5200
-       SYS_IO_DESTROY             = 5201
-       SYS_IO_GETEVENTS           = 5202
-       SYS_IO_SUBMIT              = 5203
-       SYS_IO_CANCEL              = 5204
-       SYS_EXIT_GROUP             = 5205
-       SYS_LOOKUP_DCOOKIE         = 5206
-       SYS_EPOLL_CREATE           = 5207
-       SYS_EPOLL_CTL              = 5208
-       SYS_EPOLL_WAIT             = 5209
-       SYS_REMAP_FILE_PAGES       = 5210
-       SYS_RT_SIGRETURN           = 5211
-       SYS_SET_TID_ADDRESS        = 5212
-       SYS_RESTART_SYSCALL        = 5213
-       SYS_SEMTIMEDOP             = 5214
-       SYS_FADVISE64              = 5215
-       SYS_TIMER_CREATE           = 5216
-       SYS_TIMER_SETTIME          = 5217
-       SYS_TIMER_GETTIME          = 5218
-       SYS_TIMER_GETOVERRUN       = 5219
-       SYS_TIMER_DELETE           = 5220
-       SYS_CLOCK_SETTIME          = 5221
-       SYS_CLOCK_GETTIME          = 5222
-       SYS_CLOCK_GETRES           = 5223
-       SYS_CLOCK_NANOSLEEP        = 5224
-       SYS_TGKILL                 = 5225
-       SYS_UTIMES                 = 5226
-       SYS_MBIND                  = 5227
-       SYS_GET_MEMPOLICY          = 5228
-       SYS_SET_MEMPOLICY          = 5229
-       SYS_MQ_OPEN                = 5230
-       SYS_MQ_UNLINK              = 5231
-       SYS_MQ_TIMEDSEND           = 5232
-       SYS_MQ_TIMEDRECEIVE        = 5233
-       SYS_MQ_NOTIFY              = 5234
-       SYS_MQ_GETSETATTR          = 5235
-       SYS_VSERVER                = 5236
-       SYS_WAITID                 = 5237
-       SYS_ADD_KEY                = 5239
-       SYS_REQUEST_KEY            = 5240
-       SYS_KEYCTL                 = 5241
-       SYS_SET_THREAD_AREA        = 5242
-       SYS_INOTIFY_INIT           = 5243
-       SYS_INOTIFY_ADD_WATCH      = 5244
-       SYS_INOTIFY_RM_WATCH       = 5245
-       SYS_MIGRATE_PAGES          = 5246
-       SYS_OPENAT                 = 5247
-       SYS_MKDIRAT                = 5248
-       SYS_MKNODAT                = 5249
-       SYS_FCHOWNAT               = 5250
-       SYS_FUTIMESAT              = 5251
-       SYS_NEWFSTATAT             = 5252
-       SYS_UNLINKAT               = 5253
-       SYS_RENAMEAT               = 5254
-       SYS_LINKAT                 = 5255
-       SYS_SYMLINKAT              = 5256
-       SYS_READLINKAT             = 5257
-       SYS_FCHMODAT               = 5258
-       SYS_FACCESSAT              = 5259
-       SYS_PSELECT6               = 5260
-       SYS_PPOLL                  = 5261
-       SYS_UNSHARE                = 5262
-       SYS_SPLICE                 = 5263
-       SYS_SYNC_FILE_RANGE        = 5264
-       SYS_TEE                    = 5265
-       SYS_VMSPLICE               = 5266
-       SYS_MOVE_PAGES             = 5267
-       SYS_SET_ROBUST_LIST        = 5268
-       SYS_GET_ROBUST_LIST        = 5269
-       SYS_KEXEC_LOAD             = 5270
-       SYS_GETCPU                 = 5271
-       SYS_EPOLL_PWAIT            = 5272
-       SYS_IOPRIO_SET             = 5273
-       SYS_IOPRIO_GET             = 5274
-       SYS_UTIMENSAT              = 5275
-       SYS_SIGNALFD               = 5276
-       SYS_TIMERFD                = 5277
-       SYS_EVENTFD                = 5278
-       SYS_FALLOCATE              = 5279
-       SYS_TIMERFD_CREATE         = 5280
-       SYS_TIMERFD_GETTIME        = 5281
-       SYS_TIMERFD_SETTIME        = 5282
-       SYS_SIGNALFD4              = 5283
-       SYS_EVENTFD2               = 5284
-       SYS_EPOLL_CREATE1          = 5285
-       SYS_DUP3                   = 5286
-       SYS_PIPE2                  = 5287
-       SYS_INOTIFY_INIT1          = 5288
-       SYS_PREADV                 = 5289
-       SYS_PWRITEV                = 5290
-       SYS_RT_TGSIGQUEUEINFO      = 5291
-       SYS_PERF_EVENT_OPEN        = 5292
-       SYS_ACCEPT4                = 5293
-       SYS_RECVMMSG               = 5294
-       SYS_FANOTIFY_INIT          = 5295
-       SYS_FANOTIFY_MARK          = 5296
-       SYS_PRLIMIT64              = 5297
-       SYS_NAME_TO_HANDLE_AT      = 5298
-       SYS_OPEN_BY_HANDLE_AT      = 5299
-       SYS_CLOCK_ADJTIME          = 5300
-       SYS_SYNCFS                 = 5301
-       SYS_SENDMMSG               = 5302
-       SYS_SETNS                  = 5303
-       SYS_PROCESS_VM_READV       = 5304
-       SYS_PROCESS_VM_WRITEV      = 5305
-       SYS_KCMP                   = 5306
-       SYS_FINIT_MODULE           = 5307
-       SYS_GETDENTS64             = 5308
-       SYS_SCHED_SETATTR          = 5309
-       SYS_SCHED_GETATTR          = 5310
-       SYS_RENAMEAT2              = 5311
-       SYS_SECCOMP                = 5312
-       SYS_GETRANDOM              = 5313
-       SYS_MEMFD_CREATE           = 5314
-       SYS_BPF                    = 5315
-       SYS_EXECVEAT               = 5316
-       SYS_USERFAULTFD            = 5317
-       SYS_MEMBARRIER             = 5318
-       SYS_MLOCK2                 = 5319
-       SYS_COPY_FILE_RANGE        = 5320
-       SYS_PREADV2                = 5321
-       SYS_PWRITEV2               = 5322
-       SYS_PKEY_MPROTECT          = 5323
-       SYS_PKEY_ALLOC             = 5324
-       SYS_PKEY_FREE              = 5325
-       SYS_STATX                  = 5326
-       SYS_RSEQ                   = 5327
-       SYS_IO_PGETEVENTS          = 5328
-       SYS_PIDFD_SEND_SIGNAL      = 5424
-       SYS_IO_URING_SETUP         = 5425
-       SYS_IO_URING_ENTER         = 5426
-       SYS_IO_URING_REGISTER      = 5427
-       SYS_OPEN_TREE              = 5428
-       SYS_MOVE_MOUNT             = 5429
-       SYS_FSOPEN                 = 5430
-       SYS_FSCONFIG               = 5431
-       SYS_FSMOUNT                = 5432
-       SYS_FSPICK                 = 5433
-       SYS_PIDFD_OPEN             = 5434
-       SYS_CLONE3                 = 5435
-       SYS_CLOSE_RANGE            = 5436
-       SYS_OPENAT2                = 5437
-       SYS_PIDFD_GETFD            = 5438
-       SYS_FACCESSAT2             = 5439
-       SYS_PROCESS_MADVISE        = 5440
-       SYS_EPOLL_PWAIT2           = 5441
-       SYS_MOUNT_SETATTR          = 5442
+       SYS_READ                    = 5000
+       SYS_WRITE                   = 5001
+       SYS_OPEN                    = 5002
+       SYS_CLOSE                   = 5003
+       SYS_STAT                    = 5004
+       SYS_FSTAT                   = 5005
+       SYS_LSTAT                   = 5006
+       SYS_POLL                    = 5007
+       SYS_LSEEK                   = 5008
+       SYS_MMAP                    = 5009
+       SYS_MPROTECT                = 5010
+       SYS_MUNMAP                  = 5011
+       SYS_BRK                     = 5012
+       SYS_RT_SIGACTION            = 5013
+       SYS_RT_SIGPROCMASK          = 5014
+       SYS_IOCTL                   = 5015
+       SYS_PREAD64                 = 5016
+       SYS_PWRITE64                = 5017
+       SYS_READV                   = 5018
+       SYS_WRITEV                  = 5019
+       SYS_ACCESS                  = 5020
+       SYS_PIPE                    = 5021
+       SYS__NEWSELECT              = 5022
+       SYS_SCHED_YIELD             = 5023
+       SYS_MREMAP                  = 5024
+       SYS_MSYNC                   = 5025
+       SYS_MINCORE                 = 5026
+       SYS_MADVISE                 = 5027
+       SYS_SHMGET                  = 5028
+       SYS_SHMAT                   = 5029
+       SYS_SHMCTL                  = 5030
+       SYS_DUP                     = 5031
+       SYS_DUP2                    = 5032
+       SYS_PAUSE                   = 5033
+       SYS_NANOSLEEP               = 5034
+       SYS_GETITIMER               = 5035
+       SYS_SETITIMER               = 5036
+       SYS_ALARM                   = 5037
+       SYS_GETPID                  = 5038
+       SYS_SENDFILE                = 5039
+       SYS_SOCKET                  = 5040
+       SYS_CONNECT                 = 5041
+       SYS_ACCEPT                  = 5042
+       SYS_SENDTO                  = 5043
+       SYS_RECVFROM                = 5044
+       SYS_SENDMSG                 = 5045
+       SYS_RECVMSG                 = 5046
+       SYS_SHUTDOWN                = 5047
+       SYS_BIND                    = 5048
+       SYS_LISTEN                  = 5049
+       SYS_GETSOCKNAME             = 5050
+       SYS_GETPEERNAME             = 5051
+       SYS_SOCKETPAIR              = 5052
+       SYS_SETSOCKOPT              = 5053
+       SYS_GETSOCKOPT              = 5054
+       SYS_CLONE                   = 5055
+       SYS_FORK                    = 5056
+       SYS_EXECVE                  = 5057
+       SYS_EXIT                    = 5058
+       SYS_WAIT4                   = 5059
+       SYS_KILL                    = 5060
+       SYS_UNAME                   = 5061
+       SYS_SEMGET                  = 5062
+       SYS_SEMOP                   = 5063
+       SYS_SEMCTL                  = 5064
+       SYS_SHMDT                   = 5065
+       SYS_MSGGET                  = 5066
+       SYS_MSGSND                  = 5067
+       SYS_MSGRCV                  = 5068
+       SYS_MSGCTL                  = 5069
+       SYS_FCNTL                   = 5070
+       SYS_FLOCK                   = 5071
+       SYS_FSYNC                   = 5072
+       SYS_FDATASYNC               = 5073
+       SYS_TRUNCATE                = 5074
+       SYS_FTRUNCATE               = 5075
+       SYS_GETDENTS                = 5076
+       SYS_GETCWD                  = 5077
+       SYS_CHDIR                   = 5078
+       SYS_FCHDIR                  = 5079
+       SYS_RENAME                  = 5080
+       SYS_MKDIR                   = 5081
+       SYS_RMDIR                   = 5082
+       SYS_CREAT                   = 5083
+       SYS_LINK                    = 5084
+       SYS_UNLINK                  = 5085
+       SYS_SYMLINK                 = 5086
+       SYS_READLINK                = 5087
+       SYS_CHMOD                   = 5088
+       SYS_FCHMOD                  = 5089
+       SYS_CHOWN                   = 5090
+       SYS_FCHOWN                  = 5091
+       SYS_LCHOWN                  = 5092
+       SYS_UMASK                   = 5093
+       SYS_GETTIMEOFDAY            = 5094
+       SYS_GETRLIMIT               = 5095
+       SYS_GETRUSAGE               = 5096
+       SYS_SYSINFO                 = 5097
+       SYS_TIMES                   = 5098
+       SYS_PTRACE                  = 5099
+       SYS_GETUID                  = 5100
+       SYS_SYSLOG                  = 5101
+       SYS_GETGID                  = 5102
+       SYS_SETUID                  = 5103
+       SYS_SETGID                  = 5104
+       SYS_GETEUID                 = 5105
+       SYS_GETEGID                 = 5106
+       SYS_SETPGID                 = 5107
+       SYS_GETPPID                 = 5108
+       SYS_GETPGRP                 = 5109
+       SYS_SETSID                  = 5110
+       SYS_SETREUID                = 5111
+       SYS_SETREGID                = 5112
+       SYS_GETGROUPS               = 5113
+       SYS_SETGROUPS               = 5114
+       SYS_SETRESUID               = 5115
+       SYS_GETRESUID               = 5116
+       SYS_SETRESGID               = 5117
+       SYS_GETRESGID               = 5118
+       SYS_GETPGID                 = 5119
+       SYS_SETFSUID                = 5120
+       SYS_SETFSGID                = 5121
+       SYS_GETSID                  = 5122
+       SYS_CAPGET                  = 5123
+       SYS_CAPSET                  = 5124
+       SYS_RT_SIGPENDING           = 5125
+       SYS_RT_SIGTIMEDWAIT         = 5126
+       SYS_RT_SIGQUEUEINFO         = 5127
+       SYS_RT_SIGSUSPEND           = 5128
+       SYS_SIGALTSTACK             = 5129
+       SYS_UTIME                   = 5130
+       SYS_MKNOD                   = 5131
+       SYS_PERSONALITY             = 5132
+       SYS_USTAT                   = 5133
+       SYS_STATFS                  = 5134
+       SYS_FSTATFS                 = 5135
+       SYS_SYSFS                   = 5136
+       SYS_GETPRIORITY             = 5137
+       SYS_SETPRIORITY             = 5138
+       SYS_SCHED_SETPARAM          = 5139
+       SYS_SCHED_GETPARAM          = 5140
+       SYS_SCHED_SETSCHEDULER      = 5141
+       SYS_SCHED_GETSCHEDULER      = 5142
+       SYS_SCHED_GET_PRIORITY_MAX  = 5143
+       SYS_SCHED_GET_PRIORITY_MIN  = 5144
+       SYS_SCHED_RR_GET_INTERVAL   = 5145
+       SYS_MLOCK                   = 5146
+       SYS_MUNLOCK                 = 5147
+       SYS_MLOCKALL                = 5148
+       SYS_MUNLOCKALL              = 5149
+       SYS_VHANGUP                 = 5150
+       SYS_PIVOT_ROOT              = 5151
+       SYS__SYSCTL                 = 5152
+       SYS_PRCTL                   = 5153
+       SYS_ADJTIMEX                = 5154
+       SYS_SETRLIMIT               = 5155
+       SYS_CHROOT                  = 5156
+       SYS_SYNC                    = 5157
+       SYS_ACCT                    = 5158
+       SYS_SETTIMEOFDAY            = 5159
+       SYS_MOUNT                   = 5160
+       SYS_UMOUNT2                 = 5161
+       SYS_SWAPON                  = 5162
+       SYS_SWAPOFF                 = 5163
+       SYS_REBOOT                  = 5164
+       SYS_SETHOSTNAME             = 5165
+       SYS_SETDOMAINNAME           = 5166
+       SYS_CREATE_MODULE           = 5167
+       SYS_INIT_MODULE             = 5168
+       SYS_DELETE_MODULE           = 5169
+       SYS_GET_KERNEL_SYMS         = 5170
+       SYS_QUERY_MODULE            = 5171
+       SYS_QUOTACTL                = 5172
+       SYS_NFSSERVCTL              = 5173
+       SYS_GETPMSG                 = 5174
+       SYS_PUTPMSG                 = 5175
+       SYS_AFS_SYSCALL             = 5176
+       SYS_RESERVED177             = 5177
+       SYS_GETTID                  = 5178
+       SYS_READAHEAD               = 5179
+       SYS_SETXATTR                = 5180
+       SYS_LSETXATTR               = 5181
+       SYS_FSETXATTR               = 5182
+       SYS_GETXATTR                = 5183
+       SYS_LGETXATTR               = 5184
+       SYS_FGETXATTR               = 5185
+       SYS_LISTXATTR               = 5186
+       SYS_LLISTXATTR              = 5187
+       SYS_FLISTXATTR              = 5188
+       SYS_REMOVEXATTR             = 5189
+       SYS_LREMOVEXATTR            = 5190
+       SYS_FREMOVEXATTR            = 5191
+       SYS_TKILL                   = 5192
+       SYS_RESERVED193             = 5193
+       SYS_FUTEX                   = 5194
+       SYS_SCHED_SETAFFINITY       = 5195
+       SYS_SCHED_GETAFFINITY       = 5196
+       SYS_CACHEFLUSH              = 5197
+       SYS_CACHECTL                = 5198
+       SYS_SYSMIPS                 = 5199
+       SYS_IO_SETUP                = 5200
+       SYS_IO_DESTROY              = 5201
+       SYS_IO_GETEVENTS            = 5202
+       SYS_IO_SUBMIT               = 5203
+       SYS_IO_CANCEL               = 5204
+       SYS_EXIT_GROUP              = 5205
+       SYS_LOOKUP_DCOOKIE          = 5206
+       SYS_EPOLL_CREATE            = 5207
+       SYS_EPOLL_CTL               = 5208
+       SYS_EPOLL_WAIT              = 5209
+       SYS_REMAP_FILE_PAGES        = 5210
+       SYS_RT_SIGRETURN            = 5211
+       SYS_SET_TID_ADDRESS         = 5212
+       SYS_RESTART_SYSCALL         = 5213
+       SYS_SEMTIMEDOP              = 5214
+       SYS_FADVISE64               = 5215
+       SYS_TIMER_CREATE            = 5216
+       SYS_TIMER_SETTIME           = 5217
+       SYS_TIMER_GETTIME           = 5218
+       SYS_TIMER_GETOVERRUN        = 5219
+       SYS_TIMER_DELETE            = 5220
+       SYS_CLOCK_SETTIME           = 5221
+       SYS_CLOCK_GETTIME           = 5222
+       SYS_CLOCK_GETRES            = 5223
+       SYS_CLOCK_NANOSLEEP         = 5224
+       SYS_TGKILL                  = 5225
+       SYS_UTIMES                  = 5226
+       SYS_MBIND                   = 5227
+       SYS_GET_MEMPOLICY           = 5228
+       SYS_SET_MEMPOLICY           = 5229
+       SYS_MQ_OPEN                 = 5230
+       SYS_MQ_UNLINK               = 5231
+       SYS_MQ_TIMEDSEND            = 5232
+       SYS_MQ_TIMEDRECEIVE         = 5233
+       SYS_MQ_NOTIFY               = 5234
+       SYS_MQ_GETSETATTR           = 5235
+       SYS_VSERVER                 = 5236
+       SYS_WAITID                  = 5237
+       SYS_ADD_KEY                 = 5239
+       SYS_REQUEST_KEY             = 5240
+       SYS_KEYCTL                  = 5241
+       SYS_SET_THREAD_AREA         = 5242
+       SYS_INOTIFY_INIT            = 5243
+       SYS_INOTIFY_ADD_WATCH       = 5244
+       SYS_INOTIFY_RM_WATCH        = 5245
+       SYS_MIGRATE_PAGES           = 5246
+       SYS_OPENAT                  = 5247
+       SYS_MKDIRAT                 = 5248
+       SYS_MKNODAT                 = 5249
+       SYS_FCHOWNAT                = 5250
+       SYS_FUTIMESAT               = 5251
+       SYS_NEWFSTATAT              = 5252
+       SYS_UNLINKAT                = 5253
+       SYS_RENAMEAT                = 5254
+       SYS_LINKAT                  = 5255
+       SYS_SYMLINKAT               = 5256
+       SYS_READLINKAT              = 5257
+       SYS_FCHMODAT                = 5258
+       SYS_FACCESSAT               = 5259
+       SYS_PSELECT6                = 5260
+       SYS_PPOLL                   = 5261
+       SYS_UNSHARE                 = 5262
+       SYS_SPLICE                  = 5263
+       SYS_SYNC_FILE_RANGE         = 5264
+       SYS_TEE                     = 5265
+       SYS_VMSPLICE                = 5266
+       SYS_MOVE_PAGES              = 5267
+       SYS_SET_ROBUST_LIST         = 5268
+       SYS_GET_ROBUST_LIST         = 5269
+       SYS_KEXEC_LOAD              = 5270
+       SYS_GETCPU                  = 5271
+       SYS_EPOLL_PWAIT             = 5272
+       SYS_IOPRIO_SET              = 5273
+       SYS_IOPRIO_GET              = 5274
+       SYS_UTIMENSAT               = 5275
+       SYS_SIGNALFD                = 5276
+       SYS_TIMERFD                 = 5277
+       SYS_EVENTFD                 = 5278
+       SYS_FALLOCATE               = 5279
+       SYS_TIMERFD_CREATE          = 5280
+       SYS_TIMERFD_GETTIME         = 5281
+       SYS_TIMERFD_SETTIME         = 5282
+       SYS_SIGNALFD4               = 5283
+       SYS_EVENTFD2                = 5284
+       SYS_EPOLL_CREATE1           = 5285
+       SYS_DUP3                    = 5286
+       SYS_PIPE2                   = 5287
+       SYS_INOTIFY_INIT1           = 5288
+       SYS_PREADV                  = 5289
+       SYS_PWRITEV                 = 5290
+       SYS_RT_TGSIGQUEUEINFO       = 5291
+       SYS_PERF_EVENT_OPEN         = 5292
+       SYS_ACCEPT4                 = 5293
+       SYS_RECVMMSG                = 5294
+       SYS_FANOTIFY_INIT           = 5295
+       SYS_FANOTIFY_MARK           = 5296
+       SYS_PRLIMIT64               = 5297
+       SYS_NAME_TO_HANDLE_AT       = 5298
+       SYS_OPEN_BY_HANDLE_AT       = 5299
+       SYS_CLOCK_ADJTIME           = 5300
+       SYS_SYNCFS                  = 5301
+       SYS_SENDMMSG                = 5302
+       SYS_SETNS                   = 5303
+       SYS_PROCESS_VM_READV        = 5304
+       SYS_PROCESS_VM_WRITEV       = 5305
+       SYS_KCMP                    = 5306
+       SYS_FINIT_MODULE            = 5307
+       SYS_GETDENTS64              = 5308
+       SYS_SCHED_SETATTR           = 5309
+       SYS_SCHED_GETATTR           = 5310
+       SYS_RENAMEAT2               = 5311
+       SYS_SECCOMP                 = 5312
+       SYS_GETRANDOM               = 5313
+       SYS_MEMFD_CREATE            = 5314
+       SYS_BPF                     = 5315
+       SYS_EXECVEAT                = 5316
+       SYS_USERFAULTFD             = 5317
+       SYS_MEMBARRIER              = 5318
+       SYS_MLOCK2                  = 5319
+       SYS_COPY_FILE_RANGE         = 5320
+       SYS_PREADV2                 = 5321
+       SYS_PWRITEV2                = 5322
+       SYS_PKEY_MPROTECT           = 5323
+       SYS_PKEY_ALLOC              = 5324
+       SYS_PKEY_FREE               = 5325
+       SYS_STATX                   = 5326
+       SYS_RSEQ                    = 5327
+       SYS_IO_PGETEVENTS           = 5328
+       SYS_PIDFD_SEND_SIGNAL       = 5424
+       SYS_IO_URING_SETUP          = 5425
+       SYS_IO_URING_ENTER          = 5426
+       SYS_IO_URING_REGISTER       = 5427
+       SYS_OPEN_TREE               = 5428
+       SYS_MOVE_MOUNT              = 5429
+       SYS_FSOPEN                  = 5430
+       SYS_FSCONFIG                = 5431
+       SYS_FSMOUNT                 = 5432
+       SYS_FSPICK                  = 5433
+       SYS_PIDFD_OPEN              = 5434
+       SYS_CLONE3                  = 5435
+       SYS_CLOSE_RANGE             = 5436
+       SYS_OPENAT2                 = 5437
+       SYS_PIDFD_GETFD             = 5438
+       SYS_FACCESSAT2              = 5439
+       SYS_PROCESS_MADVISE         = 5440
+       SYS_EPOLL_PWAIT2            = 5441
+       SYS_MOUNT_SETATTR           = 5442
+       SYS_QUOTACTL_FD             = 5443
+       SYS_LANDLOCK_CREATE_RULESET = 5444
+       SYS_LANDLOCK_ADD_RULE       = 5445
+       SYS_LANDLOCK_RESTRICT_SELF  = 5446
 )
index 46077689ab1f02b2052cd0bdc7e90d82e3f3d784..45082dd67fffbe24be424727b6c3654eb53cf8c6 100644 (file)
 package unix
 
 const (
-       SYS_READ                   = 5000
-       SYS_WRITE                  = 5001
-       SYS_OPEN                   = 5002
-       SYS_CLOSE                  = 5003
-       SYS_STAT                   = 5004
-       SYS_FSTAT                  = 5005
-       SYS_LSTAT                  = 5006
-       SYS_POLL                   = 5007
-       SYS_LSEEK                  = 5008
-       SYS_MMAP                   = 5009
-       SYS_MPROTECT               = 5010
-       SYS_MUNMAP                 = 5011
-       SYS_BRK                    = 5012
-       SYS_RT_SIGACTION           = 5013
-       SYS_RT_SIGPROCMASK         = 5014
-       SYS_IOCTL                  = 5015
-       SYS_PREAD64                = 5016
-       SYS_PWRITE64               = 5017
-       SYS_READV                  = 5018
-       SYS_WRITEV                 = 5019
-       SYS_ACCESS                 = 5020
-       SYS_PIPE                   = 5021
-       SYS__NEWSELECT             = 5022
-       SYS_SCHED_YIELD            = 5023
-       SYS_MREMAP                 = 5024
-       SYS_MSYNC                  = 5025
-       SYS_MINCORE                = 5026
-       SYS_MADVISE                = 5027
-       SYS_SHMGET                 = 5028
-       SYS_SHMAT                  = 5029
-       SYS_SHMCTL                 = 5030
-       SYS_DUP                    = 5031
-       SYS_DUP2                   = 5032
-       SYS_PAUSE                  = 5033
-       SYS_NANOSLEEP              = 5034
-       SYS_GETITIMER              = 5035
-       SYS_SETITIMER              = 5036
-       SYS_ALARM                  = 5037
-       SYS_GETPID                 = 5038
-       SYS_SENDFILE               = 5039
-       SYS_SOCKET                 = 5040
-       SYS_CONNECT                = 5041
-       SYS_ACCEPT                 = 5042
-       SYS_SENDTO                 = 5043
-       SYS_RECVFROM               = 5044
-       SYS_SENDMSG                = 5045
-       SYS_RECVMSG                = 5046
-       SYS_SHUTDOWN               = 5047
-       SYS_BIND                   = 5048
-       SYS_LISTEN                 = 5049
-       SYS_GETSOCKNAME            = 5050
-       SYS_GETPEERNAME            = 5051
-       SYS_SOCKETPAIR             = 5052
-       SYS_SETSOCKOPT             = 5053
-       SYS_GETSOCKOPT             = 5054
-       SYS_CLONE                  = 5055
-       SYS_FORK                   = 5056
-       SYS_EXECVE                 = 5057
-       SYS_EXIT                   = 5058
-       SYS_WAIT4                  = 5059
-       SYS_KILL                   = 5060
-       SYS_UNAME                  = 5061
-       SYS_SEMGET                 = 5062
-       SYS_SEMOP                  = 5063
-       SYS_SEMCTL                 = 5064
-       SYS_SHMDT                  = 5065
-       SYS_MSGGET                 = 5066
-       SYS_MSGSND                 = 5067
-       SYS_MSGRCV                 = 5068
-       SYS_MSGCTL                 = 5069
-       SYS_FCNTL                  = 5070
-       SYS_FLOCK                  = 5071
-       SYS_FSYNC                  = 5072
-       SYS_FDATASYNC              = 5073
-       SYS_TRUNCATE               = 5074
-       SYS_FTRUNCATE              = 5075
-       SYS_GETDENTS               = 5076
-       SYS_GETCWD                 = 5077
-       SYS_CHDIR                  = 5078
-       SYS_FCHDIR                 = 5079
-       SYS_RENAME                 = 5080
-       SYS_MKDIR                  = 5081
-       SYS_RMDIR                  = 5082
-       SYS_CREAT                  = 5083
-       SYS_LINK                   = 5084
-       SYS_UNLINK                 = 5085
-       SYS_SYMLINK                = 5086
-       SYS_READLINK               = 5087
-       SYS_CHMOD                  = 5088
-       SYS_FCHMOD                 = 5089
-       SYS_CHOWN                  = 5090
-       SYS_FCHOWN                 = 5091
-       SYS_LCHOWN                 = 5092
-       SYS_UMASK                  = 5093
-       SYS_GETTIMEOFDAY           = 5094
-       SYS_GETRLIMIT              = 5095
-       SYS_GETRUSAGE              = 5096
-       SYS_SYSINFO                = 5097
-       SYS_TIMES                  = 5098
-       SYS_PTRACE                 = 5099
-       SYS_GETUID                 = 5100
-       SYS_SYSLOG                 = 5101
-       SYS_GETGID                 = 5102
-       SYS_SETUID                 = 5103
-       SYS_SETGID                 = 5104
-       SYS_GETEUID                = 5105
-       SYS_GETEGID                = 5106
-       SYS_SETPGID                = 5107
-       SYS_GETPPID                = 5108
-       SYS_GETPGRP                = 5109
-       SYS_SETSID                 = 5110
-       SYS_SETREUID               = 5111
-       SYS_SETREGID               = 5112
-       SYS_GETGROUPS              = 5113
-       SYS_SETGROUPS              = 5114
-       SYS_SETRESUID              = 5115
-       SYS_GETRESUID              = 5116
-       SYS_SETRESGID              = 5117
-       SYS_GETRESGID              = 5118
-       SYS_GETPGID                = 5119
-       SYS_SETFSUID               = 5120
-       SYS_SETFSGID               = 5121
-       SYS_GETSID                 = 5122
-       SYS_CAPGET                 = 5123
-       SYS_CAPSET                 = 5124
-       SYS_RT_SIGPENDING          = 5125
-       SYS_RT_SIGTIMEDWAIT        = 5126
-       SYS_RT_SIGQUEUEINFO        = 5127
-       SYS_RT_SIGSUSPEND          = 5128
-       SYS_SIGALTSTACK            = 5129
-       SYS_UTIME                  = 5130
-       SYS_MKNOD                  = 5131
-       SYS_PERSONALITY            = 5132
-       SYS_USTAT                  = 5133
-       SYS_STATFS                 = 5134
-       SYS_FSTATFS                = 5135
-       SYS_SYSFS                  = 5136
-       SYS_GETPRIORITY            = 5137
-       SYS_SETPRIORITY            = 5138
-       SYS_SCHED_SETPARAM         = 5139
-       SYS_SCHED_GETPARAM         = 5140
-       SYS_SCHED_SETSCHEDULER     = 5141
-       SYS_SCHED_GETSCHEDULER     = 5142
-       SYS_SCHED_GET_PRIORITY_MAX = 5143
-       SYS_SCHED_GET_PRIORITY_MIN = 5144
-       SYS_SCHED_RR_GET_INTERVAL  = 5145
-       SYS_MLOCK                  = 5146
-       SYS_MUNLOCK                = 5147
-       SYS_MLOCKALL               = 5148
-       SYS_MUNLOCKALL             = 5149
-       SYS_VHANGUP                = 5150
-       SYS_PIVOT_ROOT             = 5151
-       SYS__SYSCTL                = 5152
-       SYS_PRCTL                  = 5153
-       SYS_ADJTIMEX               = 5154
-       SYS_SETRLIMIT              = 5155
-       SYS_CHROOT                 = 5156
-       SYS_SYNC                   = 5157
-       SYS_ACCT                   = 5158
-       SYS_SETTIMEOFDAY           = 5159
-       SYS_MOUNT                  = 5160
-       SYS_UMOUNT2                = 5161
-       SYS_SWAPON                 = 5162
-       SYS_SWAPOFF                = 5163
-       SYS_REBOOT                 = 5164
-       SYS_SETHOSTNAME            = 5165
-       SYS_SETDOMAINNAME          = 5166
-       SYS_CREATE_MODULE          = 5167
-       SYS_INIT_MODULE            = 5168
-       SYS_DELETE_MODULE          = 5169
-       SYS_GET_KERNEL_SYMS        = 5170
-       SYS_QUERY_MODULE           = 5171
-       SYS_QUOTACTL               = 5172
-       SYS_NFSSERVCTL             = 5173
-       SYS_GETPMSG                = 5174
-       SYS_PUTPMSG                = 5175
-       SYS_AFS_SYSCALL            = 5176
-       SYS_RESERVED177            = 5177
-       SYS_GETTID                 = 5178
-       SYS_READAHEAD              = 5179
-       SYS_SETXATTR               = 5180
-       SYS_LSETXATTR              = 5181
-       SYS_FSETXATTR              = 5182
-       SYS_GETXATTR               = 5183
-       SYS_LGETXATTR              = 5184
-       SYS_FGETXATTR              = 5185
-       SYS_LISTXATTR              = 5186
-       SYS_LLISTXATTR             = 5187
-       SYS_FLISTXATTR             = 5188
-       SYS_REMOVEXATTR            = 5189
-       SYS_LREMOVEXATTR           = 5190
-       SYS_FREMOVEXATTR           = 5191
-       SYS_TKILL                  = 5192
-       SYS_RESERVED193            = 5193
-       SYS_FUTEX                  = 5194
-       SYS_SCHED_SETAFFINITY      = 5195
-       SYS_SCHED_GETAFFINITY      = 5196
-       SYS_CACHEFLUSH             = 5197
-       SYS_CACHECTL               = 5198
-       SYS_SYSMIPS                = 5199
-       SYS_IO_SETUP               = 5200
-       SYS_IO_DESTROY             = 5201
-       SYS_IO_GETEVENTS           = 5202
-       SYS_IO_SUBMIT              = 5203
-       SYS_IO_CANCEL              = 5204
-       SYS_EXIT_GROUP             = 5205
-       SYS_LOOKUP_DCOOKIE         = 5206
-       SYS_EPOLL_CREATE           = 5207
-       SYS_EPOLL_CTL              = 5208
-       SYS_EPOLL_WAIT             = 5209
-       SYS_REMAP_FILE_PAGES       = 5210
-       SYS_RT_SIGRETURN           = 5211
-       SYS_SET_TID_ADDRESS        = 5212
-       SYS_RESTART_SYSCALL        = 5213
-       SYS_SEMTIMEDOP             = 5214
-       SYS_FADVISE64              = 5215
-       SYS_TIMER_CREATE           = 5216
-       SYS_TIMER_SETTIME          = 5217
-       SYS_TIMER_GETTIME          = 5218
-       SYS_TIMER_GETOVERRUN       = 5219
-       SYS_TIMER_DELETE           = 5220
-       SYS_CLOCK_SETTIME          = 5221
-       SYS_CLOCK_GETTIME          = 5222
-       SYS_CLOCK_GETRES           = 5223
-       SYS_CLOCK_NANOSLEEP        = 5224
-       SYS_TGKILL                 = 5225
-       SYS_UTIMES                 = 5226
-       SYS_MBIND                  = 5227
-       SYS_GET_MEMPOLICY          = 5228
-       SYS_SET_MEMPOLICY          = 5229
-       SYS_MQ_OPEN                = 5230
-       SYS_MQ_UNLINK              = 5231
-       SYS_MQ_TIMEDSEND           = 5232
-       SYS_MQ_TIMEDRECEIVE        = 5233
-       SYS_MQ_NOTIFY              = 5234
-       SYS_MQ_GETSETATTR          = 5235
-       SYS_VSERVER                = 5236
-       SYS_WAITID                 = 5237
-       SYS_ADD_KEY                = 5239
-       SYS_REQUEST_KEY            = 5240
-       SYS_KEYCTL                 = 5241
-       SYS_SET_THREAD_AREA        = 5242
-       SYS_INOTIFY_INIT           = 5243
-       SYS_INOTIFY_ADD_WATCH      = 5244
-       SYS_INOTIFY_RM_WATCH       = 5245
-       SYS_MIGRATE_PAGES          = 5246
-       SYS_OPENAT                 = 5247
-       SYS_MKDIRAT                = 5248
-       SYS_MKNODAT                = 5249
-       SYS_FCHOWNAT               = 5250
-       SYS_FUTIMESAT              = 5251
-       SYS_NEWFSTATAT             = 5252
-       SYS_UNLINKAT               = 5253
-       SYS_RENAMEAT               = 5254
-       SYS_LINKAT                 = 5255
-       SYS_SYMLINKAT              = 5256
-       SYS_READLINKAT             = 5257
-       SYS_FCHMODAT               = 5258
-       SYS_FACCESSAT              = 5259
-       SYS_PSELECT6               = 5260
-       SYS_PPOLL                  = 5261
-       SYS_UNSHARE                = 5262
-       SYS_SPLICE                 = 5263
-       SYS_SYNC_FILE_RANGE        = 5264
-       SYS_TEE                    = 5265
-       SYS_VMSPLICE               = 5266
-       SYS_MOVE_PAGES             = 5267
-       SYS_SET_ROBUST_LIST        = 5268
-       SYS_GET_ROBUST_LIST        = 5269
-       SYS_KEXEC_LOAD             = 5270
-       SYS_GETCPU                 = 5271
-       SYS_EPOLL_PWAIT            = 5272
-       SYS_IOPRIO_SET             = 5273
-       SYS_IOPRIO_GET             = 5274
-       SYS_UTIMENSAT              = 5275
-       SYS_SIGNALFD               = 5276
-       SYS_TIMERFD                = 5277
-       SYS_EVENTFD                = 5278
-       SYS_FALLOCATE              = 5279
-       SYS_TIMERFD_CREATE         = 5280
-       SYS_TIMERFD_GETTIME        = 5281
-       SYS_TIMERFD_SETTIME        = 5282
-       SYS_SIGNALFD4              = 5283
-       SYS_EVENTFD2               = 5284
-       SYS_EPOLL_CREATE1          = 5285
-       SYS_DUP3                   = 5286
-       SYS_PIPE2                  = 5287
-       SYS_INOTIFY_INIT1          = 5288
-       SYS_PREADV                 = 5289
-       SYS_PWRITEV                = 5290
-       SYS_RT_TGSIGQUEUEINFO      = 5291
-       SYS_PERF_EVENT_OPEN        = 5292
-       SYS_ACCEPT4                = 5293
-       SYS_RECVMMSG               = 5294
-       SYS_FANOTIFY_INIT          = 5295
-       SYS_FANOTIFY_MARK          = 5296
-       SYS_PRLIMIT64              = 5297
-       SYS_NAME_TO_HANDLE_AT      = 5298
-       SYS_OPEN_BY_HANDLE_AT      = 5299
-       SYS_CLOCK_ADJTIME          = 5300
-       SYS_SYNCFS                 = 5301
-       SYS_SENDMMSG               = 5302
-       SYS_SETNS                  = 5303
-       SYS_PROCESS_VM_READV       = 5304
-       SYS_PROCESS_VM_WRITEV      = 5305
-       SYS_KCMP                   = 5306
-       SYS_FINIT_MODULE           = 5307
-       SYS_GETDENTS64             = 5308
-       SYS_SCHED_SETATTR          = 5309
-       SYS_SCHED_GETATTR          = 5310
-       SYS_RENAMEAT2              = 5311
-       SYS_SECCOMP                = 5312
-       SYS_GETRANDOM              = 5313
-       SYS_MEMFD_CREATE           = 5314
-       SYS_BPF                    = 5315
-       SYS_EXECVEAT               = 5316
-       SYS_USERFAULTFD            = 5317
-       SYS_MEMBARRIER             = 5318
-       SYS_MLOCK2                 = 5319
-       SYS_COPY_FILE_RANGE        = 5320
-       SYS_PREADV2                = 5321
-       SYS_PWRITEV2               = 5322
-       SYS_PKEY_MPROTECT          = 5323
-       SYS_PKEY_ALLOC             = 5324
-       SYS_PKEY_FREE              = 5325
-       SYS_STATX                  = 5326
-       SYS_RSEQ                   = 5327
-       SYS_IO_PGETEVENTS          = 5328
-       SYS_PIDFD_SEND_SIGNAL      = 5424
-       SYS_IO_URING_SETUP         = 5425
-       SYS_IO_URING_ENTER         = 5426
-       SYS_IO_URING_REGISTER      = 5427
-       SYS_OPEN_TREE              = 5428
-       SYS_MOVE_MOUNT             = 5429
-       SYS_FSOPEN                 = 5430
-       SYS_FSCONFIG               = 5431
-       SYS_FSMOUNT                = 5432
-       SYS_FSPICK                 = 5433
-       SYS_PIDFD_OPEN             = 5434
-       SYS_CLONE3                 = 5435
-       SYS_CLOSE_RANGE            = 5436
-       SYS_OPENAT2                = 5437
-       SYS_PIDFD_GETFD            = 5438
-       SYS_FACCESSAT2             = 5439
-       SYS_PROCESS_MADVISE        = 5440
-       SYS_EPOLL_PWAIT2           = 5441
-       SYS_MOUNT_SETATTR          = 5442
+       SYS_READ                    = 5000
+       SYS_WRITE                   = 5001
+       SYS_OPEN                    = 5002
+       SYS_CLOSE                   = 5003
+       SYS_STAT                    = 5004
+       SYS_FSTAT                   = 5005
+       SYS_LSTAT                   = 5006
+       SYS_POLL                    = 5007
+       SYS_LSEEK                   = 5008
+       SYS_MMAP                    = 5009
+       SYS_MPROTECT                = 5010
+       SYS_MUNMAP                  = 5011
+       SYS_BRK                     = 5012
+       SYS_RT_SIGACTION            = 5013
+       SYS_RT_SIGPROCMASK          = 5014
+       SYS_IOCTL                   = 5015
+       SYS_PREAD64                 = 5016
+       SYS_PWRITE64                = 5017
+       SYS_READV                   = 5018
+       SYS_WRITEV                  = 5019
+       SYS_ACCESS                  = 5020
+       SYS_PIPE                    = 5021
+       SYS__NEWSELECT              = 5022
+       SYS_SCHED_YIELD             = 5023
+       SYS_MREMAP                  = 5024
+       SYS_MSYNC                   = 5025
+       SYS_MINCORE                 = 5026
+       SYS_MADVISE                 = 5027
+       SYS_SHMGET                  = 5028
+       SYS_SHMAT                   = 5029
+       SYS_SHMCTL                  = 5030
+       SYS_DUP                     = 5031
+       SYS_DUP2                    = 5032
+       SYS_PAUSE                   = 5033
+       SYS_NANOSLEEP               = 5034
+       SYS_GETITIMER               = 5035
+       SYS_SETITIMER               = 5036
+       SYS_ALARM                   = 5037
+       SYS_GETPID                  = 5038
+       SYS_SENDFILE                = 5039
+       SYS_SOCKET                  = 5040
+       SYS_CONNECT                 = 5041
+       SYS_ACCEPT                  = 5042
+       SYS_SENDTO                  = 5043
+       SYS_RECVFROM                = 5044
+       SYS_SENDMSG                 = 5045
+       SYS_RECVMSG                 = 5046
+       SYS_SHUTDOWN                = 5047
+       SYS_BIND                    = 5048
+       SYS_LISTEN                  = 5049
+       SYS_GETSOCKNAME             = 5050
+       SYS_GETPEERNAME             = 5051
+       SYS_SOCKETPAIR              = 5052
+       SYS_SETSOCKOPT              = 5053
+       SYS_GETSOCKOPT              = 5054
+       SYS_CLONE                   = 5055
+       SYS_FORK                    = 5056
+       SYS_EXECVE                  = 5057
+       SYS_EXIT                    = 5058
+       SYS_WAIT4                   = 5059
+       SYS_KILL                    = 5060
+       SYS_UNAME                   = 5061
+       SYS_SEMGET                  = 5062
+       SYS_SEMOP                   = 5063
+       SYS_SEMCTL                  = 5064
+       SYS_SHMDT                   = 5065
+       SYS_MSGGET                  = 5066
+       SYS_MSGSND                  = 5067
+       SYS_MSGRCV                  = 5068
+       SYS_MSGCTL                  = 5069
+       SYS_FCNTL                   = 5070
+       SYS_FLOCK                   = 5071
+       SYS_FSYNC                   = 5072
+       SYS_FDATASYNC               = 5073
+       SYS_TRUNCATE                = 5074
+       SYS_FTRUNCATE               = 5075
+       SYS_GETDENTS                = 5076
+       SYS_GETCWD                  = 5077
+       SYS_CHDIR                   = 5078
+       SYS_FCHDIR                  = 5079
+       SYS_RENAME                  = 5080
+       SYS_MKDIR                   = 5081
+       SYS_RMDIR                   = 5082
+       SYS_CREAT                   = 5083
+       SYS_LINK                    = 5084
+       SYS_UNLINK                  = 5085
+       SYS_SYMLINK                 = 5086
+       SYS_READLINK                = 5087
+       SYS_CHMOD                   = 5088
+       SYS_FCHMOD                  = 5089
+       SYS_CHOWN                   = 5090
+       SYS_FCHOWN                  = 5091
+       SYS_LCHOWN                  = 5092
+       SYS_UMASK                   = 5093
+       SYS_GETTIMEOFDAY            = 5094
+       SYS_GETRLIMIT               = 5095
+       SYS_GETRUSAGE               = 5096
+       SYS_SYSINFO                 = 5097
+       SYS_TIMES                   = 5098
+       SYS_PTRACE                  = 5099
+       SYS_GETUID                  = 5100
+       SYS_SYSLOG                  = 5101
+       SYS_GETGID                  = 5102
+       SYS_SETUID                  = 5103
+       SYS_SETGID                  = 5104
+       SYS_GETEUID                 = 5105
+       SYS_GETEGID                 = 5106
+       SYS_SETPGID                 = 5107
+       SYS_GETPPID                 = 5108
+       SYS_GETPGRP                 = 5109
+       SYS_SETSID                  = 5110
+       SYS_SETREUID                = 5111
+       SYS_SETREGID                = 5112
+       SYS_GETGROUPS               = 5113
+       SYS_SETGROUPS               = 5114
+       SYS_SETRESUID               = 5115
+       SYS_GETRESUID               = 5116
+       SYS_SETRESGID               = 5117
+       SYS_GETRESGID               = 5118
+       SYS_GETPGID                 = 5119
+       SYS_SETFSUID                = 5120
+       SYS_SETFSGID                = 5121
+       SYS_GETSID                  = 5122
+       SYS_CAPGET                  = 5123
+       SYS_CAPSET                  = 5124
+       SYS_RT_SIGPENDING           = 5125
+       SYS_RT_SIGTIMEDWAIT         = 5126
+       SYS_RT_SIGQUEUEINFO         = 5127
+       SYS_RT_SIGSUSPEND           = 5128
+       SYS_SIGALTSTACK             = 5129
+       SYS_UTIME                   = 5130
+       SYS_MKNOD                   = 5131
+       SYS_PERSONALITY             = 5132
+       SYS_USTAT                   = 5133
+       SYS_STATFS                  = 5134
+       SYS_FSTATFS                 = 5135
+       SYS_SYSFS                   = 5136
+       SYS_GETPRIORITY             = 5137
+       SYS_SETPRIORITY             = 5138
+       SYS_SCHED_SETPARAM          = 5139
+       SYS_SCHED_GETPARAM          = 5140
+       SYS_SCHED_SETSCHEDULER      = 5141
+       SYS_SCHED_GETSCHEDULER      = 5142
+       SYS_SCHED_GET_PRIORITY_MAX  = 5143
+       SYS_SCHED_GET_PRIORITY_MIN  = 5144
+       SYS_SCHED_RR_GET_INTERVAL   = 5145
+       SYS_MLOCK                   = 5146
+       SYS_MUNLOCK                 = 5147
+       SYS_MLOCKALL                = 5148
+       SYS_MUNLOCKALL              = 5149
+       SYS_VHANGUP                 = 5150
+       SYS_PIVOT_ROOT              = 5151
+       SYS__SYSCTL                 = 5152
+       SYS_PRCTL                   = 5153
+       SYS_ADJTIMEX                = 5154
+       SYS_SETRLIMIT               = 5155
+       SYS_CHROOT                  = 5156
+       SYS_SYNC                    = 5157
+       SYS_ACCT                    = 5158
+       SYS_SETTIMEOFDAY            = 5159
+       SYS_MOUNT                   = 5160
+       SYS_UMOUNT2                 = 5161
+       SYS_SWAPON                  = 5162
+       SYS_SWAPOFF                 = 5163
+       SYS_REBOOT                  = 5164
+       SYS_SETHOSTNAME             = 5165
+       SYS_SETDOMAINNAME           = 5166
+       SYS_CREATE_MODULE           = 5167
+       SYS_INIT_MODULE             = 5168
+       SYS_DELETE_MODULE           = 5169
+       SYS_GET_KERNEL_SYMS         = 5170
+       SYS_QUERY_MODULE            = 5171
+       SYS_QUOTACTL                = 5172
+       SYS_NFSSERVCTL              = 5173
+       SYS_GETPMSG                 = 5174
+       SYS_PUTPMSG                 = 5175
+       SYS_AFS_SYSCALL             = 5176
+       SYS_RESERVED177             = 5177
+       SYS_GETTID                  = 5178
+       SYS_READAHEAD               = 5179
+       SYS_SETXATTR                = 5180
+       SYS_LSETXATTR               = 5181
+       SYS_FSETXATTR               = 5182
+       SYS_GETXATTR                = 5183
+       SYS_LGETXATTR               = 5184
+       SYS_FGETXATTR               = 5185
+       SYS_LISTXATTR               = 5186
+       SYS_LLISTXATTR              = 5187
+       SYS_FLISTXATTR              = 5188
+       SYS_REMOVEXATTR             = 5189
+       SYS_LREMOVEXATTR            = 5190
+       SYS_FREMOVEXATTR            = 5191
+       SYS_TKILL                   = 5192
+       SYS_RESERVED193             = 5193
+       SYS_FUTEX                   = 5194
+       SYS_SCHED_SETAFFINITY       = 5195
+       SYS_SCHED_GETAFFINITY       = 5196
+       SYS_CACHEFLUSH              = 5197
+       SYS_CACHECTL                = 5198
+       SYS_SYSMIPS                 = 5199
+       SYS_IO_SETUP                = 5200
+       SYS_IO_DESTROY              = 5201
+       SYS_IO_GETEVENTS            = 5202
+       SYS_IO_SUBMIT               = 5203
+       SYS_IO_CANCEL               = 5204
+       SYS_EXIT_GROUP              = 5205
+       SYS_LOOKUP_DCOOKIE          = 5206
+       SYS_EPOLL_CREATE            = 5207
+       SYS_EPOLL_CTL               = 5208
+       SYS_EPOLL_WAIT              = 5209
+       SYS_REMAP_FILE_PAGES        = 5210
+       SYS_RT_SIGRETURN            = 5211
+       SYS_SET_TID_ADDRESS         = 5212
+       SYS_RESTART_SYSCALL         = 5213
+       SYS_SEMTIMEDOP              = 5214
+       SYS_FADVISE64               = 5215
+       SYS_TIMER_CREATE            = 5216
+       SYS_TIMER_SETTIME           = 5217
+       SYS_TIMER_GETTIME           = 5218
+       SYS_TIMER_GETOVERRUN        = 5219
+       SYS_TIMER_DELETE            = 5220
+       SYS_CLOCK_SETTIME           = 5221
+       SYS_CLOCK_GETTIME           = 5222
+       SYS_CLOCK_GETRES            = 5223
+       SYS_CLOCK_NANOSLEEP         = 5224
+       SYS_TGKILL                  = 5225
+       SYS_UTIMES                  = 5226
+       SYS_MBIND                   = 5227
+       SYS_GET_MEMPOLICY           = 5228
+       SYS_SET_MEMPOLICY           = 5229
+       SYS_MQ_OPEN                 = 5230
+       SYS_MQ_UNLINK               = 5231
+       SYS_MQ_TIMEDSEND            = 5232
+       SYS_MQ_TIMEDRECEIVE         = 5233
+       SYS_MQ_NOTIFY               = 5234
+       SYS_MQ_GETSETATTR           = 5235
+       SYS_VSERVER                 = 5236
+       SYS_WAITID                  = 5237
+       SYS_ADD_KEY                 = 5239
+       SYS_REQUEST_KEY             = 5240
+       SYS_KEYCTL                  = 5241
+       SYS_SET_THREAD_AREA         = 5242
+       SYS_INOTIFY_INIT            = 5243
+       SYS_INOTIFY_ADD_WATCH       = 5244
+       SYS_INOTIFY_RM_WATCH        = 5245
+       SYS_MIGRATE_PAGES           = 5246
+       SYS_OPENAT                  = 5247
+       SYS_MKDIRAT                 = 5248
+       SYS_MKNODAT                 = 5249
+       SYS_FCHOWNAT                = 5250
+       SYS_FUTIMESAT               = 5251
+       SYS_NEWFSTATAT              = 5252
+       SYS_UNLINKAT                = 5253
+       SYS_RENAMEAT                = 5254
+       SYS_LINKAT                  = 5255
+       SYS_SYMLINKAT               = 5256
+       SYS_READLINKAT              = 5257
+       SYS_FCHMODAT                = 5258
+       SYS_FACCESSAT               = 5259
+       SYS_PSELECT6                = 5260
+       SYS_PPOLL                   = 5261
+       SYS_UNSHARE                 = 5262
+       SYS_SPLICE                  = 5263
+       SYS_SYNC_FILE_RANGE         = 5264
+       SYS_TEE                     = 5265
+       SYS_VMSPLICE                = 5266
+       SYS_MOVE_PAGES              = 5267
+       SYS_SET_ROBUST_LIST         = 5268
+       SYS_GET_ROBUST_LIST         = 5269
+       SYS_KEXEC_LOAD              = 5270
+       SYS_GETCPU                  = 5271
+       SYS_EPOLL_PWAIT             = 5272
+       SYS_IOPRIO_SET              = 5273
+       SYS_IOPRIO_GET              = 5274
+       SYS_UTIMENSAT               = 5275
+       SYS_SIGNALFD                = 5276
+       SYS_TIMERFD                 = 5277
+       SYS_EVENTFD                 = 5278
+       SYS_FALLOCATE               = 5279
+       SYS_TIMERFD_CREATE          = 5280
+       SYS_TIMERFD_GETTIME         = 5281
+       SYS_TIMERFD_SETTIME         = 5282
+       SYS_SIGNALFD4               = 5283
+       SYS_EVENTFD2                = 5284
+       SYS_EPOLL_CREATE1           = 5285
+       SYS_DUP3                    = 5286
+       SYS_PIPE2                   = 5287
+       SYS_INOTIFY_INIT1           = 5288
+       SYS_PREADV                  = 5289
+       SYS_PWRITEV                 = 5290
+       SYS_RT_TGSIGQUEUEINFO       = 5291
+       SYS_PERF_EVENT_OPEN         = 5292
+       SYS_ACCEPT4                 = 5293
+       SYS_RECVMMSG                = 5294
+       SYS_FANOTIFY_INIT           = 5295
+       SYS_FANOTIFY_MARK           = 5296
+       SYS_PRLIMIT64               = 5297
+       SYS_NAME_TO_HANDLE_AT       = 5298
+       SYS_OPEN_BY_HANDLE_AT       = 5299
+       SYS_CLOCK_ADJTIME           = 5300
+       SYS_SYNCFS                  = 5301
+       SYS_SENDMMSG                = 5302
+       SYS_SETNS                   = 5303
+       SYS_PROCESS_VM_READV        = 5304
+       SYS_PROCESS_VM_WRITEV       = 5305
+       SYS_KCMP                    = 5306
+       SYS_FINIT_MODULE            = 5307
+       SYS_GETDENTS64              = 5308
+       SYS_SCHED_SETATTR           = 5309
+       SYS_SCHED_GETATTR           = 5310
+       SYS_RENAMEAT2               = 5311
+       SYS_SECCOMP                 = 5312
+       SYS_GETRANDOM               = 5313
+       SYS_MEMFD_CREATE            = 5314
+       SYS_BPF                     = 5315
+       SYS_EXECVEAT                = 5316
+       SYS_USERFAULTFD             = 5317
+       SYS_MEMBARRIER              = 5318
+       SYS_MLOCK2                  = 5319
+       SYS_COPY_FILE_RANGE         = 5320
+       SYS_PREADV2                 = 5321
+       SYS_PWRITEV2                = 5322
+       SYS_PKEY_MPROTECT           = 5323
+       SYS_PKEY_ALLOC              = 5324
+       SYS_PKEY_FREE               = 5325
+       SYS_STATX                   = 5326
+       SYS_RSEQ                    = 5327
+       SYS_IO_PGETEVENTS           = 5328
+       SYS_PIDFD_SEND_SIGNAL       = 5424
+       SYS_IO_URING_SETUP          = 5425
+       SYS_IO_URING_ENTER          = 5426
+       SYS_IO_URING_REGISTER       = 5427
+       SYS_OPEN_TREE               = 5428
+       SYS_MOVE_MOUNT              = 5429
+       SYS_FSOPEN                  = 5430
+       SYS_FSCONFIG                = 5431
+       SYS_FSMOUNT                 = 5432
+       SYS_FSPICK                  = 5433
+       SYS_PIDFD_OPEN              = 5434
+       SYS_CLONE3                  = 5435
+       SYS_CLOSE_RANGE             = 5436
+       SYS_OPENAT2                 = 5437
+       SYS_PIDFD_GETFD             = 5438
+       SYS_FACCESSAT2              = 5439
+       SYS_PROCESS_MADVISE         = 5440
+       SYS_EPOLL_PWAIT2            = 5441
+       SYS_MOUNT_SETATTR           = 5442
+       SYS_QUOTACTL_FD             = 5443
+       SYS_LANDLOCK_CREATE_RULESET = 5444
+       SYS_LANDLOCK_ADD_RULE       = 5445
+       SYS_LANDLOCK_RESTRICT_SELF  = 5446
 )
index 80e6696b39dbedf1960d311b56789e45e7ee67ef..570a857a56ead7c6953ebfa01556053abecce4dc 100644 (file)
@@ -424,4 +424,8 @@ const (
        SYS_PROCESS_MADVISE              = 4440
        SYS_EPOLL_PWAIT2                 = 4441
        SYS_MOUNT_SETATTR                = 4442
+       SYS_QUOTACTL_FD                  = 4443
+       SYS_LANDLOCK_CREATE_RULESET      = 4444
+       SYS_LANDLOCK_ADD_RULE            = 4445
+       SYS_LANDLOCK_RESTRICT_SELF       = 4446
 )
index b9d697ffb1c019575b5471c80d4b122f6cfafd9a..638498d62e228996a973d433669a3fa62a931e93 100644 (file)
@@ -431,4 +431,8 @@ const (
        SYS_PROCESS_MADVISE              = 440
        SYS_EPOLL_PWAIT2                 = 441
        SYS_MOUNT_SETATTR                = 442
+       SYS_QUOTACTL_FD                  = 443
+       SYS_LANDLOCK_CREATE_RULESET      = 444
+       SYS_LANDLOCK_ADD_RULE            = 445
+       SYS_LANDLOCK_RESTRICT_SELF       = 446
 )
index 08edc54d35de252cea6e9d3e83f8ddb94ae38a8d..702beebfefe23b3d1ac92566c5679a6f55677e10 100644 (file)
 package unix
 
 const (
-       SYS_RESTART_SYSCALL        = 0
-       SYS_EXIT                   = 1
-       SYS_FORK                   = 2
-       SYS_READ                   = 3
-       SYS_WRITE                  = 4
-       SYS_OPEN                   = 5
-       SYS_CLOSE                  = 6
-       SYS_WAITPID                = 7
-       SYS_CREAT                  = 8
-       SYS_LINK                   = 9
-       SYS_UNLINK                 = 10
-       SYS_EXECVE                 = 11
-       SYS_CHDIR                  = 12
-       SYS_TIME                   = 13
-       SYS_MKNOD                  = 14
-       SYS_CHMOD                  = 15
-       SYS_LCHOWN                 = 16
-       SYS_BREAK                  = 17
-       SYS_OLDSTAT                = 18
-       SYS_LSEEK                  = 19
-       SYS_GETPID                 = 20
-       SYS_MOUNT                  = 21
-       SYS_UMOUNT                 = 22
-       SYS_SETUID                 = 23
-       SYS_GETUID                 = 24
-       SYS_STIME                  = 25
-       SYS_PTRACE                 = 26
-       SYS_ALARM                  = 27
-       SYS_OLDFSTAT               = 28
-       SYS_PAUSE                  = 29
-       SYS_UTIME                  = 30
-       SYS_STTY                   = 31
-       SYS_GTTY                   = 32
-       SYS_ACCESS                 = 33
-       SYS_NICE                   = 34
-       SYS_FTIME                  = 35
-       SYS_SYNC                   = 36
-       SYS_KILL                   = 37
-       SYS_RENAME                 = 38
-       SYS_MKDIR                  = 39
-       SYS_RMDIR                  = 40
-       SYS_DUP                    = 41
-       SYS_PIPE                   = 42
-       SYS_TIMES                  = 43
-       SYS_PROF                   = 44
-       SYS_BRK                    = 45
-       SYS_SETGID                 = 46
-       SYS_GETGID                 = 47
-       SYS_SIGNAL                 = 48
-       SYS_GETEUID                = 49
-       SYS_GETEGID                = 50
-       SYS_ACCT                   = 51
-       SYS_UMOUNT2                = 52
-       SYS_LOCK                   = 53
-       SYS_IOCTL                  = 54
-       SYS_FCNTL                  = 55
-       SYS_MPX                    = 56
-       SYS_SETPGID                = 57
-       SYS_ULIMIT                 = 58
-       SYS_OLDOLDUNAME            = 59
-       SYS_UMASK                  = 60
-       SYS_CHROOT                 = 61
-       SYS_USTAT                  = 62
-       SYS_DUP2                   = 63
-       SYS_GETPPID                = 64
-       SYS_GETPGRP                = 65
-       SYS_SETSID                 = 66
-       SYS_SIGACTION              = 67
-       SYS_SGETMASK               = 68
-       SYS_SSETMASK               = 69
-       SYS_SETREUID               = 70
-       SYS_SETREGID               = 71
-       SYS_SIGSUSPEND             = 72
-       SYS_SIGPENDING             = 73
-       SYS_SETHOSTNAME            = 74
-       SYS_SETRLIMIT              = 75
-       SYS_GETRLIMIT              = 76
-       SYS_GETRUSAGE              = 77
-       SYS_GETTIMEOFDAY           = 78
-       SYS_SETTIMEOFDAY           = 79
-       SYS_GETGROUPS              = 80
-       SYS_SETGROUPS              = 81
-       SYS_SELECT                 = 82
-       SYS_SYMLINK                = 83
-       SYS_OLDLSTAT               = 84
-       SYS_READLINK               = 85
-       SYS_USELIB                 = 86
-       SYS_SWAPON                 = 87
-       SYS_REBOOT                 = 88
-       SYS_READDIR                = 89
-       SYS_MMAP                   = 90
-       SYS_MUNMAP                 = 91
-       SYS_TRUNCATE               = 92
-       SYS_FTRUNCATE              = 93
-       SYS_FCHMOD                 = 94
-       SYS_FCHOWN                 = 95
-       SYS_GETPRIORITY            = 96
-       SYS_SETPRIORITY            = 97
-       SYS_PROFIL                 = 98
-       SYS_STATFS                 = 99
-       SYS_FSTATFS                = 100
-       SYS_IOPERM                 = 101
-       SYS_SOCKETCALL             = 102
-       SYS_SYSLOG                 = 103
-       SYS_SETITIMER              = 104
-       SYS_GETITIMER              = 105
-       SYS_STAT                   = 106
-       SYS_LSTAT                  = 107
-       SYS_FSTAT                  = 108
-       SYS_OLDUNAME               = 109
-       SYS_IOPL                   = 110
-       SYS_VHANGUP                = 111
-       SYS_IDLE                   = 112
-       SYS_VM86                   = 113
-       SYS_WAIT4                  = 114
-       SYS_SWAPOFF                = 115
-       SYS_SYSINFO                = 116
-       SYS_IPC                    = 117
-       SYS_FSYNC                  = 118
-       SYS_SIGRETURN              = 119
-       SYS_CLONE                  = 120
-       SYS_SETDOMAINNAME          = 121
-       SYS_UNAME                  = 122
-       SYS_MODIFY_LDT             = 123
-       SYS_ADJTIMEX               = 124
-       SYS_MPROTECT               = 125
-       SYS_SIGPROCMASK            = 126
-       SYS_CREATE_MODULE          = 127
-       SYS_INIT_MODULE            = 128
-       SYS_DELETE_MODULE          = 129
-       SYS_GET_KERNEL_SYMS        = 130
-       SYS_QUOTACTL               = 131
-       SYS_GETPGID                = 132
-       SYS_FCHDIR                 = 133
-       SYS_BDFLUSH                = 134
-       SYS_SYSFS                  = 135
-       SYS_PERSONALITY            = 136
-       SYS_AFS_SYSCALL            = 137
-       SYS_SETFSUID               = 138
-       SYS_SETFSGID               = 139
-       SYS__LLSEEK                = 140
-       SYS_GETDENTS               = 141
-       SYS__NEWSELECT             = 142
-       SYS_FLOCK                  = 143
-       SYS_MSYNC                  = 144
-       SYS_READV                  = 145
-       SYS_WRITEV                 = 146
-       SYS_GETSID                 = 147
-       SYS_FDATASYNC              = 148
-       SYS__SYSCTL                = 149
-       SYS_MLOCK                  = 150
-       SYS_MUNLOCK                = 151
-       SYS_MLOCKALL               = 152
-       SYS_MUNLOCKALL             = 153
-       SYS_SCHED_SETPARAM         = 154
-       SYS_SCHED_GETPARAM         = 155
-       SYS_SCHED_SETSCHEDULER     = 156
-       SYS_SCHED_GETSCHEDULER     = 157
-       SYS_SCHED_YIELD            = 158
-       SYS_SCHED_GET_PRIORITY_MAX = 159
-       SYS_SCHED_GET_PRIORITY_MIN = 160
-       SYS_SCHED_RR_GET_INTERVAL  = 161
-       SYS_NANOSLEEP              = 162
-       SYS_MREMAP                 = 163
-       SYS_SETRESUID              = 164
-       SYS_GETRESUID              = 165
-       SYS_QUERY_MODULE           = 166
-       SYS_POLL                   = 167
-       SYS_NFSSERVCTL             = 168
-       SYS_SETRESGID              = 169
-       SYS_GETRESGID              = 170
-       SYS_PRCTL                  = 171
-       SYS_RT_SIGRETURN           = 172
-       SYS_RT_SIGACTION           = 173
-       SYS_RT_SIGPROCMASK         = 174
-       SYS_RT_SIGPENDING          = 175
-       SYS_RT_SIGTIMEDWAIT        = 176
-       SYS_RT_SIGQUEUEINFO        = 177
-       SYS_RT_SIGSUSPEND          = 178
-       SYS_PREAD64                = 179
-       SYS_PWRITE64               = 180
-       SYS_CHOWN                  = 181
-       SYS_GETCWD                 = 182
-       SYS_CAPGET                 = 183
-       SYS_CAPSET                 = 184
-       SYS_SIGALTSTACK            = 185
-       SYS_SENDFILE               = 186
-       SYS_GETPMSG                = 187
-       SYS_PUTPMSG                = 188
-       SYS_VFORK                  = 189
-       SYS_UGETRLIMIT             = 190
-       SYS_READAHEAD              = 191
-       SYS_PCICONFIG_READ         = 198
-       SYS_PCICONFIG_WRITE        = 199
-       SYS_PCICONFIG_IOBASE       = 200
-       SYS_MULTIPLEXER            = 201
-       SYS_GETDENTS64             = 202
-       SYS_PIVOT_ROOT             = 203
-       SYS_MADVISE                = 205
-       SYS_MINCORE                = 206
-       SYS_GETTID                 = 207
-       SYS_TKILL                  = 208
-       SYS_SETXATTR               = 209
-       SYS_LSETXATTR              = 210
-       SYS_FSETXATTR              = 211
-       SYS_GETXATTR               = 212
-       SYS_LGETXATTR              = 213
-       SYS_FGETXATTR              = 214
-       SYS_LISTXATTR              = 215
-       SYS_LLISTXATTR             = 216
-       SYS_FLISTXATTR             = 217
-       SYS_REMOVEXATTR            = 218
-       SYS_LREMOVEXATTR           = 219
-       SYS_FREMOVEXATTR           = 220
-       SYS_FUTEX                  = 221
-       SYS_SCHED_SETAFFINITY      = 222
-       SYS_SCHED_GETAFFINITY      = 223
-       SYS_TUXCALL                = 225
-       SYS_IO_SETUP               = 227
-       SYS_IO_DESTROY             = 228
-       SYS_IO_GETEVENTS           = 229
-       SYS_IO_SUBMIT              = 230
-       SYS_IO_CANCEL              = 231
-       SYS_SET_TID_ADDRESS        = 232
-       SYS_FADVISE64              = 233
-       SYS_EXIT_GROUP             = 234
-       SYS_LOOKUP_DCOOKIE         = 235
-       SYS_EPOLL_CREATE           = 236
-       SYS_EPOLL_CTL              = 237
-       SYS_EPOLL_WAIT             = 238
-       SYS_REMAP_FILE_PAGES       = 239
-       SYS_TIMER_CREATE           = 240
-       SYS_TIMER_SETTIME          = 241
-       SYS_TIMER_GETTIME          = 242
-       SYS_TIMER_GETOVERRUN       = 243
-       SYS_TIMER_DELETE           = 244
-       SYS_CLOCK_SETTIME          = 245
-       SYS_CLOCK_GETTIME          = 246
-       SYS_CLOCK_GETRES           = 247
-       SYS_CLOCK_NANOSLEEP        = 248
-       SYS_SWAPCONTEXT            = 249
-       SYS_TGKILL                 = 250
-       SYS_UTIMES                 = 251
-       SYS_STATFS64               = 252
-       SYS_FSTATFS64              = 253
-       SYS_RTAS                   = 255
-       SYS_SYS_DEBUG_SETCONTEXT   = 256
-       SYS_MIGRATE_PAGES          = 258
-       SYS_MBIND                  = 259
-       SYS_GET_MEMPOLICY          = 260
-       SYS_SET_MEMPOLICY          = 261
-       SYS_MQ_OPEN                = 262
-       SYS_MQ_UNLINK              = 263
-       SYS_MQ_TIMEDSEND           = 264
-       SYS_MQ_TIMEDRECEIVE        = 265
-       SYS_MQ_NOTIFY              = 266
-       SYS_MQ_GETSETATTR          = 267
-       SYS_KEXEC_LOAD             = 268
-       SYS_ADD_KEY                = 269
-       SYS_REQUEST_KEY            = 270
-       SYS_KEYCTL                 = 271
-       SYS_WAITID                 = 272
-       SYS_IOPRIO_SET             = 273
-       SYS_IOPRIO_GET             = 274
-       SYS_INOTIFY_INIT           = 275
-       SYS_INOTIFY_ADD_WATCH      = 276
-       SYS_INOTIFY_RM_WATCH       = 277
-       SYS_SPU_RUN                = 278
-       SYS_SPU_CREATE             = 279
-       SYS_PSELECT6               = 280
-       SYS_PPOLL                  = 281
-       SYS_UNSHARE                = 282
-       SYS_SPLICE                 = 283
-       SYS_TEE                    = 284
-       SYS_VMSPLICE               = 285
-       SYS_OPENAT                 = 286
-       SYS_MKDIRAT                = 287
-       SYS_MKNODAT                = 288
-       SYS_FCHOWNAT               = 289
-       SYS_FUTIMESAT              = 290
-       SYS_NEWFSTATAT             = 291
-       SYS_UNLINKAT               = 292
-       SYS_RENAMEAT               = 293
-       SYS_LINKAT                 = 294
-       SYS_SYMLINKAT              = 295
-       SYS_READLINKAT             = 296
-       SYS_FCHMODAT               = 297
-       SYS_FACCESSAT              = 298
-       SYS_GET_ROBUST_LIST        = 299
-       SYS_SET_ROBUST_LIST        = 300
-       SYS_MOVE_PAGES             = 301
-       SYS_GETCPU                 = 302
-       SYS_EPOLL_PWAIT            = 303
-       SYS_UTIMENSAT              = 304
-       SYS_SIGNALFD               = 305
-       SYS_TIMERFD_CREATE         = 306
-       SYS_EVENTFD                = 307
-       SYS_SYNC_FILE_RANGE2       = 308
-       SYS_FALLOCATE              = 309
-       SYS_SUBPAGE_PROT           = 310
-       SYS_TIMERFD_SETTIME        = 311
-       SYS_TIMERFD_GETTIME        = 312
-       SYS_SIGNALFD4              = 313
-       SYS_EVENTFD2               = 314
-       SYS_EPOLL_CREATE1          = 315
-       SYS_DUP3                   = 316
-       SYS_PIPE2                  = 317
-       SYS_INOTIFY_INIT1          = 318
-       SYS_PERF_EVENT_OPEN        = 319
-       SYS_PREADV                 = 320
-       SYS_PWRITEV                = 321
-       SYS_RT_TGSIGQUEUEINFO      = 322
-       SYS_FANOTIFY_INIT          = 323
-       SYS_FANOTIFY_MARK          = 324
-       SYS_PRLIMIT64              = 325
-       SYS_SOCKET                 = 326
-       SYS_BIND                   = 327
-       SYS_CONNECT                = 328
-       SYS_LISTEN                 = 329
-       SYS_ACCEPT                 = 330
-       SYS_GETSOCKNAME            = 331
-       SYS_GETPEERNAME            = 332
-       SYS_SOCKETPAIR             = 333
-       SYS_SEND                   = 334
-       SYS_SENDTO                 = 335
-       SYS_RECV                   = 336
-       SYS_RECVFROM               = 337
-       SYS_SHUTDOWN               = 338
-       SYS_SETSOCKOPT             = 339
-       SYS_GETSOCKOPT             = 340
-       SYS_SENDMSG                = 341
-       SYS_RECVMSG                = 342
-       SYS_RECVMMSG               = 343
-       SYS_ACCEPT4                = 344
-       SYS_NAME_TO_HANDLE_AT      = 345
-       SYS_OPEN_BY_HANDLE_AT      = 346
-       SYS_CLOCK_ADJTIME          = 347
-       SYS_SYNCFS                 = 348
-       SYS_SENDMMSG               = 349
-       SYS_SETNS                  = 350
-       SYS_PROCESS_VM_READV       = 351
-       SYS_PROCESS_VM_WRITEV      = 352
-       SYS_FINIT_MODULE           = 353
-       SYS_KCMP                   = 354
-       SYS_SCHED_SETATTR          = 355
-       SYS_SCHED_GETATTR          = 356
-       SYS_RENAMEAT2              = 357
-       SYS_SECCOMP                = 358
-       SYS_GETRANDOM              = 359
-       SYS_MEMFD_CREATE           = 360
-       SYS_BPF                    = 361
-       SYS_EXECVEAT               = 362
-       SYS_SWITCH_ENDIAN          = 363
-       SYS_USERFAULTFD            = 364
-       SYS_MEMBARRIER             = 365
-       SYS_MLOCK2                 = 378
-       SYS_COPY_FILE_RANGE        = 379
-       SYS_PREADV2                = 380
-       SYS_PWRITEV2               = 381
-       SYS_KEXEC_FILE_LOAD        = 382
-       SYS_STATX                  = 383
-       SYS_PKEY_ALLOC             = 384
-       SYS_PKEY_FREE              = 385
-       SYS_PKEY_MPROTECT          = 386
-       SYS_RSEQ                   = 387
-       SYS_IO_PGETEVENTS          = 388
-       SYS_SEMTIMEDOP             = 392
-       SYS_SEMGET                 = 393
-       SYS_SEMCTL                 = 394
-       SYS_SHMGET                 = 395
-       SYS_SHMCTL                 = 396
-       SYS_SHMAT                  = 397
-       SYS_SHMDT                  = 398
-       SYS_MSGGET                 = 399
-       SYS_MSGSND                 = 400
-       SYS_MSGRCV                 = 401
-       SYS_MSGCTL                 = 402
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLONE3                 = 435
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_RESTART_SYSCALL         = 0
+       SYS_EXIT                    = 1
+       SYS_FORK                    = 2
+       SYS_READ                    = 3
+       SYS_WRITE                   = 4
+       SYS_OPEN                    = 5
+       SYS_CLOSE                   = 6
+       SYS_WAITPID                 = 7
+       SYS_CREAT                   = 8
+       SYS_LINK                    = 9
+       SYS_UNLINK                  = 10
+       SYS_EXECVE                  = 11
+       SYS_CHDIR                   = 12
+       SYS_TIME                    = 13
+       SYS_MKNOD                   = 14
+       SYS_CHMOD                   = 15
+       SYS_LCHOWN                  = 16
+       SYS_BREAK                   = 17
+       SYS_OLDSTAT                 = 18
+       SYS_LSEEK                   = 19
+       SYS_GETPID                  = 20
+       SYS_MOUNT                   = 21
+       SYS_UMOUNT                  = 22
+       SYS_SETUID                  = 23
+       SYS_GETUID                  = 24
+       SYS_STIME                   = 25
+       SYS_PTRACE                  = 26
+       SYS_ALARM                   = 27
+       SYS_OLDFSTAT                = 28
+       SYS_PAUSE                   = 29
+       SYS_UTIME                   = 30
+       SYS_STTY                    = 31
+       SYS_GTTY                    = 32
+       SYS_ACCESS                  = 33
+       SYS_NICE                    = 34
+       SYS_FTIME                   = 35
+       SYS_SYNC                    = 36
+       SYS_KILL                    = 37
+       SYS_RENAME                  = 38
+       SYS_MKDIR                   = 39
+       SYS_RMDIR                   = 40
+       SYS_DUP                     = 41
+       SYS_PIPE                    = 42
+       SYS_TIMES                   = 43
+       SYS_PROF                    = 44
+       SYS_BRK                     = 45
+       SYS_SETGID                  = 46
+       SYS_GETGID                  = 47
+       SYS_SIGNAL                  = 48
+       SYS_GETEUID                 = 49
+       SYS_GETEGID                 = 50
+       SYS_ACCT                    = 51
+       SYS_UMOUNT2                 = 52
+       SYS_LOCK                    = 53
+       SYS_IOCTL                   = 54
+       SYS_FCNTL                   = 55
+       SYS_MPX                     = 56
+       SYS_SETPGID                 = 57
+       SYS_ULIMIT                  = 58
+       SYS_OLDOLDUNAME             = 59
+       SYS_UMASK                   = 60
+       SYS_CHROOT                  = 61
+       SYS_USTAT                   = 62
+       SYS_DUP2                    = 63
+       SYS_GETPPID                 = 64
+       SYS_GETPGRP                 = 65
+       SYS_SETSID                  = 66
+       SYS_SIGACTION               = 67
+       SYS_SGETMASK                = 68
+       SYS_SSETMASK                = 69
+       SYS_SETREUID                = 70
+       SYS_SETREGID                = 71
+       SYS_SIGSUSPEND              = 72
+       SYS_SIGPENDING              = 73
+       SYS_SETHOSTNAME             = 74
+       SYS_SETRLIMIT               = 75
+       SYS_GETRLIMIT               = 76
+       SYS_GETRUSAGE               = 77
+       SYS_GETTIMEOFDAY            = 78
+       SYS_SETTIMEOFDAY            = 79
+       SYS_GETGROUPS               = 80
+       SYS_SETGROUPS               = 81
+       SYS_SELECT                  = 82
+       SYS_SYMLINK                 = 83
+       SYS_OLDLSTAT                = 84
+       SYS_READLINK                = 85
+       SYS_USELIB                  = 86
+       SYS_SWAPON                  = 87
+       SYS_REBOOT                  = 88
+       SYS_READDIR                 = 89
+       SYS_MMAP                    = 90
+       SYS_MUNMAP                  = 91
+       SYS_TRUNCATE                = 92
+       SYS_FTRUNCATE               = 93
+       SYS_FCHMOD                  = 94
+       SYS_FCHOWN                  = 95
+       SYS_GETPRIORITY             = 96
+       SYS_SETPRIORITY             = 97
+       SYS_PROFIL                  = 98
+       SYS_STATFS                  = 99
+       SYS_FSTATFS                 = 100
+       SYS_IOPERM                  = 101
+       SYS_SOCKETCALL              = 102
+       SYS_SYSLOG                  = 103
+       SYS_SETITIMER               = 104
+       SYS_GETITIMER               = 105
+       SYS_STAT                    = 106
+       SYS_LSTAT                   = 107
+       SYS_FSTAT                   = 108
+       SYS_OLDUNAME                = 109
+       SYS_IOPL                    = 110
+       SYS_VHANGUP                 = 111
+       SYS_IDLE                    = 112
+       SYS_VM86                    = 113
+       SYS_WAIT4                   = 114
+       SYS_SWAPOFF                 = 115
+       SYS_SYSINFO                 = 116
+       SYS_IPC                     = 117
+       SYS_FSYNC                   = 118
+       SYS_SIGRETURN               = 119
+       SYS_CLONE                   = 120
+       SYS_SETDOMAINNAME           = 121
+       SYS_UNAME                   = 122
+       SYS_MODIFY_LDT              = 123
+       SYS_ADJTIMEX                = 124
+       SYS_MPROTECT                = 125
+       SYS_SIGPROCMASK             = 126
+       SYS_CREATE_MODULE           = 127
+       SYS_INIT_MODULE             = 128
+       SYS_DELETE_MODULE           = 129
+       SYS_GET_KERNEL_SYMS         = 130
+       SYS_QUOTACTL                = 131
+       SYS_GETPGID                 = 132
+       SYS_FCHDIR                  = 133
+       SYS_BDFLUSH                 = 134
+       SYS_SYSFS                   = 135
+       SYS_PERSONALITY             = 136
+       SYS_AFS_SYSCALL             = 137
+       SYS_SETFSUID                = 138
+       SYS_SETFSGID                = 139
+       SYS__LLSEEK                 = 140
+       SYS_GETDENTS                = 141
+       SYS__NEWSELECT              = 142
+       SYS_FLOCK                   = 143
+       SYS_MSYNC                   = 144
+       SYS_READV                   = 145
+       SYS_WRITEV                  = 146
+       SYS_GETSID                  = 147
+       SYS_FDATASYNC               = 148
+       SYS__SYSCTL                 = 149
+       SYS_MLOCK                   = 150
+       SYS_MUNLOCK                 = 151
+       SYS_MLOCKALL                = 152
+       SYS_MUNLOCKALL              = 153
+       SYS_SCHED_SETPARAM          = 154
+       SYS_SCHED_GETPARAM          = 155
+       SYS_SCHED_SETSCHEDULER      = 156
+       SYS_SCHED_GETSCHEDULER      = 157
+       SYS_SCHED_YIELD             = 158
+       SYS_SCHED_GET_PRIORITY_MAX  = 159
+       SYS_SCHED_GET_PRIORITY_MIN  = 160
+       SYS_SCHED_RR_GET_INTERVAL   = 161
+       SYS_NANOSLEEP               = 162
+       SYS_MREMAP                  = 163
+       SYS_SETRESUID               = 164
+       SYS_GETRESUID               = 165
+       SYS_QUERY_MODULE            = 166
+       SYS_POLL                    = 167
+       SYS_NFSSERVCTL              = 168
+       SYS_SETRESGID               = 169
+       SYS_GETRESGID               = 170
+       SYS_PRCTL                   = 171
+       SYS_RT_SIGRETURN            = 172
+       SYS_RT_SIGACTION            = 173
+       SYS_RT_SIGPROCMASK          = 174
+       SYS_RT_SIGPENDING           = 175
+       SYS_RT_SIGTIMEDWAIT         = 176
+       SYS_RT_SIGQUEUEINFO         = 177
+       SYS_RT_SIGSUSPEND           = 178
+       SYS_PREAD64                 = 179
+       SYS_PWRITE64                = 180
+       SYS_CHOWN                   = 181
+       SYS_GETCWD                  = 182
+       SYS_CAPGET                  = 183
+       SYS_CAPSET                  = 184
+       SYS_SIGALTSTACK             = 185
+       SYS_SENDFILE                = 186
+       SYS_GETPMSG                 = 187
+       SYS_PUTPMSG                 = 188
+       SYS_VFORK                   = 189
+       SYS_UGETRLIMIT              = 190
+       SYS_READAHEAD               = 191
+       SYS_PCICONFIG_READ          = 198
+       SYS_PCICONFIG_WRITE         = 199
+       SYS_PCICONFIG_IOBASE        = 200
+       SYS_MULTIPLEXER             = 201
+       SYS_GETDENTS64              = 202
+       SYS_PIVOT_ROOT              = 203
+       SYS_MADVISE                 = 205
+       SYS_MINCORE                 = 206
+       SYS_GETTID                  = 207
+       SYS_TKILL                   = 208
+       SYS_SETXATTR                = 209
+       SYS_LSETXATTR               = 210
+       SYS_FSETXATTR               = 211
+       SYS_GETXATTR                = 212
+       SYS_LGETXATTR               = 213
+       SYS_FGETXATTR               = 214
+       SYS_LISTXATTR               = 215
+       SYS_LLISTXATTR              = 216
+       SYS_FLISTXATTR              = 217
+       SYS_REMOVEXATTR             = 218
+       SYS_LREMOVEXATTR            = 219
+       SYS_FREMOVEXATTR            = 220
+       SYS_FUTEX                   = 221
+       SYS_SCHED_SETAFFINITY       = 222
+       SYS_SCHED_GETAFFINITY       = 223
+       SYS_TUXCALL                 = 225
+       SYS_IO_SETUP                = 227
+       SYS_IO_DESTROY              = 228
+       SYS_IO_GETEVENTS            = 229
+       SYS_IO_SUBMIT               = 230
+       SYS_IO_CANCEL               = 231
+       SYS_SET_TID_ADDRESS         = 232
+       SYS_FADVISE64               = 233
+       SYS_EXIT_GROUP              = 234
+       SYS_LOOKUP_DCOOKIE          = 235
+       SYS_EPOLL_CREATE            = 236
+       SYS_EPOLL_CTL               = 237
+       SYS_EPOLL_WAIT              = 238
+       SYS_REMAP_FILE_PAGES        = 239
+       SYS_TIMER_CREATE            = 240
+       SYS_TIMER_SETTIME           = 241
+       SYS_TIMER_GETTIME           = 242
+       SYS_TIMER_GETOVERRUN        = 243
+       SYS_TIMER_DELETE            = 244
+       SYS_CLOCK_SETTIME           = 245
+       SYS_CLOCK_GETTIME           = 246
+       SYS_CLOCK_GETRES            = 247
+       SYS_CLOCK_NANOSLEEP         = 248
+       SYS_SWAPCONTEXT             = 249
+       SYS_TGKILL                  = 250
+       SYS_UTIMES                  = 251
+       SYS_STATFS64                = 252
+       SYS_FSTATFS64               = 253
+       SYS_RTAS                    = 255
+       SYS_SYS_DEBUG_SETCONTEXT    = 256
+       SYS_MIGRATE_PAGES           = 258
+       SYS_MBIND                   = 259
+       SYS_GET_MEMPOLICY           = 260
+       SYS_SET_MEMPOLICY           = 261
+       SYS_MQ_OPEN                 = 262
+       SYS_MQ_UNLINK               = 263
+       SYS_MQ_TIMEDSEND            = 264
+       SYS_MQ_TIMEDRECEIVE         = 265
+       SYS_MQ_NOTIFY               = 266
+       SYS_MQ_GETSETATTR           = 267
+       SYS_KEXEC_LOAD              = 268
+       SYS_ADD_KEY                 = 269
+       SYS_REQUEST_KEY             = 270
+       SYS_KEYCTL                  = 271
+       SYS_WAITID                  = 272
+       SYS_IOPRIO_SET              = 273
+       SYS_IOPRIO_GET              = 274
+       SYS_INOTIFY_INIT            = 275
+       SYS_INOTIFY_ADD_WATCH       = 276
+       SYS_INOTIFY_RM_WATCH        = 277
+       SYS_SPU_RUN                 = 278
+       SYS_SPU_CREATE              = 279
+       SYS_PSELECT6                = 280
+       SYS_PPOLL                   = 281
+       SYS_UNSHARE                 = 282
+       SYS_SPLICE                  = 283
+       SYS_TEE                     = 284
+       SYS_VMSPLICE                = 285
+       SYS_OPENAT                  = 286
+       SYS_MKDIRAT                 = 287
+       SYS_MKNODAT                 = 288
+       SYS_FCHOWNAT                = 289
+       SYS_FUTIMESAT               = 290
+       SYS_NEWFSTATAT              = 291
+       SYS_UNLINKAT                = 292
+       SYS_RENAMEAT                = 293
+       SYS_LINKAT                  = 294
+       SYS_SYMLINKAT               = 295
+       SYS_READLINKAT              = 296
+       SYS_FCHMODAT                = 297
+       SYS_FACCESSAT               = 298
+       SYS_GET_ROBUST_LIST         = 299
+       SYS_SET_ROBUST_LIST         = 300
+       SYS_MOVE_PAGES              = 301
+       SYS_GETCPU                  = 302
+       SYS_EPOLL_PWAIT             = 303
+       SYS_UTIMENSAT               = 304
+       SYS_SIGNALFD                = 305
+       SYS_TIMERFD_CREATE          = 306
+       SYS_EVENTFD                 = 307
+       SYS_SYNC_FILE_RANGE2        = 308
+       SYS_FALLOCATE               = 309
+       SYS_SUBPAGE_PROT            = 310
+       SYS_TIMERFD_SETTIME         = 311
+       SYS_TIMERFD_GETTIME         = 312
+       SYS_SIGNALFD4               = 313
+       SYS_EVENTFD2                = 314
+       SYS_EPOLL_CREATE1           = 315
+       SYS_DUP3                    = 316
+       SYS_PIPE2                   = 317
+       SYS_INOTIFY_INIT1           = 318
+       SYS_PERF_EVENT_OPEN         = 319
+       SYS_PREADV                  = 320
+       SYS_PWRITEV                 = 321
+       SYS_RT_TGSIGQUEUEINFO       = 322
+       SYS_FANOTIFY_INIT           = 323
+       SYS_FANOTIFY_MARK           = 324
+       SYS_PRLIMIT64               = 325
+       SYS_SOCKET                  = 326
+       SYS_BIND                    = 327
+       SYS_CONNECT                 = 328
+       SYS_LISTEN                  = 329
+       SYS_ACCEPT                  = 330
+       SYS_GETSOCKNAME             = 331
+       SYS_GETPEERNAME             = 332
+       SYS_SOCKETPAIR              = 333
+       SYS_SEND                    = 334
+       SYS_SENDTO                  = 335
+       SYS_RECV                    = 336
+       SYS_RECVFROM                = 337
+       SYS_SHUTDOWN                = 338
+       SYS_SETSOCKOPT              = 339
+       SYS_GETSOCKOPT              = 340
+       SYS_SENDMSG                 = 341
+       SYS_RECVMSG                 = 342
+       SYS_RECVMMSG                = 343
+       SYS_ACCEPT4                 = 344
+       SYS_NAME_TO_HANDLE_AT       = 345
+       SYS_OPEN_BY_HANDLE_AT       = 346
+       SYS_CLOCK_ADJTIME           = 347
+       SYS_SYNCFS                  = 348
+       SYS_SENDMMSG                = 349
+       SYS_SETNS                   = 350
+       SYS_PROCESS_VM_READV        = 351
+       SYS_PROCESS_VM_WRITEV       = 352
+       SYS_FINIT_MODULE            = 353
+       SYS_KCMP                    = 354
+       SYS_SCHED_SETATTR           = 355
+       SYS_SCHED_GETATTR           = 356
+       SYS_RENAMEAT2               = 357
+       SYS_SECCOMP                 = 358
+       SYS_GETRANDOM               = 359
+       SYS_MEMFD_CREATE            = 360
+       SYS_BPF                     = 361
+       SYS_EXECVEAT                = 362
+       SYS_SWITCH_ENDIAN           = 363
+       SYS_USERFAULTFD             = 364
+       SYS_MEMBARRIER              = 365
+       SYS_MLOCK2                  = 378
+       SYS_COPY_FILE_RANGE         = 379
+       SYS_PREADV2                 = 380
+       SYS_PWRITEV2                = 381
+       SYS_KEXEC_FILE_LOAD         = 382
+       SYS_STATX                   = 383
+       SYS_PKEY_ALLOC              = 384
+       SYS_PKEY_FREE               = 385
+       SYS_PKEY_MPROTECT           = 386
+       SYS_RSEQ                    = 387
+       SYS_IO_PGETEVENTS           = 388
+       SYS_SEMTIMEDOP              = 392
+       SYS_SEMGET                  = 393
+       SYS_SEMCTL                  = 394
+       SYS_SHMGET                  = 395
+       SYS_SHMCTL                  = 396
+       SYS_SHMAT                   = 397
+       SYS_SHMDT                   = 398
+       SYS_MSGGET                  = 399
+       SYS_MSGSND                  = 400
+       SYS_MSGRCV                  = 401
+       SYS_MSGCTL                  = 402
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLONE3                  = 435
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
 )
index 33b33b08342dc7b36788b424af71de25fdf07f66..bfc87ea4443995b6ea7ddb44d900af1dc25a0365 100644 (file)
 package unix
 
 const (
-       SYS_RESTART_SYSCALL        = 0
-       SYS_EXIT                   = 1
-       SYS_FORK                   = 2
-       SYS_READ                   = 3
-       SYS_WRITE                  = 4
-       SYS_OPEN                   = 5
-       SYS_CLOSE                  = 6
-       SYS_WAITPID                = 7
-       SYS_CREAT                  = 8
-       SYS_LINK                   = 9
-       SYS_UNLINK                 = 10
-       SYS_EXECVE                 = 11
-       SYS_CHDIR                  = 12
-       SYS_TIME                   = 13
-       SYS_MKNOD                  = 14
-       SYS_CHMOD                  = 15
-       SYS_LCHOWN                 = 16
-       SYS_BREAK                  = 17
-       SYS_OLDSTAT                = 18
-       SYS_LSEEK                  = 19
-       SYS_GETPID                 = 20
-       SYS_MOUNT                  = 21
-       SYS_UMOUNT                 = 22
-       SYS_SETUID                 = 23
-       SYS_GETUID                 = 24
-       SYS_STIME                  = 25
-       SYS_PTRACE                 = 26
-       SYS_ALARM                  = 27
-       SYS_OLDFSTAT               = 28
-       SYS_PAUSE                  = 29
-       SYS_UTIME                  = 30
-       SYS_STTY                   = 31
-       SYS_GTTY                   = 32
-       SYS_ACCESS                 = 33
-       SYS_NICE                   = 34
-       SYS_FTIME                  = 35
-       SYS_SYNC                   = 36
-       SYS_KILL                   = 37
-       SYS_RENAME                 = 38
-       SYS_MKDIR                  = 39
-       SYS_RMDIR                  = 40
-       SYS_DUP                    = 41
-       SYS_PIPE                   = 42
-       SYS_TIMES                  = 43
-       SYS_PROF                   = 44
-       SYS_BRK                    = 45
-       SYS_SETGID                 = 46
-       SYS_GETGID                 = 47
-       SYS_SIGNAL                 = 48
-       SYS_GETEUID                = 49
-       SYS_GETEGID                = 50
-       SYS_ACCT                   = 51
-       SYS_UMOUNT2                = 52
-       SYS_LOCK                   = 53
-       SYS_IOCTL                  = 54
-       SYS_FCNTL                  = 55
-       SYS_MPX                    = 56
-       SYS_SETPGID                = 57
-       SYS_ULIMIT                 = 58
-       SYS_OLDOLDUNAME            = 59
-       SYS_UMASK                  = 60
-       SYS_CHROOT                 = 61
-       SYS_USTAT                  = 62
-       SYS_DUP2                   = 63
-       SYS_GETPPID                = 64
-       SYS_GETPGRP                = 65
-       SYS_SETSID                 = 66
-       SYS_SIGACTION              = 67
-       SYS_SGETMASK               = 68
-       SYS_SSETMASK               = 69
-       SYS_SETREUID               = 70
-       SYS_SETREGID               = 71
-       SYS_SIGSUSPEND             = 72
-       SYS_SIGPENDING             = 73
-       SYS_SETHOSTNAME            = 74
-       SYS_SETRLIMIT              = 75
-       SYS_GETRLIMIT              = 76
-       SYS_GETRUSAGE              = 77
-       SYS_GETTIMEOFDAY           = 78
-       SYS_SETTIMEOFDAY           = 79
-       SYS_GETGROUPS              = 80
-       SYS_SETGROUPS              = 81
-       SYS_SELECT                 = 82
-       SYS_SYMLINK                = 83
-       SYS_OLDLSTAT               = 84
-       SYS_READLINK               = 85
-       SYS_USELIB                 = 86
-       SYS_SWAPON                 = 87
-       SYS_REBOOT                 = 88
-       SYS_READDIR                = 89
-       SYS_MMAP                   = 90
-       SYS_MUNMAP                 = 91
-       SYS_TRUNCATE               = 92
-       SYS_FTRUNCATE              = 93
-       SYS_FCHMOD                 = 94
-       SYS_FCHOWN                 = 95
-       SYS_GETPRIORITY            = 96
-       SYS_SETPRIORITY            = 97
-       SYS_PROFIL                 = 98
-       SYS_STATFS                 = 99
-       SYS_FSTATFS                = 100
-       SYS_IOPERM                 = 101
-       SYS_SOCKETCALL             = 102
-       SYS_SYSLOG                 = 103
-       SYS_SETITIMER              = 104
-       SYS_GETITIMER              = 105
-       SYS_STAT                   = 106
-       SYS_LSTAT                  = 107
-       SYS_FSTAT                  = 108
-       SYS_OLDUNAME               = 109
-       SYS_IOPL                   = 110
-       SYS_VHANGUP                = 111
-       SYS_IDLE                   = 112
-       SYS_VM86                   = 113
-       SYS_WAIT4                  = 114
-       SYS_SWAPOFF                = 115
-       SYS_SYSINFO                = 116
-       SYS_IPC                    = 117
-       SYS_FSYNC                  = 118
-       SYS_SIGRETURN              = 119
-       SYS_CLONE                  = 120
-       SYS_SETDOMAINNAME          = 121
-       SYS_UNAME                  = 122
-       SYS_MODIFY_LDT             = 123
-       SYS_ADJTIMEX               = 124
-       SYS_MPROTECT               = 125
-       SYS_SIGPROCMASK            = 126
-       SYS_CREATE_MODULE          = 127
-       SYS_INIT_MODULE            = 128
-       SYS_DELETE_MODULE          = 129
-       SYS_GET_KERNEL_SYMS        = 130
-       SYS_QUOTACTL               = 131
-       SYS_GETPGID                = 132
-       SYS_FCHDIR                 = 133
-       SYS_BDFLUSH                = 134
-       SYS_SYSFS                  = 135
-       SYS_PERSONALITY            = 136
-       SYS_AFS_SYSCALL            = 137
-       SYS_SETFSUID               = 138
-       SYS_SETFSGID               = 139
-       SYS__LLSEEK                = 140
-       SYS_GETDENTS               = 141
-       SYS__NEWSELECT             = 142
-       SYS_FLOCK                  = 143
-       SYS_MSYNC                  = 144
-       SYS_READV                  = 145
-       SYS_WRITEV                 = 146
-       SYS_GETSID                 = 147
-       SYS_FDATASYNC              = 148
-       SYS__SYSCTL                = 149
-       SYS_MLOCK                  = 150
-       SYS_MUNLOCK                = 151
-       SYS_MLOCKALL               = 152
-       SYS_MUNLOCKALL             = 153
-       SYS_SCHED_SETPARAM         = 154
-       SYS_SCHED_GETPARAM         = 155
-       SYS_SCHED_SETSCHEDULER     = 156
-       SYS_SCHED_GETSCHEDULER     = 157
-       SYS_SCHED_YIELD            = 158
-       SYS_SCHED_GET_PRIORITY_MAX = 159
-       SYS_SCHED_GET_PRIORITY_MIN = 160
-       SYS_SCHED_RR_GET_INTERVAL  = 161
-       SYS_NANOSLEEP              = 162
-       SYS_MREMAP                 = 163
-       SYS_SETRESUID              = 164
-       SYS_GETRESUID              = 165
-       SYS_QUERY_MODULE           = 166
-       SYS_POLL                   = 167
-       SYS_NFSSERVCTL             = 168
-       SYS_SETRESGID              = 169
-       SYS_GETRESGID              = 170
-       SYS_PRCTL                  = 171
-       SYS_RT_SIGRETURN           = 172
-       SYS_RT_SIGACTION           = 173
-       SYS_RT_SIGPROCMASK         = 174
-       SYS_RT_SIGPENDING          = 175
-       SYS_RT_SIGTIMEDWAIT        = 176
-       SYS_RT_SIGQUEUEINFO        = 177
-       SYS_RT_SIGSUSPEND          = 178
-       SYS_PREAD64                = 179
-       SYS_PWRITE64               = 180
-       SYS_CHOWN                  = 181
-       SYS_GETCWD                 = 182
-       SYS_CAPGET                 = 183
-       SYS_CAPSET                 = 184
-       SYS_SIGALTSTACK            = 185
-       SYS_SENDFILE               = 186
-       SYS_GETPMSG                = 187
-       SYS_PUTPMSG                = 188
-       SYS_VFORK                  = 189
-       SYS_UGETRLIMIT             = 190
-       SYS_READAHEAD              = 191
-       SYS_PCICONFIG_READ         = 198
-       SYS_PCICONFIG_WRITE        = 199
-       SYS_PCICONFIG_IOBASE       = 200
-       SYS_MULTIPLEXER            = 201
-       SYS_GETDENTS64             = 202
-       SYS_PIVOT_ROOT             = 203
-       SYS_MADVISE                = 205
-       SYS_MINCORE                = 206
-       SYS_GETTID                 = 207
-       SYS_TKILL                  = 208
-       SYS_SETXATTR               = 209
-       SYS_LSETXATTR              = 210
-       SYS_FSETXATTR              = 211
-       SYS_GETXATTR               = 212
-       SYS_LGETXATTR              = 213
-       SYS_FGETXATTR              = 214
-       SYS_LISTXATTR              = 215
-       SYS_LLISTXATTR             = 216
-       SYS_FLISTXATTR             = 217
-       SYS_REMOVEXATTR            = 218
-       SYS_LREMOVEXATTR           = 219
-       SYS_FREMOVEXATTR           = 220
-       SYS_FUTEX                  = 221
-       SYS_SCHED_SETAFFINITY      = 222
-       SYS_SCHED_GETAFFINITY      = 223
-       SYS_TUXCALL                = 225
-       SYS_IO_SETUP               = 227
-       SYS_IO_DESTROY             = 228
-       SYS_IO_GETEVENTS           = 229
-       SYS_IO_SUBMIT              = 230
-       SYS_IO_CANCEL              = 231
-       SYS_SET_TID_ADDRESS        = 232
-       SYS_FADVISE64              = 233
-       SYS_EXIT_GROUP             = 234
-       SYS_LOOKUP_DCOOKIE         = 235
-       SYS_EPOLL_CREATE           = 236
-       SYS_EPOLL_CTL              = 237
-       SYS_EPOLL_WAIT             = 238
-       SYS_REMAP_FILE_PAGES       = 239
-       SYS_TIMER_CREATE           = 240
-       SYS_TIMER_SETTIME          = 241
-       SYS_TIMER_GETTIME          = 242
-       SYS_TIMER_GETOVERRUN       = 243
-       SYS_TIMER_DELETE           = 244
-       SYS_CLOCK_SETTIME          = 245
-       SYS_CLOCK_GETTIME          = 246
-       SYS_CLOCK_GETRES           = 247
-       SYS_CLOCK_NANOSLEEP        = 248
-       SYS_SWAPCONTEXT            = 249
-       SYS_TGKILL                 = 250
-       SYS_UTIMES                 = 251
-       SYS_STATFS64               = 252
-       SYS_FSTATFS64              = 253
-       SYS_RTAS                   = 255
-       SYS_SYS_DEBUG_SETCONTEXT   = 256
-       SYS_MIGRATE_PAGES          = 258
-       SYS_MBIND                  = 259
-       SYS_GET_MEMPOLICY          = 260
-       SYS_SET_MEMPOLICY          = 261
-       SYS_MQ_OPEN                = 262
-       SYS_MQ_UNLINK              = 263
-       SYS_MQ_TIMEDSEND           = 264
-       SYS_MQ_TIMEDRECEIVE        = 265
-       SYS_MQ_NOTIFY              = 266
-       SYS_MQ_GETSETATTR          = 267
-       SYS_KEXEC_LOAD             = 268
-       SYS_ADD_KEY                = 269
-       SYS_REQUEST_KEY            = 270
-       SYS_KEYCTL                 = 271
-       SYS_WAITID                 = 272
-       SYS_IOPRIO_SET             = 273
-       SYS_IOPRIO_GET             = 274
-       SYS_INOTIFY_INIT           = 275
-       SYS_INOTIFY_ADD_WATCH      = 276
-       SYS_INOTIFY_RM_WATCH       = 277
-       SYS_SPU_RUN                = 278
-       SYS_SPU_CREATE             = 279
-       SYS_PSELECT6               = 280
-       SYS_PPOLL                  = 281
-       SYS_UNSHARE                = 282
-       SYS_SPLICE                 = 283
-       SYS_TEE                    = 284
-       SYS_VMSPLICE               = 285
-       SYS_OPENAT                 = 286
-       SYS_MKDIRAT                = 287
-       SYS_MKNODAT                = 288
-       SYS_FCHOWNAT               = 289
-       SYS_FUTIMESAT              = 290
-       SYS_NEWFSTATAT             = 291
-       SYS_UNLINKAT               = 292
-       SYS_RENAMEAT               = 293
-       SYS_LINKAT                 = 294
-       SYS_SYMLINKAT              = 295
-       SYS_READLINKAT             = 296
-       SYS_FCHMODAT               = 297
-       SYS_FACCESSAT              = 298
-       SYS_GET_ROBUST_LIST        = 299
-       SYS_SET_ROBUST_LIST        = 300
-       SYS_MOVE_PAGES             = 301
-       SYS_GETCPU                 = 302
-       SYS_EPOLL_PWAIT            = 303
-       SYS_UTIMENSAT              = 304
-       SYS_SIGNALFD               = 305
-       SYS_TIMERFD_CREATE         = 306
-       SYS_EVENTFD                = 307
-       SYS_SYNC_FILE_RANGE2       = 308
-       SYS_FALLOCATE              = 309
-       SYS_SUBPAGE_PROT           = 310
-       SYS_TIMERFD_SETTIME        = 311
-       SYS_TIMERFD_GETTIME        = 312
-       SYS_SIGNALFD4              = 313
-       SYS_EVENTFD2               = 314
-       SYS_EPOLL_CREATE1          = 315
-       SYS_DUP3                   = 316
-       SYS_PIPE2                  = 317
-       SYS_INOTIFY_INIT1          = 318
-       SYS_PERF_EVENT_OPEN        = 319
-       SYS_PREADV                 = 320
-       SYS_PWRITEV                = 321
-       SYS_RT_TGSIGQUEUEINFO      = 322
-       SYS_FANOTIFY_INIT          = 323
-       SYS_FANOTIFY_MARK          = 324
-       SYS_PRLIMIT64              = 325
-       SYS_SOCKET                 = 326
-       SYS_BIND                   = 327
-       SYS_CONNECT                = 328
-       SYS_LISTEN                 = 329
-       SYS_ACCEPT                 = 330
-       SYS_GETSOCKNAME            = 331
-       SYS_GETPEERNAME            = 332
-       SYS_SOCKETPAIR             = 333
-       SYS_SEND                   = 334
-       SYS_SENDTO                 = 335
-       SYS_RECV                   = 336
-       SYS_RECVFROM               = 337
-       SYS_SHUTDOWN               = 338
-       SYS_SETSOCKOPT             = 339
-       SYS_GETSOCKOPT             = 340
-       SYS_SENDMSG                = 341
-       SYS_RECVMSG                = 342
-       SYS_RECVMMSG               = 343
-       SYS_ACCEPT4                = 344
-       SYS_NAME_TO_HANDLE_AT      = 345
-       SYS_OPEN_BY_HANDLE_AT      = 346
-       SYS_CLOCK_ADJTIME          = 347
-       SYS_SYNCFS                 = 348
-       SYS_SENDMMSG               = 349
-       SYS_SETNS                  = 350
-       SYS_PROCESS_VM_READV       = 351
-       SYS_PROCESS_VM_WRITEV      = 352
-       SYS_FINIT_MODULE           = 353
-       SYS_KCMP                   = 354
-       SYS_SCHED_SETATTR          = 355
-       SYS_SCHED_GETATTR          = 356
-       SYS_RENAMEAT2              = 357
-       SYS_SECCOMP                = 358
-       SYS_GETRANDOM              = 359
-       SYS_MEMFD_CREATE           = 360
-       SYS_BPF                    = 361
-       SYS_EXECVEAT               = 362
-       SYS_SWITCH_ENDIAN          = 363
-       SYS_USERFAULTFD            = 364
-       SYS_MEMBARRIER             = 365
-       SYS_MLOCK2                 = 378
-       SYS_COPY_FILE_RANGE        = 379
-       SYS_PREADV2                = 380
-       SYS_PWRITEV2               = 381
-       SYS_KEXEC_FILE_LOAD        = 382
-       SYS_STATX                  = 383
-       SYS_PKEY_ALLOC             = 384
-       SYS_PKEY_FREE              = 385
-       SYS_PKEY_MPROTECT          = 386
-       SYS_RSEQ                   = 387
-       SYS_IO_PGETEVENTS          = 388
-       SYS_SEMTIMEDOP             = 392
-       SYS_SEMGET                 = 393
-       SYS_SEMCTL                 = 394
-       SYS_SHMGET                 = 395
-       SYS_SHMCTL                 = 396
-       SYS_SHMAT                  = 397
-       SYS_SHMDT                  = 398
-       SYS_MSGGET                 = 399
-       SYS_MSGSND                 = 400
-       SYS_MSGRCV                 = 401
-       SYS_MSGCTL                 = 402
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLONE3                 = 435
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_RESTART_SYSCALL         = 0
+       SYS_EXIT                    = 1
+       SYS_FORK                    = 2
+       SYS_READ                    = 3
+       SYS_WRITE                   = 4
+       SYS_OPEN                    = 5
+       SYS_CLOSE                   = 6
+       SYS_WAITPID                 = 7
+       SYS_CREAT                   = 8
+       SYS_LINK                    = 9
+       SYS_UNLINK                  = 10
+       SYS_EXECVE                  = 11
+       SYS_CHDIR                   = 12
+       SYS_TIME                    = 13
+       SYS_MKNOD                   = 14
+       SYS_CHMOD                   = 15
+       SYS_LCHOWN                  = 16
+       SYS_BREAK                   = 17
+       SYS_OLDSTAT                 = 18
+       SYS_LSEEK                   = 19
+       SYS_GETPID                  = 20
+       SYS_MOUNT                   = 21
+       SYS_UMOUNT                  = 22
+       SYS_SETUID                  = 23
+       SYS_GETUID                  = 24
+       SYS_STIME                   = 25
+       SYS_PTRACE                  = 26
+       SYS_ALARM                   = 27
+       SYS_OLDFSTAT                = 28
+       SYS_PAUSE                   = 29
+       SYS_UTIME                   = 30
+       SYS_STTY                    = 31
+       SYS_GTTY                    = 32
+       SYS_ACCESS                  = 33
+       SYS_NICE                    = 34
+       SYS_FTIME                   = 35
+       SYS_SYNC                    = 36
+       SYS_KILL                    = 37
+       SYS_RENAME                  = 38
+       SYS_MKDIR                   = 39
+       SYS_RMDIR                   = 40
+       SYS_DUP                     = 41
+       SYS_PIPE                    = 42
+       SYS_TIMES                   = 43
+       SYS_PROF                    = 44
+       SYS_BRK                     = 45
+       SYS_SETGID                  = 46
+       SYS_GETGID                  = 47
+       SYS_SIGNAL                  = 48
+       SYS_GETEUID                 = 49
+       SYS_GETEGID                 = 50
+       SYS_ACCT                    = 51
+       SYS_UMOUNT2                 = 52
+       SYS_LOCK                    = 53
+       SYS_IOCTL                   = 54
+       SYS_FCNTL                   = 55
+       SYS_MPX                     = 56
+       SYS_SETPGID                 = 57
+       SYS_ULIMIT                  = 58
+       SYS_OLDOLDUNAME             = 59
+       SYS_UMASK                   = 60
+       SYS_CHROOT                  = 61
+       SYS_USTAT                   = 62
+       SYS_DUP2                    = 63
+       SYS_GETPPID                 = 64
+       SYS_GETPGRP                 = 65
+       SYS_SETSID                  = 66
+       SYS_SIGACTION               = 67
+       SYS_SGETMASK                = 68
+       SYS_SSETMASK                = 69
+       SYS_SETREUID                = 70
+       SYS_SETREGID                = 71
+       SYS_SIGSUSPEND              = 72
+       SYS_SIGPENDING              = 73
+       SYS_SETHOSTNAME             = 74
+       SYS_SETRLIMIT               = 75
+       SYS_GETRLIMIT               = 76
+       SYS_GETRUSAGE               = 77
+       SYS_GETTIMEOFDAY            = 78
+       SYS_SETTIMEOFDAY            = 79
+       SYS_GETGROUPS               = 80
+       SYS_SETGROUPS               = 81
+       SYS_SELECT                  = 82
+       SYS_SYMLINK                 = 83
+       SYS_OLDLSTAT                = 84
+       SYS_READLINK                = 85
+       SYS_USELIB                  = 86
+       SYS_SWAPON                  = 87
+       SYS_REBOOT                  = 88
+       SYS_READDIR                 = 89
+       SYS_MMAP                    = 90
+       SYS_MUNMAP                  = 91
+       SYS_TRUNCATE                = 92
+       SYS_FTRUNCATE               = 93
+       SYS_FCHMOD                  = 94
+       SYS_FCHOWN                  = 95
+       SYS_GETPRIORITY             = 96
+       SYS_SETPRIORITY             = 97
+       SYS_PROFIL                  = 98
+       SYS_STATFS                  = 99
+       SYS_FSTATFS                 = 100
+       SYS_IOPERM                  = 101
+       SYS_SOCKETCALL              = 102
+       SYS_SYSLOG                  = 103
+       SYS_SETITIMER               = 104
+       SYS_GETITIMER               = 105
+       SYS_STAT                    = 106
+       SYS_LSTAT                   = 107
+       SYS_FSTAT                   = 108
+       SYS_OLDUNAME                = 109
+       SYS_IOPL                    = 110
+       SYS_VHANGUP                 = 111
+       SYS_IDLE                    = 112
+       SYS_VM86                    = 113
+       SYS_WAIT4                   = 114
+       SYS_SWAPOFF                 = 115
+       SYS_SYSINFO                 = 116
+       SYS_IPC                     = 117
+       SYS_FSYNC                   = 118
+       SYS_SIGRETURN               = 119
+       SYS_CLONE                   = 120
+       SYS_SETDOMAINNAME           = 121
+       SYS_UNAME                   = 122
+       SYS_MODIFY_LDT              = 123
+       SYS_ADJTIMEX                = 124
+       SYS_MPROTECT                = 125
+       SYS_SIGPROCMASK             = 126
+       SYS_CREATE_MODULE           = 127
+       SYS_INIT_MODULE             = 128
+       SYS_DELETE_MODULE           = 129
+       SYS_GET_KERNEL_SYMS         = 130
+       SYS_QUOTACTL                = 131
+       SYS_GETPGID                 = 132
+       SYS_FCHDIR                  = 133
+       SYS_BDFLUSH                 = 134
+       SYS_SYSFS                   = 135
+       SYS_PERSONALITY             = 136
+       SYS_AFS_SYSCALL             = 137
+       SYS_SETFSUID                = 138
+       SYS_SETFSGID                = 139
+       SYS__LLSEEK                 = 140
+       SYS_GETDENTS                = 141
+       SYS__NEWSELECT              = 142
+       SYS_FLOCK                   = 143
+       SYS_MSYNC                   = 144
+       SYS_READV                   = 145
+       SYS_WRITEV                  = 146
+       SYS_GETSID                  = 147
+       SYS_FDATASYNC               = 148
+       SYS__SYSCTL                 = 149
+       SYS_MLOCK                   = 150
+       SYS_MUNLOCK                 = 151
+       SYS_MLOCKALL                = 152
+       SYS_MUNLOCKALL              = 153
+       SYS_SCHED_SETPARAM          = 154
+       SYS_SCHED_GETPARAM          = 155
+       SYS_SCHED_SETSCHEDULER      = 156
+       SYS_SCHED_GETSCHEDULER      = 157
+       SYS_SCHED_YIELD             = 158
+       SYS_SCHED_GET_PRIORITY_MAX  = 159
+       SYS_SCHED_GET_PRIORITY_MIN  = 160
+       SYS_SCHED_RR_GET_INTERVAL   = 161
+       SYS_NANOSLEEP               = 162
+       SYS_MREMAP                  = 163
+       SYS_SETRESUID               = 164
+       SYS_GETRESUID               = 165
+       SYS_QUERY_MODULE            = 166
+       SYS_POLL                    = 167
+       SYS_NFSSERVCTL              = 168
+       SYS_SETRESGID               = 169
+       SYS_GETRESGID               = 170
+       SYS_PRCTL                   = 171
+       SYS_RT_SIGRETURN            = 172
+       SYS_RT_SIGACTION            = 173
+       SYS_RT_SIGPROCMASK          = 174
+       SYS_RT_SIGPENDING           = 175
+       SYS_RT_SIGTIMEDWAIT         = 176
+       SYS_RT_SIGQUEUEINFO         = 177
+       SYS_RT_SIGSUSPEND           = 178
+       SYS_PREAD64                 = 179
+       SYS_PWRITE64                = 180
+       SYS_CHOWN                   = 181
+       SYS_GETCWD                  = 182
+       SYS_CAPGET                  = 183
+       SYS_CAPSET                  = 184
+       SYS_SIGALTSTACK             = 185
+       SYS_SENDFILE                = 186
+       SYS_GETPMSG                 = 187
+       SYS_PUTPMSG                 = 188
+       SYS_VFORK                   = 189
+       SYS_UGETRLIMIT              = 190
+       SYS_READAHEAD               = 191
+       SYS_PCICONFIG_READ          = 198
+       SYS_PCICONFIG_WRITE         = 199
+       SYS_PCICONFIG_IOBASE        = 200
+       SYS_MULTIPLEXER             = 201
+       SYS_GETDENTS64              = 202
+       SYS_PIVOT_ROOT              = 203
+       SYS_MADVISE                 = 205
+       SYS_MINCORE                 = 206
+       SYS_GETTID                  = 207
+       SYS_TKILL                   = 208
+       SYS_SETXATTR                = 209
+       SYS_LSETXATTR               = 210
+       SYS_FSETXATTR               = 211
+       SYS_GETXATTR                = 212
+       SYS_LGETXATTR               = 213
+       SYS_FGETXATTR               = 214
+       SYS_LISTXATTR               = 215
+       SYS_LLISTXATTR              = 216
+       SYS_FLISTXATTR              = 217
+       SYS_REMOVEXATTR             = 218
+       SYS_LREMOVEXATTR            = 219
+       SYS_FREMOVEXATTR            = 220
+       SYS_FUTEX                   = 221
+       SYS_SCHED_SETAFFINITY       = 222
+       SYS_SCHED_GETAFFINITY       = 223
+       SYS_TUXCALL                 = 225
+       SYS_IO_SETUP                = 227
+       SYS_IO_DESTROY              = 228
+       SYS_IO_GETEVENTS            = 229
+       SYS_IO_SUBMIT               = 230
+       SYS_IO_CANCEL               = 231
+       SYS_SET_TID_ADDRESS         = 232
+       SYS_FADVISE64               = 233
+       SYS_EXIT_GROUP              = 234
+       SYS_LOOKUP_DCOOKIE          = 235
+       SYS_EPOLL_CREATE            = 236
+       SYS_EPOLL_CTL               = 237
+       SYS_EPOLL_WAIT              = 238
+       SYS_REMAP_FILE_PAGES        = 239
+       SYS_TIMER_CREATE            = 240
+       SYS_TIMER_SETTIME           = 241
+       SYS_TIMER_GETTIME           = 242
+       SYS_TIMER_GETOVERRUN        = 243
+       SYS_TIMER_DELETE            = 244
+       SYS_CLOCK_SETTIME           = 245
+       SYS_CLOCK_GETTIME           = 246
+       SYS_CLOCK_GETRES            = 247
+       SYS_CLOCK_NANOSLEEP         = 248
+       SYS_SWAPCONTEXT             = 249
+       SYS_TGKILL                  = 250
+       SYS_UTIMES                  = 251
+       SYS_STATFS64                = 252
+       SYS_FSTATFS64               = 253
+       SYS_RTAS                    = 255
+       SYS_SYS_DEBUG_SETCONTEXT    = 256
+       SYS_MIGRATE_PAGES           = 258
+       SYS_MBIND                   = 259
+       SYS_GET_MEMPOLICY           = 260
+       SYS_SET_MEMPOLICY           = 261
+       SYS_MQ_OPEN                 = 262
+       SYS_MQ_UNLINK               = 263
+       SYS_MQ_TIMEDSEND            = 264
+       SYS_MQ_TIMEDRECEIVE         = 265
+       SYS_MQ_NOTIFY               = 266
+       SYS_MQ_GETSETATTR           = 267
+       SYS_KEXEC_LOAD              = 268
+       SYS_ADD_KEY                 = 269
+       SYS_REQUEST_KEY             = 270
+       SYS_KEYCTL                  = 271
+       SYS_WAITID                  = 272
+       SYS_IOPRIO_SET              = 273
+       SYS_IOPRIO_GET              = 274
+       SYS_INOTIFY_INIT            = 275
+       SYS_INOTIFY_ADD_WATCH       = 276
+       SYS_INOTIFY_RM_WATCH        = 277
+       SYS_SPU_RUN                 = 278
+       SYS_SPU_CREATE              = 279
+       SYS_PSELECT6                = 280
+       SYS_PPOLL                   = 281
+       SYS_UNSHARE                 = 282
+       SYS_SPLICE                  = 283
+       SYS_TEE                     = 284
+       SYS_VMSPLICE                = 285
+       SYS_OPENAT                  = 286
+       SYS_MKDIRAT                 = 287
+       SYS_MKNODAT                 = 288
+       SYS_FCHOWNAT                = 289
+       SYS_FUTIMESAT               = 290
+       SYS_NEWFSTATAT              = 291
+       SYS_UNLINKAT                = 292
+       SYS_RENAMEAT                = 293
+       SYS_LINKAT                  = 294
+       SYS_SYMLINKAT               = 295
+       SYS_READLINKAT              = 296
+       SYS_FCHMODAT                = 297
+       SYS_FACCESSAT               = 298
+       SYS_GET_ROBUST_LIST         = 299
+       SYS_SET_ROBUST_LIST         = 300
+       SYS_MOVE_PAGES              = 301
+       SYS_GETCPU                  = 302
+       SYS_EPOLL_PWAIT             = 303
+       SYS_UTIMENSAT               = 304
+       SYS_SIGNALFD                = 305
+       SYS_TIMERFD_CREATE          = 306
+       SYS_EVENTFD                 = 307
+       SYS_SYNC_FILE_RANGE2        = 308
+       SYS_FALLOCATE               = 309
+       SYS_SUBPAGE_PROT            = 310
+       SYS_TIMERFD_SETTIME         = 311
+       SYS_TIMERFD_GETTIME         = 312
+       SYS_SIGNALFD4               = 313
+       SYS_EVENTFD2                = 314
+       SYS_EPOLL_CREATE1           = 315
+       SYS_DUP3                    = 316
+       SYS_PIPE2                   = 317
+       SYS_INOTIFY_INIT1           = 318
+       SYS_PERF_EVENT_OPEN         = 319
+       SYS_PREADV                  = 320
+       SYS_PWRITEV                 = 321
+       SYS_RT_TGSIGQUEUEINFO       = 322
+       SYS_FANOTIFY_INIT           = 323
+       SYS_FANOTIFY_MARK           = 324
+       SYS_PRLIMIT64               = 325
+       SYS_SOCKET                  = 326
+       SYS_BIND                    = 327
+       SYS_CONNECT                 = 328
+       SYS_LISTEN                  = 329
+       SYS_ACCEPT                  = 330
+       SYS_GETSOCKNAME             = 331
+       SYS_GETPEERNAME             = 332
+       SYS_SOCKETPAIR              = 333
+       SYS_SEND                    = 334
+       SYS_SENDTO                  = 335
+       SYS_RECV                    = 336
+       SYS_RECVFROM                = 337
+       SYS_SHUTDOWN                = 338
+       SYS_SETSOCKOPT              = 339
+       SYS_GETSOCKOPT              = 340
+       SYS_SENDMSG                 = 341
+       SYS_RECVMSG                 = 342
+       SYS_RECVMMSG                = 343
+       SYS_ACCEPT4                 = 344
+       SYS_NAME_TO_HANDLE_AT       = 345
+       SYS_OPEN_BY_HANDLE_AT       = 346
+       SYS_CLOCK_ADJTIME           = 347
+       SYS_SYNCFS                  = 348
+       SYS_SENDMMSG                = 349
+       SYS_SETNS                   = 350
+       SYS_PROCESS_VM_READV        = 351
+       SYS_PROCESS_VM_WRITEV       = 352
+       SYS_FINIT_MODULE            = 353
+       SYS_KCMP                    = 354
+       SYS_SCHED_SETATTR           = 355
+       SYS_SCHED_GETATTR           = 356
+       SYS_RENAMEAT2               = 357
+       SYS_SECCOMP                 = 358
+       SYS_GETRANDOM               = 359
+       SYS_MEMFD_CREATE            = 360
+       SYS_BPF                     = 361
+       SYS_EXECVEAT                = 362
+       SYS_SWITCH_ENDIAN           = 363
+       SYS_USERFAULTFD             = 364
+       SYS_MEMBARRIER              = 365
+       SYS_MLOCK2                  = 378
+       SYS_COPY_FILE_RANGE         = 379
+       SYS_PREADV2                 = 380
+       SYS_PWRITEV2                = 381
+       SYS_KEXEC_FILE_LOAD         = 382
+       SYS_STATX                   = 383
+       SYS_PKEY_ALLOC              = 384
+       SYS_PKEY_FREE               = 385
+       SYS_PKEY_MPROTECT           = 386
+       SYS_RSEQ                    = 387
+       SYS_IO_PGETEVENTS           = 388
+       SYS_SEMTIMEDOP              = 392
+       SYS_SEMGET                  = 393
+       SYS_SEMCTL                  = 394
+       SYS_SHMGET                  = 395
+       SYS_SHMCTL                  = 396
+       SYS_SHMAT                   = 397
+       SYS_SHMDT                   = 398
+       SYS_MSGGET                  = 399
+       SYS_MSGSND                  = 400
+       SYS_MSGRCV                  = 401
+       SYS_MSGCTL                  = 402
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLONE3                  = 435
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
 )
index 66c8a8e09e1a0a90a87d33558556449858fde0bd..a390e147d3c2212d3abf50a22eb4822ea47779a1 100644 (file)
 package unix
 
 const (
-       SYS_IO_SETUP               = 0
-       SYS_IO_DESTROY             = 1
-       SYS_IO_SUBMIT              = 2
-       SYS_IO_CANCEL              = 3
-       SYS_IO_GETEVENTS           = 4
-       SYS_SETXATTR               = 5
-       SYS_LSETXATTR              = 6
-       SYS_FSETXATTR              = 7
-       SYS_GETXATTR               = 8
-       SYS_LGETXATTR              = 9
-       SYS_FGETXATTR              = 10
-       SYS_LISTXATTR              = 11
-       SYS_LLISTXATTR             = 12
-       SYS_FLISTXATTR             = 13
-       SYS_REMOVEXATTR            = 14
-       SYS_LREMOVEXATTR           = 15
-       SYS_FREMOVEXATTR           = 16
-       SYS_GETCWD                 = 17
-       SYS_LOOKUP_DCOOKIE         = 18
-       SYS_EVENTFD2               = 19
-       SYS_EPOLL_CREATE1          = 20
-       SYS_EPOLL_CTL              = 21
-       SYS_EPOLL_PWAIT            = 22
-       SYS_DUP                    = 23
-       SYS_DUP3                   = 24
-       SYS_FCNTL                  = 25
-       SYS_INOTIFY_INIT1          = 26
-       SYS_INOTIFY_ADD_WATCH      = 27
-       SYS_INOTIFY_RM_WATCH       = 28
-       SYS_IOCTL                  = 29
-       SYS_IOPRIO_SET             = 30
-       SYS_IOPRIO_GET             = 31
-       SYS_FLOCK                  = 32
-       SYS_MKNODAT                = 33
-       SYS_MKDIRAT                = 34
-       SYS_UNLINKAT               = 35
-       SYS_SYMLINKAT              = 36
-       SYS_LINKAT                 = 37
-       SYS_UMOUNT2                = 39
-       SYS_MOUNT                  = 40
-       SYS_PIVOT_ROOT             = 41
-       SYS_NFSSERVCTL             = 42
-       SYS_STATFS                 = 43
-       SYS_FSTATFS                = 44
-       SYS_TRUNCATE               = 45
-       SYS_FTRUNCATE              = 46
-       SYS_FALLOCATE              = 47
-       SYS_FACCESSAT              = 48
-       SYS_CHDIR                  = 49
-       SYS_FCHDIR                 = 50
-       SYS_CHROOT                 = 51
-       SYS_FCHMOD                 = 52
-       SYS_FCHMODAT               = 53
-       SYS_FCHOWNAT               = 54
-       SYS_FCHOWN                 = 55
-       SYS_OPENAT                 = 56
-       SYS_CLOSE                  = 57
-       SYS_VHANGUP                = 58
-       SYS_PIPE2                  = 59
-       SYS_QUOTACTL               = 60
-       SYS_GETDENTS64             = 61
-       SYS_LSEEK                  = 62
-       SYS_READ                   = 63
-       SYS_WRITE                  = 64
-       SYS_READV                  = 65
-       SYS_WRITEV                 = 66
-       SYS_PREAD64                = 67
-       SYS_PWRITE64               = 68
-       SYS_PREADV                 = 69
-       SYS_PWRITEV                = 70
-       SYS_SENDFILE               = 71
-       SYS_PSELECT6               = 72
-       SYS_PPOLL                  = 73
-       SYS_SIGNALFD4              = 74
-       SYS_VMSPLICE               = 75
-       SYS_SPLICE                 = 76
-       SYS_TEE                    = 77
-       SYS_READLINKAT             = 78
-       SYS_FSTATAT                = 79
-       SYS_FSTAT                  = 80
-       SYS_SYNC                   = 81
-       SYS_FSYNC                  = 82
-       SYS_FDATASYNC              = 83
-       SYS_SYNC_FILE_RANGE        = 84
-       SYS_TIMERFD_CREATE         = 85
-       SYS_TIMERFD_SETTIME        = 86
-       SYS_TIMERFD_GETTIME        = 87
-       SYS_UTIMENSAT              = 88
-       SYS_ACCT                   = 89
-       SYS_CAPGET                 = 90
-       SYS_CAPSET                 = 91
-       SYS_PERSONALITY            = 92
-       SYS_EXIT                   = 93
-       SYS_EXIT_GROUP             = 94
-       SYS_WAITID                 = 95
-       SYS_SET_TID_ADDRESS        = 96
-       SYS_UNSHARE                = 97
-       SYS_FUTEX                  = 98
-       SYS_SET_ROBUST_LIST        = 99
-       SYS_GET_ROBUST_LIST        = 100
-       SYS_NANOSLEEP              = 101
-       SYS_GETITIMER              = 102
-       SYS_SETITIMER              = 103
-       SYS_KEXEC_LOAD             = 104
-       SYS_INIT_MODULE            = 105
-       SYS_DELETE_MODULE          = 106
-       SYS_TIMER_CREATE           = 107
-       SYS_TIMER_GETTIME          = 108
-       SYS_TIMER_GETOVERRUN       = 109
-       SYS_TIMER_SETTIME          = 110
-       SYS_TIMER_DELETE           = 111
-       SYS_CLOCK_SETTIME          = 112
-       SYS_CLOCK_GETTIME          = 113
-       SYS_CLOCK_GETRES           = 114
-       SYS_CLOCK_NANOSLEEP        = 115
-       SYS_SYSLOG                 = 116
-       SYS_PTRACE                 = 117
-       SYS_SCHED_SETPARAM         = 118
-       SYS_SCHED_SETSCHEDULER     = 119
-       SYS_SCHED_GETSCHEDULER     = 120
-       SYS_SCHED_GETPARAM         = 121
-       SYS_SCHED_SETAFFINITY      = 122
-       SYS_SCHED_GETAFFINITY      = 123
-       SYS_SCHED_YIELD            = 124
-       SYS_SCHED_GET_PRIORITY_MAX = 125
-       SYS_SCHED_GET_PRIORITY_MIN = 126
-       SYS_SCHED_RR_GET_INTERVAL  = 127
-       SYS_RESTART_SYSCALL        = 128
-       SYS_KILL                   = 129
-       SYS_TKILL                  = 130
-       SYS_TGKILL                 = 131
-       SYS_SIGALTSTACK            = 132
-       SYS_RT_SIGSUSPEND          = 133
-       SYS_RT_SIGACTION           = 134
-       SYS_RT_SIGPROCMASK         = 135
-       SYS_RT_SIGPENDING          = 136
-       SYS_RT_SIGTIMEDWAIT        = 137
-       SYS_RT_SIGQUEUEINFO        = 138
-       SYS_RT_SIGRETURN           = 139
-       SYS_SETPRIORITY            = 140
-       SYS_GETPRIORITY            = 141
-       SYS_REBOOT                 = 142
-       SYS_SETREGID               = 143
-       SYS_SETGID                 = 144
-       SYS_SETREUID               = 145
-       SYS_SETUID                 = 146
-       SYS_SETRESUID              = 147
-       SYS_GETRESUID              = 148
-       SYS_SETRESGID              = 149
-       SYS_GETRESGID              = 150
-       SYS_SETFSUID               = 151
-       SYS_SETFSGID               = 152
-       SYS_TIMES                  = 153
-       SYS_SETPGID                = 154
-       SYS_GETPGID                = 155
-       SYS_GETSID                 = 156
-       SYS_SETSID                 = 157
-       SYS_GETGROUPS              = 158
-       SYS_SETGROUPS              = 159
-       SYS_UNAME                  = 160
-       SYS_SETHOSTNAME            = 161
-       SYS_SETDOMAINNAME          = 162
-       SYS_GETRLIMIT              = 163
-       SYS_SETRLIMIT              = 164
-       SYS_GETRUSAGE              = 165
-       SYS_UMASK                  = 166
-       SYS_PRCTL                  = 167
-       SYS_GETCPU                 = 168
-       SYS_GETTIMEOFDAY           = 169
-       SYS_SETTIMEOFDAY           = 170
-       SYS_ADJTIMEX               = 171
-       SYS_GETPID                 = 172
-       SYS_GETPPID                = 173
-       SYS_GETUID                 = 174
-       SYS_GETEUID                = 175
-       SYS_GETGID                 = 176
-       SYS_GETEGID                = 177
-       SYS_GETTID                 = 178
-       SYS_SYSINFO                = 179
-       SYS_MQ_OPEN                = 180
-       SYS_MQ_UNLINK              = 181
-       SYS_MQ_TIMEDSEND           = 182
-       SYS_MQ_TIMEDRECEIVE        = 183
-       SYS_MQ_NOTIFY              = 184
-       SYS_MQ_GETSETATTR          = 185
-       SYS_MSGGET                 = 186
-       SYS_MSGCTL                 = 187
-       SYS_MSGRCV                 = 188
-       SYS_MSGSND                 = 189
-       SYS_SEMGET                 = 190
-       SYS_SEMCTL                 = 191
-       SYS_SEMTIMEDOP             = 192
-       SYS_SEMOP                  = 193
-       SYS_SHMGET                 = 194
-       SYS_SHMCTL                 = 195
-       SYS_SHMAT                  = 196
-       SYS_SHMDT                  = 197
-       SYS_SOCKET                 = 198
-       SYS_SOCKETPAIR             = 199
-       SYS_BIND                   = 200
-       SYS_LISTEN                 = 201
-       SYS_ACCEPT                 = 202
-       SYS_CONNECT                = 203
-       SYS_GETSOCKNAME            = 204
-       SYS_GETPEERNAME            = 205
-       SYS_SENDTO                 = 206
-       SYS_RECVFROM               = 207
-       SYS_SETSOCKOPT             = 208
-       SYS_GETSOCKOPT             = 209
-       SYS_SHUTDOWN               = 210
-       SYS_SENDMSG                = 211
-       SYS_RECVMSG                = 212
-       SYS_READAHEAD              = 213
-       SYS_BRK                    = 214
-       SYS_MUNMAP                 = 215
-       SYS_MREMAP                 = 216
-       SYS_ADD_KEY                = 217
-       SYS_REQUEST_KEY            = 218
-       SYS_KEYCTL                 = 219
-       SYS_CLONE                  = 220
-       SYS_EXECVE                 = 221
-       SYS_MMAP                   = 222
-       SYS_FADVISE64              = 223
-       SYS_SWAPON                 = 224
-       SYS_SWAPOFF                = 225
-       SYS_MPROTECT               = 226
-       SYS_MSYNC                  = 227
-       SYS_MLOCK                  = 228
-       SYS_MUNLOCK                = 229
-       SYS_MLOCKALL               = 230
-       SYS_MUNLOCKALL             = 231
-       SYS_MINCORE                = 232
-       SYS_MADVISE                = 233
-       SYS_REMAP_FILE_PAGES       = 234
-       SYS_MBIND                  = 235
-       SYS_GET_MEMPOLICY          = 236
-       SYS_SET_MEMPOLICY          = 237
-       SYS_MIGRATE_PAGES          = 238
-       SYS_MOVE_PAGES             = 239
-       SYS_RT_TGSIGQUEUEINFO      = 240
-       SYS_PERF_EVENT_OPEN        = 241
-       SYS_ACCEPT4                = 242
-       SYS_RECVMMSG               = 243
-       SYS_ARCH_SPECIFIC_SYSCALL  = 244
-       SYS_WAIT4                  = 260
-       SYS_PRLIMIT64              = 261
-       SYS_FANOTIFY_INIT          = 262
-       SYS_FANOTIFY_MARK          = 263
-       SYS_NAME_TO_HANDLE_AT      = 264
-       SYS_OPEN_BY_HANDLE_AT      = 265
-       SYS_CLOCK_ADJTIME          = 266
-       SYS_SYNCFS                 = 267
-       SYS_SETNS                  = 268
-       SYS_SENDMMSG               = 269
-       SYS_PROCESS_VM_READV       = 270
-       SYS_PROCESS_VM_WRITEV      = 271
-       SYS_KCMP                   = 272
-       SYS_FINIT_MODULE           = 273
-       SYS_SCHED_SETATTR          = 274
-       SYS_SCHED_GETATTR          = 275
-       SYS_RENAMEAT2              = 276
-       SYS_SECCOMP                = 277
-       SYS_GETRANDOM              = 278
-       SYS_MEMFD_CREATE           = 279
-       SYS_BPF                    = 280
-       SYS_EXECVEAT               = 281
-       SYS_USERFAULTFD            = 282
-       SYS_MEMBARRIER             = 283
-       SYS_MLOCK2                 = 284
-       SYS_COPY_FILE_RANGE        = 285
-       SYS_PREADV2                = 286
-       SYS_PWRITEV2               = 287
-       SYS_PKEY_MPROTECT          = 288
-       SYS_PKEY_ALLOC             = 289
-       SYS_PKEY_FREE              = 290
-       SYS_STATX                  = 291
-       SYS_IO_PGETEVENTS          = 292
-       SYS_RSEQ                   = 293
-       SYS_KEXEC_FILE_LOAD        = 294
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLONE3                 = 435
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_IO_SETUP                = 0
+       SYS_IO_DESTROY              = 1
+       SYS_IO_SUBMIT               = 2
+       SYS_IO_CANCEL               = 3
+       SYS_IO_GETEVENTS            = 4
+       SYS_SETXATTR                = 5
+       SYS_LSETXATTR               = 6
+       SYS_FSETXATTR               = 7
+       SYS_GETXATTR                = 8
+       SYS_LGETXATTR               = 9
+       SYS_FGETXATTR               = 10
+       SYS_LISTXATTR               = 11
+       SYS_LLISTXATTR              = 12
+       SYS_FLISTXATTR              = 13
+       SYS_REMOVEXATTR             = 14
+       SYS_LREMOVEXATTR            = 15
+       SYS_FREMOVEXATTR            = 16
+       SYS_GETCWD                  = 17
+       SYS_LOOKUP_DCOOKIE          = 18
+       SYS_EVENTFD2                = 19
+       SYS_EPOLL_CREATE1           = 20
+       SYS_EPOLL_CTL               = 21
+       SYS_EPOLL_PWAIT             = 22
+       SYS_DUP                     = 23
+       SYS_DUP3                    = 24
+       SYS_FCNTL                   = 25
+       SYS_INOTIFY_INIT1           = 26
+       SYS_INOTIFY_ADD_WATCH       = 27
+       SYS_INOTIFY_RM_WATCH        = 28
+       SYS_IOCTL                   = 29
+       SYS_IOPRIO_SET              = 30
+       SYS_IOPRIO_GET              = 31
+       SYS_FLOCK                   = 32
+       SYS_MKNODAT                 = 33
+       SYS_MKDIRAT                 = 34
+       SYS_UNLINKAT                = 35
+       SYS_SYMLINKAT               = 36
+       SYS_LINKAT                  = 37
+       SYS_UMOUNT2                 = 39
+       SYS_MOUNT                   = 40
+       SYS_PIVOT_ROOT              = 41
+       SYS_NFSSERVCTL              = 42
+       SYS_STATFS                  = 43
+       SYS_FSTATFS                 = 44
+       SYS_TRUNCATE                = 45
+       SYS_FTRUNCATE               = 46
+       SYS_FALLOCATE               = 47
+       SYS_FACCESSAT               = 48
+       SYS_CHDIR                   = 49
+       SYS_FCHDIR                  = 50
+       SYS_CHROOT                  = 51
+       SYS_FCHMOD                  = 52
+       SYS_FCHMODAT                = 53
+       SYS_FCHOWNAT                = 54
+       SYS_FCHOWN                  = 55
+       SYS_OPENAT                  = 56
+       SYS_CLOSE                   = 57
+       SYS_VHANGUP                 = 58
+       SYS_PIPE2                   = 59
+       SYS_QUOTACTL                = 60
+       SYS_GETDENTS64              = 61
+       SYS_LSEEK                   = 62
+       SYS_READ                    = 63
+       SYS_WRITE                   = 64
+       SYS_READV                   = 65
+       SYS_WRITEV                  = 66
+       SYS_PREAD64                 = 67
+       SYS_PWRITE64                = 68
+       SYS_PREADV                  = 69
+       SYS_PWRITEV                 = 70
+       SYS_SENDFILE                = 71
+       SYS_PSELECT6                = 72
+       SYS_PPOLL                   = 73
+       SYS_SIGNALFD4               = 74
+       SYS_VMSPLICE                = 75
+       SYS_SPLICE                  = 76
+       SYS_TEE                     = 77
+       SYS_READLINKAT              = 78
+       SYS_FSTATAT                 = 79
+       SYS_FSTAT                   = 80
+       SYS_SYNC                    = 81
+       SYS_FSYNC                   = 82
+       SYS_FDATASYNC               = 83
+       SYS_SYNC_FILE_RANGE         = 84
+       SYS_TIMERFD_CREATE          = 85
+       SYS_TIMERFD_SETTIME         = 86
+       SYS_TIMERFD_GETTIME         = 87
+       SYS_UTIMENSAT               = 88
+       SYS_ACCT                    = 89
+       SYS_CAPGET                  = 90
+       SYS_CAPSET                  = 91
+       SYS_PERSONALITY             = 92
+       SYS_EXIT                    = 93
+       SYS_EXIT_GROUP              = 94
+       SYS_WAITID                  = 95
+       SYS_SET_TID_ADDRESS         = 96
+       SYS_UNSHARE                 = 97
+       SYS_FUTEX                   = 98
+       SYS_SET_ROBUST_LIST         = 99
+       SYS_GET_ROBUST_LIST         = 100
+       SYS_NANOSLEEP               = 101
+       SYS_GETITIMER               = 102
+       SYS_SETITIMER               = 103
+       SYS_KEXEC_LOAD              = 104
+       SYS_INIT_MODULE             = 105
+       SYS_DELETE_MODULE           = 106
+       SYS_TIMER_CREATE            = 107
+       SYS_TIMER_GETTIME           = 108
+       SYS_TIMER_GETOVERRUN        = 109
+       SYS_TIMER_SETTIME           = 110
+       SYS_TIMER_DELETE            = 111
+       SYS_CLOCK_SETTIME           = 112
+       SYS_CLOCK_GETTIME           = 113
+       SYS_CLOCK_GETRES            = 114
+       SYS_CLOCK_NANOSLEEP         = 115
+       SYS_SYSLOG                  = 116
+       SYS_PTRACE                  = 117
+       SYS_SCHED_SETPARAM          = 118
+       SYS_SCHED_SETSCHEDULER      = 119
+       SYS_SCHED_GETSCHEDULER      = 120
+       SYS_SCHED_GETPARAM          = 121
+       SYS_SCHED_SETAFFINITY       = 122
+       SYS_SCHED_GETAFFINITY       = 123
+       SYS_SCHED_YIELD             = 124
+       SYS_SCHED_GET_PRIORITY_MAX  = 125
+       SYS_SCHED_GET_PRIORITY_MIN  = 126
+       SYS_SCHED_RR_GET_INTERVAL   = 127
+       SYS_RESTART_SYSCALL         = 128
+       SYS_KILL                    = 129
+       SYS_TKILL                   = 130
+       SYS_TGKILL                  = 131
+       SYS_SIGALTSTACK             = 132
+       SYS_RT_SIGSUSPEND           = 133
+       SYS_RT_SIGACTION            = 134
+       SYS_RT_SIGPROCMASK          = 135
+       SYS_RT_SIGPENDING           = 136
+       SYS_RT_SIGTIMEDWAIT         = 137
+       SYS_RT_SIGQUEUEINFO         = 138
+       SYS_RT_SIGRETURN            = 139
+       SYS_SETPRIORITY             = 140
+       SYS_GETPRIORITY             = 141
+       SYS_REBOOT                  = 142
+       SYS_SETREGID                = 143
+       SYS_SETGID                  = 144
+       SYS_SETREUID                = 145
+       SYS_SETUID                  = 146
+       SYS_SETRESUID               = 147
+       SYS_GETRESUID               = 148
+       SYS_SETRESGID               = 149
+       SYS_GETRESGID               = 150
+       SYS_SETFSUID                = 151
+       SYS_SETFSGID                = 152
+       SYS_TIMES                   = 153
+       SYS_SETPGID                 = 154
+       SYS_GETPGID                 = 155
+       SYS_GETSID                  = 156
+       SYS_SETSID                  = 157
+       SYS_GETGROUPS               = 158
+       SYS_SETGROUPS               = 159
+       SYS_UNAME                   = 160
+       SYS_SETHOSTNAME             = 161
+       SYS_SETDOMAINNAME           = 162
+       SYS_GETRLIMIT               = 163
+       SYS_SETRLIMIT               = 164
+       SYS_GETRUSAGE               = 165
+       SYS_UMASK                   = 166
+       SYS_PRCTL                   = 167
+       SYS_GETCPU                  = 168
+       SYS_GETTIMEOFDAY            = 169
+       SYS_SETTIMEOFDAY            = 170
+       SYS_ADJTIMEX                = 171
+       SYS_GETPID                  = 172
+       SYS_GETPPID                 = 173
+       SYS_GETUID                  = 174
+       SYS_GETEUID                 = 175
+       SYS_GETGID                  = 176
+       SYS_GETEGID                 = 177
+       SYS_GETTID                  = 178
+       SYS_SYSINFO                 = 179
+       SYS_MQ_OPEN                 = 180
+       SYS_MQ_UNLINK               = 181
+       SYS_MQ_TIMEDSEND            = 182
+       SYS_MQ_TIMEDRECEIVE         = 183
+       SYS_MQ_NOTIFY               = 184
+       SYS_MQ_GETSETATTR           = 185
+       SYS_MSGGET                  = 186
+       SYS_MSGCTL                  = 187
+       SYS_MSGRCV                  = 188
+       SYS_MSGSND                  = 189
+       SYS_SEMGET                  = 190
+       SYS_SEMCTL                  = 191
+       SYS_SEMTIMEDOP              = 192
+       SYS_SEMOP                   = 193
+       SYS_SHMGET                  = 194
+       SYS_SHMCTL                  = 195
+       SYS_SHMAT                   = 196
+       SYS_SHMDT                   = 197
+       SYS_SOCKET                  = 198
+       SYS_SOCKETPAIR              = 199
+       SYS_BIND                    = 200
+       SYS_LISTEN                  = 201
+       SYS_ACCEPT                  = 202
+       SYS_CONNECT                 = 203
+       SYS_GETSOCKNAME             = 204
+       SYS_GETPEERNAME             = 205
+       SYS_SENDTO                  = 206
+       SYS_RECVFROM                = 207
+       SYS_SETSOCKOPT              = 208
+       SYS_GETSOCKOPT              = 209
+       SYS_SHUTDOWN                = 210
+       SYS_SENDMSG                 = 211
+       SYS_RECVMSG                 = 212
+       SYS_READAHEAD               = 213
+       SYS_BRK                     = 214
+       SYS_MUNMAP                  = 215
+       SYS_MREMAP                  = 216
+       SYS_ADD_KEY                 = 217
+       SYS_REQUEST_KEY             = 218
+       SYS_KEYCTL                  = 219
+       SYS_CLONE                   = 220
+       SYS_EXECVE                  = 221
+       SYS_MMAP                    = 222
+       SYS_FADVISE64               = 223
+       SYS_SWAPON                  = 224
+       SYS_SWAPOFF                 = 225
+       SYS_MPROTECT                = 226
+       SYS_MSYNC                   = 227
+       SYS_MLOCK                   = 228
+       SYS_MUNLOCK                 = 229
+       SYS_MLOCKALL                = 230
+       SYS_MUNLOCKALL              = 231
+       SYS_MINCORE                 = 232
+       SYS_MADVISE                 = 233
+       SYS_REMAP_FILE_PAGES        = 234
+       SYS_MBIND                   = 235
+       SYS_GET_MEMPOLICY           = 236
+       SYS_SET_MEMPOLICY           = 237
+       SYS_MIGRATE_PAGES           = 238
+       SYS_MOVE_PAGES              = 239
+       SYS_RT_TGSIGQUEUEINFO       = 240
+       SYS_PERF_EVENT_OPEN         = 241
+       SYS_ACCEPT4                 = 242
+       SYS_RECVMMSG                = 243
+       SYS_ARCH_SPECIFIC_SYSCALL   = 244
+       SYS_WAIT4                   = 260
+       SYS_PRLIMIT64               = 261
+       SYS_FANOTIFY_INIT           = 262
+       SYS_FANOTIFY_MARK           = 263
+       SYS_NAME_TO_HANDLE_AT       = 264
+       SYS_OPEN_BY_HANDLE_AT       = 265
+       SYS_CLOCK_ADJTIME           = 266
+       SYS_SYNCFS                  = 267
+       SYS_SETNS                   = 268
+       SYS_SENDMMSG                = 269
+       SYS_PROCESS_VM_READV        = 270
+       SYS_PROCESS_VM_WRITEV       = 271
+       SYS_KCMP                    = 272
+       SYS_FINIT_MODULE            = 273
+       SYS_SCHED_SETATTR           = 274
+       SYS_SCHED_GETATTR           = 275
+       SYS_RENAMEAT2               = 276
+       SYS_SECCOMP                 = 277
+       SYS_GETRANDOM               = 278
+       SYS_MEMFD_CREATE            = 279
+       SYS_BPF                     = 280
+       SYS_EXECVEAT                = 281
+       SYS_USERFAULTFD             = 282
+       SYS_MEMBARRIER              = 283
+       SYS_MLOCK2                  = 284
+       SYS_COPY_FILE_RANGE         = 285
+       SYS_PREADV2                 = 286
+       SYS_PWRITEV2                = 287
+       SYS_PKEY_MPROTECT           = 288
+       SYS_PKEY_ALLOC              = 289
+       SYS_PKEY_FREE               = 290
+       SYS_STATX                   = 291
+       SYS_IO_PGETEVENTS           = 292
+       SYS_RSEQ                    = 293
+       SYS_KEXEC_FILE_LOAD         = 294
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLONE3                  = 435
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
 )
index aea5760cea26445a7d11806db1b893b4739906b6..3e791e6cd228b9930cf8b334628caf0db1de1f7d 100644 (file)
 package unix
 
 const (
-       SYS_EXIT                   = 1
-       SYS_FORK                   = 2
-       SYS_READ                   = 3
-       SYS_WRITE                  = 4
-       SYS_OPEN                   = 5
-       SYS_CLOSE                  = 6
-       SYS_RESTART_SYSCALL        = 7
-       SYS_CREAT                  = 8
-       SYS_LINK                   = 9
-       SYS_UNLINK                 = 10
-       SYS_EXECVE                 = 11
-       SYS_CHDIR                  = 12
-       SYS_MKNOD                  = 14
-       SYS_CHMOD                  = 15
-       SYS_LSEEK                  = 19
-       SYS_GETPID                 = 20
-       SYS_MOUNT                  = 21
-       SYS_UMOUNT                 = 22
-       SYS_PTRACE                 = 26
-       SYS_ALARM                  = 27
-       SYS_PAUSE                  = 29
-       SYS_UTIME                  = 30
-       SYS_ACCESS                 = 33
-       SYS_NICE                   = 34
-       SYS_SYNC                   = 36
-       SYS_KILL                   = 37
-       SYS_RENAME                 = 38
-       SYS_MKDIR                  = 39
-       SYS_RMDIR                  = 40
-       SYS_DUP                    = 41
-       SYS_PIPE                   = 42
-       SYS_TIMES                  = 43
-       SYS_BRK                    = 45
-       SYS_SIGNAL                 = 48
-       SYS_ACCT                   = 51
-       SYS_UMOUNT2                = 52
-       SYS_IOCTL                  = 54
-       SYS_FCNTL                  = 55
-       SYS_SETPGID                = 57
-       SYS_UMASK                  = 60
-       SYS_CHROOT                 = 61
-       SYS_USTAT                  = 62
-       SYS_DUP2                   = 63
-       SYS_GETPPID                = 64
-       SYS_GETPGRP                = 65
-       SYS_SETSID                 = 66
-       SYS_SIGACTION              = 67
-       SYS_SIGSUSPEND             = 72
-       SYS_SIGPENDING             = 73
-       SYS_SETHOSTNAME            = 74
-       SYS_SETRLIMIT              = 75
-       SYS_GETRUSAGE              = 77
-       SYS_GETTIMEOFDAY           = 78
-       SYS_SETTIMEOFDAY           = 79
-       SYS_SYMLINK                = 83
-       SYS_READLINK               = 85
-       SYS_USELIB                 = 86
-       SYS_SWAPON                 = 87
-       SYS_REBOOT                 = 88
-       SYS_READDIR                = 89
-       SYS_MMAP                   = 90
-       SYS_MUNMAP                 = 91
-       SYS_TRUNCATE               = 92
-       SYS_FTRUNCATE              = 93
-       SYS_FCHMOD                 = 94
-       SYS_GETPRIORITY            = 96
-       SYS_SETPRIORITY            = 97
-       SYS_STATFS                 = 99
-       SYS_FSTATFS                = 100
-       SYS_SOCKETCALL             = 102
-       SYS_SYSLOG                 = 103
-       SYS_SETITIMER              = 104
-       SYS_GETITIMER              = 105
-       SYS_STAT                   = 106
-       SYS_LSTAT                  = 107
-       SYS_FSTAT                  = 108
-       SYS_LOOKUP_DCOOKIE         = 110
-       SYS_VHANGUP                = 111
-       SYS_IDLE                   = 112
-       SYS_WAIT4                  = 114
-       SYS_SWAPOFF                = 115
-       SYS_SYSINFO                = 116
-       SYS_IPC                    = 117
-       SYS_FSYNC                  = 118
-       SYS_SIGRETURN              = 119
-       SYS_CLONE                  = 120
-       SYS_SETDOMAINNAME          = 121
-       SYS_UNAME                  = 122
-       SYS_ADJTIMEX               = 124
-       SYS_MPROTECT               = 125
-       SYS_SIGPROCMASK            = 126
-       SYS_CREATE_MODULE          = 127
-       SYS_INIT_MODULE            = 128
-       SYS_DELETE_MODULE          = 129
-       SYS_GET_KERNEL_SYMS        = 130
-       SYS_QUOTACTL               = 131
-       SYS_GETPGID                = 132
-       SYS_FCHDIR                 = 133
-       SYS_BDFLUSH                = 134
-       SYS_SYSFS                  = 135
-       SYS_PERSONALITY            = 136
-       SYS_AFS_SYSCALL            = 137
-       SYS_GETDENTS               = 141
-       SYS_SELECT                 = 142
-       SYS_FLOCK                  = 143
-       SYS_MSYNC                  = 144
-       SYS_READV                  = 145
-       SYS_WRITEV                 = 146
-       SYS_GETSID                 = 147
-       SYS_FDATASYNC              = 148
-       SYS__SYSCTL                = 149
-       SYS_MLOCK                  = 150
-       SYS_MUNLOCK                = 151
-       SYS_MLOCKALL               = 152
-       SYS_MUNLOCKALL             = 153
-       SYS_SCHED_SETPARAM         = 154
-       SYS_SCHED_GETPARAM         = 155
-       SYS_SCHED_SETSCHEDULER     = 156
-       SYS_SCHED_GETSCHEDULER     = 157
-       SYS_SCHED_YIELD            = 158
-       SYS_SCHED_GET_PRIORITY_MAX = 159
-       SYS_SCHED_GET_PRIORITY_MIN = 160
-       SYS_SCHED_RR_GET_INTERVAL  = 161
-       SYS_NANOSLEEP              = 162
-       SYS_MREMAP                 = 163
-       SYS_QUERY_MODULE           = 167
-       SYS_POLL                   = 168
-       SYS_NFSSERVCTL             = 169
-       SYS_PRCTL                  = 172
-       SYS_RT_SIGRETURN           = 173
-       SYS_RT_SIGACTION           = 174
-       SYS_RT_SIGPROCMASK         = 175
-       SYS_RT_SIGPENDING          = 176
-       SYS_RT_SIGTIMEDWAIT        = 177
-       SYS_RT_SIGQUEUEINFO        = 178
-       SYS_RT_SIGSUSPEND          = 179
-       SYS_PREAD64                = 180
-       SYS_PWRITE64               = 181
-       SYS_GETCWD                 = 183
-       SYS_CAPGET                 = 184
-       SYS_CAPSET                 = 185
-       SYS_SIGALTSTACK            = 186
-       SYS_SENDFILE               = 187
-       SYS_GETPMSG                = 188
-       SYS_PUTPMSG                = 189
-       SYS_VFORK                  = 190
-       SYS_GETRLIMIT              = 191
-       SYS_LCHOWN                 = 198
-       SYS_GETUID                 = 199
-       SYS_GETGID                 = 200
-       SYS_GETEUID                = 201
-       SYS_GETEGID                = 202
-       SYS_SETREUID               = 203
-       SYS_SETREGID               = 204
-       SYS_GETGROUPS              = 205
-       SYS_SETGROUPS              = 206
-       SYS_FCHOWN                 = 207
-       SYS_SETRESUID              = 208
-       SYS_GETRESUID              = 209
-       SYS_SETRESGID              = 210
-       SYS_GETRESGID              = 211
-       SYS_CHOWN                  = 212
-       SYS_SETUID                 = 213
-       SYS_SETGID                 = 214
-       SYS_SETFSUID               = 215
-       SYS_SETFSGID               = 216
-       SYS_PIVOT_ROOT             = 217
-       SYS_MINCORE                = 218
-       SYS_MADVISE                = 219
-       SYS_GETDENTS64             = 220
-       SYS_READAHEAD              = 222
-       SYS_SETXATTR               = 224
-       SYS_LSETXATTR              = 225
-       SYS_FSETXATTR              = 226
-       SYS_GETXATTR               = 227
-       SYS_LGETXATTR              = 228
-       SYS_FGETXATTR              = 229
-       SYS_LISTXATTR              = 230
-       SYS_LLISTXATTR             = 231
-       SYS_FLISTXATTR             = 232
-       SYS_REMOVEXATTR            = 233
-       SYS_LREMOVEXATTR           = 234
-       SYS_FREMOVEXATTR           = 235
-       SYS_GETTID                 = 236
-       SYS_TKILL                  = 237
-       SYS_FUTEX                  = 238
-       SYS_SCHED_SETAFFINITY      = 239
-       SYS_SCHED_GETAFFINITY      = 240
-       SYS_TGKILL                 = 241
-       SYS_IO_SETUP               = 243
-       SYS_IO_DESTROY             = 244
-       SYS_IO_GETEVENTS           = 245
-       SYS_IO_SUBMIT              = 246
-       SYS_IO_CANCEL              = 247
-       SYS_EXIT_GROUP             = 248
-       SYS_EPOLL_CREATE           = 249
-       SYS_EPOLL_CTL              = 250
-       SYS_EPOLL_WAIT             = 251
-       SYS_SET_TID_ADDRESS        = 252
-       SYS_FADVISE64              = 253
-       SYS_TIMER_CREATE           = 254
-       SYS_TIMER_SETTIME          = 255
-       SYS_TIMER_GETTIME          = 256
-       SYS_TIMER_GETOVERRUN       = 257
-       SYS_TIMER_DELETE           = 258
-       SYS_CLOCK_SETTIME          = 259
-       SYS_CLOCK_GETTIME          = 260
-       SYS_CLOCK_GETRES           = 261
-       SYS_CLOCK_NANOSLEEP        = 262
-       SYS_STATFS64               = 265
-       SYS_FSTATFS64              = 266
-       SYS_REMAP_FILE_PAGES       = 267
-       SYS_MBIND                  = 268
-       SYS_GET_MEMPOLICY          = 269
-       SYS_SET_MEMPOLICY          = 270
-       SYS_MQ_OPEN                = 271
-       SYS_MQ_UNLINK              = 272
-       SYS_MQ_TIMEDSEND           = 273
-       SYS_MQ_TIMEDRECEIVE        = 274
-       SYS_MQ_NOTIFY              = 275
-       SYS_MQ_GETSETATTR          = 276
-       SYS_KEXEC_LOAD             = 277
-       SYS_ADD_KEY                = 278
-       SYS_REQUEST_KEY            = 279
-       SYS_KEYCTL                 = 280
-       SYS_WAITID                 = 281
-       SYS_IOPRIO_SET             = 282
-       SYS_IOPRIO_GET             = 283
-       SYS_INOTIFY_INIT           = 284
-       SYS_INOTIFY_ADD_WATCH      = 285
-       SYS_INOTIFY_RM_WATCH       = 286
-       SYS_MIGRATE_PAGES          = 287
-       SYS_OPENAT                 = 288
-       SYS_MKDIRAT                = 289
-       SYS_MKNODAT                = 290
-       SYS_FCHOWNAT               = 291
-       SYS_FUTIMESAT              = 292
-       SYS_NEWFSTATAT             = 293
-       SYS_UNLINKAT               = 294
-       SYS_RENAMEAT               = 295
-       SYS_LINKAT                 = 296
-       SYS_SYMLINKAT              = 297
-       SYS_READLINKAT             = 298
-       SYS_FCHMODAT               = 299
-       SYS_FACCESSAT              = 300
-       SYS_PSELECT6               = 301
-       SYS_PPOLL                  = 302
-       SYS_UNSHARE                = 303
-       SYS_SET_ROBUST_LIST        = 304
-       SYS_GET_ROBUST_LIST        = 305
-       SYS_SPLICE                 = 306
-       SYS_SYNC_FILE_RANGE        = 307
-       SYS_TEE                    = 308
-       SYS_VMSPLICE               = 309
-       SYS_MOVE_PAGES             = 310
-       SYS_GETCPU                 = 311
-       SYS_EPOLL_PWAIT            = 312
-       SYS_UTIMES                 = 313
-       SYS_FALLOCATE              = 314
-       SYS_UTIMENSAT              = 315
-       SYS_SIGNALFD               = 316
-       SYS_TIMERFD                = 317
-       SYS_EVENTFD                = 318
-       SYS_TIMERFD_CREATE         = 319
-       SYS_TIMERFD_SETTIME        = 320
-       SYS_TIMERFD_GETTIME        = 321
-       SYS_SIGNALFD4              = 322
-       SYS_EVENTFD2               = 323
-       SYS_INOTIFY_INIT1          = 324
-       SYS_PIPE2                  = 325
-       SYS_DUP3                   = 326
-       SYS_EPOLL_CREATE1          = 327
-       SYS_PREADV                 = 328
-       SYS_PWRITEV                = 329
-       SYS_RT_TGSIGQUEUEINFO      = 330
-       SYS_PERF_EVENT_OPEN        = 331
-       SYS_FANOTIFY_INIT          = 332
-       SYS_FANOTIFY_MARK          = 333
-       SYS_PRLIMIT64              = 334
-       SYS_NAME_TO_HANDLE_AT      = 335
-       SYS_OPEN_BY_HANDLE_AT      = 336
-       SYS_CLOCK_ADJTIME          = 337
-       SYS_SYNCFS                 = 338
-       SYS_SETNS                  = 339
-       SYS_PROCESS_VM_READV       = 340
-       SYS_PROCESS_VM_WRITEV      = 341
-       SYS_S390_RUNTIME_INSTR     = 342
-       SYS_KCMP                   = 343
-       SYS_FINIT_MODULE           = 344
-       SYS_SCHED_SETATTR          = 345
-       SYS_SCHED_GETATTR          = 346
-       SYS_RENAMEAT2              = 347
-       SYS_SECCOMP                = 348
-       SYS_GETRANDOM              = 349
-       SYS_MEMFD_CREATE           = 350
-       SYS_BPF                    = 351
-       SYS_S390_PCI_MMIO_WRITE    = 352
-       SYS_S390_PCI_MMIO_READ     = 353
-       SYS_EXECVEAT               = 354
-       SYS_USERFAULTFD            = 355
-       SYS_MEMBARRIER             = 356
-       SYS_RECVMMSG               = 357
-       SYS_SENDMMSG               = 358
-       SYS_SOCKET                 = 359
-       SYS_SOCKETPAIR             = 360
-       SYS_BIND                   = 361
-       SYS_CONNECT                = 362
-       SYS_LISTEN                 = 363
-       SYS_ACCEPT4                = 364
-       SYS_GETSOCKOPT             = 365
-       SYS_SETSOCKOPT             = 366
-       SYS_GETSOCKNAME            = 367
-       SYS_GETPEERNAME            = 368
-       SYS_SENDTO                 = 369
-       SYS_SENDMSG                = 370
-       SYS_RECVFROM               = 371
-       SYS_RECVMSG                = 372
-       SYS_SHUTDOWN               = 373
-       SYS_MLOCK2                 = 374
-       SYS_COPY_FILE_RANGE        = 375
-       SYS_PREADV2                = 376
-       SYS_PWRITEV2               = 377
-       SYS_S390_GUARDED_STORAGE   = 378
-       SYS_STATX                  = 379
-       SYS_S390_STHYI             = 380
-       SYS_KEXEC_FILE_LOAD        = 381
-       SYS_IO_PGETEVENTS          = 382
-       SYS_RSEQ                   = 383
-       SYS_PKEY_MPROTECT          = 384
-       SYS_PKEY_ALLOC             = 385
-       SYS_PKEY_FREE              = 386
-       SYS_SEMTIMEDOP             = 392
-       SYS_SEMGET                 = 393
-       SYS_SEMCTL                 = 394
-       SYS_SHMGET                 = 395
-       SYS_SHMCTL                 = 396
-       SYS_SHMAT                  = 397
-       SYS_SHMDT                  = 398
-       SYS_MSGGET                 = 399
-       SYS_MSGSND                 = 400
-       SYS_MSGRCV                 = 401
-       SYS_MSGCTL                 = 402
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLONE3                 = 435
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_EXIT                    = 1
+       SYS_FORK                    = 2
+       SYS_READ                    = 3
+       SYS_WRITE                   = 4
+       SYS_OPEN                    = 5
+       SYS_CLOSE                   = 6
+       SYS_RESTART_SYSCALL         = 7
+       SYS_CREAT                   = 8
+       SYS_LINK                    = 9
+       SYS_UNLINK                  = 10
+       SYS_EXECVE                  = 11
+       SYS_CHDIR                   = 12
+       SYS_MKNOD                   = 14
+       SYS_CHMOD                   = 15
+       SYS_LSEEK                   = 19
+       SYS_GETPID                  = 20
+       SYS_MOUNT                   = 21
+       SYS_UMOUNT                  = 22
+       SYS_PTRACE                  = 26
+       SYS_ALARM                   = 27
+       SYS_PAUSE                   = 29
+       SYS_UTIME                   = 30
+       SYS_ACCESS                  = 33
+       SYS_NICE                    = 34
+       SYS_SYNC                    = 36
+       SYS_KILL                    = 37
+       SYS_RENAME                  = 38
+       SYS_MKDIR                   = 39
+       SYS_RMDIR                   = 40
+       SYS_DUP                     = 41
+       SYS_PIPE                    = 42
+       SYS_TIMES                   = 43
+       SYS_BRK                     = 45
+       SYS_SIGNAL                  = 48
+       SYS_ACCT                    = 51
+       SYS_UMOUNT2                 = 52
+       SYS_IOCTL                   = 54
+       SYS_FCNTL                   = 55
+       SYS_SETPGID                 = 57
+       SYS_UMASK                   = 60
+       SYS_CHROOT                  = 61
+       SYS_USTAT                   = 62
+       SYS_DUP2                    = 63
+       SYS_GETPPID                 = 64
+       SYS_GETPGRP                 = 65
+       SYS_SETSID                  = 66
+       SYS_SIGACTION               = 67
+       SYS_SIGSUSPEND              = 72
+       SYS_SIGPENDING              = 73
+       SYS_SETHOSTNAME             = 74
+       SYS_SETRLIMIT               = 75
+       SYS_GETRUSAGE               = 77
+       SYS_GETTIMEOFDAY            = 78
+       SYS_SETTIMEOFDAY            = 79
+       SYS_SYMLINK                 = 83
+       SYS_READLINK                = 85
+       SYS_USELIB                  = 86
+       SYS_SWAPON                  = 87
+       SYS_REBOOT                  = 88
+       SYS_READDIR                 = 89
+       SYS_MMAP                    = 90
+       SYS_MUNMAP                  = 91
+       SYS_TRUNCATE                = 92
+       SYS_FTRUNCATE               = 93
+       SYS_FCHMOD                  = 94
+       SYS_GETPRIORITY             = 96
+       SYS_SETPRIORITY             = 97
+       SYS_STATFS                  = 99
+       SYS_FSTATFS                 = 100
+       SYS_SOCKETCALL              = 102
+       SYS_SYSLOG                  = 103
+       SYS_SETITIMER               = 104
+       SYS_GETITIMER               = 105
+       SYS_STAT                    = 106
+       SYS_LSTAT                   = 107
+       SYS_FSTAT                   = 108
+       SYS_LOOKUP_DCOOKIE          = 110
+       SYS_VHANGUP                 = 111
+       SYS_IDLE                    = 112
+       SYS_WAIT4                   = 114
+       SYS_SWAPOFF                 = 115
+       SYS_SYSINFO                 = 116
+       SYS_IPC                     = 117
+       SYS_FSYNC                   = 118
+       SYS_SIGRETURN               = 119
+       SYS_CLONE                   = 120
+       SYS_SETDOMAINNAME           = 121
+       SYS_UNAME                   = 122
+       SYS_ADJTIMEX                = 124
+       SYS_MPROTECT                = 125
+       SYS_SIGPROCMASK             = 126
+       SYS_CREATE_MODULE           = 127
+       SYS_INIT_MODULE             = 128
+       SYS_DELETE_MODULE           = 129
+       SYS_GET_KERNEL_SYMS         = 130
+       SYS_QUOTACTL                = 131
+       SYS_GETPGID                 = 132
+       SYS_FCHDIR                  = 133
+       SYS_BDFLUSH                 = 134
+       SYS_SYSFS                   = 135
+       SYS_PERSONALITY             = 136
+       SYS_AFS_SYSCALL             = 137
+       SYS_GETDENTS                = 141
+       SYS_SELECT                  = 142
+       SYS_FLOCK                   = 143
+       SYS_MSYNC                   = 144
+       SYS_READV                   = 145
+       SYS_WRITEV                  = 146
+       SYS_GETSID                  = 147
+       SYS_FDATASYNC               = 148
+       SYS__SYSCTL                 = 149
+       SYS_MLOCK                   = 150
+       SYS_MUNLOCK                 = 151
+       SYS_MLOCKALL                = 152
+       SYS_MUNLOCKALL              = 153
+       SYS_SCHED_SETPARAM          = 154
+       SYS_SCHED_GETPARAM          = 155
+       SYS_SCHED_SETSCHEDULER      = 156
+       SYS_SCHED_GETSCHEDULER      = 157
+       SYS_SCHED_YIELD             = 158
+       SYS_SCHED_GET_PRIORITY_MAX  = 159
+       SYS_SCHED_GET_PRIORITY_MIN  = 160
+       SYS_SCHED_RR_GET_INTERVAL   = 161
+       SYS_NANOSLEEP               = 162
+       SYS_MREMAP                  = 163
+       SYS_QUERY_MODULE            = 167
+       SYS_POLL                    = 168
+       SYS_NFSSERVCTL              = 169
+       SYS_PRCTL                   = 172
+       SYS_RT_SIGRETURN            = 173
+       SYS_RT_SIGACTION            = 174
+       SYS_RT_SIGPROCMASK          = 175
+       SYS_RT_SIGPENDING           = 176
+       SYS_RT_SIGTIMEDWAIT         = 177
+       SYS_RT_SIGQUEUEINFO         = 178
+       SYS_RT_SIGSUSPEND           = 179
+       SYS_PREAD64                 = 180
+       SYS_PWRITE64                = 181
+       SYS_GETCWD                  = 183
+       SYS_CAPGET                  = 184
+       SYS_CAPSET                  = 185
+       SYS_SIGALTSTACK             = 186
+       SYS_SENDFILE                = 187
+       SYS_GETPMSG                 = 188
+       SYS_PUTPMSG                 = 189
+       SYS_VFORK                   = 190
+       SYS_GETRLIMIT               = 191
+       SYS_LCHOWN                  = 198
+       SYS_GETUID                  = 199
+       SYS_GETGID                  = 200
+       SYS_GETEUID                 = 201
+       SYS_GETEGID                 = 202
+       SYS_SETREUID                = 203
+       SYS_SETREGID                = 204
+       SYS_GETGROUPS               = 205
+       SYS_SETGROUPS               = 206
+       SYS_FCHOWN                  = 207
+       SYS_SETRESUID               = 208
+       SYS_GETRESUID               = 209
+       SYS_SETRESGID               = 210
+       SYS_GETRESGID               = 211
+       SYS_CHOWN                   = 212
+       SYS_SETUID                  = 213
+       SYS_SETGID                  = 214
+       SYS_SETFSUID                = 215
+       SYS_SETFSGID                = 216
+       SYS_PIVOT_ROOT              = 217
+       SYS_MINCORE                 = 218
+       SYS_MADVISE                 = 219
+       SYS_GETDENTS64              = 220
+       SYS_READAHEAD               = 222
+       SYS_SETXATTR                = 224
+       SYS_LSETXATTR               = 225
+       SYS_FSETXATTR               = 226
+       SYS_GETXATTR                = 227
+       SYS_LGETXATTR               = 228
+       SYS_FGETXATTR               = 229
+       SYS_LISTXATTR               = 230
+       SYS_LLISTXATTR              = 231
+       SYS_FLISTXATTR              = 232
+       SYS_REMOVEXATTR             = 233
+       SYS_LREMOVEXATTR            = 234
+       SYS_FREMOVEXATTR            = 235
+       SYS_GETTID                  = 236
+       SYS_TKILL                   = 237
+       SYS_FUTEX                   = 238
+       SYS_SCHED_SETAFFINITY       = 239
+       SYS_SCHED_GETAFFINITY       = 240
+       SYS_TGKILL                  = 241
+       SYS_IO_SETUP                = 243
+       SYS_IO_DESTROY              = 244
+       SYS_IO_GETEVENTS            = 245
+       SYS_IO_SUBMIT               = 246
+       SYS_IO_CANCEL               = 247
+       SYS_EXIT_GROUP              = 248
+       SYS_EPOLL_CREATE            = 249
+       SYS_EPOLL_CTL               = 250
+       SYS_EPOLL_WAIT              = 251
+       SYS_SET_TID_ADDRESS         = 252
+       SYS_FADVISE64               = 253
+       SYS_TIMER_CREATE            = 254
+       SYS_TIMER_SETTIME           = 255
+       SYS_TIMER_GETTIME           = 256
+       SYS_TIMER_GETOVERRUN        = 257
+       SYS_TIMER_DELETE            = 258
+       SYS_CLOCK_SETTIME           = 259
+       SYS_CLOCK_GETTIME           = 260
+       SYS_CLOCK_GETRES            = 261
+       SYS_CLOCK_NANOSLEEP         = 262
+       SYS_STATFS64                = 265
+       SYS_FSTATFS64               = 266
+       SYS_REMAP_FILE_PAGES        = 267
+       SYS_MBIND                   = 268
+       SYS_GET_MEMPOLICY           = 269
+       SYS_SET_MEMPOLICY           = 270
+       SYS_MQ_OPEN                 = 271
+       SYS_MQ_UNLINK               = 272
+       SYS_MQ_TIMEDSEND            = 273
+       SYS_MQ_TIMEDRECEIVE         = 274
+       SYS_MQ_NOTIFY               = 275
+       SYS_MQ_GETSETATTR           = 276
+       SYS_KEXEC_LOAD              = 277
+       SYS_ADD_KEY                 = 278
+       SYS_REQUEST_KEY             = 279
+       SYS_KEYCTL                  = 280
+       SYS_WAITID                  = 281
+       SYS_IOPRIO_SET              = 282
+       SYS_IOPRIO_GET              = 283
+       SYS_INOTIFY_INIT            = 284
+       SYS_INOTIFY_ADD_WATCH       = 285
+       SYS_INOTIFY_RM_WATCH        = 286
+       SYS_MIGRATE_PAGES           = 287
+       SYS_OPENAT                  = 288
+       SYS_MKDIRAT                 = 289
+       SYS_MKNODAT                 = 290
+       SYS_FCHOWNAT                = 291
+       SYS_FUTIMESAT               = 292
+       SYS_NEWFSTATAT              = 293
+       SYS_UNLINKAT                = 294
+       SYS_RENAMEAT                = 295
+       SYS_LINKAT                  = 296
+       SYS_SYMLINKAT               = 297
+       SYS_READLINKAT              = 298
+       SYS_FCHMODAT                = 299
+       SYS_FACCESSAT               = 300
+       SYS_PSELECT6                = 301
+       SYS_PPOLL                   = 302
+       SYS_UNSHARE                 = 303
+       SYS_SET_ROBUST_LIST         = 304
+       SYS_GET_ROBUST_LIST         = 305
+       SYS_SPLICE                  = 306
+       SYS_SYNC_FILE_RANGE         = 307
+       SYS_TEE                     = 308
+       SYS_VMSPLICE                = 309
+       SYS_MOVE_PAGES              = 310
+       SYS_GETCPU                  = 311
+       SYS_EPOLL_PWAIT             = 312
+       SYS_UTIMES                  = 313
+       SYS_FALLOCATE               = 314
+       SYS_UTIMENSAT               = 315
+       SYS_SIGNALFD                = 316
+       SYS_TIMERFD                 = 317
+       SYS_EVENTFD                 = 318
+       SYS_TIMERFD_CREATE          = 319
+       SYS_TIMERFD_SETTIME         = 320
+       SYS_TIMERFD_GETTIME         = 321
+       SYS_SIGNALFD4               = 322
+       SYS_EVENTFD2                = 323
+       SYS_INOTIFY_INIT1           = 324
+       SYS_PIPE2                   = 325
+       SYS_DUP3                    = 326
+       SYS_EPOLL_CREATE1           = 327
+       SYS_PREADV                  = 328
+       SYS_PWRITEV                 = 329
+       SYS_RT_TGSIGQUEUEINFO       = 330
+       SYS_PERF_EVENT_OPEN         = 331
+       SYS_FANOTIFY_INIT           = 332
+       SYS_FANOTIFY_MARK           = 333
+       SYS_PRLIMIT64               = 334
+       SYS_NAME_TO_HANDLE_AT       = 335
+       SYS_OPEN_BY_HANDLE_AT       = 336
+       SYS_CLOCK_ADJTIME           = 337
+       SYS_SYNCFS                  = 338
+       SYS_SETNS                   = 339
+       SYS_PROCESS_VM_READV        = 340
+       SYS_PROCESS_VM_WRITEV       = 341
+       SYS_S390_RUNTIME_INSTR      = 342
+       SYS_KCMP                    = 343
+       SYS_FINIT_MODULE            = 344
+       SYS_SCHED_SETATTR           = 345
+       SYS_SCHED_GETATTR           = 346
+       SYS_RENAMEAT2               = 347
+       SYS_SECCOMP                 = 348
+       SYS_GETRANDOM               = 349
+       SYS_MEMFD_CREATE            = 350
+       SYS_BPF                     = 351
+       SYS_S390_PCI_MMIO_WRITE     = 352
+       SYS_S390_PCI_MMIO_READ      = 353
+       SYS_EXECVEAT                = 354
+       SYS_USERFAULTFD             = 355
+       SYS_MEMBARRIER              = 356
+       SYS_RECVMMSG                = 357
+       SYS_SENDMMSG                = 358
+       SYS_SOCKET                  = 359
+       SYS_SOCKETPAIR              = 360
+       SYS_BIND                    = 361
+       SYS_CONNECT                 = 362
+       SYS_LISTEN                  = 363
+       SYS_ACCEPT4                 = 364
+       SYS_GETSOCKOPT              = 365
+       SYS_SETSOCKOPT              = 366
+       SYS_GETSOCKNAME             = 367
+       SYS_GETPEERNAME             = 368
+       SYS_SENDTO                  = 369
+       SYS_SENDMSG                 = 370
+       SYS_RECVFROM                = 371
+       SYS_RECVMSG                 = 372
+       SYS_SHUTDOWN                = 373
+       SYS_MLOCK2                  = 374
+       SYS_COPY_FILE_RANGE         = 375
+       SYS_PREADV2                 = 376
+       SYS_PWRITEV2                = 377
+       SYS_S390_GUARDED_STORAGE    = 378
+       SYS_STATX                   = 379
+       SYS_S390_STHYI              = 380
+       SYS_KEXEC_FILE_LOAD         = 381
+       SYS_IO_PGETEVENTS           = 382
+       SYS_RSEQ                    = 383
+       SYS_PKEY_MPROTECT           = 384
+       SYS_PKEY_ALLOC              = 385
+       SYS_PKEY_FREE               = 386
+       SYS_SEMTIMEDOP              = 392
+       SYS_SEMGET                  = 393
+       SYS_SEMCTL                  = 394
+       SYS_SHMGET                  = 395
+       SYS_SHMCTL                  = 396
+       SYS_SHMAT                   = 397
+       SYS_SHMDT                   = 398
+       SYS_MSGGET                  = 399
+       SYS_MSGSND                  = 400
+       SYS_MSGRCV                  = 401
+       SYS_MSGCTL                  = 402
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLONE3                  = 435
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
 )
index 488ca848d17616111630e616e7f5c78750278a46..78802a5cf7cd6ed4b249382ba4700a8b4cc97168 100644 (file)
 package unix
 
 const (
-       SYS_RESTART_SYSCALL        = 0
-       SYS_EXIT                   = 1
-       SYS_FORK                   = 2
-       SYS_READ                   = 3
-       SYS_WRITE                  = 4
-       SYS_OPEN                   = 5
-       SYS_CLOSE                  = 6
-       SYS_WAIT4                  = 7
-       SYS_CREAT                  = 8
-       SYS_LINK                   = 9
-       SYS_UNLINK                 = 10
-       SYS_EXECV                  = 11
-       SYS_CHDIR                  = 12
-       SYS_CHOWN                  = 13
-       SYS_MKNOD                  = 14
-       SYS_CHMOD                  = 15
-       SYS_LCHOWN                 = 16
-       SYS_BRK                    = 17
-       SYS_PERFCTR                = 18
-       SYS_LSEEK                  = 19
-       SYS_GETPID                 = 20
-       SYS_CAPGET                 = 21
-       SYS_CAPSET                 = 22
-       SYS_SETUID                 = 23
-       SYS_GETUID                 = 24
-       SYS_VMSPLICE               = 25
-       SYS_PTRACE                 = 26
-       SYS_ALARM                  = 27
-       SYS_SIGALTSTACK            = 28
-       SYS_PAUSE                  = 29
-       SYS_UTIME                  = 30
-       SYS_ACCESS                 = 33
-       SYS_NICE                   = 34
-       SYS_SYNC                   = 36
-       SYS_KILL                   = 37
-       SYS_STAT                   = 38
-       SYS_SENDFILE               = 39
-       SYS_LSTAT                  = 40
-       SYS_DUP                    = 41
-       SYS_PIPE                   = 42
-       SYS_TIMES                  = 43
-       SYS_UMOUNT2                = 45
-       SYS_SETGID                 = 46
-       SYS_GETGID                 = 47
-       SYS_SIGNAL                 = 48
-       SYS_GETEUID                = 49
-       SYS_GETEGID                = 50
-       SYS_ACCT                   = 51
-       SYS_MEMORY_ORDERING        = 52
-       SYS_IOCTL                  = 54
-       SYS_REBOOT                 = 55
-       SYS_SYMLINK                = 57
-       SYS_READLINK               = 58
-       SYS_EXECVE                 = 59
-       SYS_UMASK                  = 60
-       SYS_CHROOT                 = 61
-       SYS_FSTAT                  = 62
-       SYS_FSTAT64                = 63
-       SYS_GETPAGESIZE            = 64
-       SYS_MSYNC                  = 65
-       SYS_VFORK                  = 66
-       SYS_PREAD64                = 67
-       SYS_PWRITE64               = 68
-       SYS_MMAP                   = 71
-       SYS_MUNMAP                 = 73
-       SYS_MPROTECT               = 74
-       SYS_MADVISE                = 75
-       SYS_VHANGUP                = 76
-       SYS_MINCORE                = 78
-       SYS_GETGROUPS              = 79
-       SYS_SETGROUPS              = 80
-       SYS_GETPGRP                = 81
-       SYS_SETITIMER              = 83
-       SYS_SWAPON                 = 85
-       SYS_GETITIMER              = 86
-       SYS_SETHOSTNAME            = 88
-       SYS_DUP2                   = 90
-       SYS_FCNTL                  = 92
-       SYS_SELECT                 = 93
-       SYS_FSYNC                  = 95
-       SYS_SETPRIORITY            = 96
-       SYS_SOCKET                 = 97
-       SYS_CONNECT                = 98
-       SYS_ACCEPT                 = 99
-       SYS_GETPRIORITY            = 100
-       SYS_RT_SIGRETURN           = 101
-       SYS_RT_SIGACTION           = 102
-       SYS_RT_SIGPROCMASK         = 103
-       SYS_RT_SIGPENDING          = 104
-       SYS_RT_SIGTIMEDWAIT        = 105
-       SYS_RT_SIGQUEUEINFO        = 106
-       SYS_RT_SIGSUSPEND          = 107
-       SYS_SETRESUID              = 108
-       SYS_GETRESUID              = 109
-       SYS_SETRESGID              = 110
-       SYS_GETRESGID              = 111
-       SYS_RECVMSG                = 113
-       SYS_SENDMSG                = 114
-       SYS_GETTIMEOFDAY           = 116
-       SYS_GETRUSAGE              = 117
-       SYS_GETSOCKOPT             = 118
-       SYS_GETCWD                 = 119
-       SYS_READV                  = 120
-       SYS_WRITEV                 = 121
-       SYS_SETTIMEOFDAY           = 122
-       SYS_FCHOWN                 = 123
-       SYS_FCHMOD                 = 124
-       SYS_RECVFROM               = 125
-       SYS_SETREUID               = 126
-       SYS_SETREGID               = 127
-       SYS_RENAME                 = 128
-       SYS_TRUNCATE               = 129
-       SYS_FTRUNCATE              = 130
-       SYS_FLOCK                  = 131
-       SYS_LSTAT64                = 132
-       SYS_SENDTO                 = 133
-       SYS_SHUTDOWN               = 134
-       SYS_SOCKETPAIR             = 135
-       SYS_MKDIR                  = 136
-       SYS_RMDIR                  = 137
-       SYS_UTIMES                 = 138
-       SYS_STAT64                 = 139
-       SYS_SENDFILE64             = 140
-       SYS_GETPEERNAME            = 141
-       SYS_FUTEX                  = 142
-       SYS_GETTID                 = 143
-       SYS_GETRLIMIT              = 144
-       SYS_SETRLIMIT              = 145
-       SYS_PIVOT_ROOT             = 146
-       SYS_PRCTL                  = 147
-       SYS_PCICONFIG_READ         = 148
-       SYS_PCICONFIG_WRITE        = 149
-       SYS_GETSOCKNAME            = 150
-       SYS_INOTIFY_INIT           = 151
-       SYS_INOTIFY_ADD_WATCH      = 152
-       SYS_POLL                   = 153
-       SYS_GETDENTS64             = 154
-       SYS_INOTIFY_RM_WATCH       = 156
-       SYS_STATFS                 = 157
-       SYS_FSTATFS                = 158
-       SYS_UMOUNT                 = 159
-       SYS_SCHED_SET_AFFINITY     = 160
-       SYS_SCHED_GET_AFFINITY     = 161
-       SYS_GETDOMAINNAME          = 162
-       SYS_SETDOMAINNAME          = 163
-       SYS_UTRAP_INSTALL          = 164
-       SYS_QUOTACTL               = 165
-       SYS_SET_TID_ADDRESS        = 166
-       SYS_MOUNT                  = 167
-       SYS_USTAT                  = 168
-       SYS_SETXATTR               = 169
-       SYS_LSETXATTR              = 170
-       SYS_FSETXATTR              = 171
-       SYS_GETXATTR               = 172
-       SYS_LGETXATTR              = 173
-       SYS_GETDENTS               = 174
-       SYS_SETSID                 = 175
-       SYS_FCHDIR                 = 176
-       SYS_FGETXATTR              = 177
-       SYS_LISTXATTR              = 178
-       SYS_LLISTXATTR             = 179
-       SYS_FLISTXATTR             = 180
-       SYS_REMOVEXATTR            = 181
-       SYS_LREMOVEXATTR           = 182
-       SYS_SIGPENDING             = 183
-       SYS_QUERY_MODULE           = 184
-       SYS_SETPGID                = 185
-       SYS_FREMOVEXATTR           = 186
-       SYS_TKILL                  = 187
-       SYS_EXIT_GROUP             = 188
-       SYS_UNAME                  = 189
-       SYS_INIT_MODULE            = 190
-       SYS_PERSONALITY            = 191
-       SYS_REMAP_FILE_PAGES       = 192
-       SYS_EPOLL_CREATE           = 193
-       SYS_EPOLL_CTL              = 194
-       SYS_EPOLL_WAIT             = 195
-       SYS_IOPRIO_SET             = 196
-       SYS_GETPPID                = 197
-       SYS_SIGACTION              = 198
-       SYS_SGETMASK               = 199
-       SYS_SSETMASK               = 200
-       SYS_SIGSUSPEND             = 201
-       SYS_OLDLSTAT               = 202
-       SYS_USELIB                 = 203
-       SYS_READDIR                = 204
-       SYS_READAHEAD              = 205
-       SYS_SOCKETCALL             = 206
-       SYS_SYSLOG                 = 207
-       SYS_LOOKUP_DCOOKIE         = 208
-       SYS_FADVISE64              = 209
-       SYS_FADVISE64_64           = 210
-       SYS_TGKILL                 = 211
-       SYS_WAITPID                = 212
-       SYS_SWAPOFF                = 213
-       SYS_SYSINFO                = 214
-       SYS_IPC                    = 215
-       SYS_SIGRETURN              = 216
-       SYS_CLONE                  = 217
-       SYS_IOPRIO_GET             = 218
-       SYS_ADJTIMEX               = 219
-       SYS_SIGPROCMASK            = 220
-       SYS_CREATE_MODULE          = 221
-       SYS_DELETE_MODULE          = 222
-       SYS_GET_KERNEL_SYMS        = 223
-       SYS_GETPGID                = 224
-       SYS_BDFLUSH                = 225
-       SYS_SYSFS                  = 226
-       SYS_AFS_SYSCALL            = 227
-       SYS_SETFSUID               = 228
-       SYS_SETFSGID               = 229
-       SYS__NEWSELECT             = 230
-       SYS_SPLICE                 = 232
-       SYS_STIME                  = 233
-       SYS_STATFS64               = 234
-       SYS_FSTATFS64              = 235
-       SYS__LLSEEK                = 236
-       SYS_MLOCK                  = 237
-       SYS_MUNLOCK                = 238
-       SYS_MLOCKALL               = 239
-       SYS_MUNLOCKALL             = 240
-       SYS_SCHED_SETPARAM         = 241
-       SYS_SCHED_GETPARAM         = 242
-       SYS_SCHED_SETSCHEDULER     = 243
-       SYS_SCHED_GETSCHEDULER     = 244
-       SYS_SCHED_YIELD            = 245
-       SYS_SCHED_GET_PRIORITY_MAX = 246
-       SYS_SCHED_GET_PRIORITY_MIN = 247
-       SYS_SCHED_RR_GET_INTERVAL  = 248
-       SYS_NANOSLEEP              = 249
-       SYS_MREMAP                 = 250
-       SYS__SYSCTL                = 251
-       SYS_GETSID                 = 252
-       SYS_FDATASYNC              = 253
-       SYS_NFSSERVCTL             = 254
-       SYS_SYNC_FILE_RANGE        = 255
-       SYS_CLOCK_SETTIME          = 256
-       SYS_CLOCK_GETTIME          = 257
-       SYS_CLOCK_GETRES           = 258
-       SYS_CLOCK_NANOSLEEP        = 259
-       SYS_SCHED_GETAFFINITY      = 260
-       SYS_SCHED_SETAFFINITY      = 261
-       SYS_TIMER_SETTIME          = 262
-       SYS_TIMER_GETTIME          = 263
-       SYS_TIMER_GETOVERRUN       = 264
-       SYS_TIMER_DELETE           = 265
-       SYS_TIMER_CREATE           = 266
-       SYS_VSERVER                = 267
-       SYS_IO_SETUP               = 268
-       SYS_IO_DESTROY             = 269
-       SYS_IO_SUBMIT              = 270
-       SYS_IO_CANCEL              = 271
-       SYS_IO_GETEVENTS           = 272
-       SYS_MQ_OPEN                = 273
-       SYS_MQ_UNLINK              = 274
-       SYS_MQ_TIMEDSEND           = 275
-       SYS_MQ_TIMEDRECEIVE        = 276
-       SYS_MQ_NOTIFY              = 277
-       SYS_MQ_GETSETATTR          = 278
-       SYS_WAITID                 = 279
-       SYS_TEE                    = 280
-       SYS_ADD_KEY                = 281
-       SYS_REQUEST_KEY            = 282
-       SYS_KEYCTL                 = 283
-       SYS_OPENAT                 = 284
-       SYS_MKDIRAT                = 285
-       SYS_MKNODAT                = 286
-       SYS_FCHOWNAT               = 287
-       SYS_FUTIMESAT              = 288
-       SYS_FSTATAT64              = 289
-       SYS_UNLINKAT               = 290
-       SYS_RENAMEAT               = 291
-       SYS_LINKAT                 = 292
-       SYS_SYMLINKAT              = 293
-       SYS_READLINKAT             = 294
-       SYS_FCHMODAT               = 295
-       SYS_FACCESSAT              = 296
-       SYS_PSELECT6               = 297
-       SYS_PPOLL                  = 298
-       SYS_UNSHARE                = 299
-       SYS_SET_ROBUST_LIST        = 300
-       SYS_GET_ROBUST_LIST        = 301
-       SYS_MIGRATE_PAGES          = 302
-       SYS_MBIND                  = 303
-       SYS_GET_MEMPOLICY          = 304
-       SYS_SET_MEMPOLICY          = 305
-       SYS_KEXEC_LOAD             = 306
-       SYS_MOVE_PAGES             = 307
-       SYS_GETCPU                 = 308
-       SYS_EPOLL_PWAIT            = 309
-       SYS_UTIMENSAT              = 310
-       SYS_SIGNALFD               = 311
-       SYS_TIMERFD_CREATE         = 312
-       SYS_EVENTFD                = 313
-       SYS_FALLOCATE              = 314
-       SYS_TIMERFD_SETTIME        = 315
-       SYS_TIMERFD_GETTIME        = 316
-       SYS_SIGNALFD4              = 317
-       SYS_EVENTFD2               = 318
-       SYS_EPOLL_CREATE1          = 319
-       SYS_DUP3                   = 320
-       SYS_PIPE2                  = 321
-       SYS_INOTIFY_INIT1          = 322
-       SYS_ACCEPT4                = 323
-       SYS_PREADV                 = 324
-       SYS_PWRITEV                = 325
-       SYS_RT_TGSIGQUEUEINFO      = 326
-       SYS_PERF_EVENT_OPEN        = 327
-       SYS_RECVMMSG               = 328
-       SYS_FANOTIFY_INIT          = 329
-       SYS_FANOTIFY_MARK          = 330
-       SYS_PRLIMIT64              = 331
-       SYS_NAME_TO_HANDLE_AT      = 332
-       SYS_OPEN_BY_HANDLE_AT      = 333
-       SYS_CLOCK_ADJTIME          = 334
-       SYS_SYNCFS                 = 335
-       SYS_SENDMMSG               = 336
-       SYS_SETNS                  = 337
-       SYS_PROCESS_VM_READV       = 338
-       SYS_PROCESS_VM_WRITEV      = 339
-       SYS_KERN_FEATURES          = 340
-       SYS_KCMP                   = 341
-       SYS_FINIT_MODULE           = 342
-       SYS_SCHED_SETATTR          = 343
-       SYS_SCHED_GETATTR          = 344
-       SYS_RENAMEAT2              = 345
-       SYS_SECCOMP                = 346
-       SYS_GETRANDOM              = 347
-       SYS_MEMFD_CREATE           = 348
-       SYS_BPF                    = 349
-       SYS_EXECVEAT               = 350
-       SYS_MEMBARRIER             = 351
-       SYS_USERFAULTFD            = 352
-       SYS_BIND                   = 353
-       SYS_LISTEN                 = 354
-       SYS_SETSOCKOPT             = 355
-       SYS_MLOCK2                 = 356
-       SYS_COPY_FILE_RANGE        = 357
-       SYS_PREADV2                = 358
-       SYS_PWRITEV2               = 359
-       SYS_STATX                  = 360
-       SYS_IO_PGETEVENTS          = 361
-       SYS_PKEY_MPROTECT          = 362
-       SYS_PKEY_ALLOC             = 363
-       SYS_PKEY_FREE              = 364
-       SYS_RSEQ                   = 365
-       SYS_SEMTIMEDOP             = 392
-       SYS_SEMGET                 = 393
-       SYS_SEMCTL                 = 394
-       SYS_SHMGET                 = 395
-       SYS_SHMCTL                 = 396
-       SYS_SHMAT                  = 397
-       SYS_SHMDT                  = 398
-       SYS_MSGGET                 = 399
-       SYS_MSGSND                 = 400
-       SYS_MSGRCV                 = 401
-       SYS_MSGCTL                 = 402
-       SYS_PIDFD_SEND_SIGNAL      = 424
-       SYS_IO_URING_SETUP         = 425
-       SYS_IO_URING_ENTER         = 426
-       SYS_IO_URING_REGISTER      = 427
-       SYS_OPEN_TREE              = 428
-       SYS_MOVE_MOUNT             = 429
-       SYS_FSOPEN                 = 430
-       SYS_FSCONFIG               = 431
-       SYS_FSMOUNT                = 432
-       SYS_FSPICK                 = 433
-       SYS_PIDFD_OPEN             = 434
-       SYS_CLOSE_RANGE            = 436
-       SYS_OPENAT2                = 437
-       SYS_PIDFD_GETFD            = 438
-       SYS_FACCESSAT2             = 439
-       SYS_PROCESS_MADVISE        = 440
-       SYS_EPOLL_PWAIT2           = 441
-       SYS_MOUNT_SETATTR          = 442
+       SYS_RESTART_SYSCALL         = 0
+       SYS_EXIT                    = 1
+       SYS_FORK                    = 2
+       SYS_READ                    = 3
+       SYS_WRITE                   = 4
+       SYS_OPEN                    = 5
+       SYS_CLOSE                   = 6
+       SYS_WAIT4                   = 7
+       SYS_CREAT                   = 8
+       SYS_LINK                    = 9
+       SYS_UNLINK                  = 10
+       SYS_EXECV                   = 11
+       SYS_CHDIR                   = 12
+       SYS_CHOWN                   = 13
+       SYS_MKNOD                   = 14
+       SYS_CHMOD                   = 15
+       SYS_LCHOWN                  = 16
+       SYS_BRK                     = 17
+       SYS_PERFCTR                 = 18
+       SYS_LSEEK                   = 19
+       SYS_GETPID                  = 20
+       SYS_CAPGET                  = 21
+       SYS_CAPSET                  = 22
+       SYS_SETUID                  = 23
+       SYS_GETUID                  = 24
+       SYS_VMSPLICE                = 25
+       SYS_PTRACE                  = 26
+       SYS_ALARM                   = 27
+       SYS_SIGALTSTACK             = 28
+       SYS_PAUSE                   = 29
+       SYS_UTIME                   = 30
+       SYS_ACCESS                  = 33
+       SYS_NICE                    = 34
+       SYS_SYNC                    = 36
+       SYS_KILL                    = 37
+       SYS_STAT                    = 38
+       SYS_SENDFILE                = 39
+       SYS_LSTAT                   = 40
+       SYS_DUP                     = 41
+       SYS_PIPE                    = 42
+       SYS_TIMES                   = 43
+       SYS_UMOUNT2                 = 45
+       SYS_SETGID                  = 46
+       SYS_GETGID                  = 47
+       SYS_SIGNAL                  = 48
+       SYS_GETEUID                 = 49
+       SYS_GETEGID                 = 50
+       SYS_ACCT                    = 51
+       SYS_MEMORY_ORDERING         = 52
+       SYS_IOCTL                   = 54
+       SYS_REBOOT                  = 55
+       SYS_SYMLINK                 = 57
+       SYS_READLINK                = 58
+       SYS_EXECVE                  = 59
+       SYS_UMASK                   = 60
+       SYS_CHROOT                  = 61
+       SYS_FSTAT                   = 62
+       SYS_FSTAT64                 = 63
+       SYS_GETPAGESIZE             = 64
+       SYS_MSYNC                   = 65
+       SYS_VFORK                   = 66
+       SYS_PREAD64                 = 67
+       SYS_PWRITE64                = 68
+       SYS_MMAP                    = 71
+       SYS_MUNMAP                  = 73
+       SYS_MPROTECT                = 74
+       SYS_MADVISE                 = 75
+       SYS_VHANGUP                 = 76
+       SYS_MINCORE                 = 78
+       SYS_GETGROUPS               = 79
+       SYS_SETGROUPS               = 80
+       SYS_GETPGRP                 = 81
+       SYS_SETITIMER               = 83
+       SYS_SWAPON                  = 85
+       SYS_GETITIMER               = 86
+       SYS_SETHOSTNAME             = 88
+       SYS_DUP2                    = 90
+       SYS_FCNTL                   = 92
+       SYS_SELECT                  = 93
+       SYS_FSYNC                   = 95
+       SYS_SETPRIORITY             = 96
+       SYS_SOCKET                  = 97
+       SYS_CONNECT                 = 98
+       SYS_ACCEPT                  = 99
+       SYS_GETPRIORITY             = 100
+       SYS_RT_SIGRETURN            = 101
+       SYS_RT_SIGACTION            = 102
+       SYS_RT_SIGPROCMASK          = 103
+       SYS_RT_SIGPENDING           = 104
+       SYS_RT_SIGTIMEDWAIT         = 105
+       SYS_RT_SIGQUEUEINFO         = 106
+       SYS_RT_SIGSUSPEND           = 107
+       SYS_SETRESUID               = 108
+       SYS_GETRESUID               = 109
+       SYS_SETRESGID               = 110
+       SYS_GETRESGID               = 111
+       SYS_RECVMSG                 = 113
+       SYS_SENDMSG                 = 114
+       SYS_GETTIMEOFDAY            = 116
+       SYS_GETRUSAGE               = 117
+       SYS_GETSOCKOPT              = 118
+       SYS_GETCWD                  = 119
+       SYS_READV                   = 120
+       SYS_WRITEV                  = 121
+       SYS_SETTIMEOFDAY            = 122
+       SYS_FCHOWN                  = 123
+       SYS_FCHMOD                  = 124
+       SYS_RECVFROM                = 125
+       SYS_SETREUID                = 126
+       SYS_SETREGID                = 127
+       SYS_RENAME                  = 128
+       SYS_TRUNCATE                = 129
+       SYS_FTRUNCATE               = 130
+       SYS_FLOCK                   = 131
+       SYS_LSTAT64                 = 132
+       SYS_SENDTO                  = 133
+       SYS_SHUTDOWN                = 134
+       SYS_SOCKETPAIR              = 135
+       SYS_MKDIR                   = 136
+       SYS_RMDIR                   = 137
+       SYS_UTIMES                  = 138
+       SYS_STAT64                  = 139
+       SYS_SENDFILE64              = 140
+       SYS_GETPEERNAME             = 141
+       SYS_FUTEX                   = 142
+       SYS_GETTID                  = 143
+       SYS_GETRLIMIT               = 144
+       SYS_SETRLIMIT               = 145
+       SYS_PIVOT_ROOT              = 146
+       SYS_PRCTL                   = 147
+       SYS_PCICONFIG_READ          = 148
+       SYS_PCICONFIG_WRITE         = 149
+       SYS_GETSOCKNAME             = 150
+       SYS_INOTIFY_INIT            = 151
+       SYS_INOTIFY_ADD_WATCH       = 152
+       SYS_POLL                    = 153
+       SYS_GETDENTS64              = 154
+       SYS_INOTIFY_RM_WATCH        = 156
+       SYS_STATFS                  = 157
+       SYS_FSTATFS                 = 158
+       SYS_UMOUNT                  = 159
+       SYS_SCHED_SET_AFFINITY      = 160
+       SYS_SCHED_GET_AFFINITY      = 161
+       SYS_GETDOMAINNAME           = 162
+       SYS_SETDOMAINNAME           = 163
+       SYS_UTRAP_INSTALL           = 164
+       SYS_QUOTACTL                = 165
+       SYS_SET_TID_ADDRESS         = 166
+       SYS_MOUNT                   = 167
+       SYS_USTAT                   = 168
+       SYS_SETXATTR                = 169
+       SYS_LSETXATTR               = 170
+       SYS_FSETXATTR               = 171
+       SYS_GETXATTR                = 172
+       SYS_LGETXATTR               = 173
+       SYS_GETDENTS                = 174
+       SYS_SETSID                  = 175
+       SYS_FCHDIR                  = 176
+       SYS_FGETXATTR               = 177
+       SYS_LISTXATTR               = 178
+       SYS_LLISTXATTR              = 179
+       SYS_FLISTXATTR              = 180
+       SYS_REMOVEXATTR             = 181
+       SYS_LREMOVEXATTR            = 182
+       SYS_SIGPENDING              = 183
+       SYS_QUERY_MODULE            = 184
+       SYS_SETPGID                 = 185
+       SYS_FREMOVEXATTR            = 186
+       SYS_TKILL                   = 187
+       SYS_EXIT_GROUP              = 188
+       SYS_UNAME                   = 189
+       SYS_INIT_MODULE             = 190
+       SYS_PERSONALITY             = 191
+       SYS_REMAP_FILE_PAGES        = 192
+       SYS_EPOLL_CREATE            = 193
+       SYS_EPOLL_CTL               = 194
+       SYS_EPOLL_WAIT              = 195
+       SYS_IOPRIO_SET              = 196
+       SYS_GETPPID                 = 197
+       SYS_SIGACTION               = 198
+       SYS_SGETMASK                = 199
+       SYS_SSETMASK                = 200
+       SYS_SIGSUSPEND              = 201
+       SYS_OLDLSTAT                = 202
+       SYS_USELIB                  = 203
+       SYS_READDIR                 = 204
+       SYS_READAHEAD               = 205
+       SYS_SOCKETCALL              = 206
+       SYS_SYSLOG                  = 207
+       SYS_LOOKUP_DCOOKIE          = 208
+       SYS_FADVISE64               = 209
+       SYS_FADVISE64_64            = 210
+       SYS_TGKILL                  = 211
+       SYS_WAITPID                 = 212
+       SYS_SWAPOFF                 = 213
+       SYS_SYSINFO                 = 214
+       SYS_IPC                     = 215
+       SYS_SIGRETURN               = 216
+       SYS_CLONE                   = 217
+       SYS_IOPRIO_GET              = 218
+       SYS_ADJTIMEX                = 219
+       SYS_SIGPROCMASK             = 220
+       SYS_CREATE_MODULE           = 221
+       SYS_DELETE_MODULE           = 222
+       SYS_GET_KERNEL_SYMS         = 223
+       SYS_GETPGID                 = 224
+       SYS_BDFLUSH                 = 225
+       SYS_SYSFS                   = 226
+       SYS_AFS_SYSCALL             = 227
+       SYS_SETFSUID                = 228
+       SYS_SETFSGID                = 229
+       SYS__NEWSELECT              = 230
+       SYS_SPLICE                  = 232
+       SYS_STIME                   = 233
+       SYS_STATFS64                = 234
+       SYS_FSTATFS64               = 235
+       SYS__LLSEEK                 = 236
+       SYS_MLOCK                   = 237
+       SYS_MUNLOCK                 = 238
+       SYS_MLOCKALL                = 239
+       SYS_MUNLOCKALL              = 240
+       SYS_SCHED_SETPARAM          = 241
+       SYS_SCHED_GETPARAM          = 242
+       SYS_SCHED_SETSCHEDULER      = 243
+       SYS_SCHED_GETSCHEDULER      = 244
+       SYS_SCHED_YIELD             = 245
+       SYS_SCHED_GET_PRIORITY_MAX  = 246
+       SYS_SCHED_GET_PRIORITY_MIN  = 247
+       SYS_SCHED_RR_GET_INTERVAL   = 248
+       SYS_NANOSLEEP               = 249
+       SYS_MREMAP                  = 250
+       SYS__SYSCTL                 = 251
+       SYS_GETSID                  = 252
+       SYS_FDATASYNC               = 253
+       SYS_NFSSERVCTL              = 254
+       SYS_SYNC_FILE_RANGE         = 255
+       SYS_CLOCK_SETTIME           = 256
+       SYS_CLOCK_GETTIME           = 257
+       SYS_CLOCK_GETRES            = 258
+       SYS_CLOCK_NANOSLEEP         = 259
+       SYS_SCHED_GETAFFINITY       = 260
+       SYS_SCHED_SETAFFINITY       = 261
+       SYS_TIMER_SETTIME           = 262
+       SYS_TIMER_GETTIME           = 263
+       SYS_TIMER_GETOVERRUN        = 264
+       SYS_TIMER_DELETE            = 265
+       SYS_TIMER_CREATE            = 266
+       SYS_VSERVER                 = 267
+       SYS_IO_SETUP                = 268
+       SYS_IO_DESTROY              = 269
+       SYS_IO_SUBMIT               = 270
+       SYS_IO_CANCEL               = 271
+       SYS_IO_GETEVENTS            = 272
+       SYS_MQ_OPEN                 = 273
+       SYS_MQ_UNLINK               = 274
+       SYS_MQ_TIMEDSEND            = 275
+       SYS_MQ_TIMEDRECEIVE         = 276
+       SYS_MQ_NOTIFY               = 277
+       SYS_MQ_GETSETATTR           = 278
+       SYS_WAITID                  = 279
+       SYS_TEE                     = 280
+       SYS_ADD_KEY                 = 281
+       SYS_REQUEST_KEY             = 282
+       SYS_KEYCTL                  = 283
+       SYS_OPENAT                  = 284
+       SYS_MKDIRAT                 = 285
+       SYS_MKNODAT                 = 286
+       SYS_FCHOWNAT                = 287
+       SYS_FUTIMESAT               = 288
+       SYS_FSTATAT64               = 289
+       SYS_UNLINKAT                = 290
+       SYS_RENAMEAT                = 291
+       SYS_LINKAT                  = 292
+       SYS_SYMLINKAT               = 293
+       SYS_READLINKAT              = 294
+       SYS_FCHMODAT                = 295
+       SYS_FACCESSAT               = 296
+       SYS_PSELECT6                = 297
+       SYS_PPOLL                   = 298
+       SYS_UNSHARE                 = 299
+       SYS_SET_ROBUST_LIST         = 300
+       SYS_GET_ROBUST_LIST         = 301
+       SYS_MIGRATE_PAGES           = 302
+       SYS_MBIND                   = 303
+       SYS_GET_MEMPOLICY           = 304
+       SYS_SET_MEMPOLICY           = 305
+       SYS_KEXEC_LOAD              = 306
+       SYS_MOVE_PAGES              = 307
+       SYS_GETCPU                  = 308
+       SYS_EPOLL_PWAIT             = 309
+       SYS_UTIMENSAT               = 310
+       SYS_SIGNALFD                = 311
+       SYS_TIMERFD_CREATE          = 312
+       SYS_EVENTFD                 = 313
+       SYS_FALLOCATE               = 314
+       SYS_TIMERFD_SETTIME         = 315
+       SYS_TIMERFD_GETTIME         = 316
+       SYS_SIGNALFD4               = 317
+       SYS_EVENTFD2                = 318
+       SYS_EPOLL_CREATE1           = 319
+       SYS_DUP3                    = 320
+       SYS_PIPE2                   = 321
+       SYS_INOTIFY_INIT1           = 322
+       SYS_ACCEPT4                 = 323
+       SYS_PREADV                  = 324
+       SYS_PWRITEV                 = 325
+       SYS_RT_TGSIGQUEUEINFO       = 326
+       SYS_PERF_EVENT_OPEN         = 327
+       SYS_RECVMMSG                = 328
+       SYS_FANOTIFY_INIT           = 329
+       SYS_FANOTIFY_MARK           = 330
+       SYS_PRLIMIT64               = 331
+       SYS_NAME_TO_HANDLE_AT       = 332
+       SYS_OPEN_BY_HANDLE_AT       = 333
+       SYS_CLOCK_ADJTIME           = 334
+       SYS_SYNCFS                  = 335
+       SYS_SENDMMSG                = 336
+       SYS_SETNS                   = 337
+       SYS_PROCESS_VM_READV        = 338
+       SYS_PROCESS_VM_WRITEV       = 339
+       SYS_KERN_FEATURES           = 340
+       SYS_KCMP                    = 341
+       SYS_FINIT_MODULE            = 342
+       SYS_SCHED_SETATTR           = 343
+       SYS_SCHED_GETATTR           = 344
+       SYS_RENAMEAT2               = 345
+       SYS_SECCOMP                 = 346
+       SYS_GETRANDOM               = 347
+       SYS_MEMFD_CREATE            = 348
+       SYS_BPF                     = 349
+       SYS_EXECVEAT                = 350
+       SYS_MEMBARRIER              = 351
+       SYS_USERFAULTFD             = 352
+       SYS_BIND                    = 353
+       SYS_LISTEN                  = 354
+       SYS_SETSOCKOPT              = 355
+       SYS_MLOCK2                  = 356
+       SYS_COPY_FILE_RANGE         = 357
+       SYS_PREADV2                 = 358
+       SYS_PWRITEV2                = 359
+       SYS_STATX                   = 360
+       SYS_IO_PGETEVENTS           = 361
+       SYS_PKEY_MPROTECT           = 362
+       SYS_PKEY_ALLOC              = 363
+       SYS_PKEY_FREE               = 364
+       SYS_RSEQ                    = 365
+       SYS_SEMTIMEDOP              = 392
+       SYS_SEMGET                  = 393
+       SYS_SEMCTL                  = 394
+       SYS_SHMGET                  = 395
+       SYS_SHMCTL                  = 396
+       SYS_SHMAT                   = 397
+       SYS_SHMDT                   = 398
+       SYS_MSGGET                  = 399
+       SYS_MSGSND                  = 400
+       SYS_MSGRCV                  = 401
+       SYS_MSGCTL                  = 402
+       SYS_PIDFD_SEND_SIGNAL       = 424
+       SYS_IO_URING_SETUP          = 425
+       SYS_IO_URING_ENTER          = 426
+       SYS_IO_URING_REGISTER       = 427
+       SYS_OPEN_TREE               = 428
+       SYS_MOVE_MOUNT              = 429
+       SYS_FSOPEN                  = 430
+       SYS_FSCONFIG                = 431
+       SYS_FSMOUNT                 = 432
+       SYS_FSPICK                  = 433
+       SYS_PIDFD_OPEN              = 434
+       SYS_CLOSE_RANGE             = 436
+       SYS_OPENAT2                 = 437
+       SYS_PIDFD_GETFD             = 438
+       SYS_FACCESSAT2              = 439
+       SYS_PROCESS_MADVISE         = 440
+       SYS_EPOLL_PWAIT2            = 441
+       SYS_MOUNT_SETATTR           = 442
+       SYS_QUOTACTL_FD             = 443
+       SYS_LANDLOCK_CREATE_RULESET = 444
+       SYS_LANDLOCK_ADD_RULE       = 445
+       SYS_LANDLOCK_RESTRICT_SELF  = 446
 )
index 2673e6c5909c338d0ece15d00768482257afd2d4..7efe5ccba331f20e8598e268c5d2a285d7712cdc 100644 (file)
@@ -209,6 +209,92 @@ type RawSockaddrCtl struct {
        Sc_reserved [5]uint32
 }
 
+type RawSockaddrVM struct {
+       Len       uint8
+       Family    uint8
+       Reserved1 uint16
+       Port      uint32
+       Cid       uint32
+}
+
+type XVSockPCB struct {
+       Xv_len           uint32
+       Xv_vsockpp       uint64
+       Xvp_local_cid    uint32
+       Xvp_local_port   uint32
+       Xvp_remote_cid   uint32
+       Xvp_remote_port  uint32
+       Xvp_rxcnt        uint32
+       Xvp_txcnt        uint32
+       Xvp_peer_rxhiwat uint32
+       Xvp_peer_rxcnt   uint32
+       Xvp_last_pid     int32
+       Xvp_gencnt       uint64
+       Xv_socket        XSocket
+       _                [4]byte
+}
+
+type XSocket struct {
+       Xso_len      uint32
+       Xso_so       uint32
+       So_type      int16
+       So_options   int16
+       So_linger    int16
+       So_state     int16
+       So_pcb       uint32
+       Xso_protocol int32
+       Xso_family   int32
+       So_qlen      int16
+       So_incqlen   int16
+       So_qlimit    int16
+       So_timeo     int16
+       So_error     uint16
+       So_pgid      int32
+       So_oobmark   uint32
+       So_rcv       XSockbuf
+       So_snd       XSockbuf
+       So_uid       uint32
+}
+
+type XSocket64 struct {
+       Xso_len      uint32
+       _            [8]byte
+       So_type      int16
+       So_options   int16
+       So_linger    int16
+       So_state     int16
+       _            [8]byte
+       Xso_protocol int32
+       Xso_family   int32
+       So_qlen      int16
+       So_incqlen   int16
+       So_qlimit    int16
+       So_timeo     int16
+       So_error     uint16
+       So_pgid      int32
+       So_oobmark   uint32
+       So_rcv       XSockbuf
+       So_snd       XSockbuf
+       So_uid       uint32
+}
+
+type XSockbuf struct {
+       Cc    uint32
+       Hiwat uint32
+       Mbcnt uint32
+       Mbmax uint32
+       Lowat int32
+       Flags int16
+       Timeo int16
+}
+
+type XVSockPgen struct {
+       Len   uint32
+       Count uint64
+       Gen   uint64
+       Sogen uint64
+}
+
 type _Socklen uint32
 
 type Xucred struct {
@@ -287,6 +373,11 @@ const (
        SizeofSockaddrUnix     = 0x6a
        SizeofSockaddrDatalink = 0x14
        SizeofSockaddrCtl      = 0x20
+       SizeofSockaddrVM       = 0xc
+       SizeofXvsockpcb        = 0xa8
+       SizeofXSocket          = 0x64
+       SizeofXSockbuf         = 0x18
+       SizeofXVSockPgen       = 0x20
        SizeofXucred           = 0x4c
        SizeofLinger           = 0x8
        SizeofIovec            = 0x10
@@ -535,3 +626,143 @@ type CtlInfo struct {
        Id   uint32
        Name [96]byte
 }
+
+const SizeofKinfoProc = 0x288
+
+type Eproc struct {
+       Paddr   uintptr
+       Sess    uintptr
+       Pcred   Pcred
+       Ucred   Ucred
+       Vm      Vmspace
+       Ppid    int32
+       Pgid    int32
+       Jobc    int16
+       Tdev    int32
+       Tpgid   int32
+       Tsess   uintptr
+       Wmesg   [8]int8
+       Xsize   int32
+       Xrssize int16
+       Xccount int16
+       Xswrss  int16
+       Flag    int32
+       Login   [12]int8
+       Spare   [4]int32
+       _       [4]byte
+}
+
+type ExternProc struct {
+       P_starttime Timeval
+       P_vmspace   *Vmspace
+       P_sigacts   uintptr
+       P_flag      int32
+       P_stat      int8
+       P_pid       int32
+       P_oppid     int32
+       P_dupfd     int32
+       User_stack  *int8
+       Exit_thread *byte
+       P_debugger  int32
+       Sigwait     int32
+       P_estcpu    uint32
+       P_cpticks   int32
+       P_pctcpu    uint32
+       P_wchan     *byte
+       P_wmesg     *int8
+       P_swtime    uint32
+       P_slptime   uint32
+       P_realtimer Itimerval
+       P_rtime     Timeval
+       P_uticks    uint64
+       P_sticks    uint64
+       P_iticks    uint64
+       P_traceflag int32
+       P_tracep    uintptr
+       P_siglist   int32
+       P_textvp    uintptr
+       P_holdcnt   int32
+       P_sigmask   uint32
+       P_sigignore uint32
+       P_sigcatch  uint32
+       P_priority  uint8
+       P_usrpri    uint8
+       P_nice      int8
+       P_comm      [17]int8
+       P_pgrp      uintptr
+       P_addr      uintptr
+       P_xstat     uint16
+       P_acflag    uint16
+       P_ru        *Rusage
+}
+
+type Itimerval struct {
+       Interval Timeval
+       Value    Timeval
+}
+
+type KinfoProc struct {
+       Proc  ExternProc
+       Eproc Eproc
+}
+
+type Vmspace struct {
+       Dummy  int32
+       Dummy2 *int8
+       Dummy3 [5]int32
+       Dummy4 [3]*int8
+}
+
+type Pcred struct {
+       Pc_lock  [72]int8
+       Pc_ucred uintptr
+       P_ruid   uint32
+       P_svuid  uint32
+       P_rgid   uint32
+       P_svgid  uint32
+       P_refcnt int32
+       _        [4]byte
+}
+
+type Ucred struct {
+       Ref     int32
+       Uid     uint32
+       Ngroups int16
+       Groups  [16]uint32
+}
+
+type SysvIpcPerm struct {
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint16
+       _    uint16
+       _    int32
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Lpid   int32
+       Cpid   int32
+       Nattch uint16
+       _      [34]byte
+}
+
+const (
+       IPC_CREAT   = 0x200
+       IPC_EXCL    = 0x400
+       IPC_NOWAIT  = 0x800
+       IPC_PRIVATE = 0x0
+)
+
+const (
+       IPC_RMID = 0x0
+       IPC_SET  = 0x1
+       IPC_STAT = 0x2
+)
+
+const (
+       SHM_RDONLY = 0x1000
+       SHM_RND    = 0x2000
+)
index 1465cbcffe476d872135974ccd6f02be1d32cdcb..b23a2efe81b8262ed092a9587c1aaa51ad0af56c 100644 (file)
@@ -209,6 +209,92 @@ type RawSockaddrCtl struct {
        Sc_reserved [5]uint32
 }
 
+type RawSockaddrVM struct {
+       Len       uint8
+       Family    uint8
+       Reserved1 uint16
+       Port      uint32
+       Cid       uint32
+}
+
+type XVSockPCB struct {
+       Xv_len           uint32
+       Xv_vsockpp       uint64
+       Xvp_local_cid    uint32
+       Xvp_local_port   uint32
+       Xvp_remote_cid   uint32
+       Xvp_remote_port  uint32
+       Xvp_rxcnt        uint32
+       Xvp_txcnt        uint32
+       Xvp_peer_rxhiwat uint32
+       Xvp_peer_rxcnt   uint32
+       Xvp_last_pid     int32
+       Xvp_gencnt       uint64
+       Xv_socket        XSocket
+       _                [4]byte
+}
+
+type XSocket struct {
+       Xso_len      uint32
+       Xso_so       uint32
+       So_type      int16
+       So_options   int16
+       So_linger    int16
+       So_state     int16
+       So_pcb       uint32
+       Xso_protocol int32
+       Xso_family   int32
+       So_qlen      int16
+       So_incqlen   int16
+       So_qlimit    int16
+       So_timeo     int16
+       So_error     uint16
+       So_pgid      int32
+       So_oobmark   uint32
+       So_rcv       XSockbuf
+       So_snd       XSockbuf
+       So_uid       uint32
+}
+
+type XSocket64 struct {
+       Xso_len      uint32
+       _            [8]byte
+       So_type      int16
+       So_options   int16
+       So_linger    int16
+       So_state     int16
+       _            [8]byte
+       Xso_protocol int32
+       Xso_family   int32
+       So_qlen      int16
+       So_incqlen   int16
+       So_qlimit    int16
+       So_timeo     int16
+       So_error     uint16
+       So_pgid      int32
+       So_oobmark   uint32
+       So_rcv       XSockbuf
+       So_snd       XSockbuf
+       So_uid       uint32
+}
+
+type XSockbuf struct {
+       Cc    uint32
+       Hiwat uint32
+       Mbcnt uint32
+       Mbmax uint32
+       Lowat int32
+       Flags int16
+       Timeo int16
+}
+
+type XVSockPgen struct {
+       Len   uint32
+       Count uint64
+       Gen   uint64
+       Sogen uint64
+}
+
 type _Socklen uint32
 
 type Xucred struct {
@@ -287,6 +373,11 @@ const (
        SizeofSockaddrUnix     = 0x6a
        SizeofSockaddrDatalink = 0x14
        SizeofSockaddrCtl      = 0x20
+       SizeofSockaddrVM       = 0xc
+       SizeofXvsockpcb        = 0xa8
+       SizeofXSocket          = 0x64
+       SizeofXSockbuf         = 0x18
+       SizeofXVSockPgen       = 0x20
        SizeofXucred           = 0x4c
        SizeofLinger           = 0x8
        SizeofIovec            = 0x10
@@ -535,3 +626,143 @@ type CtlInfo struct {
        Id   uint32
        Name [96]byte
 }
+
+const SizeofKinfoProc = 0x288
+
+type Eproc struct {
+       Paddr   uintptr
+       Sess    uintptr
+       Pcred   Pcred
+       Ucred   Ucred
+       Vm      Vmspace
+       Ppid    int32
+       Pgid    int32
+       Jobc    int16
+       Tdev    int32
+       Tpgid   int32
+       Tsess   uintptr
+       Wmesg   [8]int8
+       Xsize   int32
+       Xrssize int16
+       Xccount int16
+       Xswrss  int16
+       Flag    int32
+       Login   [12]int8
+       Spare   [4]int32
+       _       [4]byte
+}
+
+type ExternProc struct {
+       P_starttime Timeval
+       P_vmspace   *Vmspace
+       P_sigacts   uintptr
+       P_flag      int32
+       P_stat      int8
+       P_pid       int32
+       P_oppid     int32
+       P_dupfd     int32
+       User_stack  *int8
+       Exit_thread *byte
+       P_debugger  int32
+       Sigwait     int32
+       P_estcpu    uint32
+       P_cpticks   int32
+       P_pctcpu    uint32
+       P_wchan     *byte
+       P_wmesg     *int8
+       P_swtime    uint32
+       P_slptime   uint32
+       P_realtimer Itimerval
+       P_rtime     Timeval
+       P_uticks    uint64
+       P_sticks    uint64
+       P_iticks    uint64
+       P_traceflag int32
+       P_tracep    uintptr
+       P_siglist   int32
+       P_textvp    uintptr
+       P_holdcnt   int32
+       P_sigmask   uint32
+       P_sigignore uint32
+       P_sigcatch  uint32
+       P_priority  uint8
+       P_usrpri    uint8
+       P_nice      int8
+       P_comm      [17]int8
+       P_pgrp      uintptr
+       P_addr      uintptr
+       P_xstat     uint16
+       P_acflag    uint16
+       P_ru        *Rusage
+}
+
+type Itimerval struct {
+       Interval Timeval
+       Value    Timeval
+}
+
+type KinfoProc struct {
+       Proc  ExternProc
+       Eproc Eproc
+}
+
+type Vmspace struct {
+       Dummy  int32
+       Dummy2 *int8
+       Dummy3 [5]int32
+       Dummy4 [3]*int8
+}
+
+type Pcred struct {
+       Pc_lock  [72]int8
+       Pc_ucred uintptr
+       P_ruid   uint32
+       P_svuid  uint32
+       P_rgid   uint32
+       P_svgid  uint32
+       P_refcnt int32
+       _        [4]byte
+}
+
+type Ucred struct {
+       Ref     int32
+       Uid     uint32
+       Ngroups int16
+       Groups  [16]uint32
+}
+
+type SysvIpcPerm struct {
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint16
+       _    uint16
+       _    int32
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Lpid   int32
+       Cpid   int32
+       Nattch uint16
+       _      [34]byte
+}
+
+const (
+       IPC_CREAT   = 0x200
+       IPC_EXCL    = 0x400
+       IPC_NOWAIT  = 0x800
+       IPC_PRIVATE = 0x0
+)
+
+const (
+       IPC_RMID = 0x0
+       IPC_SET  = 0x1
+       IPC_STAT = 0x2
+)
+
+const (
+       SHM_RDONLY = 0x1000
+       SHM_RND    = 0x2000
+)
index 1d049d7a12247c1fd80bf01b707f00f75f63784a..d0ba8e9b86a3483567cc3bcbe01e4a83612d4005 100644 (file)
@@ -431,6 +431,9 @@ type Winsize struct {
 const (
        AT_FDCWD            = 0xfffafdcd
        AT_SYMLINK_NOFOLLOW = 0x1
+       AT_REMOVEDIR        = 0x2
+       AT_EACCESS          = 0x4
+       AT_SYMLINK_FOLLOW   = 0x8
 )
 
 type PollFd struct {
index c51bc88ffdfcbf7652d3a73c506a037bd583fda1..4eec078e52490863cf2ce9f794afffcd71a453e6 100644 (file)
@@ -31,6 +31,8 @@ type Timeval struct {
        Usec int32
 }
 
+type Time_t int32
+
 type Rusage struct {
        Utime    Timeval
        Stime    Timeval
@@ -672,9 +674,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_REMOVEDIR        = 0x800
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index 395b69187113e06d10af9d700f1cf8cf012b209a..7622904a532f45f8ef0eb7d37c4dcad01fee1310 100644 (file)
@@ -31,6 +31,8 @@ type Timeval struct {
        Usec int64
 }
 
+type Time_t int64
+
 type Rusage struct {
        Utime    Timeval
        Stime    Timeval
@@ -675,9 +677,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_REMOVEDIR        = 0x800
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index d3f9d2541b5ce384f7ebabb8b5f39e0cd910bcd7..19223ce8ecf906522e85e2c5f466f6d041897436 100644 (file)
@@ -33,6 +33,8 @@ type Timeval struct {
        _    [4]byte
 }
 
+type Time_t int32
+
 type Rusage struct {
        Utime    Timeval
        Stime    Timeval
@@ -656,9 +658,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_REMOVEDIR        = 0x800
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index 434d6e8e83c4766f6c5dac517a7f473802087d1f..8e3e33f6790587e60208a6cf5f804f8005820320 100644 (file)
@@ -31,6 +31,8 @@ type Timeval struct {
        Usec int64
 }
 
+type Time_t int64
+
 type Rusage struct {
        Utime    Timeval
        Stime    Timeval
@@ -653,9 +655,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_REMOVEDIR        = 0x800
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index 236f37ef6f7ec7f5b3f587321dc2445e05c9bed1..4c485261d6dfd9e6822090db517e29f9cad07318 100644 (file)
@@ -13,6 +13,8 @@ const (
        I_STR     = 0x5308
        I_POP     = 0x5303
        I_PUSH    = 0x5302
+       I_LINK    = 0x530c
+       I_UNLINK  = 0x530d
        I_PLINK   = 0x5316
        I_PUNLINK = 0x5317
 
index 087323591e61d8cbfc35732e935e4707e20f5237..249ecfcd4cc66a75945707b69a2d3ad39a407395 100644 (file)
@@ -351,6 +351,13 @@ type RawSockaddrIUCV struct {
        Name    [8]int8
 }
 
+type RawSockaddrNFC struct {
+       Sa_family    uint16
+       Dev_idx      uint32
+       Target_idx   uint32
+       Nfc_protocol uint32
+}
+
 type _Socklen uint32
 
 type Linger struct {
@@ -445,6 +452,11 @@ type CanFilter struct {
        Mask uint32
 }
 
+type TCPRepairOpt struct {
+       Code uint32
+       Val  uint32
+}
+
 const (
        SizeofSockaddrInet4     = 0x10
        SizeofSockaddrInet6     = 0x1c
@@ -464,6 +476,7 @@ const (
        SizeofSockaddrL2TPIP    = 0x10
        SizeofSockaddrL2TPIP6   = 0x20
        SizeofSockaddrIUCV      = 0x20
+       SizeofSockaddrNFC       = 0x10
        SizeofLinger            = 0x8
        SizeofIPMreq            = 0x8
        SizeofIPMreqn           = 0xc
@@ -476,6 +489,7 @@ const (
        SizeofUcred             = 0xc
        SizeofTCPInfo           = 0x68
        SizeofCanFilter         = 0x8
+       SizeofTCPRepairOpt      = 0x8
 )
 
 const (
@@ -673,6 +687,16 @@ type NdMsg struct {
        Type    uint8
 }
 
+const (
+       ICMP_FILTER = 0x1
+
+       ICMPV6_FILTER             = 0x1
+       ICMPV6_FILTER_BLOCK       = 0x1
+       ICMPV6_FILTER_BLOCKOTHERS = 0x3
+       ICMPV6_FILTER_PASS        = 0x2
+       ICMPV6_FILTER_PASSONLY    = 0x4
+)
+
 const (
        SizeofSockFilter = 0x8
 )
@@ -993,7 +1017,7 @@ const (
        PERF_COUNT_SW_EMULATION_FAULTS        = 0x8
        PERF_COUNT_SW_DUMMY                   = 0x9
        PERF_COUNT_SW_BPF_OUTPUT              = 0xa
-       PERF_COUNT_SW_MAX                     = 0xb
+       PERF_COUNT_SW_MAX                     = 0xc
        PERF_SAMPLE_IP                        = 0x1
        PERF_SAMPLE_TID                       = 0x2
        PERF_SAMPLE_TIME                      = 0x4
@@ -1765,6 +1789,8 @@ const (
        NFPROTO_NUMPROTO = 0xd
 )
 
+const SO_ORIGINAL_DST = 0x50
+
 type Nfgenmsg struct {
        Nfgen_family uint8
        Version      uint8
@@ -2330,8 +2356,8 @@ const (
        SOF_TIMESTAMPING_OPT_PKTINFO  = 0x2000
        SOF_TIMESTAMPING_OPT_TX_SWHW  = 0x4000
 
-       SOF_TIMESTAMPING_LAST = 0x4000
-       SOF_TIMESTAMPING_MASK = 0x7fff
+       SOF_TIMESTAMPING_LAST = 0x8000
+       SOF_TIMESTAMPING_MASK = 0xffff
 
        SCM_TSTAMP_SND   = 0x0
        SCM_TSTAMP_SCHED = 0x1
@@ -2907,7 +2933,7 @@ const (
        DEVLINK_CMD_TRAP_POLICER_NEW                       = 0x47
        DEVLINK_CMD_TRAP_POLICER_DEL                       = 0x48
        DEVLINK_CMD_HEALTH_REPORTER_TEST                   = 0x49
-       DEVLINK_CMD_MAX                                    = 0x49
+       DEVLINK_CMD_MAX                                    = 0x4d
        DEVLINK_PORT_TYPE_NOTSET                           = 0x0
        DEVLINK_PORT_TYPE_AUTO                             = 0x1
        DEVLINK_PORT_TYPE_ETH                              = 0x2
@@ -3130,7 +3156,7 @@ const (
        DEVLINK_ATTR_RELOAD_ACTION_INFO                    = 0xa2
        DEVLINK_ATTR_RELOAD_ACTION_STATS                   = 0xa3
        DEVLINK_ATTR_PORT_PCI_SF_NUMBER                    = 0xa4
-       DEVLINK_ATTR_MAX                                   = 0xa4
+       DEVLINK_ATTR_MAX                                   = 0xa9
        DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE              = 0x0
        DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX           = 0x1
        DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT               = 0x0
@@ -3426,7 +3452,7 @@ const (
        ETHTOOL_MSG_CABLE_TEST_ACT                = 0x1a
        ETHTOOL_MSG_CABLE_TEST_TDR_ACT            = 0x1b
        ETHTOOL_MSG_TUNNEL_INFO_GET               = 0x1c
-       ETHTOOL_MSG_USER_MAX                      = 0x1c
+       ETHTOOL_MSG_USER_MAX                      = 0x21
        ETHTOOL_MSG_KERNEL_NONE                   = 0x0
        ETHTOOL_MSG_STRSET_GET_REPLY              = 0x1
        ETHTOOL_MSG_LINKINFO_GET_REPLY            = 0x2
@@ -3457,7 +3483,7 @@ const (
        ETHTOOL_MSG_CABLE_TEST_NTF                = 0x1b
        ETHTOOL_MSG_CABLE_TEST_TDR_NTF            = 0x1c
        ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY         = 0x1d
-       ETHTOOL_MSG_KERNEL_MAX                    = 0x1d
+       ETHTOOL_MSG_KERNEL_MAX                    = 0x22
        ETHTOOL_A_HEADER_UNSPEC                   = 0x0
        ETHTOOL_A_HEADER_DEV_INDEX                = 0x1
        ETHTOOL_A_HEADER_DEV_NAME                 = 0x2
@@ -3742,3 +3768,191 @@ const (
        NLMSGERR_ATTR_OFFS   = 0x2
        NLMSGERR_ATTR_COOKIE = 0x3
 )
+
+type (
+       EraseInfo struct {
+               Start  uint32
+               Length uint32
+       }
+       EraseInfo64 struct {
+               Start  uint64
+               Length uint64
+       }
+       MtdOobBuf struct {
+               Start  uint32
+               Length uint32
+               Ptr    *uint8
+       }
+       MtdOobBuf64 struct {
+               Start  uint64
+               Pad    uint32
+               Length uint32
+               Ptr    uint64
+       }
+       MtdWriteReq struct {
+               Start  uint64
+               Len    uint64
+               Ooblen uint64
+               Data   uint64
+               Oob    uint64
+               Mode   uint8
+               _      [7]uint8
+       }
+       MtdInfo struct {
+               Type      uint8
+               Flags     uint32
+               Size      uint32
+               Erasesize uint32
+               Writesize uint32
+               Oobsize   uint32
+               _         uint64
+       }
+       RegionInfo struct {
+               Offset      uint32
+               Erasesize   uint32
+               Numblocks   uint32
+               Regionindex uint32
+       }
+       OtpInfo struct {
+               Start  uint32
+               Length uint32
+               Locked uint32
+       }
+       NandOobinfo struct {
+               Useecc   uint32
+               Eccbytes uint32
+               Oobfree  [8][2]uint32
+               Eccpos   [32]uint32
+       }
+       NandOobfree struct {
+               Offset uint32
+               Length uint32
+       }
+       NandEcclayout struct {
+               Eccbytes uint32
+               Eccpos   [64]uint32
+               Oobavail uint32
+               Oobfree  [8]NandOobfree
+       }
+       MtdEccStats struct {
+               Corrected uint32
+               Failed    uint32
+               Badblocks uint32
+               Bbtblocks uint32
+       }
+)
+
+const (
+       MTD_OPS_PLACE_OOB = 0x0
+       MTD_OPS_AUTO_OOB  = 0x1
+       MTD_OPS_RAW       = 0x2
+)
+
+const (
+       MTD_FILE_MODE_NORMAL      = 0x0
+       MTD_FILE_MODE_OTP_FACTORY = 0x1
+       MTD_FILE_MODE_OTP_USER    = 0x2
+       MTD_FILE_MODE_RAW         = 0x3
+)
+
+const (
+       NFC_CMD_UNSPEC                    = 0x0
+       NFC_CMD_GET_DEVICE                = 0x1
+       NFC_CMD_DEV_UP                    = 0x2
+       NFC_CMD_DEV_DOWN                  = 0x3
+       NFC_CMD_DEP_LINK_UP               = 0x4
+       NFC_CMD_DEP_LINK_DOWN             = 0x5
+       NFC_CMD_START_POLL                = 0x6
+       NFC_CMD_STOP_POLL                 = 0x7
+       NFC_CMD_GET_TARGET                = 0x8
+       NFC_EVENT_TARGETS_FOUND           = 0x9
+       NFC_EVENT_DEVICE_ADDED            = 0xa
+       NFC_EVENT_DEVICE_REMOVED          = 0xb
+       NFC_EVENT_TARGET_LOST             = 0xc
+       NFC_EVENT_TM_ACTIVATED            = 0xd
+       NFC_EVENT_TM_DEACTIVATED          = 0xe
+       NFC_CMD_LLC_GET_PARAMS            = 0xf
+       NFC_CMD_LLC_SET_PARAMS            = 0x10
+       NFC_CMD_ENABLE_SE                 = 0x11
+       NFC_CMD_DISABLE_SE                = 0x12
+       NFC_CMD_LLC_SDREQ                 = 0x13
+       NFC_EVENT_LLC_SDRES               = 0x14
+       NFC_CMD_FW_DOWNLOAD               = 0x15
+       NFC_EVENT_SE_ADDED                = 0x16
+       NFC_EVENT_SE_REMOVED              = 0x17
+       NFC_EVENT_SE_CONNECTIVITY         = 0x18
+       NFC_EVENT_SE_TRANSACTION          = 0x19
+       NFC_CMD_GET_SE                    = 0x1a
+       NFC_CMD_SE_IO                     = 0x1b
+       NFC_CMD_ACTIVATE_TARGET           = 0x1c
+       NFC_CMD_VENDOR                    = 0x1d
+       NFC_CMD_DEACTIVATE_TARGET         = 0x1e
+       NFC_ATTR_UNSPEC                   = 0x0
+       NFC_ATTR_DEVICE_INDEX             = 0x1
+       NFC_ATTR_DEVICE_NAME              = 0x2
+       NFC_ATTR_PROTOCOLS                = 0x3
+       NFC_ATTR_TARGET_INDEX             = 0x4
+       NFC_ATTR_TARGET_SENS_RES          = 0x5
+       NFC_ATTR_TARGET_SEL_RES           = 0x6
+       NFC_ATTR_TARGET_NFCID1            = 0x7
+       NFC_ATTR_TARGET_SENSB_RES         = 0x8
+       NFC_ATTR_TARGET_SENSF_RES         = 0x9
+       NFC_ATTR_COMM_MODE                = 0xa
+       NFC_ATTR_RF_MODE                  = 0xb
+       NFC_ATTR_DEVICE_POWERED           = 0xc
+       NFC_ATTR_IM_PROTOCOLS             = 0xd
+       NFC_ATTR_TM_PROTOCOLS             = 0xe
+       NFC_ATTR_LLC_PARAM_LTO            = 0xf
+       NFC_ATTR_LLC_PARAM_RW             = 0x10
+       NFC_ATTR_LLC_PARAM_MIUX           = 0x11
+       NFC_ATTR_SE                       = 0x12
+       NFC_ATTR_LLC_SDP                  = 0x13
+       NFC_ATTR_FIRMWARE_NAME            = 0x14
+       NFC_ATTR_SE_INDEX                 = 0x15
+       NFC_ATTR_SE_TYPE                  = 0x16
+       NFC_ATTR_SE_AID                   = 0x17
+       NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS = 0x18
+       NFC_ATTR_SE_APDU                  = 0x19
+       NFC_ATTR_TARGET_ISO15693_DSFID    = 0x1a
+       NFC_ATTR_TARGET_ISO15693_UID      = 0x1b
+       NFC_ATTR_SE_PARAMS                = 0x1c
+       NFC_ATTR_VENDOR_ID                = 0x1d
+       NFC_ATTR_VENDOR_SUBCMD            = 0x1e
+       NFC_ATTR_VENDOR_DATA              = 0x1f
+       NFC_SDP_ATTR_UNSPEC               = 0x0
+       NFC_SDP_ATTR_URI                  = 0x1
+       NFC_SDP_ATTR_SAP                  = 0x2
+)
+
+type LandlockRulesetAttr struct {
+       Access_fs uint64
+}
+
+type LandlockPathBeneathAttr struct {
+       Allowed_access uint64
+       Parent_fd      int32
+}
+
+const (
+       LANDLOCK_RULE_PATH_BENEATH = 0x1
+)
+
+const (
+       IPC_CREAT   = 0x200
+       IPC_EXCL    = 0x400
+       IPC_NOWAIT  = 0x800
+       IPC_PRIVATE = 0x0
+
+       ipc_64 = 0x100
+)
+
+const (
+       IPC_RMID = 0x0
+       IPC_SET  = 0x1
+       IPC_STAT = 0x2
+)
+
+const (
+       SHM_RDONLY = 0x1000
+       SHM_RND    = 0x2000
+)
index 4d4d283de5b1e2afb03885639c0f7b97b0f9966a..eeeb9aa39ac1c70a1da365dd41ef2e0bf01a674a 100644 (file)
@@ -128,6 +128,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint32
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -159,10 +170,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [16]byte
+}
+
 const (
-       SizeofIovec   = 0x8
-       SizeofMsghdr  = 0x1c
-       SizeofCmsghdr = 0xc
+       SizeofSockaddrNFCLLCP = 0x58
+       SizeofIovec           = 0x8
+       SizeofMsghdr          = 0x1c
+       SizeofCmsghdr         = 0xc
 )
 
 const (
@@ -618,3 +635,36 @@ const (
        PPS_GETCAP    = 0x800470a3
        PPS_FETCH     = 0xc00470a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint16
+       _    [2]uint8
+       Seq  uint16
+       _    uint16
+       _    uint32
+       _    uint32
+}
+type SysvShmDesc struct {
+       Perm       SysvIpcPerm
+       Segsz      uint32
+       Atime      uint32
+       Atime_high uint32
+       Dtime      uint32
+       Dtime_high uint32
+       Ctime      uint32
+       Ctime_high uint32
+       Cpid       int32
+       Lpid       int32
+       Nattch     uint32
+       _          uint32
+       _          uint32
+}
index 8a2eed5ec4e37a6e172f915f736e155560536367..d30e1155cc0685b513ee87dc320d0feb96b2b259 100644 (file)
@@ -130,6 +130,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -162,10 +173,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -636,3 +653,33 @@ const (
        PPS_GETCAP    = 0x800870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index 94b34add64309cae4b36eebe444cd756f4650dcc..69d0297520c4ee046dbaf3ffd053e575c575b55e 100644 (file)
@@ -134,6 +134,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint32
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]uint8
@@ -165,10 +176,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [16]byte
+}
+
 const (
-       SizeofIovec   = 0x8
-       SizeofMsghdr  = 0x1c
-       SizeofCmsghdr = 0xc
+       SizeofSockaddrNFCLLCP = 0x58
+       SizeofIovec           = 0x8
+       SizeofMsghdr          = 0x1c
+       SizeofCmsghdr         = 0xc
 )
 
 const (
@@ -613,3 +630,36 @@ const (
        PPS_GETCAP    = 0x800470a3
        PPS_FETCH     = 0xc00470a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint16
+       _    [2]uint8
+       Seq  uint16
+       _    uint16
+       _    uint32
+       _    uint32
+}
+type SysvShmDesc struct {
+       Perm       SysvIpcPerm
+       Segsz      uint32
+       Atime      uint32
+       Atime_high uint32
+       Dtime      uint32
+       Dtime_high uint32
+       Ctime      uint32
+       Ctime_high uint32
+       Cpid       int32
+       Lpid       int32
+       Nattch     uint32
+       _          uint32
+       _          uint32
+}
index 2143de4d599f5ae9f2e5eca3851223fd51037e41..28a0455bc9d60c396b2a2dafe7720da6e6cb4a08 100644 (file)
@@ -131,6 +131,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -163,10 +174,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -615,3 +632,33 @@ const (
        PPS_GETCAP    = 0x800870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index a40216eee60a07907e80e6cd674574eef6f98284..64a845483db2e22ad97a1214459fe2b0c8ef2ba3 100644 (file)
@@ -133,6 +133,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint32
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -164,10 +175,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [16]byte
+}
+
 const (
-       SizeofIovec   = 0x8
-       SizeofMsghdr  = 0x1c
-       SizeofCmsghdr = 0xc
+       SizeofSockaddrNFCLLCP = 0x58
+       SizeofIovec           = 0x8
+       SizeofMsghdr          = 0x1c
+       SizeofCmsghdr         = 0xc
 )
 
 const (
@@ -619,3 +636,35 @@ const (
        PPS_GETCAP    = 0x400470a3
        PPS_FETCH     = 0xc00470a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x80
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint32
+       _    uint32
+}
+type SysvShmDesc struct {
+       Perm       SysvIpcPerm
+       Segsz      uint32
+       Atime      uint32
+       Dtime      uint32
+       Ctime      uint32
+       Cpid       int32
+       Lpid       int32
+       Nattch     uint32
+       Atime_high uint16
+       Dtime_high uint16
+       Ctime_high uint16
+       _          uint16
+}
index e834b069fd5c1e9f847a4e091fd8f8763e782866..a1b7dee4123d9836dfa8c1490134b4a7c24c5650 100644 (file)
@@ -131,6 +131,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -163,10 +174,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -618,3 +635,33 @@ const (
        PPS_GETCAP    = 0x400870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x80
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index e31083b0489666d06f4709acdb1ede42d2a85dc8..936fa6a266f1abb0bf192e806250fdadcc3d8095 100644 (file)
@@ -131,6 +131,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -163,10 +174,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -618,3 +635,33 @@ const (
        PPS_GETCAP    = 0x400870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x80
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index 42811f7fb5595815f62dcce8be5921816ae5a63f..5dd546fbf0790b126d3bb0a81a062a8e48a397d9 100644 (file)
@@ -133,6 +133,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint32
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -164,10 +175,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [16]byte
+}
+
 const (
-       SizeofIovec   = 0x8
-       SizeofMsghdr  = 0x1c
-       SizeofCmsghdr = 0xc
+       SizeofSockaddrNFCLLCP = 0x58
+       SizeofIovec           = 0x8
+       SizeofMsghdr          = 0x1c
+       SizeofCmsghdr         = 0xc
 )
 
 const (
@@ -619,3 +636,35 @@ const (
        PPS_GETCAP    = 0x400470a3
        PPS_FETCH     = 0xc00470a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x80
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint32
+       _    uint32
+}
+type SysvShmDesc struct {
+       Perm       SysvIpcPerm
+       Segsz      uint32
+       Atime      uint32
+       Dtime      uint32
+       Ctime      uint32
+       Cpid       int32
+       Lpid       int32
+       Nattch     uint32
+       Atime_high uint16
+       Dtime_high uint16
+       Ctime_high uint16
+       _          uint16
+}
index af7a72017e9fb1c7614483c09c365fe57fadb12c..947b32e434b05c73dc799558be8496b808ab4011 100644 (file)
@@ -134,6 +134,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint32
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]uint8
@@ -165,10 +176,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [16]byte
+}
+
 const (
-       SizeofIovec   = 0x8
-       SizeofMsghdr  = 0x1c
-       SizeofCmsghdr = 0xc
+       SizeofSockaddrNFCLLCP = 0x58
+       SizeofIovec           = 0x8
+       SizeofMsghdr          = 0x1c
+       SizeofCmsghdr         = 0xc
 )
 
 const (
@@ -625,3 +642,37 @@ const (
        PPS_GETCAP    = 0x400470a3
        PPS_FETCH     = 0xc00470a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       Seq  uint32
+       _    uint32
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm       SysvIpcPerm
+       Atime_high uint32
+       Atime      uint32
+       Dtime_high uint32
+       Dtime      uint32
+       Ctime_high uint32
+       Ctime      uint32
+       _          uint32
+       Segsz      uint32
+       Cpid       int32
+       Lpid       int32
+       Nattch     uint32
+       _          uint32
+       _          uint32
+       _          [4]byte
+}
index 2a3afbaef9fcdb2de0cab51ce71e80a41dd06998..2a606151b0c8d6086f1824c382903089c8397622 100644 (file)
@@ -132,6 +132,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]uint8
@@ -164,10 +175,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -625,3 +642,32 @@ const (
        PPS_GETCAP    = 0x400870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       Seq  uint32
+       _    uint32
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Segsz  uint64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index c0de30a658a4ab1f3fa9cd56e8691d5cc2baea0d..d0d735d02cd8eacda1b4ea2295f3c9cc29559e6a 100644 (file)
@@ -132,6 +132,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]uint8
@@ -164,10 +175,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -625,3 +642,32 @@ const (
        PPS_GETCAP    = 0x400870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       Seq  uint32
+       _    uint32
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Segsz  uint64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index 74faf2e91fdc579c3f80343827bc8948f5a4d17b..95e3d6d06fcac198ff1ed5b45bc72575d717f064 100644 (file)
@@ -131,6 +131,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]uint8
@@ -163,10 +174,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -643,3 +660,33 @@ const (
        PPS_GETCAP    = 0x800870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    [0]uint8
+       Seq  uint16
+       _    uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index 9a8f0c2c6a3d99879954a962706c5a25bf2632da..cccf1ef26a65673ed81ba8242dc99b6f0ac25d3b 100644 (file)
@@ -130,6 +130,17 @@ const (
        FADV_NOREUSE  = 0x7
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -162,10 +173,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -639,3 +656,32 @@ const (
        PPS_GETCAP    = 0x800870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x800
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    uint16
+       Seq  uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Segsz  uint64
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index 72cdda75bde94d60fe92e3fed75432c5ea81b39f..44fcbe4e9a1baaa4f1d330fa6664dfd9294251cc 100644 (file)
@@ -134,6 +134,17 @@ const (
        FADV_NOREUSE  = 0x5
 )
 
+type RawSockaddrNFCLLCP struct {
+       Sa_family        uint16
+       Dev_idx          uint32
+       Target_idx       uint32
+       Nfc_protocol     uint32
+       Dsap             uint8
+       Ssap             uint8
+       Service_name     [63]uint8
+       Service_name_len uint64
+}
+
 type RawSockaddr struct {
        Family uint16
        Data   [14]int8
@@ -166,10 +177,16 @@ type Cmsghdr struct {
        Type  int32
 }
 
+type ifreq struct {
+       Ifrn [16]byte
+       Ifru [24]byte
+}
+
 const (
-       SizeofIovec   = 0x10
-       SizeofMsghdr  = 0x38
-       SizeofCmsghdr = 0x10
+       SizeofSockaddrNFCLLCP = 0x60
+       SizeofIovec           = 0x10
+       SizeofMsghdr          = 0x38
+       SizeofCmsghdr         = 0x10
 )
 
 const (
@@ -620,3 +637,32 @@ const (
        PPS_GETCAP    = 0x400870a3
        PPS_FETCH     = 0xc00870a4
 )
+
+const (
+       PIDFD_NONBLOCK = 0x4000
+)
+
+type SysvIpcPerm struct {
+       Key  int32
+       Uid  uint32
+       Gid  uint32
+       Cuid uint32
+       Cgid uint32
+       Mode uint32
+       _    uint16
+       Seq  uint16
+       _    uint64
+       _    uint64
+}
+type SysvShmDesc struct {
+       Perm   SysvIpcPerm
+       Atime  int64
+       Dtime  int64
+       Ctime  int64
+       Segsz  uint64
+       Cpid   int32
+       Lpid   int32
+       Nattch uint64
+       _      uint64
+       _      uint64
+}
index b10e73abf95c0754de5b63f5175aa52a57673bed..2fd2060e617a4797a506475d1a24719c785b6dde 100644 (file)
@@ -445,8 +445,10 @@ type Ptmget struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index 28ed6d55ae3ac04e1f6d1e369c454962f63112f7..6a5a1a8ae5568680e7e086dc04420128621350b1 100644 (file)
@@ -453,8 +453,10 @@ type Ptmget struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index 4ba196ebe563fb23d13e82ab02b54b1e5ca6356b..84cc8d01e6566ec5eb4f4501fb000f15fcc203a5 100644 (file)
@@ -450,8 +450,10 @@ type Ptmget struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index dd642bd9c874dd7e357fcb3c20db93224489448c..c844e7096ff5a58db6ce4c88855e1e3862cb2548 100644 (file)
@@ -453,8 +453,10 @@ type Ptmget struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x400
+       AT_EACCESS          = 0x100
        AT_SYMLINK_NOFOLLOW = 0x200
+       AT_SYMLINK_FOLLOW   = 0x400
+       AT_REMOVEDIR        = 0x800
 )
 
 type PollFd struct {
index 1fdb0e5fa5f90b749ca6994b5f8c6c5c2cc14ec9..2a8b1e6f73f5197531c913487b9ad316ebb1f678 100644 (file)
@@ -438,8 +438,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x4
+       AT_EACCESS          = 0x1
        AT_SYMLINK_NOFOLLOW = 0x2
+       AT_SYMLINK_FOLLOW   = 0x4
+       AT_REMOVEDIR        = 0x8
 )
 
 type PollFd struct {
index e2fc93c7c06966ac8e474be7ae0c05ab8c3fb54d..b1759cf705c007f45fe3d68e0d2c11caf370714e 100644 (file)
@@ -438,8 +438,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x4
+       AT_EACCESS          = 0x1
        AT_SYMLINK_NOFOLLOW = 0x2
+       AT_SYMLINK_FOLLOW   = 0x4
+       AT_REMOVEDIR        = 0x8
 )
 
 type PollFd struct {
index 8d34b5a2fc065eda8ec88c6079f9c7031560dfb3..e807de2065c74e0c95cc15d3bf416926a4bc9893 100644 (file)
@@ -439,8 +439,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x4
+       AT_EACCESS          = 0x1
        AT_SYMLINK_NOFOLLOW = 0x2
+       AT_SYMLINK_FOLLOW   = 0x4
+       AT_REMOVEDIR        = 0x8
 )
 
 type PollFd struct {
index ea8f1a0d9ba2d0bd4712859b188474d0081f8b26..ff3aecaee40ac15ca6937694d92f1300b71e5514 100644 (file)
@@ -432,8 +432,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x4
+       AT_EACCESS          = 0x1
        AT_SYMLINK_NOFOLLOW = 0x2
+       AT_SYMLINK_FOLLOW   = 0x4
+       AT_REMOVEDIR        = 0x8
 )
 
 type PollFd struct {
index ec6e8bc3f13560564d1897b62d1230655bc89e7c..9ecda69174c844e5d8a305f5383b9f228c16b678 100644 (file)
@@ -432,8 +432,10 @@ type Winsize struct {
 
 const (
        AT_FDCWD            = -0x64
-       AT_SYMLINK_FOLLOW   = 0x4
+       AT_EACCESS          = 0x1
        AT_SYMLINK_NOFOLLOW = 0x2
+       AT_SYMLINK_FOLLOW   = 0x4
+       AT_REMOVEDIR        = 0x8
 )
 
 type PollFd struct {
index 85effef9c199e6b90c275d5da1829a6c91260787..ad4aad27968699379e0961876f91342d35d2b1d8 100644 (file)
@@ -440,3 +440,43 @@ const (
        POLLWRBAND = 0x100
        POLLWRNORM = 0x4
 )
+
+type fileObj struct {
+       Atim Timespec
+       Mtim Timespec
+       Ctim Timespec
+       Pad  [3]uint64
+       Name *int8
+}
+
+type portEvent struct {
+       Events int32
+       Source uint16
+       Pad    uint16
+       Object uint64
+       User   *byte
+}
+
+const (
+       PORT_SOURCE_AIO    = 0x1
+       PORT_SOURCE_TIMER  = 0x2
+       PORT_SOURCE_USER   = 0x3
+       PORT_SOURCE_FD     = 0x4
+       PORT_SOURCE_ALERT  = 0x5
+       PORT_SOURCE_MQ     = 0x6
+       PORT_SOURCE_FILE   = 0x7
+       PORT_ALERT_SET     = 0x1
+       PORT_ALERT_UPDATE  = 0x2
+       PORT_ALERT_INVALID = 0x3
+       FILE_ACCESS        = 0x1
+       FILE_MODIFIED      = 0x2
+       FILE_ATTRIB        = 0x4
+       FILE_TRUNC         = 0x100000
+       FILE_NOFOLLOW      = 0x10000000
+       FILE_DELETE        = 0x10
+       FILE_RENAME_TO     = 0x20
+       FILE_RENAME_FROM   = 0x40
+       UNMOUNTED          = 0x20000000
+       MOUNTEDOVER        = 0x40000000
+       FILE_EXCEPTION     = 0x60000070
+)
index 9eb1fb633a46f101b4454dc2c45475359fe7f875..7a11e83b7ec10206ebaf5b547690db3cfeb1de90 100644 (file)
@@ -9,6 +9,8 @@ package windows
 import (
        errorspkg "errors"
        "unsafe"
+
+       "golang.org/x/sys/internal/unsafeheader"
 )
 
 // EscapeArg rewrites command line argument s as prescribed
@@ -78,6 +80,40 @@ func EscapeArg(s string) string {
        return string(qs[:j])
 }
 
+// ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line,
+// in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
+// or any program that uses CommandLineToArgv.
+func ComposeCommandLine(args []string) string {
+       var commandLine string
+       for i := range args {
+               if i > 0 {
+                       commandLine += " "
+               }
+               commandLine += EscapeArg(args[i])
+       }
+       return commandLine
+}
+
+// DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
+// as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
+// command lines are passed around.
+func DecomposeCommandLine(commandLine string) ([]string, error) {
+       if len(commandLine) == 0 {
+               return []string{}, nil
+       }
+       var argc int32
+       argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc)
+       if err != nil {
+               return nil, err
+       }
+       defer LocalFree(Handle(unsafe.Pointer(argv)))
+       var args []string
+       for _, v := range (*argv)[:argc] {
+               args = append(args, UTF16ToString((*v)[:]))
+       }
+       return args, nil
+}
+
 func CloseOnExec(fd Handle) {
        SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
 }
@@ -101,8 +137,8 @@ func FullPath(name string) (path string, err error) {
        }
 }
 
-// NewProcThreadAttributeList allocates a new ProcThreadAttributeList, with the requested maximum number of attributes.
-func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeList, error) {
+// NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes.
+func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) {
        var size uintptr
        err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)
        if err != ERROR_INSUFFICIENT_BUFFER {
@@ -111,10 +147,9 @@ func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeList,
                }
                return nil, err
        }
-       const psize = unsafe.Sizeof(uintptr(0))
        // size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.
-       al := (*ProcThreadAttributeList)(unsafe.Pointer(&make([]unsafe.Pointer, (size+psize-1)/psize)[0]))
-       err = initializeProcThreadAttributeList(al, maxAttrCount, 0, &size)
+       al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(&make([]byte, size)[0]))}
+       err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size)
        if err != nil {
                return nil, err
        }
@@ -122,11 +157,39 @@ func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeList,
 }
 
 // Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
-func (al *ProcThreadAttributeList) Update(attribute uintptr, flags uint32, value unsafe.Pointer, size uintptr, prevValue unsafe.Pointer, returnedSize *uintptr) error {
-       return updateProcThreadAttribute(al, flags, attribute, value, size, prevValue, returnedSize)
+// Note that the value passed to this function will be copied into memory
+// allocated by LocalAlloc, the contents of which should not contain any
+// Go-managed pointers, even if the passed value itself is a Go-managed
+// pointer.
+func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error {
+       alloc, err := LocalAlloc(LMEM_FIXED, uint32(size))
+       if err != nil {
+               return err
+       }
+       var src, dst []byte
+       hdr := (*unsafeheader.Slice)(unsafe.Pointer(&src))
+       hdr.Data = value
+       hdr.Cap = int(size)
+       hdr.Len = int(size)
+       hdr = (*unsafeheader.Slice)(unsafe.Pointer(&dst))
+       hdr.Data = unsafe.Pointer(alloc)
+       hdr.Cap = int(size)
+       hdr.Len = int(size)
+       copy(dst, src)
+       al.heapAllocations = append(al.heapAllocations, alloc)
+       return updateProcThreadAttribute(al.data, 0, attribute, unsafe.Pointer(alloc), size, nil, nil)
 }
 
 // Delete frees ProcThreadAttributeList's resources.
-func (al *ProcThreadAttributeList) Delete() {
-       deleteProcThreadAttributeList(al)
+func (al *ProcThreadAttributeListContainer) Delete() {
+       deleteProcThreadAttributeList(al.data)
+       for i := range al.heapAllocations {
+               LocalFree(Handle(al.heapAllocations[i]))
+       }
+       al.heapAllocations = nil
+}
+
+// List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx.
+func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList {
+       return al.data
 }
index 1adb60739a34b9b22284602d4117b8b0882824b7..6dc0920a84da2ab53810713043af3254cac6dc55 100644 (file)
@@ -35,3 +35,14 @@ const (
        QUOTA_LIMITS_HARDWS_MAX_DISABLE = 0x00000008
        QUOTA_LIMITS_HARDWS_MAX_ENABLE  = 0x00000004
 )
+
+type MemoryBasicInformation struct {
+       BaseAddress       uintptr
+       AllocationBase    uintptr
+       AllocationProtect uint32
+       PartitionId       uint16
+       RegionSize        uintptr
+       State             uint32
+       Protect           uint32
+       Type              uint32
+}
index 111c10d3a7f6033bd5b8cbe94f085c33a4b31917..d414ef13bef04e1ae1a992502076851f0515a0d2 100644 (file)
@@ -889,6 +889,7 @@ type WTS_SESSION_INFO struct {
 //sys WTSQueryUserToken(session uint32, token *Token) (err error) = wtsapi32.WTSQueryUserToken
 //sys WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW
 //sys WTSFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory
+//sys WTSGetActiveConsoleSessionId() (sessionID uint32)
 
 type ACL struct {
        aclRevision byte
index bb6aaf89e47c6a40ffa465f68dc88168afe5431e..d3b59ae69cd3c2b0e751cda12d2ffa899cd1eea7 100644 (file)
@@ -220,6 +220,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys  CancelIo(s Handle) (err error)
 //sys  CancelIoEx(s Handle, o *Overlapped) (err error)
 //sys  CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
+//sys  CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = advapi32.CreateProcessAsUserW
 //sys   initializeProcThreadAttributeList(attrlist *ProcThreadAttributeList, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList
 //sys   deleteProcThreadAttributeList(attrlist *ProcThreadAttributeList) = DeleteProcThreadAttributeList
 //sys   updateProcThreadAttribute(attrlist *ProcThreadAttributeList, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute
@@ -273,6 +274,11 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys  VirtualAlloc(address uintptr, size uintptr, alloctype uint32, protect uint32) (value uintptr, err error) = kernel32.VirtualAlloc
 //sys  VirtualFree(address uintptr, size uintptr, freetype uint32) (err error) = kernel32.VirtualFree
 //sys  VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect *uint32) (err error) = kernel32.VirtualProtect
+//sys  VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect uint32, oldProtect *uint32) (err error) = kernel32.VirtualProtectEx
+//sys  VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery
+//sys  VirtualQueryEx(process Handle, address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQueryEx
+//sys  ReadProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uintptr, numberOfBytesRead *uintptr) (err error) = kernel32.ReadProcessMemory
+//sys  WriteProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uintptr, numberOfBytesWritten *uintptr) (err error) = kernel32.WriteProcessMemory
 //sys  TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
 //sys  ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
 //sys  FindFirstChangeNotification(path string, watchSubtree bool, notifyFilter uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.FindFirstChangeNotificationW
@@ -397,6 +403,11 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 
 // Process Status API (PSAPI)
 //sys  EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
+//sys  EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) = psapi.EnumProcessModules
+//sys  EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) = psapi.EnumProcessModulesEx
+//sys  GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) = psapi.GetModuleInformation
+//sys  GetModuleFileNameEx(process Handle, module Handle, filename *uint16, size uint32) (err error) = psapi.GetModuleFileNameExW
+//sys  GetModuleBaseName(process Handle, module Handle, baseName *uint16, size uint32) (err error) = psapi.GetModuleBaseNameW
 
 // NT Native APIs
 //sys  rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) = ntdll.RtlNtStatusToDosErrorNoTeb
index 23fe18ecef2123da402d09a306def62d35d9f999..88e0ce5d0db6c73e49b2ad94884747fd97aa5751 100644 (file)
@@ -242,6 +242,14 @@ const (
        TH32CS_INHERIT      = 0x80000000
 )
 
+const (
+       // flags for EnumProcessModulesEx
+       LIST_MODULES_32BIT   = 0x01
+       LIST_MODULES_64BIT   = 0x02
+       LIST_MODULES_ALL     = 0x03
+       LIST_MODULES_DEFAULT = 0x00
+)
+
 const (
        // filters for ReadDirectoryChangesW and FindFirstChangeNotificationW
        FILE_NOTIFY_CHANGE_FILE_NAME   = 0x001
@@ -680,7 +688,7 @@ const (
        WTD_CHOICE_CERT    = 5
 
        WTD_STATEACTION_IGNORE           = 0x00000000
-       WTD_STATEACTION_VERIFY           = 0x00000010
+       WTD_STATEACTION_VERIFY           = 0x00000001
        WTD_STATEACTION_CLOSE            = 0x00000002
        WTD_STATEACTION_AUTO_CACHE       = 0x00000003
        WTD_STATEACTION_AUTO_CACHE_FLUSH = 0x00000004
@@ -909,14 +917,15 @@ type StartupInfoEx struct {
 
 // ProcThreadAttributeList is a placeholder type to represent a PROC_THREAD_ATTRIBUTE_LIST.
 //
-// To create a *ProcThreadAttributeList, use NewProcThreadAttributeList, and
-// free its memory using ProcThreadAttributeList.Delete.
-type ProcThreadAttributeList struct {
-       // This is of type unsafe.Pointer, not of type byte or uintptr, because
-       // the contents of it is mostly a list of pointers, and in most cases,
-       // that's a list of pointers to Go-allocated objects. In order to keep
-       // the GC from collecting these objects, we declare this as unsafe.Pointer.
-       _ [1]unsafe.Pointer
+// To create a *ProcThreadAttributeList, use NewProcThreadAttributeList, update
+// it with ProcThreadAttributeListContainer.Update, free its memory using
+// ProcThreadAttributeListContainer.Delete, and access the list itself using
+// ProcThreadAttributeListContainer.List.
+type ProcThreadAttributeList struct{}
+
+type ProcThreadAttributeListContainer struct {
+       data            *ProcThreadAttributeList
+       heapAllocations []uintptr
 }
 
 type ProcessInformation struct {
@@ -2772,3 +2781,9 @@ const (
 
 // Flag for QueryFullProcessImageName.
 const PROCESS_NAME_NATIVE = 1
+
+type ModuleInfo struct {
+       BaseOfDll   uintptr
+       SizeOfImage uint32
+       EntryPoint  uintptr
+}
index 559bc845c99cdaa078b0d25125a772218fe0e846..4ea788e4c415bb424943c8864c9645c1ab2d7435 100644 (file)
@@ -69,6 +69,7 @@ var (
        procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
        procConvertStringSidToSidW                               = modadvapi32.NewProc("ConvertStringSidToSidW")
        procCopySid                                              = modadvapi32.NewProc("CopySid")
+       procCreateProcessAsUserW                                 = modadvapi32.NewProc("CreateProcessAsUserW")
        procCreateServiceW                                       = modadvapi32.NewProc("CreateServiceW")
        procCreateWellKnownSid                                   = modadvapi32.NewProc("CreateWellKnownSid")
        procCryptAcquireContextW                                 = modadvapi32.NewProc("CryptAcquireContextW")
@@ -302,6 +303,7 @@ var (
        procReadConsoleW                                         = modkernel32.NewProc("ReadConsoleW")
        procReadDirectoryChangesW                                = modkernel32.NewProc("ReadDirectoryChangesW")
        procReadFile                                             = modkernel32.NewProc("ReadFile")
+       procReadProcessMemory                                    = modkernel32.NewProc("ReadProcessMemory")
        procReleaseMutex                                         = modkernel32.NewProc("ReleaseMutex")
        procRemoveDirectoryW                                     = modkernel32.NewProc("RemoveDirectoryW")
        procResetEvent                                           = modkernel32.NewProc("ResetEvent")
@@ -344,11 +346,16 @@ var (
        procVirtualFree                                          = modkernel32.NewProc("VirtualFree")
        procVirtualLock                                          = modkernel32.NewProc("VirtualLock")
        procVirtualProtect                                       = modkernel32.NewProc("VirtualProtect")
+       procVirtualProtectEx                                     = modkernel32.NewProc("VirtualProtectEx")
+       procVirtualQuery                                         = modkernel32.NewProc("VirtualQuery")
+       procVirtualQueryEx                                       = modkernel32.NewProc("VirtualQueryEx")
        procVirtualUnlock                                        = modkernel32.NewProc("VirtualUnlock")
+       procWTSGetActiveConsoleSessionId                         = modkernel32.NewProc("WTSGetActiveConsoleSessionId")
        procWaitForMultipleObjects                               = modkernel32.NewProc("WaitForMultipleObjects")
        procWaitForSingleObject                                  = modkernel32.NewProc("WaitForSingleObject")
        procWriteConsoleW                                        = modkernel32.NewProc("WriteConsoleW")
        procWriteFile                                            = modkernel32.NewProc("WriteFile")
+       procWriteProcessMemory                                   = modkernel32.NewProc("WriteProcessMemory")
        procAcceptEx                                             = modmswsock.NewProc("AcceptEx")
        procGetAcceptExSockaddrs                                 = modmswsock.NewProc("GetAcceptExSockaddrs")
        procTransmitFile                                         = modmswsock.NewProc("TransmitFile")
@@ -375,7 +382,12 @@ var (
        procCoTaskMemFree                                        = modole32.NewProc("CoTaskMemFree")
        procCoUninitialize                                       = modole32.NewProc("CoUninitialize")
        procStringFromGUID2                                      = modole32.NewProc("StringFromGUID2")
+       procEnumProcessModules                                   = modpsapi.NewProc("EnumProcessModules")
+       procEnumProcessModulesEx                                 = modpsapi.NewProc("EnumProcessModulesEx")
        procEnumProcesses                                        = modpsapi.NewProc("EnumProcesses")
+       procGetModuleBaseNameW                                   = modpsapi.NewProc("GetModuleBaseNameW")
+       procGetModuleFileNameExW                                 = modpsapi.NewProc("GetModuleFileNameExW")
+       procGetModuleInformation                                 = modpsapi.NewProc("GetModuleInformation")
        procSubscribeServiceChangeNotifications                  = modsechost.NewProc("SubscribeServiceChangeNotifications")
        procUnsubscribeServiceChangeNotifications                = modsechost.NewProc("UnsubscribeServiceChangeNotifications")
        procGetUserNameExW                                       = modsecur32.NewProc("GetUserNameExW")
@@ -553,6 +565,18 @@ func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) {
        return
 }
 
+func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) {
+       var _p0 uint32
+       if inheritHandles {
+               _p0 = 1
+       }
+       r1, _, e1 := syscall.Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) {
        r0, _, e1 := syscall.Syscall15(procCreateServiceW.Addr(), 13, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), 0, 0)
        handle = Handle(r0)
@@ -2617,6 +2641,14 @@ func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (
        return
 }
 
+func ReadProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uintptr, numberOfBytesRead *uintptr) (err error) {
+       r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesRead)), 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func ReleaseMutex(mutex Handle) (err error) {
        r1, _, e1 := syscall.Syscall(procReleaseMutex.Addr(), 1, uintptr(mutex), 0, 0)
        if r1 == 0 {
@@ -2971,6 +3003,30 @@ func VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect
        return
 }
 
+func VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect uint32, oldProtect *uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procVirtualProtectEx.Addr(), 5, uintptr(process), uintptr(address), uintptr(size), uintptr(newProtect), uintptr(unsafe.Pointer(oldProtect)), 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) {
+       r1, _, e1 := syscall.Syscall(procVirtualQuery.Addr(), 3, uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length))
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func VirtualQueryEx(process Handle, address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) {
+       r1, _, e1 := syscall.Syscall6(procVirtualQueryEx.Addr(), 4, uintptr(process), uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length), 0, 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func VirtualUnlock(addr uintptr, length uintptr) (err error) {
        r1, _, e1 := syscall.Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
        if r1 == 0 {
@@ -2979,6 +3035,12 @@ func VirtualUnlock(addr uintptr, length uintptr) (err error) {
        return
 }
 
+func WTSGetActiveConsoleSessionId() (sessionID uint32) {
+       r0, _, _ := syscall.Syscall(procWTSGetActiveConsoleSessionId.Addr(), 0, 0, 0, 0)
+       sessionID = uint32(r0)
+       return
+}
+
 func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) {
        var _p0 uint32
        if waitAll {
@@ -3021,6 +3083,14 @@ func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped)
        return
 }
 
+func WriteProcessMemory(process Handle, baseAddress uintptr, buffer *byte, size uintptr, numberOfBytesWritten *uintptr) (err error) {
+       r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseAddress), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(numberOfBytesWritten)), 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) {
        r1, _, e1 := syscall.Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
        if r1 == 0 {
@@ -3205,6 +3275,22 @@ func stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) {
        return
 }
 
+func EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procEnumProcessModules.Addr(), 4, uintptr(process), uintptr(unsafe.Pointer(module)), uintptr(cb), uintptr(unsafe.Pointer(cbNeeded)), 0, 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procEnumProcessModulesEx.Addr(), 5, uintptr(process), uintptr(unsafe.Pointer(module)), uintptr(cb), uintptr(unsafe.Pointer(cbNeeded)), uintptr(filterFlag), 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) {
        var _p0 *uint32
        if len(processIds) > 0 {
@@ -3217,6 +3303,30 @@ func EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) {
        return
 }
 
+func GetModuleBaseName(process Handle, module Handle, baseName *uint16, size uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procGetModuleBaseNameW.Addr(), 4, uintptr(process), uintptr(module), uintptr(unsafe.Pointer(baseName)), uintptr(size), 0, 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func GetModuleFileNameEx(process Handle, module Handle, filename *uint16, size uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procGetModuleFileNameExW.Addr(), 4, uintptr(process), uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size), 0, 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) {
+       r1, _, e1 := syscall.Syscall6(procGetModuleInformation.Addr(), 4, uintptr(process), uintptr(module), uintptr(unsafe.Pointer(modinfo)), uintptr(cb), 0, 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func SubscribeServiceChangeNotifications(service Handle, eventType uint32, callback uintptr, callbackCtx uintptr, subscription *uintptr) (ret error) {
        ret = procSubscribeServiceChangeNotifications.Find()
        if ret != nil {
index 57195774cea1541a7a8c145dd15179eb4ee606b9..47a9a541164b23b90bb09e03d4f7a7aab721a6a3 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bufio"
        "errors"
        "fmt"
+       "io"
        "math"
        "os"
        "sort"
@@ -45,14 +46,18 @@ func ParseProfiles(fileName string) ([]*Profile, error) {
                return nil, err
        }
        defer pf.Close()
+       return ParseProfilesFromReader(pf)
+}
 
-       files := make(map[string]*Profile)
-       buf := bufio.NewReader(pf)
+// ParseProfilesFromReader parses profile data from the Reader and
+// returns a Profile for each source file described therein.
+func ParseProfilesFromReader(rd io.Reader) ([]*Profile, error) {
        // First line is "mode: foo", where foo is "set", "count", or "atomic".
        // Rest of file is in the format
        //      encoding/base64/base64.go:34.44,37.40 3 1
        // where the fields are: name.go:line.column,line.column numberOfStatements count
-       s := bufio.NewScanner(buf)
+       files := make(map[string]*Profile)
+       s := bufio.NewScanner(rd)
        mode := ""
        for s.Scan() {
                line := s.Text()
index 4c3ac6647f6acb26810af1d690d2c5712d37d544..025952ed5001296f08cbdab184019fdee353bdae 100644 (file)
@@ -14,6 +14,7 @@ import (
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/typeparams"
 )
 
 const Doc = `check for unkeyed composite literals
@@ -67,41 +68,52 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        // skip whitelisted types
                        return
                }
-               under := typ.Underlying()
-               for {
-                       ptr, ok := under.(*types.Pointer)
-                       if !ok {
-                               break
-                       }
-                       under = ptr.Elem().Underlying()
-               }
-               if _, ok := under.(*types.Struct); !ok {
-                       // skip non-struct composite literals
-                       return
-               }
-               if isLocalType(pass, typ) {
-                       // allow unkeyed locally defined composite literal
-                       return
+               terms, err := typeparams.StructuralTerms(typ)
+               if err != nil {
+                       return // invalid type
                }
+               for _, term := range terms {
+                       under := deref(term.Type().Underlying())
+                       if _, ok := under.(*types.Struct); !ok {
+                               // skip non-struct composite literals
+                               continue
+                       }
+                       if isLocalType(pass, term.Type()) {
+                               // allow unkeyed locally defined composite literal
+                               continue
+                       }
 
-               // check if the CompositeLit contains an unkeyed field
-               allKeyValue := true
-               for _, e := range cl.Elts {
-                       if _, ok := e.(*ast.KeyValueExpr); !ok {
-                               allKeyValue = false
-                               break
+                       // check if the CompositeLit contains an unkeyed field
+                       allKeyValue := true
+                       for _, e := range cl.Elts {
+                               if _, ok := e.(*ast.KeyValueExpr); !ok {
+                                       allKeyValue = false
+                                       break
+                               }
                        }
-               }
-               if allKeyValue {
-                       // all the composite literal fields are keyed
+                       if allKeyValue {
+                               // all the composite literal fields are keyed
+                               continue
+                       }
+
+                       pass.ReportRangef(cl, "%s composite literal uses unkeyed fields", typeName)
                        return
                }
-
-               pass.ReportRangef(cl, "%s composite literal uses unkeyed fields", typeName)
        })
        return nil, nil
 }
 
+func deref(typ types.Type) types.Type {
+       for {
+               ptr, ok := typ.(*types.Pointer)
+               if !ok {
+                       break
+               }
+               typ = ptr.Elem().Underlying()
+       }
+       return typ
+}
+
 func isLocalType(pass *analysis.Pass, typ types.Type) bool {
        switch x := typ.(type) {
        case *types.Struct:
@@ -112,6 +124,8 @@ func isLocalType(pass *analysis.Pass, typ types.Type) bool {
        case *types.Named:
                // names in package foo are local to foo_test too
                return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
+       case *typeparams.TypeParam:
+               return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
        }
        return false
 }
index 6589478af0f5c1690faff7fc4f209e7e6854f877..4169d30e4fca3a0d7ea7f4849a96a084d138f5a9 100644 (file)
@@ -490,7 +490,7 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func,
                _, ok = isPrint[strings.ToLower(fn.Name())]
        }
        if ok {
-               if fn.Name() == "Errorf" {
+               if fn.FullName() == "fmt.Errorf" {
                        kind = KindErrorf
                } else if strings.HasSuffix(fn.Name(), "f") {
                        kind = KindPrintf
@@ -590,12 +590,9 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F
                }
                if state.verb == 'w' {
                        switch kind {
-                       case KindNone, KindPrint:
+                       case KindNone, KindPrint, KindPrintf:
                                pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name)
                                return
-                       case KindPrintf:
-                               pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w, which is only supported for functions backed by fmt.Errorf", state.name)
-                               return
                        }
                        if anyW {
                                pass.Reportf(call.Pos(), "%s call has more than one error-wrapping directive %%w", state.name)
@@ -837,8 +834,9 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
        }
 
        // Could current arg implement fmt.Formatter?
+       // Skip check for the %w verb, which requires an error.
        formatter := false
-       if state.argNum < len(call.Args) {
+       if v.typ != argError && state.argNum < len(call.Args) {
                if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {
                        formatter = isFormatter(tv.Type)
                }
index d2b9a5640d934817249c23bf22f16ffcfc488d63..ce05a56cca3a3743802c99ef991dbc334b819d7a 100644 (file)
@@ -119,11 +119,33 @@ func typeIsTestingDotTOrB(expr ast.Expr) (string, bool) {
        return varTypeName, ok
 }
 
+// goStmtFunc returns the ast.Node of a call expression
+// that was invoked as a go statement. Currently, only
+// function literals declared in the same function, and
+// static calls within the same package are supported.
+func goStmtFun(goStmt *ast.GoStmt) ast.Node {
+       switch goStmt.Call.Fun.(type) {
+       case *ast.Ident:
+               id := goStmt.Call.Fun.(*ast.Ident)
+               // TODO(cuonglm): improve this once golang/go#48141 resolved.
+               if id.Obj == nil {
+                       break
+               }
+               if funDecl, ok := id.Obj.Decl.(ast.Node); ok {
+                       return funDecl
+               }
+       case *ast.FuncLit:
+               return goStmt.Call.Fun
+       }
+       return goStmt.Call
+}
+
 // checkGoStmt traverses the goroutine and checks for the
 // use of the forbidden *testing.(B, T) methods.
 func checkGoStmt(pass *analysis.Pass, goStmt *ast.GoStmt) {
+       fn := goStmtFun(goStmt)
        // Otherwise examine the goroutine to check for the forbidden methods.
-       ast.Inspect(goStmt, func(n ast.Node) bool {
+       ast.Inspect(fn, func(n ast.Node) bool {
                selExpr, ok := n.(*ast.SelectorExpr)
                if !ok {
                        return true
@@ -147,7 +169,11 @@ func checkGoStmt(pass *analysis.Pass, goStmt *ast.GoStmt) {
                        return true
                }
                if typeName, ok := typeIsTestingDotTOrB(field.Type); ok {
-                       pass.ReportRangef(selExpr, "call to (*%s).%s from a non-test goroutine", typeName, selExpr.Sel)
+                       var fnRange analysis.Range = goStmt
+                       if _, ok := fn.(*ast.FuncLit); ok {
+                               fnRange = selExpr
+                       }
+                       pass.ReportRangef(fnRange, "call to (*%s).%s from a non-test goroutine", typeName, selExpr.Sel)
                }
                return true
        })
index 8232276186aeab15f8bbecb5377ed9e20c220715..570ad5c20965b57c44334c78bf1ce647f5366fff 100644 (file)
@@ -8,7 +8,9 @@ package tests
 
 import (
        "go/ast"
+       "go/token"
        "go/types"
+       "regexp"
        "strings"
        "unicode"
        "unicode/utf8"
@@ -42,10 +44,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
                                // Ignore non-functions or functions with receivers.
                                continue
                        }
-
                        switch {
                        case strings.HasPrefix(fn.Name.Name, "Example"):
-                               checkExample(pass, fn)
+                               checkExampleName(pass, fn)
+                               checkExampleOutput(pass, fn, f.Comments)
                        case strings.HasPrefix(fn.Name.Name, "Test"):
                                checkTest(pass, fn, "Test")
                        case strings.HasPrefix(fn.Name.Name, "Benchmark"):
@@ -108,7 +110,59 @@ func lookup(pkg *types.Package, name string) []types.Object {
        return ret
 }
 
-func checkExample(pass *analysis.Pass, fn *ast.FuncDecl) {
+// This pattern is taken from /go/src/go/doc/example.go
+var outputRe = regexp.MustCompile(`(?i)^[[:space:]]*(unordered )?output:`)
+
+type commentMetadata struct {
+       isOutput bool
+       pos      token.Pos
+}
+
+func checkExampleOutput(pass *analysis.Pass, fn *ast.FuncDecl, fileComments []*ast.CommentGroup) {
+       commentsInExample := []commentMetadata{}
+       numOutputs := 0
+
+       // Find the comment blocks that are in the example. These comments are
+       // guaranteed to be in order of appearance.
+       for _, cg := range fileComments {
+               if cg.Pos() < fn.Pos() {
+                       continue
+               } else if cg.End() > fn.End() {
+                       break
+               }
+
+               isOutput := outputRe.MatchString(cg.Text())
+               if isOutput {
+                       numOutputs++
+               }
+
+               commentsInExample = append(commentsInExample, commentMetadata{
+                       isOutput: isOutput,
+                       pos:      cg.Pos(),
+               })
+       }
+
+       // Change message based on whether there are multiple output comment blocks.
+       msg := "output comment block must be the last comment block"
+       if numOutputs > 1 {
+               msg = "there can only be one output comment block per example"
+       }
+
+       for i, cg := range commentsInExample {
+               // Check for output comments that are not the last comment in the example.
+               isLast := (i == len(commentsInExample)-1)
+               if cg.isOutput && !isLast {
+                       pass.Report(
+                               analysis.Diagnostic{
+                                       Pos:     cg.pos,
+                                       Message: msg,
+                               },
+                       )
+               }
+       }
+}
+
+func checkExampleName(pass *analysis.Pass, fn *ast.FuncDecl) {
        fnName := fn.Name.Name
        if params := fn.Type.Params; len(params.List) != 0 {
                pass.Reportf(fn.Pos(), "%s should be niladic", fnName)
index 92b37caff9f113c7f2122dd004f9e324ec065de7..5129048a07662eab3716b6ab4b7f242e79a3f626 100644 (file)
@@ -14,6 +14,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/typeparams"
 )
 
 const Doc = `report passing non-pointer or non-interface values to unmarshal
@@ -85,7 +86,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
 
                t := pass.TypesInfo.Types[call.Args[argidx]].Type
                switch t.Underlying().(type) {
-               case *types.Pointer, *types.Interface:
+               case *types.Pointer, *types.Interface, *typeparams.TypeParam:
                        return
                }
 
index 5424489f8b31a46e9779262aba0c1a545c877576..b539866ddd4a6e07687d44c7024d65721931e882 100644 (file)
@@ -51,6 +51,7 @@ import (
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/internal/analysisflags"
        "golang.org/x/tools/go/analysis/internal/facts"
+       "golang.org/x/tools/internal/typeparams"
 )
 
 // A Config describes a compilation unit to be analyzed.
@@ -233,6 +234,8 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
                Scopes:     make(map[ast.Node]*types.Scope),
                Selections: make(map[*ast.SelectorExpr]*types.Selection),
        }
+       typeparams.InitInstanceInfo(info)
+
        pkg, err := tc.Check(cfg.ImportPath, fset, files, info)
        if err != nil {
                if cfg.SucceedOnTypecheckFailure {
index 6b7052b892ca07ba23a1eddd35645d50992dc42c..a5c6d6d4fa06cbc49cb7be1aea89cea6d5f821cb 100644 (file)
@@ -11,6 +11,8 @@ import (
        "go/ast"
        "go/token"
        "sort"
+
+       "golang.org/x/tools/internal/typeparams"
 )
 
 // PathEnclosingInterval returns the node that encloses the source
@@ -294,8 +296,8 @@ func childrenOf(n ast.Node) []ast.Node {
 
        case *ast.FieldList:
                children = append(children,
-                       tok(n.Opening, len("(")),
-                       tok(n.Closing, len(")")))
+                       tok(n.Opening, len("(")), // or len("[")
+                       tok(n.Closing, len(")"))) // or len("]")
 
        case *ast.File:
                // TODO test: Doc
@@ -322,6 +324,9 @@ func childrenOf(n ast.Node) []ast.Node {
                        children = append(children, n.Recv)
                }
                children = append(children, n.Name)
+               if tparams := typeparams.ForFuncType(n.Type); tparams != nil {
+                       children = append(children, tparams)
+               }
                if n.Type.Params != nil {
                        children = append(children, n.Type.Params)
                }
@@ -371,8 +376,13 @@ func childrenOf(n ast.Node) []ast.Node {
 
        case *ast.IndexExpr:
                children = append(children,
-                       tok(n.Lbrack, len("{")),
-                       tok(n.Rbrack, len("}")))
+                       tok(n.Lbrack, len("[")),
+                       tok(n.Rbrack, len("]")))
+
+       case *typeparams.IndexListExpr:
+               children = append(children,
+                       tok(n.Lbrack, len("[")),
+                       tok(n.Rbrack, len("]")))
 
        case *ast.InterfaceType:
                children = append(children,
@@ -581,6 +591,8 @@ func NodeDescription(n ast.Node) string {
                return "decrement statement"
        case *ast.IndexExpr:
                return "index expression"
+       case *typeparams.IndexListExpr:
+               return "index list expression"
        case *ast.InterfaceType:
                return "interface type"
        case *ast.KeyValueExpr:
index 5fe75b14c7573bf2d7140c00d2a3cbb0f3b19468..6d9ca23e2b02c4fd99e0136df1c998d4597e7eaa 100644 (file)
@@ -253,6 +253,10 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.
                a.apply(n, "X", nil, n.X)
                a.apply(n, "Index", nil, n.Index)
 
+       case *typeparams.IndexListExpr:
+               a.apply(n, "X", nil, n.X)
+               a.applyList(n, "Indices")
+
        case *ast.SliceExpr:
                a.apply(n, "X", nil, n.X)
                a.apply(n, "Low", nil, n.Low)
@@ -439,13 +443,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.
                }
 
        default:
-               if ix := typeparams.GetIndexExprData(n); ix != nil {
-                       a.apply(n, "X", nil, ix.X)
-                       // *ast.IndexExpr was handled above, so n must be an *ast.MultiIndexExpr.
-                       a.applyList(n, "Indices")
-               } else {
-                       panic(fmt.Sprintf("Apply: unexpected node type %T", n))
-               }
+               panic(fmt.Sprintf("Apply: unexpected node type %T", n))
        }
 
        if a.post != nil && !a.post(&a.cursor) {
index b6b00cf2e1e377ee30c870d0532e73c9d3716a89..11f4fc369a0835ba63b237f6cba4f590fdf353bc 100644 (file)
@@ -9,7 +9,11 @@ package inspector
 // The initial map-based implementation was too slow;
 // see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196
 
-import "go/ast"
+import (
+       "go/ast"
+
+       "golang.org/x/tools/internal/typeparams"
+)
 
 const (
        nArrayType = iota
@@ -47,6 +51,7 @@ const (
        nImportSpec
        nIncDecStmt
        nIndexExpr
+       nIndexListExpr
        nInterfaceType
        nKeyValueExpr
        nLabeledStmt
@@ -164,6 +169,8 @@ func typeOf(n ast.Node) uint64 {
                return 1 << nIncDecStmt
        case *ast.IndexExpr:
                return 1 << nIndexExpr
+       case *typeparams.IndexListExpr:
+               return 1 << nIndexListExpr
        case *ast.InterfaceType:
                return 1 << nInterfaceType
        case *ast.KeyValueExpr:
index 81e8fdcf0c1e5879ce93a73bd5a4ee9c6297b83e..7e96fc234e5af5514a5951b2b83093138a19d613 100644 (file)
@@ -23,10 +23,12 @@ package objectpath
 
 import (
        "fmt"
+       "go/types"
+       "sort"
        "strconv"
        "strings"
 
-       "go/types"
+       "golang.org/x/tools/internal/typeparams"
 )
 
 // A Path is an opaque name that identifies a types.Object
@@ -57,12 +59,16 @@ type Path string
 // - The only PO operator is Package.Scope.Lookup, which requires an identifier.
 // - The only OT operator is Object.Type,
 //   which we encode as '.' because dot cannot appear in an identifier.
-// - The TT operators are encoded as [EKPRU].
+// - The TT operators are encoded as [EKPRUTC];
+//   one of these (TypeParam) requires an integer operand,
+//   which is encoded as a string of decimal digits.
 // - The TO operators are encoded as [AFMO];
 //   three of these (At,Field,Method) require an integer operand,
 //   which is encoded as a string of decimal digits.
 //   These indices are stable across different representations
 //   of the same package, even source and export data.
+//   The indices used are implementation specific and may not correspond to
+//   the argument to the go/types function.
 //
 // In the example below,
 //
@@ -89,17 +95,19 @@ const (
        opType = '.' // .Type()           (Object)
 
        // type->type operators
-       opElem       = 'E' // .Elem()           (Pointer, Slice, Array, Chan, Map)
-       opKey        = 'K' // .Key()            (Map)
-       opParams     = 'P' // .Params()         (Signature)
-       opResults    = 'R' // .Results()        (Signature)
-       opUnderlying = 'U' // .Underlying()     (Named)
+       opElem       = 'E' // .Elem()                   (Pointer, Slice, Array, Chan, Map)
+       opKey        = 'K' // .Key()                    (Map)
+       opParams     = 'P' // .Params()               (Signature)
+       opResults    = 'R' // .Results()              (Signature)
+       opUnderlying = 'U' // .Underlying()         (Named)
+       opTypeParam  = 'T' // .TypeParams.At(i) (Named, Signature)
+       opConstraint = 'C' // .Constraint()     (TypeParam)
 
        // type->object operators
-       opAt     = 'A' // .At(i)                (Tuple)
-       opField  = 'F' // .Field(i)             (Struct)
-       opMethod = 'M' // .Method(i)            (Named or Interface; not Struct: "promoted" names are ignored)
-       opObj    = 'O' // .Obj()                (Named)
+       opAt     = 'A' // .At(i)                 (Tuple)
+       opField  = 'F' // .Field(i)      (Struct)
+       opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
+       opObj    = 'O' // .Obj()                 (Named, TypeParam)
 )
 
 // The For function returns the path to an object relative to its package,
@@ -190,10 +198,15 @@ func For(obj types.Object) (Path, error) {
        // 3. Not a package-level object.
        //    Reject obviously non-viable cases.
        switch obj := obj.(type) {
+       case *types.TypeName:
+               if _, ok := obj.Type().(*typeparams.TypeParam); !ok {
+                       // With the exception of type parameters, only package-level type names
+                       // have a path.
+                       return "", fmt.Errorf("no path for %v", obj)
+               }
        case *types.Const, // Only package-level constants have a path.
-               *types.TypeName, // Only package-level types have a path.
-               *types.Label,    // Labels are function-local.
-               *types.PkgName:  // PkgNames are file-local.
+               *types.Label,   // Labels are function-local.
+               *types.PkgName: // PkgNames are file-local.
                return "", fmt.Errorf("no path for %v", obj)
 
        case *types.Var:
@@ -245,6 +258,12 @@ func For(obj types.Object) (Path, error) {
                                return Path(r), nil
                        }
                } else {
+                       if named, _ := T.(*types.Named); named != nil {
+                               if r := findTypeParam(obj, typeparams.ForNamed(named), path); r != nil {
+                                       // generic named type
+                                       return Path(r), nil
+                               }
+                       }
                        // defined (named) type
                        if r := find(obj, T.Underlying(), append(path, opUnderlying)); r != nil {
                                return Path(r), nil
@@ -270,8 +289,12 @@ func For(obj types.Object) (Path, error) {
                // Inspect declared methods of defined types.
                if T, ok := o.Type().(*types.Named); ok {
                        path = append(path, opType)
-                       for i := 0; i < T.NumMethods(); i++ {
-                               m := T.Method(i)
+                       // Note that method index here is always with respect
+                       // to canonical ordering of methods, regardless of how
+                       // they appear in the underlying type.
+                       canonical := canonicalize(T)
+                       for i := 0; i < len(canonical); i++ {
+                               m := canonical[i]
                                path2 := appendOpArg(path, opMethod, i)
                                if m == obj {
                                        return Path(path2), nil // found declared method
@@ -313,6 +336,9 @@ func find(obj types.Object, T types.Type, path []byte) []byte {
                }
                return find(obj, T.Elem(), append(path, opElem))
        case *types.Signature:
+               if r := findTypeParam(obj, typeparams.ForSignature(T), path); r != nil {
+                       return r
+               }
                if r := find(obj, T.Params(), append(path, opParams)); r != nil {
                        return r
                }
@@ -353,10 +379,30 @@ func find(obj types.Object, T types.Type, path []byte) []byte {
                        }
                }
                return nil
+       case *typeparams.TypeParam:
+               name := T.Obj()
+               if name == obj {
+                       return append(path, opObj)
+               }
+               if r := find(obj, T.Constraint(), append(path, opConstraint)); r != nil {
+                       return r
+               }
+               return nil
        }
        panic(T)
 }
 
+func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte) []byte {
+       for i := 0; i < list.Len(); i++ {
+               tparam := list.At(i)
+               path2 := appendOpArg(path, opTypeParam, i)
+               if r := find(obj, tparam, path2); r != nil {
+                       return r
+               }
+       }
+       return nil
+}
+
 // Object returns the object denoted by path p within the package pkg.
 func Object(pkg *types.Package, p Path) (types.Object, error) {
        if p == "" {
@@ -381,10 +427,13 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
        type hasElem interface {
                Elem() types.Type
        }
-       // abstraction of *types.{Interface,Named}
-       type hasMethods interface {
-               Method(int) *types.Func
-               NumMethods() int
+       // abstraction of *types.{Named,Signature}
+       type hasTypeParams interface {
+               TypeParams() *typeparams.TypeParamList
+       }
+       // abstraction of *types.{Named,TypeParam}
+       type hasObj interface {
+               Obj() *types.TypeName
        }
 
        // The loop state is the pair (t, obj),
@@ -401,7 +450,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
                // Codes [AFM] have an integer operand.
                var index int
                switch code {
-               case opAt, opField, opMethod:
+               case opAt, opField, opMethod, opTypeParam:
                        rest := strings.TrimLeft(suffix, "0123456789")
                        numerals := suffix[:len(suffix)-len(rest)]
                        suffix = rest
@@ -466,14 +515,32 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
                case opUnderlying:
                        named, ok := t.(*types.Named)
                        if !ok {
-                               return nil, fmt.Errorf("cannot apply %q to %s (got %s, want named)", code, t, t)
+                               return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named)", code, t, t)
                        }
                        t = named.Underlying()
 
+               case opTypeParam:
+                       hasTypeParams, ok := t.(hasTypeParams) // Named, Signature
+                       if !ok {
+                               return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or signature)", code, t, t)
+                       }
+                       tparams := hasTypeParams.TypeParams()
+                       if n := tparams.Len(); index >= n {
+                               return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
+                       }
+                       t = tparams.At(index)
+
+               case opConstraint:
+                       tparam, ok := t.(*typeparams.TypeParam)
+                       if !ok {
+                               return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t)
+                       }
+                       t = tparam.Constraint()
+
                case opAt:
                        tuple, ok := t.(*types.Tuple)
                        if !ok {
-                               return nil, fmt.Errorf("cannot apply %q to %s (got %s, want tuple)", code, t, t)
+                               return nil, fmt.Errorf("cannot apply %q to %s (got %T, want tuple)", code, t, t)
                        }
                        if n := tuple.Len(); index >= n {
                                return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
@@ -495,20 +562,21 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
                case opMethod:
                        hasMethods, ok := t.(hasMethods) // Interface or Named
                        if !ok {
-                               return nil, fmt.Errorf("cannot apply %q to %s (got %s, want interface or named)", code, t, t)
+                               return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
                        }
-                       if n := hasMethods.NumMethods(); index >= n {
+                       canonical := canonicalize(hasMethods)
+                       if n := len(canonical); index >= n {
                                return nil, fmt.Errorf("method index %d out of range [0-%d)", index, n)
                        }
-                       obj = hasMethods.Method(index)
+                       obj = canonical[index]
                        t = nil
 
                case opObj:
-                       named, ok := t.(*types.Named)
+                       hasObj, ok := t.(hasObj)
                        if !ok {
-                               return nil, fmt.Errorf("cannot apply %q to %s (got %s, want named)", code, t, t)
+                               return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or type param)", code, t, t)
                        }
-                       obj = named.Obj()
+                       obj = hasObj.Obj()
                        t = nil
 
                default:
@@ -522,3 +590,28 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
 
        return obj, nil // success
 }
+
+// hasMethods is an abstraction of *types.{Interface,Named}. This is pulled up
+// because it is used by methodOrdering, which is in turn used by both encoding
+// and decoding.
+type hasMethods interface {
+       Method(int) *types.Func
+       NumMethods() int
+}
+
+// canonicalize returns a canonical order for the methods in a hasMethod.
+func canonicalize(hm hasMethods) []*types.Func {
+       count := hm.NumMethods()
+       if count <= 0 {
+               return nil
+       }
+       canon := make([]*types.Func, count)
+       for i := 0; i < count; i++ {
+               canon[i] = hm.Method(i)
+       }
+       less := func(i, j int) bool {
+               return canon[i].Id() < canon[j].Id()
+       }
+       sort.Slice(canon, less)
+       return canon
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
new file mode 100644 (file)
index 0000000..1821239
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2021 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:build !go1.18
+// +build !go1.18
+
+package typeparams
+
+// Enabled reports whether type parameters are enabled in the current build
+// environment.
+const Enabled = false
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
new file mode 100644 (file)
index 0000000..d671488
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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:build go1.18
+// +build go1.18
+
+package typeparams
+
+// Note: this constant is in a separate file as this is the only acceptable
+// diff between the <1.18 API of this package and the 1.18 API.
+
+// Enabled reports whether type parameters are enabled in the current build
+// environment.
+const Enabled = true
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/normalize.go
new file mode 100644 (file)
index 0000000..2937350
--- /dev/null
@@ -0,0 +1,212 @@
+// Copyright 2021 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 typeparams
+
+import (
+       "errors"
+       "fmt"
+       "go/types"
+       "os"
+       "strings"
+)
+
+//go:generate go run copytermlist.go
+
+const debug = false
+
+// NormalizeInterface returns the normal form of the interface iface, or nil if iface
+// has an empty type set (i.e. there are no types that satisfy iface). If the
+// resulting interface is non-nil, it will be identical to iface.
+//
+// An error is returned if the interface type is invalid, or too complicated to
+// reasonably normalize (for example, contains unions with more than a hundred
+// terms).
+//
+// An interface is in normal form if and only if:
+//   - it has 0 or 1 embedded types.
+//   - its embedded type is either a types.Union or has a concrete
+//     (non-interface) underlying type
+//   - if the embedded type is a union, each term of the union has a concrete
+//     underlying type, and no terms may be removed without changing the type set
+//     of the interface
+func NormalizeInterface(iface *types.Interface) (*types.Interface, error) {
+       var methods []*types.Func
+       for i := 0; i < iface.NumMethods(); i++ {
+               methods = append(methods, iface.Method(i))
+       }
+       var embeddeds []types.Type
+       tset, err := computeTermSet(iface, make(map[types.Type]*termSet), 0)
+       if err != nil {
+               return nil, err
+       }
+       switch {
+       case tset.terms.isEmpty():
+               // Special case: as documented
+               return nil, nil
+
+       case tset.terms.isAll():
+               // No embeddeds.
+
+       case len(tset.terms) == 1:
+               if !tset.terms[0].tilde {
+                       embeddeds = append(embeddeds, tset.terms[0].typ)
+                       break
+               }
+               fallthrough
+       default:
+               var terms []*Term
+               for _, term := range tset.terms {
+                       terms = append(terms, NewTerm(term.tilde, term.typ))
+               }
+               embeddeds = append(embeddeds, NewUnion(terms))
+       }
+
+       return types.NewInterfaceType(methods, embeddeds), nil
+}
+
+var ErrEmptyTypeSet = errors.New("empty type set")
+
+// StructuralTerms returns the normalized structural type restrictions of a
+// type, if any. For types that are not type parameters, it returns term slice
+// containing a single non-tilde term holding the given type. For type
+// parameters, it returns the normalized term list of the type parameter's
+// constraint. See NormalizeInterface for more information on the normal form
+// of a constraint interface.
+//
+// StructuralTerms returns an error if the structural term list cannot be
+// computed. If the type set of typ is empty, it returns ErrEmptyTypeSet.
+func StructuralTerms(typ types.Type) ([]*Term, error) {
+       switch typ := typ.(type) {
+       case *TypeParam:
+               iface, _ := typ.Constraint().(*types.Interface)
+               if iface == nil {
+                       return nil, fmt.Errorf("constraint is %T, not *types.Interface", typ)
+               }
+               tset, err := computeTermSet(iface, make(map[types.Type]*termSet), 0)
+               if err != nil {
+                       return nil, err
+               }
+               if tset.terms.isEmpty() {
+                       return nil, ErrEmptyTypeSet
+               }
+               if tset.terms.isAll() {
+                       return nil, nil
+               }
+               var terms []*Term
+               for _, term := range tset.terms {
+                       terms = append(terms, NewTerm(term.tilde, term.typ))
+               }
+               return terms, nil
+       default:
+               return []*Term{NewTerm(false, typ)}, nil
+       }
+}
+
+// A termSet holds the normalized set of terms for a given type.
+//
+// The name termSet is intentionally distinct from 'type set': a type set is
+// all types that implement a type (and includes method restrictions), whereas
+// a term set just represents the structural restrictions on a type.
+type termSet struct {
+       complete bool
+       terms    termlist
+}
+
+func indentf(depth int, format string, args ...interface{}) {
+       fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...)
+}
+
+func computeTermSet(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) {
+       if t == nil {
+               panic("nil type")
+       }
+
+       if debug {
+               indentf(depth, "%s", t.String())
+               defer func() {
+                       if err != nil {
+                               indentf(depth, "=> %s", err)
+                       } else {
+                               indentf(depth, "=> %s", res.terms.String())
+                       }
+               }()
+       }
+
+       const maxTermCount = 100
+       if tset, ok := seen[t]; ok {
+               if !tset.complete {
+                       return nil, fmt.Errorf("cycle detected in the declaration of %s", t)
+               }
+               return tset, nil
+       }
+
+       // Mark the current type as seen to avoid infinite recursion.
+       tset := new(termSet)
+       defer func() {
+               tset.complete = true
+       }()
+       seen[t] = tset
+
+       switch u := t.Underlying().(type) {
+       case *types.Interface:
+               // The term set of an interface is the intersection of the term sets of its
+               // embedded types.
+               tset.terms = allTermlist
+               for i := 0; i < u.NumEmbeddeds(); i++ {
+                       embedded := u.EmbeddedType(i)
+                       if _, ok := embedded.Underlying().(*TypeParam); ok {
+                               return nil, fmt.Errorf("invalid embedded type %T", embedded)
+                       }
+                       tset2, err := computeTermSet(embedded, seen, depth+1)
+                       if err != nil {
+                               return nil, err
+                       }
+                       tset.terms = tset.terms.intersect(tset2.terms)
+               }
+       case *Union:
+               // The term set of a union is the union of term sets of its terms.
+               tset.terms = nil
+               for i := 0; i < u.Len(); i++ {
+                       t := u.Term(i)
+                       var terms termlist
+                       switch t.Type().Underlying().(type) {
+                       case *types.Interface:
+                               tset2, err := computeTermSet(t.Type(), seen, depth+1)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               terms = tset2.terms
+                       case *TypeParam, *Union:
+                               // A stand-alone type parameter or union is not permitted as union
+                               // term.
+                               return nil, fmt.Errorf("invalid union term %T", t)
+                       default:
+                               if t.Type() == types.Typ[types.Invalid] {
+                                       continue
+                               }
+                               terms = termlist{{t.Tilde(), t.Type()}}
+                       }
+                       tset.terms = tset.terms.union(terms)
+                       if len(tset.terms) > maxTermCount {
+                               return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
+                       }
+               }
+       case *TypeParam:
+               panic("unreachable")
+       default:
+               // For all other types, the term set is just a single non-tilde term
+               // holding the type itself.
+               if u != types.Typ[types.Invalid] {
+                       tset.terms = termlist{{false, t}}
+               }
+       }
+       return tset, nil
+}
+
+// under is a facade for the go/types internal function of the same name. It is
+// used by typeterm.go.
+func under(t types.Type) types.Type {
+       return t.Underlying()
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/notypeparams.go
deleted file mode 100644 (file)
index e975e47..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2021 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:build !typeparams || !go1.18
-// +build !typeparams !go1.18
-
-package typeparams
-
-import (
-       "go/ast"
-       "go/types"
-)
-
-// NOTE: doc comments must be kept in sync with typeparams.go.
-
-// Enabled reports whether type parameters are enabled in the current build
-// environment.
-const Enabled = false
-
-// GetIndexExprData extracts data from AST nodes that represent index
-// expressions.
-//
-// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
-// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a
-// variable number of index expressions.
-//
-// For nodes that don't represent index expressions, GetIndexExprData returns
-// nil.
-func GetIndexExprData(n ast.Node) *IndexExprData {
-       if e, _ := n.(*ast.IndexExpr); e != nil {
-               return &IndexExprData{
-                       X:       e.X,
-                       Lbrack:  e.Lbrack,
-                       Indices: []ast.Expr{e.Index},
-                       Rbrack:  e.Rbrack,
-               }
-       }
-       return nil
-}
-
-// ForTypeDecl extracts the (possibly nil) type parameter node list from n.
-func ForTypeDecl(*ast.TypeSpec) *ast.FieldList {
-       return nil
-}
-
-// ForFuncDecl extracts the (possibly nil) type parameter node list from n.
-func ForFuncDecl(*ast.FuncDecl) *ast.FieldList {
-       return nil
-}
-
-// ForSignature extracts the (possibly empty) type parameter object list from
-// sig.
-func ForSignature(*types.Signature) []*types.TypeName {
-       return nil
-}
-
-// IsComparable reports if iface is the comparable interface.
-func IsComparable(*types.Interface) bool {
-       return false
-}
-
-// IsConstraint reports whether iface may only be used as a type parameter
-// constraint (i.e. has a type set or is the comparable interface).
-func IsConstraint(*types.Interface) bool {
-       return false
-}
-
-// ForNamed extracts the (possibly empty) type parameter object list from
-// named.
-func ForNamed(*types.Named) []*types.TypeName {
-       return nil
-}
-
-// NamedTArgs extracts the (possibly empty) type argument list from named.
-func NamedTArgs(*types.Named) []types.Type {
-       return nil
-}
-
-// InitInferred initializes info to record inferred type information.
-func InitInferred(*types.Info) {
-}
-
-// GetInferred extracts inferred type information from info for e.
-//
-// The expression e may have an inferred type if it is an *ast.IndexExpr
-// representing partial instantiation of a generic function type for which type
-// arguments have been inferred using constraint type inference, or if it is an
-// *ast.CallExpr for which type type arguments have be inferred using both
-// constraint type inference and function argument inference.
-func GetInferred(*types.Info, ast.Expr) ([]types.Type, *types.Signature) {
-       return nil, nil
-}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/termlist.go
new file mode 100644 (file)
index 0000000..10857d5
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright 2021 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 copytermlist.go DO NOT EDIT.
+
+package typeparams
+
+import (
+       "bytes"
+       "go/types"
+)
+
+// A termlist represents the type set represented by the union
+// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn.
+// A termlist is in normal form if all terms are disjoint.
+// termlist operations don't require the operands to be in
+// normal form.
+type termlist []*term
+
+// allTermlist represents the set of all types.
+// It is in normal form.
+var allTermlist = termlist{new(term)}
+
+// String prints the termlist exactly (without normalization).
+func (xl termlist) String() string {
+       if len(xl) == 0 {
+               return "∅"
+       }
+       var buf bytes.Buffer
+       for i, x := range xl {
+               if i > 0 {
+                       buf.WriteString(" ∪ ")
+               }
+               buf.WriteString(x.String())
+       }
+       return buf.String()
+}
+
+// isEmpty reports whether the termlist xl represents the empty set of types.
+func (xl termlist) isEmpty() bool {
+       // If there's a non-nil term, the entire list is not empty.
+       // If the termlist is in normal form, this requires at most
+       // one iteration.
+       for _, x := range xl {
+               if x != nil {
+                       return false
+               }
+       }
+       return true
+}
+
+// isAll reports whether the termlist xl represents the set of all types.
+func (xl termlist) isAll() bool {
+       // If there's a 𝓤 term, the entire list is 𝓤.
+       // If the termlist is in normal form, this requires at most
+       // one iteration.
+       for _, x := range xl {
+               if x != nil && x.typ == nil {
+                       return true
+               }
+       }
+       return false
+}
+
+// norm returns the normal form of xl.
+func (xl termlist) norm() termlist {
+       // Quadratic algorithm, but good enough for now.
+       // TODO(gri) fix asymptotic performance
+       used := make([]bool, len(xl))
+       var rl termlist
+       for i, xi := range xl {
+               if xi == nil || used[i] {
+                       continue
+               }
+               for j := i + 1; j < len(xl); j++ {
+                       xj := xl[j]
+                       if xj == nil || used[j] {
+                               continue
+                       }
+                       if u1, u2 := xi.union(xj); u2 == nil {
+                               // If we encounter a 𝓤 term, the entire list is 𝓤.
+                               // Exit early.
+                               // (Note that this is not just an optimization;
+                               // if we continue, we may end up with a 𝓤 term
+                               // and other terms and the result would not be
+                               // in normal form.)
+                               if u1.typ == nil {
+                                       return allTermlist
+                               }
+                               xi = u1
+                               used[j] = true // xj is now unioned into xi - ignore it in future iterations
+                       }
+               }
+               rl = append(rl, xi)
+       }
+       return rl
+}
+
+// If the type set represented by xl is specified by a single (non-𝓤) term,
+// structuralType returns that type. Otherwise it returns nil.
+func (xl termlist) structuralType() types.Type {
+       if nl := xl.norm(); len(nl) == 1 {
+               return nl[0].typ // if nl.isAll() then typ is nil, which is ok
+       }
+       return nil
+}
+
+// union returns the union xl ∪ yl.
+func (xl termlist) union(yl termlist) termlist {
+       return append(xl, yl...).norm()
+}
+
+// intersect returns the intersection xl ∩ yl.
+func (xl termlist) intersect(yl termlist) termlist {
+       if xl.isEmpty() || yl.isEmpty() {
+               return nil
+       }
+
+       // Quadratic algorithm, but good enough for now.
+       // TODO(gri) fix asymptotic performance
+       var rl termlist
+       for _, x := range xl {
+               for _, y := range yl {
+                       if r := x.intersect(y); r != nil {
+                               rl = append(rl, r)
+                       }
+               }
+       }
+       return rl.norm()
+}
+
+// equal reports whether xl and yl represent the same type set.
+func (xl termlist) equal(yl termlist) bool {
+       // TODO(gri) this should be more efficient
+       return xl.subsetOf(yl) && yl.subsetOf(xl)
+}
+
+// includes reports whether t ∈ xl.
+func (xl termlist) includes(t types.Type) bool {
+       for _, x := range xl {
+               if x.includes(t) {
+                       return true
+               }
+       }
+       return false
+}
+
+// supersetOf reports whether y ⊆ xl.
+func (xl termlist) supersetOf(y *term) bool {
+       for _, x := range xl {
+               if y.subsetOf(x) {
+                       return true
+               }
+       }
+       return false
+}
+
+// subsetOf reports whether xl ⊆ yl.
+func (xl termlist) subsetOf(yl termlist) bool {
+       if yl.isEmpty() {
+               return xl.isEmpty()
+       }
+
+       // each term x of xl must be a subset of yl
+       for _, x := range xl {
+               if !yl.supersetOf(x) {
+                       return false // x is not a subset yl
+               }
+       }
+       return true
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams.go
deleted file mode 100644 (file)
index be6b052..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2021 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:build typeparams && go1.18
-// +build typeparams,go1.18
-
-package typeparams
-
-import (
-       "go/ast"
-       "go/types"
-)
-
-// NOTE: doc comments must be kept in sync with notypeparams.go.
-
-// Enabled reports whether type parameters are enabled in the current build
-// environment.
-const Enabled = true
-
-// GetIndexExprData extracts data from AST nodes that represent index
-// expressions.
-//
-// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
-// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a
-// variable number of index expressions.
-//
-// For nodes that don't represent index expressions, GetIndexExprData returns
-// nil.
-func GetIndexExprData(n ast.Node) *IndexExprData {
-       switch e := n.(type) {
-       case *ast.IndexExpr:
-               return &IndexExprData{
-                       X:       e.X,
-                       Lbrack:  e.Lbrack,
-                       Indices: []ast.Expr{e.Index},
-                       Rbrack:  e.Rbrack,
-               }
-       case *ast.MultiIndexExpr:
-               return (*IndexExprData)(e)
-       }
-       return nil
-}
-
-// ForTypeDecl extracts the (possibly nil) type parameter node list from n.
-func ForTypeDecl(n *ast.TypeSpec) *ast.FieldList {
-       return n.TParams
-}
-
-// ForFuncDecl extracts the (possibly nil) type parameter node list from n.
-func ForFuncDecl(n *ast.FuncDecl) *ast.FieldList {
-       if n.Type != nil {
-               return n.Type.TParams
-       }
-       return nil
-}
-
-// ForSignature extracts the (possibly empty) type parameter object list from
-// sig.
-func ForSignature(sig *types.Signature) []*types.TypeName {
-       return tparamsSlice(sig.TParams())
-}
-
-// IsComparable reports if iface is the comparable interface.
-func IsComparable(iface *types.Interface) bool {
-       return iface.IsComparable()
-}
-
-// IsConstraint reports whether iface may only be used as a type parameter
-// constraint (i.e. has a type set or is the comparable interface).
-func IsConstraint(iface *types.Interface) bool {
-       return iface.IsConstraint()
-}
-
-// ForNamed extracts the (possibly empty) type parameter object list from
-// named.
-func ForNamed(named *types.Named) []*types.TypeName {
-       return tparamsSlice(named.TParams())
-}
-
-func tparamsSlice(tparams *types.TypeParams) []*types.TypeName {
-       if tparams.Len() == 0 {
-               return nil
-       }
-       result := make([]*types.TypeName, tparams.Len())
-       for i := 0; i < tparams.Len(); i++ {
-               result[i] = tparams.At(i)
-       }
-       return result
-}
-
-// NamedTArgs extracts the (possibly empty) type argument list from named.
-func NamedTArgs(named *types.Named) []types.Type {
-       return named.TArgs()
-}
-
-// InitInferred initializes info to record inferred type information.
-func InitInferred(info *types.Info) {
-       info.Inferred = make(map[ast.Expr]types.Inferred)
-}
-
-// GetInferred extracts inferred type information from info for e.
-//
-// The expression e may have an inferred type if it is an *ast.IndexExpr
-// representing partial instantiation of a generic function type for which type
-// arguments have been inferred using constraint type inference, or if it is an
-// *ast.CallExpr for which type type arguments have be inferred using both
-// constraint type inference and function argument inference.
-func GetInferred(info *types.Info, e ast.Expr) ([]types.Type, *types.Signature) {
-       if info.Inferred == nil {
-               return nil, nil
-       }
-       inf := info.Inferred[e]
-       return inf.TArgs, inf.Sig
-}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
new file mode 100644 (file)
index 0000000..6ad3a43
--- /dev/null
@@ -0,0 +1,223 @@
+// Copyright 2021 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:build !go1.18
+// +build !go1.18
+
+package typeparams
+
+import (
+       "go/ast"
+       "go/token"
+       "go/types"
+)
+
+func unsupported() {
+       panic("type parameters are unsupported at this go version")
+}
+
+// GetIndexExprData extracts data from *ast.IndexExpr nodes.
+// For other nodes, GetIndexExprData returns nil.
+func GetIndexExprData(n ast.Node) *IndexExprData {
+       if e, _ := n.(*ast.IndexExpr); e != nil {
+               return &IndexExprData{
+                       X:       e.X,
+                       Lbrack:  e.Lbrack,
+                       Indices: []ast.Expr{e.Index},
+                       Rbrack:  e.Rbrack,
+               }
+       }
+       return nil
+}
+
+// PackIndexExpr returns an *ast.IndexExpr with the given index.
+// Calling PackIndexExpr with len(indices) != 1 will panic.
+func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
+       switch len(indices) {
+       case 0:
+               panic("empty indices")
+       case 1:
+               return &ast.IndexExpr{
+                       X:      x,
+                       Lbrack: lbrack,
+                       Index:  indices[0],
+                       Rbrack: rbrack,
+               }
+       default:
+               panic("cannot pack multiple indices at this go version")
+       }
+}
+
+// IndexListExpr is a placeholder type, as type parameters are not supported at
+// this Go version. Its methods panic on use.
+type IndexListExpr struct {
+       ast.Expr
+       X       ast.Expr   // expression
+       Lbrack  token.Pos  // position of "["
+       Indices []ast.Expr // index expressions
+       Rbrack  token.Pos  // position of "]"
+}
+
+// ForTypeSpec returns an empty field list, as type parameters on not supported
+// at this Go version.
+func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
+       return nil
+}
+
+// ForFuncType returns an empty field list, as type parameters are not
+// supported at this Go version.
+func ForFuncType(*ast.FuncType) *ast.FieldList {
+       return nil
+}
+
+// TypeParam is a placeholder type, as type parameters are not supported at
+// this Go version. Its methods panic on use.
+type TypeParam struct{ types.Type }
+
+func (*TypeParam) Constraint() types.Type { unsupported(); return nil }
+func (*TypeParam) Obj() *types.TypeName   { unsupported(); return nil }
+
+// TypeParamList is a placeholder for an empty type parameter list.
+type TypeParamList struct{}
+
+func (*TypeParamList) Len() int          { return 0 }
+func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil }
+
+// TypeList is a placeholder for an empty type list.
+type TypeList struct{}
+
+func (*TypeList) Len() int          { return 0 }
+func (*TypeList) At(int) types.Type { unsupported(); return nil }
+
+// NewTypeParam is unsupported at this Go version, and panics.
+func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
+       unsupported()
+       return nil
+}
+
+// SetTypeParamConstraint is unsupported at this Go version, and panics.
+func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
+       unsupported()
+}
+
+// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or
+// typeParams is non-empty.
+func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
+       if len(recvTypeParams) != 0 || len(typeParams) != 0 {
+               panic("signatures cannot have type parameters at this Go version")
+       }
+       return types.NewSignature(recv, params, results, variadic)
+}
+
+// ForSignature returns an empty slice.
+func ForSignature(*types.Signature) *TypeParamList {
+       return nil
+}
+
+// RecvTypeParams returns a nil slice.
+func RecvTypeParams(sig *types.Signature) *TypeParamList {
+       return nil
+}
+
+// IsComparable returns false, as no interfaces are type-restricted at this Go
+// version.
+func IsComparable(*types.Interface) bool {
+       return false
+}
+
+// IsMethodSet returns true, as no interfaces are type-restricted at this Go
+// version.
+func IsMethodSet(*types.Interface) bool {
+       return true
+}
+
+// IsImplicit returns false, as no interfaces are implicit at this Go version.
+func IsImplicit(*types.Interface) bool {
+       return false
+}
+
+// MarkImplicit does nothing, because this Go version does not have implicit
+// interfaces.
+func MarkImplicit(*types.Interface) {}
+
+// ForNamed returns an empty type parameter list, as type parameters are not
+// supported at this Go version.
+func ForNamed(*types.Named) *TypeParamList {
+       return nil
+}
+
+// SetForNamed panics if tparams is non-empty.
+func SetForNamed(_ *types.Named, tparams []*TypeParam) {
+       if len(tparams) > 0 {
+               unsupported()
+       }
+}
+
+// NamedTypeArgs returns nil.
+func NamedTypeArgs(*types.Named) *TypeList {
+       return nil
+}
+
+// NamedTypeOrigin is the identity method at this Go version.
+func NamedTypeOrigin(named *types.Named) types.Type {
+       return named
+}
+
+// Term holds information about a structural type restriction.
+type Term struct {
+       tilde bool
+       typ   types.Type
+}
+
+func (m *Term) Tilde() bool      { return m.tilde }
+func (m *Term) Type() types.Type { return m.typ }
+func (m *Term) String() string {
+       pre := ""
+       if m.tilde {
+               pre = "~"
+       }
+       return pre + m.typ.String()
+}
+
+// NewTerm is unsupported at this Go version, and panics.
+func NewTerm(tilde bool, typ types.Type) *Term {
+       return &Term{tilde, typ}
+}
+
+// Union is a placeholder type, as type parameters are not supported at this Go
+// version. Its methods panic on use.
+type Union struct{ types.Type }
+
+func (*Union) Len() int         { return 0 }
+func (*Union) Term(i int) *Term { unsupported(); return nil }
+
+// NewUnion is unsupported at this Go version, and panics.
+func NewUnion(terms []*Term) *Union {
+       unsupported()
+       return nil
+}
+
+// InitInstanceInfo is a noop at this Go version.
+func InitInstanceInfo(*types.Info) {}
+
+// Instance is a placeholder type, as type parameters are not supported at this
+// Go version.
+type Instance struct {
+       TypeArgs *TypeList
+       Type     types.Type
+}
+
+// GetInstances returns a nil map, as type parameters are not supported at this
+// Go version.
+func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil }
+
+// Context is a placeholder type, as type parameters are not supported at
+// this Go version.
+type Context struct{}
+
+// Instantiate is unsupported on this Go version, and panics.
+func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
+       unsupported()
+       return nil, nil
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
new file mode 100644 (file)
index 0000000..e45896f
--- /dev/null
@@ -0,0 +1,196 @@
+// Copyright 2021 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:build go1.18
+// +build go1.18
+
+package typeparams
+
+import (
+       "go/ast"
+       "go/token"
+       "go/types"
+)
+
+// GetIndexExprData extracts data from AST nodes that represent index
+// expressions.
+//
+// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
+// index expression. For an ast.IndexListExpr (go1.18+), it may have a
+// variable number of index expressions.
+//
+// For nodes that don't represent index expressions, GetIndexExprData returns
+// nil.
+// TODO(rfindley): remove this function in favor of using the alias below.
+func GetIndexExprData(n ast.Node) *IndexExprData {
+       switch e := n.(type) {
+       case *ast.IndexExpr:
+               return &IndexExprData{
+                       X:       e.X,
+                       Lbrack:  e.Lbrack,
+                       Indices: []ast.Expr{e.Index},
+                       Rbrack:  e.Rbrack,
+               }
+       case *ast.IndexListExpr:
+               return (*IndexExprData)(e)
+       }
+       return nil
+}
+
+// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on
+// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0
+// will panic.
+func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
+       switch len(indices) {
+       case 0:
+               panic("empty indices")
+       case 1:
+               return &ast.IndexExpr{
+                       X:      x,
+                       Lbrack: lbrack,
+                       Index:  indices[0],
+                       Rbrack: rbrack,
+               }
+       default:
+               return &ast.IndexListExpr{
+                       X:       x,
+                       Lbrack:  lbrack,
+                       Indices: indices,
+                       Rbrack:  rbrack,
+               }
+       }
+}
+
+// IndexListExpr is an alias for ast.IndexListExpr.
+type IndexListExpr = ast.IndexListExpr
+
+// ForTypeSpec returns n.TypeParams.
+func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
+       if n == nil {
+               return nil
+       }
+       return n.TypeParams
+}
+
+// ForFuncType returns n.TypeParams.
+func ForFuncType(n *ast.FuncType) *ast.FieldList {
+       if n == nil {
+               return nil
+       }
+       return n.TypeParams
+}
+
+// TypeParam is an alias for types.TypeParam
+type TypeParam = types.TypeParam
+
+// TypeParamList is an alias for types.TypeParamList
+type TypeParamList = types.TypeParamList
+
+// TypeList is an alias for types.TypeList
+type TypeList = types.TypeList
+
+// NewTypeParam calls types.NewTypeParam.
+func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
+       return types.NewTypeParam(name, constraint)
+}
+
+// SetTypeParamConstraint calls tparam.SetConstraint(constraint).
+func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
+       tparam.SetConstraint(constraint)
+}
+
+// NewSignatureType calls types.NewSignatureType.
+func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
+       return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic)
+}
+
+// ForSignature returns sig.TypeParams()
+func ForSignature(sig *types.Signature) *TypeParamList {
+       return sig.TypeParams()
+}
+
+// RecvTypeParams returns sig.RecvTypeParams().
+func RecvTypeParams(sig *types.Signature) *TypeParamList {
+       return sig.RecvTypeParams()
+}
+
+// IsComparable calls iface.IsComparable().
+func IsComparable(iface *types.Interface) bool {
+       return iface.IsComparable()
+}
+
+// IsMethodSet calls iface.IsMethodSet().
+func IsMethodSet(iface *types.Interface) bool {
+       return iface.IsMethodSet()
+}
+
+// IsImplicit calls iface.IsImplicit().
+func IsImplicit(iface *types.Interface) bool {
+       return iface.IsImplicit()
+}
+
+// MarkImplicit calls iface.MarkImplicit().
+func MarkImplicit(iface *types.Interface) {
+       iface.MarkImplicit()
+}
+
+// ForNamed extracts the (possibly empty) type parameter object list from
+// named.
+func ForNamed(named *types.Named) *TypeParamList {
+       return named.TypeParams()
+}
+
+// SetForNamed sets the type params tparams on n. Each tparam must be of
+// dynamic type *types.TypeParam.
+func SetForNamed(n *types.Named, tparams []*TypeParam) {
+       n.SetTypeParams(tparams)
+}
+
+// NamedTypeArgs returns named.TypeArgs().
+func NamedTypeArgs(named *types.Named) *TypeList {
+       return named.TypeArgs()
+}
+
+// NamedTypeOrigin returns named.Orig().
+func NamedTypeOrigin(named *types.Named) types.Type {
+       return named.Origin()
+}
+
+// Term is an alias for types.Term.
+type Term = types.Term
+
+// NewTerm calls types.NewTerm.
+func NewTerm(tilde bool, typ types.Type) *Term {
+       return types.NewTerm(tilde, typ)
+}
+
+// Union is an alias for types.Union
+type Union = types.Union
+
+// NewUnion calls types.NewUnion.
+func NewUnion(terms []*Term) *Union {
+       return types.NewUnion(terms)
+}
+
+// InitInstanceInfo initializes info to record information about type and
+// function instances.
+func InitInstanceInfo(info *types.Info) {
+       info.Instances = make(map[*ast.Ident]types.Instance)
+}
+
+// Instance is an alias for types.Instance.
+type Instance = types.Instance
+
+// GetInstances returns info.Instances.
+func GetInstances(info *types.Info) map[*ast.Ident]Instance {
+       return info.Instances
+}
+
+// Context is an alias for types.Context.
+type Context = types.Context
+
+// Instantiate calls types.Instantiate.
+func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
+       return types.Instantiate(ctxt, typ, targs, validate)
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeterm.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/typeterm.go
new file mode 100644 (file)
index 0000000..7ddee28
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2021 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 copytermlist.go DO NOT EDIT.
+
+package typeparams
+
+import "go/types"
+
+// A term describes elementary type sets:
+//
+//   ∅:  (*term)(nil)     == ∅                      // set of no types (empty set)
+//   𝓤:  &term{}          == 𝓤                      // set of all types (𝓤niverse)
+//   T:  &term{false, T}  == {T}                    // set of type T
+//  ~t:  &term{true, t}   == {t' | under(t') == t}  // set of types with underlying type t
+//
+type term struct {
+       tilde bool // valid if typ != nil
+       typ   types.Type
+}
+
+func (x *term) String() string {
+       switch {
+       case x == nil:
+               return "∅"
+       case x.typ == nil:
+               return "𝓤"
+       case x.tilde:
+               return "~" + x.typ.String()
+       default:
+               return x.typ.String()
+       }
+}
+
+// equal reports whether x and y represent the same type set.
+func (x *term) equal(y *term) bool {
+       // easy cases
+       switch {
+       case x == nil || y == nil:
+               return x == y
+       case x.typ == nil || y.typ == nil:
+               return x.typ == y.typ
+       }
+       // ∅ ⊂ x, y ⊂ 𝓤
+
+       return x.tilde == y.tilde && types.Identical(x.typ, y.typ)
+}
+
+// union returns the union x ∪ y: zero, one, or two non-nil terms.
+func (x *term) union(y *term) (_, _ *term) {
+       // easy cases
+       switch {
+       case x == nil && y == nil:
+               return nil, nil // ∅ ∪ ∅ == ∅
+       case x == nil:
+               return y, nil // ∅ ∪ y == y
+       case y == nil:
+               return x, nil // x ∪ ∅ == x
+       case x.typ == nil:
+               return x, nil // 𝓤 ∪ y == 𝓤
+       case y.typ == nil:
+               return y, nil // x ∪ 𝓤 == 𝓤
+       }
+       // ∅ ⊂ x, y ⊂ 𝓤
+
+       if x.disjoint(y) {
+               return x, y // x ∪ y == (x, y) if x ∩ y == ∅
+       }
+       // x.typ == y.typ
+
+       // ~t ∪ ~t == ~t
+       // ~t ∪  T == ~t
+       //  T ∪ ~t == ~t
+       //  T ∪  T ==  T
+       if x.tilde || !y.tilde {
+               return x, nil
+       }
+       return y, nil
+}
+
+// intersect returns the intersection x ∩ y.
+func (x *term) intersect(y *term) *term {
+       // easy cases
+       switch {
+       case x == nil || y == nil:
+               return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅
+       case x.typ == nil:
+               return y // 𝓤 ∩ y == y
+       case y.typ == nil:
+               return x // x ∩ 𝓤 == x
+       }
+       // ∅ ⊂ x, y ⊂ 𝓤
+
+       if x.disjoint(y) {
+               return nil // x ∩ y == ∅ if x ∩ y == ∅
+       }
+       // x.typ == y.typ
+
+       // ~t ∩ ~t == ~t
+       // ~t ∩  T ==  T
+       //  T ∩ ~t ==  T
+       //  T ∩  T ==  T
+       if !x.tilde || y.tilde {
+               return x
+       }
+       return y
+}
+
+// includes reports whether t ∈ x.
+func (x *term) includes(t types.Type) bool {
+       // easy cases
+       switch {
+       case x == nil:
+               return false // t ∈ ∅ == false
+       case x.typ == nil:
+               return true // t ∈ 𝓤 == true
+       }
+       // ∅ ⊂ x ⊂ 𝓤
+
+       u := t
+       if x.tilde {
+               u = under(u)
+       }
+       return types.Identical(x.typ, u)
+}
+
+// subsetOf reports whether x ⊆ y.
+func (x *term) subsetOf(y *term) bool {
+       // easy cases
+       switch {
+       case x == nil:
+               return true // ∅ ⊆ y == true
+       case y == nil:
+               return false // x ⊆ ∅ == false since x != ∅
+       case y.typ == nil:
+               return true // x ⊆ 𝓤 == true
+       case x.typ == nil:
+               return false // 𝓤 ⊆ y == false since y != 𝓤
+       }
+       // ∅ ⊂ x, y ⊂ 𝓤
+
+       if x.disjoint(y) {
+               return false // x ⊆ y == false if x ∩ y == ∅
+       }
+       // x.typ == y.typ
+
+       // ~t ⊆ ~t == true
+       // ~t ⊆ T == false
+       //  T ⊆ ~t == true
+       //  T ⊆  T == true
+       return !x.tilde || y.tilde
+}
+
+// disjoint reports whether x ∩ y == ∅.
+// x.typ and y.typ must not be nil.
+func (x *term) disjoint(y *term) bool {
+       if debug && (x.typ == nil || y.typ == nil) {
+               panic("invalid argument(s)")
+       }
+       ux := x.typ
+       if y.tilde {
+               ux = under(ux)
+       }
+       uy := y.typ
+       if x.tilde {
+               uy = under(uy)
+       }
+       return !types.Identical(ux, uy)
+}
similarity index 96%
rename from src/cmd/go/internal/txtar/archive.go
rename to src/cmd/vendor/golang.org/x/tools/txtar/archive.go
index 17966848771b3c16be035a1f583fc0f3e6e70445..214256617b58d479906b70fb2d0027e2541ab303 100644 (file)
@@ -34,7 +34,7 @@ package txtar
 import (
        "bytes"
        "fmt"
-       "os"
+       "io/ioutil"
        "strings"
 )
 
@@ -66,7 +66,7 @@ func Format(a *Archive) []byte {
 
 // ParseFile parses the named file as an archive.
 func ParseFile(file string) (*Archive, error) {
-       data, err := os.ReadFile(file)
+       data, err := ioutil.ReadFile(file)
        if err != nil {
                return nil, err
        }
@@ -121,7 +121,7 @@ func isMarker(data []byte) (name string, after []byte) {
        if i := bytes.IndexByte(data, '\n'); i >= 0 {
                data, after = data[:i], data[i+1:]
        }
-       if !bytes.HasSuffix(data, markerEnd) {
+       if !(bytes.HasSuffix(data, markerEnd) && len(data) >= len(marker)+len(markerEnd)) {
                return "", nil
        }
        return strings.TrimSpace(string(data[len(marker) : len(data)-len(markerEnd)])), after
index c98bdcd3440168f4c76f717dc907d3eaf73f4c89..ad08e583fb774eff633c165342805b0b9900a038 100644 (file)
@@ -1,4 +1,4 @@
-# github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
+# github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31
 ## explicit; go 1.14
 github.com/google/pprof/driver
 github.com/google/pprof/internal/binutils
@@ -15,20 +15,20 @@ github.com/google/pprof/profile
 github.com/google/pprof/third_party/d3
 github.com/google/pprof/third_party/d3flamegraph
 github.com/google/pprof/third_party/svgpan
-# github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639
-## explicit
+# github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d
+## explicit; go 1.12
 github.com/ianlancetaylor/demangle
-# golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
+# golang.org/x/arch v0.0.0-20210901143047-ebb09ed340f1
 ## explicit; go 1.17
 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-20210503195802-e9a32991a82e
+# golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
 ## explicit; go 1.17
 golang.org/x/crypto/ed25519
 golang.org/x/crypto/ed25519/internal/edwards25519
-# golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
+# golang.org/x/mod v0.5.1-0.20210913215816-37dd6891021a
 ## explicit; go 1.17
 golang.org/x/mod/internal/lazyregexp
 golang.org/x/mod/modfile
@@ -39,16 +39,19 @@ golang.org/x/mod/sumdb/dirhash
 golang.org/x/mod/sumdb/note
 golang.org/x/mod/sumdb/tlog
 golang.org/x/mod/zip
-# golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744
+# golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+## explicit
+golang.org/x/sync/semaphore
+# golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac
 ## explicit; go 1.17
 golang.org/x/sys/internal/unsafeheader
 golang.org/x/sys/plan9
 golang.org/x/sys/unix
 golang.org/x/sys/windows
-# golang.org/x/term v0.0.0-20210503060354-a79de5458b56
+# golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
 ## explicit; go 1.17
 golang.org/x/term
-# golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151
+# golang.org/x/tools v0.1.8-0.20211025211149-f916b54a1784
 ## explicit; go 1.17
 golang.org/x/tools/cover
 golang.org/x/tools/go/analysis
@@ -93,6 +96,7 @@ golang.org/x/tools/go/types/typeutil
 golang.org/x/tools/internal/analysisinternal
 golang.org/x/tools/internal/lsp/fuzzy
 golang.org/x/tools/internal/typeparams
+golang.org/x/tools/txtar
 # golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
 ## explicit; go 1.11
 golang.org/x/xerrors
index 50dd0735fa9e7ceed0345794463e92e7a3daea4a..714ee320aee603f72975e4fd3e9d703f5825d4e8 100644 (file)
@@ -241,8 +241,8 @@ func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
                        // Assume errmsg says "file:line: foo".
                        // Cut leading "file:line: " to avoid accidental matching of file name instead of message.
                        text := errmsg
-                       if i := strings.Index(text, " "); i >= 0 {
-                               text = text[i+1:]
+                       if _, suffix, ok := strings.Cut(text, " "); ok {
+                               text = suffix
                        }
                        if we.re.MatchString(text) {
                                matched = true
index 20da0b6824a6a922d2a3e95b2b407aa3a59a294c..faee9bd43a68ed83b4e63f12afed38016a3e4c8e 100644 (file)
@@ -1,3 +1,7 @@
+// Copyright 2016 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 gzip
 
 import (
index 552bdc2ce1746238bb066a2b1a15f1f4c48181b5..cf06ea80c787d7d09d9a3ca8460e58811f927af9 100644 (file)
@@ -137,7 +137,19 @@ func (w *Writer) Write(p []byte) (n int, err error) {
        n = len(p)
        code := w.savedCode
        if code == invalidCode {
-               // The first code sent is always a literal code.
+               // This is the first write; send a clear code.
+               // https://www.w3.org/Graphics/GIF/spec-gif89a.txt Appendix F
+               // "Variable-Length-Code LZW Compression" says that "Encoders should
+               // output a Clear code as the first code of each image data stream".
+               //
+               // LZW compression isn't only used by GIF, but it's cheap to follow
+               // that directive unconditionally.
+               clear := uint32(1) << w.litWidth
+               if err := w.write(w, clear); err != nil {
+                       return 0, err
+               }
+               // After the starting clear code, the next code sent (for non-empty
+               // input) is always a literal code.
                code, p = uint32(p[0]), p[1:]
        }
 loop:
@@ -202,6 +214,12 @@ func (w *Writer) Close() error {
                if err := w.incHi(); err != nil && err != errOutOfCodes {
                        return err
                }
+       } else {
+               // Write the starting clear code, as w.Write did not.
+               clear := uint32(1) << w.litWidth
+               if err := w.write(w, clear); err != nil {
+                       return err
+               }
        }
        // Write the eof code.
        eof := uint32(1)<<w.litWidth + 1
index 9f59c8bb18a6946d042b5f28477326e9e176da66..edf683a512d47a1ad31541f233897b2d5e1a865f 100644 (file)
@@ -168,6 +168,34 @@ func TestSmallLitWidth(t *testing.T) {
        }
 }
 
+func TestStartsWithClearCode(t *testing.T) {
+       // A literal width of 7 bits means that the code width starts at 8 bits,
+       // which makes it easier to visually inspect the output (provided that the
+       // output is short so codes don't get longer). Each byte is a code:
+       //  - ASCII bytes are literal codes,
+       //  - 0x80 is the clear code,
+       //  - 0x81 is the end code.
+       //  - 0x82 and above are copy codes (unused in this test case).
+       for _, empty := range []bool{false, true} {
+               var buf bytes.Buffer
+               w := NewWriter(&buf, LSB, 7)
+               if !empty {
+                       w.Write([]byte("Hi"))
+               }
+               w.Close()
+               got := buf.String()
+
+               want := "\x80\x81"
+               if !empty {
+                       want = "\x80Hi\x81"
+               }
+
+               if got != want {
+                       t.Errorf("empty=%t: got %q, want %q", empty, got, want)
+               }
+       }
+}
+
 func BenchmarkEncoder(b *testing.B) {
        buf, err := os.ReadFile("../testdata/e.txt")
        if err != nil {
diff --git a/src/constraints/constraints.go b/src/constraints/constraints.go
new file mode 100644 (file)
index 0000000..2c033df
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2021 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 constraints defines a set of useful constraints to be used
+// with type parameters.
+package constraints
+
+// Signed is a constraint that permits any signed integer type.
+// If future releases of Go add new predeclared signed integer types,
+// this constraint will be modified to include them.
+type Signed interface {
+       ~int | ~int8 | ~int16 | ~int32 | ~int64
+}
+
+// Unsigned is a constraint that permits any unsigned integer type.
+// If future releases of Go add new predeclared unsigned integer types,
+// this constraint will be modified to include them.
+type Unsigned interface {
+       ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+// Integer is a constraint that permits any integer type.
+// If future releases of Go add new predeclared integer types,
+// this constraint will be modified to include them.
+type Integer interface {
+       Signed | Unsigned
+}
+
+// Float is a constraint that permits any floating-point type.
+// If future releases of Go add new predeclared floating-point types,
+// this constraint will be modified to include them.
+type Float interface {
+       ~float32 | ~float64
+}
+
+// Complex is a constraint that permits any complex numeric type.
+// If future releases of Go add new predeclared complex numeric types,
+// this constraint will be modified to include them.
+type Complex interface {
+       ~complex64 | ~complex128
+}
+
+// Ordered is a constraint that permits any ordered type: any type
+// that supports the operators < <= >= >.
+// If future releases of Go add new ordered types,
+// this constraint will be modified to include them.
+type Ordered interface {
+       Integer | Float | ~string
+}
diff --git a/src/constraints/constraints_test.go b/src/constraints/constraints_test.go
new file mode 100644 (file)
index 0000000..538dc84
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2021 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 constraints
+
+import (
+       "bytes"
+       "fmt"
+       "internal/testenv"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "testing"
+)
+
+type (
+       testSigned[T Signed]     struct{ f T }
+       testUnsigned[T Unsigned] struct{ f T }
+       testInteger[T Integer]   struct{ f T }
+       testFloat[T Float]       struct{ f T }
+       testComplex[T Complex]   struct{ f T }
+       testOrdered[T Ordered]   struct{ f T }
+)
+
+// TestTypes passes if it compiles.
+type TestTypes struct {
+       _ testSigned[int]
+       _ testSigned[int64]
+       _ testUnsigned[uint]
+       _ testUnsigned[uintptr]
+       _ testInteger[int8]
+       _ testInteger[uint8]
+       _ testInteger[uintptr]
+       _ testFloat[float32]
+       _ testComplex[complex64]
+       _ testOrdered[int]
+       _ testOrdered[float64]
+       _ testOrdered[string]
+}
+
+var prolog = []byte(`
+package constrainttest
+
+import "constraints"
+
+type (
+       testSigned[T constraints.Signed]     struct{ f T }
+       testUnsigned[T constraints.Unsigned] struct{ f T }
+       testInteger[T constraints.Integer]   struct{ f T }
+       testFloat[T constraints.Float]       struct{ f T }
+       testComplex[T constraints.Complex]   struct{ f T }
+       testOrdered[T constraints.Ordered]   struct{ f T }
+)
+`)
+
+func TestFailure(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       gocmd := testenv.GoToolPath(t)
+       tmpdir := t.TempDir()
+
+       if err := os.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module constraintest"), 0666); err != nil {
+               t.Fatal(err)
+       }
+
+       // Test for types that should not satisfy a constraint.
+       // For each pair of constraint and type, write a Go file
+       //     var V constraint[type]
+       // For example,
+       //     var V testSigned[uint]
+       // This should not compile, as testSigned (above) uses
+       // constraints.Signed, and uint does not satisfy that constraint.
+       // Therefore, the build of that code should fail.
+       for i, test := range []struct {
+               constraint, typ string
+       }{
+               {"testSigned", "uint"},
+               {"testUnsigned", "int"},
+               {"testInteger", "float32"},
+               {"testFloat", "int8"},
+               {"testComplex", "float64"},
+               {"testOrdered", "bool"},
+       } {
+               i := i
+               test := test
+               t.Run(fmt.Sprintf("%s %d", test.constraint, i), func(t *testing.T) {
+                       t.Parallel()
+                       name := fmt.Sprintf("go%d.go", i)
+                       f, err := os.Create(filepath.Join(tmpdir, name))
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if _, err := f.Write(prolog); err != nil {
+                               t.Fatal(err)
+                       }
+                       if _, err := fmt.Fprintf(f, "var V %s[%s]\n", test.constraint, test.typ); err != nil {
+                               t.Fatal(err)
+                       }
+                       if err := f.Close(); err != nil {
+                               t.Fatal(err)
+                       }
+                       cmd := exec.Command(gocmd, "build", name)
+                       cmd.Dir = tmpdir
+                       if out, err := cmd.CombinedOutput(); err == nil {
+                               t.Error("build succeeded, but expected to fail")
+                       } else if len(out) > 0 {
+                               t.Logf("%s", out)
+                               const want = "does not satisfy"
+                               if !bytes.Contains(out, []byte(want)) {
+                                       t.Errorf("output does not include %q", want)
+                               }
+                       } else {
+                               t.Error("no error output, expected something")
+                       }
+               })
+       }
+}
index 210424ceed7b7cac8bb793f9614845aa3ecc2080..aa89b7f599d9f0b75222bf9e327083e2fce27aa1 100644 (file)
@@ -104,21 +104,20 @@ func (l *List) insertValue(v interface{}, at *Element) *Element {
        return l.insert(&Element{Value: v}, at)
 }
 
-// remove removes e from its list, decrements l.len, and returns e.
-func (l *List) remove(e *Element) *Element {
+// remove removes e from its list, decrements l.len
+func (l *List) remove(e *Element) {
        e.prev.next = e.next
        e.next.prev = e.prev
        e.next = nil // avoid memory leaks
        e.prev = nil // avoid memory leaks
        e.list = nil
        l.len--
-       return e
 }
 
-// move moves e to next to at and returns e.
-func (l *List) move(e, at *Element) *Element {
+// move moves e to next to at.
+func (l *List) move(e, at *Element) {
        if e == at {
-               return e
+               return
        }
        e.prev.next = e.next
        e.next.prev = e.prev
@@ -127,8 +126,6 @@ func (l *List) move(e, at *Element) *Element {
        e.next = at.next
        e.prev.next = e
        e.next.prev = e
-
-       return e
 }
 
 // Remove removes e from l if e is an element of list l.
index 99e006f39fdafddc07ba9ffd506dfbf920abe516..c74724b3985a67ca4f341f8b06d02e33ae37f08b 100644 (file)
@@ -283,7 +283,6 @@ func TestMove(t *testing.T) {
 
        l.MoveAfter(e2, e3)
        checkListPointers(t, l, []*Element{e1, e3, e2, e4})
-       e2, e3 = e3, e2
 }
 
 // Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
index 69d75fff1866baa06362994adbc1ddadc647e226..144f473a4448166892aa66c8d214e8db64848069 100644 (file)
@@ -152,3 +152,39 @@ func BenchmarkContextCancelDone(b *testing.B) {
                }
        })
 }
+
+func BenchmarkDeepValueNewGoRoutine(b *testing.B) {
+       for _, depth := range []int{10, 20, 30, 50, 100} {
+               ctx := Background()
+               for i := 0; i < depth; i++ {
+                       ctx = WithValue(ctx, i, i)
+               }
+
+               b.Run(fmt.Sprintf("depth=%d", depth), func(b *testing.B) {
+                       for i := 0; i < b.N; i++ {
+                               var wg sync.WaitGroup
+                               wg.Add(1)
+                               go func() {
+                                       defer wg.Done()
+                                       ctx.Value(-1)
+                               }()
+                               wg.Wait()
+                       }
+               })
+       }
+}
+
+func BenchmarkDeepValueSameGoRoutine(b *testing.B) {
+       for _, depth := range []int{10, 20, 30, 50, 100} {
+               ctx := Background()
+               for i := 0; i < depth; i++ {
+                       ctx = WithValue(ctx, i, i)
+               }
+
+               b.Run(fmt.Sprintf("depth=%d", depth), func(b *testing.B) {
+                       for i := 0; i < b.N; i++ {
+                               ctx.Value(-1)
+                       }
+               })
+       }
+}
index 733c5f56d9274d178923f7d452434bc8a379db7a..a9e14703fd335652debb793a2f747b76d1b82f9e 100644 (file)
@@ -352,7 +352,7 @@ func (c *cancelCtx) Value(key interface{}) interface{} {
        if key == &cancelCtxKey {
                return c
        }
-       return c.Context.Value(key)
+       return value(c.Context, key)
 }
 
 func (c *cancelCtx) Done() <-chan struct{} {
@@ -563,5 +563,31 @@ func (c *valueCtx) Value(key interface{}) interface{} {
        if c.key == key {
                return c.val
        }
-       return c.Context.Value(key)
+       return value(c.Context, key)
+}
+
+func value(c Context, key interface{}) interface{} {
+       for {
+               switch ctx := c.(type) {
+               case *valueCtx:
+                       if key == ctx.key {
+                               return ctx.val
+                       }
+                       c = ctx.Context
+               case *cancelCtx:
+                       if key == &cancelCtxKey {
+                               return c
+                       }
+                       c = ctx.Context
+               case *timerCtx:
+                       if key == &cancelCtxKey {
+                               return &ctx.cancelCtx
+                       }
+                       c = ctx.Context
+               case *emptyCtx:
+                       return nil
+               default:
+                       return c.Value(key)
+               }
+       }
 }
index 1de0e457a266e02bd8fff70a84c73b6f606d1478..98fb6d8e9bf3249eec28284c7dc0c9042fc83b05 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64
-// +build amd64 arm64
 
 package aes
 
index 846f56ab56fd73c10ca6c75ba7d01d6340725596..ecc6ccbbfbb6129424c9ea5e893c9c6fd002afc0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64
-// +build amd64 arm64
 
 package aes
 
index 22ce3be7f3c0a88ee916141539099a887a2e7615..bff21ae54b59c01c2c06b65e624b6f5ab43c6f04 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !s390x && !ppc64le && !arm64
-// +build !amd64,!s390x,!ppc64le,!arm64
 
 package aes
 
index 01b4e0875738d0f5140bdbf9dfa99c8babf34772..cba6c8873fecf4dfb59fb96b3d3f7950924d3622 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64le
-// +build ppc64le
 
 package aes
 
index 03208402d79bd459b3552dacbeec21c980f6163d..43517a8e20329be56b5b5195598844e735201bed 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !ppc64 && !ppc64le && !arm64
-// +build !amd64,!ppc64,!ppc64le,!arm64
 
 package cipher
 
index f520208a379011889a7078113398eb6077cdd71c..f81eec531d8983793e103cdfd1dfd0c07290b61c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package cipher
 
index ce473b5afe1a4ac1f94d778d91b2f7158fce2a34..cb87972afc7611b8a83bade8f2669f9a85364fbb 100644 (file)
@@ -150,9 +150,29 @@ func RegisterHash(h Hash, f func() hash.Hash) {
 }
 
 // PublicKey represents a public key using an unspecified algorithm.
+//
+// Although this type is an empty interface for backwards compatibility reasons,
+// all public key types in the standard library implement the following interface
+//
+//     interface{
+//         Equal(x crypto.PublicKey) bool
+//     }
+//
+// which can be used for increased type safety within applications.
 type PublicKey interface{}
 
 // PrivateKey represents a private key using an unspecified algorithm.
+//
+// Although this type is an empty interface for backwards compatibility reasons,
+// all private key types in the standard library implement the following interface
+//
+//     interface{
+//         Public() crypto.PublicKey
+//         Equal(x crypto.PrivateKey) bool
+//     }
+//
+// as well as purpose-specific interfaces such as Signer and Decrypter, which
+// can be used for increased type safety within applications.
 type PrivateKey interface{}
 
 // Signer is an interface for an opaque private key that can be used for
index 1a7635ec2be3364981b845f298f989c4c267fb0e..4be0026b9a5dc4914041c13bf741e9d42084a678 100644 (file)
@@ -236,12 +236,8 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
        }
        boring.UnreachableExceptTests()
 
-       // Get min(log2(q) / 2, 256) bits of entropy from rand.
-       entropylen := (priv.Curve.Params().BitSize + 7) / 16
-       if entropylen > 32 {
-               entropylen = 32
-       }
-       entropy := make([]byte, entropylen)
+       // Get 256 bits of entropy from rand.
+       entropy := make([]byte, 32)
        _, err = io.ReadFull(rand, entropy)
        if err != nil {
                return
index 68670a4f93fc61463d27ea405c11b3eabd561172..7fbca10b56f26166de48db64f4d3f9737b38a64c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !s390x
-// +build !s390x
 
 package ecdsa
 
index f5633fb8a62dec57d7e48f96774dadc92577948f..fd1dc7c0605a5d94cf0aff5e632cc82f95c35f4f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build s390x
-// +build s390x
 
 package ecdsa
 
index 556818acf4d14ac411cfc3393746e8bb075dca56..c8390b2cc9ffc4516b79114a5d40178ba6a0c22a 100644 (file)
@@ -219,9 +219,9 @@ func TestVectors(t *testing.T) {
 
                if line[0] == '[' {
                        line = line[1 : len(line)-1]
-                       parts := strings.SplitN(line, ",", 2)
+                       curve, hash, _ := strings.Cut(line, ",")
 
-                       switch parts[0] {
+                       switch curve {
                        case "P-224":
                                pub.Curve = elliptic.P224()
                        case "P-256":
@@ -234,7 +234,7 @@ func TestVectors(t *testing.T) {
                                pub.Curve = nil
                        }
 
-                       switch parts[1] {
+                       switch hash {
                        case "SHA-1":
                                h = sha1.New()
                        case "SHA-224":
index 8fe583939f15a5d0079ed309fa6866b3764aed0d..363020bd6b8fc86888933d9fc24e835bb97c3a58 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
 
 //go:build amd64 && gc && !purego
-// +build amd64,gc,!purego
 
 package field
 
index ddb6c9b8f7f2453bfedcf56d7533048b38255d1a..9da280d1d887d01790b1a4c936a77b9eaefa20e7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 || !gc || purego
-// +build !amd64 !gc purego
 
 package field
 
index af459ef51549e743f65998ef295447dc0feac8ff..075fe9b925742e031a45f7f398fbe3ffea18d3e0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 && gc && !purego
-// +build arm64,gc,!purego
 
 package field
 
index 234a5b2e5d18abb386567fe10e05517930cc4815..fc029ac12dae057c74925b3e5336c0367b73f831 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !arm64 || !gc || purego
-// +build !arm64 !gc purego
 
 package field
 
index beec956bf7e0a5d6df19297844808413d5f20708..5ca40f7bfa7a87f1b54ff65ced24d56db7142e6a 100644 (file)
@@ -40,7 +40,7 @@ func (v *projLookupTable) FromP3(q *Point) {
        for i := 0; i < 7; i++ {
                // Compute (i+1)*Q as Q + i*Q and convert to a ProjCached
                // This is needlessly complicated because the API has explicit
-               // recievers instead of creating stack objects and relying on RVO
+               // receivers instead of creating stack objects and relying on RVO
                v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
        }
 }
index f072960bfeddf83ce69d6a6ec1c701b99a2a6d9b..cdde0c4e607b2f7c6f6a7295538496833b0155c7 100644 (file)
@@ -21,9 +21,12 @@ import (
 
 // A Curve represents a short-form Weierstrass curve with a=-3.
 //
-// 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.
+// The output of Add, Double, and ScalarMult when the input is not a point on
+// the curve is undefined.
+//
+// Note that the conventional point at infinity (0, 0) is not considered on the
+// curve, although it can be returned by Add, Double, ScalarMult, or
+// ScalarBaseMult (but not Unmarshal or UnmarshalCompressed).
 type Curve interface {
        // Params returns the parameters for the curve.
        Params() *CurveParams
index 183861a54b52fe2678f9165b171a38b471e9b40f..d30a6939a4e35c5382d15c52d78b03de2a3cf884 100644 (file)
@@ -109,6 +109,15 @@ func testInfinity(t *testing.T, curve Curve) {
        if curve.IsOnCurve(x, y) {
                t.Errorf("IsOnCurve(∞) == true")
        }
+
+       if xx, yy := Unmarshal(curve, Marshal(curve, x, y)); xx != nil || yy != nil {
+               t.Errorf("Unmarshal(Marshal(∞)) did not return an error")
+       }
+       // We don't test UnmarshalCompressed(MarshalCompressed(∞)) because there are
+       // two valid points with x = 0.
+       if xx, yy := Unmarshal(curve, []byte{0x00}); xx != nil || yy != nil {
+               t.Errorf("Unmarshal(∞) did not return an error")
+       }
 }
 
 func TestMarshal(t *testing.T) {
@@ -232,6 +241,16 @@ func testMarshalCompressed(t *testing.T, curve Curve, x, y *big.Int, want []byte
        }
 }
 
+func TestLargeIsOnCurve(t *testing.T) {
+       testAllCurves(t, func(t *testing.T, curve Curve) {
+               large := big.NewInt(1)
+               large.Lsh(large, 1000)
+               if curve.IsOnCurve(large, large) {
+                       t.Errorf("(2^1000, 2^1000) is reported on the curve")
+               }
+       })
+}
+
 func benchmarkAllCurves(t *testing.B, f func(*testing.B, Curve)) {
        tests := []struct {
                name  string
@@ -274,3 +293,29 @@ func BenchmarkScalarMult(b *testing.B) {
                }
        })
 }
+
+func BenchmarkMarshalUnmarshal(b *testing.B) {
+       benchmarkAllCurves(b, func(b *testing.B, curve Curve) {
+               _, x, y, _ := GenerateKey(curve, rand.Reader)
+               b.Run("Uncompressed", func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               buf := Marshal(curve, x, y)
+                               xx, yy := Unmarshal(curve, buf)
+                               if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+                                       b.Error("Unmarshal output different from Marshal input")
+                               }
+                       }
+               })
+               b.Run("Compressed", func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               buf := Marshal(curve, x, y)
+                               xx, yy := Unmarshal(curve, buf)
+                               if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+                                       b.Error("Unmarshal output different from Marshal input")
+                               }
+                       }
+               })
+       })
+}
diff --git a/src/crypto/elliptic/export_generate.go b/src/crypto/elliptic/export_generate.go
new file mode 100644 (file)
index 0000000..f15b302
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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:build tablegen
+
+package elliptic
+
+// This block exports p256-related internals for the p256 table generator in internal/gen.
+var (
+       P256PointDoubleAsm = p256PointDoubleAsm
+       P256PointAddAsm    = p256PointAddAsm
+       P256Inverse        = p256Inverse
+       P256Sqr            = p256Sqr
+       P256Mul            = p256Mul
+)
index 8ff3bf3cc245056169cc4c74d74de4db0d390217..2b5ddae1d9e96ee61293b245fae397976f31d08f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64 || ppc64le
-// +build amd64 arm64 ppc64le
 
 package elliptic
 
diff --git a/src/crypto/elliptic/gen_p256_table.go b/src/crypto/elliptic/gen_p256_table.go
new file mode 100644 (file)
index 0000000..367bd4b
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2021 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:build ignore
+
+package main
+
+import (
+       "bytes"
+       "crypto/elliptic"
+       "encoding/binary"
+       "fmt"
+       "go/format"
+       "log"
+       "os"
+)
+
+func main() {
+       buf := new(bytes.Buffer)
+       fmt.Fprint(buf, `
+// Copyright 2021 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.
+
+// Generated by gen_p256_table.go. DO NOT EDIT.
+
+//go:build amd64 || arm64
+
+package elliptic
+
+`[1:])
+
+       // Generate precomputed p256 tables.
+       var pre [43][32 * 8]uint64
+       basePoint := []uint64{
+               0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510, 0x18905f76a53755c6,
+               0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325, 0x8571ff1825885d85,
+               0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe,
+       }
+       t1 := make([]uint64, 12)
+       t2 := make([]uint64, 12)
+       copy(t2, basePoint)
+       zInv := make([]uint64, 4)
+       zInvSq := make([]uint64, 4)
+       for j := 0; j < 32; j++ {
+               copy(t1, t2)
+               for i := 0; i < 43; i++ {
+                       // The window size is 6 so we need to double 6 times.
+                       if i != 0 {
+                               for k := 0; k < 6; k++ {
+                                       elliptic.P256PointDoubleAsm(t1, t1)
+                               }
+                       }
+                       // Convert the point to affine form. (Its values are
+                       // still in Montgomery form however.)
+                       elliptic.P256Inverse(zInv, t1[8:12])
+                       elliptic.P256Sqr(zInvSq, zInv, 1)
+                       elliptic.P256Mul(zInv, zInv, zInvSq)
+                       elliptic.P256Mul(t1[:4], t1[:4], zInvSq)
+                       elliptic.P256Mul(t1[4:8], t1[4:8], zInv)
+                       copy(t1[8:12], basePoint[8:12])
+                       // Update the table entry
+                       copy(pre[i][j*8:], t1[:8])
+               }
+               if j == 0 {
+                       elliptic.P256PointDoubleAsm(t2, basePoint)
+               } else {
+                       elliptic.P256PointAddAsm(t2, t2, basePoint)
+               }
+       }
+
+       fmt.Fprint(buf, "const p256Precomputed = \"\" +\n\n")
+
+       // Dump the precomputed tables, flattened, little-endian.
+       // These tables are used directly by assembly on little-endian platforms.
+       // Putting the data in a const string lets it be stored readonly.
+       for i := range &pre {
+               for j, v := range &pre[i] {
+                       fmt.Fprintf(buf, "\"")
+                       var u8 [8]byte
+                       binary.LittleEndian.PutUint64(u8[:], v)
+                       for _, b := range &u8 {
+                               fmt.Fprintf(buf, "\\x%02x", b)
+                       }
+                       fmt.Fprintf(buf, "\"")
+                       if i < len(pre)-1 || j < len(pre[i])-1 {
+                               fmt.Fprint(buf, "+")
+                       }
+                       if j%8 == 7 {
+                               fmt.Fprint(buf, "\n")
+                       }
+               }
+               fmt.Fprint(buf, "\n")
+       }
+
+       src := buf.Bytes()
+       fmtsrc, fmterr := format.Source(src)
+       // If formatting failed, keep the original source for debugging.
+       if fmterr == nil {
+               src = fmtsrc
+       }
+       err := os.WriteFile("p256_asm_table.go", src, 0644)
+       if err != nil {
+               log.Fatal(err)
+       }
+       if fmterr != nil {
+               log.Fatal(fmterr)
+       }
+}
index dc677327e6de899c7c84047aabd242d717ef071d..647c3f914f7b7f04c8f372acc95c6a1484c5c365 100644 (file)
@@ -53,28 +53,40 @@ func (e *P521Element) Set(t *P521Element) *P521Element {
        return e
 }
 
-// Bytes returns the 66-byte little-endian encoding of e.
+// Bytes returns the 66-byte big-endian encoding of e.
 func (e *P521Element) Bytes() []byte {
-       // This function must be inlined to move the allocation to the parent and
-       // save it from escaping to the heap.
+       // This function is outlined to make the allocations inline in the caller
+       // rather than happen on the heap.
        var out [66]byte
-       p521ToBytes(&out, &e.x)
+       return e.bytes(&out)
+}
+
+func (e *P521Element) bytes(out *[66]byte) []byte {
+       p521ToBytes(out, &e.x)
+       invertEndianness(out[:])
        return out[:]
 }
 
-// SetBytes sets e = v, where v is a little-endian 66-byte encoding, and returns
+// SetBytes sets e = v, where v is a big-endian 66-byte encoding, and returns
 // e. If v is not 66 bytes or it encodes a value higher than 2^521 - 1, SetBytes
 // returns nil and an error, and e is unchanged.
 func (e *P521Element) SetBytes(v []byte) (*P521Element, error) {
-       if len(v) != 66 || v[65] > 1 {
+       if len(v) != 66 || v[0] > 1 {
                return nil, errors.New("invalid P-521 field encoding")
        }
        var in [66]byte
        copy(in[:], v)
+       invertEndianness(in[:])
        p521FromBytes(&e.x, &in)
        return e, nil
 }
 
+func invertEndianness(v []byte) {
+       for i := 0; i < len(v)/2; i++ {
+               v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
+       }
+}
+
 // Add sets e = t1 + t2, and returns e.
 func (e *P521Element) Add(t1, t2 *P521Element) *P521Element {
        p521Add(&e.x, &t1.x, &t2.x)
index 661bde397e43924d519ca77b7fa3a400191ca71c..2b374faa2723b44fdb0710f3eb70c5213c55401d 100644 (file)
@@ -15,7 +15,7 @@ func p521Random(t *testing.T) *fiat.P521Element {
        if _, err := rand.Read(buf); err != nil {
                t.Fatal(err)
        }
-       buf[65] &= 1
+       buf[0] &= 1
        e, err := new(fiat.P521Element).SetBytes(buf)
        if err != nil {
                t.Fatal(err)
diff --git a/src/crypto/elliptic/internal/nistec/p521.go b/src/crypto/elliptic/internal/nistec/p521.go
new file mode 100644 (file)
index 0000000..e5b4e46
--- /dev/null
@@ -0,0 +1,306 @@
+// Copyright 2021 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 nistec implements the NIST P elliptic curves from FIPS 186-4.
+//
+// This package uses fiat-crypto for its backend field arithmetic (not math/big)
+// and exposes constant-time, heap allocation-free, byte slice-based safe APIs.
+// Group operations use modern and safe complete addition formulas. The point at
+// infinity is handled and encoded according to SEC 1, Version 2.0, and invalid
+// curve points can't be represented.
+package nistec
+
+import (
+       "crypto/elliptic/internal/fiat"
+       "crypto/subtle"
+       "errors"
+)
+
+var p521B, _ = new(fiat.P521Element).SetBytes([]byte{
+       0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a, 0x1f, 0x92, 0x9a,
+       0x21, 0xa0, 0xb6, 0x85, 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
+       0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09, 0xe1, 0x56, 0x19,
+       0x39, 0x51, 0xec, 0x7e, 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
+       0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34, 0xf1, 0xef, 0x45,
+       0x1f, 0xd4, 0x6b, 0x50, 0x3f, 0x00})
+
+var p521G, _ = NewP521Point().SetBytes([]byte{0x04,
+       0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd, 0x9e, 0x3e,
+       0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
+       0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba, 0xa1, 0x4b,
+       0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
+       0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b, 0xf9, 0x7e,
+       0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78,
+       0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9,
+       0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17,
+       0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40,
+       0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86,
+       0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50})
+
+const p521ElementLength = 66
+
+// P521Point is a P-521 point. The zero value is NOT valid.
+type P521Point struct {
+       // The point is represented in projective coordinates (X:Y:Z),
+       // where x = X/Z and y = Y/Z.
+       x, y, z *fiat.P521Element
+}
+
+// NewP521Point returns a new P521Point representing the point at infinity point.
+func NewP521Point() *P521Point {
+       return &P521Point{
+               x: new(fiat.P521Element),
+               y: new(fiat.P521Element).One(),
+               z: new(fiat.P521Element),
+       }
+}
+
+// NewP521Generator returns a new P521Point set to the canonical generator.
+func NewP521Generator() *P521Point {
+       return NewP521Point().Set(p521G)
+}
+
+// Set sets p = q and returns p.
+func (p *P521Point) Set(q *P521Point) *P521Point {
+       p.x.Set(q.x)
+       p.y.Set(q.y)
+       p.z.Set(q.z)
+       return p
+}
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *P521Point) SetBytes(b []byte) (*P521Point, error) {
+       switch {
+       // Point at infinity.
+       case len(b) == 1 && b[0] == 0:
+               return p.Set(NewP521Point()), nil
+
+       // Uncompressed form.
+       case len(b) == 1+2*p521ElementLength && b[0] == 4:
+               x, err := new(fiat.P521Element).SetBytes(b[1 : 1+p521ElementLength])
+               if err != nil {
+                       return nil, err
+               }
+               y, err := new(fiat.P521Element).SetBytes(b[1+p521ElementLength:])
+               if err != nil {
+                       return nil, err
+               }
+               if err := p521CheckOnCurve(x, y); err != nil {
+                       return nil, err
+               }
+               p.x.Set(x)
+               p.y.Set(y)
+               p.z.One()
+               return p, nil
+
+       // Compressed form
+       case len(b) == 1+p521ElementLength && b[0] == 0:
+               return nil, errors.New("unimplemented") // TODO(filippo)
+
+       default:
+               return nil, errors.New("invalid P521 point encoding")
+       }
+}
+
+func p521CheckOnCurve(x, y *fiat.P521Element) error {
+       // x³ - 3x + b.
+       x3 := new(fiat.P521Element).Square(x)
+       x3.Mul(x3, x)
+
+       threeX := new(fiat.P521Element).Add(x, x)
+       threeX.Add(threeX, x)
+
+       x3.Sub(x3, threeX)
+       x3.Add(x3, p521B)
+
+       // y² = x³ - 3x + b
+       y2 := new(fiat.P521Element).Square(y)
+
+       if x3.Equal(y2) != 1 {
+               return errors.New("P521 point not on curve")
+       }
+       return nil
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *P521Point) Bytes() []byte {
+       // This function is outlined to make the allocations inline in the caller
+       // rather than happen on the heap.
+       var out [133]byte
+       return p.bytes(&out)
+}
+
+func (p *P521Point) bytes(out *[133]byte) []byte {
+       if p.z.IsZero() == 1 {
+               return append(out[:0], 0)
+       }
+
+       zinv := new(fiat.P521Element).Invert(p.z)
+       xx := new(fiat.P521Element).Mul(p.x, zinv)
+       yy := new(fiat.P521Element).Mul(p.y, zinv)
+
+       buf := append(out[:0], 4)
+       buf = append(buf, xx.Bytes()...)
+       buf = append(buf, yy.Bytes()...)
+       return buf
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *P521Point) Add(p1, p2 *P521Point) *P521Point {
+       // Complete addition formula for a = -3 from "Complete addition formulas for
+       // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+       t0 := new(fiat.P521Element).Mul(p1.x, p2.x) // t0 := X1 * X2
+       t1 := new(fiat.P521Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
+       t2 := new(fiat.P521Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
+       t3 := new(fiat.P521Element).Add(p1.x, p1.y) // t3 := X1 + Y1
+       t4 := new(fiat.P521Element).Add(p2.x, p2.y) // t4 := X2 + Y2
+       t3.Mul(t3, t4)                              // t3 := t3 * t4
+       t4.Add(t0, t1)                              // t4 := t0 + t1
+       t3.Sub(t3, t4)                              // t3 := t3 - t4
+       t4.Add(p1.y, p1.z)                          // t4 := Y1 + Z1
+       x3 := new(fiat.P521Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
+       t4.Mul(t4, x3)                              // t4 := t4 * X3
+       x3.Add(t1, t2)                              // X3 := t1 + t2
+       t4.Sub(t4, x3)                              // t4 := t4 - X3
+       x3.Add(p1.x, p1.z)                          // X3 := X1 + Z1
+       y3 := new(fiat.P521Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
+       x3.Mul(x3, y3)                              // X3 := X3 * Y3
+       y3.Add(t0, t2)                              // Y3 := t0 + t2
+       y3.Sub(x3, y3)                              // Y3 := X3 - Y3
+       z3 := new(fiat.P521Element).Mul(p521B, t2)  // Z3 := b * t2
+       x3.Sub(y3, z3)                              // X3 := Y3 - Z3
+       z3.Add(x3, x3)                              // Z3 := X3 + X3
+       x3.Add(x3, z3)                              // X3 := X3 + Z3
+       z3.Sub(t1, x3)                              // Z3 := t1 - X3
+       x3.Add(t1, x3)                              // X3 := t1 + X3
+       y3.Mul(p521B, y3)                           // Y3 := b * Y3
+       t1.Add(t2, t2)                              // t1 := t2 + t2
+       t2.Add(t1, t2)                              // t2 := t1 + t2
+       y3.Sub(y3, t2)                              // Y3 := Y3 - t2
+       y3.Sub(y3, t0)                              // Y3 := Y3 - t0
+       t1.Add(y3, y3)                              // t1 := Y3 + Y3
+       y3.Add(t1, y3)                              // Y3 := t1 + Y3
+       t1.Add(t0, t0)                              // t1 := t0 + t0
+       t0.Add(t1, t0)                              // t0 := t1 + t0
+       t0.Sub(t0, t2)                              // t0 := t0 - t2
+       t1.Mul(t4, y3)                              // t1 := t4 * Y3
+       t2.Mul(t0, y3)                              // t2 := t0 * Y3
+       y3.Mul(x3, z3)                              // Y3 := X3 * Z3
+       y3.Add(y3, t2)                              // Y3 := Y3 + t2
+       x3.Mul(t3, x3)                              // X3 := t3 * X3
+       x3.Sub(x3, t1)                              // X3 := X3 - t1
+       z3.Mul(t4, z3)                              // Z3 := t4 * Z3
+       t1.Mul(t3, t0)                              // t1 := t3 * t0
+       z3.Add(z3, t1)                              // Z3 := Z3 + t1
+
+       q.x.Set(x3)
+       q.y.Set(y3)
+       q.z.Set(z3)
+       return q
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *P521Point) Double(p *P521Point) *P521Point {
+       // Complete addition formula for a = -3 from "Complete addition formulas for
+       // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+       t0 := new(fiat.P521Element).Square(p.x)    // t0 := X ^ 2
+       t1 := new(fiat.P521Element).Square(p.y)    // t1 := Y ^ 2
+       t2 := new(fiat.P521Element).Square(p.z)    // t2 := Z ^ 2
+       t3 := new(fiat.P521Element).Mul(p.x, p.y)  // t3 := X * Y
+       t3.Add(t3, t3)                             // t3 := t3 + t3
+       z3 := new(fiat.P521Element).Mul(p.x, p.z)  // Z3 := X * Z
+       z3.Add(z3, z3)                             // Z3 := Z3 + Z3
+       y3 := new(fiat.P521Element).Mul(p521B, t2) // Y3 := b * t2
+       y3.Sub(y3, z3)                             // Y3 := Y3 - Z3
+       x3 := new(fiat.P521Element).Add(y3, y3)    // X3 := Y3 + Y3
+       y3.Add(x3, y3)                             // Y3 := X3 + Y3
+       x3.Sub(t1, y3)                             // X3 := t1 - Y3
+       y3.Add(t1, y3)                             // Y3 := t1 + Y3
+       y3.Mul(x3, y3)                             // Y3 := X3 * Y3
+       x3.Mul(x3, t3)                             // X3 := X3 * t3
+       t3.Add(t2, t2)                             // t3 := t2 + t2
+       t2.Add(t2, t3)                             // t2 := t2 + t3
+       z3.Mul(p521B, z3)                          // Z3 := b * Z3
+       z3.Sub(z3, t2)                             // Z3 := Z3 - t2
+       z3.Sub(z3, t0)                             // Z3 := Z3 - t0
+       t3.Add(z3, z3)                             // t3 := Z3 + Z3
+       z3.Add(z3, t3)                             // Z3 := Z3 + t3
+       t3.Add(t0, t0)                             // t3 := t0 + t0
+       t0.Add(t3, t0)                             // t0 := t3 + t0
+       t0.Sub(t0, t2)                             // t0 := t0 - t2
+       t0.Mul(t0, z3)                             // t0 := t0 * Z3
+       y3.Add(y3, t0)                             // Y3 := Y3 + t0
+       t0.Mul(p.y, p.z)                           // t0 := Y * Z
+       t0.Add(t0, t0)                             // t0 := t0 + t0
+       z3.Mul(t0, z3)                             // Z3 := t0 * Z3
+       x3.Sub(x3, z3)                             // X3 := X3 - Z3
+       z3.Mul(t0, t1)                             // Z3 := t0 * t1
+       z3.Add(z3, z3)                             // Z3 := Z3 + Z3
+       z3.Add(z3, z3)                             // Z3 := Z3 + Z3
+
+       q.x.Set(x3)
+       q.y.Set(y3)
+       q.z.Set(z3)
+       return q
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *P521Point) Select(p1, p2 *P521Point, cond int) *P521Point {
+       q.x.Select(p1.x, p2.x, cond)
+       q.y.Select(p1.y, p2.y, cond)
+       q.z.Select(p1.z, p2.z, cond)
+       return q
+}
+
+// ScalarMult sets p = scalar * q, and returns p.
+func (p *P521Point) ScalarMult(q *P521Point, scalar []byte) *P521Point {
+       // table holds the first 16 multiples of q. The explicit newP521Point calls
+       // get inlined, letting the allocations live on the stack.
+       var table = [16]*P521Point{
+               NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
+               NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
+               NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
+               NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
+       }
+       for i := 1; i < 16; i++ {
+               table[i].Add(table[i-1], q)
+       }
+
+       // Instead of doing the classic double-and-add chain, we do it with a
+       // four-bit window: we double four times, and then add [0-15]P.
+       t := NewP521Point()
+       p.Set(NewP521Point())
+       for _, byte := range scalar {
+               p.Double(p)
+               p.Double(p)
+               p.Double(p)
+               p.Double(p)
+
+               for i := uint8(0); i < 16; i++ {
+                       cond := subtle.ConstantTimeByteEq(byte>>4, i)
+                       t.Select(table[i], t, cond)
+               }
+               p.Add(p, t)
+
+               p.Double(p)
+               p.Double(p)
+               p.Double(p)
+               p.Double(p)
+
+               for i := uint8(0); i < 16; i++ {
+                       cond := subtle.ConstantTimeByteEq(byte&0b1111, i)
+                       t.Select(table[i], t, cond)
+               }
+               p.Add(p, t)
+       }
+
+       return p
+}
diff --git a/src/crypto/elliptic/internal/nistec/p521_test.go b/src/crypto/elliptic/internal/nistec/p521_test.go
new file mode 100644 (file)
index 0000000..e62c1cb
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2021 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 nistec_test
+
+import (
+       "crypto/elliptic/internal/nistec"
+       "math/rand"
+       "os"
+       "strings"
+       "testing"
+)
+
+func TestP521Allocations(t *testing.T) {
+       if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") {
+               t.Skip("skipping allocations test without relevant optimizations")
+       }
+       if allocs := testing.AllocsPerRun(100, func() {
+               p := nistec.NewP521Generator()
+               scalar := make([]byte, 66)
+               rand.Read(scalar)
+               p.ScalarMult(p, scalar)
+               out := p.Bytes()
+               if _, err := p.SetBytes(out); err != nil {
+                       t.Fatal(err)
+               }
+       }); allocs > 0 {
+               t.Errorf("expected zero allocations, got %0.1f", allocs)
+       }
+}
+
+func BenchmarkScalarMult(b *testing.B) {
+       b.Run("P521", func(b *testing.B) {
+               scalar := make([]byte, 66)
+               rand.Read(scalar)
+               p := nistec.NewP521Generator()
+               b.ReportAllocs()
+               b.ResetTimer()
+               for i := 0; i < b.N; i++ {
+                       p.ScalarMult(p, scalar)
+               }
+       })
+}
index 8c76021464207f4f78a1bd0a7bc3d7d8e7bbb20e..34079d14b12496c7ba375e7a1452ff0b67d1816e 100644 (file)
@@ -10,7 +10,9 @@ package elliptic
 // See https://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
 
 import (
+       "encoding/binary"
        "math/big"
+       "math/bits"
 )
 
 var p224 p224Curve
@@ -48,6 +50,10 @@ func (curve p224Curve) Params() *CurveParams {
 }
 
 func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool {
+       if bigX.BitLen() > 224 || bigY.BitLen() > 224 {
+               return false
+       }
+
        var x, y p224FieldElement
        p224FromBig(&x, bigX)
        p224FromBig(&y, bigY)
@@ -139,41 +145,22 @@ func (curve p224Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
 type p224FieldElement [8]uint32
 
 // p224P is the order of the field, represented as a p224FieldElement.
-var p224P = [8]uint32{1, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
+var p224P = p224FieldElement{1, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
 
 // p224IsZero returns 1 if a == 0 mod p and 0 otherwise.
 //
 // a[i] < 2**29
 func p224IsZero(a *p224FieldElement) uint32 {
-       // Since a p224FieldElement contains 224 bits there are two possible
-       // representations of 0: 0 and p.
        var minimal p224FieldElement
        p224Contract(&minimal, a)
 
-       var isZero, isP uint32
-       for i, v := range minimal {
-               isZero |= v
-               isP |= v - p224P[i]
+       var acc uint32
+       for _, v := range minimal {
+               acc |= v
        }
+       mask := ^maskIsNotZero(acc)
 
-       // If either isZero or isP is 0, then we should return 1.
-       isZero |= isZero >> 16
-       isZero |= isZero >> 8
-       isZero |= isZero >> 4
-       isZero |= isZero >> 2
-       isZero |= isZero >> 1
-
-       isP |= isP >> 16
-       isP |= isP >> 8
-       isP |= isP >> 4
-       isP |= isP >> 2
-       isP |= isP >> 1
-
-       // For isZero and isP, the LSB is 0 iff all the bits are zero.
-       result := isZero & isP
-       result = (^result) & 1
-
-       return result
+       return 1 & mask
 }
 
 // p224Add computes *out = a+b
@@ -192,6 +179,12 @@ const two31m15m3 = 1<<31 - 1<<15 - 1<<3
 // p224ZeroModP31 is 0 mod p where bit 31 is set in all limbs so that we can
 // subtract smaller amounts without underflow. See the section "Subtraction" in
 // [1] for reasoning.
+//
+// To calculate this value, start by adding 2³¹ to the lowest limb and
+// subtracting 2³ from the next one to compensate. Repeat for each next limb,
+// ending up with 2³¹ - 2³ in each of them, and a carry of -2³. Apply the
+// reduction identity, and we need to subtract 2³ * 2⁹⁶ - 2³ = 2¹⁵ * 2⁸⁴ - 2³ so
+// we subtract 2¹⁵ from the 4th limb and add 2³ to the first limb.
 var p224ZeroModP31 = []uint32{two31p3, two31m3, two31m3, two31m15m3, two31m3, two31m3, two31m3, two31m3}
 
 // p224Sub computes *out = a-b
@@ -225,7 +218,7 @@ const bottom28Bits = 0xfffffff
 // a[i] < 2**29, b[i] < 2**30 (or vice versa)
 // out[i] < 2**29
 func p224Mul(out, a, b *p224FieldElement, tmp *p224LargeFieldElement) {
-       for i := 0; i < 15; i++ {
+       for i := range tmp {
                tmp[i] = 0
        }
 
@@ -243,7 +236,7 @@ func p224Mul(out, a, b *p224FieldElement, tmp *p224LargeFieldElement) {
 // a[i] < 2**29
 // out[i] < 2**29
 func p224Square(out, a *p224FieldElement, tmp *p224LargeFieldElement) {
-       for i := 0; i < 15; i++ {
+       for i := range tmp {
                tmp[i] = 0
        }
 
@@ -253,7 +246,7 @@ func p224Square(out, a *p224FieldElement, tmp *p224LargeFieldElement) {
                        if i == j {
                                tmp[i+j] += r
                        } else {
-                               tmp[i+j] += r << 1
+                               tmp[i+j] += r * 2
                        }
                }
        }
@@ -264,22 +257,33 @@ func p224Square(out, a *p224FieldElement, tmp *p224LargeFieldElement) {
 // ReduceLarge converts a p224LargeFieldElement to a p224FieldElement.
 //
 // in[i] < 2**62
+// out[i] < 2**29
 func p224ReduceLarge(out *p224FieldElement, in *p224LargeFieldElement) {
        for i := 0; i < 8; i++ {
                in[i] += p224ZeroModP63[i]
        }
 
-       // Eliminate the coefficients at 2**224 and greater.
+       // Eliminate the coefficients at 2**224 and greater by applying the
+       // reduction identity.
+       //
+       //   a + top * 2²²⁴ = a + top * 2⁹⁶ - top
+       //
+       // Since top here is in[8..14], both the subtraction at offset 0 and the
+       // addition at offset 96 (3 * 28 + 16) span multiple limbs. The subtraction
+       // can't underflow because of the p224ZeroModP63 addition above, while the
+       // addition can't overflow because of the 62 bit input bounds.
        for i := 14; i >= 8; i-- {
                in[i-8] -= in[i]
                in[i-5] += (in[i] & 0xffff) << 12
                in[i-4] += in[i] >> 16
        }
        in[8] = 0
-       // in[0..8] < 2**64
+       // in[0..7] < 2**64
+       // in[9..14] discarded
 
-       // As the values become small enough, we start to store them in |out|
-       // and use 32-bit operations.
+       // Run a carry chain and light reduction. Keep [0] large so we can do the
+       // subtraction safely. As the values become small enough, we start to store
+       // them in out and use 32-bit operations.
        for i := 1; i < 8; i++ {
                in[i+1] += in[i] >> 28
                out[i] = uint32(in[i] & bottom28Bits)
@@ -292,6 +296,7 @@ func p224ReduceLarge(out *p224FieldElement, in *p224LargeFieldElement) {
        // out[4] < 2**29
        // out[1,2,5..7] < 2**28
 
+       // Carry the overflow of [0] into the short 28 bit limbs.
        out[0] = uint32(in[0] & bottom28Bits)
        out[1] += uint32((in[0] >> 28) & bottom28Bits)
        out[2] += uint32(in[0] >> 56)
@@ -312,28 +317,23 @@ func p224Reduce(a *p224FieldElement) {
        top := a[7] >> 28
        a[7] &= bottom28Bits
 
-       // top < 2**4
-       mask := top
-       mask |= mask >> 2
-       mask |= mask >> 1
-       mask <<= 31
-       mask = uint32(int32(mask) >> 31)
-       // Mask is all ones if top != 0, all zero otherwise
-
        a[0] -= top
        a[3] += top << 12
 
-       // We may have just made a[0] negative but, if we did, then we must
-       // have added something to a[3], this it's > 2**12. Therefore we can
-       // carry down to a[0].
+       // We may have just made a[0] negative but if we did top must have been not
+       // zero, so a[3] is not zero, so we can carry down to a[0]. (Note that we
+       // don't actually check if a[0] went negative, like in p224Contract, nor we
+       // try to stop the carry at a[1] or a[2], because here we can afford to go
+       // above 28 bits, so instead we carry all the way down from a[3].)
+       mask := maskIsNotZero(top)
        a[3] -= 1 & mask
        a[2] += mask & (1<<28 - 1)
        a[1] += mask & (1<<28 - 1)
        a[0] += mask & (1 << 28)
 }
 
-// p224Invert calculates *out = in**-1 by computing in**(2**224 - 2**96 - 1),
-// i.e. Fermat's little theorem.
+// p224Invert calculates *out = in**-1 by using Fermat's little theorem and
+// computing in**(p-2) = in**(2**224 - 2**96 - 1).
 func p224Invert(out, in *p224FieldElement) {
        var f1, f2, f3, f4 p224FieldElement
        var c p224LargeFieldElement
@@ -408,13 +408,14 @@ func p224Contract(out, in *p224FieldElement) {
        // out[0] negative then we know that out[3] is sufficiently positive
        // because we just added to it.
        for i := 0; i < 3; i++ {
-               mask := uint32(int32(out[i]) >> 31)
+               mask := maskIsNegative(out[i])
                out[i] += (1 << 28) & mask
                out[i+1] -= 1 & mask
        }
 
        // We might have pushed out[3] over 2**28 so we perform another, partial,
-       // carry chain.
+       // carry chain; carry the overflow according to the reduction identity; and
+       // carry down in case we made out[0] negative.
        for i := 3; i < 7; i++ {
                out[i+1] += out[i] >> 28
                out[i] &= bottom28Bits
@@ -422,10 +423,15 @@ func p224Contract(out, in *p224FieldElement) {
        top = out[7] >> 28
        out[7] &= bottom28Bits
 
-       // Eliminate top while maintaining the same value mod p.
        out[0] -= top
        out[3] += top << 12
 
+       for i := 0; i < 3; i++ {
+               mask := maskIsNegative(out[i])
+               out[i] += (1 << 28) & mask
+               out[i+1] -= 1 & mask
+       }
+
        // There are two cases to consider for out[3]:
        //   1) The first time that we eliminated top, we didn't push out[3] over
        //      2**28. In this case, the partial carry chain didn't change any values
@@ -436,60 +442,14 @@ func p224Contract(out, in *p224FieldElement) {
        // In both cases, out[3] cannot have overflowed when we eliminated top for
        // the second time.
 
-       // Again, we may just have made out[0] negative, so do the same carry down.
-       // As before, if we made out[0] negative then we know that out[3] is
-       // sufficiently positive.
-       for i := 0; i < 3; i++ {
-               mask := uint32(int32(out[i]) >> 31)
-               out[i] += (1 << 28) & mask
-               out[i+1] -= 1 & mask
+       // Now we need to subtract p if the value is >= p. To check, we subtract p
+       // with a borrow chain and look at the final borrow bit.
+       var b uint32
+       for i := 0; i < len(out); i++ {
+               _, b = bits.Sub32(out[i], p224P[i], b)
        }
+       mask := ^maskIsNotZero(b)
 
-       // Now we see if the value is >= p and, if so, subtract p.
-
-       // First we build a mask from the top four limbs, which must all be
-       // equal to bottom28Bits if the whole value is >= p. If top4AllOnes
-       // ends up with any zero bits in the bottom 28 bits, then this wasn't
-       // true.
-       top4AllOnes := uint32(0xffffffff)
-       for i := 4; i < 8; i++ {
-               top4AllOnes &= out[i]
-       }
-       top4AllOnes |= 0xf0000000
-       // Now we replicate any zero bits to all the bits in top4AllOnes.
-       top4AllOnes &= top4AllOnes >> 16
-       top4AllOnes &= top4AllOnes >> 8
-       top4AllOnes &= top4AllOnes >> 4
-       top4AllOnes &= top4AllOnes >> 2
-       top4AllOnes &= top4AllOnes >> 1
-       top4AllOnes = uint32(int32(top4AllOnes<<31) >> 31)
-
-       // Now we test whether the bottom three limbs are non-zero.
-       bottom3NonZero := out[0] | out[1] | out[2]
-       bottom3NonZero |= bottom3NonZero >> 16
-       bottom3NonZero |= bottom3NonZero >> 8
-       bottom3NonZero |= bottom3NonZero >> 4
-       bottom3NonZero |= bottom3NonZero >> 2
-       bottom3NonZero |= bottom3NonZero >> 1
-       bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
-
-       // Assuming top4AllOnes != 0, everything depends on the value of out[3].
-       //    If it's > 0xffff000 then the whole value is > p
-       //    If it's = 0xffff000 and bottom3NonZero != 0, then the whole value is >= p
-       //    If it's < 0xffff000, then the whole value is < p
-       n := 0xffff000 - out[3]
-       out3Equal := n
-       out3Equal |= out3Equal >> 16
-       out3Equal |= out3Equal >> 8
-       out3Equal |= out3Equal >> 4
-       out3Equal |= out3Equal >> 2
-       out3Equal |= out3Equal >> 1
-       out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
-
-       // If out[3] > 0xffff000 then n's MSB will be one.
-       out3GT := uint32(int32(n) >> 31)
-
-       mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
        out[0] -= 1 & mask
        out[3] -= 0xffff000 & mask
        out[4] -= 0xfffffff & mask
@@ -501,12 +461,26 @@ func p224Contract(out, in *p224FieldElement) {
        // out[0..3] needs to be positive and able to absorb the -1 or the value
        // would have been < p, and the subtraction wouldn't have happened.
        for i := 0; i < 3; i++ {
-               mask := uint32(int32(out[i]) >> 31)
+               mask := maskIsNegative(out[i])
                out[i] += (1 << 28) & mask
                out[i+1] -= 1 & mask
        }
 }
 
+// maskIsNegative returns 0xffffffff if the most significant bit of v is set,
+// and 0 otherwise.
+func maskIsNegative(v uint32) uint32 { return uint32(int32(v) >> 31) }
+
+// maskIfNegative returns 0xffffffff if v is not zero, and 0 otherwise.
+func maskIsNotZero(v uint32) uint32 {
+       v |= v >> 16
+       v |= v >> 8
+       v |= v >> 4
+       v |= v >> 2
+       v |= v >> 1
+       return uint32(int32(v<<31) >> 31)
+}
+
 // Group element functions.
 //
 // These functions deal with group elements. The group is an elliptic curve
@@ -650,14 +624,11 @@ func p224DoubleJacobian(x3, y3, z3, x1, y1, z1 *p224FieldElement) {
        p224Reduce(y3)
 }
 
-// p224CopyConditional sets *out = *in iff the least-significant-bit of control
-// is true, and it runs in constant time.
+// p224CopyConditional sets *out = *in in constant time if control is not zero.
 func p224CopyConditional(out, in *p224FieldElement, control uint32) {
-       control <<= 31
-       control = uint32(int32(control) >> 31)
-
+       mask := maskIsNotZero(control)
        for i := 0; i < 8; i++ {
-               out[i] ^= (out[i] ^ in[i]) & control
+               out[i] ^= (out[i] ^ in[i]) & mask
        }
 }
 
@@ -702,37 +673,27 @@ func p224ToAffine(x, y, z *p224FieldElement) (*big.Int, *big.Int) {
 }
 
 // get28BitsFromEnd returns the least-significant 28 bits from buf>>shift,
-// where buf is interpreted as a big-endian number.
-func get28BitsFromEnd(buf []byte, shift uint) (uint32, []byte) {
-       var ret uint32
-
-       for i := uint(0); i < 4; i++ {
-               var b byte
-               if l := len(buf); l > 0 {
-                       b = buf[l-1]
-                       // We don't remove the byte if we're about to return and we're not
-                       // reading all of it.
-                       if i != 3 || shift == 4 {
-                               buf = buf[:l-1]
-                       }
-               }
-               ret |= uint32(b) << (8 * i) >> shift
+// where buf is interpreted as a big-endian number. shift must be at most
+// 4 bits higher than a multiple of 8.
+func get28BitsFromEnd(buf []byte, shift int) uint32 {
+       buf = buf[:len(buf)-shift/8]
+       shift = shift % 8
+       if shift > 4 {
+               panic("misuse of get28BitsFromEnd")
        }
+
+       ret := binary.BigEndian.Uint32(buf[len(buf)-4:])
+       ret >>= shift
        ret &= bottom28Bits
-       return ret, buf
+       return ret
 }
 
 // p224FromBig sets *out = *in.
 func p224FromBig(out *p224FieldElement, in *big.Int) {
-       bytes := in.Bytes()
-       out[0], bytes = get28BitsFromEnd(bytes, 0)
-       out[1], bytes = get28BitsFromEnd(bytes, 4)
-       out[2], bytes = get28BitsFromEnd(bytes, 0)
-       out[3], bytes = get28BitsFromEnd(bytes, 4)
-       out[4], bytes = get28BitsFromEnd(bytes, 0)
-       out[5], bytes = get28BitsFromEnd(bytes, 4)
-       out[6], bytes = get28BitsFromEnd(bytes, 0)
-       out[7], bytes = get28BitsFromEnd(bytes, 4)
+       bytes := in.FillBytes(make([]byte, 224/8))
+       for i := range out {
+               out[i] = get28BitsFromEnd(bytes, 28*i)
+       }
 }
 
 // p224ToBig returns in as a big.Int.
index b213b273d23d887b5c6e6d888e29872022d45f3c..3e0c78b0f9c0de2993efbb83832ff3cde161f75b 100644 (file)
@@ -261,7 +261,7 @@ func TestP224IsZero(t *testing.T) {
        if got := p224IsZero(&p224FieldElement{}); got != 1 {
                t.Errorf("p224IsZero(0) = %d, expected 1", got)
        }
-       if got := p224IsZero((*p224FieldElement)(&p224P)); got != 1 {
+       if got := p224IsZero(&p224P); got != 1 {
                t.Errorf("p224IsZero(p) = %d, expected 1", got)
        }
        if got := p224IsZero(&p224FieldElement{1}); got != 0 {
@@ -294,7 +294,7 @@ func TestP224Invert(t *testing.T) {
                t.Errorf("p224Invert(0) = %x, expected 0", out)
        }
 
-       p224Invert(&out, (*p224FieldElement)(&p224P))
+       p224Invert(&out, &p224P)
        if got := p224IsZero(&out); got != 1 {
                t.Errorf("p224Invert(p) = %x, expected 0", out)
        }
index b2b12c8f138bfeace215e47cc36cc2f3a5b33df6..7747de7a50bb3855800576f391f8b9c3678a81f4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !arm64
-// +build !amd64,!arm64
 
 package elliptic
 
index 9a808f260ac09535d488dfa390b61584506beba4..ff0c1596aa0cd59c5cabf0dd01589e528d162077 100644 (file)
@@ -11,7 +11,6 @@
 // https://eprint.iacr.org/2013/816.pdf
 
 //go:build amd64 || arm64
-// +build amd64 arm64
 
 package elliptic
 
@@ -19,6 +18,8 @@ import (
        "math/big"
 )
 
+//go:generate go run -tags=tablegen gen_p256_table.go
+
 type (
        p256Curve struct {
                *CurveParams
@@ -79,7 +80,7 @@ func p256LittleToBig(res []byte, in []uint64)
 func p256Select(point, table []uint64, idx int)
 
 //go:noescape
-func p256SelectBase(point, table []uint64, idx int)
+func p256SelectBase(point *[12]uint64, table string, idx int)
 
 // Montgomery multiplication modulo Ord(G)
 //go:noescape
@@ -410,7 +411,7 @@ func boothW6(in uint) (int, int) {
 func (p *p256Point) p256BaseMult(scalar []uint64) {
        wvalue := (scalar[0] << 1) & 0x7f
        sel, sign := boothW6(uint(wvalue))
-       p256SelectBase(p.xyz[0:8], p256Precomputed[0][0:], sel)
+       p256SelectBase(&p.xyz, p256Precomputed, sel)
        p256NegCond(p.xyz[4:8], sign)
 
        // (This is one, in the Montgomery domain.)
@@ -437,7 +438,7 @@ func (p *p256Point) p256BaseMult(scalar []uint64) {
                }
                index += 6
                sel, sign = boothW6(uint(wvalue))
-               p256SelectBase(t0.xyz[0:8], p256Precomputed[i][0:], sel)
+               p256SelectBase(&t0.xyz, p256Precomputed[i*32*8*8:], sel)
                p256PointAddAffineAsm(p.xyz[0:12], p.xyz[0:12], t0.xyz[0:8], sign, sel, zero)
                zero |= sel
        }
index c77b11bcf25c11a8179a2ee6ccacefe5ec5b695b..bd16add24175af6173c8f61d441f35571ec672a9 100644 (file)
@@ -668,10 +668,10 @@ loop_select:
        RET
 /* ---------------------------------------*/
 // Constant time point access to base point table.
-// func p256SelectBase(point, table []uint64, idx int)
+// func p256SelectBase(point *[12]uint64, table string, idx int)
 TEXT ·p256SelectBase(SB),NOSPLIT,$0
-       MOVQ idx+48(FP),AX
-       MOVQ table+24(FP),DI
+       MOVQ idx+24(FP),AX
+       MOVQ table+8(FP),DI
        MOVQ point+0(FP),DX
 
        PXOR X15, X15   // X15 = 0
index f571c5034284f43b94910070945a21420d619d49..2b2355d57cfa67c7ab0ebfd90788903f272d1e5e 100644 (file)
@@ -324,10 +324,10 @@ loop_select:
        RET
 /* ---------------------------------------*/
 // Constant time point access to base point table.
-// func p256SelectBase(point, table []uint64, idx int)
+// func p256SelectBase(point *[12]uint64, table string, idx int)
 TEXT ·p256SelectBase(SB),NOSPLIT,$0
-       MOVD    idx+48(FP), t0
-       MOVD    table+24(FP), t1
+       MOVD    idx+24(FP), t0
+       MOVD    table_base+8(FP), t1
        MOVD    point+0(FP), res_ptr
 
        EOR     x0, x0, x0
index 16a4b4f22457fc667e2ce900c02f4b6804d67f19..ad2c6c2c51f3d8ef60d30285419dec615b22fd70 100644 (file)
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Generated by gen_p256_table.go. DO NOT EDIT.
+
 //go:build amd64 || arm64
-// +build amd64 arm64
 
 package elliptic
 
-var p256Precomputed = &[43][32 * 8]uint64{
-       {
-               8784043285714375740, 8483257759279461889, 8789745728267363600, 1770019616739251654, 15992936863339206154, 10037038012062884956, 15197544864945402661, 9615747158586711429,
-               9583737883674400333, 12279877754802111101, 8296198976379850969, 17778859909846088251, 3401986641240187301, 1525831644595056632, 1849003687033449918, 8702493044913179195,
-               18423170064697770279, 12693387071620743675, 7398701556189346968, 2779682216903406718, 12703629940499916779, 6358598532389273114, 8683512038509439374, 15415938252666293255,
-               8408419572923862476, 5066733120953500019, 926242532005776114, 6301489109130024811, 3285079390283344806, 1685054835664548935, 7740622190510199342, 9561507292862134371,
-               13698695174800826869, 10442832251048252285, 10672604962207744524, 14485711676978308040, 16947216143812808464, 8342189264337602603, 3837253281927274344, 8331789856935110934,
-               4627808394696681034, 6174000022702321214, 15351247319787348909, 1371147458593240691, 10651965436787680331, 2998319090323362997, 17592419471314886417, 11874181791118522207,
-               524165018444839759, 3157588572894920951, 17599692088379947784, 1421537803477597699, 2902517390503550285, 7440776657136679901, 17263207614729765269, 16928425260420958311,
-               2878166099891431311, 5056053391262430293, 10345032411278802027, 13214556496570163981, 17698482058276194679, 2441850938900527637, 1314061001345252336, 6263402014353842038,
-               8487436533858443496, 12386798851261442113, 3224748875345095424, 16166568617729909099, 2213369110503306004, 6246347469485852131, 3129440554298978074, 605269941184323483,
-               3177531230451277512, 11022989490494865721, 8321856985295555401, 14727273563873821327, 876865438755954294, 14139765236890058248, 6880705719513638354, 8678887646434118325,
-               16896703203004244996, 11377226897030111200, 2302364246994590389, 4499255394192625779, 1906858144627445384, 2670515414718439880, 868537809054295101, 7535366755622172814,
-               339769604981749608, 12384581172556225075, 2596838235904096350, 5684069910326796630, 913125548148611907, 1661497269948077623, 2892028918424825190, 9220412792897768138,
-               14754959387565938441, 1023838193204581133, 13599978343236540433, 8323909593307920217, 3852032956982813055, 7526785533690696419, 8993798556223495105, 18140648187477079959,
-               11692087196810962506, 1328079167955601379, 1664008958165329504, 18063501818261063470, 2861243404839114859, 13702578580056324034, 16781565866279299035, 1524194541633674171,
-               8267721299596412251, 273633183929630283, 17164190306640434032, 16332882679719778825, 4663567915067622493, 15521151801790569253, 7273215397645141911, 2324445691280731636,
-               9262509587234749312, 6377906816499461739, 15415592259881792841, 6113140067088447267, 17505803833889144731, 3922849788840338823, 6180172597177093790, 7272741317181956640,
-               10883262735810583709, 17399134577381480315, 12750035195491397119, 13953097270363313998, 2485196748577282439, 393430759246706702, 3408702096065201083, 16993508724217005008,
-               6863012803048745338, 5403358912802668606, 12029756355518540153, 7447472859343023066, 7395681837001497117, 5416243410959797052, 2749045697176435642, 7813683613416962381,
-               18350218749545913064, 7509253999860752750, 13295789896366834092, 18326374111226872828, 3258048562491844971, 6342797029666289605, 9612474478300039361, 17807494771134060923,
-               9986610307523639857, 6419466267862117340, 324428332031706042, 16344106992423140174, 9434790811884847197, 11733262517030341550, 10475871084940451430, 6836751077061091536,
-               6209985515928007176, 8422208926220809341, 7866188125456775984, 17071696982741312252, 17482363193291892153, 1949968206030126177, 8823961512355572132, 13873010936602132387,
-               1136614876084383862, 14528605954969250458, 7641208364604111421, 18286716654189762724, 10711679476846124804, 7209187038097309348, 11378652158954714549, 8736575389915992180,
-               17651988839102959720, 4019365809979531118, 15024676458991206505, 12622721674297982786, 243375780477240745, 16572583194372185930, 5189991834753707889, 9498206494038386287,
-               7870185149723322393, 7858065912377481781, 7050328012468471455, 17977001023138181397, 11912539230960339911, 1290924823368819542, 8532615064753763585, 6439520053123840906,
-               11863354073576605599, 8052916203396229040, 16399182063316628399, 10837704607074036270, 5444229620349428264, 10866168931038804304, 1298875461760659950, 8904898233335519592,
-               7053953350607273992, 16629865408105641272, 1929728580699289339, 11046110151029488400, 9569890690274721816, 6501378768832742664, 1512621765961532661, 17084264658609527495,
-               300662505135603380, 15234062183651308307, 5319536121171934679, 11496182741145732970, 10520610739189276272, 4310163027157056344, 3285324287508696251, 3261468597637865009,
-               5427469457023618335, 8296698312021944466, 10882999905197052907, 16825284839961451415, 2106903142647479713, 12008841566652934760, 5361688498494289694, 12228623597691228792,
-               6799789383171367218, 17419525584795621504, 10685476378747845090, 16314000862057872712, 11014509959317588121, 10396318154903722147, 9986284919279346079, 4005974039875805723,
-               12980531573372269379, 11790791377897350561, 14264262096731994829, 14999393269362129980, 15405842559289002684, 13147503876582120266, 15449556979080143937, 5047767509783027570,
-               16354606995222167433, 15941889353688553446, 10301254747221876749, 10704428461746587572, 15702361407127630489, 3283718562982354984, 18081088275079496700, 17549094608770385733,
-               15620168851912893400, 13762314693487747007, 13577625382054330775, 4116976667540664996, 712200332640207605, 9098568002202933512, 8905476951567380032, 7075673514150314660,
-       },
-       {
-               15811459837282651008, 4038049993244767161, 9054218236388056577, 10807376403937048775, 11113869110590438959, 10336442539492421506, 9228056645601479672, 2983388754829658480,
-               7189376137127712298, 9147574701720272724, 3983921661449444789, 12479790317447783959, 13221020976679959405, 13001868979553711359, 17918176319017234744, 18030393246529651080,
-               13903368497828271814, 8050546449078305498, 6932373216915935575, 16010012759059004304, 15451708272653450375, 211711129247219149, 10435723642185827585, 17790507800712341232,
-               5218985848865375996, 5835476376320976237, 9096499658845542933, 8952489298840360492, 16605895184424459659, 505731104315931813, 17784248872812610986, 4151555707609374291,
-               2650786429127545939, 15186825834659456704, 6983758297535957561, 1268007525252235269, 11433489869282443481, 12352824209154665189, 14555720778982121964, 3578659908492218328,
-               4038120750249579469, 8304001815287976437, 251700810512667658, 17170873737273596918, 12809642145843734737, 5765073376623244019, 7923401246629348462, 5401634486288115286,
-               12830329023522940651, 1302336131164509751, 7011936976469244509, 8446680306499168806, 1386043952588989461, 9057741950701319559, 6719607413978812889, 17371065020414280890,
-               4963953120977916566, 6585250545846301109, 4490972754776862709, 10674499592300479120, 17494988318349821345, 1814042777264686189, 8938395423478059768, 9062966010283426056,
-               4683683785459765575, 8782133909400988812, 7201726172249963453, 16855412996123591560, 12016536526053703526, 6004686128951599125, 4323130180079993082, 7578596978943754924,
-               13272384473390546409, 15052793429857194942, 3597944793474963009, 5659515835454510338, 18013102402609680655, 15096936721974473248, 9096406212198787674, 948405832772983882,
-               7533214627823316056, 8009521942734148665, 15370181949218639901, 17395801240657257383, 13217990616373936619, 16323510521919428293, 10737557422966235859, 11113837024463125316,
-               3879469818714011415, 11493820457829716643, 10091807027724827301, 5032134849078736052, 18015749204009276046, 9667758283246223357, 4629693773460610802, 3807196436109718946,
-               3214144211600931504, 9454007581819416365, 15275469051811991033, 18196204074031746058, 14853793468372596948, 7707818604949749658, 3266782539036976530, 12810995382868348472,
-               17461133192060813135, 16870745208936545685, 5903437034120721004, 9683544852742219696, 7903581348090948266, 13461951083275541722, 2454715926022970060, 11781268272016425522,
-               3026443193966185195, 8027125782547146632, 17998666917527163386, 17214321347454260227, 10230244243647560419, 8728893474426972780, 16205038544687771303, 13771356055080873468,
-               5724217930909760221, 15420221591912350415, 9910465013739250802, 12511683773790779491, 2841532862707547306, 16614426471009646589, 407574220261191228, 17422057170120224031,
-               17151505459068312604, 2041124098660595410, 3221606782120899146, 1382742171848704850, 17222534050501711510, 3195635935311449393, 17295393886051199723, 6296241746423654238,
-               16510537668852450348, 15650518534057329304, 475704671950317376, 782416820485820540, 10970369699990900408, 16601298147057372792, 1599283701215392453, 8464446359559369186,
-               602848212987973622, 9275953159572178443, 15133444738457385545, 7264639569553811785, 14831517002293569763, 4277078717758211028, 12880437544322007232, 16339691585101354857,
-               3725101809714764432, 2995111022132376824, 9338883729618021504, 8824923738291347476, 3745497072215538317, 3576446898425965872, 2350077748663612773, 15793255155885543355,
-               8020669822852194733, 5865488997462325879, 13508617967776537887, 12934930135071898613, 11708185641249600577, 14265801329217514207, 10451671488560352734, 13251349632343744236,
-               10155392082337432799, 16725751190167983672, 17791070776350679280, 6653785531179322348, 10087876256887835780, 8422365820961469204, 13614411778251983480, 11687935452237305960,
-               6094298050768263419, 13949448434836272414, 14194554169090099223, 2625524360834828424, 2823844915913169919, 14077211807091283985, 15592587505996634401, 6562949920171518305,
-               12904339001067417585, 1972265247859388742, 8908590936681392405, 10320719400504224158, 8298368064038407143, 2105745729886511647, 16509751074757847095, 15156289751671616565,
-               13922601558154971179, 10541544592627074316, 9996345160543671471, 2956094548427827774, 3384122842786043431, 7003441038438960180, 11945730502649377204, 14797331669618433927,
-               533287349958250211, 13929395807878461602, 10036169742264959424, 18402398814900480008, 8793706913568807269, 4438954128288889267, 13996827050589647592, 6637236830429213437,
-               4308464751705576538, 12193581114161194913, 7322672375339219540, 329737085274484939, 15312435499764491079, 1530264129038944128, 1545025965426980152, 14559433923601957161,
-               885617946245226760, 17871561572095909264, 16413308527330544768, 2938750343525834336, 6332736376778563648, 16772687696658236231, 9760470695949399178, 17420556823805232882,
-               15040671962589188567, 5841393164221253498, 8923415548773111750, 17449640982747951473, 541686588805328549, 9579487672246868564, 12793813917570150236, 5744918442591934533,
-               12406806484060734474, 4655292039647906135, 5745141229449178147, 12923621608907306732, 1329768221522217568, 16293616079741201891, 16309603918079351385, 8282635243638078478,
-               10842935462043546322, 9397166878596340773, 5807145729199489911, 17083242467628861919, 11473470924584853882, 15220945465200609206, 10470712526179658906, 8129601297261864071,
-               4407657041250297528, 13832960959347315977, 15056546959967740939, 4350443362134191429, 8013419913016572733, 8888684099801298477, 15401479253620745715, 18279947201669400847,
-       },
-       {
-               7454214833719424418, 2128900810399984335, 8254953962723841408, 5341529923812819418, 11486532916552139238, 4528331821405917357, 5048485034448492541, 4189495710753944825,
-               9223539587116638677, 879142711399260546, 2878829560233905572, 13081522393987952773, 3067261963348061547, 16008150780594711643, 5466468631453287640, 16659147898971349582,
-               8047766502132608624, 8715815570878148809, 9093649079884580138, 3437267783531715968, 17562225708466062266, 3512667182749067601, 9223059995161026858, 1366690634827047376,
-               17929132376737482163, 5565926714491294456, 5252303555134107501, 8169975563698132305, 1829326230943509100, 13780918661853274468, 17736665596871232627, 4246797342334307384,
-               5113556452592134569, 7304867793218750141, 6016631926489320290, 16471860203547627727, 3444471410714850041, 16571738096215232488, 2003912224952639024, 4203884000388032492,
-               16858425223672505353, 3192567884201479579, 1688923188642613263, 4159042130811153987, 14900413503869744297, 7521485042788722327, 14038093805562042641, 14713051866364662650,
-               3738774192924465076, 14037618828827556145, 12882915396530927286, 10882862194263941815, 13115222579444494605, 18244214260845794346, 17217867059738274194, 2458870331386500577,
-               8768788172344064509, 2761897497254272960, 1400167175024837359, 2591319596670212133, 1499652044223484974, 6820326453941021707, 9701009499879906773, 6897435972338565418,
-               8314355711464256163, 8435944020779763783, 1814803522962187872, 1875253356755380905, 8214588085484192137, 18062045700553127821, 6649947905482043494, 3119726140944397531,
-               11881571666857493523, 6300786026612414187, 4928573492087752294, 18343550313462089203, 6770642120472453960, 11296815027803718740, 17312916793783562794, 13028515123652649961,
-               583508939637547757, 3195115082527873085, 8497784022800549923, 15135719419829981016, 1180291993378114150, 5447281494912347899, 4710517655176242215, 606503081693490000,
-               17732293765863716052, 853971165248416821, 2022886284923413326, 7522564752651732633, 1417954193520965954, 5046659528429172066, 11426939225844711305, 17687206690616539318,
-               6518552374736169438, 7940416740434530770, 15228615103587329007, 10662504584317997513, 18370800756791469891, 5564085264882124489, 51043856061444814, 11996026931884728651,
-               7009195269496826002, 18330778751427846129, 7903886241001925539, 8198930484643879628, 5453546027419466587, 10378692433982210944, 2242412603379120569, 14762161396393277464,
-               6146718865488327808, 8559779132928137805, 14001994895150170346, 9915701789711858841, 17119408219089522083, 4345363585985782988, 7559492126634131602, 17074565022279033371,
-               1081257522368061155, 16144982029632101790, 2280210790959566458, 5000326950136078873, 10441086845859171982, 5717080014740953823, 16816253740467637151, 5185838557034755093,
-               5835900675852976641, 14850646160621635240, 7784412869482958370, 2550282385659033114, 5102457400165153071, 16480738116286616710, 10726825595752219296, 3297564208881065856,
-               1801069609044825811, 12940364451588241698, 11725236374887225564, 4731241880784054295, 8874695411069669852, 10719836334830130110, 12983549127094653526, 3498884940869443564,
-               5044718241380586525, 9152928988998314956, 13274353997717834972, 5731942246653336838, 9453579625340936273, 6013700107129234092, 8535405089994224035, 12024982282827680252,
-               8296339816955798913, 17352704937535250450, 11768204246645005024, 263391795317009517, 6622964609352808474, 14563414288208376628, 17887389278697258458, 1552357122641071119,
-               13193447428787140357, 6701071088186218635, 17090465712567125397, 13844922841372559745, 4526664599449630663, 11321311100342816810, 2490532976442445147, 12506579957986846905,
-               15880983134955361922, 12396434033732989105, 16113831675045409693, 2288598422068078002, 2992425583703267972, 5056435264545116829, 12961420259857080621, 3600697676136115398,
-               12817090821406743193, 18109694174173693756, 17050997692981853333, 15796663317536421728, 15462568940214327094, 15151767385082666402, 17711108405932879054, 4030072071760424157,
-               15725012875727498089, 7622633481063722008, 2241559275264867670, 4018985714167034871, 6507661741395512701, 13435865773135624096, 9564553262368888543, 2283482276790194513,
-               2968718708369505078, 5001470555537559034, 985353756026354700, 3145435598301843880, 16410370922030326027, 13981261173663429189, 12565590835494971812, 222252377400865123,
-               3096505383227168071, 9129898186148780825, 13266305466206099845, 16135309871416543685, 17993464782237414425, 8124413037611692960, 8497190057115012501, 16568064870411415344,
-               7703394153241465824, 2740794419858297964, 4228931976096177316, 11207299659959318490, 3319492324515199082, 15611937984154016609, 3431896575019701337, 10686234123352138088,
-               9979039962499030832, 11759414020433216431, 15164411293105859178, 2834464820255498467, 10716371968480406389, 2722055037405581557, 9240657586762413776, 267811388229104916,
-               8385388272348876655, 16035999427286017211, 11255427708348651444, 18402964994101916340, 17964277099260928049, 16377129731672778885, 12034488763192562427, 15854195461740399790,
-               14134352329607480415, 2406779189916280288, 1148342927890148438, 15859735140823564382, 12055096645840568482, 16044304241162505738, 7466809979198503617, 4519925955244504432,
-               576546655711744206, 7729660311499709518, 16864252562359023573, 10537888397995064025, 11828992107618549830, 875843272290362538, 5328675038336932433, 3162100370899364658,
-               3897734650128449985, 3892478283047854402, 153850176068596076, 4448963435449755938, 9911011406822436713, 6379744721342779297, 360324666931028426, 8002086405015565067,
-       },
-       {
-               18068291112584812890, 10288580446655316879, 16866690514199445805, 15458664010538199871, 17175925202246173890, 12208778610361755998, 927739404697616036, 10330183209424493139,
-               17095781462759061506, 13984950766342782369, 7038608479806172868, 7073471193601880894, 9212126909381119712, 15865851343492198107, 3874039137971369196, 15366505242302572319,
-               3235058267792568155, 8030551941244615429, 12851363585510555514, 9786973022560471711, 4901414898060251968, 13240438628487941170, 4707852389766057435, 6503805666511566831,
-               12081034000518110752, 2773740877021737013, 6429475399936543899, 6804412599792308979, 16082860502313571182, 10013838454082912732, 7176778953927883654, 8065751639278576331,
-               2577328127707636877, 17299987330349518428, 15104751346159263209, 15422444943335124822, 7934601464470854115, 2803659700354182364, 186161376356596699, 10049927908892587253,
-               14226302346438044875, 11259466681405724608, 3945860952925292329, 3287876564263331089, 9461394118536996000, 12404803552046013762, 16569223065554335449, 15881973563254196893,
-               6665552777203645232, 5302850683863152336, 7778922028047389493, 14212904863357452615, 15966527672828304861, 3802704091320278344, 10517530714917238300, 3742971938824724276,
-               17741525051518363144, 1374267330336191942, 4677891169679898540, 9639823611685431337, 5482431056894095950, 6629146695374718376, 3884574854221819712, 13266790928096813258,
-               16028684877412556061, 13405436055762225966, 12268280467958284214, 17956874998292211440, 8610745336676661311, 2945210828327041653, 7889492068658434371, 8032335517518163423,
-               17096678157067198548, 11751872841896846778, 14951591239724148110, 14946797103632354342, 15001812923533485850, 1354666869219009884, 15934246013528228877, 17674533676709494379,
-               5120889077991995845, 1349360562851394781, 7965752316528770369, 16276575673105864366, 16613052983770261287, 11454051240568463780, 16146905806612132291, 15806571503343623359,
-               17505459029376928465, 14087658194607915364, 12240552390931686885, 1809009366037859941, 9468395484396723291, 9446052656478984520, 3720796795453397330, 18035355127900871187,
-               10937782812576841853, 2203021845094443505, 9622750764486021477, 5518948515641487288, 8021555402800950130, 8884074473434139094, 3925095588129480413, 6199533424090268508,
-               3824657730049729815, 4646911366274335188, 5283751816651713473, 16396970607630079440, 9102362834410101425, 3641728106404110497, 5923630184251416230, 13179374259571264822,
-               656781601862662976, 13284523818709348938, 14255949685810234815, 17662122984572331094, 14005272187244763785, 2769973460677437621, 9745740172208222044, 4399769039990314590,
-               18221138344920380175, 16761112742545021198, 14421639991115588619, 9419167563943683547, 6237248361283446238, 889754338720059891, 2289880386545166424, 4280148734121099084,
-               8456687949810928719, 6224977199672540221, 9826855484829367341, 10345583292656523462, 715642447678891171, 10791247680314230673, 4390153264475025171, 6710036254773432312,
-               11434352627810350015, 2720291857616706675, 15035363195148805272, 2358906741960696657, 9439888337759970778, 9654563570832962181, 6013570511081660799, 12742404245236356978,
-               16538557679183724426, 6137267799072203525, 13879005145532324670, 14569289845201353615, 13784903266526414562, 1051135786146476033, 9343275973150690259, 18338317230916899584,
-               5259165122317589354, 6306061166879114159, 2622163270351284906, 15212813592118086979, 11497359168652342849, 7085380391293263482, 11799059272489792659, 4912160901181298022,
-               10956239956289671191, 12649697329483184719, 17174497942073298839, 16454040570484021598, 1964314354536023134, 15533681501854792750, 11384243972598433754, 14387731385073008825,
-               1627256545355657442, 9010013556811110994, 14616120598404631231, 8391972858400276155, 244817907132802237, 1484397967210729699, 2663560284299448875, 4820353472962713985,
-               6567121006858416952, 17119959301239619281, 3965303761563489817, 10211688306206007722, 724618943950031080, 16749575186941231354, 9181397347361086360, 470616631211702666,
-               10512473611770099290, 11735037909076331019, 2922606398008539984, 2599799834378751770, 10226702495047936424, 6109026252412854338, 15572556822827169237, 11993701786788749663,
-               12951512375864063487, 9270845327881823041, 13198171264747338719, 9240466821667660686, 14918848310897324032, 10111918274408213257, 9869937817792431868, 11316967879062014936,
-               5691364106926740802, 2782311978438620206, 13067832493996441150, 12682941211395745221, 10515041347274706648, 9910726429809603026, 10540072260993990483, 15078586909891471233,
-               10892036011159420575, 9833543566604313963, 15176473361412960115, 14504845496732895720, 15845034940445278100, 5364672156984348678, 308167090528488415, 12390239901799634313,
-               5106897453764491321, 10540479232768400094, 3938246597140945859, 13156157265138481529, 4932443191001849637, 11374218582626530502, 2907557293167002437, 6807344711257391317,
-               5413712686694380670, 13147753106081951274, 2960292187746417883, 13977097845105551070, 17642067093469099040, 7699556298723812469, 11597002672863564976, 12392265705126521509,
-               4607947077536257852, 17763906282816835996, 11288463953418287893, 18299911648497821660, 3194698850612319839, 13371221457376435780, 10047718724723936081, 4488868185988157408,
-               13742985513958274859, 14201726926009534105, 2183997556320958457, 2564950343266657518, 8846625471673389624, 10147673280504740463, 186524308060896613, 16409126738088317791,
-               3993197157612782947, 14810882170056329119, 3476738916713041107, 1512933700383846542, 17820889751141311776, 9132720567660500233, 17598924894608972696, 9704537908665702455,
-       },
-       {
-               15695265447782578013, 15506558718447241194, 12341861439298989232, 18400958156300100845, 13704811286967591150, 5802260047239067846, 3266013253411255445, 9892957742319181954,
-               6053458788987550519, 3243549259991905443, 17990025476026266205, 3918149716414968130, 562225565996136148, 12175287017902713154, 16317970834262634990, 5431198806775607012,
-               15123186170178367264, 3054913246068400920, 8130663466272395280, 2852812622149318730, 6747630551931917110, 18302049774259156971, 3663865061939346221, 12340091610704678811,
-               17453312277789785069, 1148609799196055657, 5931758962926317381, 5297597381576544508, 9136842287749269744, 3007653173299649609, 12364677607049679091, 3656932227466449489,
-               17732801126130995365, 16093023291975796560, 17028512234142609413, 6293028118993952199, 4019599708379609715, 3557632583507755601, 16737140015288442165, 7041678499288317736,
-               5187842645752673199, 14914432544387315508, 4944360914161982641, 4177329533692612281, 18423887817846407126, 11935898134550505219, 9191754399457615042, 962223885189306707,
-               5467152559317256227, 13407023128339380091, 656806207084558176, 10823228592509573890, 282802378108427873, 13003319652664166176, 11501612671901244594, 8595770155487539951,
-               1805255869285898834, 11676967700876044626, 3486630203654875772, 8366336693945605431, 17874084888474647879, 8803709150655606891, 680993178667234696, 1603785777136148315,
-               3637712241808318043, 1673622542455477465, 14468899013751477571, 6607241816357171779, 2332200248940843815, 14077155355848738174, 17298155509321457563, 13624623885136011130,
-               12550073596584561722, 13898852145577133829, 31360866049197404, 12629522544897401454, 4563446134761510332, 7272813487383198495, 16767195814334178362, 13600498026689482359,
-               5170414136067325373, 10875290278133558518, 7331268231382198947, 4082234313337835514, 11725295114019619895, 6488017511603508543, 11399466652931338200, 2898113599278666684,
-               7553418756944942759, 2324485560009697358, 16004009784734101843, 8345371056076551939, 7377284629098981027, 11049718262343754276, 8021605820736410979, 8175349759714152494,
-               805625092558946929, 11996029844853502332, 1725029464967101849, 8189609560660709539, 10396089572662865065, 1756007811373736605, 7645529329516777410, 2608132938055260111,
-               17014595621244604813, 1574499958190108567, 8684546755761322906, 9997538531915911005, 5652402150243592363, 6315865356369667235, 8687115108443972047, 12369176255146729475,
-               5117004045853299762, 2238407612548002914, 12392667457861900490, 10614312910576266709, 6446577503758597410, 3767883614425995197, 17954966454260719539, 5233322901463099,
-               9194523390605857831, 2335161171394626054, 12290490336543843159, 12464172604156286188, 15842196578033029974, 9081285134201585379, 6123406461662038242, 5504260508195082396,
-               5345718195770885739, 10397124463462860788, 13439280718993427040, 15556816356929214653, 17286785976489019906, 13891416634083443852, 16346644312573564447, 917629419222512011,
-               7892626957952656865, 11229871638807701267, 5249460237065799805, 9529842808650392581, 11803106868201977918, 4600784567377577444, 7178870186583927975, 13829108773971861655,
-               1289703927368007546, 16175369390684210381, 2195306032582966573, 11284704298115036296, 4385727852306374408, 6915138269030006111, 13440775052829788601, 7742359656861485339,
-               1418252737937945274, 10664598666472920539, 5146625453081549320, 7716408631061669307, 15481216546649435253, 9087869057854823101, 8438781502742166926, 16066665509570633845,
-               13091912700111633391, 15443255616678375884, 11338466119311799740, 9641919445273031117, 12359044485240987114, 7665168466660756789, 13845183791692700257, 10700410793152785934,
-               8528578803314347534, 18126789418189181716, 6819229450418907940, 10542951903574211724, 10335954505229790439, 773396809431100386, 763679854573261611, 7782804492252573047,
-               14102889564247144327, 15479515297699126743, 6400257822506917934, 12400211936189844586, 8190162441518233318, 16489757979266243333, 11074854544980782334, 5650848136444824725,
-               49299995316533601, 1658812626798186796, 14321322055030354, 1062750633396640947, 11458188738562323084, 10319462683954522885, 15398455357851813321, 9473384090828584828,
-               17723857482947114516, 17563952877363564604, 3160294749187111891, 15485369139883303866, 7487527166185553604, 9661144290316674030, 16387431126208996705, 7499766964252214921,
-               18331281993562501191, 16034836629143884193, 11149238385567891503, 1413880911197321245, 513884082842080653, 462183409527465946, 404977499728878854, 1459875951423441439,
-               17249202826373649180, 11151860661862313351, 13606113651347187963, 13653298062695357606, 12346841931589648448, 10659825520992339734, 17857177794617595021, 12846976930859175746,
-               7421386827645898229, 4567141110780940726, 9022716764262477732, 7287282267953917487, 12950322172330872807, 2675202024861592519, 18339036521791481203, 7003909904344391740,
-               13539440097944399044, 7108271818419613260, 13229113021954558930, 14920952138366964142, 11082363944167072746, 16156446445495173622, 15515349862819133984, 12359827931233605745,
-               17013104138257181849, 6982996767213561282, 16259302607976830987, 1579942890487532721, 8635464047344487404, 10435012080572068738, 2976844365866972753, 9471858478345924179,
-               2347775782107812070, 311367032040459687, 10852128873404113998, 1338612296059509077, 1599132038614432432, 11533828746166635650, 14264087792956755961, 13004615331499537807,
-               9599159247384506427, 13011559959971256245, 6331802547989957841, 2642320882309956905, 9140255367820630480, 6883541786494880896, 9560822438260750771, 9273862677291701694,
-       },
-       {
-               6185067974942684922, 6452325785873503452, 15247257292915812252, 3689324664200339196, 3264129576054154137, 14977721630214750038, 10720913377937894256, 15914487080763816378,
-               5498621600689515064, 11498885804037952971, 12697073118321478539, 13999008478737234463, 4324885099420360642, 14021182496192299466, 10763088992583373843, 12898585157666243299,
-               11622402383521841588, 18271726976204770291, 4805501248621435402, 13483122453682180759, 9288143526654965614, 4688427612851085031, 3280806057528512375, 2249349779106893174,
-               2317249352525369754, 15030797481081533168, 12237590576308284360, 15660076992611440873, 11341015819700735887, 8280257602754365719, 9212501234696283343, 9673375202141178099,
-               1576552382781604867, 14644873134348781157, 9860879950368557094, 12941927431704225849, 11959666739052502184, 16171152369226594315, 18364294470656574060, 15172859394935215584,
-               7521577570681641021, 410124023045579310, 13806534589183327176, 2731801491329207875, 9959087943014269549, 16205635445474657221, 12069145915768935630, 14906463509471682144,
-               13803661539609326912, 3233094883493439444, 13409742688319755923, 4298169788674760921, 12847636671560067434, 6702365884489797170, 5650404576647289813, 7380374625644226212,
-               9762534010701623728, 15349113802811029024, 8305297169667044246, 18013018210154476198, 18414050009163335761, 2190126859433916996, 5444481274452218807, 13415988647365667724,
-               12538763466834894269, 1385338113050483955, 17489001033590767373, 12734464941837886525, 5762578105750980174, 1466528690684075875, 4231060025049573530, 11218444849081704286,
-               13520439252664960951, 3770430920651384098, 18274623217805904547, 11545267616883260257, 4084783424859113779, 13863968977657663867, 10237835480648574698, 7395611844854084274,
-               12891185742908997266, 2889148203703402614, 663579373261619221, 7616112456816883701, 9002890885722034437, 10753730807791931375, 3553894671829778441, 4368240432504457389,
-               11641532224340210206, 71261001011952801, 2321745415903209397, 6595984444855093239, 10341299657770272718, 11529878689049370930, 14381510695605158203, 6869272773579747365,
-               18407769999912340511, 13801873415230385184, 8080153703167941484, 14143463895182697871, 5248006623352376562, 9271982788122934275, 11225161179021692620, 5076519449784098178,
-               2388868518767189674, 381125256886459269, 11316805024982236485, 11671355336111917711, 3564177948445768908, 5245093046097324328, 16144139891410041039, 1201010948447708436,
-               16591032462856670656, 533850935988668408, 2263232738784171066, 5572124915367282948, 12583782854491678471, 15015562207264407653, 1167486851113549964, 2987176661273439670,
-               1073778278665127828, 301289653767944933, 11482324780950168317, 10626716202328004967, 7258024014655363102, 12597648090458567878, 2617914106162603499, 12324652644266476584,
-               3803745429517922765, 1699256829990081513, 2179986933466617785, 4330084096014112280, 10403896221616386733, 11682369673591069651, 3879392495596713886, 17249085256521020624,
-               13938687445393525296, 13822790166673492712, 13216892716897321740, 2165870280409061482, 9147830602451471293, 16339144108911449834, 17837507766320968023, 15340710005345158245,
-               4485838034764604283, 8426970493386126530, 7709201418726935942, 13468796449943783583, 16441091014185628843, 2374269830239737237, 13423059086148485716, 17132218391020520330,
-               13957732574177025801, 1100344278733481546, 12156946932617203965, 2007756425747006287, 16454508610548016441, 18058668363064769203, 15619001054652658323, 1201476243910931863,
-               1292412381963708933, 10908631677673353277, 15138649576688192753, 10741579086621436813, 16534963566169304684, 10228646729525192055, 4256608246548223655, 16176814322718522963,
-               3012125536603284881, 5466178753014623970, 16598422155702380175, 9902071731736699653, 13861556771123036741, 9534711573278556274, 9805898455743897538, 14683694395093520838,
-               9125214754744730198, 143353181770418225, 8976042597473555858, 13405481215779362056, 2863125481657826330, 12333764090388731260, 15250359513836914002, 5086706595778559056,
-               16341334571424533804, 4657494880554316004, 18092783076286521475, 19832895869027143, 8667365497283429486, 11501953273367138162, 5832487631687776985, 664754160781757174,
-               13604774408440609080, 12660956565879820101, 4535452877362385626, 8063311919592303330, 4591511734775484245, 5164119991271568303, 5282209033000495913, 15181017218549722334,
-               5070228782679699429, 277881850788922387, 17424210585510719837, 13586569401109299583, 16661809787463692974, 11543434536078774133, 2062889565117549061, 14261113517104795690,
-               17683343658262519228, 13727986689138309987, 9352982220536939533, 7578301410191413286, 7970586266869249410, 14357824150096386968, 4381700479561442130, 13217807763329274501,
-               13524719886605363170, 11553593166914861649, 12034020205580665813, 985175984881624722, 11040631342644137311, 12107496606245418129, 7328748654066365904, 14741972847454326011,
-               9790251609380109406, 2449588380962781369, 4694893010228180943, 5172145489692928848, 5411277023198532852, 12752098113265127406, 4559500999103209672, 14921033543082064351,
-               2248082728820243864, 8720404853152831367, 12431505213690884811, 14883031570121462817, 2278273022936639560, 14988529405400451352, 16732922988142595529, 1071232319627396164,
-               8793441611217807824, 13198147137434605751, 8167936709747999601, 7685928882032231744, 8779182451658438210, 8059106577297479923, 18394590909567718507, 15508315617300242773,
-               12828567388121500364, 2264959796189127526, 6222205589523394088, 8827682270015065013, 2619170858745203321, 14835030117099398518, 5960028394532808010, 2233397097850889639,
-       },
-       {
-               16319476863352440541, 10283930715856640343, 17675054544532098447, 11261132162985242084, 13712716897981761400, 2681907143459288706, 6930256922080133347, 1445069157579547822,
-               16928574868467385886, 166417019993787654, 5882811520342817815, 14106304179344008065, 3747123724781081800, 197109533566874475, 14303280595714789450, 15457633026018307066,
-               10773597511592584859, 12552868588431074640, 13500771767160426835, 8002499270056378440, 13792839099998553174, 12949371255843262119, 1713974340992291550, 16150173130483658061,
-               14745984256428057001, 9333707338036985191, 15365925315303462, 11789129028059619744, 7873100217437235208, 5289763977161829145, 17731215200358323788, 8876377479309635703,
-               265950821974454804, 5047467530470542278, 17523044368516619801, 10054436503372765176, 10321185867287373431, 1212061937729015591, 15311258419138633926, 11236518538207084768,
-               10904693956407098222, 9013418755007070130, 15510005599846320670, 995378633446250700, 12234095025518917836, 6689106237771514188, 2809193993744369126, 548124799387888260,
-               267350765778774337, 2853877351938464055, 3677119082593358544, 7685335121077514739, 6491980094762370981, 1384870316654548002, 10568872345228996498, 241629538659623878,
-               5839400175629113441, 5238299193248381245, 16787876416022887315, 6051613843621920008, 9219569873668974552, 5916753090530931032, 13390630214643423749, 3265335490455191268,
-               1507475744849985303, 2597075068965622770, 14968669113917266926, 597606442423659891, 44293923912414886, 3832651144752540816, 17438860065613195810, 782112340603343331,
-               9050896199196733903, 6427608033444590004, 13787696679536621857, 9682087046920409188, 4519093754155995429, 13564098392055667371, 10512507082236058799, 5289934424008191746,
-               3477191607403300916, 18283244229745029067, 8462159792484018099, 3056576498976014760, 7259283167233712785, 12530251965039903998, 10232104933720625111, 14190745998092156987,
-               15759362035410895911, 16075598437961371531, 4651513528876405575, 7694151626503869614, 14468862724637972284, 1838601521755586245, 4168957446435305706, 8694905613027663664,
-               14825552838983151434, 8639609968952840931, 15547914584352392016, 2313507499500708287, 6902543375698033684, 9987468886016348918, 9068175779860656258, 6899641689193116297,
-               7449110402827616954, 5689206471789540768, 12722069021950813669, 16017131401246233663, 2240977975275954837, 4794705713606614946, 5734937900461809607, 118285984764445639,
-               13917685647531721740, 2432096911145792817, 17733637484624159521, 3848601825403209903, 8192433211051054683, 17388066421914150767, 14336306308847565282, 7501625553608785022,
-               9844707592410952215, 8167497709587672711, 18115463401502884199, 8471563375691441535, 17525405040226359165, 2460181803833371342, 3375780580907171205, 3024376384135966552,
-               15446204978718816914, 10131769697256428720, 10937168660849553757, 12174257400309926241, 4774490771219074715, 13764876998736771340, 14299051476546774038, 11409551629093945893,
-               5471366060803425265, 5927845172343647238, 13321967429805195545, 1981489848211999240, 3657997933879283852, 1341488083977381854, 11001000434984172675, 12666440712128450303,
-               2127920575549495889, 8861781778185702064, 10501256952986753134, 8967441017586595593, 12224364761159418844, 11856305587178745520, 8176487286367052930, 4988165299911239066,
-               12279712962388998309, 7552494563001503282, 7388800608466198128, 15704167671257743517, 17781278773093632973, 6688613358271814698, 12261263098366698895, 2585757657252460656,
-               17064077609211627595, 14437064866605257652, 14386408901468621215, 14935685266532365200, 16350265985491822570, 5195856143474093260, 4623415440658404410, 2936315929072503688,
-               18399447684263070219, 11294713679768342649, 1600242588657342501, 2841752419388937826, 15111313732750279467, 8179471361906256467, 10611923788752807866, 10823997080784081293,
-               15607034385960553579, 6934034624930683639, 13318618594774430459, 7552865293216027192, 13692640408995992185, 11143313220936824014, 16721999332340829387, 6993089466645938014,
-               1749509641415861857, 8597876492914031095, 17942224190138398306, 1760222146515426983, 1030117883582412628, 6655464189981098460, 14222900139576809037, 13041171493967200019,
-               12415333505074758067, 16988669193263876033, 10482573641416551070, 368049292090348794, 16109255925523895167, 4949934055388640387, 12038479532506656790, 10829864449693781036,
-               8355401100656399994, 16963696462538033761, 10131652431024537917, 4166156454906166144, 12888240412190236596, 8396312458335953166, 445297814986468978, 10512295830234020744,
-               14405236772348157690, 6950094157338825845, 13379457125020057613, 11396720859761560260, 14063367153572826959, 4476298515903789197, 12708437873915498860, 8163633089770520638,
-               6432708226771955694, 7524978005081948959, 6442046223716866789, 4082077252385606982, 13626979819841658005, 4264573835620574342, 14788317690584235128, 4710414518172449402,
-               9592766374657389840, 3206081438027351157, 16013702689312533501, 15788528722601567812, 18314198451066123850, 13236688692074994659, 3229858297074852748, 2968037605940641303,
-               148470760067500612, 10319937899190593880, 7185467485673911733, 13041030391924988650, 17119842693824847662, 10989053172849710331, 16048294708726813099, 6612710923681979611,
-               17408606709137505005, 4263600430695220256, 8941719936291239640, 6115030817534063286, 838024703679813150, 9772071103323550178, 14394690179107421621, 8621372196164819917,
-               18138724984190926809, 4154767406604950048, 5209478936276366634, 15469512148904762872, 3613429290324777670, 12631812917445459751, 10280179062385049041, 19656860716268566,
-       },
-       {
-               12030193727051241373, 13981191132445467472, 18205169646206905593, 12162181194046583886, 10929925499200074058, 15291772758590352491, 8452344520852919320, 8199821440451878776,
-               9876482463501409337, 17331045017548147052, 17542726936580732548, 8299195336372136083, 12891767721269002608, 14062358772374813347, 4165127680073507756, 16350672737379495431,
-               7595271959296927018, 15286771623821390629, 980612661413312852, 5738158184597378995, 6972117550390447038, 6246497134979772260, 2935831443692029059, 12837371529160496660,
-               10228366644420455452, 12084265406352277347, 10265869676493821892, 3560143954870272139, 14368775225608592689, 13173522067191372913, 3592475039513249949, 11243554718624931135,
-               15959892157814064696, 1882528744932347842, 3354709518288681174, 14147909176429982637, 12969888425264095514, 12509610747258602648, 10437226619684632037, 7605683691113295811,
-               5697384515599291245, 14896081221061315030, 4329502046122948975, 16301954510440819492, 5191621061031169335, 12944691824816066027, 8080452646904372453, 793075614214301908,
-               2662373477940179766, 8950125653339535995, 15717799081080898304, 7088593450282143511, 11723351531494404904, 38673945663198753, 5289769381065195334, 1742280067441486108,
-               6543255501112359319, 6063422531520498671, 17228726254778244409, 7570754775709645369, 18222396492501523182, 14903937974816691813, 1216646642383641441, 7602781158453005929,
-               3007861146695764376, 8267227185027440857, 3177625538211272080, 3144345182124760000, 9215753228267875296, 1342253891473772992, 8185239004636232247, 14951188427081280984,
-               10569785547248986188, 3109435167722572449, 13661123218513357442, 4646373703143839998, 9712828426076586682, 11389514152975496268, 9796826623781200498, 234067627740956181,
-               2188380882990542468, 9914251329861595119, 13616219875099353594, 16135919125023820218, 10732193797566088293, 7172996278550642736, 8531638916719074975, 14749121691457005349,
-               14568782576170814716, 17582848432122737506, 1079387064102681806, 17278567874821675408, 3094302191119669899, 3730448048895347901, 3508894590334961422, 14091660942919228106,
-               8414395549498864629, 370884714015114625, 9859130251236103342, 17120282094084970181, 15213286581037020029, 2737545283554254673, 12422648607044275574, 10601123825482591606,
-               7332173975514924017, 6689389428877729175, 15162654177270425320, 17333672210015736765, 10717615330136876266, 15245080807947386155, 9830331968044142933, 16156512094344185621,
-               9151817936103586393, 3495709317444898385, 10881665308947458223, 7087755261386867019, 18372828768905212167, 12873774245490293443, 12750361906770763255, 17688389897350887716,
-               13329033749048978810, 4765695903433858377, 4452680451529163940, 5638854187414651620, 7897503022043776206, 17187635538005569019, 17766753195497526986, 13201529234556380285,
-               3638940913491383692, 16533217388164981609, 4668956005988168087, 14053696531704823982, 12029006663244142834, 12043309283447175601, 7840964186868745782, 5691369519440953069,
-               8500871974974230561, 6371833132372813539, 4002756625312698938, 7281624589760047276, 8813214993155334737, 7738842112797657395, 12616064385239668311, 11875709199633531753,
-               13080663957403320059, 7305658810888170771, 12002632153917673214, 14713338572031413494, 11629178662016777533, 11669230410217642326, 6563025945717173284, 15889630204666511658,
-               8934119620399766972, 4226481091885914732, 16000709195004445297, 14687868180928846933, 16269913392757896907, 18294005838441325342, 17625669613551023126, 10864307042201644469,
-               1539179629859629979, 3357767843775461146, 2101360073251832751, 17234081431682678130, 10847284171622250162, 2314478515498414576, 17530153382031867644, 16210890762511619844,
-               16932765725476234252, 17974885539458965712, 40892050255466590, 13934027942808790590, 6621543269907021363, 11796852321134174354, 16673775773384613137, 3370296079966463186,
-               16962514259432373133, 4639769064050336100, 16965148588326727680, 2922022742538957808, 16752379982369550296, 12896050752492664079, 2708685629936199207, 17894058559833424187,
-               14722530431277419104, 12333728409662476827, 4162946257347548625, 7052045338975163666, 16435875989376103923, 527141841571514699, 8480360258792897962, 4322786951393806781,
-               17366230017999184054, 3121469063237497918, 16903979375392804254, 8204447732627807538, 10469007462907301028, 1938243801077680483, 10156223751968769092, 14290141776757271674,
-               2576841693080637380, 17952976066680364360, 4927209893946473523, 12406446420948698970, 18104668447274679200, 11321546081935789882, 11763004760954725540, 7488613143173641394,
-               7566233859107262691, 14065899052643539237, 17156645465457086529, 11936850757897686493, 17529993825395532749, 17145245039398670236, 17597009579379584432, 3472628483897995694,
-               14380803034817149259, 11042134597430846555, 9992762805140200547, 9895143575678511242, 3228768306004664915, 16153114680219541243, 12036181641761325912, 491369524302296324,
-               6378343037075212083, 4634622317247307316, 3415247351446435530, 5939760313513758783, 9540802244218497398, 2134082884335789009, 15623633842188443713, 6824600547587227473,
-               2021901489047050575, 4365578779519871721, 8603845379677060773, 8929020214929242215, 13010370953605249273, 8071113541575997356, 10681914788594101574, 13369522272664029829,
-               4241327321249984516, 12810477007632864750, 16880581634097860698, 3630333431846970294, 3439918565119627078, 6613942714960548236, 8647431674406387604, 13352599355545805355,
-               12320933424684960076, 8906954611339502145, 16931708732547376267, 6446897311644431583, 13749563256713530203, 11522599770043814384, 14455556215959342791, 9022955938835504923,
-       },
-       {
-               14734199666349771791, 4159865781008764547, 4413963548436270853, 4489431649937855880, 2824856157476907519, 5111945927271461159, 9825486821405155220, 7657332565522279292,
-               8798422177670065832, 1250388939918922012, 5145324733132743026, 3716299737175574168, 14387202892738514375, 10255681359895407489, 8563822744122397080, 18430417713920116013,
-               7857399215288147901, 2593284350589299949, 10086687882410147351, 14407837835956327624, 4469878646287387405, 6845712208092605310, 3019047164798827279, 2760591274816994522,
-               10930605176025081830, 5850835312463207607, 9603163404664606781, 15623771803942139684, 4096748595672894276, 13060617166821837740, 11222939712741281346, 18445178894593253710,
-               7976335583419810431, 16568954524837045521, 5581116346602990350, 18369129318179031997, 1930478946186473631, 14255806344323769850, 5302512325798050097, 10008570767203424472,
-               929118050943456183, 445163760697913504, 7208246135487165437, 13565354217377841149, 3835063466770003968, 8214155842021576753, 2078717035803259674, 12502657820500987763,
-               17741004372977419914, 16320851348541958575, 11853008901690968430, 9954777341381304447, 14274892887030297417, 10721339848307167540, 8731332510371325649, 13676383433520290197,
-               6251805914672095769, 1063060143452094078, 16647397170554915088, 15454955736319919321, 11509235104607349098, 8441647766544589978, 956121464218389431, 10752793912033728149,
-               14879603883666664508, 11158422912437249402, 8667988090392051507, 12702057193823135575, 13234479167199208223, 13752955092077643608, 1117550756888145931, 1184967682872965330,
-               7004802666964716824, 395433501626287206, 16674151908279399004, 2279551165611331131, 18032555740803644790, 3573953642384243989, 9892480504006025100, 2397759375236735831,
-               15032723931727013905, 4176673226777913017, 7270920367565154969, 8867675920919464620, 8174119413251699506, 15030539680120439131, 12325981936900309518, 2932283844656871802,
-               3227890727136855788, 10772277744280338071, 10065219931092397730, 17233706446636791341, 1372997838851103811, 14430098741859995846, 3290287064497023581, 13054133915521430696,
-               3404625123065318735, 11884832674715736469, 16513753127836546671, 2355202492840722899, 2182039060332057784, 17942518439766613327, 16731345075928062112, 5501869092504492134,
-               15704211025163561149, 14596679078416770266, 10262177146233936833, 12443005669252298316, 1541294166390346144, 2952804996209068760, 15358481016273272880, 1321729586231860999,
-               6862865331233391228, 15106279167311639122, 3283008666555627541, 13405610967904725343, 9845239597399801983, 10764942720093673542, 6506992344666983370, 2483131164245259278,
-               9508384588323002196, 4786531415304518048, 2690306308552249535, 12208815515689370850, 5145548243685871201, 1536915039528215765, 709289946127949333, 7152734178531880864,
-               1555309551759198315, 13156609441579560529, 3264147002083956017, 13629162110016732793, 10295903344220946201, 13835148808782379287, 15646840234722388037, 5850505683234532491,
-               13348528763144385986, 8174978337870000956, 261860806345683810, 4561309263594732686, 973813267913726588, 5812176512716041479, 14361848397565071235, 9009461390894364897,
-               4179825720483458009, 3146850391122074949, 16612045757277946305, 5253713786583408340, 5426943015912173764, 17275032103121420023, 8467860410750483621, 18150546576917688519,
-               12762630566060098764, 9762645120146998728, 3635705124656800121, 3295681695622364165, 1764654124266477879, 16610065552429288987, 12182970194869512424, 1144643512390613083,
-               10286763540130161498, 3400614528650953395, 16801086752981339314, 5746334081386875705, 4489937467701177898, 9249554406360134002, 8258038249111147700, 1922443676251769427,
-               5981893063992017591, 11780456280008557800, 6865399120670384939, 6192294124015342683, 12388377965276278882, 754882660516751393, 13476094069874573591, 1000347292494612314,
-               12753947115797128456, 1864834899756446490, 12873792436322150068, 15420857687427067065, 6214698061215951246, 11174167031334850459, 16378107708672199269, 13073812080094584194,
-               3531275996684891316, 11764951512033875164, 12239314899306115751, 12701224435273087197, 152051042384837402, 47099568832954431, 766394328496626388, 666084094458729910,
-               145223485883456390, 2445564470200462527, 6482144922631612251, 2316071592874761856, 16548688346252111305, 342430477320199814, 17819268336019413198, 9112976726726029531,
-               8272548370610798443, 13910434751574602849, 4252192981011400377, 9590519351704710983, 4172183866405471444, 5567646223402949380, 6059725713353637560, 7169982539312028092,
-               8422701298619809502, 5749403137850675219, 16696307763582818287, 7683947097864552851, 8685161999810728314, 15931494353777534155, 21629333141204286, 14374464903502564030,
-               2354260355218724624, 2822702976206523812, 15817484232297668127, 8389777239766813455, 7962301702220496539, 8489354871723216960, 6637394823950686331, 5853452396705295777,
-               5949957329602421631, 18059540496274524007, 301304345046470155, 15775279105880040289, 15979581939040500554, 7142046514802237176, 9965619645220287167, 14369754349691428035,
-               8777708254369249245, 17882304730732025188, 3127583543205765491, 17274466425160820249, 12870181470212293464, 5881181695848312122, 15338161852429951632, 7245877162563127935,
-               2634466441339054819, 13057158409330115380, 7410310056430957860, 16362149248469660371, 1435827663585128427, 8005375008235415486, 10865470829924734253, 3177600727860863968,
-               9627905753364576437, 12776456422166281355, 2851899644189834214, 16998174196920379994, 9001602524188761177, 8960294999163663712, 6580949973363012183, 7568306074815116797,
-       },
-       {
-               13345381996769253014, 6278048669175242345, 15990349685835870151, 16358261962292186792, 8505261070637963021, 9396725065098564446, 15331953351049782155, 16194796339208321205,
-               7076257175157660597, 13221730879315432464, 4499548735964119085, 7559253754663705944, 10196808438730350168, 2391718471837563931, 914409564589897387, 6649744842278078706,
-               5502356275170104522, 12750322860129485966, 9581277511584938955, 3872282844937972630, 13668854758739140874, 15020438121087800965, 4581631138384430657, 13296613956093963588,
-               14380343880230315251, 6834909096379668102, 15975839936772635678, 7738230945027714388, 7971648870467745046, 8320128435052726628, 10820026056424631461, 7058118462476293754,
-               7264036154081699231, 1304060579978677195, 18166928140052040308, 12593450560996175288, 16027666629366472835, 3677101504316839585, 1477956412235870359, 11566116495906585190,
-               5990066097615398579, 2092999434824845091, 774626818169813708, 12815491981614523669, 6993666706115136402, 17707947501239782961, 4907798919001453899, 8644498548438963907,
-               10893744790193607860, 5425031394266373727, 7829758685118664025, 11448863214220512751, 12538690882574195219, 5021176303769859871, 5820297470465439264, 5119144562842414323,
-               11165438517321289842, 8661037418831619311, 4401480924846865713, 9355650368902126256, 14352422544185763829, 12268031594529744663, 17607497268577344783, 12698954426769962214,
-               5383780168621648368, 3613813760948797485, 5757643543708300439, 11434310585555684688, 2345981080034027974, 17817292757133028083, 18327982597027759229, 3812144950722314021,
-               8792386854586041066, 18039588893139878329, 5501406599000558473, 17117814302557684702, 7341401626090786647, 13233670006052290433, 2192568639640447778, 8946253989965365943,
-               16557600339807647183, 3024845786116641335, 415867109882960964, 5024769423994345740, 6707880221250244075, 1889203596997453159, 2063004021323938442, 15149146696320496954,
-               5091534986326281709, 8005812102849517353, 17366496686564185717, 3658878980438307796, 8455810244524637026, 7649393961871195909, 8629386422022530934, 507133797409068858,
-               8757568869745664865, 18237318628906764926, 3340648953867756474, 561136277959994100, 7271097445297070958, 2011054670254573698, 5452809131990689118, 13469888024447314143,
-               609640447772904263, 18299734743899574512, 9082773418653747144, 17312950936823165983, 8565594704932296493, 366163155689429929, 12596423288683198842, 6787120926470876217,
-               18404298100226778075, 8425329164435445437, 7431919288426595458, 10680902470574406179, 7944931189168061880, 9822761000408762356, 794258562727155839, 14627123549563592012,
-               10098955144981013765, 4095621933458866623, 313357785962326778, 14880249056209398407, 10605627454111004262, 7841561005378789988, 5015399193497762029, 5818383539901203899,
-               486788682374900660, 17535646661984222270, 10786441143551223569, 9744277172896797168, 3600223448942144865, 8847805713765285452, 15255336563751266306, 14792236445425212896,
-               1569380763811592357, 16850350231819425451, 14974316825768144065, 2974893813338477794, 16726324408135381195, 15000665607479486464, 886632233152598796, 3783793991897659851,
-               17267037371866619240, 16498595171305365582, 6453906744948258368, 17267405673163971478, 1676214913570622682, 5051819157163581842, 4315279707026326708, 15525840981760267164,
-               829322392873083372, 3459913121476606612, 4547714508342797986, 5801286056105229312, 11591136160675314269, 17965845487226778560, 7022309609363885527, 5990586084398664157,
-               17415594387520595717, 1453256163777911406, 8242859112004661961, 17561205531134219898, 4881570838375824387, 8392772608437744175, 8797957464506597080, 3142154188155936579,
-               6248409301753564092, 912147011448492506, 10413108318416902948, 3349445377400918439, 15887909530347096066, 5138859116738406557, 10990929831134698266, 5911273060564729281,
-               5197581879950405305, 3001975514736631403, 1919678782193534342, 16811100109848336275, 13086769249238533805, 4351245282425706500, 18281601243717625371, 16799537683941038764,
-               6288277991521986035, 12231480617236286340, 8633990423689180869, 13535190275290488690, 13419223868164389899, 17622732596713666209, 10071779220640400024, 9451660464882303005,
-               14029940454474238624, 4957972603307996503, 6311878080193524221, 7485203809274562760, 14450074580092843779, 16845073066403496624, 15870387052570816676, 15700883809468229388,
-               6623653867803819118, 1037643671564549885, 1236506073247459642, 2997396263933967582, 6182371056378366305, 9773995232878719062, 3356495419149379609, 10710833980055523526,
-               9965766500412107699, 16895652751136174589, 7310937934566947318, 17649841370865305295, 5052693369483848536, 8093060855248113928, 15777336335257114359, 4642979535698186085,
-               11761084765182152401, 9226969173242076459, 5445719591917489914, 9371133174853825566, 18381867235964583187, 17262888224001222346, 1934253649802391267, 3574888052111089863,
-               7862401495691359736, 674970329153306547, 14447324101549742216, 15408908436196428001, 5339840774639473099, 15542473999923245378, 17353380999887736706, 17787369898686553525,
-               2301964326759931592, 17775852221342579469, 345763078096690431, 5079606662887837532, 14863722102334084051, 8905941255852264870, 3806200576416892831, 6668327519801544161,
-               3672519063263749482, 11898207454593385701, 2364050348970898536, 3761861796987022528, 8159458273489411574, 3231262679605967088, 17179214124164291006, 8770284079122589350,
-               15270079546607712667, 8471883658965202468, 10333206241569264742, 7414741159725097798, 7709713706668701850, 4461310100162632915, 10099194304024685274, 4760203118683828795,
-       },
-       {
-               7237168574323016859, 17908810107504968137, 16225708127838178121, 11127095986977103648, 9346291308317410251, 7381283458277047010, 15168602815371846943, 9193719743691734294,
-               9607254959726458411, 16837156817186931862, 16178143308706847393, 10970721795101931539, 10840376278605273092, 8298765077094727469, 15520543037910966843, 11484620381947762562,
-               17395070963094117711, 7608132718922490881, 6531178971071758016, 1302814667007331361, 4002629363862769670, 14649492495298089937, 6868174210142585697, 15456170652716048683,
-               3688308493559609536, 5123828159813683938, 6245436817220183971, 13062234263274605325, 1313395302496832996, 4961840797708687855, 4990192311341859196, 5283131006216350959,
-               16952735659396950704, 1249482796824289329, 17859504101404809981, 13260403650830168625, 1583343855370236084, 11389120333403185826, 13676599385745755008, 5066667130137739346,
-               4799264864906918301, 18347145714884655971, 17034125441088681346, 11828378178487279470, 1759038296522081901, 9582407833575609381, 4195817009050503354, 12618256395967210055,
-               6486755100213398364, 5270923715575268322, 9268255346880651103, 3147724493117082267, 16710318779269985633, 1240462642985509644, 2400811796254219369, 13670743068809614358,
-               11437779990773246594, 13609113239383378152, 31268927496646090, 11618772705165035208, 3078024460365036167, 12138983306908962712, 4779157919015181380, 11901698850260672002,
-               14642787507945832432, 16258081639927585935, 2560321462542164242, 16286882196975458174, 4328159372518768969, 14313553865397841147, 13769372656320240568, 8950675126435331579,
-               1309709344837422378, 18403288028608342631, 17102350491414677993, 1133523394849437315, 12526496222782003755, 5447309058259018864, 17311120581405946631, 3760058661125144368,
-               17891474172606596407, 320094264574086461, 93927075222964142, 14355817838636249140, 1777882427773785068, 8237021421587560510, 11520559469641852991, 10567910693910023157,
-               9164300764173563614, 12322279811717869943, 2768902015676238485, 7761799112151133995, 5740162933856370894, 8043946608495226840, 8923704438836381869, 15189322655373943849,
-               12046275966378825708, 5909386969214935556, 1201990704907881028, 12128549009950617306, 10773478878317625320, 4554854625564648958, 14029736945871573056, 1353247251064221090,
-               11909123603272307101, 5517949035179831783, 3295386484950432959, 5605137795524476293, 10718654547602473221, 4984952409581272095, 883267724006996723, 17328431094026829348,
-               13671210467347025770, 9980617617519781731, 8339868735163579231, 2150724314757661915, 8571153021065445899, 9146903697769397191, 9122246102814640373, 7744779513085605450,
-               5733697799130763963, 962857090393715865, 10538932452511329419, 3413281437172590207, 6635428480179771287, 4404718679994229138, 329074170931436370, 17746708206910902139,
-               465623292609655544, 12740391094094156750, 15600221933467635716, 10712500242632508096, 4760789577759901270, 408323003115848014, 464706673403009712, 11801112998381624421,
-               5545681129476190458, 8725689673989867696, 2143812364199804063, 12133065347666807143, 14072918710585286097, 9027361966934517640, 12608281386782336413, 2053972384317260152,
-               11862793362110657447, 2615766363986534825, 5065170482898519596, 2878903691735623036, 5204682974850023849, 3382494556217615091, 15421437169807703253, 14936317525837021790,
-               12363228588136583724, 15035239525394825264, 16312817933687103988, 5294641777817034798, 1197907056067071148, 13084871057903003628, 5240492218216802394, 13798739245031559476,
-               16167519903361647970, 13106036157861122437, 2112866661358918425, 941609107359251234, 7240286582201258992, 17783018133711208779, 10433192833270769862, 4303514224506582113,
-               1549168540255262874, 7958641388293572779, 17867057222043259063, 1752211085999288773, 11828273580240483781, 11712913016012991853, 2373360154803731890, 6779610934665321824,
-               6633997178003959408, 145323909693817907, 2198452664824754574, 2920221908918689777, 11047294234593305837, 16840329825128198329, 5479733463453508239, 14054694221361300990,
-               7908792292118068471, 2703859967221946473, 6268006869726038724, 9406994672213611166, 12424098071734234719, 11900750387777467409, 10724482893673149484, 3191937460539390989,
-               7635348735946750413, 15019610708452651937, 107671898858364780, 16808612119435524257, 6120109999123152232, 2251481693156523545, 10792076820325151003, 12924551065805570215,
-               11225852067204798645, 7665324911993544151, 10402215331683389905, 2856131542917118235, 14152013119539822346, 12731746180172488022, 16402457225039188820, 11129045951416314666,
-               13009066459618795885, 9636541685854928780, 4783713672495759319, 13224924194053497016, 8044695420996588716, 4054951559323242873, 8718047667110955699, 13479622910466265834,
-               4333570709684826136, 3188483692974505359, 17976757824852085147, 12585927226835238762, 16665346689006249776, 14033419552450595393, 12216049696243171604, 447536030797427204,
-               14100792221456700414, 11757964686555543320, 3971513799111193530, 224065891283865758, 1282520657830780512, 9120233956471705454, 13711191981326748211, 3725543277190035504,
-               12094220323799678341, 16876894723130932646, 14806566188177921577, 2283878370700345373, 12254260799985999571, 12764268124075139223, 2425316412794046071, 2088679341162220742,
-               172600248248909168, 4338060849169481673, 12046085844143054569, 16220699277291497444, 10358794035289405365, 6739081270984238196, 16079387007561085178, 13471688054064884318,
-               179238781994802586, 9017860544212172426, 16179187983079961859, 1380105261896053495, 6187003332254463653, 9896593306091975718, 17181949235068293496, 6820143159816507763,
-       },
-       {
-               11156900805411912784, 1737275748212365168, 16993486692205800040, 12538938066475152524, 13167476167764338790, 17373319366642541595, 6054831428930905282, 7118452124011953000,
-               743288751022377974, 9226164090128370715, 17669221687181604232, 1117842260351396541, 17697784451833850722, 14382209306891991103, 16951372733687268016, 188390802712613066,
-               13268209255833199938, 16633146482265079265, 6044233937395578074, 1733872861371247406, 14239198956565602758, 4036306057099495106, 1778912298053970082, 6174082695927204648,
-               6390361653475754940, 1093882175267357438, 3784079074949811167, 17343872969822169769, 3359715652121662979, 16808529787251986583, 5169730697018536870, 52766949850965558,
-               1403521870654810721, 11668153767441183906, 12890534559297323775, 13255750643204945388, 8838011266491753399, 8488733891344199335, 7468199299966346977, 10645543722243906719,
-               17019046551094178629, 3055711824867115856, 10841870683594132444, 382072777978364200, 725450988418371589, 12501774248954630111, 10130164067258601487, 7823254091037946722,
-               1866199290196467180, 554488389245696218, 15654194385091454776, 6131785419830586829, 17856850737824439617, 17602611196814472081, 18244498160243832872, 5819736122106091373,
-               13147212495082910072, 5628914243538540648, 439989514095330941, 7620472329041817834, 4272251824771633288, 16564977601507013119, 5441117136715882317, 5622571730905974389,
-               8706277077547369587, 4848592786700984858, 11350018329458740004, 143688324288835298, 16536982722430328270, 6522962371020150117, 9511378862712142567, 18221873727623821967,
-               3985496688414455558, 11118602672015528143, 5383196298446424580, 6116994806363767576, 4051800833472889243, 12236802048340231756, 2619572929682123355, 6008593592518397571,
-               18159379849046931840, 11283007389905902377, 7465803490016928282, 7730454089227756796, 3569936088077890000, 2804205711716327520, 14107136042131448408, 12050401455009236937,
-               4207421531032215145, 7924589143024019458, 5496622772676523695, 7061817399179278712, 7371689806847905735, 8282663810521090335, 11422487361383982601, 6397294642072086677,
-               15924576759579234055, 9923512276109397968, 6142441356128988365, 11189756906743802872, 17790684027455851021, 14143953977451478354, 4002828116425422775, 7521923183240026608,
-               8349314793194266723, 8850246337652136896, 16635419760398709839, 12466509089914036008, 2686508850003621675, 15822032015692543407, 2211302095278204426, 12550915236378020964,
-               3844358527917324404, 15045102416646491178, 558560187822263769, 119801275176287297, 15593003307431898979, 12817356186703401527, 531419248069516921, 7957931139148417935,
-               960381383357168877, 16774709963697143275, 17896181076874992240, 1150415168189819777, 5498481130530161530, 6895900060791069290, 2079514944189747822, 3428689507902936354,
-               8525743843643076774, 6014251588524085384, 16423924202355808346, 2605496565158241796, 16676209604549923678, 4870342652354143869, 8337072895802905281, 2478197702680510974,
-               17076629945963768258, 7647523525256473652, 3999707005939039144, 9578933944626939348, 10469359763046002307, 17515033080264359276, 14272203721184987484, 9979666177276073145,
-               3896303254672567310, 17167309259158926479, 13231865857998180315, 2260217573257466310, 15465674863730076330, 4460025914284098438, 718707264700157542, 7215235109325196153,
-               12056920178557394302, 5131253251712581899, 16251877995882633963, 10883064494054484051, 9473274815269607947, 8874308005470196739, 4412709653190846630, 16469366225886156991,
-               13309932065155297376, 11504232979548718747, 14366229841750030472, 12797870458094162590, 12894694064456675527, 16977997035748966590, 15080606548583635864, 9292471759789693596,
-               1226107676031264801, 2683510924831720521, 4344623677417870872, 6581244316153602113, 12516966236091151915, 6758725397469564403, 3190083750600883646, 13018714111448482165,
-               877612159223846777, 1550479938877814973, 11850498481046386377, 18144061425551419288, 6811504328538189985, 16351446194603329949, 14495016749549056145, 15394017693349630053,
-               3547198835521135552, 9940690805769919242, 15170549880149605690, 10701681269101530298, 5914809102954412895, 15790219349994701461, 13664049285300230863, 5735249081148743651,
-               12395092509541605535, 2320592554345067500, 14213227630916688382, 12847883717490005600, 10192971941898238362, 18392117086623245662, 14369915478097042954, 9636190568462370402,
-               13308009076055104849, 9679299541833059768, 1512845037409468381, 18211703514703978816, 8337549295001075127, 15882458005321062689, 1212364284844818969, 13856780176955551126,
-               7602636613718406141, 2678224565451628558, 6976331354727208830, 7414684104929828967, 13536889690553324858, 13086024708711030952, 3748455179863046304, 1853373561223967487,
-               14753645881295168970, 9410794713982813264, 13485977523338061503, 14267793994973767571, 15813187206361118954, 16449603969001878152, 17705410933007144731, 10960511750491378082,
-               42380674434071200, 10068881872338405083, 14327149378182272744, 18264050153181932597, 8600790433943161385, 2952021171158508784, 13461070885471956301, 9633226987835715039,
-               10360728550079953555, 8471248683929284652, 6673003382103023756, 8972723925695500528, 5941683993959582947, 13500073059240140624, 17856131583218769324, 16799784995825923732,
-               7292102941225494742, 4807816512907139693, 11271815982004383122, 1065441269547643077, 5279915279332961503, 12100441009657772185, 10448964764090871372, 2944169874578456259,
-               4669722990542640772, 10017368027073540045, 13392819319228640800, 1070815632453829996, 7274130058405640448, 4460835865761538026, 15283885107956150892, 5815884817303156137,
-       },
-       {
-               987127652983079722, 6872208513691823695, 10110578719299008714, 16457381243184327116, 10779072738879347999, 5965282398006505989, 18251577267494363268, 9321323379108563422,
-               6119049170407437179, 12938407708038792521, 10105420405825346383, 3416306788177016826, 330648587825212481, 125568991290568141, 13857127346570918649, 4376080986981308805,
-               5930434126597036589, 11240994623469578584, 839346533006694594, 10015087329724081709, 6285097815938761787, 17244606485954860090, 11523249727882012981, 7178451948850151803,
-               16733615335426327004, 14833564736134873977, 15736159435317472941, 17560193966711884894, 4670172300306758374, 9477713670983496835, 14243955354032737980, 6459864769649694970,
-               16053517698989562256, 2069464650596796670, 18305730134729303993, 1090863611964008044, 10595928817546105363, 11743183506441120484, 8584767248013363683, 9187452830514379903,
-               6938579711827578880, 16268282168771714072, 4567473305742437221, 754548046014059669, 7773636946295303572, 8132380485366854656, 5054542590195827722, 6074347500754248128,
-               3955857908381474930, 11852678900999621852, 13783017203403417097, 13616745777931267488, 13189924588414196918, 14519927295809952876, 9334100965942760501, 15172548734242885286,
-               4869852132020793901, 14921212823114724347, 14342559113353033349, 13336827701782657309, 11168346789878684452, 9790480725902426052, 9171116079841529936, 9268902731763220711,
-               4417372365016540659, 17280138652899703220, 6650972319709075180, 11252221422799491438, 6825784270383052414, 18308562203755695191, 4237445205082731447, 8485872406483449772,
-               11718726714045105993, 2624508790343569765, 5794111482300008213, 12819216567095091385, 285329842793152354, 17257707863943097374, 16912487373614458842, 9501952033607497057,
-               13074643344738491288, 8505193022029238118, 9932652098552590323, 267408114280737600, 14802861246220332716, 17506028737327736269, 15929083591675282371, 10937680132245212187,
-               16688733766460131050, 12777635326299184071, 7769405825716531061, 12435979606514844725, 2767987141420672349, 6723940414217341603, 16114182069580717377, 4541113259200434040,
-               8506371389960537559, 18031198550689409305, 11510251852995503442, 1923472385053944821, 6189904387119195613, 345664413118550356, 6439003191582953600, 18344385760549575361,
-               5320548958745018096, 8341561189829530680, 3327828110998403156, 17981346269177513223, 14254804273025688074, 11111147827704077234, 9093333670517437191, 7272552282364063165,
-               7587268797387514088, 4402481408866840263, 11260815389095334885, 14391444701764948710, 4224880318604689771, 2472148458660279030, 961218007313548745, 13826356220879831691,
-               4477325369345373420, 299141931133875776, 6787652129916359301, 2498016036564260464, 13342319943892943548, 11124287719737492205, 2456333599771808442, 5084719026388755304,
-               11208298545009109072, 9361672558653085726, 11597473974277116433, 9123409098329262113, 2315750487079392743, 14788891796020803799, 16477373474431052867, 6394267218565388055,
-               15099803091969065643, 7815556206466442264, 10304177785190927723, 6493522556494567776, 14386173575053274652, 4399768637448990408, 2996083572119906777, 9762267038999270167,
-               204205141115459509, 15145142808374731170, 1678672167166598389, 12032976094920574395, 7472791648310888425, 3687068899306742850, 2661021646792225638, 13705804163602287184,
-               9320611303424530507, 7295004960403065170, 15749376924513664173, 11543669941217924178, 3710258597217352196, 11371260298937340150, 3902566672028686120, 17983841473999282668,
-               11814188798674654097, 13017429106091059634, 11079902218909650978, 9064898043690914606, 12023954026861289442, 3592879256613061321, 9997625973577562433, 16073808232708438680,
-               15365030910001289574, 8789654976305207659, 3460532362538090307, 12992239135084766157, 11449242863169591803, 5418502644558230048, 7981056000757137731, 13021725301900406539,
-               7782773734814780443, 9390379677704432300, 7130223982341575476, 6496906770393189740, 5095392170846288421, 11058865093605824851, 11021902438459302094, 6088242418938968652,
-               5966014717657529537, 5136588784988696205, 6360472729290909457, 4447169061266082500, 12506934948427595318, 16433395045878253504, 5116318868244944213, 6640832565780621049,
-               4132920736998081103, 11827975663170283136, 379030309731223785, 3149051804072184938, 12035317616979166548, 9642536337674500310, 15531497803043399747, 14399049832547796531,
-               5493097462539196248, 1629980144571354138, 13641173578972112594, 11096917099468924214, 10934169048860132281, 11269991112518485434, 11206050457519414207, 7939067479736521906,
-               3806755078949823895, 15988975666336042818, 8246267395645554105, 9703363749164024623, 7795606269507901456, 451102251659512683, 5865831186929065346, 81064915983990550,
-               5810137226573964106, 8424253088401255706, 4543883508937971494, 7386148745257823512, 1348150366217548727, 2103092839740150931, 8353010273955146981, 16831854467863536537,
-               5095778754322493440, 16577416628492146129, 12288076721910512064, 10563487622054214075, 14620553808255752273, 8159958565993701874, 6712100880095874267, 13203797993773281759,
-               9640010815039549413, 17460773950401928956, 18229977265837445092, 9252634318278265623, 16798979334068219458, 11731856767337519419, 1551975378671663669, 14320102155496153821,
-               10528988339881191052, 3808685834232068820, 1064376960475785008, 6466670187430364599, 16860839938395945578, 8876458447995837267, 7897541112736965607, 10283235741250763328,
-               12246932755942887931, 10842213418139067847, 1827392608284960926, 6961756951208563550, 14626966634382828071, 12653808277900379805, 3359368990539585596, 1190255644328095727,
-       },
-       {
-               10836955050615624183, 6228108794259714192, 3769609579318360527, 1481673673659326756, 301329772189110029, 3574710782304999603, 3037244905687722509, 14442941761397229485,
-               7739110373965523311, 11019153332996240080, 7346010155518751797, 14853737521111213548, 2542883237207113209, 11015136828834421504, 1998601666328316353, 1540417751495800469,
-               599034134015360884, 11263317530774995092, 6667501365379084069, 9844276013103312691, 7566306886180438990, 13702768345615509363, 12525031963170717968, 8463786212988210464,
-               16430555432520738762, 11225321696360643709, 11777973654353154098, 13133115227828884393, 17678738157022850345, 1586660156856830642, 840647763693221003, 8645742354464326466,
-               8067725618510810414, 6229041032854057836, 8025364837156161898, 1290443646630661359, 10991323655842003728, 9346782840170054789, 8939059450584871902, 4772347025802041241,
-               8187379062828795656, 14744366698824202673, 17014663804743197103, 7704635785366672415, 17162645929628468457, 12942442527592695216, 13291710923558633295, 5800071247768119960,
-               3552067877931717181, 590108493628737243, 497390871097272557, 12785795808441396281, 5561451613221796230, 14263823913216836845, 10481729699001112354, 7818094022046194698,
-               3598736754916501501, 4827022662021197854, 8203180748141933720, 10283251600632599041, 16186680658340956808, 15183393398087319142, 8714402370450665212, 13217902016653171217,
-               13766344083396522552, 3843491774288631026, 1174164282483810421, 6398024882371290634, 5459580537585379131, 5871096222069618377, 9611875286525007701, 1940221124144536452,
-               11598781954647517543, 15695098933552070478, 14976427118847622464, 7147358677856872160, 17135524627354123951, 8338407198954935663, 18099467407613897492, 9025371359994313919,
-               11451018285787631498, 11710749546511767589, 12969419493657624536, 2338911230088800542, 17492614411321910750, 15274296072504110502, 1258801445108685875, 15178229640559232741,
-               11743016372336018414, 6125536020759642301, 16563280170798047733, 14529052521060111789, 15253502329174644388, 1556763737841306861, 3041940064290508531, 18020881359462953336,
-               3035547704692483898, 462291414338050452, 4209186193642705826, 929930084709639338, 5246348806539841852, 16407585218848843770, 6076996892610687611, 16547395936238439809,
-               7781914900266335582, 17967080065814694611, 14677062197599091614, 6667353926398988267, 5658765839564756939, 15807817354312473921, 7476371642206655552, 1194561222317134506,
-               10645607622061780068, 11583886495890779582, 6879987349345299140, 5119348262235800038, 6546217876212430196, 5534845503308945424, 2003680599532879233, 2824480091030475274,
-               2297585344913389180, 13965959247788377604, 11341378863608387800, 9890953382689640379, 10443523266835246852, 9631856696811288063, 6944503116553031744, 10030824122780966395,
-               2699238910420203023, 13176131497943324759, 2961070701879546988, 1511208990650977146, 13153451530298458944, 254163587562261430, 6668642257003911712, 9040693998431169077,
-               5596789796292416136, 10505785820531892681, 3803057245175025164, 13601446877323203658, 7939638174866660891, 14141848241206986005, 13782885912650943563, 6287188921995938212,
-               12999700407775352603, 2664314004284450753, 7085329252118415126, 17472483363754271126, 15550759073378819069, 7572177503239633527, 15705617684783232308, 8586972133880335199,
-               6636244234467769744, 18284390012667441869, 722929822219329257, 3274166388651987221, 13177791837760949480, 2568122970128111127, 3477167651270374316, 11371867850093288299,
-               4065583279544717744, 15575999213135020408, 1319417044854511604, 14713082471342741360, 9399053450949627084, 8900637792268080986, 13511414538589410393, 601556817111475086,
-               9243142430859561073, 14638657859832212223, 15324499241122936340, 14477761753578941934, 14699832840191454785, 5114873517253108658, 7427057898915535537, 12536800031182849473,
-               11775949216482616439, 9736654184925478086, 2941126957776086651, 11331303510371804917, 3535865528819665754, 2488682969529955908, 922100556888217739, 17904958255578472855,
-               12876460969864886954, 4692925517843901006, 17390372170975588763, 14692578774429957295, 1759864963511373267, 12016553435172103063, 13015881292003590351, 16187569590073958370,
-               15154092100094191059, 8103665941237580228, 3265383210728928809, 8341136973870067643, 17281635732314163959, 16433737305161442677, 9130496888060417111, 7070932927684908859,
-               2129695226164849659, 15163429615374108928, 2225893409909150746, 7870945454511315288, 11525457118388411301, 10519485231888976311, 17601979933176863246, 5257431126828903605,
-               8898009465920717074, 9418463821940622934, 3166596280515383312, 14529914354665032916, 17743784337460844568, 15964972678726654742, 17116339264937332927, 17098426671353029801,
-               5868176722765418764, 8429364877332796959, 7785756492654137899, 14975349488807886278, 3272010964035218775, 8946396491617515063, 3774503492701710541, 2113917870331282160,
-               8185651664029868180, 7343199417670698200, 16586532029502206227, 1531724981369431299, 5596507566645246686, 1033673521199123313, 6075312368002387319, 6988496924054716781,
-               4604669688530289732, 1867259042549585024, 16180237500272383882, 3296394050993129267, 4326520583229998770, 6557569103657179065, 4126356691591689646, 8674328613473447843,
-               18057076842177382833, 13020419432300857029, 13646402493577420410, 16962268104464192344, 5358581430340252761, 16443104373870300795, 10099216829282619724, 14890543634568831960,
-               13276631120161396750, 16968574704982977753, 2376454925072971568, 9477134218094425043, 13784622991820528988, 2074505569780291922, 14294803056569335889, 8759684036994631222,
-       },
-       {
-               16549155412115374305, 75977962737081600, 8870825488941031605, 7403557657089993256, 5825394234709429518, 11978746413791918409, 1876293130790608838, 9416631623519692610,
-               12346821858361333862, 6352722970730511156, 9920942104315084988, 10492373916708072181, 11163323626947992791, 17035282992056675772, 835685192553490421, 12792459312570503983,
-               10447922451077327640, 1515090998837129975, 13498807582085718212, 1212623301098019779, 11573518650162536086, 4823461685803772444, 7289704908733783271, 13167881392748327839,
-               16959954449957105311, 11051594981465026138, 16062472412226411858, 1976004115345602080, 3630495248560019222, 12698191555196404138, 10107923614229901155, 1597725222698864118,
-               3416019089997140849, 3011417601086561495, 6275242351124667286, 14197557183081060761, 5633711018871057458, 9723496411345030748, 13910057756335530832, 7285051335492395815,
-               16774605620279328247, 10223834398868957807, 15781733027568799739, 2607095622729296315, 16499590296954181006, 7576646116121533069, 16638313875339315529, 14296194207652471696,
-               12874411821611501068, 1998417862388106640, 13882642435422318946, 5791129521978463837, 7512934139125398199, 6966283273373526248, 5475728301311080129, 13542211842758381589,
-               7798993150530415596, 3288770257171840452, 13373286069558329631, 9784279046496345014, 15725032660238528813, 16038931923358478835, 6921788930154218900, 6093507035435214187,
-               12194839527972802101, 8376199250979271449, 9055995864116790217, 8125030124567662718, 1070812422878398727, 3950906148308170707, 10121516919638719072, 813471384549762068,
-               7610605259962047827, 14617655900985224117, 16089669078196617440, 10594009761533811214, 3425971360520359121, 1245021768718221594, 16690372892586114152, 9933179766195044175,
-               15142732720676276463, 17435583143726694663, 6030257647680338377, 243683009289621849, 3064238900429394982, 7655019927497549159, 4484400084400458429, 11650860345018651068,
-               16203650576183697977, 17614744533772112337, 1119292890050870301, 4574885263986729787, 8108207498737924504, 9708434439316056191, 10676823369888368482, 1078311554675991883,
-               6876202174636220158, 18057502510666060150, 7821730895845187783, 8882321799602877790, 16220624224336230256, 15562800387021280583, 3043825293109091520, 697130162105054983,
-               5394549491776704087, 14795348078061113966, 14206080764200897220, 4623073019242398493, 5850602047109930316, 13783531993760979209, 14764346975698048641, 8951680172224205890,
-               7302725075484262769, 12572584665857403749, 6499691362933905099, 14476353114356185371, 7381716148644532401, 1573798302334388880, 8128390307766282880, 14547454176248589604,
-               12109367644744157376, 18037756988516427980, 814572839386760074, 913616818805172815, 12974490864633240943, 5228203788953366069, 11458421156905635350, 14534725545904442520,
-               7717994192616957513, 12204841747568567286, 3911093871228418198, 11236736110419819217, 3283907124458179474, 11742518530965881218, 15033771683298452989, 5201173013910789542,
-               13950307561490203211, 2109530041534182225, 16966608361725322273, 17050013487213560977, 6582524050666171954, 8348662591649610062, 18257068567217206885, 12084557407109908164,
-               18134052713971906645, 13522834551049471624, 11796035797088472898, 4408384297249203940, 13184035659663315829, 10318594606381671372, 43784547091343099, 5864759723778872652,
-               273751009786971880, 17433500308695913052, 14095169299451888252, 9384697581863180516, 3670310635026975567, 7512955195757960238, 1061441390592395566, 8687976820410979119,
-               5847434943730572861, 6139588162124989313, 16640425042872222986, 2868461478718351559, 4582082172412426839, 15999623457772192080, 3911979819012561187, 2157661418664981538,
-               1679437503202036379, 3357369754420384657, 14227038694942012893, 10849243658636382261, 14698996273665673323, 15473144682787301630, 12886363027445513063, 4218522843946321369,
-               4305571301049736163, 7569433164869749160, 9286896219015408706, 3061813620853218759, 13836461093317197944, 12893856993043908140, 17368798334120212403, 3507360881370918016,
-               17887381848254057882, 5080557806347717197, 10977337278063191668, 13725230338861893934, 12618602415751234016, 7913767807930932665, 7119689779124353718, 14253582440914432409,
-               16180079775228731323, 7952167928403988663, 17529082815577219791, 14568667835887326401, 80331144542697157, 16190739578357987369, 8688615216852085496, 16668129019590270615,
-               7430615013050690552, 16490141830322172211, 9793941851666815428, 12678643730925993658, 248986629347794843, 14250412400606998841, 7671639316274744213, 198890803142183275,
-               14099347485199617889, 10490379547566026579, 2979540189595374423, 1947868558918413664, 14807112327541983728, 2275659819146309375, 14464189275380358394, 11448352451702208893,
-               6508543885912264241, 11768683250765503158, 10952591955476802447, 13816638967602836229, 15422608700909569544, 2270147616630940233, 11179267547770249728, 10448962907285827304,
-               16734703714440778657, 5221611440144584595, 14517195248502569256, 17256223341936104100, 13260411672715241049, 15406026631864099983, 13737383554048659263, 15455560302156741675,
-               1751310744149771156, 13066379976997527874, 3353407191478085130, 1488844206746128853, 5630044290904406795, 14205180196532348798, 10021323252656730909, 4177092513333669169,
-               16120743770319899284, 12307096057555293266, 15459231763664176764, 889710173957193674, 4419259815443372538, 17256024223837463177, 6105822529166486288, 14459703836399905847,
-               13918155529832261002, 12953608416498491778, 4285102780598248527, 15853935066983430239, 2610351403194505517, 14905969693015035277, 12043976761492019990, 3883507340167876094,
-       },
-       {
-               10994470105201067642, 16033352651464686189, 15774427704233149170, 4596106024708523955, 8854068685612048031, 13529126595187822090, 11509928293490788309, 11620850709434334690,
-               2068337952936280662, 6856444059219131741, 17213926210819196459, 513413453513211652, 5520465604253824995, 12970886588014924605, 12296275668437451137, 16808287251356954962,
-               3413637388791433603, 16937929882486384885, 11215805046681294327, 11559398419268924015, 11697258172757450737, 6137795229387768085, 3190984692021653574, 15347236891154706739,
-               17955247196574331290, 285928599571507431, 11902987704297070981, 2841167725097799100, 9281167410796848363, 16444340476026142274, 3423202423051178709, 9101021305726472246,
-               7129792976024548817, 11116052691850916690, 13765136177550464799, 15815419857669199536, 3490265904262366633, 3075105190264147815, 13090337405102529529, 3772589223509323910,
-               1865569627339845981, 14405510401062639678, 16548248891153314376, 18134729633170718083, 7342289204282809135, 13678804825671892797, 11309594694670555920, 6482941613725556691,
-               15861081392207208208, 8373665453512079014, 1489270058265748447, 3594001972161344915, 1115942979837741628, 11080512787291988167, 8129036993725083225, 3358115086982889477,
-               8869273893561412239, 10349812081309865197, 8913824872487209090, 3148808685596180274, 530908416884501807, 10284103744075805979, 13606889938905754722, 2418062398586758364,
-               12413212040240282991, 7478703750955930147, 1623142090654002287, 3800351594986125089, 483782039790230646, 7823394007049468275, 7643246613581822171, 15001087565682987468,
-               4027740097060141621, 11299467443664320327, 11151439614540606708, 866223440636939151, 3440384894029167420, 3873155505711856537, 5954029035616033594, 15381861683078360474,
-               536906646315848696, 4762701494256722953, 3244970900590282998, 13809219136128336072, 6259009038800226590, 15448401588227595780, 5228638796256712654, 52817644221507266,
-               2298603653884322501, 601221199968240092, 1285112712738261659, 13882709760355308533, 13563254433762438170, 13447718334658435053, 13493687958886238103, 11032778298151679283,
-               17130548285854289846, 13389656739579236890, 11825243553071488462, 3295650559395515332, 5681593832990094932, 1986112566735995333, 6900923912677810734, 12885634718618182763,
-               5991348986251844787, 10652959958005297329, 4727138097613835700, 11665606181484659859, 17818486388489237050, 17381457056943650121, 11483713831771420728, 14346336385265122549,
-               6806904066777263417, 13464056321884738018, 6982639430167685380, 7669355554060154277, 5859444273628884163, 13073052226541367148, 9082949662405155834, 12390918296713433257,
-               8626760324117733843, 16403951745962159364, 5837394731212322914, 6847167719031297053, 2888142337636247281, 3409818743436360750, 1677113113408664401, 1222157560539217476,
-               2099068961815044779, 12562181036171628906, 16101890713848274666, 6017764396716978009, 13064414845499489050, 8419967306079989759, 18212218073753486044, 1008986649080828268,
-               14883940931343463293, 12319376897638542821, 12367185247284838739, 5861252096374912155, 10018798299303262817, 6422772579819453330, 2070123940915480886, 12141302052520620302,
-               7347211048650261526, 4324486111460763452, 1238262417801832007, 7620393213816116173, 13629115925647807355, 17975185632155863015, 6751253893269214002, 3530207280414557051,
-               2294668553308381923, 17165287249067859297, 9897724011823072967, 17409851874231284314, 13888575318617508639, 12092766090379658603, 8412268183255186961, 8046572777745318483,
-               4493498909328627892, 14652253245762410953, 5345262207345951514, 3970988687199074488, 2208768899312608620, 1510839623981662369, 642580537527653605, 14940785106713466054,
-               12480576687390709541, 11249304546887636239, 6075047530003410694, 6121669232248820705, 10309256543424460776, 101796817907499847, 2110451750984093184, 10778335615512351243,
-               2885395260584376454, 612553588199732392, 17978615338185945515, 10414937982597482385, 6078565000469652304, 11381998957121196965, 1536418226678270090, 15114446343888525079,
-               13178439025428734594, 16388038968589028071, 16165750006742628176, 17903639397633243161, 9560319088110737392, 7888974492854359310, 16116323630343158496, 10177829649622711030,
-               12866004572891901059, 10190228418101288877, 4717913135317392922, 13460871068228811018, 4756401774767581561, 7711771325649205249, 13695132008344052711, 13361851345229950778,
-               938191787235564236, 14328703178349042628, 10217257468952800498, 10415924210674864240, 7171739159943819214, 6502538915112206091, 3300616451202954689, 9576887970605726107,
-               17259872866446195810, 3694244894150718459, 3214322135693408389, 15571503654130046642, 2332159362399220208, 14087696453363417437, 14318693886833071484, 6131092646618026480,
-               2378363646789710539, 494954399989334038, 6915496914984330558, 757197055392642378, 9097171378505823650, 12104288338329241488, 1905673690814481722, 13011078677095066032,
-               8123217305309052526, 2527408826476194625, 10072980201182378784, 15489255866670747761, 12978131276673936002, 8312787524887306087, 13561211528259491689, 6311660759462081662,
-               16247831307849916845, 8654394682758927217, 1180998443932568506, 3847327552938166714, 17658215545137701161, 11975413369861829206, 10679985684889599173, 14928266362876119222,
-               7605162785889302718, 5718899840342120733, 6057249397801266401, 9486440247354542717, 10618370743126190918, 16153494357430969850, 16785070420314699787, 11277000340020413902,
-               12712274459771886808, 15748114764509451764, 1994630377849062253, 564390855806287868, 135493276425567450, 4305883520257541088, 4842008929542073044, 7035106970720249617,
-       },
-       {
-               5757832545805155636, 17609080533053427627, 13855662030602089892, 9622498683452213297, 12281586442064581946, 610529441714948581, 14740357477019436626, 16983190111725558863,
-               8470173855499872166, 15915210069852758660, 12368087246231545517, 3867174158581293223, 9082358201271846042, 16663463402757176964, 13740908859955866819, 7748969412274962298,
-               13375424826931892789, 8508645806391261552, 18359272328758476903, 16433208398005282080, 13071423254987294580, 7999383023651164492, 14514701556577587750, 4848295889377673720,
-               1020519568493754982, 10467781020270669620, 17607771250627508499, 6620300538436640218, 3858527175523168333, 13798129597334232823, 12495322651937391008, 3926713306087152023,
-               5116038770086590715, 9943789276328255827, 13715439407309914230, 4887040860130243503, 18288477612078228131, 7640050573721350378, 14537362862524718973, 1658575506924200900,
-               18400486168653423966, 18026904540891591040, 2037921821724043966, 18010956304511658647, 3751340308708032971, 16275459031633957091, 17177866831427164840, 1635431811339422016,
-               3897330996014812355, 14347736534650088376, 16862404119462964612, 12216005411754788835, 11561909516001453735, 6261639657930189859, 9101978764314050064, 12280333151331067982,
-               910276569977357717, 2872810615152156462, 1942106118995935911, 8734004121981822024, 13862118436432879698, 1912639548162720505, 13060137938875924732, 10642216911059510120,
-               5132232031613377471, 3053931945527415993, 2695169719602504430, 11855046366025891084, 16462491222215366712, 16664416596202206835, 3077124688577987843, 7109495326459366311,
-               3858762384693274897, 7520194928987242278, 4496744297661574884, 16159343214247089321, 6441167128044578145, 3604951495694157848, 3072075325567814428, 1964798869371174506,
-               13689578474000942304, 8998724267038772595, 3350174507425430811, 15015413657749135511, 4848907595494161497, 7935644131326131098, 385849363817229511, 10087353746314516691,
-               6067717601858189468, 10438404859927821308, 9991403870358837471, 17728358586134467771, 13476949968946830198, 7311235997042381570, 4429835371823736972, 17463216455983091974,
-               3446799583712077997, 6763499387263152328, 9231082163128267527, 7733182914440272884, 17225092062157610409, 8163842076250628108, 14230171836718858439, 8195740716303697476,
-               57759226194841354, 14962480748390190557, 2047254208877381876, 2830450574091058648, 14905486147404440754, 15792397930637469157, 16383409053580142957, 8686506861607761226,
-               11120178572139812895, 11534611317577597022, 10437856602660752754, 13925966850017814278, 16776862023867799947, 17362554889424346260, 3408825299914455645, 2606150045870067742,
-               1119490156854665483, 16772836556735128526, 8607715508817325509, 9931017263385440911, 8799481055779587022, 11740562709785257943, 1956849872282864970, 595288629437737005,
-               2281206023740505682, 9926719762453358166, 4061056930877891291, 15576657447058286418, 2614863633636977404, 2206334532799385250, 3474210873232711865, 8477734925846980028,
-               3340305349427486363, 5188523629566097463, 6160790887356413747, 9863988255192204305, 14066826366866912046, 11932779567129411871, 12863116515340321220, 15222969978942513045,
-               12758642615291604404, 3209096496454847183, 11182564090025111575, 1931382908005123647, 15151007707308352245, 5954868822601995640, 15742433078711209582, 3347972315985628205,
-               16490337555999239547, 8990885971520264447, 10360258506616249745, 6630482203535351500, 16999397485942558889, 6788531264412870316, 7229988042452941955, 9856917486277085502,
-               10734804718395003162, 14385908274213668346, 6022876926209575383, 371182857232839872, 7412466195447558077, 7961511694540082231, 8030758761844457080, 8046696009323575767,
-               6399666206029163609, 17663811097734928631, 11470778017516778751, 17702646621253134508, 14876192013866833082, 12935280981291312476, 1467399042175927183, 8848908916563618579,
-               14359906986235888744, 4587839368531771442, 10497105860390751463, 14244616431904836676, 14906421794748569105, 7955760173743833219, 17152550002849021490, 138081467951201370,
-               2349932829525749283, 14749355610935637731, 14751838563606808702, 18058355029195133983, 8461199524627795693, 4219910612621001507, 12776964042319070094, 15905069451612157329,
-               1355498131832429384, 15975585519420207244, 15757549940022310945, 11357394570768845273, 8197697208897202922, 1901621009956576265, 4290101364365692172, 11947148614241269523,
-               5840762872471677309, 7514977007446174348, 1527060545570586419, 16609099121469101859, 9320342325870097548, 13965331598495025936, 9683433385601741715, 8845290689278472178,
-               14119395813630029665, 8634138112335652518, 4658233985292819043, 9622846971166516113, 996353694479629398, 7404001202059682426, 18145845493517798921, 6449664057746980028,
-               16521775738375440178, 14142357232938693849, 10990147202113110230, 9959066954415780230, 13034621383041722634, 5025797339352139456, 10322111864643366459, 2614961497496501105,
-               12557910439954509999, 12230084394391362713, 8427020226737465235, 12518021396913122088, 7134271418642259845, 3905501389650646356, 15707807001177039585, 2909191175572717037,
-               769225015796913609, 8753059944613840368, 1611869096690868003, 11449828005116201197, 11517191665323762104, 2697717476879599241, 11188965056705006770, 6249359019890699508,
-               15594613737645580981, 3037156291483237329, 5604071908229825169, 1604475019228431078, 7766918222574600204, 9339455406279970318, 16266564745812517195, 4799424886612563329,
-               11601570184515356415, 11247678357869162156, 8415095559389686315, 9625816053586466047, 11807876143163335372, 15690209134241397733, 8684637224468015605, 15974968144193406020,
-       },
-       {
-               11275984449259340674, 14922638629881602958, 17186426309348732477, 2094500549052461127, 1245672419927595636, 7529921141299797945, 3181089597449057707, 7749529014968942143,
-               12842581296013847382, 7845624487558348664, 8747439372999364825, 849305823897878133, 2217292264321907974, 8173534404179332054, 3588643190593022889, 12047811416592660080,
-               6959527445237219799, 17170778245769606301, 807762173031474321, 9151445233487017286, 15103411489939446333, 7976669669591851659, 14824323986579638641, 1535817133122800221,
-               2365455792963674834, 2249234228455309648, 5237136544555745182, 8814246419234451463, 13017813702607013347, 2241193992640629733, 17982226236989862510, 9800528153239873634,
-               14106286229675768856, 13210380707737857536, 8049798856134302097, 9734560649539497957, 1623205786926824588, 14287958304696241706, 1800854015662052826, 1212925137572581937,
-               3026947385483276729, 13169758424754896088, 6834174387382969128, 7206544572805916922, 6934064062491731757, 10620406409375153308, 5194048681860016706, 1469688754160716493,
-               12993558037376222988, 4669474265806332952, 4832324179281001408, 4413085485243863075, 5405837906169635761, 10091776239975644239, 5290719555562061144, 4213669820858776415,
-               17271890190678399664, 284117971978206043, 14999643475704678808, 6264699496666119083, 8859934981351804429, 8300880062060532031, 3667839168820458685, 17133003164910522197,
-               2997449698566957466, 7884833253198684528, 12498695470674374226, 3115564300965505022, 13376506794876055601, 17895331353362057251, 16990581103090492269, 4674862843410794096,
-               5006430925084708381, 16053115139414023422, 7049813739763202517, 6676629839394309180, 2410666182773729148, 8945309185393628712, 17674821778351929167, 2683163960153153804,
-               14505459891908974624, 1849503921080779239, 13990490450160111440, 5181610498614712941, 8653117877167770474, 8814499350344722617, 5343755460620184433, 243401361005198353,
-               17791633957402883820, 5938849497629314459, 8356801465373786047, 3163889445599730677, 9723709910898285412, 2841967670768995554, 10896757438566636700, 7434996874241771203,
-               7372440365321345784, 2862880403174214663, 8420116322934238724, 2818552325655576635, 111342786192022359, 74705672003306783, 6591511741514218962, 13124391319573921957,
-               9931074113040228488, 15362193958291437280, 6613002366394890474, 5258448208225327677, 5126245224005997831, 8755434042915330962, 4405830479557957055, 13343591337768921462,
-               9242810916685205316, 2838356272544913798, 10099476622515682546, 15551100165305852662, 737838832976059770, 11188026425234857295, 10166119013055947704, 8628233674684143419,
-               14086272070125896854, 12009239107306499026, 6592816798466831203, 11371087141421707743, 16277593907837607793, 16449564916599232060, 17471042072158213549, 11953382410698485455,
-               823047236880870350, 7830286704456953572, 6464058012664717582, 15521380082330968365, 10182202815901986450, 18143527955004661429, 3207725716803325445, 3193887560605396493,
-               15569872930692175382, 5346306686087630019, 6632365629111827330, 15865883909120927399, 7200040798106687333, 5723169387900917854, 15027071603483375844, 11018037359110138454,
-               741009114382240162, 13879961246490269823, 4790141947869766711, 4479737908710468090, 4979904969974036721, 634413885118778288, 101727670723732801, 3160663692354720401,
-               14613304240735929191, 7658770973133328064, 3028731168325633068, 1486737152001467114, 16715835021406106944, 15214200823642287507, 18441898204110447697, 5669963154424393607,
-               4313074171267006471, 16217697149498819074, 2027993870023154350, 18018610229517524263, 117205923522590215, 1784380715025232199, 307956084870608716, 4140912860495129528,
-               3938313265660748839, 13018885466029447230, 12461354215832959401, 14495299413345669177, 16234805331742830462, 1578184208291171741, 17168468892394781152, 12575003872292801090,
-               10424668870965277693, 8952352824982702795, 18017430252932614600, 14101949308713937413, 16342352613992153502, 6862842966642668923, 7238655696295295374, 11216037980129705353,
-               8381651800836461905, 275661552864412688, 5548629401959193001, 7174991431295718071, 7441251258233899268, 14052832476485122412, 301250917807487282, 17797202428295526090,
-               5173263645506172639, 7621852612520351243, 4670271322283433581, 8663786927624336026, 14433502423455668413, 6926265712671351075, 9776903322968672826, 542207238644018218,
-               9588056942118198784, 14024040464098859998, 17712446698584877455, 17945455593410056285, 18104078100936060946, 9565731894604896153, 13213845893767817606, 16043575675737450101,
-               3436179376183792489, 8124476612946977721, 2169106928994773725, 8589833084708985039, 15137137534993478994, 12789920909097626916, 6767184505234754407, 8369097443031908183,
-               16448089571044203401, 1396460397790470601, 9796571033221459545, 8162511506983092708, 13893406727199803081, 16188892369453405032, 16023105002157964343, 7061289566170423383,
-               10448117565485426152, 8145533940921335838, 1579413779055052019, 14761309857236492983, 9815666466018583851, 15131106965446764630, 16986514923298225288, 3751380281663155649,
-               2224143503200162255, 9410177163066991107, 7157489123570995878, 13420515130397093319, 2675717750075873421, 6702938999067232257, 394050047437199204, 11922372120263518221,
-               9930837889018815244, 11397955329795684905, 6931891256005909739, 516538601500853702, 923444815286512108, 16665363217941733257, 1377231042965759902, 8439923996651310778,
-               8743817608749172620, 7804846024944300667, 507107926259802795, 5258061329638283805, 15071070675288472598, 1848743106176521296, 16295570828486620412, 7409462376590083349,
-       },
-       {
-               10223936123327786454, 2321887803300626936, 13607747528117965743, 10456421630388400123, 3266519591187534953, 1053691207967834494, 7151443045753788549, 18124688636664828399,
-               6946488664257064464, 9775328903143754150, 58700362449753229, 7901817271072273406, 5074738678159003249, 18397239731906005785, 15911102965988125888, 9277654580204145348,
-               1874700306906525099, 7337351570334852732, 7954195906114335343, 17230226427261850070, 5181329498860909261, 107167242193237170, 4364856176182710332, 14611171841443342914,
-               10990327814895720476, 16588412771027628390, 2850177278998422188, 11569813740328484871, 3922148781422941186, 3581659216490446242, 3646872304052351376, 10887870617200051198,
-               8175121141368087217, 15079393830876652065, 16766987879267543828, 10582796406546815217, 16832256009371376870, 10042650470778064892, 17867163453935683780, 7123418345572641116,
-               1782651072016504775, 11033882508408412333, 11105300284232190625, 3276372405089292929, 6399472468041061588, 15319690780388315076, 4928530863063375966, 11596222198340277418,
-               5452424185619067445, 12050433097586021281, 15018766900844679217, 273234254926088220, 15426383635547379531, 5213762666043737626, 2829185842069118470, 3230799283770935127,
-               280030342772428106, 17354882606189694746, 17455445295460080284, 18076709382926018941, 9895982528034548913, 13681172423928175330, 1656433131309057012, 11935757350437721114,
-               14437472586336929440, 17387041914242263390, 14861577074379746687, 5146556788377906297, 13036814755814090195, 15108836859245573802, 1667563994642521213, 14722845469958372258,
-               7781061995240980266, 2066078418484154391, 4089376589847114892, 2434843609506038666, 18376509832460312721, 7187709121160627756, 2455436656049651823, 14419116837518875372,
-               1270185079976403265, 9214436628411717184, 15450450827683432913, 2880014804806096082, 15448799931519826757, 10080240282127928735, 10673974088219619287, 12998944469117087518,
-               18028691745165748687, 8931519595829275195, 18379893031942930865, 12120980098075498008, 9596371470855895261, 4133427878071274570, 13159312399982591699, 1639865074052258019,
-               1661696187746428348, 2656198437014978712, 13769477291975851694, 12512848714492869444, 5980926616932344693, 15821983893144953005, 5816015630031200526, 15887565799959254415,
-               16463929919291729278, 14920112063826664828, 10056471508435050704, 10696267144984026763, 12049530292963090991, 11926086636123189182, 9464890378472966538, 9719194510330239601,
-               18110249193861022779, 5612784685592189906, 11360454032996393150, 6795401682138043705, 1961398978248902107, 8999847457729547905, 8941741619641401180, 6086938661427918241,
-               10153847769616409178, 16591913677701651064, 11369151065084080884, 9493662847124813178, 14299126668179023903, 2451525064998641745, 16055696673728703463, 7600736037142850105,
-               3331094657189179723, 8579232659787725167, 11007434086335446933, 7488529659250917009, 17217317841029490639, 7202184784979805220, 10955913831459448069, 9000508720500651545,
-               12966352809478736412, 9643078159289928329, 1577471789984999485, 3065864601417367655, 13683627106599504109, 12782093364215596525, 12883456287502344466, 384144415368165580,
-               2010495664660209855, 15520744321638216967, 5385447087428594566, 12897496516555487055, 7343279016502952747, 11323820480524965410, 3414484402519450292, 2497721392671865580,
-               16065061175628739123, 13981641072236579791, 6942197664821630380, 1667302033233547783, 11254994815452647404, 5265777633437443003, 1242523090981771320, 11333562630675377559,
-               13967113064180443992, 10679621597408504672, 16223869620849920309, 8813286726524283182, 2000697484240530777, 5417120625530117302, 12109041278382745291, 13257693171778388584,
-               11737174095432286870, 13459661128718998448, 4655386724404378836, 3119616752887818891, 13324285182058113375, 1078137740985006431, 1610820303976884986, 10433300853468291587,
-               13552049979590080822, 4379357932546858489, 7594644709024650108, 7268811721525297059, 6728671136192921869, 8183021491392757516, 6569378188404015319, 6481294988812800823,
-               6071501855022377789, 3805172128285889052, 6802689634429908933, 11713310861536728752, 18291420299754708339, 7582277238191809023, 6183429490206797252, 10452668103640934631,
-               16083971675285095468, 2965035896159234764, 9379493912871845724, 13109394112987303523, 231416620515766991, 630445729708227114, 10015412267172773636, 18104521419340860951,
-               13169770634232644390, 12462964563528956096, 2689434882719314440, 5936289129999384022, 17773436345927091892, 2631892834965929605, 8167719122803587721, 2458223071457452931,
-               10744932251818515465, 13367480890778627284, 15909410072235544918, 9252559547875570290, 16355895225285344183, 5115003811789024567, 7369371640924666845, 4586532908333332092,
-               15999516281080615520, 10972478396135936147, 9002100275598932738, 9043399249857967875, 4975188939801806064, 14240375126510021504, 4497218436093285729, 899858725260616391,
-               4788026362409273347, 8940774760122210910, 66616358927988247, 13054723206705508289, 6256911511259454580, 589353691478007084, 17831732841616807303, 10847300659030294141,
-               3016120727980669767, 340560476433708073, 10516500208515875331, 14933811541787518485, 9941997565508314935, 9752941942651093949, 1928238223054143159, 16147782066840428568,
-               8953947187833770878, 6627103431982157573, 1279114735725952920, 5378128106441279737, 15447712974588571571, 10552843735673449739, 14956126644414569830, 1994513099978508850,
-               3339871688614476269, 2937156932445032796, 2071344655111136329, 509603454456841298, 10929109734329673813, 4531629375826317764, 1802431569220697099, 7971315018970882891,
-       },
-       {
-               4307546666223047416, 13914498777427309061, 6812156124789414732, 1680174913762530491, 6756325174405757110, 2535144759174364990, 11263393915003278429, 14767595249676286403,
-               6981289090623415465, 8930069945493884157, 8223216504978132408, 796477795300774057, 3120155459209743472, 14825603392456550470, 3711879425019804830, 11041054473536223927,
-               14135544350792474553, 6171419888118563156, 12495035851387242130, 2843310747449412555, 5668766087526340552, 10117858698838396246, 5181027414039980750, 13247490124270426,
-               10847249691051757241, 13332329214721571156, 12457628412284474075, 17044657510482764070, 5218221397478351943, 6922630493693541156, 6207927102810766143, 5644846665334649748,
-               3169200533952511826, 13123046990387029463, 10303462306703730135, 3315008874027436174, 12427067008037332041, 13190195608614554888, 11930408619792340463, 12881268563913740396,
-               6700154625941523096, 796110091507466427, 5388163944686450548, 3113104467109529928, 12930558649635882086, 7536049463980825715, 11851825635055645132, 2654888532632283214,
-               17530163750522835336, 9722612350417778827, 13244522480616169491, 13740964907388846002, 793235549667461791, 1998252773625399730, 9697911491069876538, 3365596945186794622,
-               6506371904134856034, 9541373683805144018, 3149037850125132851, 7111810601994573897, 16732445693192247884, 4994069681898274622, 7223719243730104348, 5649174084086150712,
-               4640203560336739679, 9900565149463137003, 1093715346388527458, 17169722430093991108, 14911871124664548213, 8091096017016862097, 2911569128494944136, 10192934055727569503,
-               13251895658744991883, 18083873142202267221, 8241707078409323349, 5240943892375002838, 7329419846032881810, 17784005510850539551, 14034072243705748841, 10459194866755836024,
-               16396304393792022741, 510358226971662693, 2002127643935690257, 14681425695950046262, 481902649451190280, 1717807040845239061, 3358903321435525144, 12361252150277163759,
-               16562962997045986629, 1977585352264948582, 15588655103333244279, 253344970359156714, 12939363813291366775, 12548224526376199974, 14450582788883748364, 5869541533939881460,
-               15346378007864735078, 9904337403373774864, 17933855382993937953, 9391248304932723816, 2250334275383247202, 5978804056136420670, 1528238852592364099, 6491566547950141733,
-               8439860020828526478, 8674532462170555517, 13889716766953024111, 1166696901054897271, 3599113965286446905, 3276801695553601157, 6631284861504552600, 757022358659145685,
-               1117291222568805017, 7148845117809308441, 4044258438241699262, 16593433123496068718, 13992202310165134218, 2998204381658279116, 11137382784909083266, 11972581616612094469,
-               13970586842647892965, 3680317572634289692, 3416494470839852757, 8341497967750607131, 5522860734580749818, 6847292760525096386, 9317394708872196559, 8522252330730808934,
-               7951036477225560362, 3718789111033607646, 11667291286820266731, 6927579620295878614, 6796746225018555970, 2070061401518338268, 2452626412419851405, 6130352643925327785,
-               128317967134069640, 18241952544586374251, 10689311587315723515, 16537482248073764435, 15914436258832414511, 15518344078557945167, 15883120902045970449, 16251109112716994957,
-               11957637677355945602, 8965882791601648704, 9390723380463051523, 15025038333096274711, 14983844148312808973, 14488574793452236487, 15795526425513195718, 11651978879566144360,
-               6838341670149165895, 12326189699069923388, 9258908232339348843, 17297038041466207989, 5242182985453021593, 9648294165629935142, 9715128265517308395, 2662662536493743894,
-               11289660454922592938, 470300170724369955, 4571871646010841181, 8724229358245178735, 10173959190953118810, 3611286966550223594, 10810806064515103403, 13571898391208639897,
-               6782514579206442308, 893150666351200058, 2099535232722538223, 300696716419619813, 4778737709473194628, 16786610674618434170, 1751624209281870237, 1677055321500839173,
-               8950755642341912951, 1974922263791844623, 5333377426024439800, 13909803085973342843, 7639604505882407937, 16195074617613125552, 8954461446680048430, 6823359994465290754,
-               6790869670806738567, 4499989093713728199, 17496748050437205626, 7194829324969293638, 18432532588985091708, 12041300075343806904, 7788543067151959941, 13703334460383638224,
-               15088053026772564466, 18172984562199594382, 3119317310593433742, 13835498717175822656, 10015747176747842576, 11008571041665092033, 9377877781626879674, 10465443099481589185,
-               8933481722931715231, 10811948483433850165, 16314247813274714890, 503147444786527544, 2533443680646505069, 7617720894972668760, 12477410920355308950, 422423516920457876,
-               1501843276089632258, 18180777013307233967, 2535426997299341256, 5318958493284100856, 16758265544916918856, 8118598628492446123, 2511013049335776232, 11181447982017705826,
-               5996381448168274884, 8108757135223610234, 8067369725584584297, 7184925262427750366, 8199341143188441284, 13031376443169557016, 16036606349050125404, 11958720833222295864,
-               15336831835795822898, 6806921200736832713, 5959923980569572002, 16835674225684329982, 9985579070716031367, 6517360043741716503, 16609518082836868591, 15878184747124924573,
-               4786224758360153905, 10283234398763800487, 13695837902615591472, 7260571034197533442, 9225062953237806971, 5969706575516748564, 6537573986766117532, 15754484267739133126,
-               5004791824134844360, 4971286291135250424, 1811371968353107289, 15772458387007519716, 17381493577383518445, 14326903440006940586, 14237922492359728234, 6234116464684325431,
-               9293668142017263584, 17134656749295164870, 5879480323258506465, 4788695233340705697, 17809277710857366810, 15157733645094688870, 14143869691462709080, 3162286338158090229,
-       },
-       {
-               4471613312912718060, 13601785177495103328, 8083849806888905297, 9053545412554844461, 1876605639999952155, 6124537911475118673, 16877891074567085688, 16541720065079132344,
-               18138305348849897995, 11498878557125400853, 14125346336359365201, 11991638807788804369, 13935355764550912568, 16209147067155729660, 11086190285777019292, 16727288863943596410,
-               8873152377611229668, 6260821826956744083, 11489383533808918262, 6585112195310961861, 7365821041919648819, 1936165695028211587, 16164747634991415711, 17957320776652490392,
-               13065030057172289846, 7278765836407486850, 383827150208081081, 7832055893191054601, 5249323286889945617, 1631661912887095912, 4431088469837785451, 2866263172993336891,
-               6140213328062333551, 16704025329777067037, 5839832043209342792, 9196354634862869885, 2735762290983671190, 5323501742548818139, 3199127466610501482, 6719610946615763192,
-               4032564124345275293, 240208626666701335, 10264845378648897042, 15608289126091352415, 17866864241918154829, 6207477318890336372, 491708931325462670, 7002400618323099260,
-               11507747783030541234, 13683043390668171754, 9924966309328785763, 5549516466627385909, 3724001483041449858, 2408778220985427590, 10510707601023430105, 12862520912519186496,
-               5012372868660694231, 12033652755433827667, 5960732801180177919, 6089487525155575261, 18400192045204062277, 12754175136438960528, 6170965736016609163, 10141374482047067946,
-               11781193922347227447, 16937876011211881637, 2982972111293427964, 1728244726890919596, 3327997232304084768, 4754833121145407334, 5871027825507908591, 15772493911709624273,
-               5862944033912881884, 11132730978666088350, 12167180155548291888, 16449838286695349787, 14399676610730016345, 17071083123672650337, 13727728787831175379, 7507765123422748291,
-               4883057314704644529, 6606742732149784343, 16070555141087563722, 8408294891669305261, 4298316003054547788, 1573237855902568238, 5357176885445018289, 5855732582172939202,
-               11721126538980357625, 7216004194033429913, 12765889884935948315, 6003399149613653734, 4571046290325663920, 15023470461830485075, 11463513436288928362, 16135217522406374542,
-               14300855104129153291, 11491527690078786162, 5674183453812271017, 5044682546652747711, 9153978680942338831, 400454762074409409, 12351470849648616331, 10559229320903248832,
-               11839166519633311143, 16489041153719856002, 4820713204385149226, 13768001962143023630, 13107713406478328396, 15471245828032402460, 6733652296473831544, 7665657127090105428,
-               6114372925011600760, 13061069979571997963, 12156991017966837826, 12403009591138383583, 5761958709898299258, 1907771304051897263, 3007439379929412593, 18410854883912163962,
-               14408045416865494124, 2442199381796557002, 10475326303775862953, 13637445125954159957, 3778313603630758744, 9247460369874272772, 17572237597883145087, 11338350096360776602,
-               16486104352829691584, 11856560607954368882, 7574789609701925021, 12240083183242127118, 9872957337376856275, 11508929285199799229, 12084460294902152451, 5537978390111837838,
-               17987471707896681874, 13038244305326284081, 6130570860032709721, 13697749322780057427, 15250226813583295859, 11214437899623632196, 11227424166765094355, 16073863048822462466,
-               12399110995748365941, 8259021120978314016, 13249466772279340115, 11201772702582865107, 6680428295197296613, 14825065014187212998, 11638499193934854444, 13944483483619391536,
-               12792956896156056673, 17521293339475028823, 5738513258925006248, 7070317930523546296, 11175557000762820214, 15356683721815441509, 3038847573301969409, 3712495274059632476,
-               9703339902904468931, 6903532388259237787, 6598718994389707957, 3524767540333384210, 17230409287786477986, 398508689507908728, 12956323124513250470, 3050411724956364887,
-               9936181795041159997, 16502578966693139346, 12331385558134766329, 16368402633574222539, 17549179704234998175, 16732353056786161257, 7018642409136068141, 13907639522324102590,
-               3202436334590923936, 10521323531132496064, 17087322194145514933, 2557934785422493682, 1054672647095378624, 13197226692868722325, 1089249862965154915, 6479925079582112772,
-               3880905381896902231, 16702686708922296685, 9815623322445801304, 3275100382267252573, 6882533095211022198, 11000715667767797665, 17615808190378608947, 7418883369171949489,
-               15109802007060416273, 6172716471862133951, 10675428021956965140, 5719399515177959211, 13414568332401128475, 15437234656470291881, 15174397947571718085, 15093134682110367825,
-               12767354263003560893, 9423701226679222965, 15980976879563466685, 16370172902785037004, 8843543841582241065, 16817827501960591898, 1524531339915785994, 11624580276885598157,
-               17147068462804570503, 413038056092618151, 5178874804057490245, 6267545065511948977, 17573054445714024932, 7120476833739422223, 5707115123830922617, 10971108972695387841,
-               12546478152711337402, 3213958910433616233, 1066524299473173792, 6276669942370566610, 14816818963020520773, 7372806616674468946, 12220278123497641030, 4953625488417522128,
-               9443607421568920607, 2583030461169574647, 9900905053299561307, 15892418329702922907, 1184158607153919924, 17842123060489837980, 2681791639846598155, 14394984710894548047,
-               17363678829105605076, 3907856148144141388, 7535915338133892356, 4354053943074081189, 9644954727645503986, 6816908226661921388, 15867806610099035654, 13874346146744695721,
-               2654416582410062512, 9232324386948815478, 13864516581612906345, 17132638924861000235, 16875312639179645137, 11536057026563830119, 1090137303802556590, 15667188983774010898,
-               4336697789732072031, 16054848662858822197, 17934449813415035557, 14518380622432694666, 14100582434152190048, 6262866632984449325, 18069160441815400774, 9798342103009260692,
-       },
-       {
-               687104890149081183, 1938816743979859301, 11342071981175913904, 4270322127259097184, 4964776270155503160, 17849333582861534767, 15814479527332819692, 8083943565773123408,
-               3986890035154628803, 15316660330065019741, 11560940574529263780, 12576851520091035878, 10883944418224886092, 9908329441525486205, 11238684990962507809, 12900626758810151662,
-               4077800412543228484, 7173833470188867493, 4604439809988262876, 8090706047559948234, 6117166546062912279, 15748537214854486946, 16719594636199001564, 563850925691991999,
-               7109145612337154341, 10502845970727626855, 6527587047878193251, 7049690136888681718, 16750703006415156202, 2559311261501721445, 1222802194566919230, 18019462938525560766,
-               322982839910423931, 2590270731903609206, 14012397059804449007, 4254569016772908483, 8508420263334539908, 9175848619353159735, 9777676085150569067, 51565612432741329,
-               10233009747926770582, 4858065366607044068, 17837971428933010861, 10016544790726166742, 15260359301638740999, 5101999662344938158, 8809855615759524306, 15369468763003019252,
-               4549989329927399868, 4866130696079291940, 2784467031729859937, 12617898982021887868, 2721301974598150044, 1014232218549205942, 5446756626431953863, 7315134179045561903,
-               2592184418896595488, 1723751460114310463, 11198512454461769811, 6203707848404803677, 2601731234271436477, 18186700975610533226, 4757569424831899615, 13359873383138312209,
-               7339520839328992093, 3349084091338116256, 16532710170417471614, 4425958052714174548, 16833748535746803845, 12665172019028452441, 11274971974705134171, 6504206221872290467,
-               17921256304121537300, 16573867650874642543, 18439217559900658467, 2917797231317530012, 2415475159165597656, 2027542924210178369, 13542535558170959524, 9428931592662127870,
-               17821420552135083528, 332847653840014838, 11832506312426064436, 8314663852639826188, 5744960486691350299, 8069724388577179929, 7949740770152910898, 7431049632429535950,
-               13904640252203718708, 10747313134117021792, 14667070697514384141, 2600977347774743546, 15498986940124021079, 14740645313274577011, 17403811028932224808, 8060102076475954685,
-               3517334016249952489, 10826317205305313746, 9664766330892822745, 4145357045596983962, 123566849370572650, 6452080295201963409, 15558941970553263818, 1191650177320171029,
-               13303794914626036653, 12135860919529132656, 3620217653879289461, 5443663950311568399, 9020744500355505374, 11953955628401776228, 2101814526784564259, 18218598416910848525,
-               306945432061418036, 3150552227215797902, 12928374347433953916, 13299101042862573370, 13702883318367407795, 4879985767563062391, 17591048490944890593, 5088664549487213106,
-               12990649636107730851, 13002224935892458030, 4380799638612122791, 7935443787987894924, 10438069978940053126, 302419699431148366, 551508078777729872, 366155636877501719,
-               1657628676376133571, 11398060401420699070, 15376723048512638551, 9875623386041366116, 9978954704196888739, 13768323245406799962, 3568095027938899541, 11120740210192996096,
-               15561317952331530901, 10479759083279078649, 16536004935523752634, 2928518661531554130, 736056663469575928, 6131440330717529370, 11275149343392851570, 9601030074480228347,
-               2397968519718544666, 7793046606567840651, 8971792946996316712, 16581860514259510747, 9067804351225143661, 12322425857061932421, 10680196669251962457, 7226521395530060461,
-               14734735764746786753, 1378251478826083755, 13509550209468602124, 14458158239096821346, 5681313138148713219, 9054039627425609375, 4235536482830620712, 1502753755874778370,
-               10053374816829223121, 5956370573575798562, 6842782625116195714, 6646143553705917790, 10487617951080656190, 3930886288654953669, 13141858447548326172, 6966039733711006320,
-               3565931266726110263, 10142260659118036168, 18315406451571961983, 16857333990691080595, 6889519058362658033, 11812045051361479600, 12503117299646153207, 7223531498406875484,
-               15243128568488310595, 13798032762330794140, 4456440673105474920, 17896260893739107970, 5519537045179649847, 11908888770632658821, 5444504459295913107, 5588728973482930155,
-               8914021876030553161, 9071747156187788379, 14974736924255494885, 17070198435868341999, 3643991391224035758, 260637732328275649, 17609644917816078225, 2302996326941944665,
-               1293835161492069734, 5795029109259991590, 6978986253519330084, 10360755458408067486, 9467742127861782141, 9197981630801498774, 6297600026339958279, 1375635441408481019,
-               16875086338187280639, 18188722331528885957, 2047282716697647836, 17808297209051779725, 4756860180475663362, 16103863616340614471, 4416311024167936572, 6340715229216403079,
-               14261984008515151673, 8778722476581699445, 1624620854396291363, 8490568310899028272, 6147263592092458803, 3717414274397202281, 3449154725620836174, 13526832985450537957,
-               5888744936142942064, 17277140802638358763, 10290028650289820825, 1940657436863195045, 10796401239257150661, 7788083050548605852, 13474393003015663489, 8961936186303685357,
-               81364364291228199, 11636155122637141142, 927710893705810893, 1403208391464987879, 4332234662194589819, 7913319387647351094, 2589089673930123808, 5387282875974124558,
-               10611669207938469024, 4491327257859270050, 14129391883837344111, 13924810848449766461, 8792187899775727862, 15048142623570073200, 3933861866144269656, 1162055633060412126,
-               6883724061714130987, 10416279294253729103, 12247033224345499651, 10291073256885105234, 4480789666471481188, 6022169887991948086, 3778647272347441051, 9527380466585130391,
-               16407225233842256953, 13423683834633513951, 17454464203550700633, 6033758555290610449, 5063673994339442907, 12250392784929419939, 5954485814444410119, 10099095370725442279,
-       },
-       {
-               7669790431656261769, 2776517632462593286, 11694025667665633506, 9533794089008895277, 2895611631120558023, 11551410655448788956, 10026541900772270925, 6243136875017000843,
-               9434484992529186384, 16435748047660609525, 16190660694150989986, 7083965852434071085, 4216306437741910756, 2698742177539497614, 5199793642504009017, 17298424769819019160,
-               4041169394784902550, 5699517344009382913, 5306272267462320559, 15846674482556330025, 2606351264228884283, 4162585980422107281, 3715151019132039005, 6607223447043258693,
-               8168579295855409503, 16727569921530031841, 6182114460261837773, 8940603165471931374, 6081572078077526926, 5890840443923124563, 11215305828294759727, 2875117534361804712,
-               9045974983664041829, 905036705033699463, 6962033946652121779, 3027264198782618401, 13786415307358010100, 3643342525745067473, 13641958783381681886, 15675065537779359584,
-               7507377696839752642, 1061259379811757443, 10276590160392917813, 6889137095037822679, 16373913505782725550, 12287733095803524526, 5695917172259210496, 6360958736925918808,
-               7459854586357006968, 702429387211615855, 8231296036461604410, 628323703857882004, 1059802628602873385, 12517208225099517507, 2368172548334856593, 4792344750094708709,
-               18352334786472886037, 7096021570596476676, 17045407505128867173, 2467670847537319400, 2225663888244226889, 1876713214939672742, 5329943993157142620, 12168650975912182188,
-               6639850268372381409, 2284514769224558945, 15390110317831975716, 13933785559694229008, 12787641603764341997, 793886210532292741, 3222136169196008839, 11104892506868626444,
-               12660547967989039787, 2109392063597767300, 9889743271997754037, 11803327596624324036, 6940409327849314286, 1466399127363116843, 2572333022681966275, 4216097356402537802,
-               16858757460581672909, 5838407119753001493, 4453405435911954669, 2828665451507432751, 13657966632733241760, 6875986784381874300, 2390233934255482553, 17386653779125555159,
-               2976756344404126744, 17032556609402836559, 16348907464011574182, 2196781021202618892, 8270822867494340805, 4738372358350764889, 6088256422707334932, 17121369334507507505,
-               2081729301541563384, 5577186154173396778, 1865152567701500436, 1422284589642218069, 2489023909725140903, 276494395149046869, 17420927169263487236, 8292343688801608074,
-               7819174654675104600, 12778055482430336726, 14615848543490171611, 17498415175263742825, 4785899184222234034, 5227136636239697699, 1570704808469050246, 2858953380860123257,
-               4323577007857413306, 10524228743339400397, 5418808897687027557, 5939367271366264075, 3569359126353670574, 12961495213964770607, 8906990808988099905, 261084295374207271,
-               13937553904380032591, 9165760362893872288, 14159606902675650669, 7794101517494576908, 11994596892880464164, 16211278212275417034, 1568324133241165712, 6579463633356173526,
-               3784436423124943604, 14504130598322564217, 13343318845201913758, 2617267381187565844, 10063945174501910869, 8584806992850354016, 17494557973113338328, 16987450461117846543,
-               3191556545349441897, 4780077336463115599, 102121356289129288, 18353108394754479957, 10099934050411322327, 10323433488737585897, 1480832277301232858, 8304664509429164326,
-               16494820005379860880, 1719281141269927630, 2983529566257876158, 15928721259545722550, 3714203000118655889, 15922105900709017310, 17662263539397115758, 1577461381995722723,
-               3426958921435818822, 395886748655323570, 280632942609884625, 4361473570148050146, 6600885194277340683, 16668323952296831943, 10057749804882861513, 5701592287343868424,
-               6951585494335471689, 15680855848517030170, 9776921814538436791, 17640230976984644473, 5777838393869379647, 2176689364164694052, 10884627395386092313, 17656310368333301757,
-               215205608065278414, 15361057989137229644, 6756215047166430628, 12215084297877052825, 7185815532109454500, 3394755837885079236, 1778980761557523977, 1861969072415300655,
-               1535235777601157298, 8875662482214652105, 15404846185148709157, 6538418983879634448, 8341745508628160868, 7582603669233291629, 13003716464169800826, 13309194956036155778,
-               4791947847339351337, 15204996809755844932, 11672964318683763318, 13067259871945801803, 2139419248113049376, 18195694858089271989, 7208559250123396675, 4671149208567820584,
-               7276586425415793787, 14549539461274532692, 7381249250982432115, 3215735370879771405, 9197833835152018601, 17236122023193655371, 5029275100388702506, 10829687080866991082,
-               15533362570521057331, 6942829144635570952, 9572990445468151820, 6294042535380467396, 9052929167426522790, 18293430694900525497, 9076155092724374912, 6410242671697688127,
-               16930844972313552415, 9009509357611549679, 10722442939705348974, 4686888495512108749, 6326319203058274828, 2590592779822711917, 12876493112068819735, 12372064322375408146,
-               11938822647496400962, 15333527667419199710, 2385985954862343680, 14776415112244140169, 12817753724474105460, 5129368568396757194, 607898027127847045, 3917240453172744497,
-               47211231428738650, 9333275559955619158, 7534434473427098199, 8557232404317963052, 11597011861056629671, 15926835677212702441, 17943276685960195536, 2513989430679125485,
-               2903417389682946131, 15905578940823611094, 4910425097773753648, 10817415382143821768, 16356392378927186116, 1174713154793914656, 9176413825070952738, 17779105524945038711,
-               18302140065591767046, 6334261306636966429, 4203057092695998640, 2740754645452686340, 10020911575632378009, 5906713384548665207, 13902791548718280892, 2505591245136304093,
-               369660229032730089, 11851915833529805698, 13485269529443969890, 1270120511649175022, 9128783725626301238, 6173048611666804214, 14151404531169195672, 18241008099921643437,
-       },
-       {
-               16226789363155700046, 13734705589524056856, 9629995513492843231, 2636144377026081617, 1233405076007260313, 2119672919365858964, 4932766292290315579, 4185117177904214366,
-               16996170392430604056, 2476294162951949891, 6677439492116109133, 1649550562276235959, 7307278264575968221, 17128676264244010843, 9768062299436691373, 3825325732056225433,
-               5861627228365499618, 5011684805137210454, 1579621475012951778, 11535371650014354624, 12847902922833318241, 4997014846790385136, 9875988184618650628, 13094082946822736823,
-               17224650011872599657, 11430188086182976152, 12892063618843720029, 5912993124689510433, 7069617917494051681, 1298012103142698333, 7943359430865057535, 9329776843721719539,
-               9091412025380293893, 8622355764644651307, 8718353412518918238, 12338548766610785709, 5241721208413391572, 6315749100915178625, 17919741546105181107, 13677847475856526539,
-               17388254638056933809, 5422523708003180288, 16851423629233109043, 5504298365310420423, 15145549220326540137, 5184279399795985462, 2201159255780420815, 12506121988996036804,
-               4460258780042860751, 1816027820333214126, 7778555198679811350, 8155451943744426012, 18392325810806023014, 3955295139981696248, 17141295608995204052, 14206938573418983337,
-               9464085603669036454, 7848014338005901108, 2368914226155404065, 11578416111848517850, 6323647866244499941, 14399589996703947996, 2824522520842155768, 391310842153371124,
-               17489550078249576530, 13418700716683405568, 8265132837103985034, 8386855948619700037, 4642739669076635265, 1941217860224507563, 7402267177254210690, 9863923110146355168,
-               6176679707488254741, 4307819088229734202, 7082712522654871200, 14603822721598353371, 4115674343542702663, 4132348830250348245, 5992042367418590636, 15937819366199058986,
-               11008669567537833607, 14841150752801539889, 5253470025479549456, 5665837575328478629, 4601810548582757669, 6173003636576141170, 6899193615399367692, 968231402917393055,
-               9948650801233133770, 5836115460383443197, 11404170696974449207, 4791020823967734476, 423024247809958592, 11251668387880260801, 5562546584223492723, 578572156618131794,
-               13456676488167240303, 17121749146829956377, 17370555398500311209, 5041791432274350681, 4009412063225388868, 2407629981571159579, 13052555280728877038, 11483117063845312302,
-               13421089948800544371, 5001604265596626568, 15312985179876036482, 16032805766802337150, 12508684642650694186, 10422897636519090240, 3970071218688010847, 17419166239676042564,
-               400453640980208069, 15220637399286523210, 17321057148174216619, 14860227640908306879, 8047994708253288483, 10174040071518845057, 3280567772472213687, 5651529697807929627,
-               13988854693674964723, 10817154032069031941, 3171651998645961547, 5518712225783687705, 14706905091132091970, 13960758460934966876, 12141035142079693145, 3149939820435101269,
-               17047631647660916802, 11327141967045825261, 6773994317182166280, 5064726840218426586, 11921340002806613391, 9067034595359929709, 16499225867422892436, 9333282251383805811,
-               16851791401266483516, 3629537449474963381, 9616439067014312078, 17691280261538133313, 13915291913519800282, 4229243823856128517, 5998682815524220834, 18293451622818510596,
-               13740317056016164038, 15410121987858832401, 12080671504470100936, 11635316325777860129, 2584464163154495637, 9849046399519426256, 7991103215010751716, 2109987257001640948,
-               2505301881938098126, 9962323478923652140, 9312199523950444342, 12957822502673689705, 8060810607849163143, 737408553843844193, 8143568733429881786, 18003168270780769476,
-               18361695650419575705, 15964191128341330249, 14834821085064012697, 12512940671502931238, 11592194993753547188, 14358438239394059598, 2876909840522954216, 13154864917311376528,
-               1919485747906370662, 5250174270363591951, 6270889482486194520, 726576673961648732, 5067680336545953003, 3152041783219682891, 15674051618916413369, 12438966377512424334,
-               7755405178378312585, 2001220826274540277, 13276328134279740680, 5464764824709243977, 5374818714652367118, 7988129049563289676, 13996688354532099099, 14091540329663446637,
-               4460927228453411137, 16058422703785787527, 8016770980039986075, 11450941100964860520, 2742597710491507274, 16940752978671801273, 5897441526901650840, 5926672707007682446,
-               11513132526446047688, 2371334524276946445, 2461552185903242316, 2195417192784351355, 8821293936856062699, 17392142102281287994, 4066797133115509650, 10704373174879556404,
-               15778536817306082589, 5755579035239870289, 2105368957367433938, 16043807797277162048, 14990960263520315004, 15618512283659189876, 1020703273079622517, 9735594589053383212,
-               11529096471626785524, 13217557548494128192, 6973227637542883184, 17901194406865837244, 2414269359614891938, 9165268075797348071, 1013041849562373861, 17525420894350269712,
-               5772778048593061508, 15424756817708323928, 11842041259277183807, 17669952685051160523, 5405007811515938363, 4415223809135251038, 2223192286456742546, 15742105795795272774,
-               2844957165101842208, 5188198001787563362, 17071130520794983821, 6691797472842348899, 4294126956896299534, 5788827614077663481, 16267876196920424765, 10795461545625002360,
-               4405006158507706423, 8343317561528812223, 7851955346465616798, 14568481075913348758, 4391527082463073614, 13997921112025001396, 15259963045788570485, 6787776208020191083,
-               4002627348223514978, 16231148554725644698, 9578235186329928114, 14741034641204805809, 14651073646349829984, 1797163177099497214, 982043220105120238, 9027434646723092211,
-               11809342655313500273, 16822704101813284237, 13097372075606737923, 5463281428453250615, 11967866991673525562, 6828790575157689223, 12568831962097805646, 8385980093725157349,
-       },
-       {
-               9246769514475702626, 5788284997389507365, 15857897362850327403, 13864676801095094218, 12881526722328523267, 2620841421323221200, 12599981775316397124, 12820989846844560040,
-               13066648645100247757, 16727492115601921665, 15749471761440498106, 937594351871983779, 8381111811209734349, 10884357918725639691, 781591570669492079, 12778743765298428266,
-               1797915488494232282, 17274756142259274463, 14207994319179101777, 9405903752538915237, 9001743317941152797, 15048752608061590843, 4925745663463425863, 17143694017177138485,
-               11613437975225156304, 8619196433402562266, 11907033287998837424, 5056904365610561965, 7637552956459333558, 2827449950719061527, 9998507085256853501, 9238562885525900325,
-               13246436769495027717, 5445015753017977819, 16266739009580878036, 15566606095998238977, 12196078605380432771, 4854324313875295137, 10974170498288217052, 6425550765546527417,
-               14574824159194628650, 16992289415800830701, 3499062703303067574, 11220872042664151226, 18135860701984580530, 13630928571014923388, 2913126838766947469, 15869180955632349704,
-               10621010745328025245, 14637275395423748577, 12928463178963493980, 3270672471462681194, 11765440832075775157, 8138439106739837848, 10004644076263261924, 12582897670868871780,
-               9605391611675301152, 14014632424042523224, 4638465078692570733, 3013469722048440965, 10972600060210514686, 4497572559400894366, 2652629676209366276, 15827846806499715082,
-               216774559418075105, 7056732230404238374, 4342481467357759950, 16143194646968227790, 12304857685680249595, 5021239809847286634, 745754913624924064, 1603290801266214539,
-               2784418922013631805, 3554650219010546629, 8896448905401216908, 13445015286698819482, 6508982623352460996, 3322529327934132311, 18417788670080975365, 17554108945303789353,
-               17620122226715347133, 9738429733440215024, 15577771434516492888, 12422193389576942718, 18383756008252443605, 12736926759685644351, 16981429110294392086, 11999528928951986433,
-               14489177617081844909, 15995916840320959685, 6361381313838994395, 11146176143708648759, 17190512001934479207, 8406914945663974955, 18073221191428103088, 14075266763636071788,
-               11493260321718935244, 7134447477334726345, 10489281872281557152, 6145540581503915475, 4002857892747271740, 5167943945955725680, 2892864850826359384, 16887114279977647596,
-               16493058314197913501, 14642843949567816202, 8421201635021034279, 3645913604138483317, 6127272877310948153, 3660286308390076870, 14343325047340052700, 5355450922054278073,
-               8426383571761073988, 17627146217941553397, 7396223609641674418, 2402241526082789613, 4067059813672963823, 10306840429023537942, 18342506396531908477, 7249869764848707701,
-               17055119974261943875, 6266720893662254540, 13102139953381148874, 5249314164321788611, 7157525732140787612, 15381277459195914226, 17265025258266710353, 17573500432599548120,
-               11703325491493519624, 6756922948215553472, 10849241105791329449, 4442124988071574400, 13193138084274485850, 11408181130174894537, 16602978650637017500, 4282478513876287613,
-               15849352004835856215, 7022332658299393045, 2753527422472509447, 2508636546397160815, 18156018186852519542, 13445036260276495365, 6279372959444826452, 4487789154840943220,
-               6912674041294744283, 18177825269025993506, 2129493844567951509, 6833453501368177831, 1878514166200306112, 12873954541639117785, 7984716702294892278, 1590286870058148425,
-               13310953099825480439, 942949035351116482, 7073926138905956784, 7700580694019269362, 3135382872993338421, 14860196563555722941, 10662854588851556233, 5736680857908686906,
-               3285730769783013255, 5648284582450022694, 16712547815126338303, 16508335566005209527, 12272617736405465053, 6690178916455692547, 3481505327914964440, 9148348679521508925,
-               5445751308732564169, 15671537507319596886, 17721221564106627243, 379590599139121791, 11923849517192812255, 11794879354344258105, 4802202540817083733, 9502952511912834734,
-               10387170863530151921, 5325952605083195756, 9255511257002170523, 413412942592261158, 2693041233704004652, 14135620291598275670, 11595337134421837671, 1965085859594934829,
-               10567751951694288416, 10466024270444644770, 17138727632883910786, 12652567654757797118, 13864111438265559205, 2552332838857882141, 3739570066357761968, 1439381288436968019,
-               14926469836092482784, 1974273958550553776, 10770915481273902280, 4033929759715842024, 15461883773070197251, 5631323369668498153, 13319268013678629907, 16483196656661792008,
-               5825598074470439590, 15514383036808278765, 836600073173284669, 17006029483641514808, 2253041172677940136, 10109282146738215012, 2050330973627959134, 13783991480192211446,
-               7361422649689322835, 16012782899552425604, 10324124765039044621, 12319908523309013390, 17065808121376215422, 14844145564675640794, 2754581529304803758, 1149534055082731343,
-               5371192675994106473, 15892724499541682278, 3862864290653799361, 15759456296270265029, 12018492462347307225, 11503979417352537931, 1894695486127847219, 15184833349947874986,
-               14711143160318482298, 15515618319260581947, 10015362293284733112, 1169298538214120845, 14481541537099551545, 10304547737174682912, 9351439436434829996, 15807708290724844107,
-               16946643895530263911, 6110142153011856496, 6857516759047242219, 2026267735072107620, 10338469980804248611, 8224240981205716101, 12739986350836865860, 6828408496869642385,
-               18199296108774357398, 10154672256889745380, 1190269705881674139, 2317654455984851716, 6948704988682993246, 7864433505284017226, 12371653445644439372, 16432795124971446509,
-               940679263188661008, 14653357165718140350, 15439920797347843673, 9415587255510557494, 18115037054677722678, 8165849408798239027, 17369387099667572407, 17619066457126678815,
-       },
-       {
-               11047138821675365077, 8918121441180891972, 26692501222219426, 15248413052700323978, 7305399157133896461, 7065644238942265367, 3949166834387057064, 14178248206708015607,
-               69860179712677448, 15464996655458230480, 15095351218136595554, 3792171085643513009, 3187131848664503636, 12713332789590787064, 6278731049699775392, 1597379696359884724,
-               3952205381894147962, 11371446109407143937, 7231851263356642380, 11612512368538303138, 5227214975837085115, 10737565048439707166, 6333629542995218640, 12386725921557807638,
-               3631886121917081375, 14286411187847401959, 1546298555066841633, 4790996540037176549, 9541492152219486842, 12304868498960755609, 11426775785781090329, 10793898029125361155,
-               16970032026045908366, 4739834790205788500, 11604777595337607879, 7222013010088766249, 5472916641327283117, 4172262758310864960, 5724466588558015820, 1116300519629843659,
-               15795014995613238211, 14290583239597353888, 2490895887909073495, 11130992987297321872, 17554999787604367088, 3420129662095546057, 11472786435923282727, 16869713476687852227,
-               15035061229930585935, 453017670704522761, 13269498238801130975, 9381945743239523058, 2560842189862328725, 6461599464735341542, 12067824007347016987, 254830492191366350,
-               10932352970046201499, 5875690226460998551, 3699681560657289718, 8665743594825198441, 10232089728487302472, 15664572298733091969, 7267222702489958195, 10552093353886118696,
-               15492342672675114391, 415437554733257587, 12890781990283079094, 13204935186176658494, 16394061615709463286, 5115734945762570776, 10421418042968619739, 5523853293632283162,
-               11813086056645720947, 8830149648607040713, 12579056778157665738, 8379445845509747387, 11968812374998926933, 7579079245215672446, 18392522237039663466, 14209436550919930092,
-               10567400467353853420, 12039111362360014956, 9752698954159464580, 974455144078370581, 16749750902684349652, 7431880327875076520, 16572811640260132367, 197121614392940749,
-               4008236965647744142, 8547116629188387980, 13874587567755370880, 12696453513706541959, 10752386832421030566, 365775083075323708, 14295272684753058141, 11024897725724291722,
-               9389823976782902582, 12987864137510618346, 14351996708263571593, 9397276818616280108, 8943695845699072910, 16761881794918812428, 14395546039428720745, 9608138420173912436,
-               1876375509629583057, 3290820252719995988, 488255726920613097, 12524692306565281959, 1588481057230489293, 2737168321842385117, 3787136521155591587, 2297952115270241626,
-               14002797112021507101, 15941913959379016886, 13373428680779564378, 905956693320605119, 14911807685762669378, 13046351903511292109, 5010776430112230246, 13569296078340893444,
-               2399232949134869057, 16408469118941953277, 17229778225562184411, 15990256768949242309, 10694906341686584836, 2816242351659628719, 10794163145486835660, 15601904974333104002,
-               11025280186920123511, 2638544612389113264, 14138782464677956897, 8182901095979048555, 11304014986311338849, 5418181013691186545, 4702887342992202530, 10901371551431733592,
-               7470028071605003558, 15552389775050890646, 8285175978626575302, 11755261053723122966, 10951094485216236078, 5507384267235142469, 13239757172982680465, 16153920989213321821,
-               18058993449364903238, 13898361855323379776, 4830208064835445821, 2108287244297002782, 403367259355957679, 5208097191763320114, 5105753392567780820, 6874403921011777407,
-               1158521281204350113, 6232098057848694897, 12517518152351190341, 17852831094628421272, 11653774695260269881, 4420518556213490728, 13835371272800239099, 12119809446886544909,
-               13202632776652821767, 12444449950521044637, 11128589812117041029, 13640351754206364654, 12210309609173025143, 2998033188714623978, 2790558847086549679, 1412882974937756344,
-               8872627396983903111, 13010748252899511409, 9503554222158928531, 17266043773425260257, 14299273669130129568, 8206060595465248374, 2391269797717981426, 11490348680137544215,
-               5625434013536513462, 11006046905736534335, 12974260386406529669, 9092861657954444193, 9064784322822166467, 388172762639483312, 7975459140038679785, 16519143691087724914,
-               5143546864201185527, 6400878864024957342, 15513803558106064076, 6712861984922181478, 15623960351786428150, 3094277713920675576, 6184647748693682810, 7857605928718754519,
-               17306606255667524897, 5112741148301782470, 12807238528895999857, 15137864759480529337, 14604908573844046691, 17945466774813936069, 8840495514948749443, 11197321446299638637,
-               17220811598578674405, 4438480777123093236, 3563461541688367236, 3111403934731489046, 16319666149508644048, 11775149819643332554, 6467838040542164752, 1567553021477840718,
-               5384669083154912160, 17619132083131362037, 8938889855576647487, 9107335704092137106, 10077424566800668390, 15550874273916351174, 15171215175982142697, 15277375103802490853,
-               2219152199405421709, 5367881810186787185, 9606063680551349934, 18233690822105957780, 9941441403610160291, 14996958158691873775, 4936282940888570414, 16608409936766385729,
-               3344228690528365773, 14741103791830625697, 12105806333035047780, 4814603778329751458, 15692542571489717296, 4074467482166609769, 11583878004635312071, 15057041878895842153,
-               12046059187840675577, 1106267261822046486, 4800396230944794513, 6983782857932290361, 12630891077786998995, 18331269049237387531, 8843236455524152484, 8233277245902259517,
-               4072376012468301087, 15956856707868364136, 6651399164294705117, 9169559249495366525, 8774931051408681195, 7328702764302633441, 3821510551720221090, 13559321821383641691,
-               13270099407878039596, 11569032926557804346, 7759575992876193458, 8239088820951102451, 9633607727685959064, 9775909232917811341, 12297921731498614906, 14756100221590046549,
-       },
-       {
-               5228416958727036186, 12534300056259911378, 6859045937063682340, 16561718753727911412, 9427589074776024847, 4167904055656501509, 10156691045253563236, 17557096561606923049,
-               12847261474293104380, 15935635664155479706, 11956861064550631146, 11743590506948225647, 15973092866215748716, 8269726904881958353, 15639962392523441528, 15171417818360069012,
-               2605212343977737441, 18393471024186189813, 2302707671753008158, 8606549841034095192, 3842822953634987820, 3094721493917442423, 6408313759447502937, 13486364200254727287,
-               2191808101092881088, 128992526124656216, 738676021426139131, 10157323147642681558, 11221959943853120586, 18255489816550713347, 10885231659068427649, 12104397395119665023,
-               7707807226411417919, 16609863548699265350, 17639371636697428128, 8755472387723764172, 164779854477783265, 9714199241756765614, 3491355372893948450, 17683742455036967163,
-               13595758632462338296, 14515163666150177917, 6720823780841221770, 15071435664343609336, 9016075014492765983, 16881277609836316886, 6969993988115170067, 15419704786434737070,
-               14933348768149415725, 8499210770493553168, 6778840616148281272, 13282837866452012488, 12007326272174861053, 11172739862019218274, 15202495365302649711, 8797477675597086120,
-               17862558746132168231, 4941846130090682869, 17131557654945008226, 5312800819142473968, 5818269467205924209, 13458582047859447022, 2683428091382447153, 12956887954464730664,
-               11820752998821943867, 5623379642132478491, 11666807493120740820, 7241997274572162616, 17165010508995490690, 1769225877906480182, 3814296306467163522, 1913823003062817434,
-               11936813336110488997, 3878433838529606580, 6540053284493149566, 10610279324743393563, 14079852809920102066, 9176732841330794388, 14287311909822853963, 7146204303626670196,
-               1222343790928490335, 2199405396044383670, 14080919887213592148, 7341303626667347624, 11784881532696657518, 17307742911086150556, 6036132721599132043, 12167106497065306941,
-               13817073203406999359, 7220729284169210756, 14908407498603601482, 13536224989620701632, 1615171540711527931, 2063856048260214664, 10622581435417474559, 16378505765730768032,
-               6855676470217754770, 9517149712286624325, 11080380031068971680, 667425509348698033, 6136243307299269825, 5326577850303193160, 16120190278345757447, 1982981965726975383,
-               15399454106099176868, 3988744407816581672, 3596277710300384050, 15129113714633923498, 1554582462382333698, 3164553872715651710, 12729140363982748426, 16366728035709811784,
-               11647936211409428873, 14704462653811533865, 10005129575282387925, 1526194796943187368, 10906326807488904308, 18256878690674435807, 13093574545395154003, 12352810226542367406,
-               15290817014272444879, 8012864091692295774, 7591940515496590516, 9299619125326026848, 7297256232167521068, 17861204372399797627, 3100022958796565106, 15313770879200204613,
-               10190931844127971311, 4449277895844944513, 18060903840299422620, 5786504870079014862, 13877878835839147302, 17536010013969819055, 12266576574650233794, 3344384108564085445,
-               10406231172694378191, 12785551100938284935, 12210880209800471137, 16615829503150405150, 11718424737227538631, 2245674303359461903, 9283401225508960391, 7699506693893764319,
-               2278745583218618906, 10638058115573097116, 5685140621618740987, 7758115175926730915, 9043786871908073988, 11442680114439652875, 15805407285446479015, 17615595308217319903,
-               17127838629068819444, 14692086977823146619, 2491742894643214379, 3238012827598604955, 4066194902402629617, 3613111175737094005, 3296022969960608152, 4860674720288543209,
-               3753308721541654311, 13160824061458819791, 11298768140351857216, 14042645015841972579, 10518697187157549363, 9641851844202952198, 9254393371864075771, 11429987449073904258,
-               2566815986599406395, 7824829323439900657, 14465315986665451243, 2957504741164666523, 2280672126115151165, 14999624386740200468, 6090063205272921919, 3478652904863279960,
-               18131467168461028363, 16471039226156513736, 14133684792391617163, 7137732710914086892, 17299189471163637576, 17270681183882183871, 9046519354210103502, 16091721986926209161,
-               6572875037492082093, 18318192911446580882, 18107990043035854610, 13573958681720538720, 2821064027974708708, 13000417359062035623, 18286430707379660800, 13070676610179458046,
-               8521670721910745896, 7440450230382417926, 13794050882540606099, 3657777690979179248, 15466400576048586018, 7802926536345945651, 11932698778931413693, 4291944108972289013,
-               16729016738422946915, 4082443597391481873, 2238453914102498318, 1806710580451019071, 18305396377745213463, 2262209146853870557, 17240603302299977012, 1540474707615687112,
-               16013022710115947086, 8748688582020024424, 10921431579160628425, 2228053349060750948, 7024441100951863599, 15816203310189470753, 9078141084316010447, 9841344410499582933,
-               13377311905703150010, 6352753896568161822, 11086576920416079356, 7629848369702522073, 5472036379742160857, 6535781794177956975, 7671272114437903042, 5056286897725243410,
-               14579350500102276494, 5882738271691348624, 7188200631561491668, 3605286077046581049, 8957701412704914688, 10347270272487533128, 5995825272041784807, 18321189862831103872,
-               2376178340116743056, 2263593380938083722, 1990228394694589285, 13477447633165073333, 9023956677421314778, 7820910817739139038, 5288765314200405868, 13070699273589738968,
-               6765952613794178887, 347733275422001747, 7640026333627494061, 12925707101320796635, 5670472934143686904, 15041817307271371058, 18176041895529109656, 6838891343875575060,
-               9902363248877274636, 15776195244792726061, 1935342462634574355, 16572507349421626602, 7503944294807242065, 7454248748618678609, 2837392985175901475, 16494567631149775512,
-       },
-       {
-               12299242278498309265, 117303082144788574, 18382936515565701803, 7941141688858846015, 14923823358299367958, 15681089039073030752, 16878721085421212785, 3933697483394042011,
-               2878536922988449879, 8819365314325664735, 2696760638950720974, 11357179421800829605, 14730809809256560583, 16277258726425730599, 13189689275745970592, 13769784951430309444,
-               10292669945637125918, 13595563061674492799, 18301330068714272653, 16981073598172019270, 4022713583718555211, 847970754090163894, 12867993617169467387, 10021141621864633865,
-               15254713655124736464, 6283719686609422435, 5417864180357938798, 14010638809605797246, 10873690600705871523, 15014239467130590294, 15765460219545280655, 6048061577845125750,
-               13465802402879986040, 12777495579796377113, 11251142258511736751, 8312965145580158560, 223338793373356823, 813747086573652373, 534790745256052224, 3658554932030960904,
-               223170064814687698, 12938716002978051117, 3848816111228150666, 17463649319617382466, 12886402189488467296, 9605942357133455486, 12272689261734151433, 9916808458308982839,
-               2879267873712146919, 1770061136847768757, 3497337219301780129, 17065005588401306579, 7675751531915094916, 4337540836976665798, 12505868586426061855, 16929961945120117126,
-               12012729503226546642, 4811951115754240681, 2652621264600062520, 1108958391967017223, 2508980100759035797, 9023233544151778447, 11183557587641545146, 10726727280840759519,
-               7189877122763725514, 14656082750550993666, 13508306914749420120, 4564443784575285318, 15450566991657647015, 14019683331552104148, 7751003035652012225, 960642801291306739,
-               4621870789074053275, 2699296606556701282, 17510056683561737074, 14554735156054608866, 9556940770704438829, 10801168482998872433, 2280142648958056556, 4982572404720159279,
-               14621729774738200671, 16850208728798178903, 2650832773786164628, 8325244333065591089, 17692120343646193143, 2242845836784335580, 9386711085286369304, 517979059098779699,
-               396296174223428093, 16763788748988621834, 10606803701784640909, 2399987183687936561, 3641562114746393614, 8536687357022564742, 14532545286961725758, 14658331097531946901,
-               13237433907493396869, 4990918623816750268, 17673032790739307275, 15907935024302716062, 8613470231259845273, 9346326052910147032, 17747177708802561938, 4490130127498754807,
-               13867405496809412712, 7002613759387491643, 13033935552806967378, 67437088702121131, 1528641041740753990, 7001198041125832592, 6102137699349551632, 11527483925092226802,
-               5535652777947676324, 1216916140919282417, 343617165825197489, 10806931059627863289, 3212291315152120591, 3351900116486367965, 8595828725191802110, 15621077401736893558,
-               2386026063595321071, 9144724461940169335, 13121187420621518554, 17351696676224980491, 143495028693925520, 4590642171152119027, 8655406817079059692, 10005507077955932112,
-               6982427644490593208, 5211219672384700779, 14348546115682624722, 5876199850746516331, 18396840586595761484, 1465795856184232635, 9374516147960853174, 11803025633575966436,
-               16374709377982692229, 2545295070586009694, 17366393861359867323, 18067336234259281315, 9181658491221440805, 16188192004088261717, 13669686513572099673, 2044092029751770484,
-               7308293641399229883, 9813539775451467496, 4837144575100457648, 14073521030008335794, 12371724228966966456, 9185074727660313894, 7387427551441329556, 1866580457929037678,
-               2047964090310465728, 14133690277069748515, 8287749071957055844, 16821270580974431218, 10324684883587585565, 9652498187344172497, 2461802306013063247, 15048850312040680643,
-               9659170831875656345, 4251587871822599596, 12391279033133774782, 7346556824831912968, 2133114137534468833, 8694105814921565301, 1000087733076615381, 3478818915231998954,
-               15832320183998834886, 898251865651859288, 16874504161383651033, 18425166917936355349, 13387271833996394553, 808054572728974308, 2281828182196149100, 14620221246129351423,
-               2755242181069093228, 16155597320469161129, 17375128328249992589, 13376690667170223367, 12825454052191060221, 13625129606409283552, 5627148592782580041, 3092789333954796605,
-               105705035058376953, 7541598459498134635, 6627685529861836787, 5724525771392188178, 13865897118300842617, 627652561624109853, 167084371112939132, 14192831153344015422,
-               15618434900514973465, 14267977447705810206, 8823759714826430108, 7918740515193061263, 1664424041430494212, 9076733744947861202, 12010737794701759719, 13920688631446302868,
-               14823160144680924028, 15690572793903331709, 1101762466949115887, 19462496059060771, 6099422315003219574, 4300077459158116870, 1282001407902323746, 5792772971400374848,
-               11488321122368726901, 14632273370344181937, 12984850848826263218, 1857014998357880446, 13897135914532207935, 15925630222053677390, 11992050787349110965, 10072349923584966035,
-               12837696619944805389, 13470316523008526719, 3074966674353053986, 2630814767089382743, 13353767941686870870, 11405513520090968568, 3071969598389884693, 8212421686942839224,
-               7866179127856055582, 11874624506147226333, 5793384221044709375, 4411967221310302622, 3004913667339358722, 12230878672003882045, 7395980261120250376, 5188846147165419817,
-               16160221386626609076, 2876994290210606255, 6065036384672004173, 14696333348949573335, 2667009584785381424, 12100192661844794919, 12401945669155059163, 12847772853650923808,
-               2286437117905535902, 3130250324287833414, 3662253455746154641, 13229041365675585947, 3663813013822489770, 3093300797589723687, 11507645566517710232, 3715061633580408995,
-               3464453985305889088, 7486900500389940957, 8944303108517222303, 18319933556403836918, 6782476025105836770, 12822840946923377510, 2799592944286097404, 8737598030273298051,
-       },
-       {
-               2754563581284692865, 11257360722362829387, 8254261291934606879, 10023569920325096229, 7980898855627864603, 17162063449612285703, 9275759455936104363, 15936804738099638644,
-               303387668469489035, 7978391052264888020, 15413722057350324494, 508608987485166058, 5585753287556892522, 1344134516582665443, 15144279405777509214, 17014353449841567149,
-               12518577022215294774, 11347384788122950558, 17122718824958020364, 5431993665805279177, 1445831254446028321, 9845654210244803480, 18315778529692612284, 930563922336183289,
-               4894710987714215219, 15704993603878996107, 1606204036324478223, 14308635149530198932, 5026736228773269251, 2911689442372084137, 9004077539360196849, 7770049130277452000,
-               2745120518194234905, 17255944807561408883, 7371907591838942770, 11781525288383871227, 7814952754785494862, 15022715213812536212, 4112388658963418656, 13703771908397991335,
-               17455440140812341569, 16738670164475421762, 13259904130186215994, 2168106064304872507, 1969289843772256992, 9025317999701057831, 5835661391798891929, 3826587698101558069,
-               9149648374608464235, 7248346993716635643, 17283919168525322365, 10107681064815728795, 12176813938029507719, 15110337574289033068, 2436453685316043712, 5876967059744625564,
-               6197919059881189313, 3300993078638782623, 9357667752372201437, 17688129755135009447, 5477090746558113696, 12602024521188880300, 15889961935507293355, 7135039746373941272,
-               12561063426893244305, 3079971284510744316, 15695857190375815873, 16730673956207425338, 12065477821845465116, 13846158368121919228, 2126156187526559500, 3005167441915916768,
-               3858987859895327040, 17043903959888117395, 5861237635520080595, 3292646198413575902, 14286644557048422360, 14346409530388980974, 12583555046601155161, 4665981927428063991,
-               7657686120974201842, 2388299767028319466, 17934808017791217639, 16708640707026372313, 14122341266134976486, 9547124998857374491, 11194069918436025923, 14657538980930727877,
-               18115789712912297420, 6543740714573413570, 1955886376702349613, 14736853369719086334, 3914330395250768396, 7607848156418885173, 18220633528980056514, 11930952850158858930,
-               17010681753474701341, 6961088634819162945, 18395881317121515295, 11611411242007267179, 7996717433149311639, 2687736005475404867, 15340214362731923149, 7116441414289074727,
-               14302198697220662403, 11915041511943922518, 12363437164440173650, 4047410026894059083, 11439743031696133447, 8776097395071907030, 6851061783357383945, 16484733576581941012,
-               2861660066704264713, 16453202148771053225, 10039035813504063627, 6275446616881871868, 7150609984920482782, 11100941755544354363, 6219760433202580646, 2875377482232912143,
-               16477698187919702699, 2757160833848759781, 5976267476122243443, 7375951277779829055, 6525111513935493528, 9969722922172879681, 12582700753056539952, 3861958159147836631,
-               4207324524057007052, 13478421263392765917, 13318275642734768006, 8504333045658265535, 3960720256367501697, 1601661680373853468, 7704205542213854353, 1552780884856863914,
-               11788483659211580527, 8739274750400900816, 17562450707643849072, 2113004873311762141, 8542099133996522813, 5273956141012313478, 15661081976505113338, 2290009483289921559,
-               7730337285529332076, 910421998453976119, 1242962796308775978, 15931313183507922513, 296811920445331257, 5821874870466240960, 3843405649348506130, 9007082448812181532,
-               7200777231000974420, 15816416455380831370, 12932038056359512011, 16422801186386616731, 489979647738684819, 8269568123908387407, 11617965045895762979, 10069799398667455631,
-               8245819835927284113, 5237630684564909794, 16572245571184457585, 13396211619915630497, 9177789877937729597, 7598297211302983411, 3133511073496333246, 16553020037702090576,
-               13441991323065749602, 15441570013111011986, 291172418860690999, 765089869758770890, 15943751395897588683, 1887511823199710563, 15452188663399676440, 15028027691170546376,
-               11009923302693800320, 5465227554242327455, 6511134004216481185, 2187999546010819375, 8387421071023131689, 174295266381833460, 6010935117399493668, 3340537243300033200,
-               270646782953286316, 6635640130829923909, 12717598479778596267, 3198506535831522029, 2605714695474737827, 14548588937126505914, 10448279824323025574, 16008560590494788290,
-               11460241048816176102, 6557818897531989327, 6948658872009630691, 12506263743501199667, 1813031030961999507, 18320107449706503757, 16783076453582799039, 10113937529079967843,
-               3096618551325580575, 16427990761832670936, 11792441105446619028, 682188988823121368, 15606025696371121549, 15395362449248397023, 10158149307437310549, 4442375503593769727,
-               5486499432056098253, 3811951715772590831, 3856863699598204250, 559724736042732093, 13251752681229681959, 3173330346541355882, 3597530263899943500, 11567248716558420280,
-               12822024566847931229, 14487146762942136806, 1361688279016339671, 2776885758026394514, 13616222293131162973, 4629388276054227930, 8304132204812769256, 15188275451670510949,
-               3676452641243730693, 10839008248003066479, 7676518604603740317, 18384275325050378660, 7827069556104560937, 14335741841451672783, 1145975213382205474, 13691620069378415495,
-               2513451633312793643, 17331457978938147928, 11588204658848186728, 8824497684232939293, 5956154520546906549, 14434958079241686709, 11798870987920360447, 5875117843056165993,
-               11313908033360767461, 14678575871510948417, 8479250768537158849, 13854183783158898926, 9413525381201650053, 10077438283140087199, 11413783222317729281, 4418417663988371635,
-               6001837395299394988, 7545846298204709215, 6662102781970969966, 12696054550672669874, 7436995610194789060, 9042605089262227561, 11621508125069628605, 7289479057360149973,
-       },
-       {
-               15555649500689005370, 7857014165815014600, 4664069234996337119, 8058230521837307501, 18090421626009183450, 9278179697462444898, 17138879353097908770, 18285223269807746171,
-               12741225973381753432, 5461579923265799106, 4348015554411389960, 14970536173310927872, 11568371199139699619, 11748662751675667230, 15495664823061891700, 670495577617908409,
-               9865772269601493999, 7325690007062740244, 18437964667185475354, 9546360111100619473, 6266116854923135821, 295905071295541234, 16037468634731642095, 16602609756229843150,
-               13266892287530449189, 2232961926857263527, 5934654989155432442, 5415975493246016158, 17117784386882463158, 3875398271691758986, 15755743581177209843, 11380746535012415659,
-               2047267291755864302, 5637045342080349843, 15779859211873634959, 2415175423642772217, 8664113127182901077, 3032959071705433205, 4250761979529656864, 8729259992491925346,
-               16559648310139278090, 4796731467175572814, 9267555165184254828, 1400425639375650333, 5199035239208036114, 7994153995816640929, 15677746297407711038, 16338895562326287438,
-               1740700879164022194, 8442598604870387302, 14969965175291161450, 3086786406508018865, 12097766404705693713, 3199218739761578935, 1744290654371906763, 3672816528005113908,
-               10162459499000477259, 7534168794800651527, 6320985751131807192, 9263840233901040421, 12178625283764017250, 13143797113231152006, 13089053551699608219, 13480464010111258056,
-               6572275813002629593, 15328678880838895837, 4281489161088939969, 17996597009627631572, 10405019085582914256, 4773602940383417103, 1455403777441353089, 14766164051850429812,
-               3886207141264898075, 4215113531127552656, 14283840761174092490, 11161507022796293343, 11235510295695006534, 2260082644337974884, 3781681413610409735, 5577127823856153222,
-               15609337727165147542, 5725010295752332028, 10091444858515990726, 16162855978360002823, 2478705273652882251, 11394669968372227148, 512641267828429208, 581410050368207889,
-               11426681347395118622, 17135867298562042628, 10870734720453621112, 13803364322975322217, 9740527283062276630, 13765238480893165263, 4792349632705804116, 18359029140065847048,
-               15215482935039834459, 3553551735757600990, 2471323651039083728, 11355669733892999598, 15830640053604899661, 1625382463038435804, 11969247519895019474, 14372668755409420943,
-               11113773299077372683, 16618589175113863833, 12580653821785550146, 8264195478884998326, 13569468260761711850, 16539804400793525042, 14464540796871846551, 7710175783216723569,
-               17565888320840294282, 12018783137972195797, 12159604578082686310, 3210316551614996638, 7700243787046971168, 8307491254792612954, 18022719331150542511, 15890872243361196004,
-               1420251412241033168, 6449255753238336368, 7468624722117319576, 5716072259994197219, 8165015263320602150, 4757529151848960259, 2040364517493350115, 11069642333484542749,
-               6861520668253090597, 14998859189233167760, 4851545815068976365, 594940747993801912, 8473464707442482665, 2316305389548210767, 3995416902578245152, 15770229481630179441,
-               7316766449463697051, 1410976281384361962, 2878678490331118371, 17638505404208445694, 1130528985192221086, 7544558337870473835, 12071909234624857373, 436426448500115731,
-               17436263074416557505, 4339627812592344328, 1076653379358004720, 4996950998108333398, 8528954985898069924, 8259369611572362613, 7869239207308554342, 3592003501289265534,
-               9434687670958330812, 4808705744496679962, 13910334628239183613, 2628594509406050235, 10055911465166862298, 8069256921143792190, 11886968715847498191, 6351594160398684406,
-               9865961381837093259, 9590584894285774485, 10674927452501376239, 13861388033657872936, 808108663597281834, 16581187679405825998, 490312642991375167, 11352102610468872412,
-               12888468148530619065, 542846015600866106, 2086677842713697080, 2758534484095407635, 15767123419143795297, 7077908316515201321, 10297306681753168866, 4641656730233236179,
-               104445550853777927, 3829969899624802332, 4713997522991885393, 677661257782477991, 12383280183673921457, 4373178143111769979, 6375181113677777933, 18335077047046332699,
-               5472832021993175857, 6120966193470238758, 13156950075464061259, 14833372202848630444, 5760885723102571027, 18022572190906170343, 9870918995920897221, 9546055667466056471,
-               9516299398994303577, 11139435630263588724, 7364473923787049608, 15378275072059759415, 7378721410182635028, 2461490895435109307, 2579531356642691202, 11061693189962996686,
-               17380308085259417126, 12584808641030185141, 15485460243194852460, 16172215807782473427, 690761937231979275, 17570908286361380250, 3347059970688467328, 10404397759606846636,
-               1302709369035452282, 7149637102192386111, 11659118804203241786, 13909758997057192683, 4361167997834561257, 2300569874961985919, 1609719848856066643, 9866395233709297503,
-               17124591880405051324, 3379747334483646957, 2084957978131092947, 2413497199486596627, 2867893699156486423, 1357836849049583382, 13607307985344221035, 18039194570940763745,
-               831259058391834318, 12782538711785697535, 12640197944141330321, 11004378265133697847, 13622812183191119169, 5878590957416415562, 4810392157669422629, 11128662835376944411,
-               2248775486830407244, 1550340755758127506, 8399436463450785695, 11063895076440303538, 2168511054719571959, 12238498894267955838, 10824266376477587807, 1073243669335517712,
-               13568560319245254019, 17615770913976878569, 13214159705850440913, 7542574047209989510, 7392331519546111377, 2685908847786414772, 14835825677444128105, 11347648758435372538,
-               13230815692170010235, 10662664037814374845, 10120384214921531334, 8892863196093018212, 4443096401408136417, 1896901619181196514, 739574867683694091, 11233952771600927581,
-       },
-       {
-               10708602749843635238, 8046488591192123621, 11391158257016334553, 2512908912806916201, 14760224624269838038, 2631910198880826809, 2387247811669872033, 2048193899742148806,
-               17392983665205025720, 12603331233691760840, 3752711326309791976, 8281544857330094164, 17004651346561270106, 10399322540256775923, 9721299450284863176, 3725182263994944884,
-               13643198694788276032, 8127425924819487897, 14165945065582850538, 16520977003164405917, 1941948502806705647, 12390949208067741787, 17112117376594486408, 10232906951259490042,
-               74190110112564319, 11227229657066745164, 10151080599595091944, 16591051376074591375, 8256332495682655293, 7127985739945537626, 5708687346183367016, 18310921046455023281,
-               10040565835468209502, 3986586816478505371, 7957179672896506016, 13347112914739722590, 14099734293320932556, 13921950344400895005, 17478414833301838037, 961445463330402797,
-               10553899634420153414, 4215979268474142438, 3643081140297634139, 11620906704125380460, 17733628678553828301, 137473878710304143, 6211837577294956591, 13926110616399428016,
-               15203257341351417031, 11597829209697937782, 17317571979811895272, 15929491640570317745, 5731227916276913121, 17093153916149088230, 3908757069480556294, 18211818355208735794,
-               6887629766078662088, 15330755394432598442, 14144608177273202986, 13258654996547018856, 8975611270007504091, 16869834856279102361, 12707970875852047823, 8520055680055874514,
-               1643407997152867899, 5400650551136488814, 14663391437159245064, 4743209938058826866, 1728998201888511561, 11238331920657195520, 11617984741897247805, 13858029141809651878,
-               14003691155137683825, 14641672309228817657, 4031783205073356111, 7414359968614421153, 8166814052414482491, 5209260157266028169, 17555696996149558694, 9780166780476833956,
-               16029688335186691281, 4244772808651443261, 6450459413414527821, 695875191412722741, 11104054226249884864, 146461617619843327, 17480214580411209436, 11285418463967817315,
-               4922928863857449168, 7226901725606965824, 7568276305032368752, 6253457805758596797, 14345040877576203078, 1718759302498746946, 3544444746772280646, 17880302727399449566,
-               10693864548794383214, 736148233485985101, 5241869061152863453, 7166954323782542739, 16861482585847848251, 11483636939866570861, 5950529069765100144, 700887039653157350,
-               3906969739692830848, 5546431121705298614, 10491799900914853406, 5871175286230239238, 2851574662174517162, 5511397532379144624, 17409985391224790540, 319012646822749823,
-               15269778527761027251, 16471737837294177924, 8830398856035267114, 8206807757132984992, 1421214226977370752, 14233751335943482739, 9668238787333455452, 8700964319357541954,
-               17561670470565298976, 9524122142014309347, 12619871254022879995, 4098610542031538614, 8338691110372464881, 4378598564044777665, 16435680634249352743, 12067828180476756532,
-               17102475410743425567, 16244272017711449252, 17598420420289880464, 17858587557620312875, 7275673248698358659, 13952444068457447282, 14004356855576602555, 15776401868125266614,
-               9848210305813205280, 13777844361911806961, 874096498600831552, 6286216140019341540, 1229781121487503670, 1221366673976886811, 4534525466071627057, 12966848050780717673,
-               14890015174575641658, 7082696407720868596, 14546372439063914434, 18306301153433516531, 14360952638570231274, 5387283652784509262, 7246876761413034655, 4917620254108676720,
-               16572428185201836512, 15535161956998457706, 3118508753345802652, 1036719175817464914, 9929541174185476740, 17658764424885337186, 3038747611544544975, 9299826573437432057,
-               4068144934809412921, 10422353259330469599, 10820596685747357573, 18174251490011716747, 14838047097904304200, 6494279871501263445, 10908514990777375627, 2395220126873880030,
-               8963350163641627638, 7331858013030906816, 15047142507680204097, 6113080618647404016, 7520779807516814683, 10255234845683676901, 12010823325949652354, 4005195924244758895,
-               14455661618497189876, 980858168361168621, 5057114595071838088, 9447128440518577562, 17115933446433165191, 2063106073840638313, 5944852338857186064, 14601740796836275216,
-               12750698494453238590, 822220438401342753, 12735466470750534773, 15168985403101776640, 17837672477921333079, 5413174218886573483, 8340507718774735027, 3796235681866322764,
-               3366536195244539993, 13901131415620358879, 9146606194544531067, 7568835872371146677, 7101767951356426039, 1958938171972212156, 3871412404872561111, 6437054924013233533,
-               12849284342518738377, 6061751293342567452, 15168528907847693260, 2071752334274992986, 338461453751559028, 17270401493472349305, 14152214298057413781, 14074152302209367061,
-               3814267663972523036, 16047424572869508620, 328411057776532579, 2321721854548154476, 14950895796162035951, 2381867458906113095, 3121132178592915484, 11019696935452271225,
-               17929201703034060485, 15478512769360046037, 11652099424221007544, 8436785170867890275, 16340404489137765730, 13705192502407972039, 9464924753010269658, 17372624212933856135,
-               11237648987477338397, 850109691127167972, 6566350160877169296, 8028073340740368222, 4445151747345891893, 7753144690511205475, 7551118086710031441, 16785474804106433438,
-               3919851124685189663, 16028223238454025712, 9008783533564802058, 15647028843636411071, 2029953422298604024, 361326896057539567, 7653333452646403127, 9211397293968688243,
-               1817762546790624760, 15025271080704836746, 5761603182050280401, 10355268146728370750, 12900583599325924868, 1488036927944469046, 3405173852255315327, 5600132277974719103,
-               12574920924242276218, 18146097977073890534, 18281543194137545725, 4432773597060264867, 797962164984225968, 13432184750641235201, 12394976215803938078, 3054137600383896411,
-       },
-       {
-               18270562314314829224, 17574550722906577917, 15522987576586641271, 4200899284963891561, 15719788437321868967, 18390235318178988753, 17371818886753265385, 4583380351670429228,
-               10102001197913431240, 6211688443233768420, 1986665099237206297, 9248907879269017005, 3081890249882755206, 7828527646248386813, 12676034092230326487, 14655968027461080131,
-               11464797300361906821, 1444449385286554508, 12433005157477847389, 964895564896662942, 8457290958728547067, 7044433897330872257, 12292673928275053405, 13679355097865192207,
-               5841260956815214452, 9461234662498869948, 4761949640006529525, 18229823346336752572, 16055957459773168413, 4272222475092786627, 18249888117586812770, 4531982814021269346,
-               6528332072572425694, 15678657170585498065, 14462305190193144746, 10159286562616704237, 8919172138248087686, 13247073064443362933, 3056992278576665488, 8216417459286092432,
-               15095644792163717355, 9931529712396800935, 8608932369590222253, 17019087735655287783, 17120516184457264144, 16412592485673181957, 11221555966650765276, 6815162077372858604,
-               2239262553722461896, 16518231021003046485, 12875479040073845800, 5243141733462514317, 12216971859495819530, 8917663622006068692, 2606734295032613674, 11237688605489138628,
-               7270238601276019194, 7318279377964882079, 5226788506940171017, 16838449902078450273, 3375184937745100689, 16320655850583231520, 2173229791272659780, 9816381971766204380,
-               11061652864259684005, 3625039563689831268, 4435107405432574197, 17570841169180914890, 13981724030179216670, 4992487505540472327, 12893808204753555435, 12899171569920731024,
-               12002788024483301555, 629439982201171214, 13749214763651595011, 7164215996082938159, 63895081825959000, 7006379700570403491, 11929054672290963822, 14290981753366049931,
-               13554823979828564217, 15627748053816803157, 12924111102804720301, 3165135223777020148, 16345805559363705538, 17656153856991335888, 5211305829410935273, 17846236012427517420,
-               17113448198982970082, 8879656883528014268, 15215762680430094206, 15232212751792759071, 13699137317730183483, 11815206710130297569, 12298409691055054593, 2192455093917691024,
-               6973243752017383665, 15334919534387330350, 12203459507012560294, 1880762698376948842, 13008085926447766632, 11695961991328184563, 1311309249708428072, 11981691262998313807,
-               9209757463013140118, 6782250604095077195, 7896297860376631775, 11500117438976638113, 9099678680126826621, 11908588510950302487, 16863479726536938776, 6368086884375751995,
-               6220904427249143299, 4501361418756965744, 13907877383736656540, 4499586229279778873, 7233050316216252450, 2775027076708404645, 5669561106187108564, 13951461080947060780,
-               9742819322069712752, 8779224519997661749, 2591205872359340025, 9144644967919881415, 10495832103710459914, 4557264342687723360, 935865282128150338, 7120324256648044882,
-               10780007491891304021, 14382731247791652187, 3296810302419712004, 12567831906993651128, 13933396378746555124, 9754754796778422405, 2905077741505886450, 1522919492210831578,
-               7282056954663740402, 4915867300034445627, 234865561845141598, 8874426225092097899, 196269165389812019, 8951904020835594063, 6908903359164319029, 14062039535595890356,
-               17922518107542393156, 17388335427727081004, 9077910363057082196, 15157438705071651749, 5615196861086779767, 17404239261681991687, 9772161835068093639, 8380484042808490346,
-               4683169301229531061, 14940390399739549639, 13128742567354398401, 15222231511210090535, 7352694898928671332, 1221555526903686446, 8697118143614336514, 14515400523185205597,
-               1119145169329993209, 3453487026721044641, 13723232966162256192, 15282444658208236515, 17806849942057939434, 158876409507122147, 11954364486113732203, 17566268785944006600,
-               1443798830844295330, 5744920153630226551, 15739845606128975055, 10458513157123726949, 14711103578835123416, 13886988522344422595, 4454455988362290346, 3507977514728491242,
-               15328194945269186082, 16398971046683442289, 16293780909421539295, 14488637138080135219, 1108438550767062231, 16291467684905586857, 11891067917592351245, 10459212739896579624,
-               10239864229747754958, 12477284975467600510, 14054830413782031834, 17752968481181892755, 16082713391521411762, 17191329716867535304, 11245514405315337909, 15159733745232554536,
-               4102022129275956496, 9361580273813141387, 13824110615577377618, 17115977884930866990, 15058705994968389537, 8039281695081359531, 7179945727911625126, 17628825480910826356,
-               2477336341361304271, 18030759410783456479, 1164757311756325043, 14195508307731677040, 9794350654156795137, 1135232100348022155, 16693007636113380448, 17770308235375345497,
-               7064407865619227176, 13284912648471743270, 9099541805618279168, 7383718461788433067, 3311987567268438113, 10943963018398042859, 8038765968977300792, 11039205462473399718,
-               15444441705629456398, 12030687282161152512, 16500102437404896225, 11467410246278043769, 14031300093087427598, 14458597378298191386, 9434445586505481169, 18221119130471329822,
-               2269899977501467759, 9674818903084386596, 11781166634280447465, 11752600152694102168, 14011747753002945247, 1084585411243442928, 15614695372212325691, 17196679090968022414,
-               5062812993852092949, 13193601915773858975, 12910718608861476282, 447390754333146274, 18393090736120037653, 13231946117349235609, 13365030203093499221, 9724404925244523782,
-               18064151108813428175, 3928735035534454387, 186686833744587171, 18406101378699384605, 16477405641027895528, 697258480673566897, 8958117283476321666, 6970167016227017231,
-               12694666558858009121, 10992313774737315187, 6046508760845509477, 16818819584649823054, 10464090160691032219, 1221502600750419478, 8658907655588546849, 16110628890984509877,
-       },
-       {
-               6266830413981331818, 10890859480409122410, 738708598357264321, 9241173142142102299, 9152169484987657321, 12122430118903337055, 14270062735458703743, 13877635605034675649,
-               4572419849863661964, 16330741525817240677, 5456771007607263420, 8798510164381810403, 16547183593064549865, 11355135595370359779, 17581910791451710925, 11684604415749005488,
-               2766130068233451740, 15909689412657372214, 3272828023364980896, 12907534005596438003, 7065629942275705493, 10609982651084321649, 17330343421617897811, 1746246157222856918,
-               13168953859078137190, 9072500190247791267, 11090199374278127099, 3503847851309060744, 14395788825673846582, 15073993563711333791, 12879874391706003251, 15417028700542288171,
-               2686132933630431595, 334448852204016400, 5636563341880055087, 3897420469445246068, 10569177829735084588, 8244586887721364305, 17973493209847502315, 18083956436923498083,
-               15514509130323617046, 9833490355170899102, 12028021566105512521, 6349458533674010018, 13470024118569549588, 7867188201997717819, 6110792121234766402, 9917858515766574695,
-               8273062939911446888, 1936638151089648185, 44602505720759914, 7839132833110815763, 13045756168264521992, 5375972549477973022, 16964151563535745964, 2871770426902555432,
-               14164643693563803212, 6386904235704679249, 931435629437735510, 4496152555914735639, 820099532545743339, 13419988718062417698, 8948965620484833159, 7238410427920554862,
-               4387941928212462673, 8023190031094282215, 12322462122895470016, 17311901330042910195, 16445894183838823370, 690424095855074674, 12820742226551488738, 227935274674223825,
-               17437729542205914525, 8439533239207225162, 2862942422640746698, 7340866642549630610, 6770451500989398335, 17262212260581413381, 2156505157624055602, 12195119268846383898,
-               13685370053507732180, 8304030489296890211, 7042719123662732989, 12115154796394040286, 10496877583013829980, 8909625177349683785, 5268451666475070682, 8910488385056259560,
-               8874918984373509240, 6652428549855789281, 14866714872885601270, 12093494664302554643, 10149999253136441007, 1611873554177023520, 10271627298853910516, 15171882630355491729,
-               17085353800722834618, 3271271583189511718, 9338466116389304614, 4685545953421459012, 5059702655119414343, 201476627889215522, 6388612869673101372, 8357217932305360896,
-               1836621694151238424, 11438765101326043062, 5537182303007083642, 2657011195641217678, 15370176245454161308, 1478361893117141052, 8729368992402422055, 4807782542738120272,
-               5084555197036037383, 500829604818691390, 8128181767026348964, 17895639808733462562, 4138748420878083709, 267892430674902987, 8954358455330696651, 1946224964877667668,
-               9440495138081785154, 17328162383695942099, 1870751290505230781, 17987066187778049275, 9952223038481207705, 10126409487298126876, 1181369784146909444, 8158422380540037915,
-               13005094963168549814, 7254364757817833162, 3708127625424981603, 13214729399033107803, 14306349749849146051, 6983270854272831328, 14340019638575491596, 704963281855585401,
-               14561080905697443279, 7640393429462623622, 15685656608213407004, 6317405842945074950, 4586197269496115618, 4352991463721324184, 18421865732314202847, 13679296167045126011,
-               5024751682397066348, 16464187416447039066, 17561916915150311869, 1553872229528720506, 3971081625989469183, 16363381852589102144, 270446294712200212, 4668332646727035585,
-               4623922898967168175, 14927682190770218553, 18082407698612059245, 8156136453512346914, 17256761355350416250, 16185397881787027880, 15277309552707416345, 5991448876439153037,
-               1334994484802978518, 6876293985013000163, 4439518198423905531, 18287119869714109760, 10942138263490204506, 13981840082343935999, 186527448590996253, 11759869552919496944,
-               12652601656062843187, 3947181446273381189, 6235196886760030384, 10531746495897900463, 13249616872107073217, 7937663398525899211, 8701780810784627798, 5901496026068341468,
-               1059285256835989485, 18284969105568513488, 8222225088165109003, 1178299600673068913, 16068875143685216551, 17849596766342630525, 1648308197824141718, 6344465813776674352,
-               13850247359965870279, 17391106451201459411, 9882112511974412840, 9027485913083134379, 2654737707750698953, 2829872619210764000, 10765067664204983675, 6008367494734883394,
-               3596754664049660092, 4049565277418079196, 14294713401434678004, 682517403208603499, 13234861305501540306, 2878761138137340816, 7563571058666806838, 10752984583868770507,
-               16399575624290910947, 4698193514990054887, 16222170007882213172, 6300376482027477465, 11587700570984519002, 4408509191665524069, 8909599698892352923, 15110169407475815879,
-               13814725956725513903, 11675366986709837701, 8008867936756292473, 9627238521208818281, 500674066787171963, 7307892989752288627, 16701476208533897826, 13745712031279374379,
-               14988991093658383268, 6586109441484875615, 1456715231981080716, 10587865765103526958, 7439504550868615754, 430398141621608230, 17710495017725824018, 1267747579289674850,
-               7939033276966801601, 2952159422351169438, 10439776924885737877, 13630489377585028212, 1779349587540144503, 17209739673050012100, 4174716919431642272, 4986592555205663040,
-               7110204405213656469, 5225260473696365908, 13544564684169074596, 10807318789744351361, 16301252682064971136, 5046748520130689465, 7049174921499294642, 433785658536711265,
-               14622798677938552282, 10254953149954221954, 2609148400899865119, 8197897294400569748, 11784700166516996756, 18107483989994737564, 5332550435198791193, 13389061302706010047,
-               10892870009313407934, 5709686117526627488, 16343828906887149047, 16063790174205876315, 9076070192754075075, 4639156357669822592, 4904064385440242264, 5942264027390072320,
-       },
-       {
-               17271984572727555145, 2097715321690717305, 5328035183708920909, 13206781766168781008, 5915693606819932446, 3870849056297265622, 18070792155150730518, 7786839743829304936,
-               7939886940063870939, 3597929036186322512, 12732772396498766041, 13300425267730247515, 2345112231224079293, 12327614629296314761, 17106102937162407683, 1702694317559034053,
-               8821632341545057929, 16708916351043551467, 9171560460858577216, 5711973041149612575, 15808302665077457285, 8412173943543358851, 12602476370021215716, 4778674887660148537,
-               2707032230021934480, 14943945588296447659, 13333962501998857701, 10603744732015256400, 3386903941135274495, 8507451908469049716, 9231176235773710950, 995464562185179329,
-               1251633503842168929, 8646405730060859011, 7525758827556699239, 12781503299321323139, 3762059070509735358, 12904588764985510882, 518456268741331092, 2752400776174997580,
-               2965193395248314453, 17005383961540689211, 2510904953800463288, 14582093408745785683, 14930278391247460535, 15319775861672772086, 7915822626743762260, 10481055458185028303,
-               750419144665626202, 4009275022270511551, 4810013488865977907, 13090697535304919393, 17408171061427940566, 13469810562978287715, 3952372983235223818, 12596642250700034956,
-               1497127512412966214, 11292269970549257426, 13920714718237672232, 1363993524078475237, 3687544717271789391, 14097532154250414203, 8367320351336033564, 11089672460564007700,
-               3927746316404254574, 9973240942982210953, 14122301504960485144, 13249357693517290445, 4259646940372475995, 13156585130751616020, 424701295260668232, 13006066175253059189,
-               10308406270137410351, 18444509448482991837, 12509509048086126555, 8343613342319774737, 7902938427788958534, 9924925722974851885, 3762983399809982874, 3397026083592781307,
-               2116063253535766674, 12792173758770945620, 11357854367169339661, 4502375174987631263, 11374536277081101446, 718846097450449491, 6555869089578359747, 8571702699293548804,
-               16993953276024768829, 12025590727803527383, 2672535181364381995, 2183111709986676538, 14822521615475063339, 10618745739454592027, 9957515072444869664, 4797521918890127374,
-               4582720743315312164, 18280419827142252016, 13380629421749133990, 16786942173448683921, 5929601960379909803, 6715621236552343797, 11192523517069751956, 228125323996215945,
-               11861176681909235996, 830114321507110720, 13132205092670772295, 15318287322892364044, 9027539547229346224, 17629383881225964174, 17167841317952050345, 2169650970520181403,
-               11366374573920831312, 81590945660392134, 3339836125719372590, 6176339191258224503, 13498384602634172923, 17380518646558253069, 6505222573402454298, 3404196177841425416,
-               18097777493026370528, 398882723487597643, 10462164796529820357, 7704526739683689547, 12438059168025171393, 8163001730991802064, 3319372757738711275, 11518015261707325261,
-               11235814273447729629, 17827792960634604769, 10951458440780869321, 13957342734404907932, 7344502969085321880, 15052563297577817908, 9276707332138855229, 16077312904856138176,
-               10945312442787809330, 8353703025227023259, 2523779015225839136, 5997809042199398051, 5595238423081509301, 1901941038793828090, 983256298544496123, 929860142706986099,
-               1859865867925261002, 7171610585558961405, 1708769301690637951, 1669524125723022855, 1126574755172968332, 2284167219201068318, 14925928881489847288, 4349400324295146347,
-               7809927122217534998, 6003738786706135597, 16541272992243715653, 11352602417510156921, 6070703545889058045, 3742828100079104877, 9416263310824977145, 1406892456840131842,
-               15907861713154660116, 1789008941779432664, 1086909323248385272, 5337878342158043460, 16405416607888113885, 8262005873603178297, 12775015438669465500, 18394022127507526579,
-               9832954710628449545, 14612341389215489179, 8860090710725054989, 501948203387806263, 9969784653624607958, 8524029089859194791, 18028069685553315869, 7863046312587606086,
-               940114737935470576, 15661699274328042324, 2496303902262203344, 17900779334646110602, 10928989106385540880, 11160326060698033088, 6591628982832414200, 12860480197090465356,
-               4005088727670892586, 10215872293486093012, 7634075494800881158, 7707144163086802537, 7085702388211248163, 12168208652772836726, 16347414703478252736, 9386623607672009940,
-               10720163442173876242, 185901255673735804, 189524655270248212, 17937598483325200462, 9672767027914841820, 10911520298114954717, 17238190140596785520, 12302850034563751398,
-               1819872496749425461, 5856173707582412777, 8519855762092470428, 16315722646681962500, 11554620938156340375, 11822224388003836169, 8221825485736638318, 8413608007099273503,
-               16265754830488408124, 13716061973016396515, 6050948709307262401, 7654402024031530787, 149712175032162058, 8319305312043679388, 6115793437696694706, 9669523344165801010,
-               16530167766100505402, 14672843572926881623, 10752276706209340624, 6888427606311779724, 9060900993058482991, 10439396339124215720, 17640982730425880863, 12916411341252677116,
-               13182242421100666863, 5267519287044706312, 1780278156705475292, 12839545421803851420, 9724873776343820617, 11742602593528879231, 7598735248774560112, 4512374343657017031,
-               15080601286098047668, 6570749562833033851, 17494147260115946401, 4878559727303047850, 2259644365338981526, 4232993783633913284, 3035566741498855042, 4306414296080197928,
-               3878740698199360708, 1631626027682263021, 10479957065093850273, 1678395573475248815, 9964111965340163993, 8992208313996775841, 8147773940555378986, 6205594793300838098,
-               11776245660806714247, 18129100488268011560, 15389929343761297429, 14544292652959164154, 18063319363114104433, 13433144948667100183, 462314076175867487, 1862686058702915115,
-       },
-       {
-               17596113920958619489, 11920824479658301378, 3786905428099710821, 11112764289322906111, 8817260450068629272, 6518847791514184438, 14593687325057339783, 18018581321332807475,
-               2056254186648603335, 12143016575009965669, 3290271983033386616, 4338404082685850854, 12660444972475266123, 6345409453044955404, 13278869140778657354, 10063005167581762786,
-               5303950317664091150, 17409642188139937758, 12135894348302287058, 16444741243419918751, 13935885817311324323, 8496908197501732703, 12163317723288843510, 16891353436915314685,
-               4168420842704770545, 338440394515115377, 2102734009665481092, 9772725684473416465, 1247616337419130000, 4222072446972129729, 4836898447189504007, 9154346000276664999,
-               14649401370738987318, 10044081678892811795, 1306517740393103656, 16586067283450489622, 8211832777731897494, 12849393859171286949, 17327526552807783018, 14171704619529498238,
-               12849053390245557890, 12693731077061619694, 5891211584023409476, 1008960642219209210, 15593393872187214387, 7381248773473326001, 16559656086795428559, 2106025108820858934,
-               4347667984894353308, 2129883711661222690, 1076488804494872856, 15059968377755299195, 12380937310378496242, 16425480883270944108, 4769192332535557551, 10388305045430499744,
-               8553482596123775980, 12627020622203381515, 10774788686070344669, 6271789114731522097, 6270586844349642345, 5584690155569770537, 9478526526319537174, 3405597782572827563,
-               10255408065071335198, 2384996481315588922, 10679447117297819075, 3734157461055440416, 1635042286365643780, 11321809677772938996, 2373960964139986040, 4869129159740273704,
-               16681657814739017038, 2045405432090866328, 9473434018957974472, 5549808619751464269, 3650191693776946828, 15805634549736708741, 16764187297356548667, 6849534466635874363,
-               15295973549776084894, 8150873746601283651, 8017271980921908229, 4899654767305073834, 15257501950484641691, 17365331272978440066, 14582514748324426172, 14727798284858071666,
-               3180828552573045472, 17698570278585440462, 8986722854533057232, 4518665117523514004, 1718699978312382231, 16973074530347269964, 5684175730451960274, 17228649521631238473,
-               2897180423141326703, 13691273076814343144, 2967066815351306232, 1032540647518716635, 16365716239989474776, 9503666134295232767, 4599017511227366879, 14475021161770955579,
-               4512626226592149712, 13575110216387069176, 13488662643497927183, 9673147324484250604, 143936220816719815, 2307325398241477161, 468315224038772027, 17743582630124600591,
-               1476494936296433813, 3408612621327299295, 11632756669813257564, 14296719897220703576, 2241234207239321749, 12237974399755684219, 16253635131573079566, 11892871179872526079,
-               8492025373682814159, 9341562763134230960, 10104358220305514878, 17545404790574939459, 15737064134098795026, 3880597485411313924, 388663918823974597, 15032915458906101183,
-               965170717686924337, 17890763357610871180, 17588999527212997589, 13975763809893342952, 5109669798963414493, 7891916061794044612, 4789971769354067287, 13049661741280223048,
-               13047125712251887103, 6463859133854403980, 12163714608926575519, 1018022589444930561, 1736262463418943433, 15665908585957261569, 8814123147308650486, 4798595000205497714,
-               7506024921976923590, 5624217973379693717, 1727881279508834884, 6843292805721229768, 14721392495779901462, 15739256886195814859, 4955780690636679890, 7941019297099640360,
-               1679075860853192334, 11512607379850785303, 8606478479964129549, 11355506676698290554, 8638706560448426692, 11314948425220125007, 192055228531777598, 1407009579456262795,
-               13286048494307428802, 9003344338654830342, 14153483128501604993, 18443414499226619410, 1307798988667786279, 4422280407538765508, 1295189585361403916, 13026087054487841568,
-               2784400402546744378, 15890015749743051151, 2721137876244951114, 5096506081391833837, 7797931926335359630, 11689452583898581132, 14104784079353186010, 3188967683935096888,
-               11330231400343362000, 12540174755074499088, 10360616188128925049, 3458938550662172118, 9983547038346979353, 14986318734459319551, 6345635939240236679, 6320686366534231970,
-               14746231842102190633, 3622710091833101572, 12626649920759262265, 7005023704205322451, 8825692535315999015, 4515463777365688013, 9604411949030284505, 440641657645532650,
-               15551627195111259367, 17849357920181562395, 12870839822102241674, 13056924324197787476, 15109676201265834798, 12974964680406025093, 12841612415554457877, 2986633967268013902,
-               16172780290314506283, 6024364507532794579, 11981052290745212925, 14235100278052078327, 12912505872017936022, 4228821405313065812, 2097279962856941481, 5542690235350104224,
-               6815123236701278368, 6160442936745831892, 8260371745376005388, 715614132817606668, 7741929556783214361, 6266561134278568728, 13996537792746468394, 13116379830815883328,
-               2212637711439965528, 14217650183061928416, 540869510933311267, 6195450915592159668, 14904187357299823445, 5215400274033728644, 6907285779833076435, 15804222685871187391,
-               11124404141552478131, 15318338152189072517, 4067893425297764249, 1697503410612817642, 219476584157335935, 13106826093753036522, 13049745208482785760, 11832231199490391669,
-               10493328169052594634, 10627081887813813659, 11388663495964140754, 1823051796271862577, 12476400584366298768, 13709148086980681224, 4023418280354022922, 7805776130903851852,
-               11989040498741265687, 10985482710426001838, 598034896692782488, 12230542700168560619, 1496676485546951232, 6833695919100964828, 527254545105454187, 6276811762216173921,
-               9452334891928331309, 15207477416486363718, 8081596400773698461, 7528187414539292243, 4773782664413845594, 9435822414884353799, 2722451711480791323, 13642248100035410269,
-       },
-       {
-               16570512961992288509, 15784840936011612960, 17797638261217375128, 10589124475671334830, 16848440972121709899, 697679021479737566, 1456738239410270672, 7214966028857473701,
-               11434157439953722433, 9090860151661100670, 8407869262026581159, 17882547383849407986, 5277257988019769029, 11463853580825342183, 13607489835500075467, 16878800997498950751,
-               16059297404709367406, 8426877510924536482, 15269952608796785555, 6256768900860981984, 13142655793714702073, 14566340391957173918, 17147065283704191109, 879106195264399,
-               1169887957113173798, 4936710663791789838, 8029349457377894665, 3317691225106441967, 3622769674498678594, 1954144360900150482, 1432045977341997899, 934737636789214593,
-               3519438486034584001, 16935008858078961013, 11197550931955434437, 14100007087636813411, 11096181469792598416, 1355325916242161182, 3003143504356161310, 5855778258533244174,
-               3469569649879539425, 2734409579230557820, 11243101718460963222, 14449395552625174865, 2832531264658408884, 12736053595733579053, 8514265014627300817, 4646556172848350801,
-               1035318057221356651, 16671259128991069733, 933190532640544326, 10073090919720429370, 16298191828003546946, 89465711115503243, 1726024123088964037, 6293688775358665990,
-               9646181593082190523, 16068017411165381498, 13319927590045936565, 6113055520205251774, 5576373032696512038, 13880344501714804196, 12022206929479211261, 7387979357081975315,
-               14353322331225872624, 14137906560696321406, 9597841809127146330, 14479164716385450316, 18390885446667453601, 13789601367024187697, 10599569472420906075, 2183893278236533867,
-               17984045804937170919, 3008713646989855019, 11485907798025297413, 14380740919052976941, 3447658178143557676, 9095585806057103587, 698302327819557146, 7922185712178340950,
-               12592522203651044465, 1491459000495558958, 16988036704095888812, 4620491143241098446, 3378886739158384486, 4601357523445825298, 7994566595487207192, 4507705687201434902,
-               13553890993911526641, 1237937561304731611, 11053651340854998814, 8737874920379363783, 15414508226001886918, 9311523317130687807, 12080742822716708234, 4715194040021784977,
-               11413808093931937231, 8917864246709968658, 13554307490245863526, 2827250138133094370, 7637229863299622584, 6947884496333162143, 4815638417787805223, 10291803792760846879,
-               12634048591085853546, 14321728045924893987, 12328747445286182403, 436433860116637979, 5910966881246245784, 11478152401127002379, 15956760875311888867, 9580341487614973173,
-               5405380974793160831, 17240616607222875763, 18407061562244315632, 1777973921117407170, 6264824459040652928, 18267228171835175724, 1278124974392461846, 16099414790431742315,
-               17182132836049601530, 1486820395924546410, 14089047182364760490, 5375431386740917568, 2352352269256972682, 6220398075470064021, 11444733678216077372, 8173002234516562536,
-               2862732059898640615, 16485439906762588046, 8431038226899400253, 8931540904642954995, 792388953489761723, 9296018986570869365, 406447163304028453, 13270392174836298982,
-               7772216409762031099, 334915652033124323, 9705063888720244418, 9829080877134570370, 13800256788887079067, 6121678265481939341, 11747955988727867922, 15561904257519022219,
-               11919247213871390231, 15058232650937578711, 16509435050946309716, 4585646383560577121, 7109079914182671169, 11070600764446172401, 13212464399509938674, 18057628120939602025,
-               7896339057146013415, 17613745684396593735, 4238258305077796259, 15438639564771394288, 1482402451684594916, 3104492350488980260, 5195487229736262641, 1361150797580203482,
-               16473144777827648385, 1226441665397311636, 11587851779002173636, 5723433682141598491, 3818559725806959172, 9177247615754603193, 9531025756553277601, 1716800965379459594,
-               10276432666086031385, 14627452075834666747, 18000674623336885291, 15328386422432799237, 18139556051577750412, 2213209867616444127, 9597214736611625280, 2458176131336755868,
-               17117806110792423322, 15887422186644000204, 18208397717053970445, 7361598408210891485, 13818554723430207838, 12816010025806087198, 17883064936092688211, 1716893191215908273,
-               15949855327936545010, 15892613064802301412, 7776232754624386979, 2193423430757249310, 10751855334513902678, 13772090376350944100, 5644047706587449960, 370992037484721524,
-               10797607675141630710, 16625594903133516890, 4419277245854893028, 2258389314023537326, 16758443963306613299, 15289730903996513589, 17124263661185245991, 15862017582286958991,
-               12272869926038995590, 4569089761627301260, 6495211060884501138, 11124576322292919277, 18314798224925096163, 13232331582712038213, 4402693571738173484, 9384301049965683996,
-               9611026793910805538, 11152002731283498747, 12528844591327054806, 1485961507414531975, 12820893906402770618, 16248407567081091370, 15794078730898691457, 18231302945982292403,
-               16329953561108738383, 14553061366216182492, 5112198484879130320, 1893048255589705004, 11469678860036344015, 8992526488267920066, 18208245559304821518, 8980963391041920447,
-               17694621707784163170, 16317870945177246022, 9173265111786762052, 761657177655159269, 4876597178189658673, 8185879737091523833, 7520213092991049248, 6827963030155074898,
-               4104149897263226969, 1008830393844825523, 1692548451180187046, 10984924503299463085, 3526468436911084942, 18012043951628458646, 15181223987778535698, 18016160796635284569,
-               1524865955503524054, 7479709667052337482, 1064851658558537015, 14404181438374010311, 192685278892740648, 38546070651855709, 17006752915941498851, 7120034574635007914,
-               5783711159088718530, 3503029393593618754, 10736192136662142256, 15443859608128978668, 271805305647187927, 8244170003029416464, 17017071503038388446, 2536084345379259313,
-       },
-       {
-               11535283160083833975, 15102917952496589829, 12909095696891909745, 4611119212602854744, 4195756524232932570, 3754603965149529000, 11539276962358607816, 4401424391553230481,
-               6842993463058627120, 2708745114617181146, 3832382691810282630, 10333834458057320812, 15028197197004077388, 7681293343255119354, 16227537691626587485, 6703363869832495607,
-               17567108285065737529, 8693245930330183070, 4025672038042952121, 3491067119247522844, 2100799837993193702, 9579542950705774054, 5091525285265581997, 1806757015709820088,
-               7757354840118131559, 16227348978414023262, 5800861674805516343, 16486235803248700961, 15646700163023677309, 504258765210816549, 13724147899924699697, 13588899538317277096,
-               15895596198730294923, 12513494396374459899, 13552575153453342654, 11312160635199213507, 12446618129881485796, 11286186116805515445, 1584191291800429567, 10188741008566636830,
-               10157626021970320469, 6580688164585715207, 17158416694471177787, 2873484006255074946, 14852216457444863041, 7463041347566136496, 2190030775722958628, 1116223035803602728,
-               8598875756176012541, 2146658618778432566, 17575736667490551813, 3602654209723135985, 7223347129734689099, 7256921024940026570, 12249118963297692963, 18168532365040819099,
-               7585174044375463988, 2491923406404093282, 9355733262044036112, 11484079611349577325, 13145030009254943291, 1234932884591406048, 479845670619308618, 87735010308690865,
-               17307641427543377277, 5862898330718319545, 485176909118483750, 9845223919324484076, 4293549583740204024, 12765124043303931186, 17870894781132657382, 6508172378961793849,
-               14234156373312856400, 16210939788814051708, 6478880037923038392, 10435512103812909561, 18142844321802359753, 3243996803126554757, 395603619159523019, 10213589535656704607,
-               13256075137060741204, 991285459654295161, 7857174835799942102, 16201105040554625727, 18398612085349994216, 4512860776717176840, 3521452275695011919, 10622137733045360311,
-               14993897771652736376, 3320388672992783302, 18421556740970114213, 7438967127794745135, 15048397725789819354, 12721899159423777001, 1135125102123667189, 6637485660805148630,
-               205606553319362431, 15484041062449893984, 12896720585684759529, 16675624014916513672, 7579112430564108390, 4602460356900251082, 2677787525524280838, 16723483619407414479,
-               17981939084373319995, 3989926231875116241, 15342509934701840045, 12999252495311233519, 15389919024942778009, 6136335679373143315, 4117381415379544275, 13342256463740646775,
-               7622769999043907199, 15227992053145045634, 2719412067263856950, 17811161335980566241, 15036003689029442301, 4919601685231030712, 6756893600905532338, 18029567067112075531,
-               15804957839814547154, 7924193945337173678, 1080401129055171214, 10816444561878528576, 13171610473229361771, 8099842733764406841, 9284741070210451667, 9245195215372025289,
-               7352706423771400643, 11698139248518535945, 12836997796963939813, 5747451345763534394, 7572033904536738295, 17752330422795919668, 16404760947165813434, 13477251724246705199,
-               13700661979310397040, 11172816633936827025, 7087232997755437759, 601317374152115944, 16028751590837491967, 2749566595186093629, 4445248645671399873, 14714182958477634997,
-               9630153311383545953, 6436885924177487891, 2150319761793765423, 3799049242167098053, 13902640603080497957, 13121685068446422901, 10099985117244683905, 10692630753099650856,
-               15680946025356791729, 10935239212262708062, 15255596602338430716, 15502989798538458360, 906862139952472300, 16128362872146694687, 9038121313842477036, 18304772087255114926,
-               16961332967315316395, 2872796507989583018, 18145413156795763341, 6377517922859730669, 3543621377523624979, 10701607653242580646, 17747200374013876449, 15987594633077120628,
-               3487728992359467218, 11271201736509774853, 5968332690756574092, 3519182420015237550, 17144214368301394415, 1805926423542721773, 13696269518209159134, 942126126861202483,
-               16211326119697754410, 9043490763746629445, 13119640043033532883, 9720862297941999125, 12662669665140843415, 2188499520755532048, 2671631563874698813, 621164898587943254,
-               4804461736506692241, 10698651491947798952, 3524135800884470917, 11451653751986650957, 10424912129082359813, 6912080226482239953, 10357808719970986526, 11757540241185558439,
-               1841157911016607198, 17522398974331009019, 17392843956059453556, 10510758656389762948, 7666344868273530034, 10739409534839380580, 18010518965344703872, 14478457810678500914,
-               1617286442811984718, 4008909641875477702, 9328654790542709745, 12015676532404599710, 1763241944305573436, 9348325841675336084, 4072126498552363080, 17245688939115723821,
-               17277555838655940279, 16604852268187595492, 11674181070138727191, 9847423407697994070, 13562477602392929772, 8181792789545038731, 6999326623175714057, 1227784795779857129,
-               14923095901189736698, 90760593075377861, 11732533481504731510, 6000651333412910877, 7847865090059184838, 16859539404919901595, 2709105957383645337, 10263820965340474390,
-               3161036642361826348, 5744405044938832483, 8939741099437920817, 9766097724147073614, 12117283480449144394, 14632688836103128438, 9491651214417380913, 13676064073123352224,
-               4673738700738845848, 2758750364605631228, 16596306154038523740, 4124917668203310922, 2170509910405778957, 4178077301639210933, 5109055439238993109, 9627760120514410208,
-               7259236533647228872, 9608619771663043870, 4148523959415435806, 8831501534166306825, 7919036824652396994, 13625969543100731176, 2546426055029800579, 14852443398434563210,
-               7185947197544988797, 13306809398790059447, 11440959253278285287, 15084384140482244570, 5059824327869316332, 7585354587200615362, 6801884469610571467, 6427162399794357267,
-       },
-       {
-               1453348772281274490, 13028088570940491471, 16100623112750251840, 5210244400259879874, 9443916155735416174, 16869520919318450506, 7479400208826706574, 14374970913352602458,
-               10149597276931117465, 5778043705364022356, 13888443605241209218, 6889225091714429810, 16209363638493043975, 8516350006446457646, 9214830076046105138, 8894115046323798175,
-               13026208197163596446, 1935567165776196957, 17296090833026336866, 8461284827078097590, 14545382879887213077, 3302103559307506085, 16026840048628844803, 4599071908983273604,
-               16375505785562641226, 4903074653735993511, 10355787845763031761, 3188849033041803587, 3145147452182864049, 13878747873108378466, 2798650520315922121, 2325962694441538199,
-               3587824003578414733, 14942115314012282784, 5312737955169054323, 12478174640832111702, 7866537714619856949, 1076672758151595875, 12163513815501875048, 8343003998956997868,
-               1392855790923554429, 928317148609633070, 18064469091536763974, 13446092366984636072, 1975222540660444795, 15443703204026028192, 4016450768356916736, 16656367700821047808,
-               11505659892372808762, 10322665279031813234, 16948868760451861492, 13706671779256832515, 1968671033447691229, 2446599110590827903, 13721045634744350023, 11053432744256776013,
-               11530583608023224967, 15979155166527001287, 592931868138800645, 5361781029549479856, 11246418752830406096, 11882251984248471436, 12026389461944629423, 12289077922798223820,
-               7685868633977346753, 12528120620943035447, 18394735788313062922, 8523101916703102094, 14261596878655792929, 6364753027040158382, 6433482955677830548, 11538026548937002170,
-               16221339092185577802, 2285289075757313223, 1151823739515800834, 1010537560193450047, 10651328720714490261, 426599792903611671, 7181136719074122463, 15350479907287263858,
-               7559201271967630136, 3561344874280275357, 16379496429080959327, 9662226613694502966, 10995850494788192620, 14875349277152338391, 730989400822814422, 14352408679782573731,
-               1328339467113622233, 13374824154992864223, 12057132015324007824, 8507647484414695512, 9286016370798146986, 9083798709648036612, 4312959727577073260, 3732271624824420608,
-               13007262390446754395, 5631627784562092966, 2644488352265945851, 15340614364643014664, 6692152810984634488, 3903120388658969320, 2513009101887784188, 11999681442010831364,
-               8301343575202991577, 7108394080005777057, 3477086484634015274, 8772644795325835021, 14747670046873500269, 11068536909552811695, 12349879357573378133, 8898863927320049679,
-               5231654281125841638, 5181061730027800171, 10657176101406080919, 2548241936122768256, 17140253194139059526, 17961047717804458883, 12407260567549658707, 1464243167234637194,
-               14129872794455315922, 16354810591314135702, 3177417010197743958, 16494351130927698692, 16557765056328447818, 3139394196704738651, 16891813998271303650, 7374470997276173905,
-               18244279644122204437, 10097660526910786400, 9270181538098732492, 362243376823712218, 12369863141977485111, 2550957813014523686, 7768963959853738595, 470330801228165919,
-               14632133560934390222, 13844843545192224059, 12232948338847787315, 18223343336729121487, 5219716370019749202, 2729037467284418866, 4546118556621109595, 12191675540034649671,
-               15868991745937371466, 12686820201922367283, 14799186526268126508, 1241626948050017911, 7080072468753824165, 10793537086099229143, 7855065677501047369, 9747396305344084667,
-               1547814412223404746, 14194709348405912167, 15771028929623393801, 10945048172868684389, 11234483878611528405, 9542605377580701681, 4555391547268120796, 14916872217451960022,
-               398873176015355134, 17609838001051405497, 3752252377312468061, 10441993652683449973, 5218696730429184844, 6514361533063264268, 16024112124035725701, 13453525984055386124,
-               3452753233449684767, 8937677805622461008, 15346651759545553711, 17055791435062851045, 7025089132368408239, 7345356702153522862, 17760529714295220737, 10772604293313163303,
-               9940223451501501487, 13671810088603813912, 1432075826781639138, 8145669182511487125, 852664959675237493, 11640273224943853609, 16220508798123490173, 12787926729706993802,
-               15490131882364039637, 5140304620645573547, 9403655757498826823, 9824850954989176893, 6366139388903157264, 1981838834216345294, 14659870286877979556, 12091578124492612524,
-               9672198938588933438, 1848525214318852627, 6500329435429402369, 8547555101599185897, 4282139019453982058, 13391782461875853462, 956960429753408730, 1865393350316759140,
-               9155847368519787501, 17397005067762861574, 9943535970799289809, 16365250691105460494, 13595148040475375224, 8300668237654861875, 7149654787413440141, 9226755501324961219,
-               9359301870380673800, 9344500253098672841, 282669288080771734, 1996492472861301505, 4777949892950526502, 1374151996531969836, 1529729047243522545, 3371309923165192567,
-               6832171775190531128, 7903951882621813138, 13717573220828409267, 15400575122727850054, 6101307565293576434, 17226772767105983314, 3485283905347036760, 18439321272895583847,
-               5095761409418784463, 15484673138064200869, 7743962634971666154, 9119597914470879266, 17978461537972396088, 11490423388734028778, 6537551181013090408, 11706370534703673937,
-               6635008658379780815, 11428304571924124070, 392068559161657302, 16314310970878215293, 13769492864572584674, 16880907685897496637, 2877983831559338706, 10391660973242662710,
-               16861266984653213659, 1968749328591656132, 13301499995824894911, 14523175695360471336, 15130688872832023531, 1794208537894703529, 10525607764904270704, 14288604199111912452,
-               6289130721434350290, 16129337673129720846, 6648351866142453445, 7705983837166554199, 8120136556582544814, 7924417299222764443, 7821995671300500892, 17697662726179084739,
-       },
-       {
-               14086745261650819748, 17953107869776717888, 1777725846494438428, 2765314406831814212, 2603997194371852991, 2223517025105045134, 15579901335531749634, 6571733615332171148,
-               5478465698516556930, 287443454357750768, 12201204663663129285, 782849770204658255, 11270045035009204251, 18152683972363144337, 10463300037926642739, 14363641589598863851,
-               3790592075869665284, 5120320091554329756, 15361581282394028709, 14360464660911164915, 15249656958991931940, 2563751872827049233, 13745792006936646733, 14572943674933168173,
-               3167679014977537749, 3417445004776702290, 1709246158507866266, 5861367897285174360, 8437429877561342262, 17231607446243478748, 16047596399306766948, 17656438585829685897,
-               12977336347094692192, 13723871955002954132, 17399919575273038847, 16163973860244779675, 14997921584659740746, 6543247361992425067, 4675926398794487109, 17580512382853194054,
-               10778828023580771765, 9812611440536367405, 14168149065325522570, 6692229110872358750, 11010962724400581057, 13055203605065073902, 11396463140731730116, 16969789651736772232,
-               3285258013801327520, 14114268241282882888, 5367399533198476395, 17277410244918727028, 2751895479568588421, 751309667192066167, 13038472116718581917, 16013586354334596135,
-               12364168614988940500, 13194367252463423118, 12223406606527741280, 5014139294736037086, 11244699482831816093, 5336498572491451990, 14268404582568856142, 14502318820969599316,
-               13295673091232554814, 313981772853781347, 11829785736449464030, 13341198421333360997, 16787450350663111566, 6525407229623764159, 2012189087039636323, 2110887590404698758,
-               16984895766311549717, 1057465499230843916, 13565444352859773343, 1019268943988786852, 2190009140530404855, 10045598732295352970, 4789803496780829836, 10700158388954091321,
-               14840255112988420500, 10066628133368048408, 6527354835873855384, 16106607076894419125, 3989024604987083046, 10713316697020150694, 16811389107269552264, 11294596059797019619,
-               622403023838932676, 11423409007234191765, 17086830255702454786, 1213655124481948199, 3976593910085142945, 6315875935390432543, 17947502153968859628, 18031540937011531543,
-               342675887578148289, 18366454547938469828, 3853530442390999217, 7499455395579634652, 768597405171336502, 1636271570683567151, 16786205337983572309, 13056241332863199715,
-               15991153618414855143, 803325462494472241, 5709347424437559249, 10138502962472290727, 4675124205115228106, 9599016746550345197, 2769443894695609085, 12311020551315051087,
-               11470964304318784059, 17313372553735202469, 10686997186364536871, 9228453594798060121, 57933324335302024, 8931389936300346353, 17823596478938529898, 1126996688113949835,
-               10457697409306668434, 7830477435299250296, 7772379952622394912, 6109610138112185532, 4382803614711332911, 286231563340803504, 14408860285425706036, 9445290615796219321,
-               17536503470234411585, 10755841521760916925, 15905055604395954066, 10842889504280336728, 10780689817551616331, 12490302644719656914, 14399349211478895553, 6458867531104408547,
-               18263696007238300109, 14344529985676987842, 12351733186419515951, 14648750128188787544, 3817061805140294292, 13460439592176294955, 2651602395003150964, 17613970291099197676,
-               1107162420032075035, 14270134754120385897, 4090584027509443635, 16066949131129832709, 10961641187652236678, 5480069976143996625, 8549185711954755645, 3125346629140152790,
-               18337941236561689695, 2899707239319273137, 10519944305927777790, 6913088845356962577, 13796383125935684169, 2756403850320695444, 10018647980137529204, 15185795467001072323,
-               678732289042224133, 4682655677430115166, 4806112367076139288, 7101473987708012826, 9907594813802528406, 5572757906434657546, 17819688309930892783, 8734990255058630746,
-               4831187103439262344, 8323117365987697459, 10690753367486223100, 8744079000061869982, 12737295198832254982, 8667406752954112119, 7942221205780634447, 12612313636795726189,
-               16544756691464009983, 3413196415113664237, 18442955254149959801, 10193439941306925215, 15178607176290875326, 10962146035584651400, 11757614026658646304, 16241528460556234026,
-               9593194029396792148, 6376573619820601945, 14694667798662125868, 473733746941891591, 662607401339043361, 12105576520816361855, 16629740468317868384, 12416206001206121129,
-               6655696780366945398, 12313066500177107654, 15308290012322636383, 2159880960357061128, 12374858353753840133, 11331956329091160239, 11794840094276473821, 14170553661155653327,
-               3336445037682266403, 3746885541049520962, 12688476435907418892, 7399089272376853858, 4625608774712059624, 1535040330210000507, 6878676093546636363, 14533846142831376645,
-               6250279356724130049, 3901672557903829499, 4884397030724371499, 17385695093365573379, 1240675257703364805, 9703149291204612490, 10295741452056015824, 7249917314998921510,
-               3336800790505577062, 319907795530586958, 15852045830964927276, 5538471989976998401, 16558766045222360422, 3135574045680866961, 7590873965560972285, 17191236425969884848,
-               542161999237385999, 11197034618748267807, 9595673564043235773, 16351524685431643264, 17127456926935032059, 15448416181819692483, 2035065584045934249, 10976830957530152324,
-               3230012351101746458, 1662948417350421518, 16062645290454019168, 6021730506322388306, 9903225699788133023, 8549278993611431648, 16267339446315716903, 9759051179942016620,
-               14281696762614162345, 14970002486407845832, 14940104843292093805, 7021313216295048550, 18131586729996841512, 13957742754718859034, 14322894803959804982, 12861731196696133597,
-               8838210194055479741, 16190279688839291456, 16520121358582757556, 16768959728701970634, 17279896910204983538, 3582816187015369256, 372137484481226748, 12972230207718993241,
-       },
-       {
-               11480031272463364121, 2525856087688686375, 5875255653057452580, 5606696614467440464, 12094715534218447962, 6173479337351577758, 18244015404482482803, 13199349349511499695,
-               6097225965006328457, 2630336000831717722, 7049638698786526134, 4203465038263485233, 4677974565964393904, 16044036678123636261, 7266049959100300634, 11339674070148504929,
-               1979992348876614621, 7494083465935166973, 16035723662722831744, 6820849908885211777, 16740735239901023053, 2017530162004533409, 3087262288875984227, 9072904925376793991,
-               1830819081327272165, 11951292080860646547, 18002500803418629938, 13317986695217403840, 5005574200470766330, 10138179785738652504, 1610518863105278224, 13309443265578956954,
-               8383241685301818332, 6629521234420338478, 8997316634951392497, 9976633096395028594, 5171570735720385772, 8129153749198218776, 10596302915145665067, 3726383961188926740,
-               14494271933981109919, 9056473564311980628, 10557807473422306929, 1549747977888697589, 4534184223615087698, 12977118933167042558, 11930457930026683843, 8346041661496792064,
-               7756665146227128459, 15140824521273386708, 693427108108819556, 14819189462601222526, 4507393341357475468, 8710020646873218244, 4535796033535410044, 11884504632761707946,
-               14192194428653714479, 11578618567931657764, 6032668189933768881, 15981535562386193924, 8925792218631314923, 9408714146004183681, 8859017894477140398, 1675606340537058506,
-               13447287279335601133, 7792625320709870803, 5347956615552953057, 335662974452886013, 892825083599137885, 1017154417323307505, 11923254597349925339, 13818364932306372202,
-               15945578153358602744, 6304522416189552358, 2545503746231186920, 14563857419242252397, 9711931929315762229, 7949505077082864287, 8780199792032437102, 10109661610848827442,
-               1628958128919487289, 9818701341087940523, 16480240737841185501, 12633108361335093100, 7982147509828265471, 17959437456356197928, 14370416793872407673, 3577532534573396628,
-               3265119697568866078, 13753322853248061974, 15435163376825672274, 13646180516491714938, 15620545622955090250, 18241486585498394565, 459566729126467878, 9728217493753855944,
-               3187267754295885454, 7928049460349917700, 737484733736740002, 16459695106656291329, 13000947522838718027, 11933371771659873912, 4720706464557996274, 7997020276574823784,
-               12655797542121172150, 16574741514838026101, 13532097913031715162, 13578832971779600350, 18171552525916232035, 1516234640889581592, 13625693062693291889, 3869929504544890755,
-               5134589228918179333, 5186584327613952853, 4114726195152833642, 578924708883784650, 9128473117392713984, 17390547319520768186, 15077700332150016764, 8707446714183162237,
-               9883406233903270985, 17184231210468300584, 5498903678702785900, 6903833261382863389, 11489138095102981636, 9021901931786177471, 3227433089132150317, 16639455550797627042,
-               2873811051246262545, 12759149028054319339, 17920917684786397179, 2576455203420292139, 3181713670456310447, 1109589489775958300, 8920119044838278090, 16056330702164227666,
-               14277712977137303378, 3896132440952049994, 13252040000848248790, 7844779060499908154, 8651912177362107995, 5527615699397299219, 17688189207278018869, 14560189235973121390,
-               10861951673021959044, 16820848382034483641, 6761027571816469843, 3555385088072119757, 9363319138244920099, 14172742116400795253, 9535965929584057049, 15628517769546199992,
-               839045372102318861, 2032615141683118500, 1921816835840256924, 504869150737570005, 15932184001422473505, 7849475855313305697, 1189994394722618598, 9874798350548229684,
-               11973862230325381876, 7670835358390713178, 2113918814334481709, 2289514490388170400, 4570586695077036349, 9449360682811675838, 16506880875578470116, 13723444740920888736,
-               14210428465641691143, 15330786835024186142, 14173742373807858721, 15041216914246450688, 6027140311333696225, 17929849776014561356, 3955935517651718925, 12080548003455651805,
-               1974142217308765297, 2347591555456293560, 9029256828390326937, 15561672734848339972, 4719329765359230610, 1924866103348851009, 4950258359754995181, 3245952633715281425,
-               4636201671610663345, 16662311204732135584, 12398897461787695675, 1355753199357412657, 14695655628527768564, 1692838776852698754, 7346906782826540912, 14869028424564984700,
-               7242751356102425321, 7770223857340282376, 14976092066160539655, 389604327668352376, 3472336298605227213, 11456496863560248128, 14597769228654187922, 17838672631901123288,
-               10997764239928568735, 16648935573721932916, 13735964592293716412, 1364388817619955667, 2511134998006929958, 811167458534120344, 9371523327214092569, 9359553283016173792,
-               15311627918891973770, 17170652974122329165, 12620036374776436604, 17439165699070911984, 18124482726761033947, 18390083820175794165, 5492125340791896125, 16506113603670143446,
-               14240080119980315297, 4751983902385717684, 7941412103662252178, 4796803816695225123, 9327986654018000413, 15111345676387005726, 3582558555283734415, 11913156735178831102,
-               2000999613038609412, 1070613390669459171, 595743672188217500, 9169968884291187666, 17960105939867090032, 13927107353795575459, 17872593051171658925, 11087013461789649235,
-               2280207936513065312, 11704149285124951522, 2138093032627822381, 6816805886026674440, 12141709925796155041, 12164596600353477920, 5711177504477877148, 17211856235678509153,
-               6061025098309340877, 4060747063380827182, 15186975689243681841, 18380882388949786706, 927262408801716090, 7447789770541113239, 14074172896745727729, 15372475239996145400,
-               12915868875134296756, 3071143582305760275, 10848717856747030010, 10973183887638314967, 5983269487036236823, 9885184706933333413, 14509493669845681951, 9669608065801379977,
-       },
-       {
-               1190044221726873109, 732025666411072563, 7781096808432277694, 13079879637655900365, 9048680577986693793, 12528346194104542124, 10575369576322629835, 14068913038053465964,
-               3297775431071502652, 7947266993949467566, 6161673381820779563, 10604626734847205996, 17669018066064502925, 2386071939136502354, 1076023928806956187, 16075459682742916440,
-               12387028018538599950, 5791681577936683396, 7536922194386052138, 15377770247350254336, 6564316170002440575, 10629371267149545956, 16125760269901494382, 16051398044897962024,
-               6237354803374899565, 1782400080026955610, 16115027077529639342, 17907259814836219524, 13179234383592426160, 7302978467158243198, 13607720993463749225, 6693531817169120736,
-               9659467198848065929, 13765104107473534739, 820057324758632016, 16604163594878267405, 15321524555426147294, 14524167419333362957, 157291234996957911, 3689488130722730671,
-               13896531645245568605, 13598412639648980920, 3875086557856143664, 9242105512956135595, 17410265178284161091, 14904754836127450463, 2354327747158525902, 3858493849578874654,
-               17288438225198818690, 15275190140700748774, 14532856272428522409, 2192294551011758591, 4275966798014984695, 13252812474545742114, 8604705074440591847, 504054699541924162,
-               3623027910997185067, 15957466839356832933, 3504133700071704955, 4135728439139397021, 1160600455691338871, 4431928072859292239, 1542956305318065546, 14109181184369694855,
-               9135041378474229537, 15626265487594878380, 2645257479784082878, 8105679948445763432, 8579715781576202730, 13437359533149316300, 4344754720520585005, 13326372852934103673,
-               11341622086474305983, 17104958945811183278, 8154944722722765678, 6696975609844549775, 10895966360082878017, 2277686037575837054, 12236842881540344526, 2086470279064067791,
-               2942668817124399651, 11439025398519255779, 17477264434671471242, 9606507094132585461, 1771475584689465869, 10791261379080046759, 12901998265727968789, 16423426725595035468,
-               555419805011031621, 13715683285513290290, 15526654591995532751, 7023761423093873354, 15093366433178982304, 8625749648874372840, 6412297471587129206, 12161114204724955762,
-               9362623422820895267, 6491356159483508885, 8543224082493101588, 17290929683278258587, 17348088672546490894, 3323350644823701753, 398525379151271104, 17794417664139368677,
-               5880914635028486784, 2898124605786107494, 7953506026198179840, 2189477357380899574, 11207122442953694293, 9288539232660208671, 13527697625010979453, 448462453367651162,
-               11262205719433170585, 7539606872920196479, 492385789142086954, 16036594120332851267, 8084547797138041354, 10063336189771527714, 2484395715469739911, 4879298610504146231,
-               194633990068625151, 1028128699653523895, 7436102537486268753, 1855520454959348468, 5098690958966904466, 3342676718901330604, 6942212660412942406, 16510188838209674083,
-               8847926418142642416, 13342814936333556870, 7082971165114489981, 9307541560233171550, 3013250253632606412, 289291445038948658, 2146586262066552853, 17331519863134074479,
-               13747350589043267381, 6342477793304440894, 10087817302474912962, 18076409030930122816, 240893790090129194, 16364025156922886538, 13518167316464590136, 8034023137744309866,
-               14013962864860194917, 5900268096329749317, 578665371390927342, 1407477069341362927, 15142181569643383319, 5217173950329651840, 7999234477517614232, 14722759409199120103,
-               857809728583972424, 12785911478120621636, 11351522624307635957, 6288237507210579634, 15030282678317951238, 5521516375915920991, 1243458350248005764, 3567973108073272461,
-               2834660673354035229, 10728451420162645120, 13396052377701115268, 5730788601228223475, 1616452754395208882, 18236419625072278846, 1179103743668306981, 9179882267624091153,
-               14087439523312437665, 7814060325531094731, 16777382811045908592, 16916500419494378884, 16312259370378381991, 15848836870251345077, 16352246673954213424, 5228629139249919486,
-               16889782864065172884, 4486233301301317202, 12424854171669138635, 12490430652425390015, 17335301435940798099, 9685877269515541824, 8728054940414220990, 12781228698496150916,
-               15949574575791239459, 10394047428873141717, 15915386168603191086, 11400139144838475744, 17198578050070482368, 10505386377385262682, 11269920026804647377, 6796664536515856824,
-               3285292208372623455, 3132524240856145976, 9712372580979649457, 10523781046601368064, 4797168047433466290, 11748687702182632788, 4177442610271848350, 8549047039673741703,
-               6897143822689085584, 12727238507037725105, 12692443686524496083, 1187606781546544862, 11016254758711515442, 15622643445771261724, 16669571628491989170, 7099030384210775042,
-               3541342827520921014, 12596176563952906070, 5209816272233406534, 17158219989390045881, 9096207539532607151, 12291463442559161708, 5188945441827912424, 12721126884401346746,
-               8137171114112655022, 6980210601071561830, 10156197453074241467, 4481350962546197264, 1902625885079226055, 18310954340184922140, 10624840172920793227, 121304340390125189,
-               5261036238619130144, 1418912875050883205, 4741122621962383610, 17995804738511375239, 15493968366750472633, 8417505178158780382, 14685111207483504618, 9729483826733360559,
-               13434828863770210135, 2940287993177646896, 18241509923298296610, 7613631401252601295, 16815829390381900683, 8566309323681786413, 11094402941539790077, 8442864581771174862,
-               17650059733379916650, 4260524072883785227, 8351659371377110706, 710338300032970720, 5512358883882849029, 15533759462039713914, 14352344066268876816, 16708588250954382269,
-               7963995066277321795, 14986230345162551366, 10616366460602472778, 16186943329215681149, 9522855644164647723, 9858336437877021178, 16344942402271072884, 18027353494090590022,
-       },
-       {
-               13175608910844763921, 11168387468381338510, 5555873864224342205, 17780559602571640345, 1582669533588472814, 8145133762789622706, 1625372887980692455, 4576809104068554285,
-               2900978533555060931, 1749946807863203576, 11705734511931072459, 4446980691693419424, 14437524160594907241, 12795912566640000773, 10400036254697939154, 8356113088668925361,
-               8900726473285671992, 890209742292473781, 16059468388719373167, 16577940938542233221, 17381766864962227733, 231915274132518769, 16477817024012878700, 15646021286310268545,
-               17511864284462479051, 4391315454785363822, 16633389246499252566, 4290325975494843430, 15912670649662225191, 14172733821603328367, 12709802627494541709, 9648238681838878635,
-               4196883387800999444, 11261069840079702254, 7135968036494594517, 14537849011631244070, 1930221875891546479, 3029378442249928630, 6219774718328347890, 5922417028077454069,
-               12470404961188516783, 10420863874252801995, 1369334550763670666, 4781925915058005676, 13086538845357988031, 11031029468188842766, 15252022305121561855, 10497770692868889659,
-               8808726441417268278, 8201526072266158452, 1136378216494101481, 15014143365043073153, 9752793532008788265, 18423606089906807282, 12708377698545978413, 13697405528655748691,
-               12840624483048662115, 13614226123606379619, 15087571995173849344, 1395488309690794621, 7173958427217959878, 1198561064176820332, 16821886260165681626, 10019479169661217935,
-               8089335244564816024, 4652396396372834438, 8473523796721514770, 4493469844513366216, 5448577418901909194, 13487502520341193870, 17978888920023381084, 13125222810420128122,
-               11369140159803973135, 8391820975236191093, 4865145203995472561, 14899728882581231165, 11169032718524058736, 14532440521453562763, 7464998467530340358, 14981246381757614771,
-               1242992129726403300, 2014928170416925311, 6341058783517690890, 11690291498253019630, 15951586247597589423, 14033993236702971559, 16963725291567059464, 15075124616754319226,
-               9901328250515532535, 12796305315632203942, 10819069447660403847, 12542238242508661240, 17077777737462854238, 4364294351375777648, 8335244153165894685, 8863541604979427311,
-               12648774127830238318, 5576880401343711606, 11786867566889606858, 7421038047404952574, 1037620897405863409, 16680872357246325645, 10443290127564886223, 9718182896013830581,
-               15199007294286606824, 10225517367964809030, 12827778649823141649, 16046039393887815140, 284741135347255597, 4015036609703147909, 3902771329647468314, 5128707935422024078,
-               16953148044626345363, 5101833106541998042, 7655361325113312133, 15948906743291877728, 11619404274756349415, 7521254459857915559, 14978040810149334918, 18392994517091959591,
-               11029520456752683158, 2297291237551781454, 7934683676555855479, 1563954733146546128, 2252805128528536255, 10523375695822939112, 4598652721256818062, 17493379105069761435,
-               1717382065475436420, 12444276194160330384, 3605273785657402256, 17503422605669121015, 12066457002913396306, 18109827202111882684, 11555238022219952400, 1993655497207863497,
-               14852223665677610379, 4743851404709775958, 8525514757892437524, 10402777181498591725, 17096034999928466604, 4289543339828736175, 4306145672261807290, 15366124999227707930,
-               9159996652502914864, 10301349423202296392, 13530090903323000632, 4082840779249202050, 8824726775176314063, 16033767772359951785, 9181204573557660412, 7582747879080399183,
-               2747551692916263132, 3151123035150683281, 13938314333309683791, 11970864255483579560, 7894236725861110998, 10515613623232567716, 10445557830757066839, 11155097727742050955,
-               511773909731247800, 2463012923954369656, 15859141716591041471, 4940781664379556792, 12435624343534748284, 10278084527750129328, 13178135781125832492, 5930328346313533490,
-               9122100956633732655, 4007876149211873275, 8339438668849688737, 7791075492023424820, 1771434463088769532, 17441254147665904787, 9470298561063283873, 16552350513326886351,
-               2842235074681099572, 6045955093828210410, 12534027406207583719, 9023829328537353058, 1661393615224515538, 3265308219651631507, 14825441620546235307, 6190486519065164472,
-               9569762631377921701, 10341967309273270300, 4697570564829842013, 16684762125903667303, 5281929071085172097, 13027961546412671127, 18398764602992176314, 3872796039504642974,
-               3625046733403850478, 18072436321985678348, 12926724831909767455, 17260889391923475120, 2205546675974800411, 4823605748727161314, 11756378320036258430, 12725625915588142865,
-               3620769638269480452, 531680461898170, 10213227252513668871, 15446816035938502695, 15189868868814686765, 8689079054027125562, 10767300823767661010, 12185259819280811201,
-               2954211398425891878, 887045055614004603, 17024961552904496644, 11183183814128062689, 2275500228939836642, 8454621353771976628, 13706050871317440521, 13152782683288296426,
-               5035609627965208105, 6338722048255995169, 11594969687968475335, 5639340633771742838, 6928934109570365590, 11589609913085167707, 18353534295019770247, 6879412911232288750,
-               13223374340976842384, 5803903047180226505, 10382392856292138950, 6807712794865416975, 7273350714698980002, 16071615116869102753, 11130104866208195846, 17099222713467268806,
-               4288395624114587260, 10186593737807119648, 5970871638851383523, 17274628153010076591, 11083355019391773968, 15571651381840416650, 7269503864920933911, 34314525388851272,
-               13518907013113787435, 13799188114963266222, 10949327997049617616, 12851874981220611149, 14245323937486085594, 18324803746062213911, 13224741762315864830, 15910543010675195930,
-               10042008593756684008, 6713471518385846030, 10961845838926538977, 855334359173719954, 7598642325962297361, 18006511265377032901, 6844179774752820363, 248341098560552116,
-       },
-       {
-               9259451175701532574, 15597985540941612547, 4541553034987877619, 8927802479718285609, 14672230714928802576, 14284617950605306700, 13339970812390782046, 787078889494395850,
-               18165439414433063919, 14693282888419586094, 14992616289789993230, 13232208150801553912, 16850347485914337693, 223364064845089224, 7302899015436300563, 4391216311540396088,
-               12558388403188680537, 10687978569513354810, 9373570856564649772, 4079327722512691465, 5372437374337150740, 3297421622932790851, 9326853593823854687, 8305371884938201251,
-               13121472331750731303, 323745485980480220, 15110308702528119977, 4696302365805118372, 9859094500834571602, 5315656270700787939, 4187063204400651801, 1695695129564818327,
-               12817586844019849804, 15425488216915741929, 15293562913126043054, 11770898970765978555, 6806103820345670787, 17789094149138630459, 3807781571713999192, 5823254011289457198,
-               10112524230916015604, 13571143908656270599, 6031089010487808103, 5774558171390644848, 1808959243244841573, 14071312530426692155, 9241399242704553402, 9836150050655369231,
-               14083007972403535491, 16009534514129505275, 12481249112231139039, 10309390659262581143, 5782517315325366794, 16717384553294759530, 4578392002424884134, 239005024949492645,
-               1836857790164349346, 11263074778654917115, 4786985732596838094, 10525445084936097674, 1484357665966453236, 3110871407036679558, 1668700683093601768, 2736269131339849752,
-               9249362594190920246, 8088172462140746331, 4080107866285682736, 16205599538438551353, 18312943145606312277, 9100632964181080418, 3969991115337154345, 5340098959750368315,
-               12122448407048035645, 2891250339380982359, 12794212052932523400, 7166035112141500392, 15777441312724841162, 4552528682229856831, 2210391301762911476, 16410254680957321386,
-               6910044784455706429, 11951245774670922855, 207795885948948810, 3884359690300962405, 4578772752480772344, 2948797025787714138, 16774444535658202808, 1388183483009000463,
-               16561979129019905420, 1881862411760441386, 15441950514711322010, 12933020223458438856, 5570341451312029630, 18172638959728259059, 9074261777549091198, 6171200053222754816,
-               10126435102176037237, 1545112930055760251, 11563139991870561593, 10766754172364938834, 5116781688621052838, 14471715119500781375, 4724882615229687192, 10031687030722046325,
-               15016829467434780812, 6777508689306592732, 3811682306063049290, 11475361222871876387, 6080948654298953274, 11612742274762615033, 5268311600240325047, 9147351973710519861,
-               12130203770930472759, 3880998309361490881, 8807462332494735511, 9291388074337055133, 18165312304248982432, 12733144434841535979, 18090195697688236271, 5825342884125782172,
-               13034385644450400616, 16498936039876211302, 13019014556329727588, 17911110193068084415, 2034190024798401134, 1526884555531436223, 8108814142164064795, 4075908755148182733,
-               6404489603451030675, 16601749455344583377, 12907740667428956072, 8446383351289364752, 698035388979141580, 3593914367189873571, 6744392605914028800, 18168078953147292456,
-               14484703498492722699, 6030798911934842161, 15931002029256202288, 13491601992324491240, 8585568434702372483, 9113555433818303018, 6375455514164501736, 1476639189214882947,
-               5209683814158663472, 16895526973128357178, 10457488910391635027, 17530003042232440701, 4030542539553991812, 9445656287872984963, 4212489101708176016, 837886727556721620,
-               2983790309644332360, 11276772732994425347, 1310621139116895737, 3131558545024164284, 3529698629777893989, 13271773334458143370, 8171825923423406479, 305718858162497191,
-               12347543988562572522, 4315642616923374215, 17586477762860427847, 1037334149869395772, 18311071546005132724, 1489505092175764848, 8926409949339059078, 10260307609945070716,
-               1253128470325829265, 917180526219408600, 10471425074479693158, 12658678264459355332, 8502334428811982364, 3789675096428271759, 4531393894096863308, 12176495757901795513,
-               15081766794595471636, 3944913291385975654, 14507832069904091484, 3624606168811123851, 11476968507677098110, 1056328247986567681, 15246608002200052960, 6566558379177875405,
-               652315099041528631, 4287214618428297946, 11730560225433863449, 7935915607867430686, 15979159466809939008, 9209839549459543141, 9501045239358734673, 15490773728258884277,
-               14281001444503113096, 9253803478538227873, 3842669056581745692, 18399990656305827164, 11841387504710944221, 16052361836589007383, 831115622826254867, 8219898649601530197,
-               2339128600785774471, 1426373723429876004, 3299581455481810683, 16966544600853047157, 8419320331267538738, 8376963013864643226, 1996128805959565963, 2376766970819731241,
-               10963611841695254911, 2914831079289063424, 15884256460390936367, 8724520571578171796, 329402220949313078, 8905943304651682982, 1280899166177109409, 6980213851983339340,
-               5524321102331478758, 2149164875175284006, 10897639484514200325, 14605181792035620644, 316829907946955098, 13776780818927038502, 18167912441745301047, 16845612593885106452,
-               15817940025107036888, 14405005201957074368, 11647077937228007305, 13795438792777593442, 9813339145840642083, 13196196205982926907, 5981408724994946624, 12303812818084690125,
-               11821409230485627325, 1934768678832528678, 15798397330147151183, 2089418311766868031, 16206123311846842647, 10276976147555604745, 14858750786699873336, 2500482310681473276,
-               9502861285700748804, 12163827978530279544, 9383068907817479934, 5717811606328725851, 12416198015020836733, 15689586164720677894, 14337921697724349521, 9392403465642971279,
-               6696074876763293236, 10302972695440286968, 16647054763285662245, 7841147641486000427, 10612636854719975349, 3592516733641215266, 14172459823963607855, 1290213042793222575,
-       },
-}
+const p256Precomputed = "" +
+
+       "\x3c\x14\xa9\x18\xd4\x30\xe7\x79" + "\x01\xb6\xed\x5f\xfc\x95\xba\x75" + "\x10\x25\x62\x77\x2b\x73\xfb\x79" + "\xc6\x55\x37\xa5\x76\x5f\x90\x18" + "\x0a\x56\x95\xce\x57\x53\xf2\xdd" + "\x5c\xe4\x19\xba\xe4\xb8\x4a\x8b" + "\x25\xf3\x21\xdd\x88\x86\xe8\xd2" + "\x85\x5d\x88\x25\x18\xff\x71\x85" +
+       "\x4d\xd6\xdd\x10\xd4\x46\x00\x85" + "\x7d\x82\x33\xa4\xc1\xe3\x6a\xaa" + "\xd9\x90\x14\x8d\x03\x05\x22\x73" + "\x3b\x3a\xcf\x3d\xe4\x32\xbb\xf6" + "\xa5\xe1\xbe\x61\xd3\x48\x36\x2f" + "\xf8\x6f\x23\xeb\xcb\xd7\x2c\x15" + "\xbe\x2d\x04\x92\x0e\xfb\xa8\x19" + "\x3b\x8a\x5b\x0a\x51\x77\xc5\x78" +
+       "\x27\xc1\xeb\x4e\x90\x3f\xac\xff" + "\xfb\x81\x7d\x08\x4a\xf8\x27\xb0" + "\x98\xbc\xcb\x87\xdd\x77\xad\x66" + "\x7e\x74\xff\xb6\x3f\x6a\x93\x26" + "\xeb\xa7\x83\xc9\x1f\x5c\x4c\xb0" + "\x1a\xfe\x61\x08\xad\x47\x3e\x58" + "\x8e\xe9\x2e\x1a\x31\x08\x82\x78" + "\x07\xcc\x87\xe5\x29\x6a\xf0\xd5" +
+       "\xcc\x8d\x91\x46\x0d\xb5\xb0\x74" + "\x73\xc1\x23\xc6\xed\xa6\x50\x46" + "\xf2\x0a\x10\xe8\xac\xac\xda\x0c" + "\x6b\x17\xb0\x41\xf5\x62\x73\x57" + "\xa6\xab\xcb\xe4\x4c\xf2\x96\x2d" + "\x47\xf4\xd6\xfa\x71\x84\x62\x17" + "\x2e\xd2\xdd\xe5\xde\x36\x6c\x6b" + "\x63\xb8\x5a\x4c\x39\x4c\xb1\x84" +
+       "\xf5\x61\x5c\xc4\xae\x8a\x1b\xbe" + "\x7d\x53\xb9\x94\x9a\x64\xec\x90" + "\x0c\xc2\x76\xd0\xaa\xb5\x1c\x94" + "\xc8\x23\x05\x89\x05\x96\x07\xc9" + "\x10\x4f\xba\xe7\x4a\x9b\x30\xeb" + "\x2b\x88\xeb\xe5\xef\x68\xc5\x73" + "\x68\x1f\x7a\x7e\x87\xa9\x40\x35" + "\x16\xe9\xd1\x2d\xbb\x76\xa0\x73" +
+       "\x4a\x66\x77\x3e\x37\x47\x39\x40" + "\x3e\xee\x6c\x34\x4f\x74\xae\x55" + "\xad\xa3\x17\x5b\x1a\x96\x0a\xd5" + "\x73\x36\x21\x54\x59\x4b\x07\x13" + "\x4b\xe4\x77\xd3\x20\x62\xd3\x93" + "\xb5\x14\xff\xad\x53\x2b\x9c\x29" + "\x11\x9f\x63\xef\x4c\xd4\x24\xf4" + "\x5f\xf7\x07\x4a\x6d\x91\xc9\xa4" +
+       "\x4f\x3b\x17\xa0\x4e\x35\x46\x07" + "\xf7\x00\x3c\xd2\x13\x02\xd2\x2b" + "\x08\xbb\x23\x0c\xb5\xaa\x3e\xf4" + "\x03\x3e\x12\xc3\x19\x51\xba\x13" + "\x4d\x9d\x5b\x3f\x30\xd0\x47\x28" + "\xdd\x7b\xa6\x5d\xf2\xf2\x42\x67" + "\x95\x41\xc9\x77\xdc\x3b\x93\xef" + "\x67\x08\x24\x6e\x15\xd9\xed\xea" +
+       "\x8f\xa7\x99\x94\xd1\x4c\xf1\x27" + "\x55\x34\x9b\x6f\xc5\xb5\x2a\x46" + "\x6b\xfc\x2c\xf0\x2a\xf0\x90\x8f" + "\x0d\x23\x65\xb2\x1e\x89\x63\xb7" + "\x77\x49\x2d\x53\xa9\xa3\x9d\xf5" + "\x15\xba\x9e\xcf\x7d\x32\xe3\x21" + "\xf0\xbb\x60\xbe\x84\x7b\x3c\x12" + "\x76\xdf\x06\x77\xf2\x12\xec\x56" +
+       "\xe8\x20\x4e\x26\x8f\x6e\xc9\x75" + "\x41\xa8\xa7\x59\xed\xbf\xe6\xab" + "\x00\xeb\xc8\x44\x04\x9c\xc0\x2c" + "\x6b\xe1\xc4\xf0\x80\x30\x5b\xe0" + "\x14\x33\x5f\xa4\x7a\x77\xb7\x1e" + "\xe3\x45\x5d\xce\xed\x7b\xaf\x56" + "\x1a\x2f\xb1\x88\x9a\x01\x6e\x2b" + "\x9b\x5f\x83\xfd\xcd\x59\x66\x08" +
+       "\xc8\x1e\xc2\x9d\xd1\xdb\x18\x2c" + "\x39\x81\xcf\x0f\x8a\x86\xf9\x98" + "\x49\x0b\x25\x48\xd6\x2c\x7d\x73" + "\x8f\x42\xb3\x24\x47\xc9\x61\xcc" + "\x76\x9e\xdd\x80\x78\x40\x2b\x0c" + "\x08\xbe\x3f\x38\x91\x89\x3a\xc4" + "\xd2\xe5\x9b\x77\x65\x2d\x7d\x5f" + "\xb5\x4a\x3b\xeb\x54\x9a\x71\x78" +
+       "\x04\xe4\x45\x62\x0a\x26\x7d\xea" + "\xe0\xdf\x7f\x6e\x95\x07\xe4\x9d" + "\xb5\x1a\xac\x8d\x15\xa4\xf3\x1f" + "\x73\x90\x9c\x64\xf1\x90\x70\x3e" + "\x88\x4e\x94\x2b\x61\x85\x76\x1a" + "\xc8\x61\x7f\xe5\x9e\x93\x0f\x25" + "\x3d\x64\xad\x1e\x89\xaa\x0d\x0c" + "\x8e\xb8\x25\xe1\x23\x00\x93\x68" +
+       "\x68\x77\x69\xd2\xa7\x1a\xb7\x04" + "\x33\x5a\x34\xca\xf5\xde\xde\xab" + "\x5e\x38\x37\xee\x9d\xd2\x09\x24" + "\x56\xe1\x83\xcb\x77\xdf\xe1\x4e" + "\x43\x5b\xbb\x1c\xd9\x12\xac\x0c" + "\x37\x56\x89\xca\xf6\xd2\x0e\x17" + "\x66\x6d\xde\x8a\xfa\x8c\x22\x28" + "\xca\x8a\x23\x53\x95\x7c\xf5\x7f" +
+       "\x09\xd7\x2e\x4b\x63\x25\xc4\xcc" + "\x0d\xd3\x6f\x85\x69\x67\x35\x0e" + "\x11\x98\x9e\x55\x3f\xd4\xbc\xbc" + "\x59\xb7\x95\x53\xac\x77\x84\x73" + "\x7f\xe1\x0e\xc0\x90\x2b\x75\x35" + "\xe3\xd2\x2e\x74\x90\x83\x74\x68" + "\xc1\x5b\x1f\xbd\x22\x64\xd0\x7c" + "\x97\xb7\xe7\xc9\x69\x87\xc0\xfb" +
+       "\x4a\x66\xcf\xb0\x5b\xa3\x42\xa2" + "\xe3\x07\x97\x7f\xf7\x48\x6e\x12" + "\x60\x26\x83\xc6\x54\xbf\x17\x17" + "\x2e\xc7\x12\xfd\x32\x73\xae\xfa" + "\x6b\x58\x5d\x99\xb7\x2d\xb5\x27" + "\xc2\x37\x22\x83\x9e\x56\x29\xbe" + "\xdb\xe7\x65\x2a\x3e\x19\xe4\xe8" + "\xbb\x1b\xaa\x2e\xdc\x06\x27\x15" +
+       "\x5b\x05\x60\xbc\xb7\xd8\xbc\x72" + "\x4b\x7e\xe2\x56\xee\x23\xcc\x03" + "\x70\x93\x81\xe4\x24\x74\x33\xee" + "\x09\xda\xd3\x0a\x43\x0e\xaa\xe2" + "\x5d\xc4\x83\x63\x4f\x52\xb8\x40" + "\x25\x1b\xa4\x42\x54\x35\x66\xd7" + "\x97\x47\x8a\x77\xde\xa6\xef\x64" + "\xf4\xad\x79\x70\x0a\x17\x42\x20" +
+       "\x80\xfb\xc6\x0b\x65\x0b\x8b\x80" + "\x6b\x2e\xfe\x3f\x75\xe0\x82\x58" + "\x49\xf5\x83\x2c\x7c\x2f\xef\xd5" + "\x23\xb7\x03\x91\x80\x3c\xd6\x54" + "\x9b\x3f\xa2\x52\xd6\x1b\xf1\xf2" + "\x87\x65\x0b\x4b\x19\xc3\x70\x36" + "\x9e\x0e\x58\xb1\x3b\x62\xc4\x55" + "\x20\xe2\xef\x01\xb2\xf7\xed\x64" +
+       "\x9d\x5c\x3c\xd5\xcb\x1d\x09\x97" + "\x7b\x17\x0a\xac\xb6\x24\x76\xf1" + "\xff\x2d\xfe\x2c\x75\x39\xf1\xb0" + "\x4e\x57\x7a\x6c\x0a\x5c\xa3\xc1" + "\x87\x99\xe7\x93\x46\x31\x7d\x22" + "\x0e\xb8\x9c\xe8\x30\xbf\x75\x05" + "\xbb\x83\x18\x0d\x7f\x24\x4e\x2f" + "\xd0\xc3\x74\x32\x26\x12\xd5\xeb" +
+       "\x7a\xa9\xad\x56\xc8\x51\x3e\x5f" + "\x3e\x40\x8b\x8f\x4d\x96\xfc\x4a" + "\x79\x29\x2e\x41\xab\x47\xf2\xa6" + "\xda\xeb\x80\x6f\x1b\xbd\x5a\x67" + "\x1d\x5a\x48\x5e\x72\xbd\xa2\x66" + "\x3c\x0b\x4f\x8f\xaf\x5c\x2a\x4b" + "\xba\x7b\x84\x1b\x7f\x92\x26\x26" + "\x4d\x39\x02\x05\xd9\xc7\x6f\x6c" +
+       "\xe8\x9a\x65\xa5\xba\x12\xa9\xfe" + "\x6e\xa1\xe1\x25\xba\x3a\x36\x68" + "\xac\x41\x2c\x75\x77\x22\x84\xb8" + "\xfc\xc3\x97\x28\x28\x5c\x54\xfe" + "\x6b\x69\x4c\xdc\xe7\xe9\x36\x2d" + "\xc5\x77\xa9\xfb\x4a\x24\x06\x58" + "\xc1\x08\x95\xe3\x9b\x5e\x66\x85" + "\x7b\x59\x12\x6d\x25\xee\x20\xf7" +
+       "\x31\x7a\x33\xd2\x29\x91\x97\x8a" + "\xdc\x2b\x86\x0f\x8f\x86\x16\x59" + "\xba\x83\xd2\x5d\xd9\x99\x80\x04" + "\x4e\xfb\x5b\xfe\xb6\xee\xd1\xe2" + "\x5d\x00\x84\x78\x41\x1c\xef\x82" + "\xae\xcb\xff\xff\x17\xec\xd4\xa2" + "\x66\x5e\xa9\x8a\x3f\xc5\x61\x91" + "\xd0\xe0\xfe\xc5\xe1\x04\xe1\x5e" +
+       "\x08\xb2\x35\xc1\xec\x4c\x2e\x56" + "\x7d\xf4\x83\x47\x65\xb2\xe1\x74" + "\x30\x3b\x3f\x5a\x6c\x50\x2a\x6d" + "\xfc\x62\x67\xc1\xf4\xd9\xea\xec" + "\xb9\xe5\x86\xe2\xb2\xd4\x9d\xf2" + "\x61\x3c\xbb\x83\xc0\xad\x0f\x1b" + "\xa4\x29\xac\x7f\x3e\x02\x75\x7a" + "\xa3\x7f\x47\xc9\xf1\xd5\x86\xc0" +
+       "\x76\x30\x6f\x2f\x35\x11\xc6\x0f" + "\x9a\x2a\x91\xe3\x23\xfa\x9f\xc9" + "\x3d\xba\xf8\xd2\x85\x06\x0b\x6a" + "\xa4\x58\x33\xe9\xe8\x77\xc7\xfd" + "\x04\x5f\x41\x35\xbb\x87\xa7\x94" + "\xa4\xfe\x23\x4d\x6a\x2d\x0c\x64" + "\xb5\x35\x3a\x15\xda\x17\xe9\x9d" + "\x74\xd0\x5c\x5d\x07\x8d\x3e\x79" +
+       "\x68\x50\xe4\x2d\x53\x76\xf8\xf4" + "\x6e\x1f\x2e\x9e\xe8\xa7\xc7\x37" + "\x69\x40\x58\xa3\xa2\x5f\x82\xd0" + "\x42\xbf\x27\x17\x7c\xea\x2c\xaf" + "\xa9\x85\x47\x9e\xfb\xa4\x60\x03" + "\x4a\x9f\x29\x27\x9c\xa4\xfd\xe5" + "\x71\x2f\xac\x71\x13\x8e\x06\x48" + "\x6f\x66\x77\x90\x7b\x68\xd0\x83" +
+       "\x19\x28\xd0\x15\xb2\x83\x38\x6d" + "\x35\x9a\xdd\x40\x50\x75\x0d\x6d" + "\x9f\x46\x2b\x1d\xf9\xcb\xd7\x61" + "\x15\x31\xfc\x2e\x2f\x23\x7b\xf9" + "\xc7\xcb\x4b\xb2\x50\xd7\x51\xa5" + "\x56\xe3\xa1\x88\x49\x49\xea\x11" + "\x01\x75\xcb\x93\x31\xf0\x69\x76" + "\x8a\x7b\x73\xca\x5e\xc5\x5d\x59" +
+       "\x9f\x87\x37\xd8\xac\x19\xa3\xa4" + "\xb0\x67\x6b\xed\x9e\xb4\xc1\x6f" + "\xaf\xf3\xf1\x32\x33\x99\x95\xe3" + "\x2e\x2a\x43\x65\xeb\x42\x67\x96" + "\x28\x62\x96\xb4\xfe\xc9\x8d\x4b" + "\x50\x39\xf4\x43\x12\x63\xcc\x96" + "\xee\x31\xb7\xc9\x59\x88\x06\x12" + "\x68\x99\xf7\x56\xc3\x8d\x94\x7b" +
+       "\x08\x80\x1f\xed\x32\xad\xe4\x61" + "\x38\x75\xb1\xd8\x7a\x26\xc9\xe6" + "\xfb\xf6\x7f\x85\xeb\xc5\xc7\x1a" + "\x10\xfb\xf2\x55\xa8\xaa\x4b\x99" + "\x18\x80\x24\x1d\xe1\x14\xcf\x84" + "\x08\xc5\x8a\x62\x8b\x89\x39\x5a" + "\xf5\x44\xa9\x5f\x7b\xe9\xfd\x14" + "\xc7\x5a\x2e\xd1\x30\x80\x17\xed" +
+       "\xb4\xfe\xe2\x97\xf4\x2a\x2c\x04" + "\x13\x73\xbf\xae\xd7\x42\x6a\xd3" + "\xd7\xfd\x4f\x08\xeb\xc9\xd2\x49" + "\x6a\xc7\xf7\x2e\x4b\xa5\x8a\x9f" + "\x70\x5e\x89\x09\xba\xb7\x00\x92" + "\x58\xfb\xb7\xdd\x6f\xc6\xd0\x3b" + "\xbb\x4c\xeb\x78\x08\xd1\x97\x2d" + "\x31\xde\x4b\xd8\x68\x10\x43\x2d" +
+       "\x1f\xcd\x2c\x17\xb7\x3e\x52\x4b" + "\x92\xa8\xa6\x30\x28\xcb\x23\x73" + "\xeb\x53\xe1\xcf\xc0\x2e\x08\x97" + "\x97\xdb\xaa\xf2\x6a\x6b\x7f\xe9" + "\xa1\x3d\xa8\xd1\x3e\x39\x3d\x1d" + "\x68\x2a\x4b\x80\xc7\xf9\xa7\xa6" + "\x1e\xb7\x0c\x2d\x48\x8b\x68\x4a" + "\x78\x52\x58\x40\x5f\xcc\xb4\xa9" +
+       "\x32\xe1\x66\xcb\x6a\xb4\x5d\x5e" + "\x80\x58\x92\x0d\x3a\x96\xbe\xf1" + "\xe2\xb9\x17\x03\x27\x70\x4a\x94" + "\x48\x3d\x60\x48\x59\xf9\x66\xe2" + "\x99\x88\x20\x5c\x73\x66\xdb\x98" + "\xa3\x18\xfb\xa2\x47\x24\x47\x90" + "\x9f\x61\x7c\x77\x39\x69\x96\x8a" + "\x1b\xe2\x3b\x2a\x2a\x14\x98\x37" +
+       "\x43\xb3\x98\x32\xb1\x1c\x24\xb4" + "\xa1\x65\x4f\xb4\x49\x4e\xa1\xa3" + "\xcd\x7a\xc7\x3a\xcd\xd6\xf4\xc5" + "\x3c\xfc\xb6\x52\xb5\x8c\x28\xd0" + "\xbc\x0a\x04\x1c\x2f\x8c\xcc\xd5" + "\x4a\x9b\xbf\x06\x1e\x51\x75\xb6" + "\x41\xa4\x3a\x9b\x37\xda\x67\xd6" + "\x72\x1f\x60\x51\xce\x45\x0d\x46" +
+       "\x89\xff\x55\x67\x69\x3c\xf7\xe2" + "\xe6\x17\x30\x47\xe7\xf7\x3c\xdd" + "\x0d\x60\xf7\x3c\x9d\x68\xf5\x8e" + "\xb4\x87\xfc\xb1\xf8\xc4\x8d\x94" + "\x99\x32\xa5\x4e\x81\xfe\xe9\xd9" + "\x28\x60\xeb\x98\xa2\x1c\x92\x2d" + "\xfc\x03\x98\x0c\xfd\xed\xec\xfa" + "\x45\x47\x7b\x4d\x91\xe8\x8a\xf3" +
+       "\xd8\xa3\xe3\xc5\xcf\xfc\xc5\xd8" + "\xbf\xdf\x79\x40\x4c\x90\xfd\xbe" + "\x97\x01\xad\xfe\x58\x6a\x6d\xbc" + "\xa4\x32\x55\x69\x77\x70\x22\x39" + "\xf5\x42\xef\xdb\x6d\x3e\xe2\x09" + "\x08\x99\x0a\x48\x64\x9b\x44\x7e" + "\x40\x2e\x9a\xad\x1a\x9c\x96\x7b" + "\xa4\xc2\x91\x95\x92\xd7\x31\x62" +
+
+       "\x80\x8b\x96\x05\xf3\x96\x6d\xdb" + "\xb9\x73\x9f\x08\x13\x09\x0a\x38" + "\x01\x1e\xc6\xc2\x83\x0b\xa7\x7d" + "\xc7\x38\x9b\x56\x94\x83\xfb\x95" + "\x2f\xfe\xed\x80\x12\x65\x3c\x9a" + "\x82\xaf\xae\x8f\xb9\x6b\x72\x8f" + "\xf8\x4b\x42\x78\xa0\xa4\x10\x80" + "\x70\x49\x84\x0e\x44\x20\x67\x29" +
+       "\x2a\xd6\x2a\x7a\x81\xcb\xc5\x63" + "\x54\xff\x62\xac\xb9\xb6\xf2\x7e" + "\xb5\x9d\xad\xb3\xa4\xbb\x49\x37" + "\x17\xa6\xd5\x46\x2c\x1f\x31\xad" + "\x6d\x3b\xff\xc2\x87\x80\x7a\xb7" + "\xff\x34\x78\x36\xf3\xea\x6f\xb4" + "\x38\xb1\xd6\x75\x6d\x26\xaa\xf8" + "\x88\x81\x00\xec\x20\xd3\x38\xfa" +
+       "\xc6\x16\x69\x4e\xfc\xaf\xf2\xc0" + "\xda\x42\x18\x81\x57\x49\xb9\x6f" + "\x57\xd1\xb4\x24\xb6\xbc\x34\x60" + "\x90\xfb\x2e\x99\xc7\xfd\x2e\xde" + "\x87\x3c\x79\xac\xce\x7e\x6f\xd6" + "\xcd\xfd\xc6\x7d\x26\x26\xf0\x02" + "\x01\xc5\xa1\x9a\x5c\x23\xd3\x90" + "\xf0\x66\x46\x2b\x96\x94\xe4\xf6" +
+       "\xfc\x46\x69\x69\xfa\x8f\x6d\x48" + "\x6d\xa5\xcb\xb9\xd8\xc6\xfb\x50" + "\x15\x5a\xf3\x90\x3e\x42\x3d\x7e" + "\x2c\x96\xdd\xc0\x95\xa1\x3d\x7c" + "\x8b\x5d\xfd\x3c\xb0\xfd\x73\xe6" + "\xa5\xfc\x9d\x88\xc2\xb7\x04\x07" + "\xaa\x05\x23\xf5\x1f\x58\xce\xf6" + "\x53\x5e\x4d\x91\xeb\x49\x9d\x39" +
+       "\x53\xd4\x92\x7b\x36\x7c\xc9\x24" + "\xc0\x26\x9a\x24\xa2\x71\xc2\xd2" + "\x39\x4a\xd1\x89\x2b\x4b\xeb\x60" + "\x05\x80\x2e\x43\x20\xde\x98\x11" + "\xd9\x80\x9b\x79\x75\xea\xab\x9e" + "\xe5\x6a\x82\x8f\x2b\x0c\x6e\xab" + "\xec\x61\x00\xd1\xed\x4e\x00\xca" + "\xd8\x4f\x9c\xe9\x39\xf4\xa9\x31" +
+       "\xcd\x93\xc2\x6e\x6d\x49\x0a\x38" + "\xf5\x51\x70\x8e\xa7\xbd\x3d\x73" + "\x0a\x14\x49\xb8\x8d\x38\x7e\x03" + "\xf6\xdb\x46\x59\xb0\x32\x4b\xee" + "\xd1\x68\xe3\xca\xa9\xfd\xc4\xb1" + "\xf3\xb2\xb0\xfd\xb0\xa7\x01\x50" + "\x6e\xc4\x3a\x2e\x74\x93\xf5\x6d" + "\x56\xe6\xb3\x39\xf2\x75\xf6\x4a" +
+       "\xeb\x26\x78\xd6\x44\x7c\x0e\xb2" + "\x37\x96\x37\xac\xcf\xd3\x12\x12" + "\x5d\x3a\xe0\x7d\x87\x67\x4f\x61" + "\x26\xaa\x2b\x80\xfc\xa2\x38\x75" + "\x15\x24\x25\x9d\xa1\x37\x3c\x13" + "\x87\xb5\xb4\x6e\x50\x90\xb3\x7d" + "\xd9\xd1\x49\x4c\x57\xd7\x40\x5d" + "\xba\xc4\x01\xa8\x99\x6b\x12\xf1" +
+       "\x96\x92\x94\x39\x10\x81\xe3\x44" + "\xb5\xb1\x1d\x36\x7b\x82\x63\x5b" + "\xf5\xaf\x6e\x20\xed\x23\x53\x3e" + "\x90\x42\x1f\xc2\xd2\x70\x23\x94" + "\xa1\x85\xd9\xe0\x2e\xaf\xca\xf2" + "\x6d\x84\x39\x72\x4b\xc6\x2c\x19" + "\xf8\x12\x63\xae\x47\x8f\x0b\x7c" + "\x08\x01\x62\x96\x91\x1f\xc6\x7d" +
+       "\x47\x11\x96\x70\x96\xc9\xff\x40" + "\x8c\x2c\xc2\xc7\x42\x68\xe0\x79" + "\xbd\xbb\x97\x1a\xcc\xab\xf1\x63" + "\x88\x03\x73\xf0\xd0\x74\xea\xe9" + "\x66\xff\xef\xd9\x4d\x50\xc3\xa6" + "\x15\x20\xe0\x57\x38\xee\x54\x53" + "\xfa\x40\x70\x6d\xfe\xd7\xfe\x3b" + "\xac\x82\xca\x99\xcc\x95\x2c\x69" +
+       "\xe9\x7d\xda\xc2\x5b\xfb\x30\xb8" + "\xbe\xd3\xf8\x0f\xdf\x43\xe6\xd0" + "\x41\x96\x8a\x18\xba\x77\xee\x31" + "\x02\xd5\xf6\xbc\xaa\xa3\x8a\x4e" + "\x0f\x11\x49\x9a\x32\x65\xfb\xf9" + "\x20\xb2\xd6\x2d\xf6\x17\x83\xd1" + "\x5a\xea\xc3\x52\x41\xed\x3c\x7e" + "\x4a\x9c\x57\x7d\x14\x6a\x29\x0d" +
+       "\x58\x6c\x2f\x94\xca\x5a\x8b\x68" + "\x39\x94\x5d\x49\xc5\x89\x27\x6f" + "\x1d\x50\x4c\x50\x0c\xdb\x4d\xd5" + "\xa7\xe3\xac\xbc\x0f\x4d\x6a\xf1" + "\xeb\x41\x6a\x05\x6f\xbc\x6f\xb7" + "\xc5\xd6\x5b\x82\x55\xc2\x88\xe2" + "\xd3\xe2\x42\x0f\x96\x77\x03\x95" + "\x44\x7b\xb5\xde\xe3\x47\x3c\x9a" +
+       "\x17\x37\x4c\xed\x3e\xa5\xd6\x35" + "\xa3\xd2\x0e\x3d\xcf\x40\x82\x9f" + "\xa5\x3a\x54\xe5\x05\x4d\x0d\x8c" + "\xb4\xb4\x33\xdd\xfb\xbb\xd5\x45" + "\x8e\xd2\x7f\x13\x73\xcc\x04\xfa" + "\xfd\x3f\x3b\xc7\xef\xc6\x2a\x86" + "\xf2\x1e\xf5\x31\xf5\xf9\x3f\x40" + "\xa2\xf5\x73\xbc\xfc\xe0\xd5\x34" +
+       "\xb0\xfa\x59\x95\x21\xef\x9a\x2c" + "\x2d\x2f\x32\x62\xce\x61\x33\x83" + "\xf9\x0d\xba\x72\x2b\x5e\xfd\xd3" + "\x0a\x8c\x2d\x9d\x32\xe7\x85\xfc" + "\xd4\xb8\x5d\xf1\x75\x46\x23\xce" + "\x9a\x3f\x2d\xf5\x2e\xac\xf7\x6a" + "\x92\x65\xbf\x3d\x69\xf1\x55\x2d" + "\x38\x8e\x09\xd7\x6c\xcc\xc9\xb1" +
+       "\x4f\x3f\x91\x08\x20\x68\x52\xf2" + "\x95\x3d\xc9\xea\x61\xed\x20\xea" + "\x6c\xb2\xa6\x6c\xb4\x38\xed\x51" + "\xb0\x27\x43\xea\xbc\xdc\x62\x86" + "\xaa\x2a\x5d\x72\x5c\x29\xaf\x6d" + "\xda\xdc\x52\x8e\x2f\x75\xd2\xba" + "\xcc\xda\x17\x0b\x21\xe7\x10\x22" + "\x32\x82\x1e\xd5\x12\x79\x7f\xa3" +
+       "\xeb\xca\x40\xd5\x0c\x16\x00\x2a" + "\x88\x27\x1a\xa4\x5e\x14\x66\x6f" + "\xfa\x11\xc8\x51\x33\x1c\xc8\xf9" + "\x03\x54\x6f\x64\x0f\x8e\xe5\xee" + "\xe3\xfa\x18\xfc\xef\x20\xf9\x8d" + "\x6c\xea\x71\x09\x5e\x42\x23\x79" + "\xa7\xae\xa0\xcb\xb2\xdc\xe3\xe0" + "\xfc\x2d\x85\x4a\x5e\xaf\x1d\xbf" +
+       "\xdd\x3a\xcc\x44\xe1\x81\x70\x4f" + "\xcf\x82\xbe\x87\xd6\xa1\xff\xd5" + "\x72\x64\xdd\x0e\x6c\x0b\x89\x89" + "\x63\x78\xd1\x3e\x1a\x6e\xa2\xad" + "\xaa\x3c\x48\x63\x15\x27\x6f\x27" + "\xfd\x77\x60\x2f\xd9\x4c\x92\xe6" + "\x3c\x6e\x46\x0a\x98\xfe\xa7\x05" + "\x1f\x2d\x90\xb1\xb0\x94\xc7\xf1" +
+       "\x1c\x9c\xf0\xaa\x57\x63\x06\xee" + "\xd2\x76\x27\xab\x8d\x87\x53\x1c" + "\x4a\x32\x4e\xae\x4c\x72\xb5\x2c" + "\x52\x83\xfe\xe0\xad\x7c\x30\x13" + "\x96\x56\x39\x54\x78\xbb\x02\xef" + "\x31\x4d\xb6\xb3\xf3\x2d\x59\x2c" + "\xeb\x6a\x8b\xbc\x1a\x95\x05\xf0" + "\x5e\x27\x91\x6b\x82\xbe\x60\x57" +
+       "\x2c\x04\xa8\x82\x88\x36\x21\xe5" + "\x98\x82\x27\xcd\xaf\xcf\x31\xd9" + "\x40\xa7\x97\xf5\xe0\x0a\x9a\x06" + "\x7c\x10\x59\xeb\xf3\xb3\xdb\x0a" + "\xb8\x8e\xaa\x5e\x1e\x95\x3e\x98" + "\x78\x8e\xb4\x11\xb5\xa8\x63\xe6" + "\xc5\xf2\x03\x8a\x0d\xcc\x31\x16" + "\xe2\x71\xe2\x11\x1e\xc1\x77\x75" +
+       "\xf6\x8f\xa0\x74\x41\xbf\x5d\x08" + "\x0b\x46\x76\xa5\x40\xce\xba\x80" + "\x49\xba\xc1\x27\xcf\xcb\x04\xd2" + "\x49\x69\x80\xe4\x32\x2f\xd1\x64" + "\xe3\xe8\xdf\x01\x22\x22\xd4\xcd" + "\xd4\x83\x5c\xd0\x6e\x3c\x5b\x3b" + "\xc0\x00\xeb\xfc\xb3\x81\xc0\xb2" + "\x69\xd7\x67\xdd\xec\x3e\xc2\xe2" +
+       "\x90\x9a\x36\x08\x5c\x38\xb2\x33" + "\xf8\xb4\x0e\x19\x9b\xc5\x90\x29" + "\x80\xac\x8e\xc6\x45\x61\x9a\x81" + "\x14\xa0\xc4\x2e\x62\x6d\x78\x7a" + "\x8d\x3a\xac\x20\xbe\xad\xfa\x33" + "\x30\x2d\xba\x5a\x81\x17\xa2\x31" + "\x65\xf5\xa4\xdb\x42\x27\x9d\x20" + "\xbb\x0f\xaa\x55\xe3\xe9\x2c\xdb" +
+       "\xad\xe1\xcc\x63\xb5\x24\x4f\x6f" + "\x77\x3a\xb4\x9f\x2a\x67\x66\x51" + "\x1f\x9d\xc7\x4f\x78\x40\x78\xbb" + "\xf5\xbb\x74\xf7\x6c\x1a\x82\xb3" + "\x41\xf4\x02\xdf\xce\xd4\x7b\xa2" + "\xdf\x2a\x4e\xb8\xb9\x4e\xfa\xc5" + "\xde\xcd\xb7\xf0\xd7\xcb\x0b\x91" + "\xec\x1e\x5a\x2e\x48\x40\xe6\xb7" +
+       "\xdf\x84\x89\x16\x4b\x33\xef\x8c" + "\x38\x96\x87\x33\x17\xce\x1d\xe8" + "\xf0\x20\x37\x26\x9c\x94\xe6\xf6" + "\xec\xcb\x93\xf5\xaf\xfe\x56\x5c" + "\x84\x8c\xe5\xfd\x01\x56\xff\x8b" + "\x14\xb3\xcc\x2e\x17\x41\xe2\x74" + "\x78\x8a\x9a\x4c\x61\x1b\xf0\xbc" + "\x68\x98\x4c\x54\x5e\xe3\x33\xa2" +
+       "\xfb\xd8\x65\xc7\xc9\x4b\x93\x54" + "\x1e\x75\x0b\xb3\x71\x65\x96\xc1" + "\x17\xc8\xa7\x91\xcf\x2f\xfd\xc4" + "\x88\xc8\xb1\xdc\x7e\xbc\x6f\x24" + "\xff\x1b\xcc\x59\xfd\x4f\x30\x27" + "\x11\x58\x9c\xe5\x8d\x4d\x5c\xc3" + "\x21\x99\x1f\x40\xb9\xff\x63\xd8" + "\x61\x69\x80\x2e\x2e\x48\x14\x5b" +
+       "\xf1\xaf\xd7\x8b\xf3\x6b\x15\xb3" + "\x46\xb1\x81\x1d\xcb\xe4\x5e\x1b" + "\x15\xa9\x28\xd6\x41\xac\xa1\x7b" + "\x9e\x69\x89\xfd\x9c\x8f\x3a\x8f" + "\xe7\x8b\x74\xa0\xc9\xb9\x29\x73" + "\x1f\x62\x2e\xa9\x95\x1c\x39\x1d" + "\x37\xa8\x10\x4d\x21\x6b\x1e\xe5" + "\x35\xb4\x47\x49\x3a\xf5\x55\xd2" +
+       "\x2b\x88\x20\x1f\x5a\x04\x37\xc1" + "\x0c\x05\x7a\x9b\xf4\x16\x4b\x92" + "\xaf\x94\x66\xea\xf5\x26\xba\x8a" + "\x3e\x6a\x82\x69\x54\x28\x06\x29" + "\x27\x16\x8c\xb0\xcb\xd1\xf6\x2e" + "\x34\x0c\x8c\xc5\x84\x38\x31\x61" + "\xb4\xf1\xf6\xd8\x99\xc2\xc7\xa5" + "\x87\x9f\x3e\xff\xc0\xae\x5a\xcd" +
+       "\xe3\x8e\x78\xf1\x04\x9e\x66\x07" + "\xa2\x38\x69\xa8\xaf\x27\x4f\xc1" + "\xc0\x01\x3a\xe9\x34\xa3\x47\x8b" + "\x08\x68\x36\xd9\x38\x74\x62\xff" + "\x65\x59\x2a\xca\xd8\x85\x09\x7a" + "\xb3\xb9\xe9\xd6\x42\x55\x9a\x3d" + "\xe8\x72\xf9\x4c\x0b\xb8\x3e\xc2" + "\xfd\x72\xdf\x4f\xbb\x33\x1c\x5c" +
+       "\x5a\xd4\xb3\x4c\xdd\xbd\xca\x3b" + "\xa1\x67\x7d\x41\x6b\x4d\x38\xa9" + "\x54\xfa\xa8\x6a\xba\x5b\x9f\x65" + "\xcb\xf0\x0e\xcd\x21\x76\x93\x04" + "\x47\x23\x8b\x51\xf5\xb2\x80\xd4" + "\x80\x87\xe3\x1f\x1e\x97\x3c\x15" + "\x38\xb5\x07\xfe\xed\x08\x71\x15" + "\x29\x01\x11\xab\x03\x80\x0d\xca" +
+       "\x08\x61\xa8\x74\xd4\x58\x4a\x0c" + "\x90\x5d\x4c\xee\x8f\x8a\x04\xf8" + "\x80\x4c\x6d\xe8\x24\xc9\xc7\xe3" + "\x60\x1e\x6a\x05\xde\x89\xc8\x28" + "\x40\xa0\x14\xb2\x2e\x66\xe2\x57" + "\x47\x03\xe1\x37\x98\x8e\xc4\xe8" + "\x8a\x74\xac\x80\x62\x28\x74\x87" + "\xf2\x06\x6b\x18\x22\x40\xc2\xf1" +
+       "\xd7\x51\x4e\x09\x76\x33\xbb\xd0" + "\x7a\x87\xcd\x42\x22\xcc\x10\x51" + "\xc6\x97\xd1\xcf\x29\x57\xd6\x7b" + "\x71\x31\xca\x8a\x05\x94\x29\xf2" + "\xa5\xae\x55\x21\x15\x75\x84\x07" + "\x54\x1a\x82\x9a\x48\x2d\xf1\x84" + "\x5c\xaf\x37\x37\xf9\xc1\x8c\xb1" + "\x45\x58\x48\xba\xe2\x0c\xba\x4f" +
+       "\x0a\x04\x74\x5f\xc3\xd4\x2d\xac" + "\x57\xc9\xea\xfc\x71\xeb\x9a\x40" + "\x23\xec\xc4\x55\x82\xd7\xba\x4f" + "\xec\x76\x7b\x8a\x61\xed\x59\xb3" + "\x60\x4a\x6f\xed\x26\x49\x74\x12" + "\xe3\x2d\x91\x4b\x7f\x8d\x1e\xe2" + "\x59\x5a\x70\xfc\x59\x5a\x57\xe2" + "\x0e\xbc\x2d\xed\xde\xd4\xf1\x72" +
+       "\xd2\x72\x97\xb9\x5a\xd8\x79\x96" + "\x25\x1c\xcd\xdd\x7c\x71\x69\x82" + "\x77\xc3\xdc\xeb\x45\x20\x97\x50" + "\xdf\xc9\xe2\x6e\x83\xde\x13\xed" + "\x7a\x21\xa7\x50\x04\xf5\x39\x9f" + "\xb6\x07\xe0\xae\x41\xa9\x3b\xd3" + "\x9a\xec\x2b\xfc\x90\x71\x4f\x91" + "\x87\x24\xd9\xb0\x4e\x25\xd2\x70" +
+       "\xb8\x26\x79\xeb\xb9\x24\x2b\x3d" + "\x09\x55\xbe\xcd\xb3\x8c\xf8\xbf" + "\x0b\x64\xdd\xe4\xaf\x99\xf3\xd0" + "\x45\xed\x76\x2f\x30\xe1\x5f\x3c" + "\x3d\xfb\x64\x37\xf4\x62\x35\x6f" + "\x2d\xb6\x51\x31\x18\xf3\x5a\x7b" + "\xf3\xe5\x9c\xd7\xc7\x0b\xbd\xd5" + "\x0f\x89\x66\xec\x20\x6b\xaf\xfd" +
+
+       "\xa2\x35\x4b\xab\xe5\xb0\x72\x67" + "\xcf\xaa\xee\xf5\x01\x60\x8b\x1d" + "\x80\x95\x5b\x79\xe4\x7c\x8f\x72" + "\xda\x81\xfb\x41\x2a\xed\x20\x4a" + "\xe6\x01\xec\x4f\xd4\x5c\x68\x9f" + "\xad\x50\xff\xa7\xcc\xdd\xd7\x3e" + "\xfd\x97\x2d\x0c\x64\xd2\x0f\x46" + "\xf9\xf4\x82\xeb\x26\x14\x24\x3a" +
+       "\xd5\x21\xd7\xd5\x62\x98\x00\x80" + "\x82\xa1\xd3\x5b\xa3\x57\x33\x0c" + "\xa4\xcd\xa2\x7a\x3b\xa8\xf3\x27" + "\x85\x30\xf8\xf6\x4e\xe7\x8a\xb5" + "\x6b\xad\x6d\x2e\x81\x1a\x91\x2a" + "\x5b\x6c\x3d\xf4\x51\x60\x28\xde" + "\xd8\xc4\x96\xf9\x41\xcc\xdc\x4b" + "\x4e\xe2\xe1\x0a\xc0\x2e\x31\xe7" +
+       "\x70\xee\xe6\xaa\xfe\x68\xaf\x6f" + "\xc9\xb0\x02\x56\x15\xcc\xf4\x78" + "\x2a\x05\x94\x6e\xa8\x21\x33\x7e" + "\x80\x5d\x4d\x73\xd6\xa0\xb3\x2f" + "\xba\x43\x5a\xb2\x3b\x8f\xb9\xf3" + "\x51\x29\xee\x19\x31\x80\xbf\x30" + "\x2a\x61\xb0\x21\x33\xe4\xfe\x7f" + "\xd0\x21\xb8\x2e\xe4\x75\xf7\x12" +
+       "\xb3\x85\x64\x6e\xe7\x12\xd1\xf8" + "\xf8\x52\x1c\x77\xdb\x24\x3e\x4d" + "\x6d\x2f\x4a\x68\x41\xee\xe3\x48" + "\x51\x55\xd9\x21\x7d\x95\x61\x71" + "\x6c\x2a\xb1\xcd\x83\x12\x63\x19" + "\x64\xe1\x50\x2e\x82\xa8\x3f\xbf" + "\x73\xcc\x66\x31\x63\x4b\x25\xf6" + "\x38\xcc\xe8\xae\xae\xa7\xef\x3a" +
+       "\xa9\x29\xa9\x37\x80\x00\xf7\x46" + "\xbd\xc6\xfe\x19\x8e\x1a\x60\x65" + "\x62\x8b\xab\x12\xdc\x5e\x7f\x53" + "\xcf\x90\x59\x5e\x95\xcd\x97\xe4" + "\xf9\xb2\xa5\x9a\x7f\x38\xcd\x2f" + "\xe8\x8f\xb7\x67\xff\xa3\xfa\xe5" + "\x30\x5e\x5d\x29\x8d\x53\xcf\x1b" + "\xec\xa7\x13\xa8\x39\x32\x57\x3a" +
+       "\x09\x24\x7c\xd1\x6b\x28\xf5\xe9" + "\x9b\x4d\x26\x63\x93\x47\x4e\x2c" + "\x0f\x88\xf6\x17\xb1\x42\x70\x17" + "\x43\xee\xe1\x4c\xc8\xe2\xb7\x39" + "\xa9\xf4\x96\xd0\x22\xe7\xc8\xce" + "\x97\xe6\xd5\xbe\xcb\xae\x61\x68" + "\x11\x19\x23\x6c\xf0\x53\xd1\xc2" + "\x7a\x53\x90\x28\xb8\x42\x2f\xcc" +
+       "\xb4\x17\xa9\xd0\x51\xcb\xe2\x33" + "\x31\xf9\x99\x48\xf3\xa3\xcf\xc2" + "\xb6\xf6\xa2\xe9\x4b\x4f\xc9\xb2" + "\xb7\x62\xa1\x7c\x81\xb1\x07\x97" + "\x0d\xb1\xf8\xd5\x72\xa1\x02\xb6" + "\x2a\x54\xd4\x4f\x35\x78\x30\xfd" + "\x92\x69\x99\xdd\xdd\x26\xf2\xee" + "\xe1\x15\x0a\xeb\x89\xa9\x1f\x22" +
+       "\xfd\xf9\x36\x3b\x62\xfe\xb0\x79" + "\xc0\x9f\xe1\xfd\x23\x3b\x54\x26" + "\xef\x82\x84\x95\xa0\x64\x6e\x13" + "\x25\x58\x09\x9b\x71\x37\xf6\x23" + "\x2e\x14\xa1\xb6\x96\xd5\xcf\x14" + "\x0b\xac\x5a\x33\xc6\xaa\xa6\x5e" + "\xd5\x1d\x08\xf3\xbd\xe8\xa0\x86" + "\x2a\xc1\x3d\x00\x79\x9d\xb8\x5f" +
+       "\xa3\x32\x11\xde\x77\x86\x62\x73" + "\x47\x88\xa8\x2f\x64\x7e\x12\x75" + "\x60\xe6\x49\x5b\x30\x7a\x2f\x19" + "\xa9\x6a\x43\x11\xfe\x3c\x06\x1a" + "\x89\x01\x71\x4b\x57\x14\x00\x72" + "\x8d\x37\x57\x2a\xde\x46\xa9\xfa" + "\x66\x30\x1c\x19\x63\x5c\x49\x5c" + "\xdb\xb4\x7d\x6b\x65\x7e\x4b\x2b" +
+       "\x13\x04\x63\xd0\x7a\xd2\xe3\xa4" + "\xeb\x56\xfa\x19\x82\xe3\x70\x57" + "\x66\x06\x4c\x75\x7a\xcf\x65\x44" + "\xf3\xc5\x69\x61\xd2\x61\x91\xfe" + "\x48\xe3\x0e\xdc\x22\x27\xf6\x5d" + "\x54\x04\x89\x29\x6a\x59\xc6\x9c" + "\x2a\x32\x5d\x9f\x18\xd6\x43\xf0" + "\xe9\xe3\x1e\x18\x7a\x95\xce\xb4" +
+       "\xed\x62\x5c\xfe\x49\x0a\x19\x08" + "\x3d\x18\x91\x36\x3d\x54\x57\x2c" + "\x23\x48\x04\xa9\x8b\x31\xee\x75" + "\x58\x8f\xf2\xae\x9e\xe0\x0c\xd2" + "\x66\x4a\x8a\x84\x50\x3d\x61\x10" + "\xfb\x2e\xcf\x9f\xa8\xa1\x98\x4b" + "\x27\x64\xfc\x98\xd9\x1e\x5f\x41" + "\x50\x2b\x85\xe3\x56\xbb\x6a\x08" +
+       "\xd4\x34\x2e\xf7\x3a\xc3\x15\xf6" + "\x35\xec\x0e\x11\x40\xea\xd9\x0b" + "\x4e\xa3\xde\xc1\x5b\xbc\x12\x1c" + "\x99\x46\xae\x49\xc9\x84\x65\x68" + "\x42\xb9\x97\x8c\xd3\x95\xad\x13" + "\x62\x75\x5c\x4e\x1a\x56\x09\x46" + "\x89\x7f\x73\xf2\xae\xa4\x94\x9e" + "\xb6\x78\x1c\x37\xc6\x94\x75\xf5" +
+       "\xde\xa9\xed\x19\xd9\x8c\x76\x5a" + "\xd2\x51\x2a\x8e\xf4\x06\x32\x6e" + "\xef\xa3\x78\x86\xc0\xe8\x56\xd3" + "\xc9\x91\x3f\x54\x6d\xd3\xf8\x93" + "\x43\x67\x08\xa4\xf4\x31\xf2\xfe" + "\xc9\xc6\x48\x91\x11\x9a\x37\x4d" + "\xce\x32\x82\xdc\x1d\x58\xb5\x00" + "\x4b\x21\x02\xd7\xef\x72\x7a\xa6" +
+       "\x92\xe8\xb4\x17\xf6\xa9\x45\x61" + "\xf1\x9f\x22\x5f\x27\x02\x64\xfe" + "\xa3\x6b\x04\xdc\xa8\x3e\xb0\x6d" + "\xcc\xda\x51\x03\xd6\x73\xc8\x71" + "\x5b\x7b\x94\xc2\x37\xe3\xae\x4b" + "\x80\x43\x8b\xb0\xc7\x85\x08\x90" + "\xb9\x79\x45\xc8\x61\xa6\x1e\x1f" + "\x18\x78\x01\xa5\x93\xbb\xdd\xcc" +
+       "\x80\xb4\x9f\xcf\x3d\x88\x4d\x55" + "\x4d\x9a\xfb\x0d\xc5\x71\xca\x76" + "\xea\x40\x42\xe0\x2b\x14\x51\xc2" + "\x99\xfc\x7a\xfa\x3d\xa6\x9b\x89" + "\xa3\xcd\xbb\x9f\x12\x5b\x94\xed" + "\xcc\xa4\x99\xa2\x28\xd5\x4d\x3c" + "\x92\xc0\x63\x8a\x09\xb6\xe8\x68" + "\x1b\x62\x40\x3f\x6c\x0a\xf5\xec" +
+       "\xe3\x9e\x77\xe3\xfc\x65\x01\x0f" + "\x9e\x5d\x49\xbd\x9d\x7f\x0e\xe0" + "\x7a\x4e\x28\x20\xa2\xef\xa4\x1f" + "\x19\x62\xac\x47\xde\xba\x64\x45" + "\x8e\x8e\x70\xc4\x2a\x31\xe6\x90" + "\xdf\x9a\x1e\xa7\xfb\x25\x57\x4f" + "\x9f\x4b\x68\x3d\xae\x55\x5f\xe9" + "\x15\xb4\x94\x1e\xb1\xcc\xf7\x47" +
+       "\x01\xc2\xad\xa8\xbe\x48\xfd\x50" + "\xa8\x06\xdf\x40\x00\x18\x18\xce" + "\x22\xce\x82\xde\x42\xca\x07\x6c" + "\x1a\x76\x24\x5a\x51\x6c\x64\x23" + "\x2f\x39\x68\xb2\xf8\x91\xcf\x46" + "\x86\x14\x81\x81\xff\x57\xb7\xe4" + "\xa0\x02\x61\xd2\x0b\x57\xdd\x94" + "\x80\xdf\x65\x3e\x2d\x4d\xc3\x2d" +
+       "\xd3\x56\xde\x56\x44\xaf\xfe\x18" + "\x22\x79\x02\x61\xe8\x68\x95\xb3" + "\xdc\x58\xa4\x28\x5c\x68\xb8\xa2" + "\x17\xa8\x95\x62\x6c\xbf\xa8\x41" + "\xdc\xd1\x98\xca\x74\x40\x29\x7b" + "\xbe\x13\xe0\xb3\x59\x82\xc4\x94" + "\x56\x52\x4f\x2c\x24\xd5\x2e\xb4" + "\xec\x9f\x7c\xda\x50\x89\x8e\x30" +
+       "\x1d\x54\x6c\x31\x83\x70\x02\x46" + "\xcc\xab\x9e\xd3\x6b\xbc\x05\x7f" + "\xdc\x0c\xc2\x60\xa1\xfa\x37\xb8" + "\x06\x9d\xd3\xac\x1a\xf3\x8b\x4f" + "\x51\x20\x51\x00\x95\xdc\x31\x83" + "\xac\xa2\x2a\xaf\x62\xf4\x74\x53" + "\xa3\xb1\x2a\xf3\xb4\xd9\x73\x76" + "\xfc\x49\x4f\xd6\xac\x51\xe1\xa6" +
+       "\x81\x65\x94\x8d\x1b\x85\x22\x73" + "\x12\xa0\xf4\xbd\x33\x31\xd1\xf0" + "\xe0\xda\x84\x65\x69\x0f\x51\xa3" + "\x6d\x6c\x9f\x3c\x71\xc1\xa7\x03" + "\x1a\x38\x75\xe4\x38\x7f\xe9\x5b" + "\x34\x33\x82\x85\x22\xa4\x1b\xca" + "\xda\x7d\xe1\x0b\xc7\xc5\x3c\xf8" + "\x0f\x8c\x91\x0b\x94\x14\x8b\x15" +
+       "\x05\xf7\xa5\xdb\x88\x8a\x18\xb7" + "\x8b\xd8\xfa\xa1\xa6\xfc\xfe\x5c" + "\x95\x85\x8e\x33\x04\x88\x2d\xed" + "\x81\x09\xb4\x7e\xf8\x0b\x23\xc0" + "\xc7\xf7\x87\x4b\x78\xf1\xd1\x3e" + "\x2a\xd0\x9e\x7f\x76\x60\x1d\x9d" + "\x5b\x8d\x3f\xf2\x8b\x26\x90\x22" + "\xb9\x68\xd3\x86\x35\x4c\x90\xad" +
+       "\x82\xd6\xfb\x2a\x05\x96\x64\xdc" + "\xb1\xb0\x37\x16\x13\xfb\x08\xac" + "\x9d\xf3\x84\xa1\x88\xd4\x9f\xdf" + "\xb2\x25\xe3\xac\x23\xbc\xc2\x1f" + "\x84\x9a\x6c\xbd\x36\x3b\x87\x29" + "\x9d\x52\xf8\x3c\x15\x11\x2c\x46" + "\x2d\x21\x55\xc5\x0d\x37\xe0\xb3" + "\xc6\xec\xaa\x89\x75\x3f\xf8\x31" +
+       "\x99\x5a\xde\xb7\x31\x74\xdf\xb1" + "\x3c\x87\x95\xf2\xe6\x8e\x52\xfb" + "\x95\x3c\x30\xcc\x0f\x50\xa1\xec" + "\x60\xb7\x33\xce\x97\x05\x39\xdb" + "\x36\x97\x76\xe4\x86\x14\x96\xd6" + "\xa2\x9d\x33\xc3\x28\xe4\x45\xd2" + "\xce\x6c\x10\xfa\x41\x7f\xca\xf5" + "\xdd\xac\x80\x70\x32\xb1\xed\x37" +
+       "\x69\x6b\x2e\x52\xe5\x77\x3a\xda" + "\x18\x6c\xcd\xbb\xc3\x08\xc9\x69" + "\x56\xfd\x24\xd9\x48\x9e\x1b\x1f" + "\xf7\xb3\x4b\xaa\x36\x4e\xc6\x37" + "\x7d\x8d\x47\xee\xdf\xdb\x4f\x5a" + "\xa0\xf7\x93\x01\xbc\xc8\x75\xba" + "\xdf\x16\xcd\x56\x84\x1e\xbc\x84" + "\x51\xd1\xfa\x46\x08\x8f\xb0\x1f" +
+       "\x36\xbb\x6b\xb2\xef\x01\x33\x29" + "\xfa\x4d\x64\xa9\xf8\xca\x68\x45" + "\x0c\x3c\x0c\x3e\x05\xae\xac\x0d" + "\xa8\x51\xa6\xec\x02\xd5\xa6\x2b" + "\x0b\x61\x04\x60\x68\x59\xbd\xe3" + "\x45\x72\x2b\x28\xf6\x6a\x07\xc2" + "\xa4\xe9\x94\x1e\x4a\xf2\x61\xae" + "\x63\xf1\x76\x15\x5c\x99\x15\x03" +
+       "\x47\x15\x57\x74\x3d\xff\xf8\x2a" + "\x19\x9b\xe1\x2c\x07\xea\xb3\x7e" + "\x85\x99\x09\x9b\x88\x62\x1b\xb8" + "\xc5\x09\xa3\xea\xd6\x22\xec\xdf" + "\x19\x34\xc3\xcf\xe2\xa0\xb5\xf9" + "\xa0\xb3\x65\xdb\x9c\xb6\xbf\x70" + "\x95\x4d\x52\x3f\x56\x15\xec\x75" + "\x30\x2f\x80\xe0\x37\x97\xed\xe5" +
+       "\xe0\x53\xc7\x04\x2b\xf4\xe7\x6a" + "\x6c\xd4\x06\xe6\x00\x42\x09\x26" + "\xa4\xdc\x80\xf6\x39\x2f\xb0\x3a" + "\xda\x37\x3b\x73\xa9\x53\x88\x9b" + "\x6a\x38\x5d\x85\xae\x34\x11\x2e" + "\x61\x9b\xed\x88\xe1\xbe\xa8\xd8" + "\x59\xd4\xed\x83\xc0\x8b\xa0\x2f" + "\x68\xe1\x0f\x2d\x51\x21\x4d\x94" +
+       "\x30\x9f\x2e\x84\xf9\xab\x7c\x8a" + "\xaf\x83\xab\x5e\xbf\xd4\x31\xa3" + "\x6a\x2a\x7f\x01\xba\xcf\x72\xd2" + "\xe3\xa0\xab\x83\xbc\x0a\x56\x27" + "\x75\x6b\x3a\x0e\x87\x33\xb8\x94" + "\xf5\x50\x9f\x6b\xa2\xae\xc6\x25" + "\xd0\xf6\xfd\xb5\x1d\x69\x3d\x80" + "\x14\x35\x33\xe6\x09\x75\xb7\x03" +
+       "\x6f\xcf\x14\xbd\x34\xe2\x5e\x74" + "\xbb\x24\xc0\x49\x84\x50\x8b\xde" + "\xb4\xd7\x35\xef\xdd\x4f\x33\x9c" + "\xb4\xb2\x64\xb7\x28\x77\x64\xff" + "\x31\xe0\x21\xcc\xd7\xee\x4d\xf9" + "\x85\x28\xd8\xa0\xb8\x40\x47\xe3" + "\xfb\xd2\x85\xc7\xc4\x17\x03\xa7" + "\xae\x8c\xa5\xf8\xc5\x6a\x05\xdc" +
+       "\x5f\x04\x78\x88\x8e\x4e\x27\xc4" + "\xe0\x25\xc3\xeb\xeb\x98\x66\x21" + "\x56\x6c\x39\x09\xcf\xbb\xef\x0f" + "\x5e\x80\x91\x04\x15\x19\x19\xdc" + "\xa2\x80\x54\x5c\x87\x4e\x4c\xa7" + "\x0a\xce\xc8\x72\xb3\xd1\xa8\xde" + "\xc1\xfa\x77\x7f\x1d\x70\x9f\x67" + "\x70\xb5\x6a\x6d\xb5\x00\xba\x3e" +
+       "\xce\x50\x23\xf2\x20\x4e\x00\x08" + "\x4e\x1c\x60\x8d\x19\x45\x45\x6b" + "\xd5\x77\xe1\xd5\x5a\xdc\x09\xea" + "\xd9\xba\x34\x75\xaa\x19\x3e\x92" + "\x46\xc0\x80\x31\xa6\x05\x29\xa4" + "\xaa\x64\xc8\xd3\xd0\x9e\x27\x0c" + "\x51\x5a\x90\xff\xb6\x41\xf3\x49" + "\x32\x6b\x96\xa7\x88\x09\xe2\x2b" +
+       "\xc1\x41\xa3\x61\x03\x89\x17\x36" + "\x42\x61\xfd\x0c\x60\xdc\x04\x36" + "\x6c\x31\x33\x85\xeb\x95\x22\x02" + "\x22\x29\xaf\x44\xac\xe4\xbd\x3d" + "\x69\xef\x7e\x1c\x5d\xfc\x8a\x89" + "\xa1\x4f\x4f\xd1\x05\x68\x89\x58" + "\xca\x21\x3c\x20\x60\x21\x00\x05" + "\x0b\x73\xef\x40\x30\x1f\x0d\x6f" +
+
+       "\x5a\x19\xf7\x77\x09\x77\xbf\xfa" + "\x8f\x83\xeb\xad\x67\x61\xc8\x8e" + "\x2d\x01\x4f\xbb\xa8\x85\x12\xea" + "\x3f\xab\x3e\x9a\x03\x35\x88\xd6" + "\xc2\x04\x90\x30\xf8\x24\x5d\xee" + "\x5e\xe9\xff\x13\x76\x4b\x6e\xa9" + "\xa4\x3e\x22\xbd\x12\xfe\xdf\x0c" + "\x53\x9a\x73\xb6\xe5\x2e\x5c\x8f" +
+       "\x02\x38\x76\xbd\xa9\x6a\x40\xed" + "\xa1\x3d\x30\x65\xa0\x86\x14\xc2" + "\xc4\x2e\xe6\xc7\x1e\x29\xae\x61" + "\x3e\x33\x99\xdf\x92\x04\x2a\x62" + "\xe0\x8e\x7a\xbb\x9d\x0c\xd8\x7f" + "\xdb\xae\x01\x6c\xbc\xd3\x2e\xdc" + "\xec\x74\xbe\x08\x12\x5a\xc3\x35" + "\x1f\x67\x9f\x46\x1a\xcb\x40\xd5" +
+       "\x5b\x6f\x77\xbf\x5a\x3c\xe5\x2c" + "\x05\x7b\x35\x60\x71\x40\x72\x6f" + "\x7a\x3f\xbf\x71\x17\x37\x59\xb2" + "\x9f\x4a\x0c\x44\x1c\x50\xd2\x87" + "\x40\x53\xb0\x87\xe1\x52\x05\x44" + "\x32\x4c\x62\x21\xc8\x7c\xbf\xb7" + "\xdb\xcd\xfa\x22\xce\xa6\x55\x41" + "\xef\x37\x98\x88\xcb\x28\x42\x5a" +
+       "\x20\x5e\x4c\x58\x6a\x74\xa8\xa7" + "\x35\x70\xdc\xb9\xa1\x4e\x7e\x26" + "\x9b\x8c\x54\xb9\xcf\x15\x3a\x59" + "\xf3\x12\xd0\x4b\x35\x21\x6e\x5e" + "\x6e\x93\x8f\x8c\x6a\xcc\x31\xdf" + "\xdc\x41\xc2\xb5\x04\x4d\xf8\x8a" + "\x86\xfb\x5e\x34\x6f\x0a\x99\x63" + "\xcb\x62\xb9\xb9\x61\x4e\xef\x6f" +
+       "\x8d\xe4\xa2\xe1\x46\x82\xc4\x23" + "\x5c\xce\x3d\x54\xd1\xe6\x15\xf0" + "\xe9\x1d\x6d\x28\x52\xdb\x9e\xd1" + "\x56\x6f\x82\xdf\xf6\x87\x07\xd6" + "\xe3\x59\x14\x1c\xfe\x5d\x1d\x6e" + "\xdc\x6c\xb0\x9e\xa4\x99\xe8\x26" + "\xdb\xfb\xa1\x14\xc9\x60\x95\x02" + "\xf5\xb4\xd3\xb3\x2f\x84\x78\x8b" +
+       "\xcb\xec\xbe\x22\x9c\xfa\x6d\xc5" + "\xc0\xd7\x88\xa1\x4a\xa9\x41\x9c" + "\x29\x47\x32\x70\xa1\x83\xc2\x36" + "\x11\x65\x3f\xb6\x50\xe2\xa0\x2d" + "\xa0\x24\x5e\x7b\xd2\x9f\x4d\x83" + "\x42\xdd\x34\x6c\x1b\xb7\x26\xac" + "\xd9\x36\x93\x32\x97\xb4\xf1\xe5" + "\x9d\x4a\xe9\x39\xcf\x1a\x68\xdc" +
+       "\x30\x7b\xd7\x6c\xef\xcc\x80\x5c" + "\xd0\xb6\x99\xec\x99\x82\x97\x49" + "\x35\xd3\x39\xb9\x5e\x48\xf4\x6b" + "\x47\xc1\xd7\x86\xab\x61\x3e\xc5" + "\xdd\x1d\x60\xfb\x52\x80\x94\xdd" + "\x48\xdd\x11\x35\x39\xeb\xc5\x34" + "\x1c\xf6\xe6\x00\x76\xc6\xf5\x91" + "\x34\x1f\xe7\xb1\x25\xb5\xf1\x33" +
+       "\x08\x26\x72\x25\x09\x8f\x36\xf6" + "\xc6\xf5\x1c\x13\xdb\x60\x12\x13" + "\xac\xf7\xb4\xfa\x3b\x35\xeb\x40" + "\x29\xe8\xee\x37\x80\x88\xc7\x85" + "\x4e\xf2\xbd\xc3\xff\x81\x15\x4c" + "\xa8\xc5\xc3\xf5\xcb\x75\xff\x5b" + "\x40\x6f\x4e\xa1\x3f\xc8\xe8\x35" + "\xca\xe0\x95\x02\x0f\x1c\x1d\xb8" +
+       "\x1d\xdd\xd9\xee\xf8\x53\x71\xde" + "\x2e\xcb\xeb\x52\x11\xad\x09\xba" + "\xb6\x3f\x84\xe1\x15\xb0\x41\xaa" + "\xf0\xe6\x4c\xdd\xab\xa2\x33\xf9" + "\x3f\xb8\xf6\x13\x43\x83\x7f\x77" + "\x75\x3a\x11\xdb\xa4\x7d\xdf\x28" + "\x43\xd1\xa5\x72\x3c\x1b\x7d\x6d" + "\xdf\x6d\x6c\x96\x98\x96\x78\x6f" +
+       "\x54\xa0\x2b\xa7\x33\x9a\x43\xed" + "\xba\x65\xd2\xea\x15\x0a\x17\xa3" + "\x8e\xa5\x99\xfe\x03\xb9\x7e\xcf" + "\x26\x0c\xd8\x33\xc6\xb0\x6d\xcf" + "\x1a\xe7\x13\xf6\x5e\x25\x31\xd0" + "\x5c\x25\xca\x18\x57\xbe\xcc\x12" + "\x0d\xc4\x08\x78\x53\xd0\x21\xdd" + "\x6b\xbe\xf2\x3a\xbc\x8e\x48\xf5" +
+       "\xc5\xf9\xe3\x1b\x7c\x0d\x11\x47" + "\xdd\xb4\xad\x5e\x48\xe4\xb9\x12" + "\x41\x3d\x71\x0b\x87\x09\x8c\x6e" + "\xae\x56\x3d\x73\x56\x03\xe2\xe1" + "\x27\xa7\x5e\x44\xab\x6b\x8d\xe6" + "\xa4\xa1\x34\xc9\xea\xf6\xf4\x9e" + "\xc3\xf1\xce\xf8\x47\x55\x15\xe0" + "\xbf\xdc\x9b\x15\x09\x39\x5c\xdb" +
+       "\xd1\x8a\x2a\x44\x3d\xe2\xef\xf2" + "\x64\xc1\xb9\x06\x7d\x6a\x81\xc3" + "\xe5\xa5\x0a\xdc\x8b\x2d\xdf\xa9" + "\x65\x8e\x0a\x12\x6f\xe4\x1a\x19" + "\x5b\x1c\x61\x00\x87\x7f\x66\x83" + "\x48\x99\x10\xff\xd7\x1e\x17\x83" + "\x52\x59\x69\xca\xf8\xec\xa2\x33" + "\x13\x1a\x8d\xf4\xee\x73\x4a\xfa" +
+       "\x7d\x00\x04\x66\x84\xcf\xca\x97" + "\xf1\xa9\x47\x2d\xb2\xb4\x92\x1e" + "\x65\xd1\x4e\x37\xd6\xe0\x8a\x85" + "\xb8\xef\x7a\x30\x6f\x3e\x97\x4c" + "\x72\xeb\x10\x8a\x23\x4a\x52\x6f" + "\xd6\x49\x28\xeb\xa9\x92\x4a\x7b" + "\xdd\x1e\xe9\x2f\xa4\xbd\x78\x36" + "\x5c\xc3\x0f\x7c\xcd\x2a\x09\x56" +
+       "\x17\xe5\x10\x0b\xf1\xe9\x13\x35" + "\xd4\xc1\x81\x69\x44\x25\x7d\x40" + "\xc1\xab\xd9\x60\x48\xa8\x53\x49" + "\xd0\xd5\x4f\x8c\xe4\xbd\x8d\xe3" + "\xb1\x5a\xbb\x81\xc5\x16\x52\x7e" + "\xa1\xe0\xc5\x06\x6b\x04\x8a\x32" + "\xa6\x5e\x16\x91\x44\xf6\x34\x52" + "\x36\x0d\xac\xcf\x0f\x8b\xe6\xb6" +
+       "\x40\x3b\x09\x1a\x63\x5b\x1d\x09" + "\x4a\xf2\x62\x58\x07\x1c\x5c\xb8" + "\xbf\x85\x8f\x3e\xb5\x4e\xd7\xc5" + "\x56\x24\xb2\xca\x46\x77\x1c\xf5" + "\x89\xda\x61\xe7\xd9\xb8\x5c\xc2" + "\xb5\x28\xf0\xc0\x2f\xec\x70\x26" + "\x5c\xaf\xb9\x2d\x0d\xd3\x3f\x87" + "\x5e\x56\x62\x82\xa1\x1e\x0f\x3d" +
+       "\x0f\x73\x3a\xf4\xc8\x7c\xde\xfc" + "\x0e\x59\xab\x33\x3c\x6f\x9b\xe8" + "\x0b\x24\x03\xad\x29\xf5\x23\xc8" + "\xdb\xa5\xbe\x98\xfe\x9a\xb7\x82" + "\xde\xe5\x2f\x96\x56\x28\x8f\x56" + "\xf3\x91\xc5\x60\xdb\x0a\x59\x0c" + "\x58\xa8\x28\x4a\x14\x4a\xc7\x1f" + "\x4c\x3f\x20\xb3\x98\x24\x66\x3b" +
+       "\x4f\x8c\xce\x88\xe2\x30\x5c\x75" + "\x3d\x3c\x63\x21\xc8\x8f\x63\x56" + "\x2d\x7c\x5a\xa0\xff\x00\x60\x88" + "\xc6\x18\x02\x01\x31\xe5\x92\x8f" + "\xa3\x64\x17\xb8\x03\x79\xee\x09" + "\x91\x47\x63\x3c\x97\x36\xc2\x95" + "\x13\x2f\x8e\x4e\x22\xf5\xec\x3c" + "\xf8\x4f\xc3\x23\x6c\xd6\x1e\x5d" +
+       "\xbf\xb3\x30\x19\x22\xfb\xae\x9e" + "\x73\x9c\xa1\x22\x08\x6b\xc0\x25" + "\x98\xa4\xd3\x4b\x2a\x57\xa8\xd0" + "\x51\x63\xd7\x0c\x2f\x85\xbc\x20" + "\xda\x25\x89\xb3\x6d\x38\x01\x83" + "\x85\xf2\xec\x64\x6a\xe6\xfb\x85" + "\x7f\x61\xc9\xc0\x84\x7e\x74\x53" + "\x72\x17\xbe\x1d\x26\x1d\xd6\xb0" +
+       "\x8a\xff\x0d\x8d\x95\xc2\x84\xe5" + "\x05\x63\x24\xef\x8b\xf4\x2b\x55" + "\x3e\xdb\x45\x4f\xa5\x21\x9c\xc0" + "\x8f\xbb\xee\x3c\xec\x83\x30\xca" + "\xe2\xc6\x6d\x40\x7c\xd0\x4d\xbf" + "\x01\x30\xf6\xa7\x6d\x62\x96\x0e" + "\xd3\xcb\x16\xaa\xfe\xfb\xa9\x81" + "\x00\x13\x3a\x67\x5c\xca\x7e\xfe" +
+       "\x6a\x1b\xdd\x82\xd0\x4e\xfc\x48" + "\xaf\x03\xb7\x67\x38\xa1\x83\x57" + "\xaa\x6a\x5d\x00\x9a\xcb\x63\x24" + "\x43\xcd\x6e\x70\x5c\xc5\x1e\xd3" + "\x41\x76\x9a\x8e\x3f\xd3\x8e\x9f" + "\x7a\x9e\x8d\x09\xed\x53\x54\x62" + "\x93\x74\x88\xec\xe4\xad\xbe\xa3" + "\x66\x55\x79\x5a\x50\x80\x2b\x44" +
+       "\x17\x50\x96\x0c\x31\x62\x0c\x98" + "\x4f\x7a\x0d\x40\xb3\xc0\x8c\xaf" + "\x97\xcf\xf4\x48\xe2\x12\x58\xee" + "\x5e\xd9\x90\xbb\xb8\x7e\x58\xe4" + "\x5e\x04\x52\x81\x7f\xa5\x42\x1b" + "\x2e\x7c\x1c\x64\x06\xb9\x92\xd7" + "\xda\x87\x1c\xa7\x93\xf5\xfc\x9d" + "\xb9\x00\x04\x1b\x77\x7d\xab\xc7" +
+       "\xe2\x70\x5a\xd8\x34\x2d\x95\x16" + "\x52\x1a\x2e\xc3\x97\xff\x09\x7d" + "\xbf\x8a\x2d\xa6\x3e\xe4\xd6\xca" + "\xbb\xfe\xaa\x25\xda\x46\x76\x74" + "\xbd\x24\x4e\xe5\x96\xc4\x65\x03" + "\xe3\x50\xe8\x24\x16\xa4\x99\x14" + "\x2b\xd2\x81\x67\xf7\xdd\xf6\x24" + "\x81\x59\xc3\xbf\xf1\x55\xe5\x42" +
+       "\x38\x33\xcd\xfa\xc2\x19\x23\x5b" + "\xd1\x3e\x88\x6f\x47\x50\x96\xed" + "\x19\x16\x83\x16\xc3\x96\x07\x37" + "\xaa\x61\x6b\x20\x69\x34\xb7\x8d" + "\xe8\x08\xa9\x1f\x17\x5d\x0e\x0a" + "\xfa\x40\x54\xb4\xe3\x71\x72\xe8" + "\x98\xdb\x2b\x07\x3e\xe0\x6a\x7f" + "\x8a\xb9\xc3\x28\x55\xf7\x87\x06" +
+       "\x5a\x76\x39\x6c\x0d\xcf\xe3\x91" + "\x0b\xca\x3c\xac\xcd\x3a\xdb\xa2" + "\x50\x3b\x95\xcb\x08\x2f\x8f\x28" + "\x1a\xcf\x43\xcf\x2c\x58\x14\x24" + "\xa8\xe9\xee\x60\xbc\x8b\xec\x8d" + "\x42\xa0\x9a\x72\x02\x9f\xc7\x54" + "\xd5\xf5\x32\x65\xec\xd5\x1c\xd8" + "\x5f\xe1\x82\xcf\x3a\x30\x72\xa6" +
+       "\xff\xf5\x73\xc3\xe2\x03\xbd\xb3" + "\x41\x63\xfc\xe7\xb4\xa8\xa8\x80" + "\xdf\x7b\x08\xa0\xd6\x52\x29\xb7" + "\x8e\xa3\x48\xc0\x9d\xbb\x3c\x80" + "\x00\xb0\xf8\xcc\x7e\x65\x0a\xcf" + "\x09\xeb\xe1\x67\x18\xc0\x54\x8c" + "\xfc\x46\xb6\xf0\x26\x10\xf9\x88" + "\xd8\x4b\xff\x7d\x53\xf2\x0d\x9d" +
+       "\x42\xd5\xc6\x48\x80\xc9\xfb\x4e" + "\x2e\xf4\x25\xc9\x00\xc2\x9c\x26" + "\x3e\xfe\xf6\xbc\x6a\x44\x5a\xb5" + "\xc5\xe5\x67\xac\xd5\xdb\x02\xb0" + "\xd8\x8e\xda\xee\x64\xee\xec\x91" + "\xd2\x71\xe0\xba\x2d\xf9\x89\x89" + "\x53\xbf\x7e\xaf\xe0\xdb\x45\x92" + "\x81\xa7\xef\x9e\xe7\xe6\x41\xd1" +
+       "\x9f\x7e\xeb\x2d\x0b\x49\x28\x97" + "\x6b\x25\xc7\x02\xc6\xc3\x77\x88" + "\x73\xaf\x32\x22\x1d\xaa\x9d\xd2" + "\xe8\x49\xb0\x1a\x21\x90\x4b\xc9" + "\x94\xbf\xe4\xe6\x53\xdf\xe4\xdb" + "\x06\x10\x7b\x4d\xe7\x24\x73\x4a" + "\xdf\x8b\x6a\x0a\x56\xd4\x46\x04" + "\x89\x55\xa3\x5c\x8b\xf9\xf2\xab" +
+       "\x39\xb8\xfa\x3b\x2d\x58\xdf\x46" + "\xde\xda\x8a\x2f\x04\x4e\x47\x92" + "\xc3\x1b\x7a\x14\x6a\x76\xa7\x36" + "\x79\xf9\xc0\x0d\x54\x0f\x94\xb6" + "\x25\x9f\x75\xf2\xf2\x8e\x73\x44" + "\xc6\xf4\x19\xa7\x89\x57\xd9\x9d" + "\x45\xc3\x50\x07\xf4\xb7\x59\x28" + "\xd5\x80\x21\xb2\xf2\x8b\x78\x5e" +
+       "\x7e\xb4\x71\x66\x01\x5f\x21\x4b" + "\x2a\xae\x8d\x4a\xca\x33\x76\xb6" + "\xdb\x3c\xfd\x79\x0f\x12\x15\x29" + "\xde\xe6\x64\xb0\x6f\xa0\xf8\xc1" + "\x20\x74\xd5\xc1\x8c\x36\xd5\xf4" + "\x75\xe4\x8d\xe1\xa8\x51\xda\x6a" + "\xb0\xd4\x49\xc7\x7c\xd4\xf0\xa0" + "\xa5\x6a\x52\x74\x00\x2c\xfa\xab" +
+       "\x3c\x17\x59\xfc\x73\xb7\xf2\x3f" + "\x9c\x91\xa0\xa2\xa5\x12\x86\xf6" + "\x15\x7b\x4c\x23\x28\xae\xa8\x9c" + "\xdc\xe7\xbe\xed\xaf\x58\xf6\xfd" + "\x5f\x96\x18\xab\xad\xd9\x55\x2c" + "\x44\xde\x00\x5c\x12\x1f\x90\xb9" + "\x51\x0b\x36\xee\xf1\xaa\x70\x8b" + "\xe0\x4f\x60\x05\xd5\xa9\x4b\x3e" +
+       "\x2b\x77\xd2\xf0\x82\xe4\xb8\xbe" + "\x99\x06\xe6\x2d\x65\xab\x16\xc5" + "\xf9\xf7\xd4\xc6\x34\x1e\x4f\x1e" + "\xee\xe4\xec\x5c\xbf\x88\x98\x23" + "\x38\xd2\x03\xbc\xfe\x86\xc5\x7a" + "\x6f\x3a\x35\x7d\x15\xc7\xd3\x8c" + "\x65\xfd\xf1\xb3\xde\xaa\x96\x02" + "\x5f\x53\x1e\x3a\xd4\xed\xb8\xe3" +
+       "\x63\x05\x9c\x71\xa8\xaf\x6a\x37" + "\x9f\xc7\x5f\xbc\xdc\xd2\x8a\xcd" + "\xd3\x0c\x75\xcb\x9f\xdb\x3f\x30" + "\x8e\xb0\x18\x44\x2f\x05\xff\x14" + "\x20\x65\x2d\x3e\xcf\x84\x50\xf7" + "\x09\xd5\x4e\x14\xf8\xf0\xbd\x7e" + "\x98\x5b\xf2\xd3\xf2\xf0\x3b\xf4" + "\x37\xd8\x54\xa3\xcf\x71\xad\x86" +
+
+       "\x5d\xf7\x8a\x86\xc4\xc8\xd0\xd9" + "\xea\xc7\xc8\x45\xff\x5c\x32\xd7" + "\xb0\xec\x81\xcc\x96\x19\x47\xab" + "\xed\x24\x18\x61\xf3\x55\x5d\xff" + "\xee\xa0\x77\x19\x41\x45\x31\xbe" + "\xc6\x38\x20\x72\xc5\xc4\x85\x50" + "\x95\xb4\x4b\xf9\xbf\x35\x53\x2d" + "\x82\xa0\xe2\xc8\xa6\xd8\x4a\x89" +
+       "\x37\xbb\x11\x2c\xb2\x34\x02\x54" + "\xa3\x74\x4c\xed\xdd\x66\x03\x2d" + "\x5d\xf2\xc5\xee\xda\x68\xa9\xf9" + "\x42\x31\xb6\x67\x68\x10\x60\x36" + "\xd4\xb6\xd7\x68\x2c\x6d\xcd\x07" + "\x42\x29\x84\x0c\x09\x4f\xf7\xa8" + "\xee\xb1\x68\x77\x04\x14\x75\xe2" + "\xe4\xae\x62\xfe\x89\x7e\x5f\x4b" +
+       "\x20\xef\x94\x19\xb2\x59\xe0\xd1" + "\x18\xe3\x8a\x63\x69\x3b\x65\x2a" + "\x10\x90\x69\x2f\x58\xeb\xd5\x70" + "\x4a\xf8\xf5\x09\xf7\x39\x97\x27" + "\x36\x93\x79\x8b\x3c\x66\xa4\x5d" + "\xeb\x37\x3c\x20\x4d\xf1\xfd\xfd" + "\x2d\xfb\xdb\xa1\xdc\xa9\xd8\x32" + "\x9b\x8f\xd4\x77\xf0\xcf\x40\xab" +
+       "\xed\xbb\x9f\x87\x0b\x9f\x36\xf2" + "\x69\x18\x9d\xda\x86\xae\xf0\x0f" + "\x45\x6f\x76\x56\x59\xd7\x51\x52" + "\xfc\xd0\xe8\x2b\xc0\xd8\x84\x49" + "\xf0\x08\x10\xd2\xa6\x95\xcc\x7e" + "\x49\x1c\x1a\x3a\xa0\x54\xbd\x29" + "\xf3\x50\x6c\xd2\xc5\x28\x98\xab" + "\x51\xd2\xd0\x51\x7c\x08\xc0\x32" +
+       "\xa5\x50\xaf\xfb\xab\x90\x17\xf6" + "\x50\x07\x4e\x68\x6b\xe7\x55\xdf" + "\x05\xb0\x76\xf1\xa7\x6d\x51\xec" + "\xc7\xdd\x2d\x7a\xbb\x53\x55\x57" + "\x73\xfa\x3a\x55\xa3\x7c\xc8\x37" + "\x51\xc2\x55\x4d\xfc\x3f\x5f\x31" + "\x35\x5d\x3e\xaf\x2a\x44\x46\xe8" + "\x28\xff\x95\x64\x49\x11\xb9\x61" +
+       "\xaf\xf3\xb5\x62\x66\xeb\xfe\x47" + "\x34\x37\xbb\x0a\x61\xb5\xfa\xce" + "\xb1\x5c\xf3\x19\x0e\xe6\x9d\x44" + "\xb9\x0e\x7f\x15\x14\xdb\xf8\x39" + "\xd6\xbf\x61\x3c\x5b\xcc\xae\xff" + "\x03\x67\x21\x41\x1d\xd4\xa4\xa5" + "\xc2\x1c\x4e\x22\xed\xab\x8f\x7f" + "\x53\xd9\x1a\x87\x86\x81\x5a\x0d" +
+       "\x23\x08\xf9\x56\x49\x3a\xdf\x4b" + "\x7b\x77\x1d\x74\x80\x50\x0f\xba" + "\x60\xf7\x8b\xf3\xc3\x71\x1d\x09" + "\x02\x5b\x62\x9b\x0f\xd5\x33\x96" + "\x61\xde\xc9\xb8\x43\xb7\xec\x03" + "\x20\x47\xe7\x5d\x54\x12\x75\xb4" + "\xb2\x1c\xce\x74\xc9\xef\x9d\x9f" + "\xef\x32\xbd\x00\x6a\x4f\x4a\x77" +
+       "\x52\x9a\x79\x01\xa6\x8e\x0d\x19" + "\x52\x29\x6d\xb8\x41\xec\x0c\xa2" + "\x7c\x2a\xff\x7f\xb2\xff\x62\x30" + "\x37\x9d\xf1\x79\xe5\x32\x1b\x74" + "\x47\x7d\xb5\x4e\x81\x81\x0d\xf8" + "\x6b\xf0\xae\x16\xd4\x0e\x2d\x7a" + "\x88\xb5\xec\x1c\xb0\x5f\x73\x09" + "\x5b\x1f\x06\xc6\xaa\xca\x41\x16" +
+       "\x5b\x1e\x13\xb0\x02\xc0\x7b\x32" + "\xd9\x14\x25\xcb\xd5\xe6\x39\x17" + "\x43\x15\xa8\x55\xfe\xda\xcb\xc8" + "\x43\x72\x13\xe1\x6c\xa3\xb1\x5b" + "\x27\x53\x32\x17\xc5\xa3\x5d\x20" + "\x7e\x05\x5a\x51\x36\x1a\x5c\xc3" + "\x9b\x5f\x92\x42\xc9\x64\x0f\xf0" + "\x7a\x9f\xd5\xb7\x3c\x63\x14\xbd" +
+       "\x3a\x8c\x6e\x65\x71\xd1\x2a\xae" + "\x05\x07\xcd\x1a\x63\xa4\xe2\xc0" + "\x5c\x05\xb6\xa0\x8a\x6a\x6f\x00" + "\x6e\xa2\x65\x2b\xd7\x13\x45\xaf" + "\xbc\xd5\x16\xd6\x14\x9e\x54\x3f" + "\x1f\x3b\x25\x71\x55\x39\xee\x64" + "\x3a\x24\xce\xb8\xc1\x0b\xb1\xe8" + "\x77\x4e\x3a\x91\xe5\xac\xbe\xbc" +
+       "\xbd\x7d\xf3\x41\x43\x00\xc1\x47" + "\xf6\xec\x68\x61\xe3\xca\xec\x96" + "\xa3\x6a\xa4\x1c\x9d\xe5\xbd\x65" + "\xfa\x8f\x69\xb8\x7a\x02\xa7\x38" + "\x37\x44\xc3\x6d\xc8\x9d\xb8\xa2" + "\x3f\x15\xa4\x43\x8d\x11\x0a\x5a" + "\xd8\x2f\xe2\x1c\x86\x0a\x33\x9e" + "\xbc\xd3\xbb\xb3\xf6\x2a\x38\x28" +
+       "\xa7\xd6\x79\xf7\x56\x22\xd3\x68" + "\x4e\x28\xe7\x19\x4d\x3b\x42\x20" + "\x53\xb1\xf3\x38\x1b\xaa\x19\xde" + "\x03\xf7\x44\x84\xc2\xb6\xd0\x73" + "\xa3\xe6\x64\x9c\x48\x61\x61\x66" + "\x24\x62\x25\x37\x37\x7c\x58\x99" + "\x63\x15\x33\x61\xfe\x77\x52\x6f" + "\x2e\x50\x56\xa6\x4a\xad\x74\x71" +
+       "\x71\x02\x1e\xd8\xc0\x27\x2e\x0b" + "\x7c\x31\x7a\x11\x96\x75\x7a\xa6" + "\x99\x3d\x72\xa6\x28\x89\xf0\x17" + "\xa3\x10\x53\x48\x81\x56\xa7\x71" + "\xa9\x6c\xb6\xaf\x62\x54\x46\x90" + "\x9d\x22\xbe\xfb\xcc\x97\x5e\x18" + "\xc2\x8f\xad\xdd\x6a\x60\x1a\x6a" + "\xcf\x97\xc7\xb3\x16\xf3\x31\x24" +
+       "\x8d\x91\x33\x01\x92\xfc\x1f\xec" + "\x97\xef\xc9\xb2\x5e\xbf\xd9\x15" + "\x9a\xbb\x6c\xfc\x42\xb5\x85\x78" + "\x5d\xcf\x20\x57\x53\x64\xbe\x8a" + "\xab\x68\xec\xd4\xce\x5d\x71\x4e" + "\xa3\x24\x9c\x27\x14\x76\xa6\x57" + "\xcf\x61\xbb\x31\x2a\xd5\x8e\x78" + "\x03\xa0\x37\xf4\x44\x24\xa8\xab" +
+       "\x32\x94\x52\x93\x11\x40\x03\x47" + "\x62\x34\x74\x30\xdd\x6b\x10\x1f" + "\xca\xd8\x66\xcd\x64\x99\xfb\xab" + "\xd5\xad\xbd\xe9\x5a\x9d\x4d\x93" + "\x22\x3d\x8e\x90\x15\xd8\x76\x59" + "\xbd\x57\xe0\x28\x2f\x36\x4a\x34" + "\xb3\xdf\x43\x54\xdc\xda\x2c\xf9" + "\x3b\x60\x89\xf0\xad\x97\x12\x00" +
+       "\x27\x14\x15\x20\x4f\x82\x99\x7f" + "\x06\x02\x43\x92\xb6\x28\x68\x20" + "\x57\x23\x11\xe1\xd7\x97\x90\xaa" + "\xec\x14\xe4\x09\xf2\xa2\xf9\xac" + "\x56\x53\x91\x27\xda\xc9\xda\xdb" + "\xe3\xfe\x1e\x00\xb7\x34\x07\x7e" + "\xe2\x88\xb2\xd2\xbb\xb5\xfa\x54" + "\x9c\xd0\x2d\xf6\xc4\x0f\x63\x4c" +
+       "\x6b\x06\x44\x50\x60\xce\x2f\x4a" + "\xf4\x47\x3a\xfa\x9c\x01\x4a\x90" + "\x60\x0a\x5c\x0c\x9c\xea\x81\xba" + "\xbd\x98\xc0\x96\x0d\xea\xe4\xd7" + "\x02\x0a\xd5\x9c\x41\x00\xe7\xef" + "\x8c\x04\x7f\x2d\xd4\x39\xc8\xc0" + "\x1f\x56\x9b\xe0\x64\xf2\xda\xe2" + "\x8b\xb1\x34\x50\x18\x13\xbc\x0c" +
+       "\xe1\xa5\x70\xbd\x66\x3e\x88\x6d" + "\x13\xe7\x5d\xd0\xc1\x84\xd8\x9b" + "\x7d\x48\xd8\xd4\x45\xd4\xd9\x48" + "\x05\xe4\xea\x0e\x8b\xcd\x40\x84" + "\x3e\xf8\x26\x3d\x29\x0f\xcd\xa3" + "\xe4\xc5\xa3\x22\x30\x45\xd9\x3f" + "\xa7\x2c\xfa\x3f\x66\x78\xa0\x63" + "\x97\xa0\xd4\x00\x29\xdd\xea\xbf" +
+       "\x7a\x3f\x32\x88\xe3\xf2\xe5\x11" + "\xcd\x84\x75\x92\xc2\x74\x7a\xe0" + "\x2d\x3d\x61\x95\x34\x4b\x77\x1e" + "\x88\x74\x78\x2c\xc5\x52\x9b\x9c" + "\x08\x1f\x42\xbe\x3e\x3c\xdd\x3c" + "\x5f\x3d\x3e\x22\x9e\x81\xf7\x5f" + "\xb9\x09\xda\xc1\xb2\x39\x87\xba" + "\x1b\x49\x8b\x4e\x16\x63\x72\x6b" +
+       "\xba\x32\x84\xd6\x59\xa5\xae\x13" + "\xdb\x15\x39\xd3\xfb\x43\x00\x94" + "\x08\xda\xe8\xe2\x94\x7c\x6c\x47" + "\xbb\x65\x30\x44\xc4\x30\x16\x6b" + "\x75\x6c\xf0\x19\x6d\x54\xd8\xd6" + "\xbd\x5a\xb3\x2e\xc2\x98\x1e\x7e" + "\x8e\x7d\x15\xf0\x10\x93\x1c\x75" + "\x75\x60\xfa\xf6\x27\x43\xf8\xde" +
+       "\xef\x3b\x94\xa0\x3c\xd1\xaf\xb5" + "\xcc\xb1\xab\x57\x29\x77\x51\xd6" + "\xbc\xb5\x61\x9b\xdc\x52\x5a\x9d" + "\xcd\x31\x6e\x80\xa6\xfa\xce\x85" + "\xea\x1d\x0a\x72\x7a\x25\x84\xab" + "\x35\x0d\xd7\xce\x1b\x26\x60\x6a" + "\x61\xda\xd6\xb9\x4d\xf9\x23\xc0" + "\x0e\xae\xa0\x54\xec\x7e\x7f\x94" +
+       "\x0e\x4e\x7a\x3a\x3c\x99\x5b\x76" + "\x14\xd3\x79\x9d\xef\x4a\x8f\xfb" + "\x24\xeb\x19\x2a\x0e\xc5\xa2\x5e" + "\x8c\xbc\x91\xb8\xe5\x16\x50\x92" + "\xe7\xec\xd1\x3a\xdc\xaf\x70\x8f" + "\xe2\xab\x8f\xf0\x4c\xa8\xbb\x0a" + "\x2b\x13\xf6\x15\xc8\x22\x99\x0a" + "\x77\x6d\x07\x5d\x73\x13\x02\x6c" +
+       "\x87\xb7\x83\x9f\x56\x87\xb7\xc3" + "\xd7\xdd\x94\x36\x26\x49\xd2\xd6" + "\x2e\xa0\x70\x5d\x94\x48\xd2\x58" + "\x6a\x8c\x27\x8c\x0e\x67\x16\xac" + "\xe6\xb6\x70\xe3\x58\x4d\xa9\x71" + "\x05\xdb\x53\x02\x84\x63\xd7\xe4" + "\xfe\x2c\xb3\x14\x88\xc9\xb1\x99" + "\x95\xcc\x78\xcc\x70\xd8\x6b\x4e" +
+       "\x61\x39\x45\xa4\x15\x26\xaf\x00" + "\x2c\x11\x3d\x99\x4b\x49\x05\x17" + "\x52\xd6\xcd\xa1\x2a\xe1\x32\x00" + "\xb3\x9c\x6d\x04\x12\xa6\xbf\x0e" + "\x8c\x72\x63\x1b\xf3\xa9\x03\x9f" + "\x05\x2b\x02\xde\xa2\x18\x36\x8f" + "\xc9\xc5\x77\x3e\x90\x4d\xb2\xd5" + "\x7c\xb7\xac\x72\xa3\x38\x78\x83" +
+       "\x14\x36\xb6\xc8\x79\xca\xf7\xf5" + "\x3c\x90\xf4\x8a\x15\xb2\xbf\xf3" + "\xd3\x7b\xd4\x96\x54\x9f\xdb\x2b" + "\xba\x63\x8a\x0e\x30\x15\xe7\xd6" + "\xc4\xbe\x93\x7a\x49\x0a\xe9\x67" + "\xee\x63\x1e\x8c\x8b\x47\x13\x86" + "\x61\xe5\xdd\xf2\xc8\xd9\x6b\xe3" + "\x89\x86\x76\x8a\x51\x86\x14\x68" +
+       "\x47\xb0\xce\x8f\xd9\xcb\x65\xfe" + "\xa1\x11\x8b\x3f\xf5\x2e\x87\xde" + "\x2f\x80\xec\x8f\x3d\x0d\xba\x9a" + "\x1d\x38\x9f\x9a\x32\x1d\x9f\x13" + "\x8d\x95\x87\xc5\xd9\xae\x21\x07" + "\xda\xa7\xf6\xb9\x5c\x01\x6a\x06" + "\x06\x9d\x5d\xed\xe3\xc4\x9e\x05" + "\x1f\xca\xba\x6c\x71\x85\x42\x14" +
+       "\x1c\x53\xaa\x94\x94\x7a\x61\xef" + "\x87\xad\xf4\xd6\x2f\x5e\xc3\x9a" + "\xfb\x68\x24\x12\x47\xa0\xd2\xbc" + "\xa6\x5c\x7c\xef\x3f\x42\x7a\xbd" + "\x40\x80\x4c\x06\x52\xcb\x58\xab" + "\x16\x47\x64\x4a\xd5\x4e\xef\x93" + "\x8d\xd4\x2c\xc3\x97\x70\xd1\xf7" + "\x42\xcf\x7f\xd1\x73\xa1\x49\xb2" +
+       "\xf5\xcd\x98\xe2\xff\x0f\xfe\x66" + "\xb6\x51\x2e\x7b\xa4\xbe\x61\x3f" + "\xa4\xaf\xd3\xba\x17\x21\x37\x7d" + "\x2f\x6e\x65\xef\x9c\xa0\x21\x65" + "\xe7\x8f\xa5\xe8\x66\xc9\xb8\xb3" + "\xc7\xeb\x47\x5a\x11\x3a\x20\x25" + "\x73\xe5\x4b\x5c\x8d\x58\x81\xfe" + "\x3c\xa0\x49\x1f\xf3\xe2\x32\x61" +
+       "\xc4\xec\xa7\xb7\x08\xc1\xe5\xbb" + "\x4c\x2e\xd2\xbf\x8e\xa7\xa5\x62" + "\xd2\x8b\x18\xdf\x33\x40\x97\xb7" + "\xae\xd1\xf7\x4d\xea\xde\x11\xcf" + "\xea\xe3\xac\x53\x4a\x77\xcc\x99" + "\xf6\xc1\x5c\x10\x71\x3a\x37\xe0" + "\x20\x7a\x3d\x13\x7f\x98\x51\xd7" + "\x71\x58\x21\xae\x04\xee\x86\xab" +
+       "\x99\x2c\x8c\x0f\x13\xb0\x1a\xec" + "\xc2\x25\x77\xf1\x8f\x96\xe8\x60" + "\x0b\x98\x0a\x94\x93\xa5\xa4\xe1" + "\xb1\xcc\xe9\x20\xb0\x15\xed\x15" + "\xec\x0b\xa0\x64\xcc\x54\xd7\x77" + "\x82\x73\x68\x41\x33\x9c\xd0\x90" + "\x51\xb6\x1f\xc3\x2d\xe0\x4f\x29" + "\x53\xae\x94\x1c\x1a\xcd\x72\x83" +
+       "\xe6\x10\xcd\x80\xa2\xf9\x94\x20" + "\xa7\x0d\x8a\x7b\xaa\x32\x52\x04" + "\x4e\x24\x03\x9c\xb6\x81\x9a\x96" + "\x55\xd9\x98\x7e\xca\xb4\x93\x12" + "\xb0\x3a\x8f\xd6\x1d\x42\x31\x16" + "\x82\x8c\x73\xc3\x22\x64\x10\xa0" + "\xf9\x4f\x2c\xf8\x45\x38\xf4\xc5" + "\x8f\xf5\xa0\x1a\xbe\xac\x79\xb4" +
+       "\x3b\x70\xc2\x1a\x7a\x10\x37\x85" + "\xb5\x57\xc8\x6b\xd8\x58\x92\xb4" + "\xd1\xcc\xda\xbc\xde\x14\xdf\x57" + "\x29\x85\xae\xc4\xd7\x68\xab\x24" + "\xd0\x59\x4e\x73\xd4\xb5\xd8\x7e" + "\x80\xcc\x95\xc4\xc8\x40\x87\x5f" + "\xb3\xb9\x1d\x29\x5a\xdd\xae\x84" + "\xbe\x95\xb9\x4f\xf8\x60\xb3\x80" +
+
+       "\xfa\x76\x1a\xa6\x8d\xc6\xd5\x55" + "\xdc\x54\x15\xca\x1d\x44\x8b\x59" + "\x9c\x27\x3b\x77\xb9\x23\x99\xd3" + "\xfc\x9e\xbf\x36\x3c\x1d\x33\x33" + "\x99\xe3\x8d\x29\x8e\x84\x4c\x2d" + "\x56\x7f\xa2\xa1\x77\x8e\xdb\xcf" + "\x70\xab\xb8\x57\xea\x55\xc8\x94" + "\xba\x79\x78\x6f\xae\x9d\xdb\xdc" +
+       "\x38\x6a\x63\x7f\x36\x07\x4f\x4c" + "\xcb\xd5\x76\x0e\xb7\x3f\x94\x9f" + "\x8b\x8b\xb6\xa8\xba\x10\x35\xb0" + "\x1f\x7a\xd0\x9e\x0a\x78\x46\xc2" + "\xc2\x9f\x54\x6d\x15\x14\x05\x3c" + "\xca\x81\x77\x60\x31\x3f\x95\xc2" + "\x13\x54\xd9\xd8\x69\x2c\x5e\x95" + "\xe3\x82\xd2\x7b\xdc\xfa\x00\xb3" +
+       "\xb4\x01\x79\xc2\x63\x11\x4b\xa1" + "\xf3\x8b\x9b\x89\xe0\x36\x92\xfd" + "\x0a\xda\xc6\xcb\xec\x91\xb0\x42" + "\x97\xd2\xd1\x5a\x6f\xac\x1d\xbb" + "\x6e\xf7\x1c\xa9\x53\x1d\xe6\x80" + "\xe7\x1e\x1f\xd3\x12\xa4\x10\x41" + "\x77\xcf\xef\x13\xba\xc3\x87\x2d" + "\x76\x0d\x45\xdf\xb4\x4b\x37\x1f" +
+       "\x9a\x51\x47\x41\x02\x86\x28\x20" + "\xf0\x72\xb3\x26\xac\x1e\x98\xd0" + "\xc8\xeb\x85\xa7\xca\xa7\xd4\xa9" + "\xe9\x58\xdf\xdb\x0d\xc5\x53\xd9" + "\x8f\x0f\x59\xfd\xcc\x61\x63\x9d" + "\x17\xc9\xe6\x44\x6b\x62\xe9\x72" + "\xcf\x64\xeb\x22\x10\x61\xd9\x7f" + "\xf3\x88\xb2\x9e\x7e\xbb\x3e\x86" +
+       "\x03\x44\x7e\x09\x0a\x0a\xe1\x15" + "\x65\x46\x85\x19\x86\x0a\x3d\xcb" + "\x26\x48\x7d\xd6\x11\xe2\xd8\x88" + "\x39\x28\x9d\x0b\x6e\xf6\x9a\xb3" + "\xa8\x5c\x47\xbd\x88\x45\xf9\xa5" + "\x0b\xb8\x77\xc0\x66\x79\x6b\xe0" + "\x6c\xc2\x27\xda\x85\x14\xdb\xfe" + "\xe0\xd5\x0f\xfe\x3a\xd3\x90\xd2" +
+       "\x3d\x58\x06\x13\xf3\x02\x62\x68" + "\x2e\x62\x7c\x43\xa0\x0d\xb1\x05" + "\xc8\x7b\x6a\x07\x0f\xaa\x9a\xbf" + "\x43\x4e\x8f\x8f\xfb\x4e\xe9\x25" + "\x6d\xc2\x3d\xfa\xb7\xc9\x35\x8a" + "\xc5\x03\xff\x96\x93\xfb\xe5\xe0" + "\xce\x94\xc3\xeb\x43\x38\x7e\xa7" + "\x60\xde\x61\x83\x95\x65\xde\xce" +
+       "\x40\xb5\x22\x0c\x09\x75\x90\xbf" + "\xd4\x67\xc2\xb7\xaa\x42\xde\x2c" + "\x93\xd6\xb0\x5a\xed\xf9\x18\xba" + "\xd9\x60\x46\x6e\xa6\x2a\xa6\x3b" + "\x6a\xa9\x9e\xab\x7b\xf9\x4b\xb2" + "\x32\x0e\xb6\xe3\x42\x96\x03\x5d" + "\xd5\x9b\x4d\x7c\x06\x45\x6a\x4e" + "\xa4\xa6\xd4\x7e\x9e\x5b\x6c\x66" +
+       "\xb0\x31\x8a\x67\xf5\x7c\x7b\x87" + "\x20\xb6\x98\x39\xae\x01\x03\xd5" + "\x96\xb3\x0f\xc0\xc5\x57\x42\x73" + "\xa6\x72\xe6\x04\xa0\x18\xfb\xf9" + "\x51\x88\x75\xe8\xeb\xd8\x8b\xff" + "\x44\xba\x99\x5d\xc6\xe4\x64\x1e" + "\xb7\x93\xfd\x7d\xdf\xae\x8e\x4b" + "\x8c\x6b\xe7\x04\x98\x2a\x2f\xba" +
+       "\xbd\xdd\x56\x9b\xf0\xa2\x02\xae" + "\xf3\x1c\x2f\x8a\xac\xb5\x39\x13" + "\x0d\xff\x9d\x83\xc7\x69\xb5\xf2" + "\x3d\xa4\xe9\xfe\x64\xe8\xb9\xb0" + "\x4e\x06\xbb\x77\x41\xca\xf8\x4f" + "\x63\x9f\x24\xfd\x12\x28\x5a\x14" + "\x9a\x68\x6f\xf8\xac\xbe\xb7\x3a" + "\x5e\x5f\xd3\x01\x27\xec\xaf\x9b" +
+       "\xb7\xc7\x57\xae\xdd\x3f\xa2\xbb" + "\x22\x25\x93\x1b\xf2\x42\x53\x34" + "\xa3\x4a\x6d\x55\xfe\x80\x9c\xfd" + "\x61\xbb\x25\x65\xba\x07\x39\xa0" + "\x33\x89\x21\xff\xe1\x10\xb0\x38" + "\x7b\x11\x52\xaa\x54\xb6\x66\xc0" + "\xea\xe6\xf2\x94\x20\x19\x14\x8e" + "\xb2\xf2\x32\x0d\xca\x7d\xa2\x66" +
+       "\x92\xbe\xab\xfb\x21\xb1\xe6\xb2" + "\x76\x00\x33\xe1\xfb\x50\x18\x28" + "\x15\x00\x89\x97\xec\x81\x35\x09" + "\xf5\x77\xff\x75\xed\xdd\xb1\x69" + "\x05\x51\x10\xab\x8f\xb1\xf0\x7c" + "\xef\xcf\x9c\xa8\x31\xed\x3c\x95" + "\x09\x40\x91\xeb\x5f\xf8\x51\x31" + "\xad\x48\xed\x88\x87\x1b\x9f\x3c" +
+       "\x1e\xb2\x0f\xe9\xe0\x07\x8f\xa1" + "\xa1\xfc\xa7\xbb\x80\x2b\xfd\x00" + "\xb5\x67\xcd\x95\x27\x7f\x38\x20" + "\xf7\x07\x97\xd3\xe7\xa4\x89\x5b" + "\xce\x07\x44\x89\x3f\xad\x83\x8f" + "\x32\x61\x22\x6c\x94\x5b\x02\xa0" + "\x3b\xc1\x06\xf9\xc7\x63\x95\xc7" + "\x25\xb0\x7b\x4e\x31\x8f\x54\x5f" +
+       "\x1f\x0c\xde\x4f\x49\x89\x75\xff" + "\x20\xec\xb6\xe5\xbe\x1a\x8a\xbf" + "\x6c\xdb\xe1\x87\xfb\x78\x22\x70" + "\x8f\x65\xed\x35\x7a\xad\x47\xc4" + "\xf2\xcc\xd0\x03\x38\xaa\xd4\x48" + "\x03\x7c\x9a\x81\x38\xb3\xac\x80" + "\xcc\xce\x17\x6e\x9e\xc8\xc7\x9b" + "\x82\x1d\xbe\x03\x8b\x6b\x73\x46" +
+       "\xaa\x5e\x3b\xd4\x42\xf7\x26\x21" + "\x85\x9b\xa5\xdf\x66\x07\x4a\x05" + "\x45\xfd\x6b\x12\x36\x5e\x0d\x9d" + "\x8f\x8a\x4f\x38\xd7\xfb\xf8\xa1" + "\xcc\xfc\x63\xd5\xf5\x80\x76\x31" + "\x28\xa9\x80\xf2\x55\x50\xca\x48" + "\xcf\x78\xb5\x27\xb2\x81\x0b\xe0" + "\x14\xa5\x94\x29\x18\xd9\xaa\x10" +
+       "\xc0\xcd\x8b\x35\x1f\x30\x3f\xe6" + "\xf8\x47\x9d\x0a\x99\x9e\x68\x07" + "\x3a\xd4\x43\x4f\x2f\x9e\x68\x1f" + "\x04\x09\x92\x90\x16\x2a\x54\x4d" + "\x07\xa7\xa0\x9c\xd5\x93\xa2\xae" + "\x65\x80\xc6\x8a\x45\xfe\x61\xd0" + "\x8c\x00\x90\x00\x1b\xbf\x33\x10" + "\xb6\x6d\x8a\xc0\x58\x95\x74\x29" +
+       "\x94\x87\x5d\xc3\xa7\xd3\xe6\x0e" + "\xe5\xba\x56\x03\x58\x65\x2e\x04" + "\xfd\x22\x33\x64\x8d\x69\x59\x9f" + "\x67\x19\xa6\x50\x15\xae\x79\x93" + "\x1e\x98\xc9\xfc\x62\xae\xb9\x64" + "\xc6\x34\x29\x6d\x31\xd6\xd3\xae" + "\xeb\x65\x4e\x5e\x02\xb3\x54\x24" + "\x28\x04\x95\xf9\x47\xf6\x09\xab" +
+       "\xcd\x71\x6e\xa6\x50\x9e\xc9\x34" + "\xe9\x13\xb7\x75\x15\xf9\x94\x17" + "\xb9\x57\x45\xe0\x90\xde\x40\x1e" + "\x18\x56\x7d\x26\x8b\x8c\x17\x3c" + "\xad\x32\x79\xc9\x7d\x10\x62\x90" + "\xd3\x1b\x31\x81\x52\x1d\x20\xa2" + "\x9e\xb7\x5b\xbc\xeb\x5e\xd6\x35" + "\xd0\xf4\x5c\xb7\xa6\x0f\x61\xef" +
+       "\x30\xca\xe0\x99\x61\x2a\x70\xc1" + "\xe8\x0a\x56\x99\x6b\x6a\xd4\xbf" + "\x0c\xc3\x1c\x61\xe6\xd5\x6b\xb7" + "\x6a\x98\x5b\x75\x8b\xb7\x0e\x1e" + "\xbd\x4b\x91\x34\x77\x9f\xf3\x7e" + "\xea\x56\x95\xa1\xff\x4c\xc0\xe2" + "\x57\x31\xd5\x69\xce\x8e\x8b\xf7" + "\x65\x04\xe1\xa6\x78\x26\xe5\xd4" +
+       "\x7b\xa3\x14\xf6\xec\xe5\x40\x3e" + "\xc2\x74\xfa\x06\x04\x9d\xf2\x74" + "\x86\x0d\x28\x61\xd8\x95\xfc\x6a" + "\x9f\x08\xf1\xae\x02\xc7\xea\xba" + "\xab\xb4\x66\x34\x2b\x7d\x2a\xe4" + "\x95\xd5\x5d\xc8\xd4\x19\xf3\x20" + "\x54\xc2\xf5\xd4\x1e\x49\x48\xba" + "\x8a\x43\x31\x33\xdb\xdd\xc1\xed" +
+       "\x09\x5f\xb8\x31\xd3\xd3\xb3\xc1" + "\x4a\xe6\x8a\xa8\x4a\x35\x45\x0f" + "\xfd\x50\xec\x2f\xd3\x26\xb6\xa8" + "\x4f\x83\x28\xe8\xd4\xfb\xdc\x1b" + "\x39\x25\x52\xcd\x66\x28\x5a\xe4" + "\xb3\x7a\x0f\x81\x32\x47\x9d\xfa" + "\x93\xf2\x05\xc9\xb4\xd6\xc1\xd8" + "\x97\xb5\x61\x34\x47\x80\xac\x10" +
+       "\x05\x6a\x43\xc2\x36\x92\xef\x11" + "\x3d\x30\x4b\xe5\xb6\x3e\x63\x97" + "\xf1\x0c\x9e\xfd\x94\x49\x17\xd2" + "\x8d\xeb\xd5\x98\x44\xc1\x11\x95" + "\x6c\x2e\x8c\xe7\xc1\xfd\x77\xe5" + "\x77\x65\x4f\xbe\x01\x74\xf3\x8d" + "\xa7\x56\x81\xd3\xa5\x82\x12\x3b" + "\x53\xbe\x16\x07\xeb\x96\x7f\xe0" +
+       "\x91\x25\x1f\x74\x37\x38\xcd\x29" + "\xe2\x6e\x39\x64\x9d\xc4\xdb\x4b" + "\x8f\x26\x9d\x26\x02\x71\x59\xe6" + "\x05\x63\x9a\xce\xc6\x39\x6b\x89" + "\x45\x02\xb3\x10\x71\x24\x5e\xc0" + "\x72\x00\x13\xa9\xa8\x19\x52\x84" + "\xc2\x9f\x2a\x0e\xb1\x8c\x15\x88" + "\xc6\x91\xf1\x39\x41\xf6\xc6\xcb" +
+       "\x56\x82\xb6\xd3\x78\x46\xa3\x7e" + "\x31\x08\xd9\x94\xf5\x4a\xfd\x01" + "\x92\x95\x2f\x6f\x2f\x4f\x91\x7c" + "\x08\x55\xb3\xf5\x23\xd6\x09\xba" + "\x1a\x7c\x95\xc1\x74\xdd\xbb\x27" + "\x7c\xd5\x16\xd7\x17\x55\x2a\xab" + "\x52\x85\x3f\x8f\x2d\x29\xa4\xd3" + "\x50\x7c\x04\xc6\xb2\x9c\x97\x46" +
+       "\x2c\xcd\x91\x6d\x36\x15\xc8\xe2" + "\xe4\xf0\xa3\xda\xea\xbe\xa2\x40" + "\x83\xe0\x41\x24\x59\x7a\x16\xfb" + "\x47\x03\x24\xe9\xe9\x75\x46\x00" + "\x6e\x44\x0e\x84\xff\xaa\x48\x78" + "\x72\x8f\x30\xea\x8f\x25\x9f\x9f" + "\xd9\xfa\x9b\x63\x99\x28\xf1\x50" + "\xf6\x0a\x5c\x20\x63\xae\x39\x09" +
+       "\x38\x79\x6d\x48\x3e\xde\xcd\xbc" + "\x45\x8f\xea\x81\xea\xc0\xb4\xaf" + "\xda\x52\xb5\xb2\x5c\x2a\xf1\x3e" + "\xe2\xea\x78\x38\x78\xa3\xe6\x6f" + "\x55\x8f\x54\x8d\x98\x53\xb8\x3f" + "\xaf\x33\x3c\x79\xc5\xa3\xaa\x47" + "\x29\xab\x5a\x11\x21\x2d\x4e\x49" + "\xde\xac\xbe\x50\xba\xce\xad\xd2" +
+       "\xe5\xaf\x95\xf1\x36\x12\x5d\x46" + "\x13\x44\xcd\x2d\x12\x3c\xdb\x03" + "\x5d\xb1\xf7\xc8\x35\x3b\xcf\xf1" + "\x7f\xc1\x4f\xb5\xe2\x30\x8d\xbc" + "\xae\x72\xe6\x40\xb9\xa3\x3a\xe7" + "\x75\x8f\xf3\x02\x8d\x84\x32\xa0" + "\x05\x0a\xb1\x3b\x21\xdb\xa0\x1c" + "\x2a\x90\x8d\x68\x2f\xa7\xe9\xc5" +
+       "\xbc\xdd\xe4\xe7\x5d\xdb\x67\xf5" + "\x63\x3b\x61\xe7\x28\x9b\x83\xbe" + "\x0d\x04\xa6\x7d\xc6\x77\xcc\x81" + "\x26\x10\x4d\x23\xfb\x88\x2b\x69" + "\x82\x35\x59\xd0\xfa\x35\x9d\x6e" + "\x98\x1b\x05\x56\xfe\x3c\x41\xc7" + "\x52\x23\x6b\xf4\x5e\xed\xce\x3c" + "\x85\x52\xa4\x3a\x21\x16\x6f\xb7" +
+       "\xe2\x27\xc6\x6f\x14\x75\xb1\xbb" + "\x51\x3a\x57\x91\xc5\x9b\x56\xa0" + "\xd5\x43\x82\x35\x9e\x6d\x01\xa7" + "\x92\x66\x1d\xac\x56\x0c\xac\x0d" + "\x5f\x0d\x59\xda\xb5\x33\x38\x99" + "\x91\x74\x81\xde\x03\x78\x06\xa8" + "\xd0\x75\xbf\x4d\x12\xf2\xb4\x65" + "\xfb\x0c\xf8\xcc\x32\x02\x96\xcc" +
+       "\x5e\x3c\xcc\xbe\xf7\xf5\xdd\x87" + "\xb9\xf8\x35\x6d\xa7\xaf\xfe\x21" + "\xcf\x77\x1d\x75\x51\x9c\x27\x41" + "\x50\x2b\xc9\x6f\xeb\x26\xc7\x47" + "\xf4\x54\xfb\x4c\xc8\xb7\x18\x4b" + "\xee\xcf\x18\xa6\xab\x8d\xf8\xb0" + "\xc8\xe0\x95\x5c\x00\x9a\x46\x3f" + "\xdf\x39\x18\xd1\xf3\x28\x12\xcf" +
+       "\x98\x7d\x05\xbd\x54\xcb\x32\x1f" + "\x87\x57\xc4\xe1\x02\x1a\x05\x79" + "\xcb\x32\x76\x7d\x20\x94\x85\xac" + "\x21\x94\x03\xfe\x5b\x26\x8b\xce" + "\x48\x68\x7e\x59\x3e\x0d\x9e\x1f" + "\x18\x09\x64\xe2\x14\xf4\x01\xd0" + "\xc9\x0d\x35\x8a\xcd\x48\x37\xe8" + "\x44\x04\x4f\x7b\x1e\xc8\xdd\x0e" +
+       "\xd0\xa9\xc6\x45\x8e\x94\x08\x7a" + "\xb7\xd8\x20\x0c\xe5\x3c\x29\xb7" + "\x71\x03\x67\x74\x29\x57\x5a\x71" + "\x40\x45\x72\xae\x98\xe7\xa9\x6a" + "\x42\xb6\x71\xf9\xec\xeb\xd5\x79" + "\xf3\x98\xd4\xaa\xbb\xb2\xd7\x6f" + "\x6b\xd4\x69\x39\xf9\xb6\x46\xff" + "\x55\xe1\xd2\x29\xe3\x9a\x38\xd7" +
+       "\xcc\x8a\x24\x22\x12\x3a\x08\xb2" + "\x66\xe3\x64\x32\xef\xc0\x6e\x1f" + "\x28\xee\xfd\x5a\x04\xb7\x59\x56" + "\xb5\x0b\x43\xe6\x40\x3a\x82\x7a" + "\x79\x0a\x90\xe1\x04\x2a\x59\x24" + "\x76\x65\xee\xc9\x4a\x9d\xe0\xcd" + "\x4a\xa5\x5e\x4b\x3f\x46\xb6\x52" + "\xa7\x65\xca\xd3\xd3\x9e\xfe\x1e" +
+
+       "\xdd\x06\x54\x30\xbe\x6d\x7a\xe2" + "\x57\x19\x5d\xdd\x7f\xdc\xb7\x8e" + "\x8f\x4d\x7d\x38\x76\x68\x4a\xf5" + "\xe4\x2d\x76\xc7\x09\x94\x47\x9c" + "\x78\x07\xb3\x99\x5d\x5b\x4d\xbe" + "\x82\x36\x79\x6e\x56\x0c\x38\x25" + "\xe3\x40\xc7\xda\xf3\x37\x2d\x60" + "\xae\xe4\x66\x15\xbe\xea\x0d\x14" +
+       "\x1e\x86\x9a\xc4\x26\x61\xee\xea" + "\x06\x0d\x4f\xe1\x65\x3b\x4f\x02" + "\x17\xfc\x9b\xc6\xe8\xf1\xa3\x51" + "\x81\x63\x68\xa7\xe9\xa8\xc3\xc3" + "\xc8\xd4\x03\xb1\x2c\x75\x00\x34" + "\x6b\xb3\x18\x92\x13\x46\xbc\x02" + "\x4a\x50\x51\x76\xeb\x75\x7f\xc6" + "\xfa\xeb\x2a\xd0\x56\x8b\x84\xd6" +
+       "\x9b\x26\x82\x17\xdb\x81\x83\x95" + "\x50\xe5\x97\x25\x79\xbf\x34\xae" + "\x53\x51\x38\x5f\x64\x60\x5c\xbb" + "\x48\x80\x08\xe3\xaf\x96\x0e\x6f" + "\x56\x44\x88\x77\x15\x02\x6a\xbf" + "\xa7\x0e\x31\x69\x8c\x68\xb5\xb3" + "\xde\xd2\xfa\x04\x95\x42\xc9\x17" + "\x4d\x6d\x89\x17\xe5\xf0\x20\xe0" +
+       "\xa9\xa1\xe5\xbb\x8d\x42\xa4\xcc" + "\x67\xbd\x26\x31\x5f\xfd\x87\x81" + "\x26\x58\x10\x48\x3a\x97\x36\x00" + "\xa0\x61\xbd\xb8\x63\x66\x9b\xa3" + "\x08\xa8\x65\x2d\xef\xde\x42\x6d" + "\x19\x6b\x63\x94\x4f\x04\x69\x49" + "\x4c\x56\x5d\xdd\x47\xee\x11\xf6" + "\x77\x30\x87\xd2\x49\x3a\x2f\x7b" +
+       "\x14\xb2\x82\x0f\xdd\xd8\xb0\x03" + "\xc6\xcb\x03\xf1\xf9\x34\x0c\x46" + "\x19\x9e\xd7\x18\x03\x5c\x2e\xf3" + "\xf8\x17\x41\xa8\xba\x88\x88\x8b" + "\x77\x26\x72\xc0\xdc\x37\x3c\x8f" + "\x27\x0f\x1c\x1c\xe9\x1b\xd2\x10" + "\xc6\xa0\xf7\xe0\x68\x84\x7c\xd4" + "\xe0\xc0\xec\xad\x13\x22\xf0\x9b" +
+       "\x6e\x7b\xfe\xb7\x60\x41\x55\x97" + "\xb2\x3f\x0a\x40\x9a\x18\x16\x7d" + "\x1e\xca\x28\xe3\xea\x9b\x3e\xd7" + "\xcc\xd8\x93\xe7\x97\x4b\xd0\x0d" + "\xcc\xb8\x6d\x50\x9b\x3c\xc8\xa9" + "\x4c\x81\x38\xcf\xae\x7a\xd4\x5c" + "\xe6\x45\x4b\xb6\x0d\x43\xfc\x26" + "\x84\xea\x18\xd8\x99\x54\x9b\x07" +
+       "\x41\x29\xac\xe0\x1a\xd2\xb5\x03" + "\x37\x19\xd3\xc2\x54\x02\x9b\x27" + "\xd0\x92\xc9\xca\x52\xc0\x07\x33" + "\xf3\xb1\xa8\xef\x92\xcb\xa7\x6a" + "\xa5\xc7\x37\x0d\x80\x25\x18\x5a" + "\x22\x54\x2d\x34\x37\x0c\x38\x13" + "\x92\xef\xd2\xd5\x66\x2d\xac\x92" + "\xc6\x63\x0c\x03\xc9\x70\x5a\x03" +
+       "\x61\x18\xba\x71\x85\xb7\x09\x51" + "\x3d\xf9\xc8\xd0\x5c\x2d\xb2\x48" + "\x93\xbb\x33\x86\xa7\x84\xfa\xe8" + "\x08\xbd\xeb\x5a\xba\xa6\xfb\x53" + "\xd8\xa7\xee\xe5\xf3\x7d\xf2\x7f" + "\x58\x71\xca\x68\x96\x87\x1c\x52" + "\x05\x1a\x6f\xce\x3b\x13\xd5\xb9" + "\xe4\xbe\x0e\xfd\x53\xcd\x50\x2d" +
+       "\x17\xff\x4c\xf7\x33\xa1\xeb\x14" + "\xf2\x13\xb8\xec\x03\xaa\x0a\x24" + "\xee\x5b\x66\x6f\x40\x65\xbb\xcf" + "\x73\xad\x25\xa4\xe4\x1f\x4b\x08" + "\xa6\xf6\x81\xd0\x16\x5d\x9d\x00" + "\x90\x2c\xf8\xee\xe8\x4f\x30\x35" + "\x22\xaa\x9e\xaa\xd5\x46\x03\xf2" + "\xe3\x91\x1c\xac\x07\x9f\xda\x0a" +
+       "\xcf\xf1\x0d\xb4\x23\x3e\x9b\x7d" + "\xb4\x71\xe9\x94\x73\x73\x33\x59" + "\x21\xf9\x9c\x66\x14\xbd\x57\xbf" + "\x64\x10\x1a\x0c\xdf\xae\x5d\x86" + "\x25\x91\x27\x83\xd3\x0b\xb7\x3e" + "\xab\xda\xec\x34\x9f\x5b\x3d\xbc" + "\xaf\x5c\x75\x5f\x7e\xed\xe3\x91" + "\x02\x6f\x1e\xd4\x54\x9f\x69\x49" +
+       "\x34\x48\x3e\x0f\x58\x77\x41\x30" + "\xcb\xaf\xa9\x17\xc2\x21\xbb\xfd" + "\xb3\x67\x9a\x2f\x7f\xa1\x6f\x75" + "\xa8\xc1\x45\xa2\x21\x24\x6b\x2a" + "\x91\x22\xf0\x4a\x94\x27\xbe\x64" + "\xfe\x04\x58\x2a\xc6\x65\xe4\xad" + "\xd7\x8f\xf0\xa6\x39\xbd\xff\x8d" + "\x3b\x40\x14\xaa\x4c\xa8\xef\xc4" +
+       "\x27\x84\x71\x47\x46\x80\xb4\xda" + "\x8b\x0f\x83\x6e\x9b\xff\x17\xdf" + "\x47\x13\x9a\xe4\xe8\x7e\x8d\x40" + "\xae\xd4\xc1\x91\x23\x1e\xc7\x6a" + "\x3c\xd7\xef\x1d\xfd\xb9\xcb\xc8" + "\xc5\xfe\xbb\xbb\x57\x06\x84\x19" + "\xea\xf8\x7e\x9e\xb5\x1c\xdb\x39" + "\x30\x5f\x10\x64\x96\x82\xaa\x78" +
+       "\x4a\xef\x5f\x06\xc2\xf1\xbe\xcd" + "\xe3\x92\x5b\xfd\x7d\x0f\xe6\x77" + "\x50\x83\x70\x26\xf0\x49\xc5\xd7" + "\xbf\x21\xf1\x34\xd0\x3a\x1b\x20" + "\x14\xfc\x34\x03\xa1\xc2\xca\x5f" + "\xf6\x52\x45\x34\x09\x9e\x9a\x8a" + "\x82\x30\x65\x97\xd3\xa1\xd8\x7d" + "\x89\xf2\xd4\x79\x8f\x73\xc0\x5f" +
+       "\xba\x02\x35\xbd\x71\x8e\x60\x67" + "\xa0\x75\xde\xb4\x24\x1f\xf4\x4e" + "\xe5\x25\x61\xfd\x5e\xde\x8d\xb0" + "\x3f\x54\x09\xa4\x25\x48\x48\xde" + "\x95\x22\xcc\x65\x98\x8d\x19\x1f" + "\xa2\xdf\x0e\x6e\x71\x37\x8a\x42" + "\xc7\x5f\xf3\xad\xa2\x97\x96\x4f" + "\xc7\xc3\xca\xf7\x79\x3c\xa4\x01" +
+       "\x0c\x44\xae\x7c\x5b\x8d\x25\xc1" + "\x31\x75\x2b\x40\x41\x8b\xc0\x21" + "\x21\x23\x93\xde\x55\x89\x1a\xf6" + "\xaf\x08\x14\x2d\xf8\xfa\x68\x35" + "\x5b\x96\xcf\x9e\x99\x5e\xb1\x71" + "\x6f\x27\x17\xe9\x48\xd2\x4e\xf1" + "\xe2\xf9\x0c\x82\xa1\xca\xf4\xc6" + "\x7e\x3c\xd8\x18\xb2\x20\x1b\x68" +
+       "\x17\xf2\x3e\x53\x65\x6d\x9f\x88" + "\x87\x2e\xca\xc3\xe4\xc7\x58\x71" + "\x67\x41\x2b\xdc\xfb\x0d\x67\xfb" + "\x7f\x25\x4c\x84\x01\x0a\x91\x75" + "\x7d\x57\x88\xcf\x07\xbf\x36\xf3" + "\xce\x2a\x5e\xe4\x50\x52\x24\x22" + "\x85\x3d\xa2\x7c\x8d\x2e\xd9\x2e" + "\x58\x2f\x81\x2b\x4c\xbe\xf8\x29" +
+       "\x92\xba\x67\x34\x97\xf1\x5b\xd6" + "\xb0\x54\x09\xf7\xdb\x46\x9b\x8c" + "\x5d\xf1\x78\x0e\xf3\xa0\xc8\x97" + "\x61\xc9\xa4\x85\x9a\xa6\xf3\xa8" + "\x9b\xce\xe4\x61\x0f\x66\x42\x42" + "\x0c\x79\xa6\x6e\xb3\xaa\x06\xbf" + "\x16\x64\x98\xec\x8e\x6f\x70\xc6" + "\x25\xc2\x9f\x9a\xc1\xde\x56\x9e" +
+       "\xf1\x03\x51\x9a\x71\x32\xee\x4b" + "\x06\xac\x0e\xf5\xc6\xef\x43\x52" + "\x19\xc1\xdc\x6a\xcb\x22\xe1\xb8" + "\x08\x0a\xb8\xc0\x84\xaa\x7f\x1b" + "\x8c\xd0\xfc\x6d\xbd\xd1\xc3\x32" + "\xde\x27\xe4\x0b\x4e\xec\x9d\x12" + "\x83\x3c\x26\x1d\x9c\x67\xab\x98" + "\xff\x4e\xf6\xce\xb7\x3c\xc8\xaf" +
+       "\x51\x5a\xdf\x3f\x7d\xe4\x87\x1d" + "\xb0\xca\xc9\x55\x93\x5f\xfb\x7a" + "\x6e\x58\xe0\x89\x8f\xf5\xbb\x91" + "\x09\x37\x84\x0d\x18\xc0\x72\x7c" + "\xdc\xc3\xb5\x99\xfb\xaa\xa5\xa9" + "\xb0\xae\x44\x38\x1d\x0f\x8a\xa4" + "\x82\xe4\x67\xb6\xdd\xb7\x78\x71" + "\x9a\xa5\x23\x6e\xe9\x85\x39\x45" +
+       "\xa5\xb8\xf4\xea\xe0\x4d\x6a\xaa" + "\x32\x0e\xc6\x4b\xca\xd9\xcf\x68" + "\x70\x5e\xd1\x7f\x01\x4b\x8a\x66" + "\x9d\xc0\x7d\xf2\x4a\x69\xf0\xd9" + "\xcd\x8b\x70\xba\xd5\xca\xc3\xf6" + "\x2a\x5c\xb9\x5b\x69\xba\xd2\x5c" + "\x8f\xa5\xc0\x33\xd3\xc1\x28\xaa" + "\x70\x78\xc7\xab\xe3\x74\xe2\x23" +
+       "\x4b\x88\xc1\x1c\x2d\xc8\xcf\xec" + "\xb4\x53\x47\x5d\x01\xc2\x5a\xc8" + "\x9f\x09\x8e\x65\xac\xca\xa6\xc7" + "\x90\x73\xb2\x04\x9e\x36\x46\xcf" + "\xea\x67\x64\x50\x49\xd0\xe7\xe2" + "\xcc\xec\xcd\x37\xa2\x63\x1b\x48" + "\x3a\x14\x80\xed\xd8\xab\x29\x40" + "\x88\x0b\xb0\xbc\xc7\xe3\xbf\x28" +
+       "\x0b\x4a\xe2\x33\x2f\xf8\x57\xff" + "\x79\x50\x56\xf2\x3f\xe2\xbe\x9c" + "\x25\x58\x5f\xeb\x27\x34\x35\x16" + "\x62\xd6\x48\xe9\xc4\xee\x6f\x27" + "\x2b\x03\x10\xda\xc6\x2b\xb6\xd1" + "\x53\x2a\xe7\xf0\xdd\x51\x83\x71" + "\xba\xe7\x20\x24\x76\x20\x45\x93" + "\x8d\x11\x00\x3a\xff\x8f\x36\x96" +
+       "\x6b\x4c\x7c\x9c\x15\x53\x97\xd8" + "\xf7\x9a\x40\xd7\xc0\xa3\x3a\x60" + "\xfb\x32\x71\x00\x0c\x3d\xd5\xb8" + "\x38\x92\x84\xa6\xf7\x2a\xd1\x68" + "\x79\x92\x5d\xbf\xe7\x07\x06\xbe" + "\xce\x74\xda\xaa\x55\x00\xa5\x9a" + "\xcb\x8c\x7e\xba\xcb\x79\x10\xe8" + "\x5e\xff\xf4\xa5\xd1\x71\x0c\x61" +
+       "\x61\xa6\xb6\xe3\xbf\x81\x47\x18" + "\xf7\x79\xd2\xe6\x1d\xcb\x51\x77" + "\x62\xb6\x9e\xc5\xd6\x95\xff\xf8" + "\xa7\xde\xd3\x58\xb7\x90\x6d\x18" + "\x54\xf7\xb4\xdf\xc1\xb6\x4b\x0e" + "\xdc\x01\x28\x2b\x6b\xf5\x5c\x5c" + "\x4d\x56\x54\x1f\x52\xe4\x61\xc5" + "\x13\x7f\xdd\xf0\x60\x8c\xfb\xb4" +
+       "\xb3\x81\xfc\x29\x0b\x20\x4c\xac" + "\xc1\x87\x1d\x17\x9f\xe0\xc3\xeb" + "\x9e\xaa\x81\x14\x30\x95\x79\x91" + "\xfa\x14\xe1\x92\xe1\x92\x1b\x05" + "\x7f\x53\xb5\xec\xe9\x92\x8f\xdf" + "\x83\x74\x0c\x29\xcc\xb2\xb1\x44" + "\x16\xb0\xde\x2a\x5a\x45\x11\xa7" + "\x2c\x0c\xa1\x81\x56\x68\x4b\x96" +
+       "\x7a\x56\x88\x40\x08\x59\xf4\x73" + "\x61\x4a\x21\x1f\x0e\x28\x6b\xeb" + "\x3d\xc1\xf0\xca\x34\xdc\x9a\x8c" + "\x80\xfb\x61\xf5\x38\x29\xd1\x39" + "\xb4\xdf\x6e\xbc\x5e\x3a\xdc\xb2" + "\x0e\x21\x4d\xfe\xb1\xb1\x85\x74" + "\x72\xae\x86\xe1\x00\x04\x2e\x06" + "\x88\x3b\xeb\x6e\x5c\x2d\xe3\x91" +
+       "\xfa\xde\x34\xb1\x85\xae\xe9\xc7" + "\x75\xd4\xb2\x1b\xd0\xb1\x73\x60" + "\x0d\xc0\x63\x28\x5e\x61\xad\xb9" + "\xc4\x4a\x5f\x52\x3d\x49\x29\x9e" + "\x4f\xcf\x9a\x4e\xea\x1d\x2b\xc3" + "\x8d\xb8\x0d\xa5\xc8\x01\x1f\x3e" + "\x6c\x91\xda\x04\xea\x70\x5d\xb0" + "\x3e\x80\x65\xd8\x0a\x0d\x4b\x71" +
+       "\xee\xaf\x79\xe0\x0c\x92\x45\x59" + "\x1f\x83\x89\x67\xa0\x17\x6e\x68" + "\xe5\x5a\x4a\xb7\xe8\xbe\x66\x59" + "\x46\x8d\x25\x1e\xa2\x73\xa6\x38" + "\x95\x1c\x14\x83\xf2\xc1\x1c\xbd" + "\x86\xe4\x96\x0e\x4f\xcf\x2e\x3b" + "\x78\xfc\xe5\x74\x96\xa8\x3a\xcd" + "\x7a\xfa\x82\x24\x0c\xc1\x5e\x41" +
+       "\x10\xf5\xc3\x6e\x31\x5a\x20\x85" + "\x75\x04\x98\xd2\x14\x4a\x7e\x2c" + "\xfd\xeb\x30\x6f\xc0\x19\x3c\xde" + "\x44\xe6\xb7\xd4\x38\x1f\x1c\xdb" + "\x4a\x36\xce\x5d\x75\x1a\x29\xfe" + "\xe3\x5b\x8f\x05\x3c\x2a\xb2\xb7" + "\x8c\xa3\xfe\x37\x02\xc3\xd2\x2c" + "\x17\xbe\x17\x2e\x7a\x96\x30\x29" +
+       "\x44\x0a\x5b\xa1\x5e\x79\x0f\x02" + "\x58\xa9\x58\x89\xd7\xc8\x37\x8f" + "\xb5\x75\xb6\xa4\x9b\xe8\xb7\x63" + "\xea\x1a\xc3\x0f\x0c\x0c\xfb\xb4" + "\x2e\x1f\xff\xa7\x39\xe6\x95\xed" + "\xfb\x14\x96\x61\xa3\xf5\x80\x98" + "\xab\x51\x71\x94\x02\xff\xb6\xde" + "\xdb\xdc\x68\xa8\x8c\x11\xc5\x5b" +
+       "\xed\x7a\x9f\x34\x91\xcb\x97\xf1" + "\x20\x84\xca\x8f\x00\x5a\x2b\x3b" + "\xd8\xf6\xaa\x23\xe8\x5e\x17\x7c" + "\xb6\x32\xaf\x35\x21\xf4\xdc\x54" + "\x1e\x56\xd6\x27\x07\x43\xa1\x0b" + "\xe2\xb1\x75\xd1\xe4\x5e\x9d\x87" + "\xb5\x7d\x80\x99\x73\x36\xc4\xc7" + "\xcd\x5b\xd5\x9c\x55\x44\xa5\x77" +
+       "\xd9\xff\x33\x21\x45\xb2\xb9\xfb" + "\x20\x1a\x0f\x83\xf1\xb2\xa8\x39" + "\x2a\xf5\xa1\xd5\x7d\xc9\x4b\x48" + "\xf8\xdd\x0e\xa4\x56\xbf\xae\xd6" + "\xc6\xda\xcc\x76\xcb\x7a\x25\x32" + "\x27\xff\x86\x15\xec\x36\x4d\xaf" + "\xd1\x7d\xde\xf8\x63\x88\xaa\x8e" + "\x16\x7c\x64\x88\xcf\xd5\x45\x00" +
+
+       "\x9d\x97\x05\xc0\x74\xd5\xf3\xa6" + "\x50\xe3\x40\x6a\x42\x2b\x07\xc2" + "\xf9\xec\xe2\x8d\x56\xc1\xa5\xfc" + "\x4e\x34\x15\xa5\x5b\xbf\xc8\xa8" + "\x4a\xf1\x4d\x11\x55\xe5\xae\x97" + "\x6b\xec\xc5\xfd\x4d\x4a\x37\xd4" + "\x18\x54\xa8\x2c\x8f\xc2\x4c\x75" + "\x78\x1f\xc4\xd3\x27\x9e\xcb\x71" +
+       "\x39\x5c\x60\x03\x79\x50\x10\x89" + "\x6c\xc9\x42\xa1\x9e\x3d\x84\xf0" + "\x84\x36\x92\x16\x34\x49\x74\xf3" + "\x93\x28\x0a\xfa\x2f\xaa\x2c\x73" + "\x70\x01\x16\x61\x70\xc2\xe8\xb2" + "\xa3\xba\x7f\x43\xcc\x88\x27\xc3" + "\xac\xa3\xed\xa6\x8e\x81\xcd\x39" + "\x07\x2e\x2b\x9e\x39\x42\xe9\xe2" +
+       "\x2a\xe5\x60\x02\x9b\xd3\x67\x69" + "\x25\x33\x65\x90\xcc\x85\x25\xd4" + "\x54\x79\xca\x21\x05\xd6\x9b\x0d" + "\xb3\x57\xed\x81\x77\x08\xa2\x4f" + "\xbe\x0b\x4a\xe3\xf8\xef\xc1\x60" + "\x64\xef\xf6\x84\x0c\x04\xb0\x56" + "\x83\x84\xaf\xb1\x24\x2b\xbe\x28" + "\x14\x16\x53\xf5\x63\x81\x27\xb2" +
+       "\x1c\xac\x22\x59\x45\x75\xf2\x8d" + "\x63\x3f\x2b\xa5\x5c\xef\xb3\xa7" + "\xc4\x57\xde\x71\x14\xb2\x77\x8e" + "\x8b\x00\x4c\x83\x10\x2c\x68\x31" + "\x31\x5d\xd5\x4b\xf0\x24\x68\xc7" + "\x71\x1c\xb6\x17\x86\xc0\xd1\xb6" + "\x9d\x08\xa5\xc2\x03\x09\xdb\x31" + "\x3f\x5d\x4e\x18\x72\x21\x09\x9c" +
+       "\x38\xc6\x0c\xc0\x5b\xed\x7c\xdd" + "\xc2\x8f\x27\x61\xeb\x15\x20\x1a" + "\xd6\xf8\x37\x6a\x88\x52\x8e\x2e" + "\xad\x33\x99\xe7\x6f\x78\x57\xc4" + "\x1a\x21\x51\x2c\xce\x4c\xfe\xb3" + "\x98\x04\xc2\x24\xb2\x10\x9b\xad" + "\xe5\xb5\x8d\xd2\x4f\x7a\xd8\x90" + "\xc3\x2f\xca\x3a\x05\xd1\x8c\x69" +
+       "\x6d\x53\x1b\xe9\x07\x2d\x11\x4f" + "\xd6\x09\xba\x9e\xf2\x82\xb9\xce" + "\x6f\x39\x7c\x19\x2c\x7b\x15\x3c" + "\x24\xeb\x66\x7b\x41\x2d\x3c\xe2" + "\x37\x0d\x33\x3f\xd9\x57\x0c\x48" + "\xeb\x8d\x10\x79\xa1\xc8\xa4\xb3" + "\xe5\x9c\x19\xcb\xde\x88\x23\x70" + "\xd4\xa8\x44\xb9\x11\x92\x01\x0b" +
+       "\x36\xb3\x0b\x84\x92\xa6\xf2\x24" + "\x7b\xfa\x69\xa6\xdc\x3b\x35\x7c" + "\x00\xc3\xc9\xde\xfc\xd6\x20\xda" + "\x17\x4f\x3a\xa1\x2f\xbe\x5f\x62" + "\x28\x73\xc1\xdb\x1a\xb6\xb1\xa2" + "\x21\x56\x51\xa9\xbf\x65\x89\x00" + "\x46\xff\x20\xc6\x39\x09\x69\x49" + "\x1c\xe9\x17\x87\x7d\xd2\x2d\x18" +
+       "\x97\x39\x6c\xea\x35\x50\xce\x5a" + "\xef\x0b\x61\xc2\xaa\x9a\x25\x54" + "\x39\xdd\x80\x3c\x3f\xbb\x18\xef" + "\x39\xfa\xc3\x5f\x5b\xb9\x10\x69" + "\xee\x9a\xe0\x43\x10\xf5\xe2\xfc" + "\x65\x56\x67\xa7\x9f\x6c\xd5\xce" + "\x61\xdb\x72\xd8\xac\x65\xe2\x10" + "\x69\xce\x9f\xae\x2e\x81\x82\x69" +
+       "\x98\x09\x80\xce\xc6\x11\xbe\x29" + "\xd9\x60\x03\xb9\x52\x17\xbb\x72" + "\x90\xd5\x4a\x5a\x97\x31\x19\x2c" + "\xc0\xdb\xc1\x9f\x48\xf5\xa2\x2b" + "\xe0\xeb\x90\xe4\xbb\xee\xe4\x7f" + "\xc0\x11\xae\x7f\xcd\xa4\xa0\x12" + "\x37\xba\x03\xe9\x81\xcf\x97\x71" + "\xd8\x6d\x1c\xde\xa8\x4a\x7d\xcf" +
+       "\x4c\x68\xd5\x3f\xf4\x6b\xaf\x92" + "\xa1\x0a\x36\x80\xcf\xee\x26\x2b" + "\x82\x6a\x54\x00\x30\x0f\x96\xbd" + "\xfe\xd8\x9a\xf5\x43\x3c\x7b\x40" + "\xba\x82\x9c\x24\xfe\xe5\xca\x86" + "\x4c\x74\x63\x24\xc7\xae\x0f\x9e" + "\x72\x62\x91\x94\xe8\x51\xf5\x87" + "\x15\x06\xeb\x6c\x44\x93\x3f\x03" +
+       "\x84\x2e\xe8\x8b\xd1\xb0\x5e\x1e" + "\xef\x2f\x58\x7a\x0e\x7f\x96\x89" + "\xfa\x21\xe9\xa6\xd5\x87\xf6\xbc" + "\xba\x09\x7a\xd3\xf3\x4c\xee\xdf" + "\x65\xc4\x93\xb4\x65\x69\xf0\x94" + "\x30\xc0\x35\x76\x1c\x9a\x8b\x63" + "\x9f\x5e\xf0\x66\x64\x78\x66\x76" + "\x25\xa7\x4d\xc0\x08\x68\xaf\xcc" +
+       "\xfc\xcc\x8f\x76\x90\xb6\x2e\xca" + "\x62\xb3\x35\xb8\x7d\xd3\x02\xf4" + "\xce\xfc\xfd\xe2\xd0\xc0\xfa\x0e" + "\x90\xd9\x38\xb6\xef\xcd\xc9\xef" + "\x8b\x9a\x66\xd1\x72\x2b\xf1\x2a" + "\xbd\xcc\x74\x57\xbc\x36\xc5\x33" + "\x0e\x87\x34\xfb\x09\x19\xb2\x30" + "\xca\x5a\xf2\x7d\xf7\xa2\x8f\xc3" +
+       "\xf5\xf3\x81\xbf\x2b\xf0\xc5\x74" + "\x81\x45\x7e\xaf\xae\xa5\x25\x05" + "\xae\x54\x3c\x43\xba\xaa\xd2\x88" + "\xc5\x56\x6a\x80\xdb\x75\x97\xed" + "\x7d\xb3\xed\xc0\x8a\x73\x20\xd3" + "\x51\x1f\xcc\x66\xee\xb6\xfd\x25" + "\x76\x0d\x60\x10\x17\x1d\x66\xac" + "\x76\xed\xd1\xbd\xf3\xc1\x1e\x93" +
+       "\xf1\x43\xee\x19\x62\x1d\xc1\x65" + "\x97\x9d\x82\x60\x3e\x7c\xd5\x5c" + "\xe8\xe6\x4b\x98\xa3\x91\x6c\xd2" + "\xbd\x53\x0c\x8b\x09\x93\x8d\xf0" + "\xea\xe4\x16\xc0\x5b\x9e\xbc\x94" + "\x2b\x3d\xd4\x11\x39\x68\x91\xd3" + "\x55\x11\x70\x73\xd7\x5a\x6c\x88" + "\x15\x07\xb0\x20\x26\x76\x37\xe0" +
+       "\x59\xba\x80\xaa\xec\xc9\x01\x7f" + "\x51\x8e\x53\x68\x1a\x41\x83\x30" + "\xaf\x28\x81\xe8\xf1\x70\x03\x97" + "\x4b\xc1\xde\x91\xdb\xc3\x5c\x62" + "\x07\x31\xac\x01\x6c\x66\xf9\xfe" + "\xc3\x7a\x05\xd5\x77\xd5\xa8\xb2" + "\xf7\x5d\xbe\x92\x99\x62\xf2\xb0" + "\x24\x39\x35\x00\xe5\xc8\x79\xf5" +
+       "\x7a\xed\x41\x13\x93\x3d\xfa\xb8" + "\x49\x9d\xb5\xa7\x2c\x27\x23\x42" + "\xa4\xc4\xb8\x83\x47\x19\xcb\x3d" + "\xe4\x02\x13\xed\x01\x3c\x41\x4e" + "\xce\x44\x7e\xe1\x27\x91\x99\x6d" + "\xfb\xad\xb3\x33\x75\xbf\x86\xee" + "\xca\x96\xaa\x25\xe6\x2f\x90\xf6" + "\x7d\xe4\xaa\xe5\xe4\x40\x35\xb7" +
+       "\x8c\x15\x4a\x1b\x7b\x1d\x80\x32" + "\x69\xa3\xe2\x27\x9e\xc9\x71\xe5" + "\x97\xf1\xd9\x10\xc0\x76\xcb\x40" + "\xae\xc0\x67\x31\x89\xc2\x08\xc3" + "\xf2\x58\x79\xeb\xd3\x9d\xef\xa6" + "\xb1\x79\x08\x30\xfc\x6d\x22\xa7" + "\x36\x06\xdf\x7e\x62\xb3\xd0\x6c" + "\xed\x7e\xc3\x7b\x6c\xce\xfb\x4e" +
+       "\x21\x90\x69\x8d\x05\x2a\xf9\x75" + "\xe3\x66\x25\x77\x79\x4c\x6d\x58" + "\x3a\xd2\x1a\x76\xf1\xa5\x8c\x37" + "\xac\xa8\x65\x14\xfc\x86\x0d\x65" + "\x51\xa2\x2b\x84\x57\xd4\x4e\x7a" + "\x33\x49\x23\x42\xe6\xe3\x65\x6b" + "\x57\xd6\xaa\x31\xb7\x43\x15\xaf" + "\x69\xc3\xfe\xcb\x98\xfe\xce\xa4" +
+       "\xfb\xbe\x47\x9f\x90\xda\x87\xb5" + "\x13\x2d\x31\x41\xfb\xe9\x62\x65" + "\xfe\xce\xf1\xef\x59\xea\x91\xa6" + "\xf6\x4c\xfc\x05\x7a\x47\x30\xcc" + "\x3d\xfd\x0f\x0b\x61\x24\x63\xa1" + "\x56\x59\x35\x5b\x3b\x6f\xf1\xa1" + "\x24\xec\x24\x42\x53\x8d\x14\x5b" + "\x2a\x01\x77\xf9\x7b\x4e\x83\xdc" +
+       "\xbc\x9d\xc6\xb2\x75\x5e\xfc\x7b" + "\x6c\xda\xc3\x03\x29\x7a\xa7\x3a" + "\x71\x02\x91\xca\x3c\xf0\x0d\xde" + "\x55\xdc\x06\x78\x4a\xca\xd5\xcb" + "\xcb\x76\xb4\x6d\x07\x58\xca\xe1" + "\x1e\xa3\x37\x5f\x62\x5d\xe1\xfd" + "\x16\xf4\x1a\xf4\x20\xf5\x9a\xf4" + "\xb5\x2d\x34\x7d\xb1\xc5\xc5\x96" +
+       "\x9b\xeb\x4c\xeb\xb7\x43\x5c\x15" + "\x1a\x37\x77\x4e\x10\x30\x99\x2e" + "\xaf\x43\x5d\x67\xda\x87\x29\x1d" + "\x72\xfd\x99\x85\xc0\xc1\x2b\xef" + "\xb2\xf6\x42\x93\x7b\x4b\x89\x96" + "\xf0\x71\x8e\x7c\xf2\xad\x1e\x20" + "\xfc\x3e\x1f\x4a\x9f\x9d\x47\xf3" + "\x04\x97\x2a\x70\x42\xa7\xf8\xe0" +
+       "\x0c\xa4\xeb\xb3\xb6\x44\xfd\xea" + "\xd0\xe0\xc1\xc1\x29\x9f\x73\xf9" + "\x5e\x50\x9d\x61\x1a\x47\x91\x00" + "\x3e\x26\x7c\x9d\x96\x9c\x5f\xc1" + "\x33\xbe\xaf\x83\x85\x72\xe4\x5b" + "\x92\xe0\xf1\x04\xaf\xd6\xb6\xa3" + "\x11\x9d\x1a\x75\xb9\x26\x65\xe7" + "\xd2\xe4\x4a\x9a\x6d\xb2\xc5\x2e" +
+       "\x8d\xfb\xf6\x02\xd9\xf4\x66\xeb" + "\x64\x21\x91\x96\x61\xc5\x63\x40" + "\x00\x30\xef\x80\xc1\x50\x70\xeb" + "\xf0\xb3\xa5\xea\x33\x1c\x8d\x28" + "\xd8\x6f\x80\x07\xd6\x68\x7c\xe8" + "\x0f\xf5\xbb\x4b\xd5\xf9\xf7\xb2" + "\x27\x66\x8d\xac\x3a\x2f\x97\x25" + "\x3b\xc1\xe8\x10\x74\x77\x54\xf8" +
+       "\x60\x4a\x2b\x87\x6c\xef\x50\xcc" + "\x1b\x52\x13\x46\xa4\x34\x2a\xab" + "\xd1\x15\x3e\x98\x90\xc1\xc5\x39" + "\x12\x55\x90\x59\xdf\xe5\xdd\x61" + "\xf3\x75\x22\x9f\x21\xf6\x17\xe4" + "\x4b\x89\x1d\x45\xb6\xc8\x50\x07" + "\xaa\xbd\xb0\x78\xb9\x4a\xb0\x75" + "\xbd\x89\x85\x45\xd4\x9f\xfd\x3b" +
+       "\xb6\x20\x91\xee\x30\x3e\x01\xf1" + "\x3e\x74\xa4\x23\x93\xaf\x51\x2b" + "\x9e\x4d\xd1\x48\xae\xff\x96\xea" + "\x32\x1d\x8a\x69\xbe\x0d\xdc\x71" + "\xa4\xcc\x80\x01\xd2\x62\x49\x91" + "\x63\x89\x56\xc3\x77\x06\xe6\x1a" + "\x44\xc4\x7b\x43\xb1\x27\xf2\x8c" + "\x7a\x2c\x96\xc9\x3b\xc8\x50\xc6" +
+       "\xc4\xcf\x7c\xfe\xdd\xc7\xc2\x23" + "\x48\x9d\x92\x1b\x9d\xc8\x25\xf9" + "\x33\x3c\x78\x06\x4b\xf7\x60\x44" + "\x5a\x47\x90\xa5\x49\x8d\x2c\xac" + "\xa0\xbb\x07\xb8\x07\xb4\x40\xfb" + "\x3a\x8f\xff\x69\x2d\x36\x1e\x9d" + "\xa4\x64\xef\xcb\x81\x96\x3e\xa3" + "\xb2\xb4\x2f\x33\xfa\xe5\xec\x67" +
+       "\xe3\x10\x9f\x73\x9b\xa9\x00\x69" + "\x25\x59\x52\xff\xa9\x1c\x34\xc3" + "\x41\xd0\xe2\xa9\x26\xa6\x18\xee" + "\xdd\x0d\x58\x29\x85\x36\xa8\xa5" + "\xcd\xe3\x7d\x9d\x81\x0c\x47\xf3" + "\x9c\xcf\x62\x20\x86\x25\xf0\xed" + "\xb0\xed\x10\xc0\xfa\x22\x35\xf4" + "\xae\xb1\xa4\x13\x35\x41\x31\x30" +
+       "\x4b\xb9\x22\xdb\x2a\xe0\x92\xc7" + "\x5b\xa4\xea\xa1\xe9\x8a\x3d\x99" + "\x63\x1c\x1e\xcd\xd3\x6c\xad\x8a" + "\x8a\x68\xce\xc5\xa7\x9c\x52\x89" + "\x53\xa2\x72\xe5\xaa\xe3\xce\x2c" + "\xfb\x1e\xa2\x02\x38\x64\x2b\xe0" + "\x58\x03\x43\xc9\x6e\x1b\x09\xa7" + "\x04\xb5\x7d\x9d\xfa\xb1\xd1\x06" +
+       "\x33\x47\x74\xc4\x32\x6d\x84\x58" + "\x34\x9e\x9f\x37\x71\x7c\x51\x40" + "\xca\xf6\x0e\x13\x5f\x65\x65\x2f" + "\x3f\x50\xf3\xf1\x88\x44\x6e\x52" + "\x76\xa9\xe4\x7e\x17\xbd\x67\x84" + "\xd1\x63\x13\x92\x13\xc9\x9d\x1d" + "\x41\xe0\x69\xb0\x33\x4c\xd2\xd8" + "\x51\x7f\xdf\x2c\x0a\xda\xb5\x5e" +
+       "\x4f\x99\x7b\x19\xb1\x3c\x0f\x1c" + "\xe9\xea\x43\x28\xc5\xa6\x95\x3c" + "\xa5\x7e\x09\xa6\xc9\xff\x66\x77" + "\x67\xb8\x23\xd7\x93\x40\xea\x7b" + "\xf9\x78\xb3\x4d\x73\x1f\x8e\xb4" + "\xac\x77\x7b\xe3\x00\x5b\x02\x70" + "\x46\xad\x24\xaf\xe7\xc8\x3d\x94" + "\x85\x0a\xd0\x16\xac\x15\x8a\xb9" +
+       "\x04\xb0\x43\x27\xba\x38\xdc\x3a" + "\xee\x15\x44\x33\xf7\xf4\xc7\xb1" + "\x5a\xd0\x62\x1e\x8f\xdf\x43\xea" + "\xb6\xa3\x76\x9d\x05\x89\x61\x32" + "\x46\x0f\x3a\xa2\xb5\x0b\xbd\x2f" + "\x8c\x91\x01\x6a\xdb\x71\xc9\x5b" + "\x94\x3f\x74\xb4\x4a\xd9\x01\x78" + "\x2b\xe2\x6a\x67\x5e\xf6\x4d\xb9" +
+       "\x4c\x89\x95\xaf\xab\xbf\xfc\xaa" + "\x41\x22\x6b\x27\x07\xdc\x9b\x7b" + "\x8b\xa4\xdd\x5b\x62\x83\xf9\xea" + "\xdf\xb4\xfc\xa3\xf2\xfa\x77\x59" + "\x5b\x4b\x2c\x05\xef\x42\xd0\xbe" + "\xf0\x91\x75\x06\x71\x7f\xe8\x9f" + "\xc7\x4e\xf2\x22\xca\x73\x9c\xc8" + "\x1b\x9f\x4a\xe6\x9e\xfa\x37\x7d" +
+
+       "\x0f\x0c\x75\x0a\x88\x64\x7a\xcc" + "\x83\x8e\x54\x4e\xe3\xcf\xba\x39" + "\x05\x0f\x11\x0c\x76\x8c\x41\x3d" + "\x88\x15\xf1\xb1\x4c\xaa\x4d\x3e" + "\xff\x69\xfc\x5f\xb5\xe7\x33\x27" + "\x27\x31\x05\x92\xbc\x47\xf1\x46" + "\x94\xdf\x22\xd7\x34\x24\x5b\x88" + "\x7c\x6b\xfc\xe6\x65\x4f\x44\x6a" +
+       "\xa8\x6e\xf1\xc3\x5a\x46\x1a\x7a" + "\x1c\xd1\xf1\xb2\x1d\x46\x5a\x11" + "\x72\xa1\x68\x6c\x95\xdd\x67\x47" + "\x98\x46\x3a\xd1\xeb\xf2\x92\x33" + "\xc7\xcd\x26\xe5\xcd\x9c\xa9\xc7" + "\x81\x2b\x29\x22\xdc\x7f\x53\x8e" + "\x98\x91\xd3\xa6\x69\xcf\xd8\x76" + "\x2d\x85\x46\x24\x43\xff\xc5\xff" +
+       "\xbd\xdf\xae\xbd\xf4\x16\x0b\x6d" + "\xed\x6c\x74\x86\x60\x32\xfd\x23" + "\x17\x3e\x4b\xff\x2f\x1d\xfb\x8b" + "\xc8\x14\x9c\x01\x2d\xec\xf2\xc7" + "\x0d\x4b\x10\x45\xf2\x32\x08\x3e" + "\x7e\x2b\xea\xad\xfb\xda\x00\x5f" + "\x0f\xfb\xfb\x99\x66\xcf\xe5\x29" + "\xda\x7c\x82\x61\x23\x97\x4f\x26" +
+       "\xe6\x67\x05\xa9\x7e\x4f\xb1\x97" + "\xb7\x5c\xae\xb6\xb7\x57\x32\x51" + "\x3d\x90\x10\x9f\x3c\x4a\x45\x85" + "\x24\x37\xbc\x69\xad\xc9\xd2\xd8" + "\x44\xcb\x29\x6b\x24\x93\xda\x38" + "\xac\xcb\xc8\x77\x1d\xa2\x40\xb5" + "\x42\x8e\x91\x01\x35\xe4\xbf\x9b" + "\x4e\x61\xc3\x56\x7a\x70\xfa\xff" +
+       "\x7f\xc2\x0b\xe3\xf3\xa2\xb1\x6e" + "\x11\x65\x83\xb0\x5a\xc0\xf0\xe5" + "\x0e\xab\x65\x49\xbf\x1b\x74\x4d" + "\xbd\x4b\x46\x83\xca\x41\xec\xfe" + "\x9f\xb0\xd0\x99\x5f\x70\xca\x1a" + "\xfa\xa5\x2d\xf4\x56\xcc\xd6\xc5" + "\x31\xb9\x52\xcc\xdd\x4e\x96\x49" + "\xd8\xd8\x84\xc8\x15\x96\xe5\x8a" +
+       "\xb7\x53\xe3\xd4\xf1\xe3\xe4\x0c" + "\xa0\xb0\x46\xef\x14\x8a\x2d\x06" + "\xfd\x73\x4b\x57\xab\xd5\x08\x64" + "\xfd\x3f\x27\xd3\xc9\xd1\x41\xbc" + "\x00\x78\xe7\x6b\xe7\xe1\x38\x35" + "\x31\x50\x65\xc5\x37\x8b\xfe\x71" + "\x1a\x33\x9b\x6b\x21\x16\xd9\x1c" + "\x73\x8f\x38\xbb\x0b\x5d\x82\xad" +
+       "\x8a\x86\xf8\x39\x7b\xb5\x34\xf6" + "\xaf\x69\xcc\x75\xd4\x4f\x7f\xe2" + "\x6e\x49\xd5\xd0\xcb\x58\x7e\xa4" + "\x7f\xe0\x23\xd3\x3f\x79\x26\x8a" + "\x49\xf3\x30\xfa\x72\x9b\x1a\xc6" + "\x34\xd1\x96\xb6\xc9\xd9\xc9\x94" + "\xd1\xa6\x80\x58\xa8\xec\x2b\x79" + "\x95\x99\x03\xaf\x45\x46\xcc\xbd" +
+       "\x19\x62\xb7\x1c\x5b\xe0\xc2\x56" + "\x7e\x7e\x56\x71\x91\xbf\xc0\x0e" + "\x10\xc9\xc4\x61\x86\x6f\x07\xe7" + "\xd9\x04\xbc\xba\x5b\x08\x7b\xd6" + "\x6a\xa9\x93\x5e\x59\x04\xb9\x9f" + "\x9a\x24\xdc\xfb\xea\xc1\x26\x75" + "\xb7\x0b\xdd\xec\x67\xd3\x44\x0d" + "\x95\xd6\xc0\x9d\x17\x99\x39\x95" +
+       "\x3c\x6c\x79\x8c\xe5\xf8\x7e\xce" + "\x7a\xe5\x66\xdd\x84\xae\xda\x9a" + "\x33\x7f\x22\x45\x3e\xe1\x4a\x78" + "\x57\xe7\x85\x2a\xb8\xc5\x46\xb0" + "\x1f\x63\x37\xec\xae\x50\xaa\xb7" + "\x58\x07\x30\x3b\xca\x4f\xdc\xbe" + "\x0b\x70\xc9\x0a\x7e\x56\x82\x0f" + "\xd2\xf8\xf5\x4f\xd4\xd9\x71\x10" +
+       "\x18\x0d\x24\x9e\xe9\x0e\x36\x61" + "\x66\x44\xb9\xb4\xac\xdc\x7c\x05" + "\x5c\x32\xe5\x2f\xd1\x7c\x66\xe7" + "\x3b\x4e\x97\x21\xb5\x97\xa2\x1f" + "\x76\x3d\x08\xdb\xe7\x81\x40\xfa" + "\x15\xbd\x06\xf2\xe6\x3b\x99\x31" + "\x8c\x9f\xc1\x14\x9b\x26\x49\x89" + "\x57\x23\xd9\xa9\x72\x8d\x46\x21" +
+       "\x11\x28\x1a\xe5\xc4\xf6\x9e\xd0" + "\xb9\x66\xfb\xb8\x2b\x86\xf6\x39" + "\x99\xaa\xdf\x22\x8d\x7f\xe7\x64" + "\xac\x8a\xb0\x61\x44\x50\x10\x7b" + "\x32\xf3\x7d\x4a\x4c\x4e\x70\x71" + "\x5b\x01\xfe\x2f\x34\x34\x97\xd0" + "\x0e\x02\xd3\x08\x44\xaf\x0e\xab" + "\x7a\xb9\x63\xed\x9e\x90\xb1\x28" +
+       "\xec\x06\xc5\xa4\x83\xc5\xcb\x2c" + "\x97\xfe\xac\xd1\x88\xd1\x7e\x95" + "\xa2\xae\xf1\x12\x33\xd8\xae\x8b" + "\x2d\x36\x25\x83\xb4\x6c\x2a\xef" + "\x43\x5c\x19\x8e\x42\xde\x0d\x13" + "\xc6\x50\x60\x0e\x5a\x02\x42\xc8" + "\x5d\x6a\x68\x08\xa7\x72\xa9\x2d" + "\xa8\xb4\x08\xe5\xa1\x99\x29\xb5" +
+       "\x4f\xcd\xad\xcd\x82\xa8\x3f\x2f" + "\x95\x19\x63\x5f\x59\x68\xef\xa4" + "\x6f\x76\x31\xe5\xf9\xa2\x2c\xe5" + "\xd3\xc1\xe2\x57\x30\x5c\xaf\x20" + "\xb8\x94\x1e\xe5\xf6\x28\x48\x1e" + "\x4f\x5d\x2f\x1a\x75\xa1\x00\xf9" + "\xa0\x58\x2c\x39\xb3\xad\x31\xe8" + "\x66\x58\x6e\x1b\xca\x90\x5a\x4c" +
+       "\xbd\xa8\xa5\x10\xb9\x90\xf0\xd9" + "\xda\x64\x68\x09\x49\xd2\x91\xca" + "\xc1\xdb\x67\x3f\xbe\x93\x6a\x8e" + "\x4c\x76\xf4\xf5\xba\x6f\xae\xac" + "\xa0\x11\x14\xd2\xe0\xc6\x63\x15" + "\xd8\x4a\x0a\xda\x7f\x78\xfa\x28" + "\x30\x80\x8c\x90\x1c\x49\x24\xd5" + "\x07\x5f\x79\x4c\x0e\xba\x57\x12" +
+       "\x7c\x82\x82\x61\xa8\xcb\x3d\x5f" + "\x52\x72\x7e\xbd\xdd\x48\xa4\xd1" + "\x15\xb8\x93\xf4\xfc\x96\x8f\x2d" + "\x5f\xa9\x0a\x3b\x26\x4c\x0a\xba" + "\x7f\x00\xa0\x63\x40\x51\xa1\x88" + "\x46\x58\x9c\x6a\x5e\xc2\x64\x95" + "\xca\xcb\x0f\xdc\x0f\x7b\x4d\x5a" + "\x0e\x74\x8a\x3f\xa3\xda\x75\x22" +
+       "\x54\x97\xca\xce\x67\x91\xf4\x83" + "\xa0\x39\x79\x4b\xf6\x2c\x6d\x42" + "\xbf\xd0\x3f\x72\x55\xe3\x55\x25" + "\xe2\x44\xf1\xc4\x06\x6d\x6e\xa9" + "\x61\x0e\x88\x87\xdd\xa8\x68\x47" + "\xd5\xe4\x08\xe5\x15\x38\x54\x15" + "\x15\x5e\xb6\xb1\x72\xe7\xd7\x09" + "\xa0\x2f\x30\xac\xd6\x9d\x43\x63" +
+       "\x6b\x08\x61\x04\xcc\x91\x95\x15" + "\x51\x6e\xe6\x95\x94\xaa\x95\xb6" + "\x31\xd5\xde\x79\x67\x94\x4c\x2d" + "\x79\xbe\xc2\x89\xba\x82\x24\xbd" + "\x19\xbf\x0b\xa2\x8a\x65\xe2\x8e" + "\x17\x79\x24\x32\x8a\x52\x00\xc0" + "\x45\xe8\xea\xff\x4a\xbe\x24\xd9" + "\x8b\x2c\x99\xed\xeb\x2b\x31\x51" +
+       "\xc2\x35\x4e\xc1\x2f\x80\x3f\xb9" + "\x3c\x33\x41\x43\x7c\x5b\x73\x71" + "\x62\xf3\xd4\x16\x04\x51\xa2\x03" + "\x8e\x3c\x43\xbf\x9b\x06\x4d\x3f" + "\x7c\x5a\x8f\xf7\x01\xae\x83\x0d" + "\x07\xed\x4e\x7c\xbe\xff\xa8\x50" + "\x83\x0f\xe1\x76\x06\x89\x4f\xc7" + "\xe1\xf8\xda\x9d\x66\x09\x08\x7d" +
+       "\xd9\x2b\x75\xdc\x58\xb9\x01\x3a" + "\x45\x5d\x21\x0c\xc2\xdb\xab\x2b" + "\xc1\x41\x16\x13\x9a\xd7\x89\xe6" + "\xd4\x5e\xe0\x80\xda\xf0\xe8\x48" + "\xc4\x70\xbb\x77\xeb\x5f\x50\x4b" + "\xf7\x7e\x05\xb6\x2b\x3e\xbd\xef" + "\xa5\x3c\x60\xce\x2d\xe2\x83\x75" + "\xc7\x70\x5c\x2c\xf2\xb1\xe3\xfb" +
+       "\xcc\x04\x8e\x69\xe1\xf8\x1d\xb1" + "\xc8\x05\x90\x16\x03\xe2\x7b\x87" + "\x79\x61\x3c\x4f\x8c\x9e\x74\x32" + "\x05\xfc\x53\x78\x0a\x9d\xbc\x2d" + "\x37\xd9\x54\x94\x93\x4f\x7d\x18" + "\x1b\x0e\x80\xb4\x9d\xce\x82\xe6" + "\xe8\x68\x5e\x16\xd8\x9a\x12\xa9" + "\x5b\x78\x7f\xbe\x35\x97\xe2\x0f" +
+       "\x5a\xe3\xe5\x29\xf0\xec\xc1\x8e" + "\xb3\xc2\x45\x86\xe5\x68\x31\x2f" + "\xb2\x4c\xf9\xc7\x62\x73\x29\xe9" + "\x39\x0b\xc9\xd1\x66\x14\xbf\x4f" + "\x2a\xae\x0b\x92\x56\x76\x4f\x3e" + "\x72\xb1\xbe\xf1\xb9\x04\x5d\x80" + "\xb4\xd4\xdb\xdb\x08\x72\x9a\x72" + "\x53\xca\xae\x87\x56\xe4\xad\x1a" +
+       "\xb7\x02\x9e\x5b\x0c\xf4\x03\x53" + "\xe8\x04\xee\x35\x92\x96\x7c\xa3" + "\x2b\x63\xd6\x34\x20\xcc\x46\x5f" + "\x5b\x54\xac\x96\xb2\x72\xef\x55" + "\x62\xb0\x91\x7b\x1f\x5c\xec\xab" + "\x21\xe8\x33\xbb\xc7\xe1\x79\x0a" + "\x17\x41\x9f\x3a\x28\xb4\x04\xbb" + "\x5a\x47\x2a\xfd\x8f\xf2\xe1\x0d" +
+       "\x08\xa5\x34\x19\x54\x1f\xff\xb0" + "\x1a\xf3\xbb\x04\x76\x39\xe1\x19" + "\xb4\xa6\x17\x37\x03\xe6\xa8\xb2" + "\xb9\x2c\xf1\x0e\x5d\xe4\x01\xd6" + "\x8e\xe9\x15\xb5\xf5\x0a\x3f\x56" + "\x9b\x4f\x98\x33\xb6\x9d\x12\x9b" + "\x65\x4a\x7e\xa4\x2f\xba\x4a\xe3" + "\x82\x9d\x3f\x9e\xd1\x82\x6f\xb5" +
+       "\xb4\x34\x44\x3a\xcf\x9c\x01\x31" + "\xdc\x54\x79\x1a\x11\x81\x45\xa3" + "\xa7\x72\x49\xe3\x0d\xc8\xda\xa9" + "\xdd\xb8\xf6\x74\x54\xd0\x43\xb0" + "\x1a\x7b\x13\x11\x9e\x31\x1c\x02" + "\x3f\xc0\x5c\xed\xce\x54\xa7\x00" + "\xd4\x5a\xea\xcb\x94\xc7\xa2\x0a" + "\xb6\x15\xc0\x70\xf4\x67\x3e\x09" +
+       "\x86\x9b\x20\xb1\xfd\xef\x03\x02" + "\xbf\x6c\x9d\xb1\xed\x63\xf0\x21" + "\x5b\x27\x0f\x98\x76\x34\xf5\x59" + "\x80\x5e\xac\xb7\xd7\x56\x24\x20" + "\xc9\xed\x00\x49\x5f\xc0\xa8\xe5" + "\x86\x1e\xf0\x70\xb4\x8e\xc0\x04" + "\xce\x98\xcd\x1d\x24\xc2\x4a\xf7" + "\xdb\x30\xe8\xe2\x0c\xcc\x77\x7e" +
+       "\x6b\x3f\x7e\xc9\xe9\xfe\xcd\x72" + "\x61\x74\xda\xb6\xb4\xca\x0b\xc1" + "\xb9\x06\x98\xb5\xfc\xd2\x02\x3b" + "\x47\x6f\xde\xa1\x89\x5e\x18\x85" + "\xd4\xc4\xb6\x0e\x1f\x93\xe6\x39" + "\x04\x5b\xfa\xd4\xbd\x40\x44\x4d" + "\xb8\x7e\xbe\x34\x6e\x78\x18\x54" + "\xbc\x59\x72\x9d\x21\xe5\x80\x63" +
+       "\xde\x7e\x74\xa9\x34\x72\xe3\x74" + "\x13\x10\x1b\x36\xb1\xfb\xc9\x4f" + "\xef\x57\xf3\x3c\x73\x33\xb5\xe7" + "\x93\x41\x1c\x99\x2c\xdd\xa2\x6a" + "\x7a\x91\x70\xa7\xd2\xe4\x87\x78" + "\xcb\x24\x0d\xc2\xb4\x09\x18\xdd" + "\x3e\x2d\x9c\x8e\xc3\xd7\x4c\x00" + "\xbe\x0a\x97\xa9\xab\x5b\x7c\xc7" +
+       "\x10\xd7\x98\xd5\x51\x03\xac\x20" + "\xa4\x4d\x3a\xcb\x66\x41\x2c\x27" + "\x1f\xde\x71\xca\x1a\xfe\x82\xdb" + "\x0f\x4b\xf5\xd8\xf2\x79\x6e\x74" + "\x9b\x3e\x57\x4b\x36\xc7\x7f\x6e" + "\x40\x50\x4b\xfd\x46\x3f\xd0\x75" + "\x7b\xd8\x98\x0b\x6d\xc3\x1c\x5c" + "\xa1\x2d\x47\x1f\xf1\xa3\x3b\x51" +
+       "\x7f\x23\xaf\xc3\xaa\x7e\x92\x52" + "\x67\x87\x39\xd7\x65\x60\xa0\xfa" + "\x0b\xce\xc6\x97\xb4\x72\x2e\x04" + "\x61\x23\x9f\x0a\xc4\x0c\xed\xda" + "\x4a\xbb\xc1\x2f\x1c\xe1\xc2\xdd" + "\xf8\x9e\x1a\x0c\x77\xa5\x1d\x63" + "\xbf\x72\x02\x68\x44\xfe\x4c\x8a" + "\xc3\x5c\xfb\x62\x72\x9f\x6b\xc7" +
+       "\xdd\x77\xb1\xab\x26\xaf\xd0\x79" + "\x64\xd5\x91\x78\x68\xb5\x2a\xf8" + "\x73\x21\x23\x72\xa9\x68\x67\x2b" + "\x19\x66\x1f\x8c\xb0\x3b\xbb\xef" + "\x58\x83\xd1\xa6\xdb\x11\x9c\xb2" + "\x3a\x6d\x91\xb0\x97\x27\x9e\x51" + "\x90\xe2\x88\x91\xf0\x18\xdc\xd4" + "\x7f\xca\xb0\x98\xe3\x86\x8e\x64" +
+       "\xe3\xaa\xb3\x38\x45\x81\x8f\x24" + "\x34\x43\x20\xbc\x64\x58\x34\xb5" + "\x24\x75\x12\x1d\xbc\xb5\xd6\x66" + "\xd3\x72\xf5\x14\x0d\x08\x12\xe3" + "\xeb\xaf\xab\x16\xa7\x15\xed\x13" + "\xbe\x67\xa9\xdb\x27\xce\x18\x6f" + "\x2d\x55\x08\xef\x26\xe8\xc9\x96" + "\xe0\x63\x2b\xbe\x06\x1b\x19\x2c" +
+       "\xb5\x38\x3c\x98\x45\x31\x9d\x85" + "\x8b\xbc\x7a\x63\x6c\x17\x4f\xb1" + "\xe6\x7b\xff\xca\x9d\xfb\x93\x27" + "\x5a\x6a\xa6\x35\x5f\xa5\xe5\xeb" + "\x59\xdc\x87\x9f\xcd\x1d\xec\x7c" + "\x60\xf5\xdb\xfb\xd3\x5c\x59\x7c" + "\x57\x32\xeb\x26\x22\x3b\x54\x5b" + "\xfd\x35\xc9\xc4\x46\x06\x08\x69" +
+
+       "\x96\x16\x53\x1d\x38\x52\x34\xb9" + "\x69\xde\xcd\x88\x00\x1c\x20\x57" + "\xc7\xaf\x86\x9a\x51\x22\xe9\xdd" + "\xa8\xce\x35\xbd\x95\x38\x04\xe3" + "\x0d\x97\x55\x85\xe1\xc1\x08\x76" + "\x5e\x93\x35\x25\xa9\xdf\x67\x82" + "\x8b\xa3\x2e\x32\x57\x0a\xc6\xd4" + "\xb5\xf8\x4e\x80\x77\x79\xbf\xe0" +
+       "\xb5\xdb\x94\xc0\x68\xea\x33\x62" + "\x10\xd4\x68\xd9\x2e\x06\x7d\xb7" + "\x2d\x00\xb3\x58\xbc\x9b\x71\x3e" + "\x58\x9d\xc4\x3d\x3d\xdd\xe7\x68" + "\x58\x5e\x3a\x01\x40\x57\x82\x8d" + "\x1b\x3c\x9e\x3c\x47\x17\x31\x21" + "\xab\xb6\x99\x7c\xa7\xa2\xb0\x0c" + "\xf2\x88\xf8\xc2\xb3\xa3\x48\x5c" +
+       "\xca\xd4\x27\x29\xe1\x4b\x5c\x4c" + "\x8e\x84\x8f\x51\x16\x3f\xf2\xb0" + "\xcb\x7b\x75\x0c\x22\x89\xf7\x84" + "\x96\xeb\x5d\x32\xbb\x1c\xbd\x35" + "\x0a\xe1\x0d\x7d\xfb\x86\xb1\xbd" + "\x85\x96\x2c\xb2\xe3\x50\x73\xd0" + "\x41\xc6\x45\xef\x3e\x39\x95\x3f" + "\x44\x6d\x7b\xd0\xf1\x0f\x87\xb8" +
+       "\xf3\x24\x17\x99\x91\x3e\x91\xc7" + "\x86\xd6\xcb\x39\x9c\x79\xda\x5e" + "\x1e\xfc\xd4\x63\xc7\x95\xb5\xdd" + "\x54\xed\x4f\xac\x0b\xb8\x63\x6b" + "\x16\xb5\x5f\x7e\x69\xfc\xa0\x6e" + "\x64\xc9\xf1\xd0\xba\x08\x77\x73" + "\xa5\x2c\xa9\x11\x5f\x74\x28\x96" + "\x7a\x96\x86\x9a\x58\x79\xf3\x61" +
+       "\x9f\x65\xa2\x47\x65\x0a\xcf\x64" + "\xcb\x0b\x38\x33\x30\xf4\x18\x12" + "\x74\x8a\xd9\x0f\xe4\xe4\x1d\xfc" + "\xb8\xed\x9e\xf0\x8f\xec\xc4\xae" + "\x83\x60\xc5\x95\xe1\xb5\x6d\xde" + "\xa1\x16\xdc\x07\x56\xb0\x07\x33" + "\x97\x70\xd4\xc0\x86\xc1\x82\x14" + "\x66\x3a\x4c\x51\xac\x19\x83\xa0" +
+       "\xb3\xe6\x79\x09\x61\xfd\x20\x53" + "\x23\x07\xd4\x93\xe5\xd3\x0b\x1d" + "\xcc\xba\x80\xaa\xfc\x06\xc0\x0a" + "\x15\x25\x00\xd2\x0e\xc6\xd9\xb1" + "\x92\x0b\x78\xaf\xd0\x7e\x0e\x61" + "\x31\xce\xa9\x80\x6e\x44\xbf\xf5" + "\x4b\xb5\x20\x3c\x1d\x01\x1c\x44" + "\xc3\x96\x15\x19\xa1\x6d\xf7\x77" +
+       "\xb4\x94\x40\x4d\x2b\x5b\x2e\x97" + "\x5f\xde\x96\x5e\x4f\x95\x49\x4b" + "\x59\x0d\x87\x4f\x0a\xe4\xa8\x6c" + "\xef\x8d\xa6\x45\x6f\x88\xe2\x9e" + "\x13\x9a\x43\xc4\xec\x60\x02\xae" + "\x1f\xb7\xcf\xb4\x3e\xcd\xae\x45" + "\x20\x76\x32\x4e\xb6\xd9\xc5\x50" + "\xf3\x2c\x18\x86\xdb\xda\x0a\x47" +
+       "\x72\x50\x66\xaa\x2c\x9b\xf3\x9a" + "\xef\x24\xd3\xef\xa4\x2f\x32\x78" + "\x31\xbd\x27\xc3\x94\x33\x15\x3d" + "\xb0\xda\x29\x31\x71\xf2\xd5\x81" + "\xf5\x27\x80\xf4\x42\x0c\x2e\xc7" + "\x17\xe7\x36\x85\xbc\xcd\x40\xaa" + "\x0f\x9d\x36\x2d\x7a\x65\x5a\xf4" + "\xe6\x74\x7f\xea\xc4\xbf\x3b\xb0" +
+       "\xf0\x69\x7c\xf3\x89\x07\xb7\x4a" + "\x2d\x80\xc5\x01\x78\xd8\x26\x32" + "\x97\xf4\x0d\x36\x4c\x42\xe7\x4f" + "\x50\x0d\x89\x5f\xe5\xd4\xae\x9e" + "\xc6\x29\x37\xdd\x5c\x99\x8e\x20" + "\xf3\xea\x0d\xd0\x5c\xbd\x43\xf7" + "\x7d\x84\x61\xf1\x10\x13\x5a\xfe" + "\x25\x3f\x1a\x94\xa2\x75\xe7\x34" +
+       "\xea\x42\x6a\x9b\x42\xd5\x04\x7a" + "\xb9\x41\xaf\x3d\x85\x7e\x59\xfa" + "\x89\x0b\x6b\x72\x27\xec\x58\x4c" + "\xde\x43\x0d\x03\x6a\xb1\x8e\xed" + "\x57\xcf\x9d\xec\xe1\xe5\xe1\x65" + "\x81\xff\x7c\x69\xc1\x70\xa7\xb7" + "\x22\x2b\x6e\x9f\x8f\x91\x6d\x1e" + "\xb7\x82\x4e\xc6\x9a\x7a\x27\x7c" +
+       "\xcf\x35\x1f\x7b\xc8\x69\xc8\xe5" + "\x37\xd2\xd1\x55\x37\x69\xfa\x29" + "\x44\x9c\x57\xde\xee\x74\xc5\x05" + "\x0c\x59\x6d\x33\x2b\x91\xbb\x45" + "\xeb\x4d\x7d\x77\x85\x2d\x17\x5d" + "\x67\x65\x6c\x7b\xa9\xcc\x37\x1a" + "\x8a\x3a\x37\x25\x3a\x43\xa1\x1c" + "\x3a\x35\x77\x1c\xa8\x94\x3c\xd2" +
+       "\xed\x8d\x73\x0d\x18\xc4\xa8\x46" + "\x29\x57\xde\xe0\xb0\x5b\x1a\x6f" + "\x75\x16\xa8\x8b\xb9\x30\x02\xf1" + "\xd4\x33\x2b\x11\x0c\xf3\xc6\x32" + "\x62\xfb\xff\xd8\x9d\x12\x59\x75" + "\x05\xbf\x59\xb4\x47\x1b\x28\x6a" + "\x76\x67\x3b\xfa\x3a\xbd\xc1\x77" + "\x3a\x97\x29\x78\x80\xb3\x09\x07" +
+       "\x61\xa3\x35\xc9\x7c\x22\x89\x79" + "\x7e\x0a\x9a\xe3\xaa\xf8\x17\xfd" + "\xba\x63\x91\x26\x86\x5e\x5c\x2e" + "\xf4\xea\x63\xc6\x78\x8e\xc9\x07" + "\x6e\xa3\x2e\x42\x9a\x20\xe8\x64" + "\x82\x08\x6a\x4c\x91\xb3\xe8\x1b" + "\x5e\xa5\x4f\xec\x03\x45\xac\x4b" + "\xdf\x68\x78\xad\xca\xa7\xee\xba" +
+       "\x47\xcb\x36\xda\xc1\xe0\x75\x08" + "\xf0\x10\x02\x1e\xcb\xb7\xf5\xfd" + "\xc8\x87\x37\x3a\x4d\x7e\x0c\x7e" + "\x1f\x74\x1c\x2b\x26\xf5\x43\xf0" + "\x2d\xd7\x74\x6d\x00\x1b\xdf\x76" + "\xa9\x5b\xb4\x38\x73\xdf\x14\x05" + "\x7a\x79\x6b\x0a\x3e\x7c\xcf\xae" + "\x39\xac\xea\xdd\x85\xb2\x30\x5e" +
+       "\xdb\xe3\x69\xac\x9c\x33\x69\xff" + "\xbd\xd6\xe9\x59\x3c\xc8\xec\x74" + "\x82\x84\x0a\x82\x37\x7b\x23\x67" + "\x23\xfa\x2d\x07\x35\x30\x3a\x94" + "\xb8\xbd\x48\x8f\xd2\x10\x42\x6e" + "\xf4\xc7\xec\x2e\x16\x75\x51\x88" + "\x7f\x18\x2a\x63\xf4\xc5\x05\x0b" + "\x4c\x1d\x7d\xd9\x5e\xfb\xfd\xca" +
+       "\x05\x65\x32\xa3\x32\xb2\x26\x8c" + "\xbf\x41\x1d\xee\x72\x92\xd6\x38" + "\xfa\x2a\xe3\xff\x3e\x45\x59\x04" + "\x87\xea\xb3\x7c\xad\x43\x81\xce" + "\x66\xb6\x6a\x7e\xfa\xc1\x2e\x93" + "\x64\x62\x28\x22\x30\xd2\xd2\x6c" + "\xed\xf8\x36\x67\xfe\x46\x9a\x45" + "\xbb\x85\xca\x9e\x00\x0d\xbf\x50" +
+       "\xb4\xeb\xa2\x3d\xba\x6b\xc1\x06" + "\x3e\x7c\x55\x32\xbb\x21\x5b\xf3" + "\x11\x67\x07\x30\x12\x23\xb1\x95" + "\xf0\x11\x76\x1b\x76\xa0\x3a\x87" + "\x61\x6d\x3a\xea\x26\x90\xf6\x31" + "\x4c\xbe\xa6\x42\x6b\xb8\xc9\x7a" + "\x02\x28\x6c\x4b\xc7\xd7\xb5\xd3" + "\xe0\x1d\x28\xab\xac\x94\x48\xcd" +
+       "\xa5\x38\x52\x60\x7d\x8f\xc7\x15" + "\xab\x96\x84\x44\x42\x78\xd8\xe9" + "\xc1\xac\x10\xd2\xd0\x75\xcf\xcf" + "\xe2\x14\x8c\x5c\x29\xf2\x48\x29" + "\xcb\xf0\xda\xe8\x6d\xd7\x1f\xe8" + "\x00\xe8\x3b\xa0\xe4\x11\x2d\xd0" + "\x0c\xd3\x78\x87\x51\xf3\x4d\x0c" + "\xcb\x39\x51\x96\x96\xbc\x82\x34" +
+       "\x68\x1d\x81\x49\x01\xd7\xa0\xef" + "\x4e\xa0\xa1\x1e\xe5\xc8\xf6\xe4" + "\x40\x76\x23\x82\xfd\xe1\x90\x59" + "\x96\xdb\x80\x1d\xf9\x25\xa2\xef" + "\xda\xcc\x96\x3a\x95\x1c\x43\x17" + "\x92\xa1\x3f\xfc\xc1\xaa\x1b\x46" + "\xb4\x84\xc1\xbb\x07\xf4\xe2\x3b" + "\x9c\xd3\x05\x0d\x1d\xde\x76\xd7" +
+       "\xec\x21\x7a\x87\x52\x58\x82\x0b" + "\x94\x7a\x53\x0f\xa7\x14\x04\x30" + "\xa2\xa6\xa9\x21\x40\xba\x1c\x3f" + "\x00\x3c\x94\x76\xee\x4e\x82\x50" + "\x5d\xba\x3c\xf8\xec\xfc\xdb\xa0" + "\xc0\xf3\xb4\x93\x48\x81\x53\xf9" + "\xd7\x4d\xf2\x48\x62\x41\x74\x61" + "\xdd\x09\xfb\xe4\x4d\xd6\x22\x53" +
+       "\x05\xa7\x73\xdc\xd2\x9e\xb0\xf1" + "\x6e\x1a\xa1\x01\xc8\x00\x2b\x14" + "\xc9\x32\xa1\x98\xb0\x84\x64\x72" + "\x7a\x56\xe1\x26\x63\xef\xb5\xf3" + "\x03\xfc\x4b\x57\xd0\xd2\xbe\x43" + "\x2f\x72\x8f\x76\x38\x1e\x79\x74" + "\xd8\x7e\xe9\x4c\xb3\x9f\x18\x7a" + "\x43\x5f\x8a\x16\x96\x2c\x9b\x2b" +
+       "\xbc\x8b\x44\x8a\x27\xcf\xb6\x56" + "\xda\x51\x52\xc8\xdf\x98\xa8\x0c" + "\x24\x9b\xe7\x36\xd8\xca\x82\x90" + "\xa7\x51\x8e\x1a\xd3\x9e\x7b\x2e" + "\x02\xc8\xe1\x43\x8a\x31\x7d\xdc" + "\x9d\x68\xf8\xcb\x23\xe5\x50\x47" + "\x1a\x1b\x07\xf0\x72\xa0\x87\x98" + "\xc1\xfd\x4b\x81\x87\x0f\x09\x52" +
+       "\xb9\x6e\x73\x8d\x2e\x85\x21\x48" + "\x6b\x1e\x4c\x54\xd3\x28\xa9\x29" + "\x86\x05\x80\x77\xae\x11\xa4\x1a" + "\x93\x57\x0a\x1b\x7b\x06\x4d\xe9" + "\xad\x46\x5e\xa6\x4b\x8b\x9d\xb5" + "\x04\x18\x94\xcd\x87\xba\x62\x3c" + "\x1b\xe6\x20\x99\x78\x4b\xb5\xfd" + "\xac\x1a\x18\x0a\x84\xf2\x23\xe9" +
+       "\xf3\x25\x93\x3d\x84\x73\x44\x57" + "\x84\xcb\x71\xf3\xd0\xf2\xbe\xa9" + "\xc5\x36\x1e\xa6\x8b\x18\xd2\x77" + "\x72\xdf\x02\xc6\xd7\xa7\xd6\xbb" + "\x0b\xbc\x61\x8f\x02\xa9\x3a\xba" + "\xa1\xb6\xd0\x6e\xed\x85\x90\xf4" + "\x98\x82\x6e\xae\xd6\x25\xc6\x8b" + "\x1d\xc0\xe9\xa2\x1d\x0b\x2b\x83" +
+       "\xa0\xca\xd1\x70\x82\x5c\xb4\xc2" + "\x57\xb5\x4a\x72\xd0\x41\xce\x44" + "\xfd\x71\x82\x13\xac\x4b\x98\x57" + "\xc8\x08\x36\xcb\x34\xc9\xe0\x67" + "\x03\xf7\x55\x54\x45\xfa\x88\xc8" + "\xb0\x02\x7b\x72\xb4\xb8\xc5\xe9" + "\xa4\x30\x71\x7c\xf0\xf0\x3e\xdc" + "\x0c\x27\x09\x4b\xa3\xbe\xe4\xd9" +
+       "\x6e\xbc\x96\x61\x19\xf2\xeb\x5b" + "\xfd\x7e\x09\xef\x6b\x73\x66\x0e" + "\x3a\x29\x87\xea\xb8\xf3\x28\x11" + "\xde\xfc\xdd\x6a\x05\xe4\x98\x29" + "\x61\xc9\x16\x5d\xb8\x31\xcc\x55" + "\x56\xf0\x18\x24\xe1\x34\xa4\x87" + "\x19\xe8\x9f\xdc\xcc\xaa\x94\x2e" + "\xc6\x90\x64\xa5\xc1\x86\xa4\x94" +
+       "\xb3\x2b\x8d\xcb\xd4\x83\x4d\x8a" + "\xfd\xb1\xd2\xff\xa8\x6a\x79\xea" + "\xf6\x79\xca\x04\x51\xab\x75\x65" + "\xcf\x86\x6b\xc4\x36\xd5\xf0\xf4" + "\x58\x6b\x0e\x67\xd9\xc5\x1e\x46" + "\x08\xd1\xae\x0e\xf8\x53\x50\x70" + "\xf7\x16\xdd\x14\xce\x5b\xf4\xda" + "\x65\xcf\xb2\xc4\x49\x2d\x6f\x40" +
+       "\xd1\xce\xf0\xf1\x47\xc4\x37\xa3" + "\x2b\xdd\x92\x94\x93\xc7\x0c\x80" + "\xfa\x8e\xa0\xbe\x1d\x15\x93\x4b" + "\x1e\x74\x0a\xde\xf8\xf3\x0c\x82" + "\x13\x7d\x0f\x1c\xdc\x82\x19\xff" + "\xca\xe6\xdd\x84\x60\x19\x92\xef" + "\xe3\x6e\xf9\x45\x72\xd9\xd7\x1a" + "\xc7\xa0\xde\x29\xbe\x8d\x9c\x31" +
+       "\xf8\xf5\x2e\xe8\x80\xdc\x1c\x6d" + "\xb3\x7f\x1c\x2f\xf0\xf9\x5d\x09" + "\x88\xd8\xcf\xa3\xb9\x34\x7f\xc8" + "\xe1\x08\x02\x34\x95\x70\xd7\xd5" + "\xcb\x51\x88\x91\xe4\xec\x1a\x4a" + "\x42\x71\x2b\x60\xc1\xf5\xb1\xd7" + "\x82\x4f\x52\xc6\x13\x98\xd3\xf0" + "\xb5\x1d\xb0\x6b\xae\x6e\xd9\xf6" +
+       "\xc8\x9e\x25\xde\x5b\x38\xf2\x1f" + "\x0d\x7b\xf6\x30\x6a\x83\xb0\xf6" + "\xff\x1c\x66\x06\xb0\x65\xcc\x04" + "\x5c\x0f\x23\xd4\x58\x63\x7e\x46" + "\xd3\xd3\xbe\x2d\x80\x8c\x46\xce" + "\xa6\x0d\x92\xf1\x62\x42\x98\x7b" + "\x9f\x47\x37\x15\x42\x57\xd2\x34" + "\xe1\x8d\xbb\x87\x8c\xa8\x8a\x5c" +
+       "\x6a\xa5\xaf\x54\xa1\x68\xf7\x32" + "\xe5\x84\xf1\xfa\xa3\xec\x1e\xa5" + "\x68\x74\x8c\x61\x44\xcb\xce\x20" + "\xc0\x2c\x86\x87\x5f\xd1\x34\x34" + "\xf6\x5d\xf5\xae\x11\x38\x3c\x71" + "\xf0\xf8\xe3\x81\x49\xc0\xd7\x2c" + "\xbe\x99\x2f\xff\x39\xd4\x68\xee" + "\xa6\xa6\x5d\x2b\xe7\x4e\xb6\x79" +
+       "\x9b\xb9\x82\x7b\x71\x38\xea\xd3" + "\x24\xb6\x0e\x47\x4d\x2d\x92\x75" + "\x66\xd4\x95\x3b\x54\xec\x66\x8f" + "\x46\xe3\xe1\xbe\xcc\x73\xe6\x66" + "\x9a\xb8\xf2\xb5\xc4\x67\xfe\x6a" + "\xd3\x5c\x0e\x29\xe6\xc1\xe9\x3d" + "\xda\x2a\x0a\x31\xb6\x8b\x27\x8c" + "\x3b\x32\xdb\x0b\x84\xa3\x0f\x42" +
+
+       "\x9b\xc4\x24\x64\x79\x96\x6f\x64" + "\xc9\x41\xc2\x67\xe8\xdf\x88\xf8" + "\x49\x8b\xf6\x24\x93\x4b\x2d\xe1" + "\x20\xdf\x71\xa5\xd8\x62\x6b\x9a" + "\xcb\x83\x94\x17\x6d\xb2\xb4\x81" + "\xe2\xfa\x11\x95\x32\x96\x6f\x66" + "\x1f\xa5\x3a\xd5\xe4\xb3\x81\xd2" + "\x16\xbd\x3d\x7f\x65\xa7\x96\x7f" +
+       "\x2b\xf6\x1a\x05\x7c\xd3\x53\x85" + "\x96\x44\xf9\x0b\xeb\x98\xa9\xe9" + "\xa1\x9a\xd5\xb0\x9f\x4f\x84\xe0" + "\x13\xb8\xaf\xe6\x58\xd5\x3f\x98" + "\x04\x98\xd6\x65\xca\xc0\x70\x96" + "\x2d\xff\xa5\x6e\xde\x22\x2b\x73" + "\x3b\x62\xd8\x5f\xa9\x0b\x64\xd7" + "\x82\x17\x35\xa6\x63\x91\x61\x9f" +
+       "\x4f\xdd\xef\xbd\xe0\xb4\x67\xf1" + "\x01\xe4\x66\xf3\x65\x84\x95\x69" + "\xc0\xbe\x3b\xa7\xab\x68\xa3\x5a" + "\x21\x0c\x24\x7b\x09\x87\x14\x12" + "\x06\x90\x96\x18\x33\x32\x8c\x37" + "\xd1\x53\xfe\xe1\xce\x73\x4d\xcb" + "\x61\x43\x0c\x13\x0e\xa8\x50\x5f" + "\x2b\x21\xf5\x7e\x51\x59\x7f\xd6" +
+       "\xc0\x38\xad\x8c\x08\x81\x2f\x33" + "\xe2\x8a\xd6\x6b\x90\x7e\x1b\x47" + "\xa3\x27\x8e\x0d\xb2\x3f\xac\x56" + "\x0d\x4b\x6b\x13\xdb\x60\x46\xb5" + "\xe4\x8d\xfd\xa6\x11\x1e\x3a\x12" + "\xef\x99\x77\xa3\xea\xff\xdb\x44" + "\x7c\xc1\x6a\xce\x77\xb9\x40\x45" + "\xef\xac\x60\xaf\xa8\x73\x51\x49" +
+       "\xb0\xea\x73\x45\x43\x37\x44\xeb" + "\x31\x60\xac\xd1\xfb\x0d\x57\x11" + "\xfd\x9a\xdd\x44\x5b\xb4\xd9\xf7" + "\x31\x72\x06\x22\xdd\x6a\x06\xb8" + "\xb4\xf0\xa3\xf8\xd8\x2a\xf9\x15" + "\xa2\xe2\xac\xe0\x99\x48\x0e\x9e" + "\x80\x8b\xb3\xfa\xad\x0a\xcd\xbd" + "\x52\x00\x02\x17\xe9\x6a\x50\x46" +
+       "\x9d\x39\xca\x8f\xf7\x69\x9a\x42" + "\x63\xbb\x07\x02\xd2\x27\x9e\xfe" + "\x82\xf5\x88\x87\xd6\x5e\x65\xec" + "\x6e\x5f\xb7\xad\x48\xd7\x26\xa4" + "\x6d\xc6\x81\xca\x02\x5c\x69\x18" + "\x25\xd4\x31\xa5\x27\x8d\xfb\x84" + "\xba\x48\xff\xde\x56\x89\x3a\x3a" + "\x47\x22\x6d\x76\x56\x0d\x1d\xaf" +
+       "\x5c\x4b\x2c\x35\x65\x95\x05\x5a" + "\xe2\xc3\x0b\x59\x31\x15\x26\x49" + "\x5f\x9f\x6f\xf6\x21\x75\x9f\x80" + "\x9b\x4a\x0a\xc7\xbf\xf6\xae\x2b" + "\x61\x35\xed\x09\x65\xfa\xe6\xe7" + "\x0c\x23\x4b\x98\x33\x02\x37\x11" + "\x69\xdc\x4c\xd0\x9b\x65\x51\x21" + "\x16\xd4\x07\xf0\x63\x3c\xb8\xbd" +
+       "\x82\x2a\x1c\x39\x4d\x28\xbb\x9e" + "\xe8\x08\x83\x15\x63\x48\xdd\xbc" + "\xca\xed\xf1\x83\xec\x16\x6f\x00" + "\xc8\xc6\x5d\x69\x37\x2c\x3e\xa1" + "\x87\x7a\x05\x4a\xf0\x56\xb7\x2a" + "\x98\x8f\xb4\xa6\x00\x55\x76\xa8" + "\x44\x1c\x65\x68\xce\xfa\x52\x42" + "\x02\x5e\x76\xe1\x0b\x54\x2b\xa5" +
+       "\xf0\x7f\xa3\x5c\xa8\xa1\x35\xcb" + "\x8f\x1c\x2f\xcd\x1c\x4f\xa0\xe1" + "\x12\x61\xa2\x15\xce\x16\x88\x23" + "\x7e\x17\x5b\x09\x11\xa1\x06\xe2" + "\x49\x41\x42\x8a\x04\xb6\x10\x3c" + "\xfb\x2c\x75\x74\x67\xf5\xa3\xc6" + "\xb8\xdb\xf1\x47\x7a\xa3\x16\xbf" + "\xfb\x3d\x1a\xd3\x9a\x2f\x37\x7c" +
+       "\x2a\x4d\x0b\xc2\xb5\x05\x2d\x12" + "\x67\x2a\x66\x0c\xf5\x9c\x65\xff" + "\xe9\xc9\xff\xe8\x28\xc1\x57\xed" + "\x83\x76\x98\x9e\x85\x15\xbb\x0f" + "\x2b\x9a\x31\x47\xf2\x0d\xd7\xad" + "\x70\xe4\x4b\x37\xba\xba\x98\x4b" + "\x07\xb3\xa7\x56\x73\x74\x3d\xf0" + "\x30\xbf\xfe\x3e\x6e\x69\x2e\x34" +
+       "\x37\xc5\x4a\x86\xf7\x48\x4b\xf8" + "\x3d\x0d\x94\xa6\x09\x34\x71\x04" + "\xae\xc7\x74\x61\x2d\xb2\x4d\x01" + "\x34\x30\x21\x8c\x43\x1c\x3a\xc7" + "\xec\x93\xdd\xff\xa5\x4e\xac\x18" + "\x3e\x78\x02\x61\x57\xc7\x4f\x72" + "\x3f\xe8\xc3\x91\xcc\x3f\xe1\x9f" + "\xf5\x0b\x8f\xf0\xc8\xc2\xa8\x92" +
+       "\xde\xf6\x67\x8f\xfd\x22\x2e\x7f" + "\x77\x31\x69\xd8\x33\x88\x01\xab" + "\x95\xca\x3e\x86\xb6\x1d\x6d\x26" + "\x2b\xef\xb5\x31\x2b\x73\xb7\x6b" + "\xce\x80\x5f\x91\xc6\x27\xa9\x4f" + "\xd8\xef\x90\x5f\xd2\xd6\xa1\x6f" + "\xad\x48\x6b\x45\xe8\x5d\xd7\x7b" + "\x29\x64\x5b\x84\x7a\x50\xcb\xd2" +
+       "\xec\xd7\x55\xe2\x2a\xf8\x2c\xa7" + "\x04\xe2\x60\xa4\x23\x5c\x02\x52" + "\x44\x0a\x5b\x7d\x2d\x54\xae\x10" + "\xda\xae\x05\x93\x10\x43\x51\xa8" + "\xe8\xbf\x4b\xa1\xf5\x15\x83\x95" + "\xfe\x65\x53\x38\x26\x18\x36\x3f" + "\x40\x50\xd9\x66\x6b\xa3\xb3\xc2" + "\xa2\xed\xf4\x7c\x34\xb3\xc7\x12" +
+       "\x9d\x11\x44\xe7\xd1\xb4\x45\xa5" + "\xe7\x71\x9a\x82\x69\xb1\x93\x4c" + "\xbf\xfc\x17\x61\x8c\x90\xbb\x2d" + "\x85\x3d\x5a\xb3\x20\x73\xc9\x4d" + "\x05\x81\xf8\x6b\x85\x4f\xc0\x94" + "\x1f\xbc\x51\x1b\xce\x1b\x2e\x45" + "\xf3\x3a\x01\xb3\x50\xff\x41\x0c" + "\x24\x7e\x4d\x22\x45\xf4\x7a\xf0" +
+       "\x6a\x4f\xd2\xa3\x7c\xe5\xb9\xbd" + "\x63\xa7\x45\xf3\xd7\x46\x82\x8a" + "\x5f\xbb\xcf\x98\x6d\x2a\xbd\x73" + "\xdb\x04\xed\x86\x5e\xe8\xd8\x1d" + "\x0b\x42\x1f\xc0\x42\xda\xf2\x76" + "\xc7\x7b\x40\x64\x73\x54\xf0\x7e" + "\xf5\x48\xf5\xaf\x7f\xba\x98\x7e" + "\x4a\xb6\x30\xfd\xee\xfb\x7a\x6b" +
+       "\xbb\xd2\xa0\x16\xc5\x2f\x92\x4f" + "\x99\x34\x62\x1a\x6c\xc1\x5c\x0d" + "\x8b\x2c\xc6\x57\x3a\xcf\x41\x92" + "\x7f\x66\x1b\xfd\x61\x69\x5e\x2f" + "\x97\x17\xa0\xf5\x0b\xc7\x15\x5c" + "\x92\x61\x95\x60\x4d\xb4\x20\x3d" + "\x52\xdb\x1f\x07\x37\x1b\x91\x04" + "\x7b\x0f\x6f\x8d\x16\xf9\x48\xf6" +
+       "\xf8\x72\x25\xeb\xea\x39\x76\x06" + "\xce\x53\x08\xd7\x32\xf6\xce\xb0" + "\x04\x90\x98\xe9\x31\x1f\x7f\xd8" + "\xc0\x82\x65\xa2\x36\x72\xaa\x94" + "\x56\xc6\xc2\xb0\xe5\xb8\x11\x42" + "\x4e\x41\x57\xa2\x9b\xa7\xaa\x05" + "\xb0\x9a\xf0\xe0\x41\xf8\x72\x06" + "\x65\x1c\xc8\x3e\xbf\xf9\xc5\xa3" +
+       "\xfa\xf0\x03\xe0\x9a\x37\xf6\x4c" + "\xb0\xc8\x75\x1e\x87\xe0\x17\x79" + "\x9f\x3c\x38\xa1\xfc\x59\xc0\x1d" + "\x67\x09\x48\x64\xa6\x4e\x61\xa8" + "\xd1\x5d\x62\x79\x01\x0d\x4d\xc3" + "\x88\xe7\x00\x42\xe1\xa1\x47\x7d" + "\x9d\xa5\x54\xa7\x1e\x9d\xf9\xae" + "\x78\x41\xb1\x49\x00\x2d\x81\x1c" +
+       "\xa7\xb3\x77\x08\xb6\x1b\xa1\xa4" + "\xa9\x21\xd5\x2c\xa6\x11\x4d\x24" + "\x2c\xc6\xf5\xbf\xb7\x19\x4b\x46" + "\x7c\x65\x76\x90\xa7\xeb\xf3\x27" + "\xa9\x81\x75\x0c\x97\xbf\x3a\x48" + "\xf3\x22\x0b\xae\xe0\x08\xf1\x2e" + "\xd5\xbc\x64\x50\x66\xf3\x03\xd6" + "\x5e\x02\xf5\x5b\xa7\x75\x48\xcf" +
+       "\x2c\xd2\xd5\xd0\xe5\x02\x93\xab" + "\x30\x40\x12\x30\xb0\xe6\xa7\xd0" + "\xf4\xa1\x0a\x4f\x7b\xc5\x62\xe2" + "\x2e\x20\xba\x0b\xa5\x58\x7a\x49" + "\xac\xcc\xcf\xe6\x1e\xd2\x9f\x10" + "\xec\x27\x19\x8a\xe6\xcc\x96\xb5" + "\x5a\xe8\x02\x3b\xe8\xf7\xb9\x48" + "\x34\x11\x59\x08\x3c\xf8\x7e\xbf" +
+       "\x62\xc5\xed\x62\xb1\x91\x5e\xe0" + "\x85\xd1\xbc\x62\x72\xfe\xe1\xb5" + "\x19\x5b\x10\xb8\x08\x69\x52\x1d" + "\x22\xbb\x6b\x89\x7e\x44\x11\x0d" + "\xf0\x13\x22\x2c\x49\xaa\x7a\x64" + "\x4b\xc1\x2f\x2e\xc6\xf8\xc9\xf6" + "\xc6\x68\x41\xbc\x9a\x25\xca\x90" + "\x61\x34\x8e\xdd\x62\x27\xb9\x3b" +
+       "\x9a\x18\x20\x5b\x94\xc0\x7f\x15" + "\xab\xc8\xf5\x0b\x2d\xc6\x72\x6e" + "\xb7\x50\x77\x35\xe1\x89\xf4\xf7" + "\xc5\x31\x7d\xf8\xb2\x1a\x51\x18" + "\xc5\x35\x5f\x00\x27\x78\x26\xa4" + "\x6d\xed\x80\x94\x54\xa0\x8c\xa2" + "\xb2\x7d\x24\x77\x7c\xde\xef\x20" + "\x60\x9d\x14\xa4\x39\x04\x16\x5e" +
+       "\x70\xae\xde\xf3\x48\xb1\x10\x5c" + "\x33\xc4\xab\x6e\x53\x4b\x04\x02" + "\x8e\xf1\x63\xfe\x0c\x79\x82\x1e" + "\xf1\x5f\x69\xaa\x5a\xb6\x86\x28" + "\xed\xa4\x27\x46\x93\xdf\x4f\x99" + "\xb9\xb0\x2e\x87\xc0\xde\xb4\xe9" + "\x8f\xa2\xf7\x58\x8d\xec\x0b\x4c" + "\xfe\xc5\xf9\xea\xed\x4d\x0c\xc3" +
+       "\xf7\x7c\x0b\xe6\xaf\xac\xc1\x6d" + "\x69\xd8\xa9\x84\x50\x0a\x86\x25" + "\xc4\x8a\xba\xe7\x09\x6f\xfc\x56" + "\x9e\xd2\x48\x61\xd0\x5b\x8c\x82" + "\x5f\xae\x55\xdc\x5e\x43\x6b\xac" + "\x11\x74\x11\xc0\x6c\xf5\x27\xa5" + "\x2c\x34\x24\xfd\x5e\x04\xd5\x94" + "\x0d\x7c\xb6\x70\x35\x0a\x4c\x2c" +
+       "\xcd\x79\x55\xb6\x38\x35\xf6\x69" + "\xa1\x33\xf9\xad\x5c\x60\x70\xd0" + "\x6c\x9f\xbe\x83\x05\x87\x7e\x01" + "\xa1\xb8\x47\xb2\xaa\x2f\x44\xe9" + "\x68\x3d\x0d\x54\x9e\xff\xee\x54" + "\x19\xbe\xe3\xca\xab\xde\x3e\x1f" + "\x1b\x31\x35\x70\xb0\x28\xc5\x95" + "\xa7\xc0\xbc\x96\xb7\x3a\x5d\xb3" +
+       "\xb5\x98\xd3\x5e\xfa\x3c\xca\x9b" + "\xd7\xdd\x53\x13\x65\xb4\x60\x6a" + "\xd1\x51\x1c\x1a\xbb\x17\x5c\x90" + "\x1b\xf9\x5c\x7f\x81\x04\xa3\x27" + "\x0a\xbf\xd6\x9e\xf3\x0c\x66\xc4" + "\x56\x1d\x9e\xf7\xb1\x3f\xb0\xb0" + "\x54\x13\x00\x36\xf1\x3b\xa1\xe3" + "\x2a\x2b\x2b\x1f\x54\x50\x72\x9a" +
+       "\x6d\xe1\x06\x21\x05\x7d\x89\xb4" + "\x8c\x7f\xa0\x50\x9b\xdf\xbb\x85" + "\xd7\xff\x49\x6c\x3d\x2a\x63\x42" + "\xb8\x20\x07\x60\x7c\x5e\x88\xb7" + "\xac\x94\xb6\xde\xdc\x7f\xa4\x6f" + "\x79\xd1\xe0\x8a\xf5\x14\x46\x38" + "\xb3\x4a\x12\xbd\x29\xba\xfc\x78" + "\xea\x12\x8f\x74\x9e\x3d\x11\xbb" +
+       "\x18\x30\xcd\xa7\x99\xef\x23\x3c" + "\x8f\xfd\xde\x83\x06\xc5\x3f\x2c" + "\x9b\x49\x88\x2b\xff\x45\x7a\xf9" + "\x6a\x7f\x6e\x34\x21\x32\xaa\xae" + "\x30\x27\xf3\x50\x84\x34\x47\xe7" + "\x41\xca\xd6\x0f\xbb\xb8\xc0\xc2" + "\x14\xc1\x17\xaf\x79\x20\x88\xa9" + "\x04\x72\xde\x1b\xa6\xf7\x35\x06" +
+       "\xfe\x93\x84\xf3\xd0\x13\xb0\xc3" + "\x18\xf7\xba\x07\x96\xae\x2c\xa3" + "\xba\xb3\x95\x20\xc2\xa6\x1d\x37" + "\x9e\x90\x41\xb0\xbd\x0a\x1c\x03" + "\x60\x9e\x1a\x43\xbe\x6d\xcc\x11" + "\x6e\x8f\xf3\x5b\x76\x94\x91\x7e" + "\x33\x4a\x2a\x46\x76\xf0\x47\xbe" + "\x30\xb8\x41\x30\xdf\xc9\xb3\x33" +
+       "\x85\xbd\x63\x7b\x4e\x4d\xd7\xa7" + "\xa6\x3d\xe2\x43\x55\xc6\x36\xea" + "\x29\x96\xa7\xe5\x7f\x7d\x7b\xcd" + "\x1d\xc0\xca\x13\x47\xf7\xb1\x1f" + "\xd3\xde\x28\x90\x45\xe1\x0f\xaa" + "\x97\x20\x57\x19\x3b\xca\x23\xb1" + "\x77\x86\x83\x74\x6d\x74\xa8\x21" + "\xc6\xcc\xab\x63\xcb\x7a\xfc\x1c" +
+       "\x70\x3d\x05\xe5\x02\x33\x65\x02" + "\xc9\xbf\xc6\xb8\x5b\xe3\x33\x3c" + "\xe9\x1e\x02\x9a\x40\x4b\x2c\xa7" + "\xe4\x27\x65\x3f\x0d\x80\x1b\xe1" + "\xb5\x37\xdc\xb6\x4a\xd4\xc1\x8f" + "\x74\xe4\x80\xf5\xb5\x06\x86\x5d" + "\xfa\xb0\xb5\x87\x4a\x75\x25\xdf" + "\x5e\x2a\x69\xbb\xe8\x0c\xf5\xba" +
+       "\x9a\x1d\xc6\xfa\xb8\xc8\x7c\x02" + "\x8a\xfe\xc6\xe3\x62\xe0\x25\x7d" + "\x03\xf5\xbf\xe5\xbf\x05\x88\xe0" + "\xf7\x32\xf6\x6f\x6c\x1e\x27\x13" + "\xa5\x76\x2f\x23\xc0\xa6\xdc\x55" + "\x26\xf4\x1e\x70\x2d\xc3\x57\x89" + "\x78\x51\x0a\xa1\xcb\x8b\x72\xee" + "\x73\x51\x2c\xb6\x11\x04\xa6\x5e" +
+
+       "\x50\xbc\xd8\xb4\x2b\x46\xd5\x9a" + "\x70\x57\x19\xa9\x16\x0b\x1c\x18" + "\x68\x2a\x41\x78\x1c\xfe\xd4\xeb" + "\x8c\xf4\xdf\xc0\xbc\x41\x03\xae" + "\x66\xe8\x03\x70\xcf\x45\xbc\xb6" + "\x1b\xa4\x24\x8a\xea\x6d\x1a\xf1" + "\xc2\x24\x4c\xd0\x1a\x15\x07\x54" + "\x68\x7b\x5b\xda\x7d\xd2\xc9\x62" +
+       "\xf6\x8b\x3b\x52\x2e\xb1\x50\x0a" + "\x1b\x0c\x91\x8f\x5b\xeb\x09\x80" + "\x88\x75\x16\x4a\x82\xaf\x35\xf5" + "\xbd\x2a\x2a\xfb\x9c\x5f\x83\x0f" + "\x62\xeb\xfc\x2a\x31\x29\x9b\xf5" + "\x3f\x38\x9d\x16\x2a\xdf\x97\xc7" + "\xb0\x02\xac\x66\xb0\x5f\x3f\xeb" + "\xca\xd0\xa2\xda\x6f\x4c\x9d\x02" +
+       "\x42\xe5\x7c\x2b\x05\x26\x22\xb8" + "\xe1\xbd\x72\x74\x99\xce\xd4\xe6" + "\xda\xf4\xd2\x09\xbe\x6e\xe1\x53" + "\x2e\x2b\xb9\x53\x2e\xf4\x0f\x18" + "\xc6\xa1\x34\x2c\x02\xcc\x9b\xc5" + "\xc2\x46\x2c\x42\xf9\xd6\x03\x38" + "\xa2\xa8\x14\x5c\x4f\xf7\xaf\x18" + "\x28\x8b\xa0\x10\x80\xbf\xae\x55" +
+       "\xbc\x43\xb3\xf5\x10\x20\xaf\x58" + "\xfe\x42\xf1\xf2\x0a\x40\x2e\x0f" + "\xdf\x4b\x5f\xa8\xde\xbf\x83\x34" + "\xa9\xea\xbf\x03\x93\xd0\xb1\xf0" + "\x03\x16\x08\xc7\x95\x1b\xa0\x2e" + "\x97\x10\xba\x3d\xc9\xe4\x43\xe9" + "\xa6\xf3\x38\xb4\xad\x92\xbe\x47" + "\x36\x66\xbf\xe5\x42\x77\xbb\x00" +
+       "\x61\x2a\xdf\x86\xb4\x4f\x7a\x13" + "\xa2\xb4\xf7\xec\x07\x9c\xed\xa1" + "\xff\x42\xd0\x7b\xe2\x60\xe4\xb2" + "\xec\xf5\x62\x5f\xfa\xe2\xf5\xb7" + "\xb7\x23\x24\xcc\x6b\xec\xa6\x7a" + "\xa7\xee\x63\xba\x7f\x0a\xce\x75" + "\xe1\xa6\x50\xf2\xb1\x5f\xa4\x67" + "\x9f\xdc\x3c\xe5\x9c\x91\xbc\x93" +
+       "\x45\x33\xce\xdd\xaa\xcc\x2f\xec" + "\x50\x43\x2a\x01\xb7\x11\x68\x2a" + "\xdc\x8b\x59\xac\xf1\x0f\x76\x96" + "\x28\x41\xbf\xd1\x2a\x65\x4d\x05" + "\x05\x10\xa2\x92\xd4\x51\x11\x0a" + "\xdf\x0f\x11\x33\x71\x39\x7f\xad" + "\x0f\x10\x60\x19\x8c\x92\x95\x8c" + "\x62\x33\xf0\x7b\x25\xc8\x91\x6c" +
+       "\xec\x1d\x3f\xec\x5d\x12\xe6\x19" + "\xda\x78\x11\x91\x40\xf0\xb1\x07" + "\x38\x67\x4a\x90\xda\xde\x3e\xd9" + "\xcd\xed\xeb\x0b\x5a\x7a\x18\x55" + "\x41\x9d\x32\xeb\x22\x47\xd0\xf7" + "\x91\xb3\x70\xf1\x9e\x09\x49\xf4" + "\x28\xf8\x99\xca\x69\x7a\x31\xfd" + "\x6d\x97\xa4\x34\x2b\xdb\xc3\x50" +
+       "\x78\x71\xfe\x7b\x1b\x48\x74\xb6" + "\x68\x58\x40\x65\xae\xeb\x1d\x4e" + "\x7d\x86\x8c\xc4\x21\x28\x1b\x06" + "\xea\x30\x3b\x51\x35\x5b\xc1\x69" + "\x88\x10\x87\x36\x66\x16\x4a\x3b" + "\xff\xb1\x20\x12\x5d\x9f\xe2\xe5" + "\x4d\x9f\x3d\x23\x35\xbb\x82\x4b" + "\x75\xc6\xcd\x18\x33\x63\x07\x4e" +
+       "\x73\x44\x56\xcb\xdf\xe8\xd2\x78" + "\x1a\x62\xd5\x57\x73\xa9\x49\x43" + "\x24\x8b\x8f\x21\x89\x5d\x83\x9d" + "\xe2\x6e\x9b\x07\xc5\x7b\xfe\x01" + "\xce\x5d\x3b\x5b\x2b\x2a\x7f\xe5" + "\x65\x55\xe5\x5f\xb7\x37\x86\x5a" + "\xe7\xba\x1d\xa4\xae\x34\xff\x83" + "\x8f\x7a\x0a\x95\x9c\x19\xe1\xfc" +
+       "\x06\x77\x70\x3e\x1f\x54\x4f\x37" + "\xcf\xd0\x31\xa8\x38\x36\x4d\x9a" + "\x04\xca\x18\x15\x83\xf4\xb4\x4a" + "\x18\xc3\x38\xfe\x5d\xee\xe3\x54" + "\x9b\x81\xc8\x03\x64\xe3\x3a\x38" + "\x4c\x86\x17\x2e\xa1\xda\xd1\xa9" + "\x5b\xaa\xee\x50\xb3\x97\x5a\x24" + "\x83\x4e\xbf\x99\x09\xd0\x62\x53" +
+       "\x80\x39\xd4\x9b\xc2\x13\x03\xfc" + "\x29\xdb\x72\xf1\x70\x4b\x95\x9c" + "\x1a\xa2\x54\xf9\xb7\xdc\x9b\x67" + "\xfc\xe4\xe2\x54\x09\x17\x48\x6b" + "\xd0\xf1\xba\x30\xf5\xf5\x8a\x31" + "\x60\x20\xf9\xcb\x3c\x8a\xea\x26" + "\x58\xe2\x5a\xcd\x7c\x9d\xc6\xc3" + "\xc9\x07\xad\x0e\x47\xa0\x3b\xa7" +
+       "\x69\x5e\x81\x31\x97\xc3\x63\x3a" + "\x02\x28\xdd\xdc\xd6\xcb\xf9\x6d" + "\xaf\xf6\xb4\x15\x4a\xed\x47\x4c" + "\x78\xf9\xc0\x6a\x82\x9d\x00\x62" + "\xc7\x8f\x89\x8b\xd2\x80\x4d\x66" + "\x1f\xc9\x17\x2c\xda\xee\xf1\x72" + "\x09\x66\xae\x7a\xbc\xd3\x84\x9e" + "\x95\x68\x37\x28\x95\xc1\xc7\x58" +
+       "\x07\x4f\x29\xd9\x30\x76\xff\xdc" + "\xd0\x8f\xba\x8d\xd6\x65\xb7\x89" + "\xcd\xac\xbc\x8d\xde\x55\x3e\x55" + "\xf8\x2b\x70\xed\x9e\x00\x4a\x9b" + "\x0d\xca\xb8\x27\xdd\x34\xe5\xf6" + "\x52\xfd\x77\x61\x34\x6b\x49\xc4" + "\xb7\xb7\x7b\xc8\xf6\xe6\x8c\x37" + "\xf0\x19\xcc\x44\x48\x3d\x63\x68" +
+       "\x63\x20\x42\x5e\x91\xb9\xde\x73" + "\xc0\x1b\x75\x4a\x27\x64\xd2\x7a" + "\x4f\x34\x14\x44\x22\xe2\xdc\xe6" + "\x28\x1f\x81\x85\xf7\xef\x01\xad" + "\x2b\xb7\x68\xba\x90\x65\x48\x25" + "\xaf\x35\x36\x20\x4a\x26\x93\xdb" + "\x0a\x66\x22\x28\x8a\x1f\xb0\x1e" + "\x64\x8c\x59\xee\xe8\xce\x2d\xae" +
+       "\x74\x78\xc1\x7d\xb6\xe7\x59\x35" + "\x2a\xcc\x95\x81\xef\xf0\xca\xd0" + "\xd9\x4d\xd2\x0c\x88\x67\xc0\x07" + "\x41\x7c\x85\x02\xa0\x9e\xa9\x01" + "\x63\x2f\xf8\x90\xe4\x79\x65\xd8" + "\x37\x92\x1c\xe4\x8a\x65\xe0\xb1" + "\x79\x1e\xfd\x93\xfd\xfa\x5f\x07" + "\x8f\x0b\xf6\x47\x35\x40\x70\x6e" +
+       "\xed\xfc\xe6\xa3\xc7\xf5\x53\x0d" + "\xeb\xbd\x5f\xf4\xd5\xbd\xcb\xe8" + "\x70\x9a\x33\x13\xdf\x01\x5c\xf8" + "\x81\xeb\x2c\x14\x80\x18\xf7\x0f" + "\x7a\x43\x70\xbd\x74\x87\x4e\x4c" + "\x6a\xda\x0b\xba\x91\x28\xb3\x5f" + "\x6e\xd2\x8b\xf1\xd2\xeb\xdb\x1c" + "\x22\xd5\xa9\x03\xf1\x26\x95\x2f" +
+       "\xa6\xb0\x51\xbe\xda\x86\x51\x76" + "\x88\x90\xce\x73\xf4\xe9\x76\x53" + "\x5a\xd8\x5b\x5b\x0b\x80\xed\xe3" + "\x04\xe6\xc1\x4d\x52\x95\x28\x24" + "\x5e\xd3\x27\xef\x47\xcc\x6d\xe7" + "\x7d\xa6\x00\x90\xd6\xee\x96\x43" + "\xc1\x92\xde\x84\xa0\x3b\xb3\x73" + "\xfe\x01\x76\x37\xae\x53\x64\x22" +
+       "\xc2\xe9\xf7\xc1\x75\x60\xfc\xec" + "\x34\xec\x5a\xbe\x20\x76\x21\x6a" + "\xa8\x3b\xa3\x9e\x54\xd0\x81\x37" + "\xd4\x85\x6b\xd8\xab\x35\xef\x84" + "\x83\xee\x1f\x46\x3c\xa3\x4a\x91" + "\x6c\x7d\x5f\xb2\xc9\xe5\x11\xf3" + "\x5c\x49\x3d\xc3\xaa\x0d\x11\xc6" + "\xb9\x54\x85\x81\x83\xe5\x7e\x8a" +
+       "\x0e\xec\xf4\xa7\x2a\x73\x12\x36" + "\x8f\x34\x71\x9d\xd0\x88\x3e\xee" + "\xdb\xcf\x99\x75\xe4\x07\xa1\xb7" + "\xc6\x51\x1b\x61\xe8\xe7\x5d\x1f" + "\xaa\xaa\x51\x10\x59\x1d\xa1\xd6" + "\x86\xc3\xf0\x55\xf0\x31\xe5\x3d" + "\x66\x0e\xf2\x09\x73\x5c\xf9\x09" + "\x79\x4b\x41\x9e\x1a\xaa\x21\x64" +
+       "\x7e\x1d\x27\xa8\x05\xc9\x52\xa7" + "\x0b\x81\xe5\x58\xa5\xdf\x35\x47" + "\xeb\x5a\x92\x5d\xee\x44\x8a\xe1" + "\x53\xa8\xc8\x13\x7f\x69\x08\x97" + "\x0b\x9a\xcc\xbf\x40\xd5\x77\x83" + "\x03\xd4\x74\xe5\x1c\xe0\x27\x7b" + "\xa6\xa8\x60\xcf\x0c\x18\x3d\x3d" + "\xbf\x98\xc2\xf1\x52\xf1\x8e\xe4" +
+       "\x60\xb0\x29\xb8\xb1\x60\xb6\xb8" + "\x9b\xc6\x55\x5f\xf1\x3e\xa7\x9f" + "\x88\x78\x20\xef\xec\x19\x5f\xc7" + "\x9e\x12\x2b\x28\x60\x2b\x9b\xb1" + "\xc7\x30\x47\xbf\xee\x27\xf3\xb2" + "\xbe\xc0\x73\xc9\x59\xf6\x9d\xeb" + "\x98\xdb\xc1\x65\xc1\x13\x49\xd1" + "\x9c\x1a\x9d\xf7\xd4\x7d\xf5\x80" +
+       "\x21\x28\x39\x66\x6f\x02\x04\x11" + "\x49\x84\x79\xe1\xf7\xbe\x3d\x25" + "\x18\x56\x3e\x3f\x37\x34\x4b\x3c" + "\x41\xe0\x64\x2c\xd6\x46\x55\x5b" + "\x2b\x76\xc5\x57\x79\x32\xb5\xad" + "\xf3\x8d\x95\x92\xf0\xd0\xcb\x5d" + "\xbe\xbd\x4f\xf6\x44\x74\x45\x2c" + "\x75\x81\x40\x1d\x82\xc3\xab\xb4" +
+       "\x79\xd7\x19\xe9\x9b\xe7\x2d\x0c" + "\xbd\x78\x2e\x24\x4a\x69\x84\x15" + "\xc9\x76\x13\xf6\x94\x6d\x75\xa4" + "\x98\x27\xdc\x34\xbc\xa7\xcc\xfb" + "\xa1\xf0\x8d\x10\x19\x53\x87\x5e" + "\x9d\x89\x3e\x29\xae\x01\xec\xe2" + "\x91\x70\x35\x92\xef\xa4\x28\xc9" + "\x65\xd0\x2e\xf6\x87\x89\xa2\xd5" +
+       "\xc0\xa3\xea\x0a\x8c\x2e\x3a\x31" + "\x0a\x5b\xe8\xab\x9e\x6d\xf4\x89" + "\x3a\x7d\xa9\x2d\xbd\x9e\x88\xd2" + "\xba\x8c\x3f\x10\x6a\x02\x84\x94" + "\x5f\x3b\xd8\x87\x8a\x9f\x15\x52" + "\x95\x02\xef\xb1\xd6\x20\x22\xdb" + "\xcf\x1a\xc0\x03\x6e\x74\xa0\xbd" + "\xe3\x9f\x41\x14\xa7\xb2\x97\x4f" +
+       "\x9f\x20\x55\x25\xf7\x36\x04\xac" + "\xec\x73\x27\x16\xa2\x66\x34\x20" + "\xfe\x59\x8e\xb4\x39\x87\x3f\xc5" + "\x60\x56\x84\x88\x2b\xda\x4c\xb2" + "\x9a\x39\x5e\xfa\xf9\xb5\x74\x8d" + "\x5e\x25\x92\x6f\x0b\xed\x3d\xff" + "\x0a\x9e\x5c\x04\xfe\x31\x6c\xc7" + "\x62\x46\x2b\x6d\x44\xa0\xba\x85" +
+       "\x51\x5d\xf0\xed\xbe\x8b\xaf\xb8" + "\xb8\x8d\x8f\x71\xa6\xc7\x53\x86" + "\xdd\xff\x00\xcf\x8b\xb4\xfe\x14" + "\x40\xe1\xa9\x5c\xdb\xf7\xbc\xfc" + "\xb7\xfd\xd8\xd9\xe8\xec\xb4\x73" + "\x21\x99\x38\x2f\x68\xd3\x69\xdc" + "\x19\xc2\x8b\xc8\xe4\x2e\xd3\x10" + "\x96\x2d\x1c\x92\x27\x2c\x4d\xc0" +
+       "\xfd\x73\x10\x3d\xb8\xfd\x81\x69" + "\x0e\x20\x78\x6c\x0d\xf7\x2a\x25" + "\x7e\x57\xef\xa9\x67\xe8\xd0\x60" + "\x67\xe0\x13\xa4\xe8\x3f\xe6\x66" + "\x3a\x15\x14\xb9\x73\xb1\xdc\xbb" + "\xa8\xa0\xb4\xcc\x23\xe6\x9a\xb5" + "\xa0\xb8\x35\x3c\x20\x30\x05\x34" + "\xff\xf2\xda\x30\x6f\x81\xb8\x19" +
+       "\xca\xe5\x80\xc8\xc2\x7a\xbf\xcc" + "\x50\xc4\x11\x8d\xee\xdb\x99\x82" + "\xbf\xa6\x77\x0f\x1b\xd1\x27\xbb" + "\x93\xe7\xdc\x5e\x0b\x63\x01\xc6" + "\xea\xf8\xe7\x79\xfb\xb9\x73\xdb" + "\x88\x72\x36\xf4\xa7\xbb\x48\xe4" + "\x1b\x57\x35\xb0\x6f\x41\xb6\xf5" + "\xa2\x91\x88\xa4\x5d\x8f\x1b\x98" +
+       "\xa0\xfa\xfb\xb4\xff\x90\x96\x00" + "\xdb\xc6\x19\x36\xb7\xda\xbb\x8b" + "\xe8\x56\x83\x72\x73\x42\xd4\xc6" + "\x35\xec\x53\xe4\xd8\xf0\x76\xfd" + "\x29\x8a\xc2\xaa\x54\x25\x5c\x77" + "\xf0\xe4\x55\x5c\x9d\xaf\xf7\x28" + "\x4d\xad\xe8\x88\xa6\x54\xcf\xba" + "\xdf\x6d\xa7\x0a\xe8\x18\xb0\x85" +
+       "\x93\x7a\xc3\x09\xb9\xb3\xc8\x8f" + "\x2c\xb0\x99\xa1\xcb\xeb\x8f\x75" + "\x8c\x20\x3b\x8f\x38\x45\x9b\x5c" + "\xf0\x90\xba\xf2\xde\x84\x85\x7c" + "\xe3\xcc\x95\xb3\x1c\x1a\x75\x52" + "\x50\x5f\xd4\xc1\xeb\xe4\x59\xbb" + "\xac\x5d\x63\xb0\x11\xb9\xcd\xf7" + "\x94\x36\x24\xd3\x71\xd3\x24\xe9" +
+       "\xd6\xa8\x53\x65\xfd\xc0\x32\x65" + "\x6d\x5a\x16\x45\xa5\xcb\xb8\x42" + "\x92\x2d\xf1\x3c\xea\x88\x6d\x9c" + "\xc5\xb0\x6d\x90\x30\x35\xc9\x0e" + "\xdf\x6c\xcc\xec\xf8\x06\x46\x49" + "\x99\x78\x38\xc6\xfc\x66\xed\xa7" + "\x4c\xae\x35\x8a\x17\x2e\x02\x91" + "\xc3\xbe\xa7\xec\xe6\xca\xdb\x28" +
+       "\x84\xd6\xc4\x92\x51\x30\xce\x40" + "\xcd\xef\x12\x76\x25\xd7\x04\x8b" + "\x20\xae\x9c\x6f\x36\xda\xdc\xb9" + "\x6c\x85\x58\xf0\x24\x4d\xdc\x0e" + "\x00\x79\x42\x85\xbf\xe6\xf2\x64" + "\xea\xdf\x09\xdc\x95\x12\xe8\x3d" + "\x6c\xf2\x9b\x37\x87\x44\x1b\xd4" + "\xa9\x35\xf1\x6d\x6d\x2c\xb6\x50" +
+
+       "\x2a\x83\x05\xd0\x5e\xfb\xb2\x0d" + "\x4f\x2e\x04\x91\x3b\xfd\x5e\x5f" + "\xca\xf8\x70\xed\xc6\xfd\x4f\x8c" + "\xcc\xa9\x2d\xb5\x0b\x5d\x64\xe4" + "\x1f\x1d\x00\xc9\x8b\xf5\x96\x95" + "\x05\x72\x11\x4e\xbc\xf0\xc8\x52" + "\x84\xa0\x98\xe3\xd2\xa0\x4a\xfd" + "\xde\x49\x4f\x10\x3a\xfe\x5b\x81" +
+       "\x7b\xb3\x48\xe5\xcc\x3a\xeb\x54" + "\x49\x05\xd4\x84\x42\x75\x8e\xb3" + "\x4f\x1b\x34\x7b\x51\xaa\x3d\x8c" + "\xfa\xf7\x0b\x69\xec\x28\x69\x2f" + "\x41\x6c\xce\x86\x23\xb3\x96\x04" + "\xcd\xad\xad\x10\x55\x1c\xbe\x01" + "\xf9\xfa\xb5\x4b\xe7\x67\x4e\xc0" + "\x85\x99\x5c\xe1\x78\xf6\xba\x3c" +
+       "\x2d\x9a\xab\xd7\x6a\x22\x4d\x52" + "\x58\xe9\xfa\x7d\x0d\x09\x00\x9c" + "\xc2\xd8\x51\x87\x39\xf5\xa5\x0b" + "\x2d\x26\xb8\x3a\xdd\xbc\xfc\x8a" + "\x3b\x04\x9d\xe9\x29\x27\x39\x57" + "\x3a\x94\xbc\xae\x3b\x26\x51\xef" + "\x35\x29\x86\x20\x93\xce\xea\x9f" + "\x7b\x81\x6c\xb0\x03\xfc\x9e\x63" +
+       "\xdc\x81\x1d\x34\x7d\xbe\x39\xe8" + "\x79\x83\x14\x32\x89\x68\xdb\xcd" + "\xad\x6e\x02\xf7\xa1\x11\x62\xda" + "\x5e\xcc\xd1\xf4\x5f\x57\xb2\xf3" + "\xe6\x3a\xa7\xa7\xf6\xc8\xcf\x40" + "\x83\xb4\xd5\x61\x5e\x9a\x87\x83" + "\xbc\x0e\xa5\x41\xed\xb1\xac\xc5" + "\xfa\xd8\x07\x3c\xc8\x0c\xa6\x59" +
+       "\x90\x19\xb8\xc3\x4a\x8d\xc9\xde" + "\xfe\xc8\x0c\x9e\x22\x37\xb8\x1c" + "\xb9\x27\xb4\xd2\x91\x04\x0b\xfe" + "\x6c\xa6\x83\xe9\xac\x86\x23\x0f" + "\x13\x12\x29\xb3\x1e\x4d\x0c\x93" + "\xe4\x2a\xa6\x59\x2e\x2b\xf8\xa2" + "\xe3\x89\x3e\xf9\x53\x38\x23\x77" + "\x7f\x7c\x77\x11\xac\x63\x80\x7f" +
+       "\x00\x10\x37\x59\x7c\xc9\x4a\x60" + "\x18\x9c\x75\x7f\x70\x8c\xc4\xe1" + "\x65\x6b\xdb\xa5\xc5\xec\x62\x3f" + "\x95\x14\xa2\x38\x73\xb1\x78\x0a" + "\x94\xad\xc8\xbc\x9d\x81\xe1\x6b" + "\x00\x34\x9c\xd8\xf6\x04\xdc\x70" + "\x0a\x84\xb4\xa6\xb4\x57\x25\x46" + "\xc0\x21\xbd\x60\xde\x6a\x4c\x54" +
+       "\x72\x60\xff\x02\xcf\x07\xe6\x36" + "\xdc\x8c\xd9\x8a\xa9\x2c\x7d\xa4" + "\x09\x66\xf5\xf5\x1e\x1d\x47\xbf" + "\xa0\xad\x64\xf2\x23\x66\xf8\xbc" + "\xb6\x5c\x9e\xaa\x87\x06\x0c\xb7" + "\x6c\x1c\x40\x17\xf2\x24\x81\xc9" + "\x35\x14\xa6\xd4\x5f\x63\x89\x81" + "\xa6\x8e\xd9\xa9\xaf\xb8\x8f\xd2" +
+       "\x2d\x32\xc7\x65\xb6\x30\x95\x43" + "\xfb\xb3\xc1\xb3\x01\xcc\x12\xcf" + "\x85\xf6\x72\x01\x86\x01\x0b\xc7" + "\x1d\x39\x58\x1b\x22\xee\x15\xb9" + "\x24\xdb\x17\xa3\x3b\xf0\xfd\x9a" + "\xc4\xff\xb8\x17\x59\xc6\xde\x87" + "\x50\xd0\xd3\xe4\x7b\x59\x46\x7f" + "\xe7\x00\x65\x00\xed\xc1\xa1\x80" +
+       "\xf3\x25\x70\x01\xc3\xa8\x4d\x3d" + "\xb4\x79\x95\xfb\x8c\x62\xcf\xef" + "\xec\x16\x37\x1f\x16\x00\x4d\x5c" + "\x6e\x11\x01\x68\xc4\xeb\x27\x9c" + "\x7e\x76\xa1\x1d\xa1\x0e\xba\x5e" + "\x57\x4c\x00\x47\x52\x14\x15\xfe" + "\xb7\x73\x23\x8c\xf6\x6d\xce\x3a" + "\xac\x37\xbc\x5d\xfe\xdf\xc3\x75" +
+       "\x49\x07\x8a\xa2\xdb\x47\xa1\xa2" + "\x65\x91\x51\xee\xd6\x20\x6c\x24" + "\x15\x07\x81\xd3\xb1\xd1\x68\x50" + "\xb9\x60\x81\x74\x8c\x01\xe7\xb1" + "\x62\xff\x80\xf3\xfa\xb1\xf5\x03" + "\x1e\x2c\xcb\xf3\xdd\xb1\x7f\xef" + "\xda\xa7\x91\xfc\xa8\x39\xb5\xea" + "\x61\xb5\xf9\xf3\x07\xb7\xdd\x83" +
+       "\x98\x1b\x10\x80\xd9\x76\x72\xb5" + "\x66\x0f\x2f\xb8\xfd\x83\x08\x76" + "\xf3\xef\xc3\x4b\x75\xde\xd7\x89" + "\x40\xab\xc2\x5d\x43\x06\xb6\x03" + "\xac\xee\x5b\xe0\xdf\x53\x6e\xcd" + "\xcd\x25\x33\xbc\x62\xe8\xf1\xf2" + "\xc3\x03\x4f\x77\x21\x79\x0f\xdd" + "\x1b\xcc\x52\x45\x21\x72\xca\x97" +
+       "\xea\x46\xec\x9c\xf0\x4a\x9a\xe7" + "\xc7\x9b\x8b\x65\xa1\x47\x53\xb1" + "\x75\x2f\xaf\x35\x6f\x79\xd2\x6b" + "\x35\xc4\x51\x40\x90\x79\x95\xac" + "\x5d\x65\x3a\xc3\xa3\xdd\x69\x26" + "\xa3\x4a\x51\x88\x2e\x3c\x50\x5d" + "\x41\xdd\x53\x37\x37\x13\xa1\xdf" + "\x78\x4f\x75\x0b\x73\x46\x05\x3f" +
+       "\xd7\xc5\x24\xe2\xb5\xb3\x0c\x76" + "\x19\x69\x61\x68\x8c\xaf\x3b\xfa" + "\x52\x25\x14\x8d\x13\xa1\xbc\x9f" + "\xf5\xeb\x69\x76\xf1\x8b\xb1\x1a" + "\xdd\x25\xdf\x9b\x3e\xf5\xe6\x55" + "\x54\xd1\x6c\xcb\xf3\x0b\xcc\x04" + "\x80\x90\xe8\x95\x49\xef\x5b\x59" + "\xc1\x9a\x4a\x10\xa8\x59\x94\xfe" +
+       "\xf0\x3e\x12\xa8\x16\x63\xd6\x49" + "\x38\x54\xf9\xe7\xb4\x2d\xc3\x73" + "\x54\x78\x9e\x0d\x09\xd2\x2e\x2e" + "\x07\x05\x9f\x9d\x29\x93\x8a\xf9" + "\x0a\xa2\x6a\x0c\xf6\x3c\xd3\xc5" + "\xb2\x9b\x27\x75\x14\xba\x32\x9a" + "\x07\x73\x4a\x77\xcb\x02\x32\x7e" + "\xbd\x2d\xc4\xe8\xc4\x4b\xed\x64" +
+       "\xe8\x20\xb0\xab\xc5\x64\x4b\x69" + "\xc7\xee\xc4\x19\x84\xc1\x18\x3d" + "\xe5\x93\x47\x1c\xef\x73\x46\x9c" + "\xe6\x92\x60\x05\xb5\xae\xb8\xc7" + "\x6b\xc1\xf8\xf0\x43\xca\xa1\x3a" + "\xf6\xb2\x79\xd6\xec\xd5\x4e\x22" + "\xc9\x05\xa2\x55\xaf\xee\x56\x0d" + "\x8b\x02\x8e\x4b\xba\x15\xe1\xbf" +
+       "\xec\xf4\xac\x97\xb3\xa7\x22\x3e" + "\x40\xb6\xa8\x5e\x00\xc4\x26\x04" + "\x85\x92\x96\x4e\xa6\x95\x32\x5e" + "\x70\x56\xa4\xa6\x59\xbc\xaa\x22" + "\xbc\x42\x59\x5f\x4c\x71\x29\xb9" + "\xed\x82\x31\xfa\xbd\x68\x61\x9a" + "\xba\x52\x41\x10\x65\xa6\x16\x22" + "\x68\x63\x92\xb6\x03\x8d\x90\x46" +
+       "\x50\xa8\xcb\x7f\x24\xe0\x8b\x9b" + "\x1e\x18\x0a\x82\x97\x57\xeb\x81" + "\x11\x12\xa0\x30\x22\x81\xf2\xa0" + "\x21\x88\x7b\xae\x3c\xdc\x9c\x7e" + "\xe7\x15\xce\x72\xcc\x32\x23\x20" + "\xd7\x38\x82\xcb\xbb\xb2\x3c\xcd" + "\x43\x2c\xe8\xc6\xdf\x63\xab\xe4" + "\x17\xd7\x83\x31\x28\x00\xbd\x58" +
+       "\xab\x42\x29\xf3\xe8\x46\x8d\xd1" + "\x18\x24\x88\x10\xf6\x6e\x76\x6c" + "\x6b\xcd\xc6\x0c\x1a\xcb\xff\x8e" + "\x60\x59\xd8\x68\x5c\xa0\x1d\x5a" + "\x1c\x6e\x29\x32\xa5\xf4\xa5\xc7" + "\xc8\x2e\x0d\xc9\x43\x1e\x0f\x3d" + "\xd9\x29\x97\x89\x22\x3a\x94\x29" + "\x17\x53\x0e\x36\x26\x8a\x7a\x87" +
+       "\xb5\xd7\x7e\x71\x7e\x7b\xd5\x02" + "\xa2\xe1\xbc\x4d\x24\x5b\x2e\xd2" + "\xf5\xdc\x4c\x2a\x71\xd7\x4b\x17" + "\xbb\x05\x82\x40\x01\xb8\xfd\xa6" + "\xe9\x87\x13\x5e\x69\xb0\xb4\x67" + "\x42\xa4\x91\x05\xa1\x19\x2b\x33" + "\x66\xf3\xac\xcc\x16\xd9\xed\x24" + "\x50\x8a\x95\x34\x45\xcc\x34\xbe" +
+       "\x4b\x18\x1c\x06\x99\x76\x59\x81" + "\x52\x89\x89\x63\x5c\x10\x3d\x65" + "\xad\xfc\x5e\x7b\xde\x06\x91\xda" + "\x52\x14\xa6\x8a\xa6\x5a\x33\xa0" + "\x04\xba\xfa\x4f\x89\x7c\x7d\x33" + "\xf6\x90\xa9\x8e\xfe\xd4\xce\x9d" + "\x28\x57\x8c\x26\xb6\xb3\x28\x36" + "\xec\x21\xaa\xc2\x89\x70\x93\xf9" +
+       "\x91\xd3\x66\x3e\x1e\x6e\xf4\xa3" + "\xb2\x69\x63\x7d\xcd\x32\xa7\xb4" + "\x22\x10\x2c\x40\x5d\xb8\xc3\x99" + "\x2e\x93\x54\x2b\xbe\xfc\xcc\x7d" + "\xe2\xdf\xb1\x56\x7b\xaa\xdd\xa6" + "\xc9\x82\x4a\xe3\xa5\x78\xdc\x31" + "\x41\x39\x4f\x70\xda\xb3\xbe\x8a" + "\x98\xfa\x55\xca\x6c\xa3\x11\xdf" +
+       "\x66\x19\x86\x89\x34\x8e\x3b\xd5" + "\x6b\x99\xea\xa0\xa1\x20\xfb\x79" + "\x43\x7f\xd3\x5a\xd9\x47\x06\x30" + "\xcd\xe3\xa7\x53\xa8\xb4\x4d\xb4" + "\xfb\x59\x66\x2e\xb9\xe1\xe3\x9e" + "\x20\x72\x68\x5f\x72\x63\x32\x4b" + "\x43\x01\xa1\xb1\x25\x68\xc2\x6e" + "\x0b\x6f\x7d\x86\x2b\x76\xb6\xb4" +
+       "\x1b\x0c\xe0\x16\x7a\xf7\x01\x6c" + "\xac\xaa\x9e\x83\x90\x54\x51\x82" + "\x34\xd3\x70\x34\xef\xa4\xf3\x62" + "\x6c\xcd\x1d\x1c\x49\xa6\x29\x5a" + "\x25\x7a\x99\xce\x2e\x78\xb6\x46" + "\x53\x99\x57\xd3\x35\xfb\x78\x99" + "\xce\xe0\x60\x09\xdf\xa9\xf5\x98" + "\x4c\x7a\x52\x1f\x39\xc8\x7d\x54" +
+       "\xc1\xbc\xba\xc2\xc6\x8a\xcb\x52" + "\x8d\xae\x81\xfe\x48\xd4\x48\x47" + "\x11\xa7\xf1\x80\x3f\xf0\x44\x58" + "\xc4\x4a\xdf\xf8\xb2\x84\xb7\x3d" + "\x36\xfe\xf1\x2d\x12\x8f\x91\xad" + "\xc0\xc7\x3c\xf3\xb9\x25\x0f\xe4" + "\x55\x55\x5e\x3b\xe7\xd0\x00\x47" + "\xf9\x26\x33\xb0\x08\xfa\x28\x5c" +
+       "\x4f\xc2\x9d\x5d\x83\x15\x5b\x39" + "\x80\xe6\x3a\xc7\x32\x69\x25\xa4" + "\xe9\xc8\xa2\xfa\x0e\x96\x42\x05" + "\x6a\x8c\x06\x71\xee\xad\xb3\x2b" + "\x54\x45\x0b\x57\x9b\x09\x06\xa7" + "\xd6\x78\xe2\xf4\xb5\x2b\xd1\x85" + "\x43\x68\x29\x64\xf6\xf6\x8a\xd7" + "\x33\xc6\x28\x84\x88\xb3\xd3\xc7" +
+       "\x58\x97\x3f\xdb\x09\x67\x3b\x4c" + "\x1a\x8c\x1d\x34\x4e\xda\x9e\x16" + "\xd2\xa6\x13\x96\x18\x2f\x4f\xbd" + "\x36\xa5\xcd\xd7\x4e\x2b\x00\x9a" + "\xb9\x03\x61\x77\xd1\xf8\xbd\x97" + "\xba\x45\x79\xb3\x34\x0d\x67\x9c" + "\xbf\x5b\x8c\xd7\x84\xe3\x83\x9b" + "\xb2\x14\x8d\x51\xcf\x3b\x2d\x6e" +
+       "\x97\xe5\xb7\x43\x93\x4f\xd4\x34" + "\x42\x0f\x53\xc2\xa7\x40\xe4\xdd" + "\xb9\xbd\x56\x78\x81\xa0\x70\x72" + "\x2f\x03\x53\x53\xeb\x45\xa9\x86" + "\x10\x98\xd3\x66\x99\x8e\x2f\x6c" + "\x6b\x4b\x8b\x9b\x1b\xa3\x42\x06" + "\x82\x9d\x50\xd1\x62\x9e\x67\x51" + "\x16\xff\xf8\x90\x1c\x00\x20\x01" +
+       "\x4a\xe3\x36\x2e\x06\xc1\xa1\x50" + "\x1a\xed\x24\xe0\x8c\xf5\xe8\x74" + "\x26\xd7\x00\x13\xfa\x1d\x0f\x3f" + "\x18\x2d\x4a\x7b\x26\xdf\x80\x66" + "\xb7\xb3\x35\x82\x9d\x97\xb5\x12" + "\x93\x14\x61\x8a\xcb\xaf\x2f\x1d" + "\xe5\xec\x48\x88\x96\xda\xeb\x73" + "\x99\xe3\x13\xa4\x75\xc2\x96\xe9" +
+       "\x00\xf0\x5f\x49\xc7\xd7\xb7\x46" + "\xd1\x95\xed\xba\x97\xd0\x0e\xe6" + "\xc0\xf9\x38\x6e\xac\x04\x88\xaa" + "\xbb\xf9\xc6\x45\x06\x0c\x99\x92" + "\x51\x98\x91\xc0\x39\xa4\xe6\xca" + "\xf2\xe1\xf5\x1b\x15\xff\x3d\x71" + "\xdb\x8c\xb3\x2e\x30\x2c\x26\x5d" + "\xdf\x31\xdf\x90\x51\x50\x3d\xb7" +
+       "\xe5\x2f\x5b\xe5\xc2\x32\xc8\x85" + "\xfc\xde\x19\x91\x65\x21\x51\xf2" + "\xe4\x0f\xb0\x99\xbc\xe3\xfd\xfc" + "\x17\x8b\x90\xd1\xe3\xf5\x67\x80" + "\x42\xae\x43\x14\xb3\xf6\x21\xe9" + "\x3b\x59\xea\x64\x92\xed\xcf\xa2" + "\x35\x7a\xe0\x59\x62\xb9\x89\x15" + "\xdd\x62\xa7\x0d\x0a\x39\xbb\xc6" +
+       "\x8c\x26\xd9\x32\x1c\x7b\x1e\x92" + "\xd4\xfa\x76\x42\x96\x2b\xdb\x34" + "\x30\xe7\x44\xcc\x34\x6d\xc5\x0e" + "\xb7\x45\x65\x09\x46\x3a\xbe\x59" + "\x6a\x3a\xcf\x66\x97\xbc\xfd\xe9" + "\x53\x9b\x4e\xd0\xed\x83\x2f\x7b" + "\xe7\xe3\xba\x8f\xcc\xb3\x99\x6d" + "\x40\x3a\xda\x7a\x6c\x64\xb5\x8e" +
+       "\xfb\x51\x12\x5a\x74\xd8\xf5\xa9" + "\xc7\x25\x27\xc7\xa8\x47\x77\x96" + "\x9e\xe8\xff\x31\xe5\x33\x5c\x19" + "\x5e\x93\x64\xe9\x0f\x21\x9d\x60" + "\x27\x22\xe1\x2f\xa8\x6c\xfd\xca" + "\x9d\x46\x26\x04\x96\x5b\x9b\xaf" + "\x3c\x18\x93\x56\x4c\xe0\x9e\x2e" + "\xef\x6f\x14\xc8\x33\xa3\x84\x10" +
+
+       "\xf7\xd1\xd1\xae\x33\x99\x64\x96" + "\x90\x30\x56\x50\xf3\xaf\x6e\x56" + "\xcf\x39\x2e\xad\xf0\x57\x50\x34" + "\x24\x21\x83\x1f\x5b\xf6\x8f\x14" + "\x0d\xcf\x94\xcf\xd4\x89\x2e\x04" + "\xb3\x58\x0c\x52\x84\xec\x9b\x31" + "\x0d\xaa\x61\x53\x26\x76\x26\x2a" + "\xad\x87\xbc\x8f\x02\xa3\x6f\xc8" +
+       "\x6f\x69\xc1\xad\xe1\xd7\x66\x6b" + "\xd0\x72\xcd\x0a\x93\xe5\xeb\x98" + "\x35\x74\x1b\xcc\x50\x45\xf2\x65" + "\xec\xa5\xb9\xb4\x93\x13\x23\xce" + "\xf9\x7d\x06\xdb\xd4\x22\x4a\x23" + "\x00\x9b\xff\xca\x95\xa0\xdd\x98" + "\xc1\xc9\x00\x61\xa0\x75\xbc\x1b" + "\x95\xf6\x9c\x93\xc8\xa9\x60\x15" +
+       "\x74\xbf\x51\xfe\x5e\x32\x50\x08" + "\x94\x00\x46\x5e\x9e\x57\x4f\x9c" + "\x25\x2f\xda\x76\x2a\xb9\x87\x5c" + "\x33\xef\xeb\x6f\xe0\xe4\x9d\x88" + "\xce\x83\x60\x64\x06\xec\x00\x69" + "\x73\x27\xe1\xbf\x35\x03\x2a\xbe" + "\x10\x41\x34\xc5\x35\xda\xd1\xad" + "\x20\xcd\x02\xb8\xb7\x68\x75\x75" +
+       "\xca\x67\xc3\xf1\x1c\x0f\x05\xe4" + "\x7d\xbc\x0f\xc9\x9b\x5a\xc8\x9b" + "\x32\x10\xa1\xe1\xa2\xc4\x73\xa3" + "\xa9\x93\x03\xad\xb7\x32\x42\xb6" + "\x29\xad\x7d\x16\xb0\x7e\x57\xf5" + "\xb2\x8a\xb7\x94\x01\xf3\x04\x16" + "\x8b\x34\x29\xe8\xaf\x94\xaa\x0b" + "\x42\x43\x65\x41\xdd\xd8\xfb\x77" +
+       "\x2e\xcd\xa7\x94\xb4\x51\xf6\x6f" + "\x6c\x33\x99\x06\xd1\xff\x71\x56" + "\x6a\x89\x9a\x97\xcc\xd2\x5f\x6f" + "\xef\x8c\x14\xd8\xa8\x93\xe8\x11" + "\x10\x7b\xcf\x65\xa1\x06\x89\x98" + "\x85\x84\x0d\xc5\x78\x71\xb6\x81" + "\xde\xb3\x35\x8a\x35\xeb\x0d\x7c" + "\x99\x97\xd2\xc1\x55\xc8\x3a\x42" +
+       "\x08\x87\x61\x09\xe1\x69\x9f\x71" + "\xb1\xf9\x83\xc1\x64\x83\x9e\xcc" + "\xaf\x21\x6a\x36\x95\x3a\x20\xec" + "\x1f\x14\x8b\x06\x6d\x5d\xec\x6a" + "\xe9\x04\x4f\x99\x8a\xf7\x2d\xee" + "\xb0\x45\x12\x27\xe8\xca\x9c\xb3" + "\x4f\x3f\xe4\x97\xa9\xa4\x75\xb8" + "\x98\xea\x2c\xdb\x11\xfe\x7d\x50" +
+       "\x3d\x12\x32\x52\xea\x7a\x4b\x31" + "\xdb\x86\xae\x65\x8c\x7c\x30\x08" + "\xed\x68\x46\xaa\x5c\x16\xe7\x06" + "\x39\xec\xd3\xb4\x8b\x45\x70\xb1" + "\x86\xb9\x9b\xc1\xc6\x3e\x2e\x4d" + "\xed\x04\x03\xae\x46\x48\xf3\xc5" + "\x22\x97\x9f\x6c\xa0\x95\x76\x91" + "\x0a\x1c\xab\x4c\x17\x73\x7f\x6c" +
+       "\xfd\xa7\xf0\xfc\x02\x48\xf1\x31" + "\x1e\xb0\x88\x54\x89\x07\xfd\x42" + "\x98\xb4\x52\x99\x6d\x8d\xd7\x71" + "\x01\x52\xac\x07\xd9\x72\xb5\x8e" + "\x88\x4a\x19\x4d\x4c\xa4\xa2\xe0" + "\x66\x7e\x01\xba\xd9\x3f\xb6\xd2" + "\xfc\xae\x88\xf8\xc8\xc6\xef\x78" + "\x11\x1a\x88\x4a\xda\x6b\x6f\xb7" +
+       "\x38\x72\xa6\xb2\x01\xe1\x0b\xbf" + "\xf2\x14\x9c\xaf\x67\xd3\x56\x35" + "\x75\x20\x66\xa5\x31\x78\x4b\x10" + "\x0a\xe6\xd9\x79\xbb\x59\xca\x58" + "\x3b\xa7\x69\xa5\x92\x53\xc4\x4b" + "\xc9\xf6\x98\x56\xe8\x52\x7a\x51" + "\x55\xd7\xad\xae\xa5\x3d\x64\x85" + "\x84\x1b\x58\x2a\xd5\x0c\xed\x1a" +
+       "\x67\xe9\xf9\x19\xbc\x26\xf7\xa0" + "\x4e\xbf\xfb\xe8\x52\x31\xd0\xd9" + "\x40\x7d\x70\xb7\x1d\xf5\xd6\xcf" + "\xe0\xe6\xf6\x63\xd9\x84\x30\x63" + "\xaf\x7e\x66\x55\xdc\x9c\xcd\xed" + "\x6f\xd5\x44\x2e\x2b\xf9\xb7\x73" + "\x14\x2b\x96\x4e\xb6\x39\x2e\xfb" + "\xbf\xfc\x71\xf6\x6e\x8f\x40\x7d" +
+       "\x8a\xcf\xdf\xf8\x75\x30\xea\x9e" + "\x25\x98\x66\x95\xaa\xf0\x84\xa2" + "\xd8\x3f\x7d\x86\x50\xa2\xfc\xb3" + "\x1e\x69\x9d\x26\x5f\x7b\x75\x20" + "\xde\xa5\xb8\x93\x20\x40\xc2\xf2" + "\xa6\x6d\xc0\xeb\x59\x33\xf9\xd3" + "\x33\x9c\x73\xb2\x3e\x29\x78\x11" + "\xe5\x86\xd6\xbc\x70\xe7\xa3\xd2" +
+       "\xee\x43\xaf\x68\x2c\x93\xf7\xa2" + "\xbd\x00\x3d\x70\x8e\x46\x02\x55" + "\xf5\x61\xb0\x2f\x8f\x97\xdc\xe5" + "\xad\x15\xc8\x28\x4a\x90\xa1\xc9" + "\xa4\x56\x0c\x47\x8d\x53\xaf\xd3" + "\xed\x8c\x3d\x19\x5f\xbc\x9a\x15" + "\xf3\x8e\x10\x20\x5f\x24\x37\x2a" + "\x78\x71\x3f\x22\x1e\x08\x17\xfa" +
+       "\x3a\xa7\xf2\xec\x8d\x6e\x20\x2a" + "\x94\x19\x55\x8e\x97\x63\x6a\x06" + "\xa2\x53\x8d\xb9\x8a\x08\x6a\x3a" + "\xaa\x24\x11\x2d\x7c\xc6\xe7\x0c" + "\x3c\x11\x9a\x75\x71\xc6\xce\x48" + "\xfa\x67\x6f\x4f\xd3\x73\xb3\xe3" + "\x7b\x72\x36\xfd\x79\xd4\x55\x54" + "\x81\x0d\x3c\xa1\xee\x28\xa4\xe5" +
+       "\x5e\xbd\xb1\x16\x5f\xea\xfe\x6b" + "\xd3\x0a\xe3\x4d\x20\xe4\x57\xf9" + "\x9e\x3b\x35\x6a\x4e\x66\xaf\xcb" + "\xeb\x4f\xd1\x26\x12\x33\x87\x5c" + "\xcb\x57\x5f\xb6\x8c\xf9\x87\x4e" + "\x41\xdd\x0c\x5e\x21\xa6\x60\xdb" + "\x40\x14\x88\xa6\x65\x68\xc1\x67" + "\xaa\x52\xab\x46\x1a\xef\x93\x10" +
+       "\x64\xec\x2e\xbb\xba\xcb\xbc\x93" + "\xbe\xad\x03\xda\x64\x3b\xc2\xa0" + "\xc4\x6a\xe8\xe0\x0a\xa0\x7a\x5f" + "\xe6\x01\x14\xfc\x1e\x94\x0b\x47" + "\x74\x35\xf4\x9d\x79\xd6\xd8\x5a" + "\x10\xd8\x65\x0f\xa9\xb8\xcf\x4c" + "\x81\xbd\x7f\xaa\xe3\x80\xce\x1b" + "\x0a\xd2\x08\x95\xad\x91\x32\x27" +
+       "\x7c\xb6\xb4\xb4\xb2\xa9\xe2\x1f" + "\x04\x06\x02\xe8\xf0\x0d\xd1\xc1" + "\xd8\x58\x80\xbc\xfc\xab\x64\x9d" + "\xbb\x0f\x2a\x71\xb2\xb9\x43\x89" + "\x04\xef\x3d\x3b\x14\xd9\xee\x90" + "\xff\x75\xe7\x4c\xa2\x3a\xab\x85" + "\x40\x90\xbc\x7b\xca\xd4\x5f\x60" + "\xfb\x5d\xc7\xe2\x64\xa5\x34\x8b" +
+       "\x0f\x36\x82\xe3\x7c\x9f\x75\x25" + "\x57\x58\xbf\x88\xc9\x05\xdb\xb6" + "\x6c\xd4\x58\x6c\x1d\xd6\x17\x29" + "\x7a\xcb\x20\xfd\x91\xe4\xf8\x14" + "\x40\x03\xc2\x11\x7a\x72\x8a\xb6" + "\xb6\xcb\x7c\xaf\x6f\xf8\x86\x03" + "\x20\x9a\xe0\xfe\xcc\xc6\x8b\x5c" + "\x35\xea\x7e\xbb\x4a\xff\x76\x7d" +
+       "\x88\x52\x8a\xaa\xaa\xca\xab\x4d" + "\xc9\xa1\x23\xaf\x8a\x0c\xcc\x91" + "\x0c\x0e\x22\x3f\x6a\x2c\xc7\x34" + "\x4a\x14\x32\x12\xdf\x0b\xc2\xbc" + "\x1b\xde\x0e\xa2\xda\x42\x2f\x6e" + "\x15\x05\xa0\x74\x0c\xf0\x41\xc4" + "\x4b\x8c\x4b\x73\xb6\xa5\x46\xbf" + "\xa4\xc9\x56\x7b\x03\x95\x40\x57" +
+       "\x1b\x57\xf3\x3f\xa5\x36\x68\xb4" + "\xc1\x27\x79\x83\x78\x8b\xf9\x24" + "\x16\xc7\x33\x45\x6a\x25\x54\x62" + "\x96\xe1\x7e\xd0\x0b\xbb\x7a\xf2" + "\xfd\x5b\x6d\x5c\xfc\x64\xcf\xd7" + "\x77\x7a\xcd\xf0\x51\xc7\x15\x69" + "\x34\xf5\x98\x87\x12\x90\xf5\xd9" + "\x5f\x8b\x1d\xf8\xa8\x0d\x2b\x77" +
+       "\x90\x7d\x2f\x8e\xf8\xac\x18\x5c" + "\xcd\x32\xbe\x77\xd7\x33\xbf\xfd" + "\xe9\x5e\xeb\xd2\xd7\x5c\x08\x0a" + "\x15\x11\x20\xb3\xfb\x2c\x70\x2d" + "\xe8\x8c\xc8\x85\xdb\xeb\xe0\xb6" + "\x17\xd6\x01\x1e\x3c\xce\xa3\x23" + "\xac\x33\x73\x56\x8e\x61\x41\x30" + "\x6b\xdb\x7e\x15\x8f\xfd\xd0\x9d" +
+       "\xb0\xd1\x07\xce\x73\xda\x6b\x38" + "\x78\x41\xad\x58\xc2\x10\x29\xd8" + "\xf4\x17\x26\xcd\xcf\x82\x4f\x12" + "\x70\x17\x69\xef\x8d\x5e\x2f\xcc" + "\xcc\x0c\xc3\xb8\x50\x25\x70\x82" + "\x5a\x57\x8e\x1a\xea\x6a\x85\x7b" + "\x59\x94\xab\xb1\xef\x2f\x82\xbb" + "\x8e\xe3\x24\xec\xbc\x28\x59\x08" +
+       "\x71\x88\xb9\x8f\x11\x3d\x46\x80" + "\xff\x6a\xc7\xbb\xc3\xf5\x26\xcb" + "\x14\x36\xe0\xfb\xdd\x8e\xab\xd4" + "\xee\x2d\xcf\xc0\x9b\x57\xeb\xc8" + "\x41\xae\x3b\xc9\x15\x4c\x00\xcc" + "\xb2\xa3\xec\x3a\x5d\xae\xfb\x46" + "\xb1\x9a\x1e\x0f\xcf\x35\x12\x67" + "\xc1\x85\xc2\x9e\x34\xa9\xfb\xad" +
+       "\x77\x64\x7c\xb5\x6b\x93\x6c\xa3" + "\xc6\xbc\x4d\xe9\x64\x8b\x1f\x87" + "\x7b\xa6\x91\xa5\x62\xfb\xd0\x28" + "\xf5\x26\xd9\xc1\x81\xe0\x40\x9d" + "\x5a\x4b\xd8\xf2\xf6\xea\x11\x31" + "\x44\xb6\x65\xa5\xf9\x93\x89\x22" + "\x8b\x18\x83\x2c\x92\xf5\xcb\x0c" + "\x97\xe1\xf3\x3d\xab\x30\x7b\xf8" +
+       "\xaa\x7a\xfa\x98\x07\x61\xb2\xb2" + "\x4e\xaa\x73\xf0\xe4\x9e\x20\x41" + "\x9b\xb1\xd6\xf2\x59\x03\x57\xf1" + "\xaf\x7c\x57\xfc\x8c\x86\xe6\xcb" + "\xd3\x4d\xc0\x32\xdc\x4b\x6c\x18" + "\x97\xe3\xee\xcf\xae\x5f\xc3\xa6" + "\xcf\xc0\x86\xf0\x12\xb3\xa1\xb4" + "\xe2\x1f\x46\xd9\xc6\xcc\xa5\xe0" +
+       "\xd3\xe5\xaa\xa7\x79\x26\x4e\xd2" + "\xc4\xc1\xe5\x0d\x3d\x01\x76\x70" + "\x29\xb6\x05\xbb\xba\xf8\x50\x2d" + "\xbb\xef\x66\x6e\xe2\xab\xc1\x73" + "\xf7\x8a\x48\xf2\x22\xb4\xd4\xef" + "\x75\xa5\x3b\x66\x02\x5d\x10\xe4" + "\x57\x94\xa6\x53\x8b\x0a\xb6\x7e" + "\x3b\x97\x45\xc9\x08\x00\x21\x62" +
+       "\xfb\xab\x66\x4b\x86\x32\x8e\x1d" + "\x00\x09\x03\x59\xe5\x52\x6f\xd2" + "\x1a\x94\x84\x55\x43\xf6\xe3\x1e" + "\x58\x59\x9f\x56\x30\x37\x3b\x6d" + "\xa5\xdb\x89\x47\x2f\xa6\xf2\x9f" + "\xb7\xc9\xb5\x72\x15\xb8\xfc\x91" + "\x0e\x9a\x8f\x6c\x7d\xcb\x46\xf4" + "\xb5\xec\xb7\x39\xc1\x25\xf6\x48" +
+       "\x12\x81\x44\x30\x77\x14\x7c\x7b" + "\x56\x86\xa3\xe4\xf1\x1a\xb5\x82" + "\x10\x50\x31\x2f\x8a\x02\xf2\x2b" + "\xd4\x8c\xa8\x6e\x1f\xa0\xa4\xc9" + "\x18\x58\x7e\x25\xd8\x95\x3e\xf6" + "\x16\x9b\x51\xb4\x10\xfa\x8e\xdd" + "\xbf\x10\xa9\x0d\xe0\x73\x89\xed" + "\xa9\xe4\x0f\x5c\x77\xd0\x49\xed" +
+       "\x0c\x11\xa6\x6f\xa3\xf3\x6f\x51" + "\x1f\x56\x93\xfb\xb1\x1e\xfb\x74" + "\x2b\x52\x57\x84\x47\x90\x0c\x6c" + "\xc6\xbd\xb8\x6b\x04\x21\xd3\xcf" + "\x57\xad\x80\xcc\xa2\x84\x68\x2d" + "\x37\xb6\xa9\x86\x35\xfc\x27\x7c" + "\xcd\xe8\xf4\xad\xed\xba\x61\x34" + "\xf0\x42\x72\x61\x1a\x25\x56\x1d" +
+       "\x94\xe0\x95\xa9\xd1\x46\x99\x71" + "\xd8\x04\x1e\xe5\xf6\x48\xe8\x65" + "\x13\x31\x1e\x6a\x00\x33\x2f\xe6" + "\x03\xe5\x1d\x50\xc1\xc7\x41\x15" + "\xde\xfa\xac\xf4\xfa\xc9\xaa\x4d" + "\x71\x0b\xcd\x44\x97\x58\x58\x0e" + "\x77\xcd\x51\x0a\x69\xd8\x4f\x54" + "\x6d\x01\x31\x00\xed\x20\xfc\x60" +
+       "\x44\x44\xdb\x64\xaf\x12\xe7\x3f" + "\x80\xd4\xcd\xbe\x34\xd6\xe9\x19" + "\x8a\x97\x30\xa9\x47\xc0\x8b\xe0" + "\x33\x07\x28\xa1\xec\x24\xbf\x2d" + "\xb2\x06\xd7\x2c\x8c\xe3\x0a\x3c" + "\xb9\x17\x90\x35\x5b\x2a\x01\x5b" + "\xae\xf5\xe0\x72\x8c\xc3\x43\x39" + "\xa3\x6f\x17\x57\xea\x67\x61\x78" +
+       "\xb1\x49\xea\xab\xb7\x9f\x97\xfa" + "\xc5\xc6\xe2\x10\x7d\xd2\xb1\xb4" + "\x7a\xde\xaf\x23\xc4\xc2\x61\xbd" + "\x58\xd3\x86\x97\xf8\x14\x66\xeb" + "\x59\x74\x6f\x7f\x6b\x81\x5d\x4a" + "\x7b\x0e\x36\x09\x4f\xa4\x31\xe4" + "\x4c\x91\x09\xc3\x32\xa0\x27\x8c" + "\xd8\xe3\xed\xca\x8a\xd6\xa5\xce" +
+       "\x0e\xd8\x1d\x43\xa9\x11\x40\xb8" + "\xd9\x6c\x30\x73\xca\x7c\x7c\xeb" + "\x30\xb7\xb3\xd1\x29\xdd\xfa\x20" + "\xd3\xb3\x37\xfe\x5b\x8b\x85\x83" + "\x5c\x1d\x25\xb6\x93\xd1\x4c\xbf" + "\x52\xd9\x52\x13\xd3\x1f\xca\x1c" + "\x51\xc0\xfb\x90\xa4\x57\x61\xc6" + "\x36\x86\xb9\x89\x38\xa6\x90\x79" +
+
+       "\xe1\xc0\xde\x87\x2a\x69\xaa\xe5" + "\x00\x9d\xb3\xf7\x8d\xed\x0d\x01" + "\xb5\xa0\xcf\x54\xc8\x80\x1b\x7b" + "\x28\xea\xf8\xa0\x76\xb8\xbe\x66" + "\x0e\xcd\x76\x34\x31\xf5\xd7\x50" + "\x49\x39\x8d\xb0\x65\x0e\x3d\xa6" + "\xc6\x9f\x47\x53\xa9\xee\x09\x1a" + "\x42\xe7\x99\xf4\x91\x98\xae\x82" +
+       "\x66\xd8\xa7\x5c\x10\xb9\x58\xab" + "\x34\x3b\xdb\x3a\xe2\x67\x29\x58" + "\xbc\xc0\xea\xcc\x47\x44\xae\x89" + "\xf5\x6a\xf5\x7b\x7c\x66\x9c\x91" + "\xd7\xdc\xf5\x60\xb1\x17\xec\x9a" + "\xbc\xad\xca\xdd\x9f\x7b\x69\xec" + "\xf5\x67\x34\x46\x41\xf3\x98\x0b" + "\x2f\x13\x67\xa9\xf7\xf1\x87\xb1" +
+       "\x18\xeb\x4a\x21\x1d\x7a\xfe\x90" + "\xf7\x32\x14\x74\x3c\xaf\x06\x15" + "\xc4\xa0\x91\xe5\xf9\x65\x55\xbb" + "\xc3\x1b\x4f\xb4\x77\x1a\xd4\x10" + "\x96\xde\x4b\xa8\xe4\x65\x9d\xa0" + "\x1c\x6a\x0a\xf2\xd8\x60\xf0\x42" + "\xe7\x9c\x7f\xf2\xfd\x3b\x2a\x65" + "\x9f\x73\x3d\x3b\x5c\xb6\xbd\xb6" +
+       "\x9f\xae\x7f\xec\xb6\xdc\x5d\xeb" + "\x5a\x6e\xb6\xef\x14\x27\x5f\x99" + "\x52\x5d\x44\x69\x8e\x5d\xe9\xde" + "\x20\x76\xe2\x09\x46\x2d\x6c\x1b" + "\x16\xd7\x29\x81\x31\x1c\x62\x32" + "\xaa\xc1\x58\x09\xf1\x09\x39\xb0" + "\x63\xaf\xf4\x1a\xf9\x8e\x46\x8c" + "\xf6\xcd\xa5\xfb\x9f\x42\x2c\x16" +
+       "\x71\x93\x3b\x75\x43\x23\x68\x2f" + "\xd7\x9c\x1f\x5f\x5a\xb4\xca\x29" + "\x96\xdb\x45\xb2\xab\x23\x16\x57" + "\x99\x99\xd7\x3f\x09\xdb\x07\xc5" + "\x32\x6c\x03\xaf\x52\xf6\x2e\x4e" + "\x5c\x8e\x01\x05\x78\xcc\xf0\x86" + "\x50\xe3\x8b\xab\xd4\x73\x0a\xc1" + "\x27\x63\x82\x7e\x97\xb3\x19\x65" +
+       "\xf7\x3d\x05\x9c\xef\x5e\xcb\xe8" + "\x6f\xea\x00\xb3\x37\x5b\xe2\x8d" + "\xfb\xcf\x49\xc8\x92\xfa\x03\xdb" + "\xbb\x69\x41\xe8\xa7\x43\x2e\x24" + "\x8e\x95\x6f\xdd\xf4\x51\xfa\xe4" + "\x8d\x5a\x44\xf4\x7f\xa7\x25\x69" + "\x49\x89\x0d\xe9\x50\x2a\xe7\xe6" + "\x90\x63\x1f\x2b\xe3\x48\x66\xc6" +
+       "\x0c\x46\x3e\x17\x57\x19\xab\xb2" + "\x90\x45\x70\x30\x75\xce\xbb\x1b" + "\x62\x71\x1c\xdb\xbd\x0d\xa9\xc0" + "\x5d\xd6\xcd\x15\x9e\x39\x5e\x50" + "\xb7\x7a\x79\x57\xcb\x4d\x43\x68" + "\xe8\xa8\x2c\x6a\xba\x35\xad\x60" + "\xc1\x36\x33\xde\xe0\xb1\xfd\x4b" + "\x15\x90\xb3\xd8\xeb\x99\xef\xbb" +
+       "\xec\xeb\x11\x17\xf3\x96\x3b\x6c" + "\xc4\xfd\x98\xce\x1f\x0f\xa4\x2d" + "\x1f\x41\xb4\x57\xd3\x74\x97\xb9" + "\xb6\x5b\xb6\x15\xf4\xbd\xc8\x87" + "\x2d\xf1\xee\xc2\xe3\x89\x3a\xda" + "\xf3\x71\x74\x3c\x9b\xbb\x95\xde" + "\x94\xc5\x12\xd8\x5b\x22\x0f\x60" + "\x6b\xa5\x75\x2b\x5d\x7c\x90\x54" +
+       "\x35\x0e\xb6\x8d\xf0\xc5\x3c\xa9" + "\x19\x33\x83\xfa\xd6\x3c\x3e\x74" + "\xc9\x83\x16\xf8\x41\x5c\xad\x7d" + "\x7e\x10\x34\x9c\xd9\xe7\xc1\x70" + "\x07\x09\xbe\xa6\x39\x4a\xdc\x0e" + "\xd3\xb7\xd0\x86\x35\x70\xd4\x36" + "\x60\xfa\x2b\x27\x03\xda\x76\x8c" + "\x14\xa4\x08\x0f\xea\x07\x4a\x0b" +
+       "\x53\xdd\xc1\x45\x29\x4d\x9e\x69" + "\xb5\xeb\x1d\x23\x98\x58\xdc\xca" + "\xe0\x00\x7f\xa7\xc7\xfc\x49\xdf" + "\x0e\x5a\x3e\xa7\xbf\x7b\x05\x93" + "\xd1\x4c\x7a\x02\xcd\x7e\x8b\x2f" + "\x1a\x01\x14\xc6\xb3\x34\x47\x11" + "\x68\x7c\x67\x67\xb7\x1d\xa0\xe7" + "\x4f\x3f\x27\x7e\x5e\xbe\xd9\x89" +
+       "\xef\x08\x98\x08\x2e\xcb\x25\xd2" + "\x07\x41\x9e\xd5\x7d\xa2\xf7\xf1" + "\xc9\xb9\x11\x82\x61\xc7\xaf\x53" + "\x59\x91\x81\xe6\x67\xbc\x61\x03" + "\x26\x14\x07\x7f\x0b\x5d\x86\x2a" + "\x67\x25\x07\xe7\x10\x18\x3c\x6a" + "\xbd\xca\x6b\x0d\x1e\xca\x3b\x3e" + "\xbc\x91\x85\x40\xc1\x2b\xb0\xa1" +
+       "\x39\xa2\xfb\x31\x59\xee\xde\xe0" + "\xd1\x91\xbd\x98\xd3\x24\x74\xf4" + "\x1d\x3c\x1a\x07\xf4\x86\x88\x0f" + "\x3b\x23\x19\xa8\xe8\x41\x7d\x3f" + "\x98\xb9\x6e\xcf\xc2\x23\x86\x70" + "\x7f\x28\x9a\x60\xaf\x49\xbb\x86" + "\x62\x07\xc9\x63\x49\xb2\x2b\x94" + "\x4b\x65\xa9\x55\xa5\xee\xf6\x0e" +
+       "\xfe\xde\xf5\x36\x72\x2d\x6d\x5f" + "\x76\x91\xf9\x56\xdc\x22\x99\xfa" + "\xc7\xe0\x8c\xf7\xce\x5e\x8c\x6c" + "\x5e\xb5\x09\xbe\x9d\x58\x44\x7b" + "\x70\x37\xa8\x9e\xca\x3b\x1b\xe1" + "\x47\x15\xb7\x2a\x7f\x2c\xfa\xd7" + "\xc0\xdc\x1d\x2a\xfa\xd6\x3d\x2a" + "\x07\x77\x7b\x5a\x30\xb4\xac\x09" +
+       "\x57\x4e\x9d\x64\x2e\x4a\xdd\x4a" + "\x6e\x52\x17\x19\xb0\xa2\x53\xcd" + "\xc4\x4a\xb4\x20\x30\x23\x26\xc5" + "\x1d\xc3\xa2\xba\x6a\x74\x28\x40" + "\x4c\x1d\x29\x64\x90\x83\x31\x51" + "\x09\xd9\x5a\xee\x51\xf1\x48\xbf" + "\x81\x56\x18\x7b\x59\x7f\xe5\xcc" + "\x42\xd4\x54\x48\xb0\xc1\x3a\x7c" +
+       "\x71\xc1\x93\xc0\xc3\x7d\x58\x65" + "\x65\x2b\xf4\x24\x24\xcb\x7a\xae" + "\xcb\x96\x59\x95\xdb\x8a\x33\x5a" + "\x1b\xf9\x51\x60\x75\x56\xe6\xc8" + "\xb1\xd0\xb8\x28\xba\x1f\x71\x66" + "\x90\x0a\xc1\xb6\x37\x41\xd7\x15" + "\x80\x2a\x23\x3a\xeb\xd7\xcd\x70" + "\x24\xed\x91\x61\x7f\xf0\xe2\xc9" +
+       "\xc0\x88\x95\xf7\xb6\x1d\x0d\xa8" + "\xcc\x68\x57\xb5\x69\xfc\x52\xfa" + "\x8a\x43\x54\x7f\xae\xf1\x4d\x0b" + "\x4f\x6a\xb4\xf9\xa7\xd1\xad\x0c" + "\x6f\xdd\x03\x18\xb3\xa6\x0e\xb4" + "\x35\xae\xea\x55\xa5\x4f\x8e\x48" + "\x16\x4e\x2e\x38\x55\x7d\x04\x9f" + "\x98\x0c\x6e\x2f\xe0\xb7\xb5\xc9" +
+       "\x49\x26\x76\x95\xd3\xd2\x1b\x6b" + "\xf6\xa3\xae\xc7\xe7\x4e\x60\xa9" + "\x96\xf8\xc6\x6d\x27\xff\x46\x36" + "\xd1\xba\x60\x28\xf5\xe7\xf0\x9b" + "\x92\x4b\xb4\x7c\x21\xc8\x92\x2d" + "\x82\xc1\xa9\xae\x63\xce\xf5\xa2" + "\xfd\xa5\x54\x91\xb1\xaf\xa2\xd0" + "\xa6\x1d\x80\x95\x4c\x47\x2e\x48" +
+       "\x4b\xc2\x11\xb6\xd0\x72\x99\xc1" + "\x51\xf3\xa8\x60\x65\x8e\x46\x1d" + "\x21\x64\xcf\x7b\x69\x80\x75\xeb" + "\x91\xc4\xfb\x88\xee\xd0\x9d\xec" + "\x32\x2e\x6c\x95\xbf\xd2\x59\x5b" + "\x4e\xf9\xdd\xdc\x64\x68\xdc\x73" + "\x65\x76\xee\xbc\x21\x23\x5e\xfd" + "\xc4\x06\x9a\x5e\xef\xf8\xb4\xa7" +
+       "\x55\xf8\x80\x72\xdd\x18\xa9\xfb" + "\x88\xc6\xae\x8b\x60\xc2\xaa\xbb" + "\x42\x0f\x40\x33\x0f\xf0\xb3\xa3" + "\xe4\xe6\xf2\x66\x29\xba\x2d\x3d" + "\x75\x93\x50\x98\x94\x1a\xf7\xb6" + "\xcc\x23\xa4\xce\x1f\x03\x33\x8f" + "\xfb\xe6\x07\x48\xd0\x8d\x9b\x00" + "\x4c\x95\xdb\x5c\xe5\xcf\x63\x51" +
+       "\xe8\xc6\x41\xcf\x17\x8f\xcc\x03" + "\x5c\x92\x7b\x03\x2a\x3c\xf0\xf1" + "\x7c\x42\xd2\x66\xcc\x19\x9c\xc3" + "\xe4\x18\x6c\x7b\xba\x24\x3d\x82" + "\x4f\x0b\x1f\x90\x13\x90\xef\x32" + "\x2e\x1c\x94\xf8\xf1\x60\x43\x68" + "\x2e\x09\x28\x2c\x52\xff\xba\x0e" + "\x2f\x93\x6c\x25\xe3\xe4\x91\x78" +
+       "\x3d\x5e\x44\xac\x19\x43\x26\x51" + "\x81\x43\xa7\x8e\xe7\x32\x34\x55" + "\x0a\xc5\xe9\x67\x69\xaa\xee\xe6" + "\xc7\x28\xe6\x62\x84\xd2\xce\x27" + "\x57\xfa\x4a\x7a\x75\xd3\x96\x3f" + "\x50\xc1\x84\xe4\xc3\x14\x0a\xde" + "\x23\x99\xbd\x38\xeb\x24\x4a\x36" + "\x22\x74\x17\xe5\xa0\x8d\xf1\x1d" +
+       "\x9b\x8a\xd3\xd8\x82\x8f\x4e\x17" + "\x91\x13\xde\xe7\x00\xc6\x97\x2e" + "\xdd\x75\xc1\xa1\x50\x98\x70\xc5" + "\x35\x50\xae\x32\xa0\x41\x90\x96" + "\x6b\x08\xa2\x76\x3b\x53\xfd\xcb" + "\xfe\xe8\xc2\xd7\x1b\xa7\xbb\xd6" + "\x67\xfb\x9d\x09\xe6\x8e\xd5\xb2" + "\xd9\x85\x4a\x06\x2d\x34\x8b\x3a" +
+       "\xe3\x9b\x2f\x52\x49\x76\xc0\x3b" + "\xa8\x49\x1f\xdf\x5b\x07\x0c\x69" + "\x42\xec\x54\x38\xe8\xae\xe1\x80" + "\xc7\x9d\x68\x17\x44\xbf\x7d\x2a" + "\x78\x40\xaf\x3f\x0e\xfc\x04\xc0" + "\x2c\x86\x11\xdf\x9e\x2e\xf0\xb2" + "\xb3\xb7\xa1\xa0\x0f\x5e\x0a\xf1" + "\x80\xec\x36\x89\x23\xa6\xac\x30" +
+       "\x9a\x0d\xf4\x02\x05\xbf\x3c\xf8" + "\x4d\x8a\x31\x2c\x68\xc4\x81\x46" + "\x74\x26\x9c\x0e\x18\x56\x57\x98" + "\x2e\x09\x47\x18\x46\xd0\x79\xbe" + "\xe0\x01\xbd\x78\x0a\x48\x1e\xaf" + "\xb9\x1d\xa5\x72\xe4\x59\xd3\x6d" + "\xb6\xba\xaf\xe3\x21\x38\xce\x62" + "\x99\x31\x73\x17\xb6\xe5\xce\xc5" +
+       "\xbb\x9f\xfd\x6f\xd4\x30\x8b\xe0" + "\xb7\x10\xc6\x36\x99\xc6\x5b\x6e" + "\xcf\x62\xe2\x9c\xf2\xcf\x43\xf3" + "\xc1\x14\xb9\x68\x35\x4e\x2e\xca" + "\xc5\x36\xde\x16\xc0\x64\x1d\x01" + "\x29\xb8\xe2\x42\xdd\x0f\xb1\xe0" + "\xf8\xaa\x85\x66\x81\x29\x94\x78" + "\x97\xde\x0e\x23\x08\x17\x51\xe7" +
+       "\xf8\x2b\x92\x3b\xfc\xd8\x1e\x67" + "\x33\xb1\x29\x4c\xa0\xc0\xd8\xe4" + "\xc4\x99\x6e\x3b\x39\x12\xeb\x87" + "\xba\xbe\x93\x87\x4c\x97\xf3\xaf" + "\x9b\xdf\x18\x2c\x05\x94\x74\x03" + "\x39\x71\x00\x91\x93\xa2\xc3\xc5" + "\x95\x0b\x7a\xe3\x4f\x23\x77\x6a" + "\x6b\xc9\x61\xb6\x21\x9a\xc2\x02" +
+       "\x61\xcf\x1e\x14\xd6\xf1\xaa\xc3" + "\x53\x2f\xb2\x3b\x9e\x50\x95\x91" + "\x57\x13\xd5\x22\x04\x74\x59\x29" + "\x60\xed\x7b\x53\x22\x38\x08\x1b" + "\xf0\x89\x72\xe0\x35\x6e\x7d\xcd" + "\xff\x6e\xd8\x6d\x8c\xc4\x94\x1f" + "\xfa\x9c\x0f\xeb\x82\x1f\xbb\xc8" + "\x7d\xb9\x2e\x1b\xe6\xb7\xe0\x9e" +
+       "\x31\x4e\xd7\x34\x2e\xfe\x52\x5a" + "\xb6\x9a\xf7\x3b\x10\xc3\x52\xa3" + "\x8f\xeb\xfe\xab\x5a\x6c\xff\x97" + "\x05\x73\xc9\xf5\xef\x8f\xbe\xbf" + "\x08\x46\x90\xa7\xe6\x1c\x08\xd6" + "\x49\xa2\xfc\xc4\x3a\x2f\x81\x1f" + "\x00\xe2\xe5\xb9\x9a\xbc\x24\x9b" + "\xe8\x2e\x01\x38\x67\x2c\x02\x91" +
+       "\xa1\x13\xa7\x30\x5d\x9c\x3d\xe8" + "\x93\x0f\xef\x84\xf0\xe3\x76\x48" + "\x28\xf9\xfb\xc1\x29\x70\x77\xc9" + "\xa4\xd2\xe7\xbc\xb3\x6b\x7a\xef" + "\x59\xa6\xa2\xdf\x28\x72\x06\xb8" + "\x8f\xa4\x77\xd8\x98\x33\xcd\xd5" + "\x3f\x0f\x5d\x02\x8f\xfd\xa4\xbe" + "\x2b\x7c\xae\x2e\x35\x2e\x7d\xd6" +
+       "\x94\x43\x5f\xcc\xd7\xe7\x4d\x18" + "\x42\xe1\x36\x45\x5c\x1b\x55\xb5" + "\x0a\xa6\x4a\xd3\x12\xb2\x89\x2e" + "\xd5\x51\x00\xf5\xea\x6f\xa9\x14" + "\x0b\xbb\x12\x0d\x74\xef\x21\x4e" + "\x7e\x67\xb9\x60\x20\xf0\x22\xc5" + "\x1d\x73\xf7\x2d\x67\xe4\x12\x8b" + "\x31\x6d\x32\x7b\x82\x03\xf8\x39" +
+       "\x94\x4a\x02\x39\x0c\x63\xb8\xdf" + "\x52\x94\x31\x97\xa8\x96\xcb\xaa" + "\x7c\x86\xa3\xed\x61\x39\x8a\xd6" + "\xca\xff\xc4\x77\xb0\xe2\x58\x0c" + "\xfa\x19\xa9\x4d\x63\x5d\x54\x3d" + "\x89\x22\x5e\xf1\x9a\xb6\x79\xef" + "\x10\xab\x8b\x80\x3d\x3d\xbc\x54" + "\x37\x2c\xf8\x45\x07\x30\xab\xc8" +
+       "\x8a\x65\x4a\x7c\xb6\x38\x27\xc1" + "\x82\x21\xe7\x40\x39\x76\xc4\xb3" + "\x4f\xe4\x98\x87\x46\xbe\x77\x3b" + "\x5f\xf8\xa7\x17\xf2\x7d\x04\xdc" + "\x2d\xd9\x59\x5e\xc5\xd4\x39\x24" + "\x8d\x4d\xe6\xe8\x75\xa4\xdc\xce" + "\x16\x9b\xca\x87\x0d\xcd\x24\xa7" + "\xfe\x0d\x54\xa5\x59\xfd\xe4\x35" +
+
+       "\x7a\x46\x29\x3a\x4f\x34\x94\x98" + "\x6d\xba\x1e\xc5\x49\xe9\x81\xde" + "\xf2\xc2\xe5\xa5\x6b\x06\xea\xda" + "\xb3\xc7\xc8\x08\x14\xa6\xc8\x3f" + "\x9f\xde\xd0\x06\x8f\xf8\xdf\x7a" + "\x0a\xce\x75\x3b\xf5\x1c\xc1\xbb" + "\xd5\x87\xbc\xfb\xcc\x7a\xbb\x9f" + "\xe2\xfd\xad\x7b\x26\x8e\x45\xa1" +
+       "\x56\xc2\x39\xe0\x68\x36\xb4\x1c" + "\x5d\xfd\x17\x7c\x8b\xfb\x26\x5f" + "\x2b\x06\xaa\x79\xaf\x26\xe4\xee" + "\x04\xbf\x8f\xd7\xd0\x02\x20\x07" + "\xe3\xb7\x4f\xe8\x37\xa2\x9c\x4c" + "\x3d\x13\x82\x0c\xa1\xd8\x01\xb4" + "\x81\x41\x7e\x6d\x92\x25\xa5\xaa" + "\x52\xb1\xdb\x73\x33\x08\x43\xe9" +
+       "\x83\xc9\xe7\x6e\x1e\xad\x5f\x2f" + "\xf5\x28\x13\xb4\x7c\x9d\x0f\xeb" + "\xf7\xd5\x78\x1d\x44\x8b\xa6\x9b" + "\x6f\x72\xbc\x35\x9e\x3b\x6b\xa0" + "\xf1\x1f\x3e\x59\x55\x02\x55\xa2" + "\x15\xc1\xbe\xdf\x3d\xd4\x2d\x55" + "\x46\xf0\xa8\xbb\xab\xa7\x48\x2c" + "\x33\xf1\x0b\xad\xa3\x56\xfc\xd4" +
+       "\x9a\x31\x24\xbe\x31\xda\x2d\xf9" + "\xe7\xa8\x95\xe0\x8b\xd2\xf7\x03" + "\x85\x21\x78\x98\x40\xe8\x2f\xa5" + "\xbc\x4d\xc2\x29\xfe\xda\x6d\x27" + "\xeb\x64\x7a\x1d\x96\x54\xcd\x80" + "\x42\xbe\x1d\x7f\x89\x08\x36\xe4" + "\xd5\xd2\x38\x84\x77\xa8\x81\x2f" + "\x36\x90\x16\x85\xa8\x52\x4d\x7e" +
+       "\xd1\xb5\x04\xba\xef\x1c\xf2\x62" + "\x52\x73\x4c\x22\x07\x27\x44\x9a" + "\x1f\x17\xc6\x33\x6c\x96\x07\xbf" + "\xb0\x16\x08\x1e\x91\xa8\x7b\xdb" + "\xa9\x45\x37\x03\x59\xea\x6f\x30" + "\x67\x8f\xa7\xc0\xe0\xf7\xac\x2a" + "\xf9\x1b\x25\xad\x83\x38\xaa\xb5" + "\x86\x70\xbd\x26\xe9\xed\x5a\x34" +
+       "\x5d\x71\x59\x1d\xb1\xd5\xe3\x19" + "\x3e\x98\x88\xd7\x62\xa7\xea\xc7" + "\x48\xf2\xf1\xab\xb0\x30\xa7\xe5" + "\x83\xfd\xe3\xfa\x84\x80\xab\xfb" + "\x2f\x5b\x76\x53\x21\x0d\xe5\x65" + "\x3d\x7f\x12\xfa\x83\xe0\xd4\xbd" + "\x10\x1b\x7b\x39\x74\xc0\xf3\x9c" + "\xd3\x9f\xb5\xb1\x0c\x09\xf8\x59" +
+       "\x10\x9f\x11\x98\x7d\xe1\x1d\xdc" + "\xa6\x36\x8c\x48\x5d\x3c\x35\x74" + "\xdf\x23\x8e\x3d\x3a\xf3\xaa\x14" + "\x93\xf5\xba\x78\xc0\x75\xe0\x31" + "\x3c\xca\xd1\x46\x3a\xa0\x7c\x0f" + "\xc7\x60\xb6\x47\xac\xe3\xc5\x99" + "\x59\x2e\xfe\x88\x13\x24\xd0\x70" + "\x05\xc0\x7e\x2a\xe1\x6b\x9a\x2e" +
+       "\x8f\xaa\x5f\x61\x9d\xfd\x15\x7b" + "\xed\x54\x85\x96\x40\xeb\xa1\x8f" + "\x82\x48\xa4\x7a\x7e\x44\xb4\x7b" + "\x32\xff\x9f\x02\xd1\xd0\xb2\x2b" + "\x2f\x6d\xaa\x6c\x64\x2a\x5e\x07" + "\x1b\x35\xe7\x22\xde\x79\xb8\x8e" + "\x62\x6c\x50\x9a\x4e\x62\xd5\xbc" + "\xdc\x24\x7e\xa8\xf0\xae\x8e\x21" +
+       "\x6f\xbd\x1f\x24\x95\x96\x44\xac" + "\x23\x12\x1c\x08\x70\xb1\xc9\x67" + "\x6f\xac\x6a\xb5\x21\x8f\x86\x16" + "\x21\xb7\xbc\xf8\xa3\x8f\xbd\x34" + "\x76\x1c\x69\xb6\x33\xbd\xb6\x06" + "\x73\x79\x1a\x38\x66\x47\x92\x6c" + "\xdb\x78\x40\xa5\x4c\x44\x12\x6a" + "\xcc\x51\x10\x6d\xa9\x91\x2e\xd0" +
+       "\x35\xfa\xdd\x44\x47\x68\xe5\x37" + "\x47\xf7\xb3\xda\xc5\xc5\xcf\x9c" + "\xf4\x6c\xe9\x1e\x3f\xdf\xc1\x9a" + "\x8f\x0b\x48\x3b\xa1\x71\x05\x0c" + "\x3c\x7b\x3a\x4b\xd5\xb3\xbe\x2f" + "\x99\xbb\xcd\x5d\x69\x36\xc0\x35" + "\x3a\x5b\x41\xb2\xdc\xf5\xa0\x52" + "\x9a\xed\x13\x44\xb4\x59\x77\xd5" +
+       "\xf8\xd3\x33\x0b\xc0\x79\x73\x07" + "\x09\xe4\x64\x70\xc6\x83\x18\x42" + "\xf6\xc8\x29\x6c\xd7\x73\x08\x2d" + "\xc8\xc0\x74\xd2\xa3\x33\xa4\xbf" + "\x1e\x89\xa5\x23\x8f\x77\xdc\x56" + "\x04\xde\xe2\x35\x65\xbf\x63\xd6" + "\xce\x17\xb5\x5d\x48\xdb\x8f\x48" + "\xc2\x26\xb2\x19\x5e\xa5\xbb\x00" +
+       "\xc5\xa2\x30\x3d\xd8\x47\xe6\x1f" + "\xdc\x81\x8a\xf7\x7e\xf7\x57\x08" + "\x9b\x4a\x1a\x13\x34\xa3\xd5\x11" + "\xf5\x93\xd3\x29\xf9\x4a\xa9\xc0" + "\x1a\xec\xa6\xda\x0b\x5c\x3a\xbc" + "\xed\xd7\xd2\x88\x93\xe4\x9f\xba" + "\x97\x47\x61\xbb\xb4\x35\x43\xbb" + "\x33\x35\xf8\x72\x68\x4d\x1c\x99" +
+       "\xb6\x8f\x05\x8a\xe7\xee\xbb\xed" + "\x1a\x12\x09\xfb\xdc\x9d\xd1\xb9" + "\xce\xdd\x4d\xd3\x5b\xb4\x1b\xa4" + "\xc4\x4b\x96\x00\xb9\x80\xbc\x2d" + "\x54\xb6\x6c\x1d\x7d\x13\xd9\x4e" + "\xc5\x01\x3d\x48\xdb\x16\x90\x1b" + "\x2e\xe2\x28\x65\xbc\x01\xc5\x5f" + "\x6b\x64\xad\x6c\x81\xf8\xd2\xb2" +
+       "\xb3\x1c\xf0\xd2\x28\x8c\x25\x53" + "\xb1\xb0\x5d\xd7\xa3\xea\xd6\x93" + "\xb4\x0d\x7d\xe8\x0d\x2b\x9a\x41" + "\x93\x84\xfe\xd8\x03\x8f\xe4\xa1" + "\x3a\xb2\x08\xc5\xf6\xfa\x47\xf7" + "\x49\x35\xd5\x35\x1a\x57\x37\xf1" + "\x38\xb8\xf9\xfc\xe2\x58\x5e\x9f" + "\xf5\x3c\xfd\xa7\xee\x6c\x18\xc7" +
+       "\x39\xad\x6b\x28\x2f\xfb\x76\x5e" + "\xe2\xd1\xca\x9d\xe3\xef\xd9\xba" + "\x04\xe9\xc7\xed\x90\x51\xe7\x60" + "\xa5\xb5\xec\x0f\x3e\x06\x6f\x6a" + "\xc3\xac\xd8\xae\x85\xed\x50\x51" + "\x6c\xaf\x20\x6d\xbc\xcf\x6c\xb5" + "\xfa\xdb\x69\x2c\x98\x1e\x0d\x7e" + "\xa9\x10\x7e\x7c\x8a\x62\xf5\xab" +
+       "\xd3\xa1\x78\xe9\xce\x68\xb8\x77" + "\x04\x2d\xb9\x7a\x33\x8b\xa6\xe3" + "\x62\xb8\xa5\x87\x94\x97\x02\x51" + "\x1d\xd4\x61\x3a\xc3\x06\x06\x5f" + "\xf1\x26\x93\x6f\x27\xbe\x14\x28" + "\x2e\x3c\xfe\xc6\x14\x1c\x52\x2f" + "\x51\x73\xdf\xac\x7d\x4d\x46\x17" + "\x44\x7e\x7f\x77\xd3\xf9\xf5\x10" +
+       "\xab\xa2\x08\x74\x19\x64\x21\x1d" + "\x6a\x91\x28\x59\x18\xd5\x55\xae" + "\xea\x5e\x16\xf3\x4a\x68\x75\xdf" + "\x59\xef\x4e\xd8\xd5\x64\x83\x53" + "\x1a\x3b\x56\x70\x15\x20\x4e\xb5" + "\xff\xef\x4c\x6b\xa7\xbb\xd9\x74" + "\xdc\x82\x06\x7a\xd8\xcb\xbe\xfc" + "\x6c\x11\x93\xf1\x02\xa4\x00\x0e" +
+       "\x7d\xb3\x9f\x26\x6b\x61\x8e\xce" + "\xe5\x2d\xe6\x7d\x04\x38\xf7\xaa" + "\x53\x41\xdd\x4f\x75\x11\xa1\xab" + "\x9b\xb4\x70\x37\xba\x59\x57\x51" + "\x61\x3a\x42\xaa\xf8\xeb\x09\x8b" + "\x92\xfb\x41\xcd\xa1\x45\x22\x59" + "\x36\x89\x4c\x9b\xc1\x8e\xba\x1c" + "\x0e\x71\x36\xaf\xe3\x91\x7e\xa8" +
+       "\x16\xc4\x9f\x84\x85\x89\xf6\x65" + "\x3c\xa7\xba\xcd\x34\xa9\x03\x3c" + "\x47\x66\xcb\xbf\x1b\x31\x2f\x11" + "\xcd\x93\x4e\xde\x40\x13\xc1\x69" + "\x7b\x53\xdb\x66\xb9\x58\x24\xbd" + "\xe7\x07\x5b\x88\x18\xb0\x74\xf9" + "\x32\xd3\xc8\x70\xa5\x45\xb1\x5d" + "\x7b\x83\x9b\x54\xd1\xd0\xfd\x30" +
+       "\xe3\xa2\x34\x3d\xe4\x4c\xd8\x1f" + "\x61\x5d\x3b\xb4\xce\x59\x37\xee" + "\xc7\x86\x91\x61\x8c\xc7\x5b\x89" + "\x5a\x72\xb9\xcb\x09\x38\x9c\xf1" + "\x1f\x4b\x74\xde\xaa\x21\xbe\xc0" + "\x6b\x05\xf8\x60\xb0\x22\xd2\xa7" + "\x11\xfe\x3e\xb2\x57\x61\xbe\x74" + "\x53\x82\xd6\x0c\x4f\x2b\xab\x6f" +
+       "\xb4\x58\x23\x51\x73\x1d\x5c\x3e" + "\xc9\x99\xbb\x30\xb2\x42\x57\xcb" + "\x1a\x03\x2d\x3c\xa8\x2f\x2e\x4a" + "\xb8\x78\x98\xfb\x2b\xc9\x1b\x37" + "\x6c\x65\x75\x82\x9c\x1f\xa7\x1e" + "\xa1\x00\x03\x1c\xa2\x94\xf7\x14" + "\xe5\x54\xea\x26\x98\xe7\xea\x08" + "\xc6\x54\x1a\x17\xe5\x54\x58\xcf" +
+       "\x25\xd7\xf1\x4b\x5f\xea\x33\xad" + "\x0f\x95\x6c\x4f\xe2\x8e\x1d\x9c" + "\x06\xaf\x77\xa3\x8a\xe7\x4e\x54" + "\xe1\x13\xa1\x94\xbb\x89\xf4\x54" + "\xe8\xb7\x2f\x99\x34\xd6\x11\x8f" + "\x47\x43\xa4\xa2\xaa\xa7\x69\x01" + "\x00\x0e\x02\x95\xaf\xd4\x49\x1d" + "\x0b\x12\x8e\xe0\x22\x57\x94\x95" +
+       "\x86\x38\xba\xb7\xb3\xfb\x0a\x28" + "\xa8\x34\x89\x36\x3e\x3a\x80\x08" + "\xab\x71\xf6\x31\x65\xdf\x80\xf9" + "\x91\x47\x72\x1a\xea\x4a\x89\x90" + "\x50\xa3\x1d\x8d\xa9\x66\x5b\x54" + "\xa5\x53\x13\x41\xbf\xfb\xf4\x9d" + "\x8a\x08\x98\xa3\x3c\x74\x52\x15" + "\x17\x57\x2d\xb8\xde\x4c\xc1\xd1" +
+       "\x82\x22\xd3\xa4\x78\x38\xe3\xb6" + "\xe7\x0a\x02\x48\x9d\x02\x6e\xe3" + "\x50\xb7\xa9\x37\xfb\x47\x58\xe0" + "\x19\x38\x9e\xb2\x2c\x81\x76\xf8" + "\xf0\x17\x3a\xd2\x8e\x13\xad\x84" + "\x0e\x95\xb3\xf0\x80\x44\x7b\x6d" + "\xe0\x7a\xd6\x2f\xf4\xae\xa8\xdf" + "\xf6\x3a\x33\x52\x24\xea\x3e\x8d" +
+       "\x83\xec\xc5\xf5\xfd\x3a\x8d\xb2" + "\xad\x9f\x04\x91\xc1\xf6\x6a\x8d" + "\x1a\x1e\xbe\xff\xff\x64\x79\x41" + "\x0a\x79\x1c\xf5\xea\x9e\xce\xba" + "\x79\x29\x0f\xb2\x36\x22\x02\x42" + "\x01\x38\x5d\x76\x29\xb7\x05\x6b" + "\xe7\xe3\x6d\x6d\x00\xe2\x0e\xbe" + "\x3a\xaf\x01\x1e\x01\xd5\x6e\xb9" +
+       "\xcc\x5a\x5d\xb1\x75\x20\x05\x0d" + "\xc4\x5b\x81\xbd\x9f\xc7\xd9\xc6" + "\xf2\x6c\xa3\xdf\x88\xfd\xca\x8d" + "\x70\x90\xaa\x38\xe2\xcb\x8c\x90" + "\xce\xaf\x35\xba\xc4\x22\x87\x63" + "\x0b\xbf\x6a\xfd\xb0\xa8\x3d\x5a" + "\xc1\x35\xc3\xc9\x2c\x25\xce\x2d" + "\x9b\x79\xaa\x65\xde\xf0\xe7\x84" +
+       "\x62\xbc\xed\xe0\xec\x62\x87\xef" + "\xfb\x73\x27\x85\x28\x98\x44\x33" + "\x85\x38\xae\xc3\xf3\x90\x9b\x2c" + "\xb2\x56\x1e\x73\x12\x18\x19\xd8" + "\xf0\x31\x68\x73\x95\x7e\x5d\x20" + "\x5d\xc1\x41\xd6\x48\x8d\x81\xc3" + "\x7c\x15\x3e\xf4\x39\x38\xb6\xc6" + "\xf0\x51\xad\x36\x47\x04\x16\x55" +
+       "\xcb\x72\x9a\xb9\x22\xa5\x01\x21" + "\x16\x80\x61\x87\x67\x6e\xde\x06" + "\x3e\x65\xf3\xe6\xcd\xc7\xf8\x5f" + "\x4a\x75\xa6\xc7\xb5\x1a\x82\x0a" + "\xa2\xb5\xb0\x7c\x2b\xa5\x3f\x7e" + "\x90\x87\x04\xc9\x1c\x12\xfb\xa7" + "\x3a\x05\xce\x06\x20\x50\x72\x1a" + "\xb0\x29\xe9\x04\x1f\xa3\x90\xb4" +
+       "\x6e\x7e\x40\xbc\x19\x77\xbb\x70" + "\x41\xeb\x4c\xd8\xef\x28\x13\x23" + "\x20\xbb\x04\xc1\x1f\x6a\xca\x8b" + "\x71\x90\x0b\x28\x25\xe4\xf4\xd6" + "\x82\x6a\x89\x92\xa2\x95\x1b\xb4" + "\x67\xdf\x34\xfa\x35\xf4\x5c\x73" + "\x69\xd7\xd6\xd9\x08\x1a\x33\xbc" + "\x7e\x74\x82\x26\x05\x86\x97\x57" +
+       "\xad\x61\xdd\x62\x7d\xe4\x7b\xe1" + "\x71\x13\xe0\x6b\x1c\x96\x1a\x78" + "\xba\xcb\xe3\xda\xd3\xbf\x63\x10" + "\xba\xc9\x73\x7f\x06\x74\x64\x35" + "\x29\xa1\x36\x27\x7b\x95\x0e\xf5" + "\x56\xf2\x13\xed\x02\x37\x31\xa6" + "\xc5\xfc\x19\x3a\x65\xee\x36\x94" + "\xb6\xc8\xa4\xe7\x29\xdb\x2b\xcf" +
+       "\xbe\xb8\xf3\x87\x42\xf7\x8a\x69" + "\x1d\x59\xa1\xd1\x1a\x9d\x5d\x4f" + "\xe1\xac\xe4\x0f\x3c\xac\x0f\x54" + "\x7d\x4a\x89\xc6\x24\x9b\xa6\x83" + "\x46\xeb\x6f\xad\xee\x07\x5c\x93" + "\xfa\x25\xf3\x7f\x88\xbd\x2c\xe0" + "\x0b\x38\xc6\xbc\x9d\x8c\xf0\xe8" + "\xce\x45\xe0\xa6\x0f\xf4\x7f\x9c" +
+       "\xd8\x5c\xf9\xc5\x44\x12\x6b\xb0" + "\xf4\x95\xab\xf4\xf0\x8a\x8c\xda" + "\x6d\x83\xe5\xb9\xc2\x59\xae\x1b" + "\xfc\xff\xcf\x3a\x7e\x1e\xd5\x07" + "\xda\xbc\xcc\xc2\x6a\x5e\xe1\x01" + "\xe0\xc3\x28\x85\x3f\x92\xc1\x3b" + "\xd4\xea\x9f\xa4\x77\x45\x32\x43" + "\x11\xa7\xa7\x2a\x84\xb8\xa1\x61" +
+
+       "\x34\x3d\xe6\xb0\x31\xee\xe7\x4f" + "\xab\x4f\xe5\xa9\x72\x05\x60\xf4" + "\xa4\xb5\xe7\xd5\x34\x33\x49\xc0" + "\x31\x48\xd5\x06\x92\xfb\x89\x85" + "\x3a\x55\x83\x65\xcc\xf5\x70\xaa" + "\xe5\x49\x56\xe2\x4a\x09\x79\x08" + "\x52\x46\x04\x10\x07\x45\x90\xcc" + "\x4f\x1c\x54\x02\x6d\x69\xb0\xeb" +
+       "\xa6\xe7\xde\xa2\x3e\x1a\x8c\x75" + "\x84\x22\x4b\x73\x3c\x2f\xde\xdc" + "\xad\xa6\xab\x4e\xd2\x45\xa4\xab" + "\xa7\xe0\xce\x76\x68\xf6\xaa\x35" + "\x9a\x04\xaa\xe5\xa9\x04\x0b\x7e" + "\x84\x3e\x10\x91\xad\x83\x40\xe7" + "\xc3\xec\xaf\x40\xce\x83\xb1\xbe" + "\x7a\x3f\x04\xea\x9f\xde\x89\x6b" +
+       "\x35\x52\x37\x99\x03\x0e\x9f\xb9" + "\x70\x79\x91\xb9\x47\xc8\x14\x76" + "\x67\xc0\x4e\x52\xe9\x3c\xc9\xfe" + "\x20\x25\x12\x9b\xf8\x7b\x0e\xe4" + "\x74\x47\x4c\xee\x31\x06\x67\xb5" + "\x4c\x91\x04\x3b\x7a\x84\x03\x6f" + "\x26\xd2\x9d\xdc\x29\x94\x6e\xc9" + "\xf8\xc1\x57\x8c\x6c\x9b\x48\x43" +
+       "\x66\xba\x67\xfe\x23\x9d\x29\x0e" + "\x34\x2f\xcf\x93\x60\x07\x45\x91" + "\x13\xf9\xfc\x97\xa9\x5e\x5b\xf4" + "\xda\xdd\xd7\x8b\x43\x08\xe0\x5b" + "\x4d\xf0\x3f\xd5\x05\x3e\x8c\x35" + "\xf7\x1e\xe9\x5d\xc3\xcd\x7c\xbf" + "\xa0\xc1\x9e\xb6\xbf\x4d\x68\xad" + "\x97\xd9\x1f\x80\xf2\x7c\x7e\x36" +
+       "\xfb\x38\x23\xcc\x27\xd2\xff\x46" + "\x53\x61\xe2\x90\xa9\x6f\xff\x89" + "\x76\x00\x1a\x33\x79\x07\x57\xbe" + "\xaf\xf3\xe1\x06\xc5\x41\xd2\x43" + "\xa3\x62\x9b\xde\x7d\xb9\xcd\xfd" + "\xea\x30\xae\xa0\x84\xe9\x06\x6a" + "\x7d\xdf\xbd\x4f\x80\x16\xbf\xc9" + "\xc4\x63\x61\xd3\xa2\x71\x04\x17" +
+       "\x5e\x65\x13\x31\xae\xa8\x5b\xff" + "\x80\x31\xb8\x57\x2b\x6e\x2c\xfa" + "\xbe\xea\xe0\x77\x19\x27\x48\x1c" + "\x97\xea\x7f\x33\x55\xc5\xf3\xf9" + "\xcb\x81\x25\xa4\x22\x70\x0f\x34" + "\xe3\x10\xf7\x18\xc2\x0b\xde\xe1" + "\xa8\x5a\x2e\xf6\xde\x0a\x64\xee" + "\x40\x89\x42\x49\x91\x38\xb2\x16" +
+       "\xc3\x0c\x95\x55\xe4\x19\x16\x36" + "\xb8\x6b\xb6\x56\x5c\x66\x1d\xc7" + "\x84\x6d\xac\xaf\x34\x4b\x03\xea" + "\xe3\xc7\xe4\xe5\x32\xf8\x87\xa9" + "\xa7\xa6\x79\x7a\x72\x27\x74\xa0" + "\x23\x6c\x6d\xe2\x17\xd0\xe5\x56" + "\x10\x7e\x16\x38\x76\xb9\x50\x7e" + "\x4e\xa8\x8a\xe8\xef\x81\x6c\xaa" +
+       "\x95\x85\xdc\xb0\xb7\xf3\xa1\x0c" + "\x2e\x9f\x1d\x9f\x08\x46\xde\x27" + "\xa7\x82\xdd\xba\x39\xbf\xf3\x1a" + "\x48\x24\x86\x65\x79\x6a\x35\x79" + "\x52\xa0\xf9\xf5\x45\x23\x60\xc0" + "\xf9\x42\x9a\x13\x89\x0f\x8b\x1a" + "\xfc\x40\x4d\x84\x42\xee\x3e\xb5" + "\x68\x63\x5b\x4e\xe5\xbf\xb0\x93" +
+       "\xbf\x5b\x32\x4d\xd7\x59\x39\x47" + "\xb9\x14\x61\x8d\xec\xbe\x61\x2a" + "\xee\xe2\x4b\x92\x94\x2a\x67\x25" + "\x0c\x3d\xc2\xf2\xdb\x95\x85\xa4" + "\x38\x18\x22\x6a\x8b\x84\x76\xe4" + "\x73\xb6\xc1\x35\x9a\xe6\x43\xe7" + "\x03\x85\x46\xd8\x99\x24\xb4\x2a" + "\xa7\x0b\xe9\xe9\x54\x00\xaa\x62" +
+       "\x11\x29\x48\xbc\xf1\x13\x8d\x35" + "\x26\x7f\xfa\xb7\x71\x19\x5d\x68" + "\xe4\xae\xe1\x2b\x1d\xa5\x67\x3e" + "\xa9\x14\xd1\x98\x09\x85\x41\xe0" + "\x61\x25\x05\x4e\x60\x9f\x63\x59" + "\x18\x08\x5d\x15\x49\x5c\x07\x32" + "\x1c\x4b\xb6\x67\x3b\x34\xa2\x2a" + "\x6a\x3e\xf5\x67\x29\x5e\x44\x1b" +
+       "\xe0\x04\xa9\x73\x17\x27\xfb\xbd" + "\x73\x8d\x88\x28\x0b\xe4\xe1\x7c" + "\x1b\x7d\xa9\xea\xf6\x35\x7e\x2e" + "\x97\xa0\xaf\xa9\x2a\x77\x61\xd0" + "\x59\x7c\x1f\x7a\xc4\xc7\x4a\x43" + "\x9a\x7b\x9b\xe7\x4a\x12\x21\x6e" + "\xc7\xec\x22\xbb\xf3\xcf\x5a\x05" + "\xd3\x58\xc8\x84\xc9\x7a\xfd\x8b" +
+       "\x9c\x78\x24\xc0\x02\xdd\x34\x54" + "\xfc\x7b\xb5\x41\xea\xa9\xdc\x90" + "\xdf\x98\x33\x24\xe2\x98\xa8\x8a" + "\xbb\x94\x4a\x89\x34\xc8\x07\xf6" + "\x76\x9b\xc9\xc2\x97\xbe\x07\xbb" + "\x02\x93\xc2\x18\x67\xba\x76\x65" + "\x8c\xa8\x03\xe7\xcc\xef\x79\x3d" + "\x06\xd1\xa0\xb6\xd7\xce\x59\xf2" +
+       "\xad\x68\x1f\x9f\xf5\x7d\xd5\x2f" + "\xc8\x70\x64\xb0\xdb\xc6\xdc\x5d" + "\x07\x73\xb4\xa9\x51\x64\x1b\x80" + "\xf4\x1b\x55\x76\xe3\xc8\x51\x6b" + "\xa9\x1d\x4e\xd4\xf7\xd1\x0b\xef" + "\x0c\x60\x4e\x4d\x1d\xcb\x4b\x71" + "\xc7\x40\x65\x0c\xe4\xb9\x7b\xc5" + "\x44\xc6\x7c\x32\xc2\x1e\xbd\x71" +
+       "\x0a\x4f\xd8\xcf\xb5\x33\xcd\x00" + "\xdd\x0d\x6b\x4e\xf7\x68\xa5\xcf" + "\xf4\x48\x0f\x2d\xdb\x4e\x69\x1c" + "\xd8\x7d\xff\xfe\xcc\xc7\x47\x27" + "\xb2\x24\x8c\xac\xad\xec\xda\xce" + "\xe5\xa5\x42\x07\x3f\xde\x29\xdb" + "\x6d\x29\x90\x30\xbb\x8f\x5d\xe3" + "\x4a\xb5\x1f\xb1\xf7\xab\x8c\x78" +
+       "\x1f\xd8\x4d\x7f\x7e\xcf\x52\x9a" + "\x5e\xc0\x69\x5e\xe1\x2b\x13\xa0" + "\x72\x4d\x0f\x2a\x47\xb7\xda\x90" + "\x06\x67\x2d\x31\x11\xf9\x42\xc1" + "\x8b\x99\x61\x82\x1f\x63\xd3\xe8" + "\x94\x1c\x5c\x61\xae\x2f\xf4\xf0" + "\x5d\xfa\xc3\xae\x8c\x94\x4e\x2f" + "\x1e\x10\x74\xa3\xa8\xe7\x2a\x24" +
+       "\x0b\x61\xde\xc8\x5d\x3a\x89\x0f" + "\xce\x23\xe2\x67\xfb\x15\xc5\xe8" + "\xc5\x6d\xad\x4e\xa6\xbf\x74\x77" + "\x8f\x72\x5c\x92\x95\x0f\xd2\x89" + "\xce\x83\x85\x09\x66\x09\x1e\x7a" + "\xd7\xa7\xf2\x93\x94\xdb\xee\xa2" + "\x4a\x4d\x30\x4c\x97\x20\x28\x1b" + "\x2d\x28\x77\xc0\xda\xe3\x42\x08" +
+       "\x52\xbe\x88\xd0\xca\x78\xa8\x1f" + "\x56\xe6\xe1\xa9\x07\xcb\xc2\x89" + "\xdb\x62\x9d\x21\xc3\xc5\x5b\x38" + "\x52\x27\xda\x5f\x6b\x67\x2b\xd8" + "\xfc\xea\x04\xe3\x9e\xdc\x49\x24" + "\xa2\x4e\x2f\x63\x91\x79\x9e\x1e" + "\xb9\xe0\xd5\xcd\x61\xe0\x36\x30" + "\xbc\x25\x08\x83\xff\xf6\xa6\x75" +
+       "\x9b\x5e\xf6\x81\x04\x26\x5b\x2e" + "\x37\xf8\x01\x49\xc0\x56\x01\x48" + "\x33\xb7\x57\xb8\xab\x86\x7f\x55" + "\x11\x44\x5b\x73\x0e\xed\xe3\x88" + "\x2e\x73\x33\x2a\x0d\x68\x37\xc3" + "\x1f\xc1\xc9\x31\xcb\xbf\x99\xa5" + "\xc4\x01\x52\xa9\x51\xf8\x82\xb2" + "\x95\xdf\x4d\x85\x8a\xda\x42\xd3" +
+       "\xb4\xed\x9d\x44\xdc\xcd\x0f\xb1" + "\xcf\x4a\x24\xd1\x42\x00\x89\x2c" + "\x17\x70\xfc\xc7\xca\x72\x30\x9b" + "\x3f\x06\xe8\x9c\x85\xa6\xcd\x1a" + "\xf5\xe2\x51\x7f\x3c\x31\x43\xd2" + "\x78\x95\x3d\xd7\xa4\xf1\xa3\x52" + "\x6e\xce\xf0\x64\x7a\x5b\x78\xda" + "\x2d\x4c\x2a\x44\x15\x63\x76\x2e" +
+       "\x7b\x2d\x9e\x3b\xa3\x72\xd9\xe4" + "\xff\x18\x82\xc4\x27\x0b\xc6\x7c" + "\x91\x9d\x14\x84\x38\x08\xc7\x8f" + "\xcc\x1e\x46\x2f\x6f\x34\x04\x5c" + "\xa9\x50\x46\x61\xf2\xfd\xe9\xeb" + "\xac\x66\xf6\xc1\x37\xb5\x35\x5e" + "\x83\xbc\xba\x88\xd1\x13\x56\x64" + "\x3e\xc9\xe1\xc5\x3a\xce\xca\x88" +
+       "\x1a\x11\x1f\x15\x04\xb0\xf9\x94" + "\xfa\xc5\xdb\x07\x5b\x03\xa5\xc7" + "\xd7\x49\x9e\x60\xa7\x8e\x95\x53" + "\xc0\xf4\x13\x90\xd7\xb4\x26\x05" + "\xbd\x2f\x3e\x59\xbb\x5e\xde\x66" + "\x37\x0c\x2e\x4c\xb4\xf8\x7c\x6e" + "\x78\x3e\x98\x8c\x8b\xfc\x72\x6f" + "\xd7\xf9\x48\x23\x63\x9b\xab\x6f" +
+       "\x59\xac\x70\xeb\x81\x2e\xd0\x58" + "\xf7\xd8\x17\x44\x9b\x76\x22\xf5" + "\xff\x74\x72\x07\xd5\x63\x30\x9f" + "\xac\xe8\x0f\x34\x4f\x6f\xac\xf5" + "\xba\x14\x09\xb5\xd1\xd9\x72\xce" + "\x5c\x25\xbc\xb7\x84\x59\x83\xb3" + "\x8f\x03\xa5\x7c\xa7\x3f\x5d\x14" + "\x13\xab\x8f\xad\xc6\xa3\xcd\x7a" +
+       "\x68\x84\x3d\x6a\x52\xa3\x48\xc7" + "\x32\x80\xe3\x27\x99\x47\xab\x3f" + "\xe7\x0c\x43\xfa\x29\x36\xad\x91" + "\x44\x4c\x61\x71\x2c\x0b\xaf\xc5" + "\x11\x16\x21\x0c\xa5\x3f\xde\xce" + "\x83\x80\x33\x02\xba\x89\x68\x6e" + "\x32\xfe\xf0\x77\x59\x19\x0a\xee" + "\x5a\xbc\x4b\x0f\x5d\x90\xea\x01" +
+       "\x23\x2e\xe9\x3d\x75\xa3\x9c\x20" + "\xe3\xb6\xbb\x5f\xc8\x3c\xb0\xcc" + "\x7e\x48\xb1\xd7\x03\x0f\xb9\xcc" + "\x1f\x94\x10\xc7\x38\x2a\x9c\xfa" + "\xed\xce\x24\x67\x23\x38\x6c\x75" + "\x23\x03\x2d\x19\x58\x22\x90\x3a" + "\x8e\x03\x5e\xea\x19\xe5\x50\xb1" + "\x91\x75\x42\xc7\x65\x28\xba\xdc" +
+       "\x48\xdb\x93\x81\x5e\xb2\xcf\x12" + "\x8c\x70\xea\x3b\x63\xae\xb4\xdd" + "\x21\xf8\x81\xf1\x2e\x10\xae\xda" + "\xd9\x89\xa0\x24\x30\x92\x9d\x9d" + "\xea\x6a\x87\xa0\x2d\x12\xc4\x71" + "\x09\x9c\xe1\xbb\x3b\xea\x63\x1a" + "\x0c\x8d\x6f\x01\x76\x80\x89\x3b" + "\x13\xb7\xa6\xae\x5d\xcc\xcc\xa5" +
+       "\x7d\xe9\xf6\x06\xe3\x8e\x0e\x51" + "\x8c\xaa\x0e\xb0\xc5\x8f\x4a\x68" + "\x33\xbf\x3f\xb9\x79\x35\x31\x15" + "\x23\x17\x6b\xf6\xa6\x5f\x7f\xe6" + "\x8c\x74\x86\xce\xf6\x81\x58\x81" + "\x10\x8b\xd5\xea\x18\xd3\xce\xc1" + "\x93\x33\xf3\xf2\x5b\x77\x62\x86" + "\xf2\x6f\x83\x7d\x04\xc9\xc0\x7a" +
+       "\x61\x2f\x8e\x4a\xaf\x2b\xf2\xc3" + "\xa6\xa6\x6d\x17\xde\x9e\xd2\x77" + "\x63\xda\x07\x16\x21\x5f\xa5\x40" + "\x91\xe3\x52\x14\x56\x38\x8b\x85" + "\x56\x3c\x1b\xfe\x67\xc2\xd3\x0d" + "\x7a\x22\x55\x7d\xdd\x4b\xc0\x66" + "\x09\x4e\x40\xe6\x55\xfe\xd2\xfb" + "\xbc\xfc\x9c\xea\x49\xcf\x81\x59" +
+       "\x32\x07\x89\x78\x7f\x23\x49\xe5" + "\xd9\xb4\xfc\x53\xf9\xbe\x43\xc4" + "\xd6\x80\x34\xeb\xa6\xd8\x84\x98" + "\x86\xb1\x48\x30\xa1\xb6\x35\x8a" + "\x0a\xa9\xe9\x65\x16\x47\xe4\xb4" + "\xc0\x06\x30\x65\x0d\x38\xbf\x45" + "\x3b\xae\xe9\x4f\x0d\x82\x3f\x8f" + "\x71\x3b\x9a\x97\xa0\x35\x4a\x24" +
+       "\xaf\x70\xa8\xae\x02\xa9\x46\xae" + "\x99\xdc\xbe\x7c\xf5\xfc\xb9\xa9" + "\x93\xe7\xb7\x79\x3f\xca\xf2\x74" + "\x28\xeb\xbe\x1d\x23\xf2\xb8\xad" + "\x85\xdf\x64\x67\x0e\x06\x02\x63" + "\x54\xd5\xeb\x57\xd2\x20\x33\x36" + "\xe1\x22\x8d\x79\x3e\x57\xfd\xd9" + "\xed\x7d\xb6\xeb\xf5\x85\x5f\x28" +
+       "\xc9\x55\xeb\x8a\x13\xd6\xac\x0a" + "\xf0\x85\x68\xd8\xa4\x1d\x79\x79" + "\x23\x5f\xb0\x44\x67\x82\x5e\x16" + "\xed\x48\x45\x28\xe8\xf5\xe5\x9e" + "\xb8\x61\xb6\x85\xcc\x48\xd5\x9f" + "\x89\x86\xc5\x89\xc0\x37\x70\x25" + "\xb2\x0c\x29\xf9\x6f\x30\x47\x9b" + "\xf4\xec\x77\x06\xeb\x2e\xba\x56" +
+       "\xb5\xa2\xca\x11\x92\x32\x6b\xd8" + "\xd1\x7b\x33\x39\x8e\x25\x26\x2a" + "\x91\xc2\xc8\x79\xb5\xa9\xc5\x4d" + "\xe6\x42\x19\x74\x87\x3d\x44\x16" + "\x0c\x40\x11\xf8\xf8\xa2\xc9\x6b" + "\x0e\x4e\xeb\x9e\x35\x69\x9c\x81" + "\x4b\x21\x0c\xce\x73\x72\xbe\xe1" + "\x81\x15\xb6\x84\x81\xfb\x9a\x42" +
+       "\xff\x06\xcd\x74\x9d\x0e\x01\xa1" + "\xac\xee\xa3\xac\xdf\xc7\x17\x9c" + "\x2b\xaa\x63\x80\xd3\x6c\xc8\x74" + "\xff\x14\x46\x73\xb3\xc4\x95\x85" + "\xcc\x62\x0f\x99\xca\x00\xde\xa3" + "\xe5\x3b\x0c\xca\x13\xd2\xbe\xd9" + "\xf5\xe9\x8c\xdf\x8a\x07\x86\x78" + "\x44\x44\xd4\x5c\xe3\x7c\xb2\xdd" +
+
+       "\x82\x83\xee\x26\x1d\x58\x7c\x9c" + "\x8e\x63\x9d\x35\xc5\xdc\x17\xcf" + "\x3d\xae\x28\xb7\xab\x73\x82\xee" + "\x47\xf0\x21\xf8\x26\x29\x11\x1d" + "\x74\x1a\x49\x50\x77\x84\x49\x11" + "\xb9\xdf\xe0\xfd\x61\xa7\x7f\x68" + "\xab\x35\xa4\x7e\x22\x80\x25\x2c" + "\x3f\x7e\xce\x91\x94\xdb\x8b\x6b" +
+       "\x56\x2b\xfb\x53\xa5\x03\x3a\xb2" + "\x78\x7f\x05\x4e\xe7\x41\xe1\x6c" + "\xd9\x90\xe4\x89\xc3\x25\x65\x79" + "\x75\x7e\x1a\xa3\x25\x57\xc9\x0b" + "\x06\xfd\x20\x12\x91\x67\xc5\x1e" + "\xd6\x0b\x8b\x40\x3c\x3a\x6e\x71" + "\xa9\xeb\xeb\xe8\xf7\x6b\xcd\x31" + "\x70\xb6\xe6\xbe\xa6\x6c\x32\xa7" +
+       "\xd7\x41\xf2\x99\x56\x35\x95\x60" + "\x9d\x34\x1a\x00\xd7\xdb\x4a\xee" + "\x91\xe4\x89\xaa\x6a\xbf\x35\x0b" + "\x46\x75\x6f\x13\xf4\x76\x00\x7f" + "\x3d\xda\x64\x92\xba\x18\x9a\xd1" + "\x8b\xa2\xa7\x62\xcd\xd2\xb2\x6e" + "\x71\xc9\x61\x87\x1f\x94\xba\xcd" + "\x5d\x4a\xbe\xa3\x8b\x51\x50\x15" +
+       "\xd2\x62\x7d\xcf\x82\xc9\xd3\x20" + "\x50\x81\xba\x23\x9d\xe2\x36\x1f" + "\x9e\x3f\x76\x92\xf0\x0b\xae\x48" + "\x07\x70\x3a\x1d\x6b\x7e\x52\x7a" + "\xe3\x85\x1a\x58\x97\x90\xa8\xb4" + "\xe5\x8b\x15\xdc\x0f\x52\x1a\x1f" + "\x6e\x72\x7d\x16\x7d\xb3\x8d\xf9" + "\x62\xe8\x13\x11\x6e\x78\x02\x88" +
+       "\x18\xfc\xce\x6b\x96\x98\xc3\xc3" + "\x00\x6e\x63\x18\x43\xb3\x54\xb7" + "\x91\x19\x3b\xf5\x68\xa1\xb6\x6f" + "\xe5\x2f\x4c\xb8\x55\x1b\x18\x87" + "\x8c\xbc\x21\x27\x10\xc9\x86\x16" + "\x2a\x0e\x03\x95\x60\x06\x49\xc6" + "\xda\x55\xdf\x97\x2f\xeb\xfd\x18" + "\x31\xd2\x27\x7c\xfc\x2c\xd5\x10" +
+       "\xb9\x31\x87\x11\x9c\xe0\x01\x2a" + "\xd8\x3c\x39\xcd\x82\x61\xc4\xb6" + "\x28\xe3\x08\x75\x65\xdd\xd7\x5e" + "\xfa\xa8\x1d\x68\x1b\xca\x02\x64" + "\x2d\x27\x9f\xce\x86\xbe\x3a\x60" + "\x9c\x7c\x16\x29\x5c\x43\x63\x93" + "\x42\x2a\x5a\xc4\xc1\xf7\x14\x48" + "\xcd\xca\x22\x9a\x22\x62\x65\x14" +
+       "\x0c\x47\x3b\x32\x31\x64\x52\xb4" + "\x18\xe4\x36\xd5\x1a\x4e\xcd\x40" + "\xc0\x3b\x93\x01\x3d\xdd\x0f\x43" + "\x23\x90\x64\x07\xde\x6d\x3e\x3d" + "\xb1\x23\x95\x2e\xef\x64\x05\x4b" + "\x4f\xbc\x79\x90\x05\x31\x0d\x8c" + "\x58\x3d\x7d\x83\x67\x69\x6c\x49" + "\x5f\x3b\x12\x89\x60\xf6\x79\x3a" +
+       "\xb0\x9a\xf0\x36\x9e\x14\xb2\xef" + "\x5b\xbb\x10\x4a\xca\x63\xf1\x03" + "\x98\x09\xe2\x06\x45\x70\x29\xd0" + "\xab\x3b\x5a\x1b\x00\xaf\xf0\x56" + "\x0d\x0e\x88\x70\xec\xcf\xf4\x7a" + "\x3f\x91\x3d\xbe\x6f\xa6\x32\x73" + "\xbd\xb4\xce\x7e\x4a\xc8\xe6\x32" + "\x55\x8f\x22\x9c\x9a\xa7\xc4\xed" +
+       "\x9a\x69\x2f\xa3\x9e\x14\x99\x29" + "\x70\x61\x18\x72\x11\x8e\x6c\x6d" + "\x52\x6e\x54\x45\x4f\x49\x74\xad" + "\xfe\xe7\xef\x89\x39\xb5\x3c\x2b" + "\x31\xb0\x2f\xe4\x0e\xe6\xa2\xb9" + "\x23\x48\x0e\x67\x0d\xfd\x58\xf8" + "\x6d\x63\x2c\x49\x7e\xab\xca\xeb" + "\x70\x46\x2c\xd3\xfc\x72\xe0\x40" +
+       "\x1d\x4e\x34\xb2\x66\x6a\x7a\x45" + "\xfe\xdc\x37\x8f\x2a\x1f\xc8\xde" + "\xd5\xf9\x40\xab\x3e\xf8\xd5\x61" + "\x3c\x04\xdf\xf1\x76\x27\xa8\x5c" + "\x7c\x67\x46\xf8\x1e\x68\x74\x21" + "\x28\x16\x6d\x51\x4f\x1f\x24\x7c" + "\x4f\x37\x01\x1f\xc3\x94\x49\xf5" + "\x0c\x21\x0f\xdf\x67\x83\x3c\x25" +
+       "\x20\x18\xe9\x20\xeb\xbe\x4d\xc9" + "\xe7\x41\xb6\x62\x04\xc2\xaa\x19" + "\x50\xcf\x49\x8b\xf0\x34\x28\xc2" + "\x6d\x5a\x5d\x8e\x4b\xc7\xe8\x47" + "\x6a\xcb\x2a\xf4\xdc\x0c\x16\x78" + "\xb9\x68\x35\x3a\x75\x64\x53\x7a" + "\x71\xeb\xd1\x6c\x47\xd5\x28\x4a" + "\x11\xbc\x8f\x8c\x3f\xbc\x60\x03" +
+       "\xec\xb6\xc6\xf4\xd1\x94\xe8\xf6" + "\x9b\xcd\xb3\x18\x27\x08\x6b\x52" + "\xbf\x7f\x11\x12\xa8\x52\xf9\x73" + "\xf5\x5b\x94\x11\xb0\x64\xe8\x2b" + "\x64\x9b\x09\x42\xa5\x8e\xf1\x86" + "\xe2\x8c\x54\x07\x8a\xb2\x70\x27" + "\x9c\x1c\x5c\x29\x28\x0f\x39\x97" + "\xc3\x06\x52\xcb\x43\x6a\x2e\x67" +
+       "\xf8\xda\xba\x8e\x73\x2b\x50\x66" + "\x07\x4c\xa0\xf9\x8e\xfe\xba\x27" + "\x04\xae\xf6\x1b\x2f\x43\xda\x74" + "\x3b\x40\x8d\x27\x68\x82\x1d\x27" + "\x57\x1b\x47\x93\xac\x91\x8b\x01" + "\x1f\xc5\x76\xb2\x69\x68\x09\x01" + "\xd2\x7d\xc5\x6d\x01\xc1\x79\x5b" + "\xa5\x80\x6c\x80\x5e\x34\x23\xb6" +
+       "\x88\x20\xd7\xe9\x49\x43\xd2\x89" + "\xe0\xf6\x9c\x3e\x03\x7a\x31\xd5" + "\xea\xf8\xc8\x73\x9d\x1a\xc6\x5b" + "\x3d\x5a\x0f\xf1\xc8\xc2\xf9\x48" + "\x07\x95\x6b\x08\xdf\x14\x24\x47" + "\x92\x9b\x54\xae\xdf\x8c\x81\x79" + "\xbf\x15\xa4\x62\x7a\xa7\x24\x3d" + "\x76\x29\xb2\xd3\x9f\xf5\x2d\xb9" +
+       "\x44\xcf\x1f\xe7\x8e\x0f\x45\x80" + "\x86\x99\x0a\xdb\xfd\xdd\x63\x27" + "\xf2\xbc\x68\x96\x7a\x8c\x28\x8c" + "\xf6\xe2\x92\x03\x35\x9b\xd0\xd7" + "\x7a\xdd\x06\x65\x82\x54\x3d\x0a" + "\x4f\x9d\xce\xcd\xc1\xda\x43\x9b" + "\xb8\x63\x8b\x45\x61\x4f\x15\x8d" + "\x3b\x97\x9c\x12\xd0\xa4\xbd\x77" +
+       "\x96\x44\x5c\xc5\xd0\x7d\x7c\xc3" + "\xd2\xab\xbb\x25\x57\x63\xa9\xa6" + "\x63\xf3\xd7\xad\xf2\x63\x7e\x5b" + "\xdf\xf1\x73\x2e\x82\x37\xce\x9d" + "\x71\x1f\xb9\xb2\x6a\xa1\xe5\xe1" + "\x3c\x16\xa0\x5b\x23\x98\x48\xe4" + "\xad\x15\xe5\xf6\x32\x9c\x75\xf2" + "\xcf\xee\x15\x86\xf8\xf1\xe2\xa5" +
+       "\xce\xab\xa6\xeb\x19\x0d\x6c\x0b" + "\xe4\xee\x9e\x64\x45\xc4\xaa\x6c" + "\x0e\xe1\x65\xb4\x83\xf2\xb4\x59" + "\x2d\x21\x29\xf7\xf2\x04\x67\xd7" + "\x92\xee\xd1\x70\x83\x73\x4e\x8d" + "\xb5\x1e\x6c\xea\x8b\xc2\xca\xfb" + "\x05\x8e\xf2\x4e\x8b\x21\x84\x2c" + "\x0d\x6e\x6c\x7e\xd0\xf7\x52\x2c" +
+       "\x16\x96\xe0\x0f\xf0\x4c\x13\xd8" + "\xc3\x8c\x8c\xe4\x9a\xe5\x31\x4a" + "\x82\x7b\xb8\x5f\x66\xe5\x0a\x5c" + "\xa7\x26\xbd\xb2\x5a\xf1\x2e\xdc" + "\x65\x17\x78\x5b\xf5\xae\xeb\x63" + "\x5e\x58\x39\x53\x3c\xc8\x6c\x4f" + "\xe4\x78\xfc\xab\x01\xe2\x8a\xd0" + "\x56\x2a\xbe\x1f\x9a\xee\xe7\x98" +
+       "\xa2\x89\x14\x0e\xdd\x97\x48\x0a" + "\x7f\x98\x3d\xe9\x36\x87\x9f\xc0" + "\x37\xa4\x79\xea\xb8\x00\x7a\x42" + "\xfa\xe9\x89\xaf\xe4\x39\x2b\x3e" + "\xf1\x38\x81\x7e\x2f\x2d\x1c\x45" + "\xb0\x8b\x14\x37\x11\xe4\xcd\x08" + "\x41\xe5\x50\x0d\xc7\x68\x69\x01" + "\x91\x12\x47\xdd\xe1\xee\xdc\x2b" +
+       "\x67\x43\xc6\x47\xc8\xe2\xcc\xca" + "\xc0\x4e\xaf\x45\x9f\x6b\x49\x6a" + "\x2c\x04\x34\x60\xf3\x36\x08\x2a" + "\xea\x62\x6c\x0b\x90\xf3\xa1\x14" + "\x40\xf5\xf1\x3e\x63\x93\xfa\xe7" + "\x93\x6d\xa7\x72\x0a\xb3\x23\xd3" + "\x51\xe4\xea\x0f\xb5\xc8\xee\xff" + "\x87\xef\x04\xbd\x72\xc1\xaf\x4e" +
+       "\x07\x40\x48\x6c\x1b\x1e\xdb\x3b" + "\x02\x02\xbe\xe6\xa1\xd5\x10\xe1" + "\xae\x5a\x66\x15\xae\xe1\x24\x1c" + "\x27\x9d\x9c\x7c\x89\xf6\x0e\xfa" + "\x07\xb6\x22\x9d\x2a\x66\xa0\x01" + "\x47\xf1\x22\x67\xce\x64\xc3\x18" + "\x4c\xf7\x21\x75\x6d\x14\x46\x04" + "\xb8\xab\xa8\x9f\x4e\x7a\x77\x39" +
+       "\x27\xe4\xea\x8d\x0c\xb3\xa7\x36" + "\x3e\x58\x2e\xb6\x5a\x5f\xac\xb4" + "\xa9\x39\x0a\xdf\xa2\x9f\xef\xac" + "\x39\x90\x65\x5d\x04\xa6\x29\xc9" + "\x7e\x2f\x26\xfc\x6e\x9d\x4d\xe1" + "\x9d\x8d\x53\x05\x2d\xd6\xe6\x15" + "\xe0\xf9\x88\xc4\x7e\xa7\x42\xee" + "\x42\x8a\x2c\x89\x65\x63\x83\xae" +
+       "\xfd\x33\xf5\x1a\x1b\xdd\xab\x90" + "\xcb\x0a\x0f\x75\x76\x25\x3d\x7c" + "\xc8\xc9\x6c\xc7\x5a\xc5\x0a\xfa" + "\x05\xaa\x75\x52\x2e\x30\xb4\xc3" + "\x9e\xc1\x2d\xef\x1d\xb3\xcb\xe2" + "\x7b\x35\x06\x38\x51\xb7\x3d\x5f" + "\x8e\xf9\x09\xf5\x00\xdf\x74\x64" + "\x89\xbd\xeb\x28\x1e\x5f\xa7\x9b" +
+       "\x51\xd5\xde\xab\xe7\x9b\x51\x74" + "\x10\x44\xb7\xc8\xb8\x58\xd3\x03" + "\xa9\xd9\x10\x0e\x0b\xb1\x00\x4d" + "\xb7\x52\xda\x28\xb1\xb0\x92\x63" + "\x04\xc9\x75\x0b\x98\xa2\x44\x67" + "\x6c\xf9\xf7\xa8\xae\xb0\x05\xc3" + "\x32\xf9\x2c\x18\x1d\x42\x2e\x04" + "\xca\x36\x46\x9e\x50\x5d\xfc\xf6" +
+       "\xdf\x76\xd6\x5f\xe0\x1f\xcb\x47" + "\x0b\x96\xa8\x9b\x91\x42\xc6\x69" + "\x6d\xde\x65\x01\x06\x23\xd0\x40" + "\x9a\xb2\xb8\xd6\x4e\xf4\x3b\x78" + "\xbd\x98\xd0\x6e\xfb\x19\x4e\xc8" + "\x23\x61\xbe\xff\xf7\x09\x1f\x60" + "\x3a\x4a\xe2\xa0\xc5\x89\xae\x87" + "\x2a\xac\x05\x5e\x9c\x4e\x86\x07" +
+       "\x00\x5e\x2c\x39\xfd\x9e\x0f\x85" + "\xde\x1b\x51\xe2\x7f\x66\x9f\xc2" + "\x8f\x29\x31\x84\x6d\x40\xcf\xf5" + "\x5d\xd0\xc0\x79\xc8\x10\x0b\xf9" + "\x12\xf0\x38\x00\x1d\x9b\x3e\xfb" + "\x99\x97\x8c\x0a\x7a\x4e\xc0\x84" + "\x86\xe9\xc8\x96\xd4\x02\x61\xb7" + "\x75\xa6\x6d\x17\x13\x3b\xa6\xde" +
+       "\x69\x53\xf5\xdd\xef\xc2\xaf\x2f" + "\xb9\x63\xac\x24\x6f\xf0\xbf\x70" + "\xdd\x6a\x92\x6e\x42\x37\x1a\x1e" + "\xcf\x18\xfa\xfd\xad\x37\x35\x77" + "\x52\xb5\x84\x59\x63\xea\x11\xd2" + "\x24\xed\x1a\x8c\x4d\xed\x7e\xb1" + "\x67\x8b\x0b\x14\x74\xde\xe9\x5d" + "\x57\xff\x8b\x76\xc8\x01\x25\x74" +
+       "\x89\x9b\xe5\xb3\x51\x5a\x43\xe4" + "\xc9\xa1\x33\x41\x55\x39\x61\x13" + "\x59\xee\x0b\x44\x73\x69\xf4\x87" + "\xe4\x01\xc4\x00\xf8\x10\x47\x71" + "\xc9\x46\xc4\xd6\xce\x4b\xcf\xc0" + "\x68\x53\x4d\x6c\xd6\x7f\xaa\xe0" + "\x37\xfc\x68\xfc\x1a\x81\x5d\xde" + "\x57\xa0\xc2\xb7\x72\xbd\xfe\x61" +
+       "\xe8\x25\x47\xbe\x91\x2b\xff\x90" + "\x1e\x00\x81\x5e\xf6\xbf\x0a\x71" + "\xf3\x04\xef\xc5\x76\x34\xeb\x15" + "\xb7\xa2\x0d\x3c\x1b\xb5\xda\xcc" + "\x2b\x65\xc0\x2c\xa5\x40\x38\x88" + "\x56\xa8\xe4\xf5\x9d\x7d\xfc\xd1" + "\x88\xfc\x0f\x07\x53\x39\xbc\xeb" + "\xc1\xed\xef\x91\x7d\x94\x0f\x34" +
+       "\xcf\x11\xbd\x6d\xbb\xbe\xdd\x1e" + "\x03\xe2\x19\xc6\x45\xaa\x97\x82" + "\xa6\xd2\x2b\x96\x6f\x82\x54\x63" + "\xc7\xed\x12\xfa\x67\x3f\x3f\xba" + "\x8d\xd8\x7a\xfc\x1d\x0f\x22\x25" + "\x01\xc8\x83\x86\x81\x9f\x05\x5d" + "\x64\x57\x38\x2d\x6e\xf2\x77\x05" + "\x0d\xe8\x53\xa4\x46\xc6\x74\xa5" +
+       "\x0c\xe3\xf4\xb8\x71\x6c\xd1\x89" + "\x29\xfa\x3d\xc6\xfb\xab\x2d\x9e" + "\xeb\x5c\xde\xdf\x5e\x06\x33\x60" + "\xc6\x45\x3c\x0f\x1f\x1d\x2b\x07" + "\xec\x29\xd4\xb8\x2a\xbc\xd0\x0c" + "\x89\x1f\x47\xc2\x8c\x43\x47\xe7" + "\x9e\x67\x9d\x31\x56\xe8\x1c\x13" + "\xba\x4e\xb2\x87\x28\xa2\x20\x75" +
+       "\x8c\xc7\x4c\xd6\xc9\x47\x58\x79" + "\x7b\xb2\x6c\x9b\x1b\x62\x50\x6c" + "\xab\x22\x80\xdf\xf8\x9b\x09\x07" + "\x1d\xda\x4e\xc0\xeb\x62\xf8\x48" + "\x16\x3c\x60\xe1\xed\x32\x27\xd1" + "\x50\x94\x9a\x5c\x0f\x0e\xa8\x19" + "\xfc\xb4\x29\xb4\x54\x7f\x25\xe2" + "\x15\x05\x46\x45\xc6\xb2\xd3\x66" +
+
+       "\xd6\xad\x3c\x45\xbc\xb7\xe2\x8d" + "\xf8\xc1\x0b\xbc\xa7\x00\x39\x20" + "\xaf\xd3\xab\xa6\x47\x6e\xd8\xbc" + "\xfb\xef\x02\x85\x12\xac\x1c\x91" + "\x69\x54\x96\xec\x42\x02\x55\x2d" + "\x7e\x01\xe0\x29\x92\x76\x9f\x0e" + "\x85\x98\x97\x65\x8f\x07\x3f\x63" + "\xef\x51\xf7\x4c\x49\xd4\x87\xfb" +
+       "\x10\xee\x51\xd5\xa2\xe2\x66\x60" + "\xa6\x09\x7e\x72\xd8\xf1\xa8\x87" + "\x8d\x14\x01\x2c\xab\x8b\xd0\x00" + "\xfe\x33\x4f\x42\xf1\xe4\xa8\x6d" + "\x71\x4e\x9a\xcf\xf0\x17\x6d\x46" + "\x19\xcb\xf5\x3b\x10\x20\x50\xff" + "\xc0\xec\x62\xd0\xd8\x97\xcf\xdc" + "\xc4\x0a\xd8\x81\xaf\xd9\xc0\x80" +
+       "\xab\xad\x7a\x1d\xff\x45\x04\x1a" + "\x7c\xa6\xf6\xd5\x60\x82\xd3\x65" + "\x6f\xb2\xcf\x91\x08\xfb\x62\x6e" + "\xd6\x91\x7d\x5c\xa5\x0f\x1e\xef" + "\xcd\x72\xdb\x33\xba\xc7\xe7\x47" + "\xb2\x74\x7c\xfa\x09\xbc\x7c\x01" + "\x3c\x50\x0a\xf5\x90\x15\x93\x3c" + "\x42\xaa\x6b\x61\x60\x4f\xc5\xca" +
+       "\x1c\x58\xf4\x1b\xeb\x7c\x85\x98" + "\x66\xb1\xa7\xac\x86\xe1\x35\xe6" + "\xac\x22\x97\x65\x22\xdd\x8d\x27" + "\x07\x80\xb6\x1d\x4c\x3c\x90\xa0" + "\x02\x14\xf2\x48\x89\x45\x6e\x36" + "\xa2\xbd\x6a\xb9\x14\x9c\xb4\x31" + "\x90\x31\x40\xe0\x09\x4b\x9c\x32" + "\xfe\x43\x9f\xd2\xa3\x7c\x19\x97" +
+       "\xb1\xe2\x07\x4b\x5d\xdd\x73\x71" + "\x21\xa2\x9e\x8d\xcb\xc4\x44\xd1" + "\x14\xab\x05\x11\xa4\x4e\xb0\xe8" + "\xf1\xd8\x80\xfe\x42\xa5\xdd\x92" + "\xe6\xdc\x03\xcf\xa8\x2f\x98\xe9" + "\xfc\xcf\x22\x1a\x65\xa9\x5e\x8b" + "\xc4\x88\xad\x3f\x7f\xea\xf4\xf7" + "\x5c\xa9\x5b\x6a\x3e\x77\xdb\x62" +
+       "\xc7\x57\x03\x82\xb4\x3f\xbd\x18" + "\xad\x58\x14\x6f\xae\x39\x20\x99" + "\xa1\x4a\xb4\x25\xc5\xf3\x1d\x9a" + "\x81\x52\x3d\xed\x57\x03\x78\x2d" + "\xd4\xd4\x7a\xc7\x4d\x7e\xcf\x58" + "\xc4\x4f\xdf\xf9\x98\x79\x9a\xd4" + "\x5e\x20\x71\x1d\xb5\xa8\x65\x44" + "\xaa\x54\x92\x64\xa6\x0e\xee\xa0" +
+       "\x35\xb2\x92\x9c\xe8\xe6\xaa\x4b" + "\xa1\x93\x39\x6b\x0e\xbd\x3b\xa7" + "\x31\xd0\x3d\x69\xec\x60\x6d\xd0" + "\x1c\x88\x56\x71\x1b\xb9\xca\x03" + "\x4b\x57\xb3\x1d\x2f\x86\x15\xd6" + "\x1a\x06\xbb\x64\x85\x01\x5b\x48" + "\x06\x1e\x18\xa0\x88\x49\x43\x27" + "\x57\xc7\xc0\xc1\xd4\x1a\xd6\x2c" +
+       "\x4a\x0d\x48\xf3\x1c\xde\xe2\x03" + "\x1a\xcf\x8a\xbc\xc7\xed\xd8\xf0" + "\x9c\x5a\x29\x68\x03\x33\x3e\xf2" + "\x7d\xa9\x46\xc5\x68\x5f\xdd\xfa" + "\xb1\xac\xf8\x96\xad\x97\x55\x89" + "\xe2\xda\x1b\x67\xd5\x49\xdd\xbd" + "\xf4\x43\xdd\x21\x28\xd5\xfc\x16" + "\x1a\x14\x19\x66\x12\x54\xa4\xa5" +
+       "\xa0\x86\x0d\x03\xd3\x34\x5c\xc8" + "\x5e\xe9\x3c\x21\x80\x2e\x4b\xf1" + "\x7f\x6d\x7e\xf0\x9b\xed\x3e\xce" + "\x79\xec\xa3\xa3\x21\x3e\x6c\x47" + "\xd3\xa5\xde\xca\xf2\x11\xec\xb4" + "\xaa\x36\xa9\xcc\x12\x5f\xad\xd1" + "\x7d\x1c\xe6\x34\x9e\x60\x24\x17" + "\xa2\x7b\xd6\x2f\xf3\x0d\x52\xcc" +
+       "\x2a\x7f\xa1\xa9\xa8\xe2\xfb\x6b" + "\x17\x50\xd9\x03\x60\x2f\xac\x1c" + "\x8c\xb4\xa2\x8e\x57\x62\xc0\x38" + "\x8a\xc3\x3c\xcc\x5c\x4d\xca\x21" + "\x91\x20\x45\x67\x54\x7a\x06\xff" + "\x2c\x46\x9d\x13\x5d\xdf\xbf\x63" + "\x6f\x00\x50\x14\xa1\x76\x13\x22" + "\xec\x9a\x2a\x33\x5e\xfe\x1a\xc8" +
+       "\x41\xa1\xfe\xba\x99\x9a\xa0\x11" + "\x40\x16\xd4\x19\x4b\x41\xe0\x7f" + "\xd1\x09\xb6\xf3\x2a\x07\x6b\xd6" + "\xd2\x54\x55\xbc\x34\xde\xf7\x27" + "\x45\x7b\x51\xbc\xaf\x29\x65\xd6" + "\x9f\x8d\xd1\x12\x21\x35\xe4\x8b" + "\xd7\xef\x0d\x4e\xe1\x92\x21\x94" + "\x1e\xaf\xc0\x90\x1f\x87\x65\xb4" +
+       "\xcf\x29\x9f\x43\x9f\xc7\x32\xfa" + "\x3b\x2a\xd8\x4d\xc0\x21\xf3\x7b" + "\xb1\xc1\xa2\xea\x54\x7f\x12\xff" + "\x18\x96\x5e\xf3\x2d\x5f\x36\xa8" + "\xdd\xf8\x0e\x4d\x02\x29\x2d\x85" + "\x4a\x8c\x22\x59\xc1\xe2\x5c\x39" + "\xd3\xfe\x5a\x21\xe8\x44\x9f\xb6" + "\xe3\x58\x74\xb2\x98\xf8\xc1\x16" +
+       "\xbc\x25\x3f\xf3\xe0\x87\x0f\x17" + "\x98\xc0\x39\xc3\x67\xb6\xdc\x24" + "\xae\x3e\x07\xab\xa4\x02\x17\xbf" + "\x44\xfb\x8c\x23\x9c\x91\xa6\xad" + "\x75\x63\xee\xdd\x11\x85\x00\x53" + "\xad\x60\xdb\xb8\x85\xfa\x92\xdb" + "\x0e\x21\x21\xa4\x66\xa3\xb6\x50" + "\x8f\x55\x37\x4c\xeb\xf8\x7b\xdc" +
+       "\x7e\x25\x4f\x2e\x08\xa1\x7b\xe4" + "\x7c\x9d\x68\x35\xdf\xe2\x0e\xcf" + "\xd0\xa0\x1b\x32\x8e\xc3\x8f\x8b" + "\x8b\x5e\x74\x0f\x4c\xc6\x70\x94" + "\x2f\xa2\x5f\xd6\xf5\x87\x38\xa7" + "\xbe\xef\xa7\xc2\x9b\xf8\x81\xa5" + "\x8a\xc9\xe4\xee\xa6\x0b\x5a\x83" + "\x71\x1a\x29\xa3\xe9\x83\xe1\x86" +
+       "\x3b\x04\xe4\x89\xb0\x87\x54\xfb" + "\xd2\x9b\x79\x09\xef\x9d\xe4\x4d" + "\xbe\x60\xe7\xb3\xc0\x70\xa8\x9d" + "\x39\x15\xee\x89\xd3\x1d\x4e\x5e" + "\xdb\x05\x57\x91\xfa\x49\x38\x1b" + "\x81\x0e\xac\x5e\x94\xe1\xe5\x7c" + "\x5c\x3f\x0d\xb0\xa0\x72\x17\x7c" + "\xa1\xb5\x00\x6c\x76\x26\x79\x54" +
+       "\x5a\xe2\x60\xc3\xbf\xb6\xe9\x8c" + "\x78\x1a\x5a\x07\x95\x51\x42\xe6" + "\xf4\x32\x17\x48\xa8\x56\xc7\x9d" + "\x7a\xb5\x32\x54\x0f\x44\xc0\x83" + "\x1f\x28\x20\xd7\xf1\xb3\x70\xc6" + "\x51\xe0\x35\xd1\x0e\x91\x05\x22" + "\xe7\x2b\x05\xdb\x0e\x4b\xd1\xde" + "\x39\xea\x68\xc5\x27\x3d\x7b\x69" +
+       "\x4b\x71\xf6\x1a\xf1\x6c\x3a\x2e" + "\x6f\xb9\x13\x3c\xa6\x8e\x0f\x77" + "\x95\xff\x8c\x4c\xfb\x42\xc2\x98" + "\x91\xbe\xa0\x95\x0c\x9a\xec\x67" + "\xcf\xe7\x8e\xeb\x5a\x33\xf0\xee" + "\x24\xc4\x71\x33\xe7\x4c\xf3\x63" + "\x05\xe5\xed\x31\x95\x39\x0b\x98" + "\x19\x36\x3f\x9b\xfe\x3a\xe8\x7c" +
+       "\x1c\x4a\x5e\x79\x2e\xbd\xf1\xb3" + "\x89\xca\xcd\xa1\x7e\x18\xd3\x85" + "\x3d\x68\x41\x35\x3c\x4e\xe4\x15" + "\x67\x40\xed\x80\x9c\x23\x8c\x2a" + "\xed\x08\xc5\xbf\x5a\x02\xe6\xbd" + "\xed\xc5\xf2\x3b\x31\x1e\x63\xb1" + "\x12\xa1\xd9\xe7\x3b\x3b\xcb\xb2" + "\xcc\x38\x78\x7c\x4f\xc1\x54\x05" +
+       "\xbf\xe0\x88\xaa\x27\xb7\xe6\x1b" + "\x07\x35\xe8\x64\xba\xc2\x64\xd7" + "\x86\xeb\xd7\xba\x97\xf3\xbc\x4a" + "\x4f\xb7\x20\x79\xbf\x1c\xfd\xb2" + "\x2b\x03\x3d\xf1\x5b\x91\xe8\x65" + "\x22\xd6\xfb\x19\xbb\x4a\x26\x9d" + "\xb4\xa2\x48\x2f\x79\xaf\x62\x2f" + "\xec\xba\x19\x86\x5f\xb0\xa9\x22" +
+       "\x33\x32\x45\xdc\x05\x90\xf2\xde" + "\xcf\x4b\xac\x2f\x7a\xc4\x08\xc2" + "\xac\x55\x3d\xac\xfe\xa3\x57\x60" + "\x07\x12\x2c\x90\x5d\x72\x23\x17" + "\xec\x0f\xeb\x33\x27\xc6\x31\x9c" + "\xbb\x63\x3c\xbb\xdb\xcc\x13\x49" + "\x38\x58\x30\x07\x2b\x54\x3e\x11" + "\x97\x2d\x0c\x31\x2a\xe7\x48\x9d" +
+       "\x58\x6b\x31\xb8\x54\x27\xd5\xc1" + "\x60\xab\x1f\x81\x42\xa3\x35\x94" + "\x35\xc9\x02\x61\x76\xc3\x26\xe1" + "\x2e\x29\x25\x3e\x95\x15\x4f\x7a" + "\x59\xad\x2c\x03\xc3\xe7\xc3\x1b" + "\xb6\x1c\x2a\xfe\x81\x7a\x2d\x4b" + "\xcb\xa6\x8b\xe0\xe2\xf4\x0b\xa8" + "\x68\x02\xf9\x8c\xb2\xc9\xfc\xb7" +
+       "\x96\x82\x28\x51\xa7\xd1\xe2\xa2" + "\xb0\xdb\x6d\xf6\x7b\x52\xca\xba" + "\xd4\x3c\x31\x80\x8f\x41\x9b\x40" + "\x8b\x6a\x3c\x87\xe8\x1a\x4b\x2b" + "\x5f\x29\x93\x2a\xc7\x5e\xe9\xb8" + "\x5f\x79\x5a\x2e\x90\x50\xf6\x0e" + "\xfa\x6a\x87\x2f\x88\xc8\x5a\x16" + "\x03\xe2\xc1\x25\xd9\x87\xca\x90" +
+       "\x36\x79\xce\x93\xa7\x8d\x12\xbc" + "\xf9\x9d\xbe\x39\xd6\x9a\xc6\x3c" + "\x7c\xd3\xb6\xec\x1f\x99\x65\x69" + "\xa3\xff\xb5\xb8\xbf\x01\xe0\x64" + "\x0d\x01\x34\x93\xbf\x0a\x61\x5d" + "\x0c\x3f\xda\xdf\xb0\xee\x8f\x71" + "\xd7\x40\x05\x03\xa8\x1e\x2b\x5b" + "\x37\xd3\xb4\xf4\x73\x2f\xf2\x59" +
+       "\x3d\xeb\xbb\xd9\xc4\x4e\x42\x54" + "\x1c\x92\xb2\xd7\xe3\xaf\xce\x34" + "\xc5\x37\x6d\x29\x2e\x02\x68\x5e" + "\xb0\x16\x9f\x35\x2b\x0a\x8e\xa2" + "\x73\x9d\x3f\xbc\xd9\x2d\xd8\xfd" + "\xff\xe1\xf3\xba\xf9\xa8\x39\x69" + "\xc4\x6d\x73\x31\x5c\xf4\xcf\x55" + "\xe7\xe8\x92\x78\x42\x56\x0f\x91" +
+       "\x2c\x04\xd0\xaa\x05\xbf\x35\xdf" + "\xcc\x6a\xda\x28\x70\xec\x25\x29" + "\x5c\x3f\xaa\xe1\x04\xa8\x2a\x82" + "\x63\x8e\x34\x3d\x7d\xec\xed\xb5" + "\xcf\xb2\xf6\xb4\x30\x28\x36\x03" + "\x2a\xba\x6b\x09\x0d\xcb\xbf\x08" + "\x04\x3f\xec\x9f\x64\xe4\xfd\x8a" + "\x17\x4e\x43\x1c\x4f\x2e\x40\xfb" +
+       "\x26\xc3\xce\x8a\x9d\x6c\xc4\xb6" + "\xc0\xb8\x6c\x29\x3d\x58\xf5\xac" + "\x08\x72\x07\xcf\xc6\xca\x52\x25" + "\xd6\x3d\xa0\x0d\x83\xef\x61\x52" + "\xb4\x46\x00\x5d\x30\xee\xa7\xf6" + "\x85\x3e\x0a\xcb\x96\x5c\x86\x24" + "\x89\x7a\xdf\x8b\x44\x91\x59\x71" + "\x83\x23\xe4\xf8\xdb\x5c\x1d\x22" +
+       "\x09\xdc\x47\x35\xf4\xaa\x1d\x95" + "\xd4\xac\xae\xd4\x0b\xd5\x82\xb9" + "\x56\x11\x9f\x45\x2b\x94\xc9\xdc" + "\x72\xb2\x45\xfa\xe2\xb1\x67\x80" + "\xb7\xfb\xa3\xd6\x0c\xd0\xfb\xe2" + "\x37\x2d\x74\xca\xdd\x24\xfc\x46" + "\xdd\xfb\x26\x7b\x76\x44\x45\x66" + "\x7c\xf6\xd8\x2f\x61\xa3\xa6\x3f" +
+       "\x60\x92\xe3\xdf\x49\xb3\x09\xde" + "\x93\x90\x54\x73\xf7\x12\x46\x98" + "\x02\x3b\x85\x67\x81\xe2\xed\x7c" + "\x03\x77\xd1\x29\xb4\x9b\x80\x7d" + "\xf0\xc4\x56\x27\xfb\x6b\x0b\x45" + "\x80\x2b\xf0\x93\xba\xf9\x9f\xc5" + "\x61\x95\xad\x20\x57\x54\x69\x3e" + "\xc7\xe2\x31\x33\xbe\xf0\x7c\x0c" +
+       "\x03\x48\x9c\xca\x9b\x7c\x72\x42" + "\x5e\xda\xdc\x29\x46\x03\x14\x7c" + "\x17\xf6\x21\xba\x39\xab\xec\x00" + "\xc1\xef\xba\xf0\x96\xb1\x2b\xb5" + "\x74\x1c\xac\x73\xde\x03\xd5\x56" + "\x2c\x9d\x9c\x53\x0f\xce\x2d\x08" + "\x87\x95\x3c\xfa\x8a\x0a\x77\xf7" + "\x7d\x7e\x5c\x59\x7a\x5a\x89\x96" +
+       "\x47\xfb\xfa\x6e\xd2\x69\xdb\x29" + "\x29\x74\x5e\xee\xf2\xe9\xb9\x04" + "\x03\x02\xe9\x88\x38\x1d\xf2\x91" + "\x15\xa6\xdf\x7a\x79\x8e\x3f\xcf" + "\x37\xe7\xeb\x61\x1c\x12\xf9\x89" + "\xbd\x03\xba\x06\x06\x69\x59\x87" + "\xb7\xfe\x78\x97\x72\x7a\xc2\x1a" + "\x18\x60\x72\x34\x3c\x72\x18\xe0" +
+       "\x7e\x93\x70\xfc\x86\xcf\x42\x7c" + "\x05\x8f\x11\xa1\x75\x33\xf8\x5b" + "\x98\xbf\xe9\x39\x13\x54\xc0\x11" + "\xf9\x08\xfa\xac\x04\xf3\xa2\x4a" + "\xb3\x6f\x8b\xda\x1a\x4d\x61\xd6" + "\x0b\xad\x05\x5b\x77\x3b\x73\x92" + "\x66\xdd\x15\x30\xf1\xd5\x8e\xcf" + "\x32\x0a\x15\xd8\x18\xef\xad\x1b" +
+       "\xed\xf9\x3f\xfb\x9a\x9b\x59\x2e" + "\x5c\x51\xf6\x17\xab\xe0\xc2\x28" + "\x49\xa4\x4d\x47\xfd\xe4\xbe\x1c" + "\x52\x44\x36\x4f\xa4\x79\x12\x07" + "\x55\xe8\xfb\x01\x66\xff\xab\x97" + "\xc4\x51\xda\x5f\xe8\x94\xe3\x3e" + "\x0b\x7c\x59\x67\xf6\x85\x03\x19" + "\x4b\xe3\x7e\xa2\xc6\xcc\x9f\x6e" +
+
+       "\xf8\x92\xa4\xdd\xde\x7a\xc7\x3b" + "\x05\x72\x29\x78\xea\x3a\x1a\xc1" + "\x4c\x1b\x93\x34\xe7\xa3\x89\x5e" + "\xbb\x94\x56\x9f\x2e\x2e\x51\x17" + "\xb6\xf8\x7b\x17\xf3\x49\xc3\x5d" + "\x3e\xff\xc7\x08\xba\xa4\x2e\x23" + "\x5d\x14\x11\xf5\x16\x9d\x4f\x9c" + "\xc3\x79\xb3\x33\xa3\x09\xf1\xcc" +
+       "\xa9\x24\xeb\x80\x70\x85\xe2\x60" + "\xfd\x0c\x8e\x48\x4d\xfb\xed\x7b" + "\xb8\xcd\x59\xc2\xd7\xbb\x1e\x72" + "\xa9\x90\x63\xbc\x55\xa8\x0d\x0b" + "\x70\x4c\x31\xde\xdb\x04\x4d\x2b" + "\x46\xe8\x32\x6c\xbc\x1f\xbf\xcd" + "\x9e\xfc\x62\xb1\xab\x3e\x83\x33" + "\xb7\x3a\xdd\xb0\x8b\xb4\x39\x99" +
+       "\xb9\xdf\xc3\x97\xb1\x8a\x2b\xc4" + "\x54\x81\x16\xcf\xb0\x49\xa5\x55" + "\x92\x06\xb5\xc1\xe7\x48\x67\xad" + "\xcb\xcb\xc5\x6f\x0f\x78\x75\x27" + "\xc8\xd7\xc9\xe1\xb8\x80\xab\x4e" + "\x56\xcd\xdb\x3f\xe1\xda\x69\x8c" + "\xce\xea\x69\x99\xfb\xb4\xe6\x47" + "\x5a\xcb\x05\xa7\x85\x10\x2f\x00" +
+       "\xb9\x0e\x1b\x71\x1f\x2c\x89\x96" + "\x54\xb9\x0a\x78\xc8\xf2\x05\xb9" + "\xdb\x92\x07\xa2\x09\x63\xe2\xac" + "\x26\xe1\x84\x06\xb3\xc9\x8a\xec" + "\x47\x24\x0a\xb4\xb6\xd8\x6a\x48" + "\x24\xfb\xe3\x9f\xc1\x1f\x12\x60" + "\x3f\x3b\x8e\x1a\xcf\xfc\x26\x56" + "\x94\xf3\xd1\x6a\x22\x86\x56\x4e" +
+       "\x52\xbf\x37\x30\x18\x43\xfb\x2b" + "\xd7\x25\xc7\x78\xb5\x6d\x1e\xb6" + "\xd7\xe5\xb3\xbb\x60\x40\xfd\x8e" + "\x8e\x48\xac\xdb\x01\x47\x01\x2e" + "\x49\xa4\x0a\x36\x9a\xcf\x75\xac" + "\x08\x4d\x63\x79\x05\xfd\x0c\xb7" + "\xef\x15\xfb\xff\x6d\x53\x91\xa5" + "\x6c\x10\x7c\xd0\x82\x75\xc3\xb2" +
+       "\x98\x4a\x6f\x23\x22\xbb\xfb\x5c" + "\xbb\x00\x68\x06\xe9\x59\x0c\x0b" + "\x74\x77\x9a\x5a\x8f\x9a\xc6\x4a" + "\x48\xc9\xbe\xd6\x04\xf8\x33\x2b" + "\x66\xc4\xe6\x32\x95\x92\x72\xb3" + "\x73\x9c\x59\x4e\x0f\x6d\x95\x68" + "\xcc\x31\x5c\x15\x9f\x24\x7a\xa4" + "\x4e\x28\xce\xe1\x0d\x0f\xd8\x24" +
+       "\x88\xd1\x57\x64\x0d\xa7\x47\xf3" + "\x8b\x38\x7a\x8b\x6b\xa8\xed\x86" + "\x13\x60\xcd\x0c\x06\xff\xcd\xb7" + "\xb2\x3f\x05\xd0\xc7\xb6\xb1\xbe" + "\x9f\x0a\x24\x99\x87\x23\x02\x0b" + "\xb2\x89\x61\x77\x4f\x38\xbb\x1b" + "\x3a\x19\x66\x90\x1e\xe7\x95\x86" + "\x7e\xac\xff\x06\x97\x00\xb5\x2e" +
+       "\x62\x3d\x8a\x4a\xc6\x46\x4b\x5a" + "\xd2\x43\x77\x24\xd0\xc4\x69\x84" + "\x33\xe4\xf7\x88\x3d\xa1\xb3\x2b" + "\x49\x58\xbe\x01\x10\x3a\xb2\x62" + "\x4c\x1a\x3d\xa6\xb4\x96\x35\xe8" + "\x3e\x3f\x18\x7d\xea\x7f\x4e\x45" + "\x1c\xb0\xaf\x17\x61\xce\x3f\x64" + "\x38\x36\x4c\x1c\xe6\xe5\x65\x4e" +
+       "\x5f\xcd\x5f\xa3\x8d\x50\x65\x40" + "\xeb\xca\x5c\x49\x8c\xdf\x65\x89" + "\x62\xa9\xe1\x12\x50\xa8\x2d\x0f" + "\xc4\x1c\xcf\xc1\x94\x1b\x47\xee" + "\x75\xfb\x08\x0a\xc8\x9b\xf1\xce" + "\x91\x35\xde\x81\xf5\x58\x49\x70" + "\x88\x4f\xef\x3a\xb2\xf8\x67\x28" + "\x5f\x9a\x9f\xea\x84\x93\x74\x8d" +
+       "\x8b\x50\x09\xdc\xe3\x30\xe8\xb7" + "\x55\x76\x31\x74\xcf\xd2\xf6\xfa" + "\x55\x03\x69\xdf\xeb\x6c\x60\x72" + "\xd6\xde\xc3\xd0\xb3\x92\xbb\x48" + "\x92\xf8\x7c\x5c\x84\x54\xb7\x65" + "\x1f\xf0\xd5\xd5\xc9\x7a\xcd\xf6" + "\x69\x1d\x40\x96\x59\x0a\xc3\xc2" + "\x78\x18\x92\xed\x50\x86\x26\x91" +
+       "\xd5\x68\x26\x8d\xf9\x5f\x8b\xe3" + "\x65\x19\xd8\x7a\x1a\x28\x15\x07" + "\x11\xce\xc6\x03\x7c\xfc\xc8\x1b" + "\x36\x04\x65\x8b\xe2\xe6\xbe\xcb" + "\x08\x98\xdb\x0c\xe8\x0f\xb0\x06" + "\x15\xd3\x3e\xfe\x66\xe0\xd6\x17" + "\x18\x50\x0b\x4d\xc6\x38\x9d\x2e" + "\xef\xca\x4d\x84\x56\xfd\x8b\xab" +
+       "\x45\x85\xdd\x6a\x17\x77\xdb\xe5" + "\x66\x9b\xc4\x72\x66\xcb\x71\x1b" + "\x77\x1d\x42\x68\x39\x07\x56\xd8" + "\xea\xaf\xe3\x83\xe8\x0f\x84\x03" + "\x77\x99\xc6\x1e\xd5\xda\x91\xb3" + "\x26\x67\x7f\x30\xb9\x3f\x24\xae" + "\x0c\x16\xca\xe8\x7b\xc8\x8a\xc8" + "\xf4\x55\xe3\x4c\xed\xcc\x74\x51" +
+       "\x66\xf5\xa4\x53\x7d\x49\xf9\xd4" + "\x10\x68\xb5\x97\x64\x46\x73\x89" + "\x21\xa6\x94\x04\x74\xda\xe1\xf8" + "\x68\x1c\x01\x8d\x93\x6a\x54\x82" + "\x62\xc1\x1a\xc6\x19\xcb\x3a\x1f" + "\x3e\x0d\xad\xab\x9c\xfa\xf8\x52" + "\x43\xea\xb7\xb4\x23\x65\x35\x15" + "\x25\x81\x60\xae\x61\xad\x16\x5a" +
+       "\x8e\x57\x81\xff\xf8\x67\x20\x75" + "\x7d\x44\x45\x90\x50\x21\x62\x78" + "\x6f\xaa\x05\x05\xcf\x2f\xc2\xc0" + "\x77\x1c\xed\x6b\xa6\xf0\x30\x10" + "\x39\xd7\x0b\x1f\x15\x9f\xf2\x31" + "\x85\xbe\xde\xe6\xc7\x89\x79\x2d" + "\x98\x7e\x67\x8e\x72\x0e\x07\x5c" + "\xd5\x1f\xe8\x06\xd3\x7b\x81\x0a" +
+       "\x99\x22\xe0\x7f\x72\x6a\x81\x0f" + "\x19\x33\x4f\x29\xc2\xcc\x35\x63" + "\xbe\xc5\x45\x47\x9f\x17\x20\x38" + "\x6e\x06\x2f\x92\x82\xb7\x47\xe6" + "\x8a\xfb\xca\x02\xde\x49\x2e\xc2" + "\xcc\xec\xc2\xfc\xff\xc2\x9b\x29" + "\x82\x82\x0e\x6e\xa2\xee\x8f\x9a" + "\x05\x32\x89\xfe\x8b\x27\x27\xa6" +
+       "\xe5\x13\xc6\xcb\xb6\x7e\xe1\xc1" + "\x1c\xa6\x7e\x49\x55\x1d\x13\x33" + "\xd5\xde\x7e\xaf\x9e\xd3\x69\x2f" + "\x1b\xf1\x6a\xde\x34\xf4\xc2\x73" + "\xfa\x75\xa3\xa4\x93\x24\xa5\x4c" + "\xc2\xc5\x33\xb8\x7c\x78\x06\x5f" + "\xcf\x71\x6e\x3e\x1f\x09\x4e\x81" + "\x66\x66\x74\x8b\x57\x1f\x45\x76" +
+       "\x2a\xe9\x33\xb5\x8c\xc1\x57\x6e" + "\xde\xb5\xbf\x55\xfe\xca\x9b\x33" + "\xeb\xa2\xee\x01\x9c\x8b\xea\xa1" + "\xd6\xa7\xf8\xf4\xf5\xb4\x23\x60" + "\x42\x4e\xb5\x52\xae\xe4\x52\x5e" + "\xdc\x70\xbf\x84\xe0\x55\xba\x1c" + "\x8d\xa4\x06\x3f\xba\x7a\x09\x22" + "\xa9\xbf\x0b\xe9\x3f\x63\x13\x55" +
+       "\x88\x93\x53\xe1\x82\xe0\xc7\x01" + "\x6b\x9c\x9a\x75\x30\x6f\x28\xfd" + "\xfb\xac\x6b\x17\x41\x10\x58\x94" + "\x53\xde\xc3\x3b\x7c\xf0\x80\xe5" + "\x2f\x77\x4d\x88\x75\x6f\xdb\xdc" + "\x4f\x9d\xbb\x40\xb8\x3b\x5c\xd7" + "\x11\x30\x08\xdb\x4e\x2e\x6c\xdc" + "\x8d\x29\x9c\xcd\xa2\x89\x87\xe1" +
+       "\x82\xce\xa0\xff\x1c\x10\xf2\xa5" + "\x40\x34\x34\x4b\xe5\x36\x6d\x7c" + "\x03\xa3\x74\x0c\x29\x8d\x52\x82" + "\x17\xab\xd4\x04\xc2\xa8\x83\xd0" + "\x0d\x1e\x00\x76\xdd\x4e\xf1\xcf" + "\xc7\x2e\x66\xc9\x02\xc2\x11\xc9" + "\xc6\x78\x02\x81\x98\xfb\x34\xdb" + "\x68\xe3\xe4\x5e\x0e\x25\xb4\xa1" +
+       "\x47\x13\xfe\x95\x84\xab\xe6\x5e" + "\x3c\x50\x24\x6f\x39\x6c\x0f\xab" + "\x6b\xdd\x86\x44\xfb\x3f\x7e\x80" + "\xf5\xfe\x02\x80\x74\x6c\x0b\xf0" + "\x99\x29\x86\xa7\xa6\xf9\xbf\x48" + "\x26\x9e\xd8\xbe\x6c\xa0\xe5\x85" + "\xeb\x19\x84\x3d\xaf\x11\xd3\x86" + "\x16\x3f\x73\x34\x78\xad\xf3\x24" +
+       "\xaa\xa2\x6f\x5a\x5e\xee\xac\x9c" + "\x23\xe6\xd4\x75\x83\xd7\x86\x06" + "\x5d\x18\x28\x0b\x0a\x8d\x72\x3f" + "\x6f\xed\x3c\xdd\x60\xb0\x12\x79" + "\x5a\xcc\x14\xf0\xfa\x29\x31\x8d" + "\xea\x5a\x39\xd7\x5c\xde\x1d\x32" + "\xab\xba\x0f\x6b\xd6\xb2\x07\x96" + "\x99\xbd\xaf\x07\xae\x11\x59\xbc" +
+       "\x44\x0d\x82\x11\x13\x55\x20\x5e" + "\x3a\x47\xc4\x86\xcc\x1b\x65\x0c" + "\xef\x0e\xd8\x9b\x2b\x0c\x23\x1d" + "\xe5\x5b\x51\x07\x12\x4a\x2c\x04" + "\x84\xe2\xe9\xbf\xa0\x7c\x51\x42" + "\x7a\x82\x69\x23\x78\x05\xf6\xe8" + "\x9d\x69\x38\x16\xf0\x04\x4f\x18" + "\x05\x6d\xbc\xf2\xed\x18\x46\x17" +
+       "\x77\xf1\x1c\x65\xd5\x78\x37\x7c" + "\x0f\xbd\x52\xd8\x55\x55\x68\x1b" + "\xf8\x1f\x46\xf3\x82\xf6\x03\x4a" + "\x7b\xca\x12\x9b\x35\x8c\x09\xc1" + "\x01\x34\x98\x5d\xd2\x53\x05\x6a" + "\xb0\x87\xc6\x3d\x8f\x76\xc0\xe0" + "\x2e\x73\x4b\x34\x3e\xa3\x44\x7c" + "\x02\x0a\xb7\x64\xc3\x71\xb1\x5e" +
+       "\x87\xd6\x68\x6c\xfc\x03\x3e\x5e" + "\xc7\x52\xf0\x1f\x3d\x2c\x73\x3e" + "\x7a\x6e\xd1\x6e\xa6\xef\xd0\xf2" + "\x46\xb7\x5b\xb6\x26\x2b\xd9\x63" + "\x7c\x86\x44\xdd\xba\x82\xcd\xff" + "\xb8\x81\xc0\xf8\x9e\x4a\x1b\xa7" + "\x85\x87\x6c\x73\xa7\x76\x16\x6c" + "\xd0\x32\x89\x9d\x16\x06\x2c\xbe" +
+       "\xf2\x39\x09\xb5\x49\x88\x63\xd1" + "\x8e\x85\x90\xba\x2c\x69\x33\xfc" + "\x8e\x00\xa6\x2f\x91\x0a\x4a\x2b" + "\x40\x39\xa3\x97\xc7\x90\x01\xc0" + "\x10\x3c\x2d\xd6\xfd\x14\xff\x8a" + "\xc1\x89\x19\x57\x09\x4d\xc6\x98" + "\xba\xfe\xe5\x00\x28\xea\x24\x82" + "\xc1\xc5\xa9\xf9\x0c\xb9\x3c\x91" +
+       "\x9f\x1c\xca\x9e\x4b\x1a\xfa\x7b" + "\x35\xe5\xe5\x8c\xdc\xc1\x0b\x96" + "\x0a\xc3\xee\x17\xf3\xd9\x67\xe2" + "\x38\x7d\x25\x6c\xef\x89\xfb\x06" + "\x6d\xa2\x64\xd3\x9a\x99\x28\x23" + "\x58\xab\xea\x26\xcb\x94\xb7\x69" + "\x96\xa5\x5b\xb8\x1f\xab\x28\xad" + "\x94\xaa\xd0\x56\xf3\xbf\xdc\x05" +
+       "\x02\xa6\xa1\xa3\x80\x9e\xd7\x14" + "\xaf\xd6\xc3\x22\x5e\x18\x4f\xfc" + "\xc8\x67\xf6\xb7\x6b\xa5\x2f\x23" + "\xf8\xea\x3e\x8f\x91\xbc\xd0\x49" + "\x48\xe2\x70\x58\xb9\x51\x91\xe8" + "\xab\x09\x44\x3d\x70\x0e\xab\x70" + "\xe8\x83\x07\x80\x10\xe9\xd8\x22" + "\x62\x77\xac\xa2\xb2\x7b\x2c\x9b" +
+       "\xc4\xfb\xcf\x2b\x28\x6d\x37\x53" + "\x7a\xdb\xea\x06\xa7\x17\x88\x70" + "\x69\xae\x35\xcd\x05\x0e\xf5\x6f" + "\xde\x7f\xbc\x74\x75\xfb\xb5\x63" + "\xc4\x08\xfe\xe7\x53\xe9\xc9\x71" + "\x18\xca\x83\xf5\xd4\xbf\xd8\xb4" + "\x5c\x1c\xe8\x45\x82\x78\x8d\xde" + "\x38\x41\x47\xe0\x3c\xe9\xf5\xa5" +
+       "\x32\x19\x83\xf0\x4b\x5f\xd7\xd4" + "\xc9\x8c\xfe\x77\xc4\x0a\x77\x5e" + "\xa2\x72\x2e\x86\x48\xe7\xb5\x52" + "\xfe\x35\x1d\x50\x82\x54\xa4\xe9" + "\x87\xb1\x9a\x4a\x42\xe7\x93\x8a" + "\x17\xa0\x8c\xe8\x6d\x50\x72\x5a" + "\xef\x2d\xeb\x01\xb2\xdc\x80\xe6" + "\x9d\x20\x68\xba\xe6\xa4\x5a\xdc" +
+       "\x31\x9f\x3c\x29\x0f\x16\x6c\x42" + "\xa7\xd7\x64\xe8\x33\x63\xb5\x8e" + "\x30\xba\xbb\x3e\x02\x64\x11\xbe" + "\x02\xa3\xd5\x2f\xe3\xba\xc2\x64" + "\x7b\xff\x5a\x26\xe1\x01\x06\x80" + "\x14\x4b\xfd\x66\x80\xa8\xd8\x52" + "\x9c\x5a\x07\x46\xe7\x20\xba\x5a" + "\xc6\x34\x12\x7e\xf8\x2b\xa3\xda" +
+       "\xc8\x2f\x56\xc4\xa5\x97\x74\x45" + "\xf8\xbf\xe2\xf3\x8a\x8e\xfd\x44" + "\x59\x7d\xc9\x49\x35\x49\x23\x19" + "\xe4\xbb\x36\x40\x56\x07\xe3\xda" + "\xed\xa0\xad\x49\x51\x78\x37\xf1" + "\xaa\x87\xef\x80\xc5\x62\xd3\xc6" + "\x6a\x5c\xa5\x30\x12\x43\x97\xc5" + "\x37\x5a\xec\x15\xe5\x07\x84\x56" +
+       "\xe0\xb7\x4d\x69\xef\xbd\xf9\x80" + "\xc6\xdd\xfc\xb9\x87\x87\xca\xed" + "\xe1\xdc\xb8\x03\x34\x1c\x98\x51" + "\xa1\x0b\xe1\x70\xf1\xdc\x74\x42" + "\x1a\x6d\xef\x6d\xb8\x43\x27\xf7" + "\x66\x18\xdb\xeb\x70\x16\x5b\xd2" + "\x58\x6f\x0c\x05\x8c\x1e\x49\xc4" + "\xf5\xd7\xfb\x87\xab\xb2\xe2\x2b" +
+
+       "\xec\xf8\x11\xd1\x9d\x5c\x0e\x3e" + "\x60\xe7\xc4\xb7\x8d\x3f\xc3\xbc" + "\x51\x2a\x39\xbd\x91\x9a\x2f\x70" + "\x2d\xe9\x32\xc1\x95\xa7\xa4\x7d" + "\x1b\x15\xb1\x0b\xe3\x0a\x0b\x1a" + "\x51\x22\xe3\x02\xc8\xba\xfe\x54" + "\x78\x9e\x4e\x69\x82\x50\x3a\xea" + "\xb8\x40\xfe\xe4\xc1\xfe\x8f\xe5" +
+       "\x0b\x12\xc4\x29\x9d\x34\xb8\xfb" + "\x15\xd9\xd0\xc0\x1f\x39\x94\x9f" + "\x51\xba\x10\x54\xa7\x4f\x07\xc4" + "\x11\x59\x0a\x15\xf6\xdb\x6a\xa6" + "\x38\xca\xbf\x34\x3c\x54\x64\xc1" + "\xfc\xcc\xe1\xb9\x60\x75\xf2\xe0" + "\x9c\x21\x20\xe8\x53\x0f\xda\x99" + "\x7a\x99\xb4\xc6\x98\x44\x23\xe8" +
+       "\xe4\x19\x6e\x51\x13\xc5\x23\x7b" + "\x93\xd5\xc4\xc5\x47\xe8\xe2\x56" + "\xf6\x1e\xe7\x5c\x73\x7d\x72\x9f" + "\xc5\x44\x9a\xf7\xa6\x04\x63\x5b" + "\x33\xe4\xb7\x3a\x36\xa7\x38\x66" + "\x83\x2f\x74\xfe\x70\xa4\xde\x1a" + "\x9f\xc1\x7f\x5b\x54\xb8\x54\xe0" + "\x98\x06\x1d\xba\x1a\x38\x35\xf9" +
+       "\x36\x49\x8e\x91\x9d\x4f\x50\xb5" + "\x82\x39\x51\xb2\xf6\x5e\x03\x65" + "\xb9\x9c\x4d\x6f\xc2\xa0\x53\x05" + "\x09\x55\xa8\xbe\x56\x0d\xb1\x6c" + "\x11\xda\x42\xa2\xb7\x57\xd9\x48" + "\x68\x72\x2b\x67\xdd\xd3\xa4\x16" + "\x6b\xa9\x02\x85\x7c\x63\x7e\x3d" + "\x3b\x46\x0d\x73\x2b\x03\xc7\x27" +
+       "\x6f\x42\x46\x58\x7d\x6b\x36\x55" + "\x1d\x44\x7d\x24\x89\x9e\xd0\xe7" + "\x48\xbf\x6f\x73\x4d\x40\x0b\x51" + "\x7d\xbd\x84\xe7\xd0\x03\xa0\x7f" + "\x96\x95\xfd\x17\x4f\x61\xf7\x25" + "\xdb\x98\xcb\x35\xa1\xe0\xe0\x49" + "\x6a\xa7\x83\x2e\x7b\x95\x65\x2c" + "\xf8\xe0\xdb\xcd\x8d\xda\x40\x5d" +
+       "\x9d\x93\x95\xa5\xb4\x8b\xf6\x37" + "\x17\x02\x74\x28\x79\x64\x55\x03" + "\x12\x76\xad\x84\x7c\x0e\x74\x8e" + "\x5f\x69\x44\x90\x43\xc8\x9b\xd8" + "\x4d\x18\xa9\x85\x5d\xda\xf3\xf7" + "\x74\xb0\xc0\x9f\xbb\x63\x25\x56" + "\x8e\x88\x8a\xf8\xaa\xe6\xd2\x06" + "\x7c\xbe\x1f\x16\x43\x86\x2d\x61" +
+       "\xb2\x0b\x53\x54\xa3\xbb\xb3\x9f" + "\xea\x69\x08\xcb\x77\xef\xe3\xbd" + "\x63\x11\x43\x0b\x46\x90\xbc\x89" + "\x35\x9a\x81\xe4\xd2\xd7\x03\x4d" + "\x82\xa7\xb6\x43\x9e\x4f\xae\x33" + "\x86\xa6\x88\x9c\x07\xb3\x6d\x21" + "\xd9\xed\xff\x00\xe0\x88\xdd\x91" + "\x40\x48\xbd\x12\x9f\xda\x80\xb2" +
+       "\xd7\x8c\x53\x3e\x91\x86\x8f\x45" + "\x53\xad\x08\x8e\x6c\x1f\x00\xa7" + "\xff\x15\x5d\xbf\xe6\xc6\xb8\x52" + "\xdd\x15\x12\x01\xa4\x34\x82\x54" + "\x45\x40\x5b\x3d\x2d\x9d\x5a\xff" + "\x90\x41\x90\x4a\xb6\xee\xff\xb0" + "\x8b\x7f\x60\x48\xa4\xac\xa3\x55" + "\x2a\x67\xa0\x30\x5c\x66\xbd\x8c" +
+       "\x37\x59\x7f\xf3\x73\x35\x7f\xa3" + "\xa5\xfc\xe4\xd1\x7d\x6c\x0f\xeb" + "\xfc\xb0\x8a\xac\x54\xa5\x65\x29" + "\xac\x76\x46\x27\x6c\xf5\xfb\x17" + "\x20\xd7\xf7\xac\xd9\x6b\x2f\x2e" + "\x66\x47\x22\x10\x88\x8f\xfc\x41" + "\xef\x3b\xd5\x85\xb3\x14\x7a\x51" + "\xd1\xa7\x76\x7d\xa5\x27\xe3\xda" +
+       "\xdc\x82\x5f\x1f\x89\x5c\x5d\x51" + "\x9e\x07\x61\x63\xd7\x67\x7f\x9a" + "\x30\x53\xa3\x11\xe3\x81\xda\xa8" + "\x1b\xbe\x18\x4b\xc4\x90\x49\xe4" + "\x59\x3e\x10\xaf\x95\xed\xd5\xc7" + "\x61\x92\xac\x8d\xa7\xab\xe8\xec" + "\xd3\xb8\x94\x93\x99\xb0\x82\xbe" + "\x83\xfe\xad\x16\x9a\xf0\x30\x68" +
+       "\xb1\xd9\xd7\x94\xc1\x1a\xc4\x43" + "\x17\x7f\x2e\xc8\x82\xdd\xaf\x5b" + "\xca\x0f\xda\x5f\xc1\x14\x06\xdf" + "\xad\x37\xae\xa8\xa7\x43\xb0\x74" + "\x4c\x73\x71\x9e\xa1\xaf\xa6\x3b" + "\x2e\x0f\x45\x9c\x7e\x43\xd5\x15" + "\xb1\x42\xe2\x67\xfe\x83\x58\x4a" + "\xc2\x53\x19\x2c\xc2\xbd\x43\x51" +
+       "\xf9\xf5\x53\x6b\x7c\xce\xa9\xa2" + "\x99\x6d\x17\x1b\x95\x65\x24\x64" + "\x1b\x08\x5c\xb9\x36\x8d\x29\xb1" + "\xe6\x9e\x9a\x1d\xb8\x5b\x50\x53" + "\xb0\x70\xba\xf2\x61\x9e\x6f\x3f" + "\x53\xd4\xfa\x8a\xc9\x16\x7e\xd0" + "\x6a\x4a\xeb\xe7\xbb\x94\x16\x9f" + "\x8e\xbc\xb0\x3c\xd9\xce\xeb\xdf" +
+       "\x0b\x39\xf3\xb1\xf2\xd7\x76\xc6" + "\x72\x12\xb6\xa5\x8c\x1b\x7a\x9f" + "\xa9\x27\xe1\xc2\xc9\xbf\xbe\x4e" + "\xbf\x97\xd9\x5d\x0c\x50\x02\x46" + "\x0f\x23\x11\x47\x1c\x77\x09\x7f" + "\xc1\x09\x0f\x02\x7c\xb3\x8e\x05" + "\x8b\xe3\xe5\xfe\x4b\x3d\x69\xab" + "\xc0\xcb\x53\x46\x1f\xeb\x89\x92" +
+       "\xa7\xf5\x70\x17\x39\x2b\x4d\xa4" + "\x82\xeb\x44\x0e\x91\xd7\xd4\xe4" + "\x2a\x71\x69\x3f\x1e\x9d\xe6\x42" + "\x0e\x82\x6a\xac\xd6\xc4\x11\xbf" + "\x4c\x22\xc4\x42\xe5\xf3\xe7\xb5" + "\x1c\x94\x9d\x44\x1c\xe8\xb4\xd6" + "\x78\xe8\x50\x54\x16\xbd\x72\x5d" + "\x54\xac\x25\xee\x8a\xe2\x61\x6a" +
+       "\x78\x25\x95\xab\xc7\x9d\xda\x54" + "\x0b\x4d\xe8\x26\xf2\x3d\x42\xb5" + "\x42\x20\x87\x9b\xeb\x4e\xb6\xa8" + "\xdf\xf6\x90\x59\x82\x57\x20\xac" + "\x7a\xc7\xf4\x21\xeb\x96\xf6\x4f" + "\xaf\x73\xb2\xaa\xe4\xc3\x79\x1a" + "\xf1\xb3\x36\x94\x2e\x92\xbc\x29" + "\x7a\xa2\xd9\xd6\xf8\x7e\x80\xff" +
+       "\x6c\x74\xf6\x33\xf8\xa8\xf3\xc7" + "\xca\x90\xa9\xfe\x65\x6f\xe4\x21" + "\xa9\xb0\xdd\xca\xc5\xd5\x5f\x91" + "\x55\x45\x61\x78\x16\xf0\x41\xbd" + "\x58\xfb\x6f\x42\x34\x44\x6f\x34" + "\x04\xc2\xdb\x14\x36\x94\x55\x80" + "\x7f\x9b\x96\x5a\xfe\x20\xdd\xf3" + "\x9a\xa3\x99\xe8\x56\xe9\x59\x9d" +
+       "\xc0\x56\x6f\xd0\x8f\x68\xca\xe4" + "\x72\x79\x02\xdf\x0d\xf7\x8a\xa4" + "\x9d\x60\x9a\x5e\x04\x0f\x1f\x69" + "\x0e\x27\x61\xee\xcd\x82\xdd\xa9" + "\xd3\x18\xef\xa0\x63\xca\x03\x89" + "\xbd\xa3\x6c\x3d\x35\xee\xb7\x9f" + "\x03\x7d\xf4\xab\x9c\xa0\xb4\xa7" + "\x8e\xde\x67\x1c\x01\xda\xda\x4c" +
+       "\x92\x15\x92\x74\x37\x56\xa0\xf9" + "\x31\x9d\xbb\xb9\x1d\x26\xf1\xb4" + "\x59\x54\x9c\x4e\xb7\x29\x14\x55" + "\x53\x1f\xa7\x6e\x6f\x2e\x18\xbe" + "\x73\x05\xc5\xdf\x7c\xb0\xa3\xd3" + "\x44\x8d\xbe\x62\xda\xaf\xa1\x9b" + "\xd3\x65\xab\x52\xcb\xd2\xcf\x9b" + "\x02\x18\x57\xa9\x47\xd5\x11\xdf" +
+       "\x75\xa6\x38\xe0\xc1\x7d\x12\xac" + "\x20\x63\x5c\x8c\xf3\xef\x9d\x72" + "\x53\x2c\x0d\xa9\xd4\x8f\xdf\xb7" + "\xd3\x7c\x1e\x68\xec\xb0\x74\x9b" + "\xe5\x07\xb4\xda\x23\xa6\xb5\x5c" + "\xc6\x40\xb3\x76\x15\x36\xbd\xcd" + "\x2c\x39\x28\x7d\x5a\x41\x84\xa1" + "\x30\x78\x6f\xe9\xd8\xc1\x84\xc1" +
+       "\x61\xfc\x43\x5e\x84\xb6\x89\xb1" + "\x57\xab\xd3\xe0\x75\x23\x28\xf3" + "\xa8\x1d\x18\xb1\x67\x4b\xa3\x4f" + "\xb8\x52\xee\x99\xb2\xd0\x1e\x62" + "\x76\x06\x99\xad\xe1\x8d\x17\x9b" + "\x65\x40\xd5\x56\x7b\xe6\x1d\xd5" + "\x01\xc2\x38\x75\xc4\x27\x2c\x2a" + "\x5c\x0f\xa4\x38\xc8\x6e\x85\x33" +
+       "\xc3\x85\x7e\x2f\x3b\x30\xa9\x86" + "\x9b\x8f\x98\x71\x21\x46\xce\x5f" + "\xb5\xac\x38\xc1\xf6\x5b\x93\x5b" + "\x12\x12\x66\x25\x67\x7d\xea\x30" + "\xa2\xb9\x1a\xe5\xf4\xb5\x1e\xef" + "\x78\x7c\x06\xae\x8a\xc9\x87\x05" + "\xa6\x9c\xca\x77\x3c\x1b\xce\xb3" + "\x57\xf0\xb5\x54\x4d\x3d\x55\x2a" +
+       "\x3d\xab\x21\xcd\xb2\x68\xe4\x89" + "\x92\xd3\x93\xc3\x22\xf0\x04\xe5" + "\xf9\x3a\x01\xa5\xd4\xe1\x21\xab" + "\xcb\x8a\xc2\xc2\x78\x3f\x28\xe3" + "\x9f\xf9\x6b\x22\xf6\x35\x8b\xf3" + "\x69\x1e\x29\x0e\x74\x42\x35\xe8" + "\x2d\x16\x0c\xb2\x15\x3a\x67\x61" + "\xbe\xbd\x4f\xb0\x75\xdc\x01\xc1" +
+       "\xa0\x94\x18\x0b\xe1\x56\x71\x2c" + "\xc0\x68\x1c\xd8\x01\x40\x03\x92" + "\xb5\x15\xb1\xc8\x00\x5d\x22\xed" + "\xf2\x07\xb9\x83\x22\x9c\x7f\x23" + "\xc0\xe2\x70\x44\x2f\xf3\xa2\x0e" + "\x95\x4e\xbe\x58\xc1\xf7\x25\xb7" + "\x63\x54\xae\xb1\xfa\xca\x1d\x0f" + "\x04\xfc\xa2\x1b\x87\x51\xed\x59" +
+       "\x57\xd6\xdd\x06\xe2\xbe\xdb\x35" + "\x6d\xa9\xf3\x2f\x11\xdd\xcb\xe7" + "\x58\xe7\x6b\x07\x68\x19\x38\x88" + "\x5d\x1f\xc9\x08\x72\x7e\x73\x2d" + "\x76\x37\xec\x86\x62\xab\x83\x5f" + "\xa1\xa7\x5f\x94\x9d\x64\xaa\x98" + "\x33\x09\xef\x72\x37\xec\x77\xf4" + "\xb1\x17\x8c\x09\x1e\x2b\xf5\x66" +
+       "\x11\x07\x52\xc9\xde\xcc\xb0\xd1" + "\xbf\x84\x8b\x3c\xed\xe4\xa9\x55" + "\x14\xf3\xfe\xa1\x39\xbd\x26\x94" + "\x2b\x3f\xb9\x6e\x8e\x63\x5f\x4f" + "\x1b\x34\xf9\x2b\xd3\x1e\x2a\xba" + "\xa9\xd5\x42\x4d\x21\x13\x3c\xd6" + "\xc5\xc7\x6d\x31\x89\x4a\x96\xd2" + "\x51\x18\x51\xca\x06\x96\x75\xd1" +
+       "\xbd\x7b\xe5\xcf\x0e\xc1\x2e\xb1" + "\xb5\xc2\xa0\x35\x56\xb6\xc7\x82" + "\xbd\x67\x1c\x16\xcd\xd5\xc7\xdd" + "\xcc\x32\x3a\xae\x85\x89\x2e\xe3" + "\x29\x55\x1a\xd1\x44\x94\xba\x7a" + "\x1a\xfa\x27\x24\x02\xed\x64\xe9" + "\x0a\x77\xa1\x24\x2d\x39\x28\x15" + "\xcd\x2f\xc7\x12\x2c\xce\x52\xa1" +
+       "\x87\x11\xc5\xf8\xea\x9f\xf6\xed" + "\xa7\x4d\x1e\x74\xec\x67\xbb\x05" + "\x45\x43\x11\x08\x32\x0f\xdf\x47" + "\xb1\x92\x97\xbb\x07\xcb\xfa\x56" + "\xe4\x29\x62\x8f\xe9\x07\xe0\xf3" + "\x0f\xba\x6f\x52\xf4\x03\xd1\x62" + "\x79\x9d\x33\xb0\xf7\xbe\x33\x4f" + "\xc1\xfe\x9b\xb5\x7b\x35\x41\x98" +
+       "\xba\xf5\x8e\xe2\x67\x0b\x1e\xae" + "\x69\xe1\x18\xcb\x99\x46\x9a\x2c" + "\x20\xbd\x6b\x1e\x33\x0e\xcd\x0e" + "\xd2\x81\x5e\xaf\x0e\x36\x1b\x57" + "\x45\x1d\x1c\x10\x58\xea\x9f\xcd" + "\x52\x04\x88\x18\x8e\x78\x51\x66" + "\x46\xd4\x8d\x1f\x35\x26\x97\xa9" + "\xd0\x81\x72\xe3\x22\xd0\xbe\x44" +
+       "\x1f\xac\xdb\x60\xea\x6e\x0e\x83" + "\xf7\xa2\x06\xda\x84\xc4\xd8\x23" + "\x5b\x53\xca\x50\xb0\x14\x67\x89" + "\x9b\x7a\xd9\xeb\x44\x36\x8d\xdc" + "\xb4\x77\x21\xb1\xfa\xf9\x6e\x10" + "\x9c\x5d\x4d\x53\x64\xf4\x9b\xf7" + "\x0b\x36\xab\xa6\x49\xa3\x37\x25" + "\x4f\x74\x0c\xa0\x53\x42\xc5\xc7" +
+       "\xd4\x69\xcf\xfa\xe5\x2d\xf8\xf0" + "\x4c\x34\x75\x47\x76\x7e\x3b\x36" + "\x04\x6d\xe3\xb2\x12\xf3\x94\x68" + "\xa5\xc9\xd1\x11\xfe\xb4\x6c\x3c" + "\xf2\xe1\x08\x40\x39\xc3\xd9\x85" + "\x6c\x32\x9f\x24\xea\x85\x9a\x5e" + "\x06\x5e\x8c\x67\x0a\xc6\x35\xdc" + "\xa9\xfb\x86\x9f\x4f\x94\x8b\xc0" +
+       "\xb0\x4a\x75\x68\xd1\x61\xd6\x24" + "\x76\x9a\x42\x6f\x1d\xce\x1f\x80" + "\x69\xe7\x8c\xa5\x5f\xa8\x68\xc0" + "\x2b\xca\x5e\x5d\x54\x5c\xc3\xed" + "\xd1\x60\xf6\xa3\x6f\x27\x31\xea" + "\x67\x71\xfc\xb8\xbe\x4e\x18\xa0" + "\xae\xb0\x8d\x1d\x1a\xf2\x20\x0f" + "\x12\x5e\xc3\x56\x5f\x09\x6d\xd9" +
+       "\x5f\xaa\x33\xb7\xa9\x0b\x2f\x3c" + "\x35\xf2\x5a\xf0\xcb\x47\xce\xde" + "\xa5\x82\xac\xa2\x15\xf7\xe3\xf8" + "\x8a\xf1\x03\x22\x41\xa6\x7b\xc9" + "\x60\x10\xc1\x09\x04\x55\xaf\xc3" + "\x2d\x51\xaf\x46\x05\x2c\xea\x56" + "\x46\x81\xf2\xf3\xaf\x8d\xc2\xfa" + "\x94\xf4\x9e\x95\x3a\xb4\xfa\x87" +
+
+       "\x5f\x10\xc5\xd4\x41\x16\x89\x09" + "\x65\xbd\x7f\x6d\x8e\x0f\xe8\x1a" + "\xb0\xbd\xe6\xbe\x5f\x22\x67\x9d" + "\x60\xd8\xc4\x7f\x59\x3b\x43\x3b" + "\x38\x56\xe8\x93\xb6\x6d\xe6\x44" + "\x2f\x86\xe9\xe3\x52\x92\xb5\xf7" + "\xec\x32\x5c\x66\x57\x51\x78\xdb" + "\x50\x2f\x36\xae\xd7\xef\x2f\x70" +
+       "\xc3\xb0\xef\x0f\x5d\x47\x54\x37" + "\x5d\xc3\xd7\x46\x6b\xb5\x8f\xd4" + "\xa4\x98\x37\x36\x33\xb6\x70\xa0" + "\xe6\x98\xdb\x8f\xd2\xf3\x89\xae" + "\x4c\xd1\x63\x63\xc8\x89\x0b\x97" + "\x7d\xd2\xab\x67\x21\x75\x81\x89" + "\x21\xa0\xd5\x44\x74\xd4\xf7\x9b" + "\xee\x2a\xc7\xca\xaf\x3b\x08\xb3" +
+       "\x44\x9a\x94\xbe\xde\x41\x97\x38" + "\xa5\x4f\x6a\x54\x88\x93\x8e\x63" + "\xdc\x7b\x04\xa0\x9c\x41\xe6\x3f" + "\xca\x57\xea\xaa\x48\xf6\x47\x70" + "\x17\xab\xfb\x41\x90\x8a\xe4\x54" + "\xa2\xdb\x6b\x57\x28\x0b\x8e\xda" + "\xdc\xfd\x2a\xc7\xbc\xee\x07\xe8" + "\xbf\x77\x25\xf4\x6d\x33\xd3\x07" +
+       "\x25\x09\xe2\xbf\x44\xc2\xa8\x62" + "\x67\xe8\xdc\x8f\xc3\x9a\xc1\x91" + "\x63\x70\x38\xdd\xd5\xa5\x96\x5a" + "\xf6\x24\xd3\x21\xd4\x87\xd5\x61" + "\xea\x73\x71\xa3\xa2\x73\x76\xe8" + "\x65\x8b\x77\x53\x08\x80\x84\x23" + "\x3e\xb4\xba\x05\x1e\x44\xf8\x10" + "\xbe\xef\x21\x46\x12\xfe\x11\xfa" +
+       "\x7b\x5d\x68\x81\x2e\x77\x7b\x04" + "\x76\xa9\x34\xbf\x81\x7d\xf2\x23" + "\xef\x48\x5f\x91\xe2\x08\x76\xc2" + "\xc3\xd5\x21\xa5\xfa\x43\x0b\x3b" + "\x84\x72\xca\x63\x26\xfb\x13\x76" + "\x37\xb8\x4d\x1d\xb4\x29\x57\x7f" + "\x6b\x52\x3b\x58\x98\x48\xb1\x87" + "\xd1\xd3\xad\xbb\xa6\x32\xb7\x00" +
+       "\x96\xe3\x48\x20\x26\xf4\x02\x8e" + "\xe4\x9d\x3d\x38\xb6\x50\x6b\x43" + "\xad\x85\x1e\x47\x81\x34\x8d\xf7" + "\xd6\xc8\x05\xd0\x6a\xea\x01\x8b" + "\x07\x5c\x01\x97\xee\xaf\xc7\xd3" + "\xae\xa2\x3b\x4e\xa9\xf1\xcd\x46" + "\xd2\xa1\xd3\x83\x01\xe5\x42\x7a" + "\xf4\xdf\x41\xb5\x68\x52\x4b\xd5" +
+       "\xbc\xe9\x23\x4e\x30\xcf\x24\x3f" + "\x24\x36\x6e\x12\x16\xf8\x87\x43" + "\x61\x6d\x0b\x3b\x03\x6a\xa4\x26" + "\x7c\x77\x2d\x8b\x45\xc8\x1b\xaf" + "\x9c\xe7\x7d\x52\xba\x01\xc4\x25" + "\xb6\xbb\x61\x42\xd4\x46\x13\x0e" + "\xc7\x4b\x7b\x28\x4b\xc4\x96\x4b" + "\x2f\x56\x54\x52\xc7\x93\x84\x65" +
+       "\x20\x4a\xa2\xb8\xfe\x49\xf9\x23" + "\x3f\xa5\x2c\xf5\xd1\xfe\xeb\x17" + "\x53\x48\xfb\xbc\xbe\x1b\x69\x9b" + "\x5d\xa0\x78\x62\x6b\xff\x17\x56" + "\xbd\x9e\xc9\xe3\xc5\x34\x1b\x24" + "\x6a\x15\x84\x17\x2e\x24\x64\xfc" + "\xdf\x67\x5d\x69\x2f\x48\x06\x42" + "\x11\xc0\x27\xee\x0e\xce\x67\xb9" +
+       "\x5d\x0b\xc8\x21\x51\x37\xdb\x65" + "\xa0\xcc\x1e\xa3\x3c\x56\x7a\x2e" + "\x7e\xa0\x38\x52\x4e\xfc\x6f\xe5" + "\x54\xd8\xce\x32\x66\x29\x6c\x3d" + "\x85\xb8\x70\xaf\x1a\x7d\x9d\xe9" + "\x59\x64\x68\x2d\xd9\xba\xc3\xaf" + "\x5b\xba\xc8\x0c\x46\xbf\x78\x9c" + "\xa3\x5a\x95\x18\x19\x95\x43\x5a" +
+       "\x14\xe3\xe4\x5f\xa8\x17\xb5\xf8" + "\x6f\x90\xb8\xfc\xd0\x34\x02\xe6" + "\x23\x1b\x06\xf2\xac\x42\xe5\xff" + "\x9c\xb5\x4c\x6b\x1f\x19\x7e\x28" + "\xd8\x77\xd8\x09\xdc\x7d\x85\x21" + "\x41\x89\x67\x14\x8c\x47\x23\x1c" + "\xa4\x5e\xe0\xb6\x56\xc0\xf0\xbb" + "\xfe\x94\x15\xb0\x53\x4b\xda\x82" +
+       "\x08\x86\xdb\xfa\x91\x67\x52\xf7" + "\xf6\xcd\x74\x7b\x2d\x83\x9e\x04" + "\x34\x0a\xb9\xc2\xcc\x81\x35\xa4" + "\x0c\xb1\x60\x93\xb8\x9e\x63\x73" + "\x1b\xa7\xe4\xe1\x1f\x33\xba\x4f" + "\x19\xf9\x72\x80\x93\x6b\xfd\x6f" + "\x32\x90\x67\x65\x1c\x27\x53\x6e" + "\xce\x72\x42\xf1\x44\x64\x20\x67" +
+       "\x34\x58\x33\xb2\xa3\x34\xf7\xc0" + "\x60\x68\xef\x90\x5a\x20\x26\x95" + "\x0d\xbb\xe2\x04\x17\xe7\x8b\xcb" + "\xfa\x83\xf3\x02\x1e\x87\x18\x24" + "\x57\xc1\x82\x40\x81\x76\x17\xd7" + "\x73\x00\xc2\x29\xd0\x4a\x91\xcc" + "\x28\xe7\x87\xe5\xeb\xc1\x86\xf1" + "\xfd\xd5\xbc\x61\x22\x3c\xdb\x6f" +
+       "\xe9\xf8\xf9\xf2\xa6\x14\xd0\x30" + "\xd2\x49\xec\x4f\x23\xce\x3e\x96" + "\xd9\xa8\x05\x96\xc5\x25\x20\x86" + "\x9a\x92\xf8\x19\x45\x44\x87\x39" + "\x6a\x47\xbf\x12\x65\xff\xb6\x01" + "\x91\x7d\xcf\x09\xd8\x64\x8a\x59" + "\xca\x56\xbe\x93\x49\x77\xec\xd7" + "\x15\x36\xb3\xcb\x85\x97\x89\x10" +
+       "\xad\xe3\xee\x02\xfd\x92\xa0\xb8" + "\x70\x52\x14\x30\x35\x3d\x6b\xa8" + "\x75\xb6\x12\x85\xc6\x98\x3d\x32" + "\x0f\xb4\xeb\x62\x85\xc7\x8b\x4b" + "\xde\x9c\x3f\x41\x54\x1f\x30\x7d" + "\x64\x56\xab\x2b\x4f\xfb\xe4\xa5" + "\x23\xec\xbf\x1c\x2d\x25\x2b\x1d" + "\x0d\x12\x77\xe1\xbb\x76\xd5\xfc" +
+       "\x34\x1a\x73\x83\x3e\x7d\x42\x04" + "\x8e\x6e\x83\xed\x8e\x02\xb9\x2b" + "\x7c\xca\x12\xb6\xf8\xcf\x6a\xb3" + "\x3a\xc7\xd9\xd3\xef\xe5\x8f\xb8" + "\xb3\x4e\xea\xed\xc6\x6b\x2a\xbe" + "\x77\xec\x8e\x48\x33\x31\xb9\x43" + "\xe1\x06\x71\xb1\x66\xf5\x1f\xf4" + "\x32\xfa\x4e\x65\x72\x91\x9e\x46" +
+       "\xa3\x3f\xc2\x41\x04\x0f\x48\xb4" + "\x2e\x9a\x98\xc1\xb0\x2e\x71\xb4" + "\xa7\x9c\xa2\x93\x0f\xba\xcb\x3c" + "\x8c\x42\x19\xd6\x14\x5c\x20\x6e" + "\x86\x16\x64\xb3\x57\x79\xdb\x90" + "\x4e\x8b\xac\x45\x1d\x69\x32\x04" + "\x50\x03\x4e\xf6\xac\x59\xa7\x07" + "\x17\x25\x97\x9c\x9c\xd8\x14\x05" +
+       "\xc3\x7f\xe6\xa8\x7f\x14\x01\x17" + "\xbe\x85\x20\xab\x8b\x0b\x2e\x9e" + "\x57\x4e\x28\xac\x24\x18\x65\xd5" + "\x64\x36\x89\x74\x25\x43\x0d\x89" + "\xa3\x68\x5e\xc5\x6e\x5e\x7c\x8a" + "\x5a\xc8\x39\x43\x0b\xe9\x12\xbf" + "\x55\xb6\x22\xf9\x85\x6b\x84\x31" + "\x00\xd7\xf4\x0b\x4d\xce\x54\x9a" +
+       "\x95\x42\xa1\xf1\x3a\xe8\xf4\xd7" + "\xf9\xd4\x85\xb2\x5c\x95\x6f\x91" + "\xba\xda\xff\x99\xe0\xb0\x7b\xe5" + "\x52\xd1\xb0\xea\x34\x30\xa4\x28" + "\xf8\xce\xa9\xb8\xa2\xff\x36\x0a" + "\x1a\x05\xec\xb9\x7e\x40\x17\x55" + "\x72\xe6\x68\xea\x96\x60\x79\x9c" + "\xfb\x77\x3c\xfb\xfb\xb5\x3d\x85" +
+       "\x1a\xa5\x64\xe8\xa9\x4b\x47\x21" + "\x8b\x1b\x8a\x6e\x99\x76\x26\x6c" + "\x28\x0a\x12\x94\x26\x36\x82\x7c" + "\xdb\xa5\x83\x83\x48\x9a\x1e\xe6" + "\x6d\x21\x84\x9f\x03\x50\xd7\x7d" + "\x85\xcd\x43\xad\x07\x0d\x02\xab" + "\x59\xc6\x12\xda\x48\xae\x37\x94" + "\xad\x52\x54\xe6\xeb\xc2\x49\x64" +
+       "\xc1\xd7\xf9\x2c\x1c\x4c\x7c\xcc" + "\xab\xe5\x95\xee\x6a\x88\x20\x13" + "\x0c\x17\xae\xbe\x56\x90\x7b\xbb" + "\x62\xd6\xc0\xdb\x50\xb2\xa5\xc8" + "\x03\x23\x1d\xc1\x32\x14\xd8\x4e" + "\x9f\x76\x03\x1f\x12\x69\xa6\x7d" + "\x28\x98\x53\x84\xfd\xa5\xc7\x3a" + "\x02\xdd\xcc\x3b\x94\xda\xda\x14" +
+       "\xd1\xb0\xf6\x7e\x21\xc3\x84\x8b" + "\x22\x3f\x93\x7c\x7a\x47\xa9\x52" + "\x82\x0b\x44\xfd\x8a\x72\xf6\x5e" + "\x5e\xbd\xe4\x6c\x59\xd8\x3b\x5c" + "\x3e\x2d\x2c\xf2\xf5\x80\x8b\x91" + "\xc5\x6c\xbb\xb7\x40\x50\x8d\x36" + "\x1c\xa1\x95\x26\xa1\x42\x61\xb6" + "\x70\xea\x19\xeb\x3a\x58\xac\x60" +
+       "\x37\x24\xab\x0e\x98\xbb\x7c\x31" + "\xc8\x54\x26\x5e\x55\x8c\xc0\x8c" + "\x7f\x30\xd8\xe6\x20\x65\x2d\xfe" + "\x93\x89\x42\x57\xf3\x47\xf1\xe9" + "\xf1\x6c\xfd\xd2\x14\x7d\x9c\x5f" + "\xb0\xcb\x4f\x2d\x64\xd0\xec\xa3" + "\xf7\x41\x73\x8e\xf0\xfe\x83\xad" + "\x5c\x11\x63\x3a\xa0\x23\x3f\x64" +
+       "\x43\xb7\x5a\xe6\xab\x78\x8a\xd3" + "\x9c\xc8\xed\x35\xb1\x75\x7c\xbf" + "\x68\xf5\x0d\x53\x2e\x75\xd8\x3d" + "\x82\xc6\x08\xe3\x76\x4a\x5c\xf8" + "\x37\xcf\x8a\xe6\xb2\x55\x99\x4c" + "\x85\xaf\x32\xab\x3d\xdf\x44\xa5" + "\x93\xf4\x5c\xa2\xf5\xc3\x8e\x4b" + "\xeb\x2f\x62\x1a\x64\x27\x8f\x4d" +
+       "\x49\xbc\xdc\xf0\xaa\xf7\xb4\x7b" + "\x5b\xb4\xbb\x70\xf9\x51\xe5\x7d" + "\xe5\xa2\x2c\x9f\xe4\xf3\xd0\xcf" + "\xef\x76\x5c\x1f\x09\x87\xe5\xec" + "\xae\x79\x7d\x16\xdd\x0e\x92\x32" + "\xc1\x7e\x7d\xfa\xa2\xf8\x9d\x03" + "\x91\xaf\x30\xbb\xc0\x06\x62\xf4" + "\x59\x6b\x67\x22\xf5\xe2\xf5\x1f" +
+       "\x66\x1d\xa5\x6e\x39\xa0\xf4\x11" + "\x26\x7a\x7d\x80\x45\x14\x6c\x50" + "\x24\x9b\x5a\x75\x05\x57\xda\x60" + "\x9e\x31\x1a\x1f\x32\xcc\xc8\x8f" + "\x7d\xd6\x33\x94\x4d\x2d\x64\x83" + "\x96\xd2\x7d\x6a\x8f\xcb\xa5\x7f" + "\x07\xde\x7b\x9b\xdb\x91\x65\x57" + "\xfb\x16\x97\x41\x25\x3d\x17\x13" +
+       "\xff\x40\xb3\xd5\x9d\x59\x30\xea" + "\xc5\x76\xfe\xb0\x97\x52\x6b\xfc" + "\xdc\x5a\x8f\xab\xc8\x68\x69\x1c" + "\x8d\x92\x1c\x90\xf5\xc7\x23\xf7" + "\x02\xd4\x73\x97\x21\xc3\x03\x42" + "\x47\xdd\x51\x1b\xa3\x6a\x7c\xdf" + "\x3c\xe2\x2b\x55\x7a\xe3\x49\x3d" + "\x87\x6e\x5a\x0b\xe8\xbe\xfe\x57" +
+       "\x39\xe7\xd8\x7b\xe4\xbe\xec\xc5" + "\x75\xbf\x63\xae\x94\x49\xd4\x79" + "\x23\x89\xfb\x38\x0f\xd0\x8b\x16" + "\x30\x31\x53\xd0\xe4\x8e\xd4\x75" + "\x33\xdf\x5c\xdb\xaa\x77\x4f\x55" + "\x69\x67\x69\x3c\x96\xe8\x96\x33" + "\x4e\x67\xfd\xd3\xf2\xdb\xdd\x2f" + "\xe5\xe3\xd0\x99\xee\xf6\xb8\xbb" +
+       "\x70\x2f\xae\xcb\x51\x06\xb9\x51" + "\xeb\xa8\xaa\x93\x05\xbc\xc4\xef" + "\x99\xf4\x1d\xdd\x89\x86\xcd\x8e" + "\xa5\x67\xf3\x22\xa8\x99\xee\x1a" + "\xc5\x74\x82\xae\xb9\x85\xd4\x95" + "\x9c\xb3\x30\x7d\x45\xd4\x14\x6c" + "\x81\xef\xc1\xbc\x0b\xa9\xfe\xba" + "\xed\xa2\x59\xa4\x7a\x31\x5f\x7c" +
+       "\x27\x42\xf4\x4e\x75\x10\x21\x01" + "\x96\xf4\x20\xdc\x6e\xed\x7b\xa1" + "\xcd\x53\x98\x81\x24\xe4\xdf\x0c" + "\xe7\x2c\x1e\xf7\x98\x32\x79\x13" + "\x7b\x30\xbe\xdb\x78\x30\x1f\x3c" + "\x36\x99\xee\x76\x0e\xc2\xd1\x6d" + "\x20\xaa\x3c\x42\x57\x4b\xee\x23" + "\x0e\x84\xfb\x8e\x3b\x79\xc3\x4a" +
+       "\xa0\x8c\x1f\xed\xeb\x38\x44\x93" + "\xa2\x25\xbb\x4e\x58\x66\x54\x3e" + "\x6f\x89\x69\xc0\x0e\xaf\x15\xc4" + "\x3d\xa4\x5a\x9a\xb0\xdd\x3e\xc1" + "\xf6\xb8\x9e\xd4\x4f\x20\x04\x7a" + "\x70\x16\x4f\xd7\xfc\xbd\xd5\xd0" + "\x58\x05\xfc\x56\x86\xe2\x97\x36" + "\xde\xba\xce\x01\x71\x73\x20\x10" +
+       "\x2b\xa8\x47\x06\x90\xe6\x87\x5f" + "\x4f\x05\x40\x8f\xd4\x0e\x8e\x90" + "\x03\x38\x85\x79\xd4\x33\xf6\xa9" + "\x52\xb2\x28\x4a\x9a\x3c\xd1\x8e" + "\x64\x0f\x46\x1f\x76\xf6\x2e\x3e" + "\x36\x63\xd0\x36\x9b\x0b\x93\x53" + "\x9b\x97\xc4\x8f\xac\x73\x70\x34" + "\x97\x55\xcd\x5e\x0e\x0e\x38\x84" +
+       "\x39\x3c\xfe\xc4\x6b\x2c\xb2\xe3" + "\xdf\xeb\x7b\x6c\x53\x81\x4a\xba" + "\x59\x34\x69\x25\xb7\xb6\x3a\xf2" + "\x11\x2b\x92\x14\x70\x37\xbc\x53" + "\xdb\x60\xfc\x5a\xab\xc8\x45\x46" + "\xa3\xf2\xb9\x20\x55\x23\x02\xaa" + "\x07\xc5\x0f\xce\x4c\x95\xa2\x52" + "\xe7\xc2\xe1\x7c\xbb\x31\x27\x8c" +
+
+       "\x89\xb8\x8f\xe4\xc2\x91\x70\x6a" + "\x06\x9d\x8a\x7b\x13\x2c\x88\x26" + "\xe2\xa0\x82\x1b\x63\x86\x49\xa2" + "\x2d\x15\x18\x35\x36\xd7\x4e\x84" + "\xc7\x27\x6e\xd8\x6f\x47\x2f\x28" + "\xdc\xef\xaf\x04\xca\xda\x4e\xa0" + "\x4d\xe3\x19\x61\xbc\x6e\x25\x8b" + "\x8b\xd7\x87\x07\xe9\x13\xa4\x56" +
+       "\x50\xbe\x74\x5a\x1d\x06\xee\x82" + "\xf5\x6f\xa1\xde\xc4\x81\x17\xe4" + "\xa2\xc8\xbf\x99\x1e\xc8\xb0\xe0" + "\x2d\x7e\x54\x0b\x69\x4d\x4f\x62" + "\xe4\x9a\xcc\xbd\x5d\x54\x83\x3a" + "\x8e\x1e\x9b\x40\xb6\xdb\x73\x25" + "\x39\x35\xc9\xa6\xc4\x60\x29\x48" + "\x98\x87\xe1\x5a\xad\x59\x10\xf0" +
+       "\x96\x9d\x55\x4d\x27\x1e\x15\x38" + "\x01\x6c\xdb\xb8\xd3\xc0\x18\x4f" + "\xaf\x21\x99\x6f\x83\xaa\xa3\x49" + "\x29\x60\x04\x8c\x7b\xb2\xea\xdb" + "\x3b\xbf\x40\x70\xaa\x9e\x2b\x24" + "\x91\xb0\x14\x16\xe5\x79\xc4\x39" + "\x5d\xaf\x4b\x0e\x2b\xde\x8e\x33" + "\x45\x39\xa5\xf0\xb7\x92\xb1\x5b" +
+       "\x5f\x79\x12\x31\x97\x9f\x5c\x71" + "\xe1\x6e\x4e\x98\x37\x44\x24\xe8" + "\xcd\x6b\xb6\xec\x58\x48\xcb\x55" + "\xee\xfb\xaf\xab\x35\x67\x13\x7c" + "\x8e\xc3\xbe\x5d\x95\x15\x66\x54" + "\x53\xd1\x8a\x38\x2c\x78\xc0\x51" + "\x2f\x95\xe0\xc6\x3a\xc5\xa4\x9b" + "\xa8\xdf\x21\x1b\x2a\x78\xe6\x27" +
+       "\x65\x7f\x5d\xec\x51\xc2\x89\x7d" + "\x87\x40\x39\x90\x16\x56\x8f\x0c" + "\xb3\x1a\x69\xf0\xfc\x1c\x9e\x60" + "\x21\x0b\xb2\xe9\xbf\x00\x03\x2a" + "\xf4\xfa\x14\xb1\xad\x2f\x53\xbf" + "\xd1\xf5\x1b\x52\xb9\xc0\x8f\x32" + "\xde\x36\xfc\x3b\x3c\xf9\x51\xbd" + "\x60\x5f\x4e\x7a\x0e\x05\x89\xd9" +
+       "\xc2\xdb\xd2\x4e\x3d\x90\x2f\x68" + "\x83\x2d\x3b\x7c\xc8\x59\xba\x0e" + "\x35\x93\x7e\x9c\x4d\xc8\x9d\x8e" + "\xd7\x26\xb2\x0e\xb0\x21\x9b\x5f" + "\xae\x7b\x26\xaf\x94\xd3\x3b\xe3" + "\xae\x15\x2e\xbe\x25\xcc\x86\xaa" + "\x00\xc5\x8e\x6a\x7d\xf6\x0b\x4f" + "\x58\x06\x63\xf9\x44\xaa\x46\x58" +
+       "\x78\xc2\xe0\xe7\x38\xba\x86\x67" + "\x6f\x2e\x8b\x58\xce\x87\xbf\x09" + "\x3a\xee\x5f\x46\x22\x70\x3b\x72" + "\x94\x23\x68\x64\x14\x41\xb8\x08" + "\x29\x46\xe6\x29\xe0\x2c\xb5\x0e" + "\x43\x8e\xa7\xcc\x8f\x0e\xb6\xad" + "\x91\xa9\x54\xb6\x62\x70\xdd\x20" + "\xe5\x6f\x9a\xc6\x28\xd4\x81\x42" +
+       "\x15\xbf\xc2\xe2\x40\x97\xb0\xfe" + "\x04\x97\xe9\xa9\x05\x22\x7a\x62" + "\x65\xc5\xfb\xc2\xd0\x73\x8d\xec" + "\xe8\x8d\x0c\xc2\x8f\xed\x3e\x22" + "\x49\x3b\x36\xa8\x83\x25\xe3\x1e" + "\xa6\xb0\xc2\xc9\xb9\x6c\x0b\x1a" + "\x5c\xc8\xdb\x90\xd2\xc3\xf7\x49" + "\xac\xc1\xf4\x1e\x97\xbb\xdf\xa8" +
+       "\xe1\x2e\x1e\xc0\xa3\x7c\x25\x5c" + "\x61\x69\xc3\x27\x14\x3a\xb4\x1f" + "\x24\xf3\x72\x34\xcb\xa7\x94\xd5" + "\x10\xbe\x0a\x66\x24\xc0\x5e\xc1" + "\xed\x4c\x61\x6b\x49\xd4\x76\xb1" + "\x85\xb8\xdb\x62\x4d\x73\x04\x0b" + "\x87\xb5\xdd\x36\xc6\x53\xb7\x2c" + "\x0c\x34\xcd\x14\xe6\x80\x1c\x9a" +
+       "\xab\xc2\xc7\x65\x4c\x4d\xb3\xaf" + "\x84\xea\xc5\xe2\xe7\x10\x46\x1d" + "\xb5\x4a\x3c\x97\x1b\x6d\x3f\x89" + "\xc4\xa5\x5b\x94\xe9\xd7\xcd\xa3" + "\xee\x17\x44\x06\x83\x49\x51\x60" + "\x2b\xdf\x6b\xad\x3c\xb2\x59\x14" + "\xc3\x26\xf7\x5c\x41\xc3\xb2\x23" + "\x4a\x35\xd6\x32\x35\x96\x82\x3a" +
+       "\xcd\xe7\x6f\xc0\x96\x56\xf6\xe9" + "\x15\x3a\xfd\x9a\x57\x30\x06\x51" + "\xed\x60\x53\x18\xa6\xac\xcd\x3d" + "\x2f\x3d\x85\xc1\x3d\x70\x41\x27" + "\xa0\xf1\x33\x1a\x4a\xd8\x8a\xbd" + "\x7c\xb0\x5c\xc3\x8c\x69\x6c\x5f" + "\xb9\xe6\x61\x65\x19\xd1\x2b\x21" + "\xd7\x4f\x7b\x61\x7e\xcd\x49\xf1" +
+       "\x18\x2c\x19\xab\x1f\x90\x4f\x29" + "\x4f\x16\x30\x70\xfe\xcb\x5f\xec" + "\xa6\x6b\x24\xe2\xb7\xfc\xe2\xe2" + "\x0c\x1a\x1a\x22\xb3\x88\x7c\x1e" + "\xc5\x88\x2d\xc9\x93\xdd\xc7\x72" + "\x59\xfb\x06\x11\x8e\x14\xc2\x41" + "\x14\x0f\xf6\xa0\xf5\xd4\x7d\x54" + "\x31\x0f\x96\x63\xb2\x52\x9b\xed" +
+       "\xf8\x2b\xe8\x30\xc5\xc9\xe3\x1c" + "\x2a\x77\xbb\x0d\x42\x25\x66\x4d" + "\x14\x72\xc1\xd9\x60\x5a\xe2\x19" + "\x55\xfa\x22\x77\x4c\xf8\xbc\x13" + "\xa7\xf7\x9e\xf8\x0e\xca\x8a\x22" + "\x55\xd4\x3e\xfd\x2f\x4e\xd6\x03" + "\x04\xc9\xe6\xdd\xf5\x90\xc3\xf1" + "\x8a\xe1\x78\x76\xa6\x52\x14\x73" +
+       "\x58\xb3\xa5\xb0\xeb\x49\x83\x6c" + "\xd6\x2e\x7e\x9e\xc2\xc5\x54\xb1" + "\xdb\x62\xa4\xed\xcf\xec\xd5\xca" + "\x69\x6b\xe6\x2d\xe4\xdb\xd6\xf2" + "\xb2\xe5\x65\x86\xf3\xed\x6a\x42" + "\x23\x57\x7f\x7b\x13\x85\x8a\x48" + "\x86\xb3\xcb\x8b\xb3\x43\xcc\x15" + "\x79\xd8\x91\xd7\xf3\x0a\xad\x27" +
+       "\xba\x2c\x63\xa0\x61\x6e\x00\x3c" + "\xcd\x5c\xb3\x45\x48\x92\x0d\x92" + "\x65\x7f\x5c\x7c\xfb\x79\x33\x4b" + "\x0b\x05\x5e\xb0\x10\xdf\x6c\x52" + "\xae\xf1\x1b\xd2\x36\xe9\x88\x31" + "\x2f\xbd\x4b\x62\x39\x7b\xe0\xb3" + "\x41\xa5\x67\x13\xf3\xfc\x9b\x7b" + "\x27\x79\x36\x8a\xc8\x8e\x9f\x03" +
+       "\x4f\x36\x6e\x84\x6e\x23\x6c\xc1" + "\xa0\x0c\xa5\xde\x7c\x52\x33\x7f" + "\x6d\xb8\x26\x09\x75\x07\x81\xc4" + "\x0c\xe7\x98\x05\x09\x36\x2a\x6c" + "\x24\xe9\x24\xf0\x52\x5e\x75\xa6" + "\xca\xaf\xb4\x9d\xa4\x07\xfa\xe0" + "\x90\x17\x83\x66\x7d\xce\xc3\x15" + "\xd6\xb0\xcb\xa6\x50\xf3\x4e\x5b" +
+       "\xf4\x82\x69\x43\xe0\x04\x85\x34" + "\x79\xec\xe3\xd8\xee\x05\x49\xc9" + "\x9e\x17\x09\x35\xcb\xfd\x2c\xb9" + "\x14\xd9\xe6\xf9\xd0\x66\x52\x24" + "\x55\x69\x31\xad\xd0\x50\xaa\x8b" + "\x60\x7f\x22\xca\x79\x5c\x23\x77" + "\xd8\xf9\xe5\x51\xc9\x27\xc9\xf2" + "\x0f\x94\x79\xe6\x30\x8c\xbf\xeb" +
+       "\x69\x59\x20\xb6\xc4\xaf\x4a\x2c" + "\x4f\x85\xc7\xf6\x02\x3f\x56\x42" + "\x48\x3b\x98\x1d\xd5\xce\x6a\x01" + "\x55\x97\x94\x99\xd8\x56\xb3\xfe" + "\xd7\x9b\xa3\xd1\x81\x2c\x2a\x8c" + "\xe9\x4a\x93\xe6\x0f\x34\x44\x8f" + "\xda\x04\x79\x44\x1c\xf9\x8c\x14" + "\x26\xa9\x51\x0f\x5f\x18\x40\x73" +
+       "\x90\x69\xac\xce\x66\x5f\xe9\xe4" + "\xce\x16\x6c\xbe\x16\x1d\xdc\x17" + "\xbe\x0c\xad\x45\x55\xa0\x67\x29" + "\xb6\x7e\x6f\x71\x97\x2f\x0e\xdd" + "\x91\x3b\xc3\x2d\xf3\x7f\x8b\x33" + "\xde\x76\xe9\x2f\xf5\xae\xf6\xdc" + "\x6e\x3f\x19\x43\x1c\xf7\x1c\xf5" + "\xe3\x77\xc0\xe8\xc4\x44\xe4\x15" +
+       "\x46\xab\x09\x74\xfb\x00\x8f\x2f" + "\xb2\x89\xe2\x80\xe6\x78\x7e\x05" + "\xd1\xe5\x88\xa8\x2c\x02\xe5\x03" + "\xe2\xe4\xed\x9d\x1a\x11\x87\x3c" + "\x0b\x46\x09\x78\x1c\x0e\x9b\x5b" + "\xc7\xab\xc9\x71\x52\xc8\x51\xe7" + "\xc9\x1d\xcc\xc7\x28\x4e\x94\x8b" + "\x08\xfa\x3c\x1d\xfa\x1f\x20\x4f" +
+       "\x49\xc0\x9f\x0f\x2d\xfe\x78\x60" + "\x1a\xd1\xf6\x40\x50\x97\x9d\xd9" + "\xb7\xc0\x54\x08\x97\x9a\xae\x87" + "\x79\xfb\x02\x93\x9c\xb0\xce\xf4" + "\x3f\xa8\x32\x2c\x68\x01\x2f\x50" + "\x24\x50\x68\xb1\x71\x27\x35\x1e" + "\x19\x2b\x79\x66\xf2\xf6\x0d\x97" + "\xfd\x87\x8d\x9c\xbb\xd0\x07\xf5" +
+       "\xce\x21\x67\x3e\x5c\x90\xfc\x02" + "\x4c\x67\xb3\xd0\xda\x70\x2d\xd5" + "\xa4\x0d\x81\x18\xca\xe5\xc2\x5d" + "\x99\xdd\x69\x5c\x73\xb2\x84\xa9" + "\xa4\x5c\xde\x84\x27\x25\xb9\x63" + "\xc4\xde\x52\xc8\x72\x98\x1c\x2f" + "\x09\xde\xe3\xc2\x93\x35\xb0\x18" + "\x2f\xdc\x13\x98\x01\x0b\xd7\x19" +
+       "\xb2\x38\x63\x42\xce\x40\x4e\x15" + "\xc9\x88\xaa\x96\x00\xb0\x2c\x7b" + "\x25\xf9\x51\xad\xfc\x01\xc9\xd5" + "\x10\xee\xd0\x7e\x6c\x21\xbd\x5a" + "\x64\xe1\x7d\xf8\x57\xd5\xc3\x73" + "\x6d\x51\x39\xe1\xdc\xd1\x3a\x69" + "\x7a\x54\xbd\x3e\x3a\x7b\x76\xb4" + "\x82\xa9\xf4\x20\x4c\xc2\xb3\xb8" +
+       "\x29\x1d\xdc\xa6\x2d\x6b\x80\x42" + "\x44\xe1\x71\xf8\x09\x00\x03\xd3" + "\x76\x92\xf4\xaa\x33\xb3\xfe\xa1" + "\x4b\xc0\x0b\xc7\x9e\x3b\x58\xb5" + "\x20\x5f\x69\x95\x78\xbe\xb0\x1d" + "\xb5\x12\xd0\x89\x11\x18\x84\xfc" + "\x43\x16\xf6\x05\x72\xf2\x09\x64" + "\x28\x31\x88\xd5\x74\x41\xd3\x40" +
+       "\x7b\x7c\x56\x08\xcd\xa0\xfb\x64" + "\x54\xfb\xcb\xa2\x0d\x59\xea\xc9" + "\x73\x0d\x6d\x13\x16\x77\x6f\x66" + "\x0d\xa3\xf2\x38\x48\x96\xa0\x2c" + "\xa9\x0c\x4e\x0f\x24\x45\xa5\x7f" + "\x4b\xb8\xbe\xc1\xa8\x01\x33\xef" + "\x2a\xb9\x62\xbc\x0e\x93\xcb\x45" + "\xea\xcb\xb6\x9b\x05\xc7\x4a\x96" +
+       "\x33\x98\x41\x67\xf5\x96\x91\xd7" + "\x08\x7b\x3b\x86\x52\xe2\x59\x60" + "\x0c\x70\x56\x1c\x17\x18\xda\x84" + "\xc4\x3e\x8d\xb2\x56\xee\x58\x57" + "\xa6\x0e\x3b\x01\x1d\x77\xa2\x7d" + "\xb9\xe9\xc5\x54\x4b\x52\xdf\xfd" + "\x80\x5d\x30\x24\xf8\xfa\xf4\x7d" + "\x3f\x76\x97\x3a\xbf\xc1\xf5\x58" +
+       "\x1f\x26\xf5\x81\xcc\x71\xf6\xea" + "\xef\x83\xfe\xbc\x06\x35\x08\x7d" + "\x6e\x53\x88\x31\x0b\xc5\xcd\x94" + "\xcd\x3e\xdd\x24\x41\x2c\x0b\x41" + "\x0c\x52\x05\x02\xcc\x99\xcb\x57" + "\x6d\x44\x06\x5f\x68\xa2\xf3\x23" + "\x17\x4b\xa0\x49\x43\x7e\xb2\xb2" + "\x12\x5a\x78\x81\xf3\x66\xb2\xab" +
+       "\x42\x60\x69\x7c\xf1\x37\xaf\xa5" + "\xde\x38\x25\x4a\x2c\xa2\xcb\xd4" + "\x00\x26\xa4\x9e\x95\xb9\x1c\x21" + "\x89\x98\x06\x7b\x41\x5f\x10\xcd" + "\x74\x1e\xb8\xdd\x19\xcf\xe1\xb1" + "\xca\xb8\x57\x51\x89\x2d\x2f\x47" + "\x85\xb8\x9d\xee\x08\xb0\x6f\x08" + "\x31\xd1\x26\x0f\x70\xd5\x5c\x36" +
+       "\x5a\xfe\xb7\x66\x5d\xba\xa7\x00" + "\x56\x5d\xfd\x05\xac\x74\x86\x81" + "\x57\x5a\x14\x04\x3c\xb0\x8f\x68" + "\x2c\x83\xd5\x97\x88\x65\xc1\x76" + "\xa7\xab\x45\x12\xd8\xdc\xf0\xa0" + "\xe9\xf6\x47\x18\xaa\x7c\x07\xdd" + "\xd0\xad\x34\x0d\x14\x53\x03\xf9" + "\xed\x3d\xb7\x48\x11\x7c\xe3\x22" +
+       "\x53\x70\xbe\xa2\xbb\x02\x4b\x28" + "\xd6\xa6\xb9\x7a\xc6\xf7\xbb\xdc" + "\x30\xa5\xf7\x20\x9c\x55\x25\x44" + "\xc8\x67\x87\x18\xfa\x2d\x1f\x96" + "\xc4\x80\xdc\x70\x35\x94\xfd\xe2" + "\x20\x41\x78\xf0\x63\x6b\x4d\x10" + "\x22\x71\x56\x53\xc1\x2b\x59\x7f" + "\x77\xad\x88\xf6\x46\x12\xbc\xf6" +
+       "\x06\xb0\x0a\xb7\x6b\x43\xfe\xfd" + "\x1d\x1a\x99\x18\x19\xd1\xe7\x57" + "\xb0\xc0\xd4\x34\x28\x42\x54\x3a" + "\x04\x84\xb5\x32\xd4\x1d\x09\x26" + "\x99\xf8\x2a\x27\xfc\x6d\x11\x8b" + "\x77\x87\x11\x34\x87\xdc\xf8\x51" + "\xbc\xf0\xa7\xdf\x40\xa3\xf0\xc0" + "\xdd\x97\xad\x56\xf6\xa5\xc5\x22" +
+       "\xe9\xdd\x15\x0f\x05\x4c\x21\x05" + "\x82\x2b\x5f\x0d\xa8\x76\x7a\xa4" + "\x62\x2b\xe8\x62\x30\x4d\x25\xbb" + "\xee\x55\xc9\x3e\xe0\x5f\xa0\x11" + "\x36\x9b\x52\x9d\x6e\xf4\xaf\x7e" + "\xf6\x3d\x9e\x8f\x01\x13\xab\x55" + "\x98\x76\x31\x99\x71\xe3\x63\xc4" + "\xad\x47\xda\xcc\x38\x14\x25\xfd" +
+
+       "\x4e\x89\xfb\xdb\xf3\x22\x31\xe1" + "\x18\x4b\x27\xce\xf6\x79\x9b\xbe" + "\xdf\xaa\x58\xca\xe5\x9d\xa4\x85" + "\x51\x73\x48\x11\x58\x77\x95\x24" + "\x99\x90\x93\xbb\x61\xef\x1d\x11" + "\x94\x36\xd1\x26\x4a\x97\x6a\x1d" + "\x3b\x25\xfc\xd3\xce\xb4\x74\x44" + "\x5e\xb1\x5d\x4c\xe6\x85\x14\x3a" +
+       "\x18\x6f\xd6\x1e\xec\x86\xde\xeb" + "\x43\xce\x1f\xd6\x6b\x90\x5d\x22" + "\x4d\xd7\xbe\xe8\xd6\x07\xab\x5c" + "\xb7\x5a\x85\x27\x7f\x61\xe4\x16" + "\xdd\xc3\xfb\xb2\xdd\xaa\x68\x65" + "\x5b\xdf\xed\x8a\x4f\x48\xb5\xed" + "\xad\x2f\xcf\x6d\xe8\x20\x8f\x87" + "\x99\x56\x5f\x61\x7c\x49\x16\x35" +
+       "\xe2\xac\x7b\x70\xe8\xae\x58\x51" + "\x56\x1c\x6d\xf8\xc6\x14\x8d\x45" + "\xe2\xbe\xb9\xc1\x5c\xf1\xeb\x15" + "\xc0\x9c\x37\x0f\x66\xdf\x15\xa0" + "\x61\xd1\x2e\x20\xa3\xeb\x4c\xb2" + "\xf0\x3d\x4b\x20\x87\xf6\x58\x45" + "\x04\x4c\x26\xbe\xed\x8e\x0e\x89" + "\xb7\x8b\xde\x90\x10\x87\xb7\xb5" +
+       "\x69\x1e\x18\xfa\xec\x3f\x0a\xef" + "\x98\x9a\xd6\x30\x81\x2f\xa0\x9e" + "\x5d\xb9\xea\x66\x8e\xcf\xe9\xb2" + "\x21\x00\x72\x24\xeb\x2b\x0f\x52" + "\x61\x43\xf8\x1d\x0a\x54\x1c\x62" + "\x5d\x6d\xfa\x71\x21\x77\x03\x12" + "\xff\xf6\xf5\x0f\x51\x7b\x3c\x6e" + "\xf3\xbe\xb2\xab\x9b\x06\x7a\x81" +
+       "\x05\xcd\x81\x97\x11\x2f\x2b\x7e" + "\x2b\xa1\xaf\x7e\xe2\xc2\xa8\x77" + "\x5e\x38\x81\xa3\x3c\xd0\xfd\x78" + "\xad\x85\xab\x15\xbb\x54\x3b\xab" + "\xd4\x8a\x1c\xcf\xaa\x55\xbe\x48" + "\x81\xbc\x8a\x52\x58\x0c\xa6\x57" + "\xb3\x93\x68\x4a\xfe\xb5\xaf\xf8" + "\xcb\xcc\x66\x9a\xcf\x79\xd1\xbd" +
+       "\xb1\x09\x6c\x65\x77\x7d\x4f\xf1" + "\x00\xdf\xa9\x29\x95\xac\x40\x4b" + "\x33\x38\x10\x14\x82\x48\xdc\xe9" + "\xc7\x45\x17\x42\x33\x32\x63\x4c" + "\x69\x03\xc2\x75\xc5\xcc\x2f\xd2" + "\x36\x0c\x37\x89\xa5\x42\xf2\x47" + "\xcf\xec\xda\x4e\xae\x16\x8c\x1e" + "\xc4\x78\xcf\x4f\xb0\xab\x8e\xad" +
+       "\xcf\x98\xc5\x9e\xba\x05\xe6\x3d" + "\xae\x29\x30\x4d\xae\xd3\x33\x19" + "\x16\x05\x14\x9b\xbd\xfa\xf2\x6b" + "\x1c\xd0\xa7\x59\x55\xfc\x2d\x71" + "\x66\x63\x57\xd2\xe0\xaa\x3e\xff" + "\xf8\x1c\x70\x48\xf9\x07\xe4\x36" + "\xd4\x4b\x1f\xb4\x89\x1d\xe2\xed" + "\xa9\xef\x6e\x66\x5c\x2f\x29\xc5" +
+       "\xa6\xcd\x94\xb2\xb6\x2f\x57\x83" + "\x34\x9f\x03\xb9\x75\xbf\xe9\x6c" + "\x21\xbb\x5c\x09\xf0\x12\xe0\x20" + "\xda\xf0\x63\xd0\x1b\xcc\xae\xa0" + "\xe5\x09\x29\xf0\x3a\x1c\xc2\x57" + "\xdc\x9c\xce\x48\xcf\x9e\xd5\xc7" + "\xf8\x36\xe3\x8a\x44\xb8\x32\x27" + "\xf4\x85\x4f\x3f\x23\x37\x6e\x05" +
+       "\x52\xa8\x78\xef\x21\x5d\xb7\xf2" + "\x00\xa9\x31\xdd\x34\xcd\x38\xba" + "\x8a\xe1\xff\x58\x86\xa6\xb3\x72" + "\x45\x57\xd9\xbf\x0c\x19\x64\x74" + "\x81\x6e\xed\x77\x21\x53\x6e\x40" + "\xab\x5e\x53\xde\x5b\x97\xf0\x1a" + "\x82\x4c\xc5\x60\xc7\x22\xba\x66" + "\xe0\x2f\x0a\xb0\xce\xb1\xe3\x88" +
+       "\x15\x7b\x33\xf0\x77\xf9\xb7\x55" + "\x3a\x97\x94\x0e\xa3\x72\xc8\x3b" + "\xa0\xee\x0d\x77\x83\xd9\x4a\x62" + "\xdb\xef\xa5\x13\x64\x33\xab\xca" + "\x47\x42\x0d\x7a\x02\xd0\x1d\x39" + "\xd5\xae\x12\xf3\x5d\x0d\x59\x39" + "\xac\x65\x13\x35\xc9\x02\x28\x53" + "\x2a\xe2\xa2\x78\x45\x82\x2e\xdd" +
+       "\x87\xe6\xbe\x2e\xa5\xa6\xc6\x98" + "\x31\xc7\xc1\x56\xfa\x5b\xf6\xcd" + "\x10\xf2\xde\x72\x27\x13\xe8\x48" + "\xa5\xb5\x83\x80\x41\x19\xa1\x4e" + "\x25\xb5\xeb\xff\x4f\xea\xdc\x3f" + "\x72\xbf\x50\xfb\x19\xea\xaa\x55" + "\x0c\xb4\x85\x2a\x0a\xdc\xbe\x5f" + "\x9f\xf2\x44\xbf\x54\xd9\x6f\x0d" +
+       "\xca\x00\xe8\x89\x31\xb5\x10\x8a" + "\xfd\x08\x52\x14\x17\x0c\xfe\x50" + "\x37\xba\x14\xb7\xd3\xc0\x43\x9e" + "\xcc\x9a\x18\x34\x0e\x20\x7d\x42" + "\xc0\xe2\x16\xe6\x4f\xe2\xde\x05" + "\xc1\x54\x18\xee\xc8\xf4\x25\x9c" + "\x73\x2a\x34\x8f\xa5\x22\x32\x4d" + "\x52\xc9\x27\xa0\x4f\x80\x07\x08" +
+       "\x6f\x32\x8f\x2e\xf8\xb7\xbf\xba" + "\x19\xa5\x25\x56\x22\xac\x9c\xed" + "\xa9\xe0\xda\x0e\x1a\x9c\x10\xf1" + "\x59\x12\x52\x58\x98\x0a\xf8\x45" + "\x44\x1f\xb7\x5a\x07\x4b\xa4\x37" + "\x1b\x16\x21\x4a\xb6\x9e\x69\x21" + "\xee\x67\xfe\x56\xdf\xfd\x23\xb5" + "\x2e\xf7\xb9\x20\x21\x3a\x5c\x9f" +
+       "\x73\x6e\xd2\x50\x33\x4a\x41\xba" + "\x88\x26\xf7\x75\x94\x44\x69\x45" + "\x82\x0f\x55\xb1\xe3\xa6\x82\xd4" + "\x7e\x6d\x16\x43\xe6\xf7\x7f\xde" + "\x2a\x22\x94\x9c\x68\xc6\x97\xad" + "\x40\x98\xfa\x72\x2d\x92\xa5\x90" + "\x5f\xaa\xe6\x32\xbd\x86\x18\x37" + "\x44\x0d\x5e\x7f\x67\x4f\xbd\xf1" +
+       "\xc5\x19\xa3\xfb\x76\xb2\x8e\x05" + "\x4a\xa5\x7f\x7f\x12\x91\x3a\xd3" + "\xab\x2d\x2a\x93\xb4\xc1\x60\xf0" + "\xbf\xd9\xc7\x79\x4e\x22\x3a\xce" + "\x23\x28\xa9\x0b\x8c\x38\xb0\x6f" + "\x81\x78\x78\x69\x8a\x73\x31\x8d" + "\xb7\x00\xcd\x03\x02\xeb\x86\x2d" + "\x1b\x91\x69\x2b\x51\x44\x6e\x4e" +
+       "\xf3\x56\x0d\x4f\x3a\x65\x22\xc2" + "\x05\xb8\x28\xca\x47\x40\x1e\x96" + "\x4b\x43\x73\x4a\xb0\xf8\x03\x2c" + "\x19\x2a\x71\xab\x87\x67\x96\x4c" + "\x42\xee\x4f\x86\x42\x6c\x19\xcc" + "\x5c\xce\x0e\x5b\xda\x93\xbe\xc1" + "\x59\xc1\x31\xc1\x22\x9f\x7d\xa8" + "\x55\x56\xe4\xdc\x93\xd5\xb6\x2b" +
+       "\x42\x40\x89\x4c\xa9\x5a\x95\xec" + "\xed\x92\x2f\xf2\x9a\x17\x32\x9d" + "\x08\x65\x28\xfa\xf0\x0f\x02\x5e" + "\xda\x1c\x9b\x23\x3a\x86\x49\x46" + "\x8f\x45\xf1\x11\x92\x1b\x71\xa5" + "\x6d\x35\x9b\xde\xec\x93\xd4\x7d" + "\x94\x81\xad\x80\x82\x06\xf9\xe4" + "\x73\x97\x30\xfe\xc1\x7a\x86\x81" +
+       "\x3c\x91\x78\xad\xfe\x96\xdd\xe9" + "\xb5\xb7\xee\x86\x14\xb5\x5e\x32" + "\x8e\xb0\x93\xa1\x61\x74\x74\x85" + "\x41\x35\xdc\x5a\xaa\x0d\x84\xf5" + "\xda\x9f\x36\xdb\x44\x0c\x1d\xc1" + "\x05\x92\x75\xad\xd9\x4a\xb1\x3a" + "\xa2\xaf\x8f\x03\x3d\x9a\x3f\x53" + "\x04\xf7\xe3\xfd\x53\x65\xdf\xfd" +
+       "\xc6\xa4\x15\x29\x90\x69\xaf\xbe" + "\x11\x1c\xc3\x37\x4d\xc0\xdb\xd5" + "\xc8\xcb\x1f\x28\xba\x2a\xa7\xa7" + "\x21\xe6\x4a\x3f\x8d\xf2\x78\xa1" + "\x95\x08\x8d\x9b\x76\xdc\xdd\x23" + "\xd0\x06\xb2\x93\x84\xd7\xae\x88" + "\xe4\xa4\x32\x0e\x09\x1a\xe6\x6e" + "\xf4\x03\x2f\x26\x3b\x2e\x48\x1d" +
+       "\xce\xb7\x09\xb8\xc9\x9e\xc4\x22" + "\x2c\x2c\xc7\xe2\x6b\x48\x41\x8a" + "\x36\xbf\xa0\xfe\x20\x94\x3b\x81" + "\x69\xac\x6d\xa6\xe9\x6e\xd3\xb3" + "\x87\xc9\x8c\x32\x8a\xc0\xdd\x6f" + "\x61\x64\x32\x3a\x2c\xcd\x3b\x0a" + "\xba\xdb\x10\xd8\x9d\xc4\x03\x71" + "\xc4\xa4\x78\x4b\x28\x1a\xd8\xf9" +
+       "\x99\x0b\x18\xdd\xe8\xd8\xd1\xfe" + "\x49\x39\x3a\xd3\x3f\x33\x8c\xdd" + "\x99\x23\xb7\xb9\x2d\xdf\xdf\xcd" + "\x26\x55\x78\x8c\x3e\xe5\xa6\xad" + "\xb4\xe1\xbd\xc1\xed\xbf\xdf\xa0" + "\x4e\xd5\x77\x24\x81\x6b\x43\xc7" + "\xe8\x45\x32\xe7\x41\xd6\xec\x27" + "\x90\xcc\x97\xe0\xf1\x77\x8f\xb6" +
+       "\x66\x5c\x62\x2b\x1e\x62\xa3\x1a" + "\x0f\xe5\xea\xa9\xae\x5d\xdc\x48" + "\x58\xa1\x52\x7d\xc2\xac\x06\x57" + "\x5c\xa2\x91\xa9\xa2\x51\x15\x0a" + "\xeb\xb4\x0d\x97\x6a\x04\x54\x46" + "\x4b\x7e\xff\x35\x4d\x4d\xbe\x2b" + "\xb9\x2f\xa6\x18\xe7\x6a\x85\xd9" + "\x8e\xd3\xa7\x10\x04\x16\xa0\xac" +
+       "\x89\xdb\x76\x7a\xeb\xbb\xa0\x6b" + "\xf5\x2a\x35\x13\xbd\xc3\xc5\x1b" + "\x08\xbd\x44\xdd\x18\xfe\x3e\xb8" + "\x49\x24\xd8\x8d\xa7\xbe\xd6\x4b" + "\x0e\xd9\xf9\xda\x24\x31\x97\x4a" + "\x4c\xd8\x32\x33\x0c\x89\xdb\x6e" + "\x1b\x84\xbb\x9b\xe6\x39\x3e\xc2" + "\x6d\x3e\xae\x07\x45\x35\x8f\xc3" +
+       "\x41\x59\xd5\xe4\xad\x65\xe8\x3d" + "\x87\x40\x38\x30\x5e\xfa\xda\xde" + "\x9b\x8b\xf1\x4e\xbb\x4a\x41\x6f" + "\x68\x52\xee\xfa\x42\xea\xe9\x9e" + "\x4a\x5a\xa5\x37\x16\xaa\x0f\x26" + "\xb9\x93\x5f\x01\x14\xa5\x19\xeb" + "\x98\x35\x9c\x9e\xd2\xeb\xd7\x51" + "\x8e\x17\x32\x19\x6d\xc5\x3f\x52" +
+       "\xc8\xf1\xcf\x9a\x08\xdd\xc6\x9f" + "\x0d\xb6\x25\x9b\x2f\xac\xe8\x20" + "\x4c\x5c\xd9\xd4\xab\x30\x29\x22" + "\x7b\x50\xb2\x15\x4e\xb0\x77\x1e" + "\xeb\xda\x9c\x2d\x19\x88\x6b\x7a" + "\x3a\x79\x97\x31\x18\x4d\x5d\xf1" + "\x92\x4b\xed\x1c\x72\x2a\x70\x38" + "\x34\x93\xea\x37\xb0\x92\x8d\x94" +
+       "\x1d\x9d\xf3\x16\xa3\x9f\xf8\xda" + "\x51\x6f\x28\x60\xa3\xec\xdf\x4f" + "\xd2\x3a\x05\x79\xe9\xc5\x37\x1d" + "\x40\xfa\x58\x19\x30\x0e\xa7\xde" + "\x7c\xe6\x1f\x25\xef\x96\x0a\xd0" + "\x74\xbe\x94\xeb\x2b\x1a\xc0\xd8" + "\x75\x4b\xfd\x0c\x38\x44\x2a\x0e" + "\x2c\xf2\xbd\x85\xb2\xc7\x1b\x87" +
+       "\xf4\x22\x86\x3c\x28\x94\xff\x9f" + "\x40\x84\x46\x8c\x8f\x32\x6e\xb7" + "\x70\x0f\xae\x31\x97\xe1\xc5\x60" + "\xbc\x9c\x72\xec\x77\xd1\x6d\xf8" + "\xa2\x97\xf4\xf3\x30\x35\x81\x21" + "\xe7\xfe\x20\x59\xc1\x92\x31\x7f" + "\xe5\x1e\xc5\xe1\x31\x0c\x0f\x0e" + "\x10\xdd\xf4\x22\x73\xcd\x36\xf3" +
+       "\x84\xe6\x8f\xb9\x0c\x07\x1d\x50" + "\x58\x14\x4a\x12\x9a\xbe\x0f\xd6" + "\x3f\x6b\xbc\x92\xc8\x61\x57\xa4" + "\xcb\x27\x6f\xfe\x58\x48\x38\xf5" + "\x3b\x76\x9e\xb5\xf7\x71\x02\x4b" + "\x5e\x8e\x5a\x5b\xa9\x06\x46\x3d" + "\x92\x82\xa4\x05\x9b\x5d\xda\x1e" + "\x46\xc4\xfe\xe6\xd0\x31\x77\xda" +
+       "\x20\xff\x18\xeb\x77\x51\x7b\x27" + "\x62\x6d\xf0\x28\x98\x2e\x00\x48" + "\x8d\x6d\x50\x0e\xc3\xd6\xe8\xec" + "\x63\xf9\x9f\xcd\x58\x0a\xde\x5c" + "\x0e\xaa\x3b\x4e\xb7\xcd\x97\x3b" + "\xf9\x38\x12\x63\x0b\x0c\x56\x50" + "\x3d\x79\x79\xcf\x35\x1b\xc3\xe1" + "\x78\x21\x5e\x35\x14\x2f\xd1\x95" +
+       "\x37\x88\x42\x2f\xc3\xb9\x21\x3d" + "\xbf\x02\x34\x0f\x1e\x6b\xc9\x73" + "\x9e\xf3\x4f\x42\xc9\xbf\xf7\x6c" + "\x96\xd6\xd0\xf6\x59\xa4\x2d\xca" + "\x4e\x15\xb8\x3b\x9d\xd6\xf1\x3c" + "\xb4\xed\x30\x54\x16\x9b\x42\xc2" + "\x75\xd3\xd0\x15\x8a\x47\xc6\xd3" + "\x6b\x37\xe4\x7d\x7f\x06\x33\x5e" +
+       "\x62\x59\x20\xcb\x5d\x30\x8c\x37" + "\x9a\x59\x04\x3d\x9d\x9f\x40\xe1" + "\xb2\xc1\x57\x80\x27\xba\xec\x84" + "\xb1\x80\xbd\xa2\xe7\xac\x92\xcc" + "\x60\xc7\xc4\x4c\xdb\x11\x53\xcb" + "\xfe\x8e\x6d\x46\x63\xce\xf0\x18" + "\xee\x49\x72\x08\x1b\xeb\xa0\x0d" + "\xf3\xde\xfb\x56\xfb\xe3\x47\x7d" +
+       "\x71\x58\xd4\x90\x93\x36\xe3\xa3" + "\x8d\x6d\x16\x06\x40\x40\x76\xe9" + "\x03\x04\xa9\x89\x82\x36\xc3\xb5" + "\x37\xd6\xf1\x72\x83\x79\xd1\x4b" + "\x3a\xc5\xd2\xd5\x9e\x67\x16\xa6" + "\x87\x3b\xcf\xfd\xd8\xbc\xc4\x5e" + "\x4e\x69\x6a\xb6\x13\x76\x6d\xae" + "\xe5\x27\xfc\xe3\x76\xfc\x60\x74" +
+
+       "\x62\x49\x3c\xc6\xe1\x1f\x53\x80" + "\x25\xdb\x1f\x98\x89\x1e\x54\x50" + "\x6b\x2b\x4c\xfd\xa1\x91\x12\xdc" + "\xca\x4f\xdf\xa6\x17\x3a\x69\xc0" + "\x03\xf2\x17\x01\x4e\x60\xc4\xb2" + "\xd0\xb8\x99\x0a\x63\x19\x5f\x24" + "\x44\x2c\x21\xc6\xaa\x20\xdc\xae" + "\xa8\x52\x0f\x52\x56\x4e\xed\xb1" +
+       "\xcd\x1a\x0a\x70\xb6\x0f\x56\xb5" + "\x81\x96\x99\xfd\x73\xfd\x23\xe8" + "\xba\xe1\xb4\x6c\x1f\x5d\x91\xda" + "\xa3\x00\xbe\x6e\x18\x01\x03\x0d" + "\xcd\xa8\xfc\x89\xc9\xb0\x4f\x74" + "\x0b\x0e\xda\xf9\xdb\x01\x0d\x97" + "\x6f\xd7\x31\x79\x64\xc5\xd8\x0a" + "\x6a\xb9\x59\xf6\xbf\x37\x57\xb1" +
+       "\xda\x22\xdf\x6b\x9c\x7a\xf3\x18" + "\xdf\x82\xdc\x90\x2f\x43\xbc\xef" + "\x51\x36\x70\x5d\x8e\xef\x2c\xc5" + "\xa5\x81\x98\xd9\xa0\x7b\x88\x82" + "\x1d\xec\x20\xb9\xda\x9d\xec\x7c" + "\x3b\x8d\x3e\xec\xc3\xe8\xd7\xd0" + "\x47\x87\xa8\x4c\x95\xc3\x5b\x44" + "\x35\x35\xd5\x9f\xe0\xa2\xea\xed" +
+       "\xd0\xc2\x53\xce\x4e\x38\x2b\xa1" + "\xda\x06\x46\x5e\x7d\x89\x9d\x77" + "\xb0\x12\xec\x73\xb0\x47\x3e\xa5" + "\xad\xf1\x56\x57\xba\xbb\x2d\x46" + "\xb6\x37\xfe\xca\xf2\x09\xfe\x69" + "\x17\x2e\xce\xec\xbf\x1e\x3d\x27" + "\xfd\x07\xf6\x3c\x38\xd5\xc1\x8a" + "\x25\x0c\xe1\x12\xff\xf7\x35\x80" +
+       "\x05\x90\x6c\x29\x0f\xcc\xd4\xb7" + "\xdb\xeb\x0a\x7b\xfa\x94\x90\x4b" + "\xd4\xc8\x0e\xc0\xf1\x10\xbf\xe1" + "\x01\xc1\x67\xd6\xc4\xb1\x07\xd8" + "\x83\x33\x71\xbe\xdf\x2c\x41\xa9" + "\xa1\x2b\x14\x81\x3e\x06\x5e\x43" + "\xdc\x6b\x0a\xaf\xec\x15\x4c\x98" + "\xb9\xda\xa3\x92\x60\x24\x2c\x59" +
+       "\x2a\xc2\x93\x20\x5a\x2d\x44\xca" + "\xed\x3a\x70\xd5\x31\xbd\xd0\xeb" + "\xb6\x87\x32\x65\xfd\x2a\x8f\x30" + "\xba\xc8\x1b\x0d\xac\x8b\xb8\x9b" + "\xb2\xe3\xc1\x75\x38\x85\xaf\xfb" + "\x7c\x44\x11\xca\x50\xc9\x2a\xbd" + "\x8d\x4c\x5c\xea\x6c\x81\x6d\x28" + "\x08\x32\xdc\x28\x00\xa8\x3a\xdc" +
+       "\x9d\x3e\xe2\x16\x00\x69\x65\x93" + "\xe1\x41\xcc\xa7\x6b\x0c\x22\xcb" + "\x5c\x24\xd6\x69\xc3\x20\x6b\xb3" + "\x6a\x9a\x2e\xb6\x48\xc3\x63\x2d" + "\xb5\xbc\xc0\xcd\x19\x3e\x47\xa3" + "\x98\x1b\x60\x8f\x3f\x8b\xf1\x70" + "\xe4\x46\xe3\xcd\xc7\xa2\xd7\x8a" + "\x64\xaa\x3a\xbd\xc3\x6e\x9f\xae" +
+       "\x20\x55\x6c\x7e\xc7\x34\x4d\x85" + "\x58\xea\xb9\xdc\xef\xf9\x7d\xc2" + "\x6d\x66\x86\xd6\x69\x23\x5f\x40" + "\x85\xaa\x17\x04\xbf\xfe\xd1\x29" + "\xfe\x0a\x47\x93\x9e\x81\x46\x98" + "\x9e\x7f\xa2\xe2\x69\x96\x6a\x3e" + "\x04\x65\x1e\xe3\xa2\x08\xd0\x24" + "\x0a\x68\xb7\x9c\xcf\xce\xa7\xdb" +
+       "\xe1\xc7\x74\x32\x50\x23\x02\x03" + "\x26\x6c\x4b\x4c\x93\x8c\xee\x61" + "\xce\x89\x93\x19\xe3\x97\x43\x3c" + "\xce\x57\x87\x48\x00\x26\x08\xe0" + "\xfb\xda\xb4\x06\xdf\xa2\xc3\xaa" + "\x6a\x5b\xff\xdd\x00\x07\xaf\x45" + "\xa0\x9f\x1d\x8c\x24\x74\x59\x0a" + "\x8b\xc6\x1f\x39\x7d\x08\x40\x16" +
+       "\x3d\xa5\x7f\xd0\x41\x3e\xa4\x26" + "\xc5\x5b\xe3\x74\x8a\xa7\x54\x31" + "\x8c\x2f\xda\xe0\x24\x89\x76\x7b" + "\x9a\x3f\x61\x23\x2b\x4a\x96\xba" + "\xc4\x16\x1d\xba\x35\x8d\x54\x5a" + "\x57\xd0\x54\xfb\xd1\xfe\x1b\x2e" + "\x05\x02\x64\xbc\x36\x21\x99\xff" + "\x29\xdf\x56\x81\x14\xb9\x9c\xf3" +
+       "\xbd\x48\x55\x4e\xcf\x3f\x87\xf4" + "\xf0\x57\xce\x03\x3f\xda\x25\x87" + "\x58\x32\x95\xca\x95\x5c\x2f\xd8" + "\x7e\x74\xf0\x7c\x12\x7f\x64\xac" + "\xd5\x0b\x57\x2d\xb0\x38\x20\xff" + "\x3f\xe0\x3a\xa1\x67\xa7\xc2\xb0" + "\x16\x2d\x93\xe9\xcd\x27\xaa\xeb" + "\x01\xe9\x34\x12\xfc\xe3\x86\xa6" +
+       "\xad\x44\xb4\x99\x46\xe6\x13\xc9" + "\xc5\x04\x05\xc4\x9d\xe9\xfc\xdd" + "\xdb\x53\x2e\xd4\x99\x2a\x48\x58" + "\x37\xf5\xaf\xd1\x25\x2c\xaf\x9a" + "\x67\xcf\x64\x26\x96\xf7\x90\xee" + "\x2b\x3e\x39\xf1\x99\x5c\xab\x74" + "\xb0\x5b\x22\xe6\xea\xfa\xd0\xfa" + "\x6c\xdd\x63\x2d\x8c\x64\x55\xc3" +
+       "\xcc\x1e\x26\x63\x5e\x43\x80\x9f" + "\xc9\xd6\x37\x43\x2e\xa6\x02\x63" + "\xa0\x58\x49\xca\x49\x6a\x91\x91" + "\xd3\xd5\x49\x31\x99\x58\x49\x55" + "\x3c\xde\x91\x9f\x0b\x02\x8d\x37" + "\x70\x51\xd2\x4d\xa3\x39\xb8\x47" + "\x58\xf2\xb7\x38\x41\x85\x25\x28" + "\xec\x7d\x7e\x43\xf7\x14\x5b\xea" +
+       "\x9d\xcf\x91\x1d\x27\x1d\xe3\xe4" + "\x0a\xb2\x77\xb3\xfd\xd4\x35\xcb" + "\x27\x13\x5e\x05\x45\x1e\xde\x74" + "\x75\x3e\x70\x28\x1b\xe3\x98\x32" + "\x39\x33\x01\xde\x37\x72\x08\x55" + "\xc6\x01\xd1\x23\x01\xf3\xcb\x32" + "\xdc\xb0\xaa\xe8\x22\xba\x0d\xc7" + "\xb9\x5b\x15\x3d\x3d\x62\x52\x4a" +
+       "\x44\x8f\x01\xb0\x36\x87\xf0\x74" + "\xf5\xd0\x46\xb4\x17\x34\xa0\xf4" + "\xb2\xa6\x0c\xa4\x2f\xaa\xa4\x66" + "\xed\x60\xdb\xba\xf0\x79\x56\x21" + "\xef\x4e\x3e\x32\x5a\x19\x71\x38" + "\x16\x2b\x95\x20\xc3\x40\x09\x8f" + "\x7d\x5f\x9d\x87\x62\xac\x8d\xfe" + "\x75\xe8\xa6\xc1\x23\xb6\x9c\x64" +
+       "\x43\x6e\x8d\x33\x41\xf5\xaf\xec" + "\xcc\xd5\x41\x45\x73\xdd\xf7\x56" + "\xca\x88\xbc\x96\xde\x26\xd4\xb5" + "\xc3\xa2\xd3\x9e\x6b\x4f\xd9\x48" + "\x9c\x27\xf8\x2e\xbb\xa3\x54\x63" + "\xf2\x67\x18\x0b\x5b\x46\x75\xd5" + "\x51\x51\x22\x95\xff\xb0\x99\xef" + "\xd8\x00\x45\xf9\x88\x9d\xe1\xf3" +
+       "\x08\xc1\x3e\x13\x87\x90\x6a\xa2" + "\xc0\xbd\x12\x27\x9f\x69\xc5\x5d" + "\xa9\x24\x42\xd1\x4d\x3f\x90\x96" + "\x80\x7b\xe4\x29\x24\x99\xa5\x3d" + "\x5a\xba\xdb\xf9\x2f\x71\x17\xb7" + "\xc9\x91\x63\x75\x4b\x00\x52\x9e" + "\x9c\x21\x9d\xcc\x1d\xa1\x69\xe6" + "\x7d\xc0\xd6\xd1\x84\x6b\x6e\x3b" +
+       "\x57\xcf\x5d\xc8\xac\x35\xf4\xdb" + "\x15\x54\x8f\xc8\x58\x56\x74\x61" + "\x07\x58\xc5\x17\x9a\x7e\x36\x26" + "\x6f\xc5\x90\xca\xa5\x77\xd0\x22" + "\x76\x4e\xe0\xa2\x58\x22\xf7\xfb" + "\x05\xe4\x06\x6e\x3e\x5d\x96\xba" + "\x54\xf9\xe6\xe3\x6f\xd0\x24\x57" + "\x74\x1a\x25\x81\x75\xd4\x47\x3e" +
+       "\xdb\xea\x6f\x67\x6a\xc0\xee\x5f" + "\x22\xf3\x69\x9d\xc5\x9b\x44\xfc" + "\x95\x88\xda\x7c\x5e\x7b\x8d\x1d" + "\xa7\x14\x33\x1a\xc1\x4d\xd5\x5e" + "\xc0\x89\xe8\x6d\xae\xd2\x11\x1a" + "\xd9\x2b\xed\x4c\x72\x79\xa9\xb2" + "\xf6\x5e\x6a\x30\x89\x69\xcf\x6e" + "\x49\xa2\xc8\x8c\x7b\xd5\x11\x16" +
+       "\xf7\x82\xfb\xe0\x51\x01\xba\xb8" + "\xc2\x8a\x66\xd5\x26\x07\x16\x0d" + "\xb0\x11\xd7\x14\x58\xa2\x2b\x62" + "\xf2\xe2\x3f\x7f\x57\xf5\xdd\x6a" + "\x35\x94\x9c\x6b\x1c\x1e\x83\x2b" + "\xbd\x26\x38\xb7\x0a\x06\x3a\xce" + "\x89\x0f\x24\x1c\xc1\x11\xfa\x93" + "\x3a\x30\x6e\x95\xd8\xc8\x9c\x4f" +
+       "\x87\xbf\x7c\x00\xba\x42\x99\x2d" + "\x26\xc9\x3f\xdf\xe6\xbc\x62\x4e" + "\xff\x0a\x56\xe4\xb0\xe5\xee\xe7" + "\xb7\x09\xb0\x7c\xbb\x63\x19\xe5" + "\xdd\x37\x9b\xe2\xce\x18\x51\xaa" + "\x03\x39\x26\x47\x47\x4a\xd8\x5c" + "\xd8\x55\x00\x62\xa6\xca\x50\x30" + "\x3d\x1e\x4b\x6c\xa7\x76\xf5\x7e" +
+       "\xc9\x82\x1f\x64\xf6\x31\x93\x4b" + "\x56\xc7\xfe\xdf\x54\x7c\x7c\xd9" + "\xab\x58\x91\x1a\x1f\x6d\xee\xf5" + "\x7f\xda\xc3\x85\xa3\x93\x44\x05" + "\xdf\x96\x7d\xeb\xf5\x05\x7a\xa5" + "\x39\x3a\x47\xe4\x47\xd4\xaf\xa3" + "\x55\x6d\xe1\x88\xc4\xd9\xa4\x42" + "\xae\x76\xf8\xf5\xf5\x44\xe1\x83" +
+       "\xf1\x8f\x00\xe6\xdd\xa4\x26\x90" + "\x6c\xd9\x8c\x1c\xad\x95\xe9\x49" + "\x9b\x58\x3e\x50\x73\x2e\x72\x80" + "\x26\xbc\xc2\x84\xe1\xbc\xbc\x05" + "\x2c\x2c\x68\xd4\xbb\x9a\x5f\x25" + "\x56\xd4\x84\xf0\xc2\xcf\x2b\xc4" + "\x67\x07\x1c\x64\xb0\xe9\xea\xa0" + "\x2d\x9a\x4c\x86\x2d\x63\x45\x1b" +
+       "\x20\xd6\x2d\xe3\x68\x32\xa8\x92" + "\xa2\x49\x78\x62\x9f\xc9\x3e\x91" + "\x82\x88\x37\x2c\xfa\xfd\xd8\xed" + "\xfe\x8c\x6f\xee\x3e\xf3\x96\xaf" + "\xa5\xa8\x3f\xdc\xe5\x37\x67\xc0" + "\x1d\x3a\xb0\xb0\x31\xb5\x6b\x23" + "\xb0\x37\xf0\x89\x29\x9f\xe5\x33" + "\x53\x2a\xa1\xd9\xa7\xb5\xf9\x13" +
+       "\xe0\x24\xe0\x6a\x3b\x79\x25\xcf" + "\xb0\xc4\xb5\x84\xb4\x07\x66\x1b" + "\xc8\x24\x16\x3f\x90\xfa\x79\x95" + "\xe8\x57\xbd\x68\xbe\x65\xfb\x37" + "\x03\xc2\x39\xfc\x5e\xa5\x93\xd6" + "\xe9\x52\x72\xc8\xc4\x7a\x26\x4e" + "\x13\x94\x89\x9f\xb0\x8b\xd7\xb8" + "\x08\x85\x3b\x0b\x07\x14\xc0\xe4" +
+       "\xa6\x9a\x02\x59\x95\xae\xd8\x50" + "\xed\xb2\x4d\x5a\x2c\x29\x4e\xd7" + "\x3d\x37\x8f\x84\x55\x33\x9c\x0b" + "\x38\xab\x45\xac\xb6\x8d\x01\xec" + "\xa8\x53\xcc\x69\x02\x69\x44\x1f" + "\x64\x98\x87\x1a\x8d\x62\x4b\x8c" + "\x5e\x47\x13\x4b\x28\x3d\x74\x1c" + "\xf6\x19\xde\x73\x38\x93\x4a\xbf" +
+       "\x53\x35\x3f\xbc\xe5\x06\x29\x66" + "\x84\x96\x45\x31\x35\xd5\x38\xde" + "\x0d\x28\xf7\x34\xc6\xa8\x46\x8f" + "\x8e\x19\x24\x3d\x87\x1b\xf9\xaa" + "\x7e\x11\x9b\x5f\x11\xee\xd5\xec" + "\xda\x8d\xae\x50\xbe\xff\x00\xce" + "\xae\xa9\x10\x77\x4e\x3d\x3a\x26" + "\x4f\xa7\x6b\xf2\x21\xf7\xf3\x0f" +
+       "\x69\xfa\xce\xf0\x47\x4f\x8a\x4a" + "\x66\x68\x54\xa4\xba\x4c\x8e\xdc" + "\xc1\x03\xf6\x23\x9b\xa6\x9b\x35" + "\xc5\x7a\x7b\x18\x01\xd6\xb4\xda" + "\xd9\xc8\xeb\xc1\x37\x43\xca\xa6" + "\x4b\x07\xb4\x52\x54\x58\xa6\x9f" + "\x33\xb7\x2f\x90\x81\x4f\x4b\x1a" + "\xaa\xde\x25\xa5\x7a\x5d\xbb\xd2" +
+       "\x7a\x57\xb3\xe6\xc2\x7a\x28\xcc" + "\x3b\x00\x12\xf6\xa7\x8c\x52\xd7" + "\xb8\x00\x14\x2c\xf1\xb6\xfd\x8a" + "\x8d\xdd\xa2\x46\xd3\x2e\x3a\x10" + "\x39\x13\xe2\x2e\x4d\xc5\xf8\xc8" + "\x20\x2d\x5a\x35\x92\x1b\x01\x8f" + "\xac\xf2\x46\x13\x9f\xfc\xc6\x81" + "\x4b\xd2\xa6\x05\xf0\x42\x60\xdb" +
+       "\x67\x95\x1f\xf8\xd5\x92\x2e\xeb" + "\x70\x84\x69\x4d\xea\x95\xcb\x54" + "\xeb\x81\x4c\xe0\x28\xcb\x2a\x5f" + "\x64\xec\xce\xf8\xc4\xbf\x1e\x1c" + "\x23\x74\xe0\x06\xac\x9f\x79\x8f" + "\x85\x0c\xfa\x37\x99\x5f\x22\x72" + "\x44\xdb\xf4\x34\x16\x86\xcd\xb0" + "\x91\x90\x2c\x75\x59\x61\xc3\x5e" +
+       "\x96\xf9\xa4\x0d\x63\xe3\x90\xfc" + "\xe4\x6f\x6d\xaa\x9d\xa4\xec\x8c" + "\x9b\x61\xfc\xbd\xfd\xaf\x84\x10" + "\x04\x0b\x14\xc1\x72\xf6\x29\x20" + "\x5e\x3e\x6f\x13\x5f\xc2\x6e\x60" + "\x4a\x4c\x22\x02\x9b\x14\x24\x6d" + "\x4c\xcf\xdf\xcf\x42\xf1\xb0\xab" + "\xed\xa0\xb1\xfa\x19\x04\x0d\xe4" +
+       "\x10\xb3\xef\x51\xce\xf6\x0d\x0d" + "\xbe\xf5\x8d\x95\xb4\x2e\x5b\xcb" + "\x59\x8e\x15\x36\x29\x9e\x45\xd6" + "\x36\xe3\x66\x14\xb9\xe2\xaa\x82" + "\x36\xa6\x1a\x41\x39\x8a\x65\xfb" + "\x33\xa9\xc0\xd4\xc5\xec\x52\x71" + "\xb7\x26\xf0\x49\x8a\x75\x0c\xf1" + "\x1f\x31\x09\xcb\x97\x7f\x83\xf4" +
+
+       "\xd5\x32\x63\x62\x3a\x52\x4f\x99" + "\x44\xbb\x61\x55\x33\x88\xc3\x7b" + "\xa2\x5e\x84\x3d\xb0\xd4\x5e\x00" + "\x8a\xf0\xa1\xc2\xe1\x3e\x9d\xd3" + "\x0d\x6b\x67\xe7\xd3\xfd\x61\x65" + "\x17\x60\x70\xfb\xff\x35\x0e\x62" + "\xa8\xf9\x64\xf2\x4f\x42\xce\x36" + "\xf7\x81\x26\xda\x9f\x41\xc3\xc4" +
+       "\x48\x16\xb8\x9b\x76\x31\xf8\x00" + "\xd0\x20\x31\x65\x85\xb4\x9e\xd6" + "\x62\xbc\xca\x4c\xf4\x75\x7d\xd1" + "\xb1\xfc\x49\xb7\x82\x7f\xa0\x34" + "\x54\x55\xfb\xbb\x87\xf7\x3a\x2c" + "\xf8\x83\xe2\x62\xd0\xd4\x6e\xb0" + "\xa0\x13\x92\xa1\x9f\x88\x22\x57" + "\xb4\xc7\xf3\xdc\x5e\x08\x2b\x16" +
+       "\x7a\x0f\x30\xeb\xda\x0d\xd9\x36" + "\x01\xe8\xb5\xed\xfc\x7d\xcf\x9d" + "\x4c\x24\xd5\x74\x68\xb2\x5c\x64" + "\xa2\x3a\x8e\x34\x79\xee\x27\xa1" + "\xbb\x1d\x5f\x57\x53\xcc\x8a\x48" + "\x1e\x16\xe6\x80\x85\x7e\x03\x95" + "\xd0\x50\x26\x29\x83\x92\xe5\x57" + "\x16\x82\x93\x14\x99\x7d\xe6\xab" +
+       "\x1f\xe7\x89\x71\x2f\x0d\x67\x32" + "\xe7\x91\xcf\x5e\x48\x87\x43\xc6" + "\x21\x7a\x75\xdb\x57\x8e\x75\x15" + "\xe5\x9c\x0a\x29\xf8\x09\x7d\x42" + "\x7a\x4a\x38\x38\x8f\x30\x6a\x84" + "\x99\x2b\x73\xb0\xb4\xac\xc3\xaa" + "\x19\x58\x84\x17\x09\x10\x94\x9e" + "\x03\x5e\xce\xa7\x11\xa1\xcb\x95" +
+       "\x8e\x05\x78\x73\x37\xaa\x81\xeb" + "\x54\x11\x41\x04\xa1\x46\xc7\x41" + "\xc7\x8a\x82\xfb\xbc\x73\x0c\xa1" + "\x29\x2b\x97\x9d\x91\xbe\x39\x64" + "\xad\xfb\xa2\x43\xb0\xb4\xf3\x4b" + "\x40\xe8\xb5\x82\xdf\xda\xe6\x39" + "\x4c\xbd\x97\x63\x08\x64\x71\x4f" + "\xcb\xec\x1e\x7f\x68\xe5\x7d\x0f" +
+       "\xc3\xc3\x7e\xf3\x73\x2a\x33\xdb" + "\xa0\xeb\x59\xdd\xbd\x59\x52\xc6" + "\x57\x32\x4d\xdb\x9c\x70\x91\x22" + "\x90\x93\x38\xbd\x25\x3b\x79\x9a" + "\xf0\x56\x37\xe4\x4b\xe3\x9f\xf3" + "\xc9\x56\xfb\x9a\xce\xbd\x76\x2f" + "\x27\x8b\x20\x61\x7a\x86\x37\x9f" + "\xc3\x72\x99\x08\x07\x43\x1d\xea" +
+       "\x4f\x9f\x42\x8a\x87\x44\xa7\xd0" + "\x09\x66\x51\xdb\x2b\x71\x49\x06" + "\xdf\xb5\x69\xe7\x57\xba\x26\xb8" + "\xf2\xaa\xc7\x1f\xf2\x5d\x33\x82" + "\x95\xd9\x93\x5c\x67\xf0\x89\x23" + "\xe6\x7b\x67\x68\x7a\x36\xac\x59" + "\x1b\x95\xd9\x21\xff\x85\x79\xa7" + "\xce\x1c\x01\x85\xfb\x56\x89\x03" +
+       "\x9b\x5e\xca\xaa\x1a\x85\xb7\x97" + "\x97\x3b\x71\x56\x21\xa5\x8a\x51" + "\xf6\x61\x0a\x15\xc7\xe8\x57\x33" + "\x69\x2b\x2c\xec\xe2\xe7\x42\x78" + "\x48\xa5\x68\x68\x65\xaf\xff\x8d" + "\x81\xfc\x68\xe0\x82\xbd\x63\xd9" + "\x33\x77\x91\x65\x8b\x5c\xda\x64" + "\x28\x73\x24\x7b\xff\x90\x70\x92" +
+       "\x97\x0d\x6d\x2f\x94\xdb\xff\xd6" + "\x73\x93\x3b\x44\x41\xee\xc3\x05" + "\xb6\x6d\xd3\xff\xeb\x41\xe5\xb2" + "\x3e\xcc\x1d\xce\x96\x5a\x41\xb7" + "\xf6\xa2\x3a\x16\x2e\x68\x83\xe3" + "\x18\xf2\x3a\x2f\xd4\xbd\xfe\x46" + "\xdb\xba\xfd\xba\x7e\x50\xa0\x90" + "\x1a\xe2\x52\xce\x4d\xab\xa8\x4c" +
+       "\x73\xfb\x7c\x1b\x2e\x83\xf0\xa3" + "\xc9\x54\xc3\x3e\x52\xfe\x8a\x7a" + "\xca\xad\x8e\x37\x7e\xc9\x91\xae" + "\xbb\x32\x3b\xac\x99\xc5\x49\x74" + "\x55\x46\x1c\x0b\x71\xc3\x19\xa6" + "\x7e\xa8\x9d\xf7\x6a\x4c\x2e\x69" + "\x6a\xd9\x38\xde\x86\x5d\x3f\xff" + "\xec\xc0\x08\x1c\x42\x0f\x32\xc5" +
+       "\xec\x5d\xec\x8f\xbc\xf2\xa6\x92" + "\x6c\x78\xd6\x84\xff\x83\x13\xa7" + "\x84\xa0\xff\xdb\x06\x8c\x58\x87" + "\x15\xe7\x57\x68\xca\xf5\x85\x0d" + "\xd4\x74\xc7\xb6\xb3\x11\x73\xe8" + "\xa8\x21\x35\x4c\xc8\x57\x23\x67" + "\x0f\xfe\x29\x5b\x61\x74\xfe\xe5" + "\xcd\x58\x71\x5b\x10\x51\xbc\x02" +
+       "\x8e\xfc\x05\xa1\x48\x1e\xa0\x37" + "\x8c\xa4\x9b\x28\x4a\x75\x9d\x76" + "\x80\x21\x1c\xd5\xe1\x6f\x8c\xc0" + "\x87\x13\xbd\xb7\x33\xdd\x32\xb0" + "\xa6\x0a\x0b\x02\xdb\x26\x38\x95" + "\x3c\xc7\x64\x06\x80\x7e\x13\x05" + "\x5d\xf9\x0c\x66\xc4\x02\x63\xc6" + "\x8a\xf2\xce\xb2\x11\x4e\x00\x99" +
+       "\x36\x35\x97\x4f\x28\x5b\x4f\x82" + "\xea\x04\x5b\xd3\x9e\x29\x3e\xb4" + "\x89\x30\xa0\x4d\xf7\x88\x2c\xc7" + "\x2c\xe4\xa2\x45\x7a\xd5\x69\x82" + "\x8e\xb3\x07\x66\xfc\x63\x1e\x7c" + "\x0c\x0b\x39\x29\xaf\x2a\x9e\xe8" + "\x69\x28\xee\x1b\xda\x40\xc7\xc7" + "\x74\xb9\x3f\xaf\xfc\xf6\x56\x85" +
+       "\xd1\xbe\xb6\xa4\x95\x39\x0a\x1a" + "\x54\x5c\x09\x97\x95\x57\xab\x2d" + "\xe9\x3c\xa7\x2a\xff\xa1\xc6\x06" + "\xa7\x38\xe4\x4d\x4b\xa5\xd0\xad" + "\xcd\x06\xa9\xfc\x1a\x6b\x0b\x16" + "\xdd\x10\xde\x29\x16\x60\xfc\x25" + "\xa3\x3d\x63\xd3\x99\x9c\x8e\x34" + "\x5a\x4d\x8a\x15\x46\xf7\xe3\x1f" +
+       "\x1d\x5c\xe8\x8b\xc8\xed\x53\xc2" + "\xb6\x9c\xa0\x3c\x48\x0e\x3d\xdd" + "\x5a\x05\xe3\x9a\x87\xf6\x97\xb9" + "\xbf\x1d\x43\x07\xd0\x9a\x92\x0c" + "\x42\xdb\xd2\x84\x15\x62\xf1\xce" + "\xcd\x28\x88\x07\xef\xf3\x0d\xb5" + "\x66\x4b\xbd\x6d\x9d\xda\x89\x45" + "\x04\x2b\x9c\xd9\xe3\xd2\x4f\xbc" +
+       "\x41\xc2\x98\xd2\xa7\xc9\x4b\x21" + "\xfd\x7c\x80\x56\xba\x97\xb6\xe3" + "\xdb\xea\x64\x45\x02\x78\x1c\xef" + "\xc5\x49\x81\xb4\xcf\xcd\xe8\xdd" + "\x04\x26\x4d\x5a\xa7\xf0\x6b\x94" + "\xaf\x38\x15\x6c\x7f\x4d\x15\x27" + "\xcc\x1f\x5b\xde\x30\x92\xcc\x95" + "\x82\x4f\x86\x66\xe9\x19\x85\xd8" +
+       "\x77\xbc\x86\x62\xea\xa9\x01\x99" + "\xb0\x4d\x79\x69\x58\xfe\x9d\x24" + "\x21\xcd\xa6\xbb\xbd\x0b\x37\xc4" + "\x6b\x5e\xfc\x21\x31\x81\x8f\x71" + "\x61\x8b\xc7\x22\xbd\xed\xdf\x9c" + "\x71\x3d\xd4\xd9\xec\x3e\x31\x4b" + "\x22\x1b\xbb\x19\x1f\x03\x44\x41" + "\x58\x31\xa3\x07\xab\x73\x49\x97" +
+       "\x26\x65\x36\x06\xf4\xde\xaa\x67" + "\x96\x5d\x53\xae\x19\x30\xd5\xd7" + "\xc6\xeb\xa2\xe3\xa7\xdb\xfa\x72" + "\x16\x9d\x26\x75\xa5\x13\x23\xa3" + "\x2e\x92\x0d\xb5\x69\x1a\xfa\x97" + "\x45\x2b\x20\xca\xcf\x28\x6e\x4c" + "\x91\x0b\x10\x68\x00\x11\xbd\xb7" + "\x5d\x6a\xc9\x73\x8d\x41\x2e\xe0" +
+       "\x46\x55\x80\x8e\xdc\x6e\x9e\xfa" + "\x40\x98\x63\x82\x78\xe6\xe0\xc0" + "\x3d\x64\xbe\xb7\xa4\x58\x08\x43" + "\x1e\x5f\xcf\x18\x14\x24\x42\x1d" + "\xaf\x49\xef\x9f\x62\x0c\x99\x05" + "\x32\x1d\xc3\x5e\xcd\xe0\x46\x48" + "\xd4\x85\xbf\xba\xa8\x47\xdb\x46" + "\x7f\x9f\x75\xaa\xf1\xc9\x66\x5f" +
+       "\xa1\x6c\xea\x96\xf7\xe4\x13\x10" + "\x71\x28\x79\x1f\x2a\xdc\x7c\x56" + "\x45\x8d\x65\x5c\x70\x28\xb7\xad" + "\x98\x0e\x60\xce\x4a\xff\xc1\xf7" + "\x39\xad\x6c\x4b\x57\x86\xba\xa1" + "\x28\xb4\x20\xba\x34\xd6\x58\x3d" + "\xfb\xfd\xe6\xa2\xde\x1c\x01\xc0" + "\x0d\x96\x18\x7b\x7a\x36\x32\xa8" +
+       "\x07\x15\x52\x50\x8f\x2c\x39\xb7" + "\x9d\x2e\xef\xe5\x4b\x91\xb3\xac" + "\x85\x6f\x44\xea\x78\xb1\x70\x9a" + "\xee\xc3\xd8\x98\xa6\x43\x4c\xbd" + "\x77\x01\x4c\x84\xe5\xbb\x73\xa9" + "\xea\xb3\x2a\x06\x4d\x27\x9b\x29" + "\xaf\xda\x6a\x85\x7c\x0e\xba\x26" + "\xb8\xb2\x5c\x76\x94\x91\x9b\x13" +
+       "\x87\xd3\x9f\xbd\x9b\xe7\x21\x7b" + "\x71\x0c\x1c\x24\x9a\x76\x8f\xb4" + "\x93\x5a\x72\x8b\x36\x68\xe3\x83" + "\xe1\x96\x5b\x1f\x55\x4f\x9d\xef" + "\xa0\x10\x99\x2a\xa4\x39\x71\xc6" + "\x76\x5e\x09\x4e\xa2\xc8\xe1\x71" + "\xf2\xb8\x19\x27\x36\x7f\x2f\x21" + "\x17\x12\xfa\x00\x3f\xeb\x75\x9f" +
+       "\xb6\x6d\x3e\x34\x6e\x8e\x11\x4e" + "\x3f\x99\xb6\x25\x59\x55\xbd\x98" + "\x85\xfa\x2e\xb3\x14\xd5\x0d\xb4" + "\xa1\xe3\x24\x7a\x80\x55\x30\x7e" + "\xc3\x57\x58\x77\x50\x95\xcc\x7d" + "\xb0\xc1\x9b\x2c\x12\x11\x63\x05" + "\xe9\xdc\xa5\x02\xd5\x85\xae\x6e" + "\x72\x41\xeb\x34\xaa\xc9\x3f\xe5" +
+       "\xf7\x38\x49\x0e\x9f\x8c\x61\x47" + "\x9e\x71\x83\xdc\x69\x7d\xd4\x58" + "\xcc\x64\x1a\xf4\x23\x1a\x4c\xd7" + "\x66\x9f\x82\xb5\x68\xe0\x28\x5d" + "\xf6\x66\x04\x21\x29\x75\xd3\xd8" + "\xf8\x4e\xa6\xc6\x2f\x15\xf1\x2a" + "\x7a\x6a\xce\x19\x5c\x48\xd4\x55" + "\xd7\xe2\x48\xf6\xf5\xd2\x0b\x6d" +
+       "\x21\xb5\x9d\xf8\xb1\x6a\x2d\xf0" + "\xc6\xed\x0c\x65\xfc\x1a\xf4\x46" + "\x71\xdf\x8a\x1c\x96\x73\xbc\xb1" + "\xb9\xb1\xbd\x7e\xcb\x7f\x14\xd2" + "\x63\x03\x08\xc1\xf7\x0e\xaf\xca" + "\xc5\x09\x5c\xd9\xf3\x1a\x0b\xf9" + "\x83\x48\xf4\xf6\xd4\xbf\xaf\x7a" + "\x6d\x9b\x8d\x8a\x87\xe0\x64\x9b" +
+       "\xe5\x6a\x35\xbd\xe8\x9c\xfc\xee" + "\xf4\x5a\xd2\x2e\xc0\xa6\x98\x3d" + "\x84\xd8\x19\x63\x64\xf5\x73\x31" + "\x16\x4f\x6c\xca\x64\xed\x2d\x2b" + "\xd0\xfc\x6d\xce\xe5\x19\x7b\xe2" + "\xca\x87\xd8\xa0\x5f\xbc\x69\xa3" + "\x10\x37\x46\x07\x6e\x60\xc2\x59" + "\x4e\xe7\xc6\xf3\x2a\x11\xc1\x15" +
+       "\xa0\x13\x7a\x7e\x00\x30\xba\x4a" + "\xf5\xaa\xbb\x89\x47\xbb\x83\xf4" + "\x3f\x27\xfd\x9f\xf6\x50\x0d\x7c" + "\x92\xd6\xa4\xf4\x91\xc1\x63\x7e" + "\xe6\xd6\xf2\x42\x40\x34\xda\x8b" + "\xc6\x72\x8b\x93\xc2\xcd\xcf\xd7" + "\xe9\x54\x6e\x6f\xd2\xfb\x8a\xd2" + "\xe5\x3f\x8b\xc2\xb6\x23\x04\xd4" +
+       "\x8d\x44\x16\xf4\x2a\x03\xcc\x1e" + "\x71\xd9\x76\xec\x10\x8c\x7e\x4a" + "\xae\x6e\x0b\xb9\x05\x98\x4f\x85" + "\x94\x05\xed\x4b\x32\x15\x0b\xfd" + "\xa3\x5c\x8b\xd9\x48\x18\xf7\x89" + "\xef\xb3\x39\xf0\xfc\xe5\x1f\xd0" + "\x2e\xda\x7b\x62\x2e\x33\x81\x44" + "\x41\x3e\x07\xa5\xd7\xec\x7c\xe6" +
+       "\xcd\xec\x9c\x8a\x46\x16\x69\x2e" + "\xa1\x6d\x3a\x05\xcc\xeb\x92\xcc" + "\x64\x6b\x3a\x78\xb8\x76\x00\xa8" + "\xa2\x2f\x99\xa5\xa0\xe8\xd0\x42" + "\x30\xec\x56\x7c\x53\x1c\xc7\xd9" + "\x69\xc7\x6b\x6b\x96\x6a\x8b\x38" + "\xc7\x9f\xbf\xd3\xab\x33\xc2\xa0" + "\x69\x53\xc4\x2f\xd0\x5b\xf5\xd0" +
+       "\xf9\xee\x92\x32\x02\x33\x2c\xa7" + "\x16\x11\x8c\x9f\x36\x40\x5a\x0f" + "\x91\xa7\x96\x3e\xf0\x6e\x9e\x42" + "\x39\x39\x84\xf3\x81\x61\xeb\x60" + "\xd3\x18\x25\x90\x83\xf0\x49\xaf" + "\x0b\x39\xe8\xb9\x13\xc0\x65\xfe" + "\xa4\x34\x4d\xec\xb3\x7c\xb9\x7a" + "\x3d\x85\x4f\x8b\x08\x7a\x42\x72" +
+       "\x1f\xad\xfe\x2e\x68\xfc\x83\x38" + "\x68\x8d\x4d\xfc\xa1\x24\x72\xdd" + "\xdd\xaf\x1d\x9f\x4c\x84\x4e\x5c" + "\x7d\x9b\x11\x15\x8e\xd1\x40\x7f" + "\xeb\x68\xc2\xb7\x4c\xd1\xc6\x79" + "\xe1\x89\xae\xc2\x55\xc8\xb4\x65" + "\xa2\xd9\xb0\x7c\x99\xbb\x08\x35" + "\x5b\x4a\xc6\x2e\x5b\x63\x2c\xbc" +
+       "\x2c\x28\xb1\x7c\x1a\xdd\x28\xb8" + "\x3a\x97\x46\xbe\x26\x76\x8d\xa0" + "\xb2\xd6\x08\xe7\x40\x8d\xaf\x6b" + "\xf3\xb3\xae\x4d\xa1\x1f\x57\x72" + "\x98\xfd\x2d\xf2\x2f\x73\xb1\x85" + "\x8d\x10\x87\x00\xa7\x01\xab\x87" + "\x7a\x20\x88\x59\xa8\xfe\xaa\xaa" + "\x55\x07\xf0\x69\xf8\x32\xc8\xcc" +
+
+       "\x1a\x9d\x8d\xca\x85\x11\x8f\x48" + "\xd2\xde\x87\xd9\x7d\xc7\xf2\xad" + "\x24\x61\xc4\x60\xf0\x39\x30\x5f" + "\xf4\x95\xe0\x71\x75\x0b\xd7\xe5" + "\x0f\xe7\x60\x62\x50\x86\xd5\x82" + "\x05\xd1\x50\xf7\xa7\x5e\xd7\x39" + "\x64\xc3\xba\x75\xb1\xd0\xf3\x8c" + "\x29\x13\xd0\x21\x4d\x56\xa7\xf3" +
+       "\xfc\x3e\xcd\x3f\x3e\xa4\x4a\xb2" + "\x9a\x8e\x08\xb8\x34\xc0\x26\xdd" + "\xea\x46\x3d\xbd\xc9\x4d\xef\xa5" + "\x6f\x6a\x4c\x8a\x58\x9d\xf9\xa2" + "\x6c\xa4\x1d\x2f\x55\xd3\xab\xdd" + "\xd1\xcd\xfa\x1a\xce\xf8\xc3\x72" + "\x78\x05\xd4\x92\xee\x4e\x0c\xd9" + "\x94\x3b\x62\xca\x1f\xb4\x8b\xd2" +
+       "\xe1\x7c\x41\xe7\xd2\x92\x27\x24" + "\xf5\xe7\x0e\x97\x71\xbc\x42\xff" + "\x1e\xa4\x67\x5c\x6d\xdc\xf4\x1f" + "\x58\x2a\x88\x20\x7b\x9b\x70\x77" + "\x2c\x7f\x21\xbe\x1d\x73\x54\x35" + "\x77\x21\xb7\x5b\xcd\xa8\xf2\x2a" + "\x59\xd0\x1d\x59\x69\xe7\xee\x58" + "\x77\x64\xba\x4b\xc9\x30\x29\xbb" +
+       "\xc0\xf2\x76\xf1\xda\xdd\x6a\x1e" + "\x58\x26\x57\xe2\x04\x46\xca\x01" + "\xfb\x2f\x34\x85\xed\x4d\x40\x0a" + "\xd6\x38\x18\x44\x96\x0f\xf6\x8c" + "\x4a\x1c\x07\xc9\x1c\x69\xbc\x9b" + "\x03\x28\x44\x34\x44\x87\x58\xfd" + "\x81\x0d\x9c\x80\x85\x1c\x10\x97" + "\x7f\x6f\x45\x8c\x4c\x75\xfb\xa7" +
+       "\x3f\x01\x71\xaf\xd5\xa1\xf7\x6a" + "\x46\xc9\xed\x0b\xe5\x16\x82\xe6" + "\xa0\x70\x73\xd2\x0b\xa3\xcb\xf4" + "\xcc\x21\x04\x87\xbf\xaf\x81\x79" + "\xe1\xf0\x49\x94\x67\x6a\x49\x02" + "\xae\xed\x47\x0a\xbe\xc4\xcf\x86" + "\x22\xca\xfe\xb1\x36\xc9\x73\x30" + "\xfb\xf8\xf8\x03\x12\x46\x69\xf5" +
+       "\xf8\x48\xde\x5b\x71\xd6\xad\xbc" + "\x7d\xbc\x89\x21\x73\x38\x70\xc9" + "\x8a\xee\x09\xc7\x9e\x29\x45\x5d" + "\xf8\xaf\x5a\x84\xe2\x7e\x28\xd1" + "\x1f\xbf\x1d\xdb\x74\x88\x1f\x7d" + "\xd6\x88\x0c\x99\x8b\x58\x46\xea" + "\x13\x83\x36\x84\x9a\x64\xba\x60" + "\xae\x43\xd5\x60\xce\xcb\xfd\xd5" +
+       "\x2d\x27\x90\x98\x95\xe9\x3d\xcf" + "\x10\x3a\x71\x3e\x2a\x43\xf3\x75" + "\xb8\x27\x82\xe2\x9f\x47\x13\x5e" + "\xc8\xcd\xfa\xfe\xa9\x1e\x56\xb8" + "\xfd\xaa\x32\x83\xa0\x97\xa2\xa6" + "\x62\x9b\x80\x73\xb5\x8b\x0d\x9b" + "\x6f\x03\x63\x0c\xfd\x1c\xfa\xd2" + "\xa8\xbd\x64\xbd\x55\xeb\x16\x7a" +
+       "\x27\x3e\xc1\x2a\x8a\x8e\xe4\xf7" + "\xf5\xa9\xb1\x4e\xdf\xf6\x94\x44" + "\x62\x0a\x1f\x98\xeb\x84\xbf\xed" + "\xf0\x38\x64\x53\x32\xdc\xba\x49" + "\x71\x75\x4f\x00\x41\xa5\xbe\x50" + "\xee\x94\x1c\xdf\x10\x7d\xc6\xba" + "\x31\xbc\x27\xb7\xa1\x73\x3d\x25" + "\x28\x6e\x68\x30\xf2\x1c\xd0\xb3" +
+       "\x3b\x5a\x6a\x30\x39\xc0\x0b\xa4" + "\x1b\x3a\x78\x96\xfd\x41\x0a\x4e" + "\xd4\xcd\x53\x02\x9a\xd3\xe8\xa1" + "\x38\x86\x38\xc7\x26\xbe\x80\x64" + "\x82\xf3\x85\x22\x1d\x5e\x36\xee" + "\x36\x5c\x0b\xec\x8f\x8d\x8d\x18" + "\x82\x4d\x0f\x1f\x48\x1a\xef\x34" + "\x9a\xd2\x87\xa4\xe1\x43\x8f\x1a" +
+       "\xa5\xdd\x02\x39\x7c\x14\xa8\xa5" + "\xb4\x73\x69\xfe\x06\xf7\xd2\x35" + "\x7e\x45\x57\xc2\xcf\xef\xc2\x5a" + "\x1b\x61\x00\x87\xd4\x48\x3f\x93" + "\xb2\xbe\x12\x49\x88\xaf\x65\xc3" + "\x94\xdf\x2e\x16\xe6\x4d\x5a\x7f" + "\x4b\xf3\x32\x0c\x7c\xba\x46\xc6" + "\x74\x10\x09\xb2\xf3\x6a\x2c\x63" +
+       "\x5f\x6f\xb2\x9b\x33\xa3\xf6\x10" + "\xb6\x85\x4d\x04\x8e\xdb\x85\x1e" + "\x54\x7e\x19\x94\x08\x7a\x69\xc3" + "\xa8\x4e\xcb\xa7\xc0\x8c\xe1\x65" + "\x6e\xfe\x71\xa4\x50\x4f\x8c\xa3" + "\x9c\x43\x13\x2f\x7a\x74\x31\xf0" + "\x8b\x31\x07\xc0\xba\xa6\xc4\x53" + "\x3d\xcb\xec\x1d\xe5\x3e\xda\xa8" +
+       "\x3f\x8f\xa4\x5c\xdf\x1a\xc0\xbf" + "\x84\x9b\x2a\xe2\x06\x2f\x35\x64" + "\x4a\x9e\x09\xc1\xa1\x4d\xe5\xce" + "\xc0\x89\x1b\xfa\xe8\x54\xda\xbb" + "\xfb\x55\x6e\x6f\xf5\x3d\x6a\x16" + "\x88\x6f\x17\x20\x24\x4a\xa4\x1c" + "\xff\xb5\xb7\xdf\x88\xfd\x6a\x93" + "\xa0\xd4\x11\x86\x37\x24\x4c\xe3" +
+       "\x92\x48\x55\x3e\x6d\x41\x24\x5f" + "\x45\x2a\x0e\x43\x3d\xb5\x13\x84" + "\xa0\xa2\x32\x90\xee\x6a\xc5\x99" + "\xb1\x67\xc3\xee\xf6\x2b\x43\x09" + "\xc1\xec\xf0\xda\xc6\x50\x28\x55" + "\x48\x20\xc9\x5b\x55\xce\xeb\x49" + "\x07\x13\x81\x54\xa6\x6b\xb6\xdf" + "\x97\x85\x29\x6f\x97\xf7\x84\x1b" +
+       "\xa4\xd5\xf8\x70\xeb\xd9\xb5\xd5" + "\x28\xb2\xbb\xd7\xe7\xdd\x5a\x37" + "\x32\x0b\x1c\x0c\x86\x8b\xe8\x31" + "\xaa\xdb\x3e\x17\xc4\x68\xf5\xd1" + "\x02\xdf\x59\x54\x83\xfc\x92\x15" + "\x7e\x9a\xcd\x0f\xfb\xc0\xea\x2b" + "\x0a\x3b\x47\x1b\xb8\xfd\xa6\xb0" + "\x48\xfc\xe8\x0f\x6f\x4c\x22\xe3" +
+       "\x89\xe1\x77\x57\x45\xc8\xa5\xa1" + "\x29\x28\x6f\x45\xe0\xbe\x10\xcc" + "\xd5\x2b\x76\xda\x56\x5c\xd9\x8a" + "\xa8\x1d\xd9\xe9\x14\x22\x2e\x15" + "\x74\x3c\xb2\x7c\x72\x0e\x5b\x97" + "\xdf\x66\x0c\xa9\x70\x76\x5d\xfd" + "\x53\xfc\x5f\x22\xad\xb8\xb5\xb5" + "\xae\xd2\xde\xfa\x73\xff\x6d\xab" +
+       "\xcf\x49\x35\x6d\x0f\xe5\x33\xd4" + "\x5e\x66\xcd\xfa\x6f\x69\x33\x6f" + "\xb4\xfc\x11\xce\xac\xfd\x5b\x69" + "\x60\x98\x7c\xaf\x52\xe2\x0e\x81" + "\x2c\xbb\x59\x71\xe1\x0f\x45\x65" + "\x7b\x35\x8b\x75\xbe\xbe\xdf\xf7" + "\x72\xea\x9f\xd6\x74\x7e\x05\x2b" + "\x45\x17\x73\x92\x7a\x71\x85\xd4" +
+       "\xef\xd7\x76\xb3\x84\x76\x6d\x8d" + "\x81\xda\xd5\x48\xac\x02\xbf\x3d" + "\x9c\x13\x89\x1b\x5a\x38\xa5\xfa" + "\xce\xa7\x20\x68\x85\xcb\x4d\x50" + "\x26\x9d\x1a\xe6\x45\x21\x98\xc0" + "\xaf\x25\x5d\xac\x32\x6c\x5c\xf3" + "\xc2\xb3\x27\x4e\x67\xa2\x3b\xaa" + "\xc5\x7a\x6c\x9f\xa0\xa3\x69\x2e" +
+       "\xcf\x86\x0b\xf3\x1d\x5c\x6a\x90" + "\x87\xef\x07\x4d\xfc\x66\x6f\xb1" + "\x61\x22\x01\xd4\xda\xc2\x75\xa9" + "\x1e\x36\xbc\x0f\xe6\x48\x97\xe6" + "\xc7\x00\x99\x2d\x36\x35\xa0\xa2" + "\x0f\xaa\xf6\x7c\xe1\x3c\x2a\x1f" + "\x87\x38\xe3\xa1\x3a\x44\xd5\x80" + "\xdf\xb4\x47\x5b\x8b\x24\xda\x6a" +
+       "\x1a\x72\x3c\xdd\x08\xbb\x9f\x1f" + "\x9c\x22\xb2\x46\x7e\xf9\xa1\x93" + "\xfb\x7e\xba\x31\x46\xad\xe5\x4e" + "\xa3\x10\xae\xf3\xa5\x5c\xaa\x6b" + "\x04\x02\x6c\x74\x3e\xfc\x81\x7d" + "\x0b\x06\x9a\x2b\xf0\x90\xcc\x9e" + "\xa7\x8c\x68\x7b\x2f\x16\x58\xdb" + "\xdf\xc1\x54\xf5\x99\x2a\x77\xf4" +
+       "\xf4\x4b\xdc\x67\x7c\x4e\xb2\xed" + "\x7b\x82\x4a\xaa\x43\xc7\xe4\xcb" + "\x2b\xf8\xcf\xfa\xf5\x72\x94\x22" + "\x9b\x4a\x2c\xcf\x82\xbb\xef\x2c" + "\xf1\x7f\x36\x59\xb8\x06\x6e\x38" + "\x75\xaf\xcd\xa3\x78\x59\x24\x32" + "\x98\xb1\x07\x98\x6d\xd3\xbd\x2d" + "\xe9\x11\x85\xb7\xe7\x95\x74\x43" +
+       "\x27\xa7\xdd\x77\x65\x6e\x16\x34" + "\xcf\xaa\xaa\x3e\xc1\xa3\xa4\xb6" + "\x40\x62\x2c\x9d\xc2\x49\xcd\x9c" + "\x63\xa1\x2b\xa4\x3d\x7f\xe1\xc2" + "\x33\x21\x6d\x7c\x5c\xeb\xf9\x91" + "\x06\x76\xa9\xe6\x2a\xbd\xce\x85" + "\xfb\x0d\xb0\x65\xbd\x35\x6e\x80" + "\x82\x2a\x39\xb9\x06\x79\x9f\x9e" +
+       "\x3b\x2b\x0d\x4d\x8a\x29\x9f\x23" + "\xf1\x07\xb2\xdb\xcf\x60\x97\x6c" + "\xeb\x2e\xf9\xd4\x3f\x20\xbf\xc8" + "\x9b\x4e\xa7\x7e\xe4\x2a\x0b\x29" + "\x3d\x7d\x3a\x16\x37\x93\xa6\x1f" + "\x14\xa4\xef\x87\xe8\x5e\x29\xd0" + "\x3f\x27\xf8\xf9\x37\x40\x84\x54" + "\x58\xab\x41\xe3\x62\xa8\x46\x30" +
+       "\x0b\xfc\xc6\x38\x53\xe9\x9f\xfb" + "\xc8\x79\x95\xac\xe8\xe2\x94\xe4" + "\x8b\xca\xd7\x69\x6f\xef\x24\xc4" + "\xec\x57\xb8\x4f\x15\x52\x0e\x63" + "\x48\xdf\xe2\x42\x2b\x11\x13\xf0" + "\xbf\x04\x52\x62\x08\xc9\xad\xef" + "\xce\xb0\x63\x11\x6c\xb1\x8b\x7d" + "\x89\x68\x14\xb7\xe3\x47\x51\xdf" +
+       "\xad\x75\xbf\xa2\x05\x8b\x37\x5b" + "\x92\x1e\xda\x25\x66\x4b\x37\xfe" + "\x12\x67\x76\xff\x00\x81\x4c\xfb" + "\x60\x46\xc8\xcb\x80\x63\x60\xbc" + "\xe4\xad\x10\x6c\xc9\x6e\x26\x27" + "\xa7\xec\xb6\x7a\xb5\xc2\x6a\xb4" + "\x00\xe8\x28\xbb\xd7\x73\xc6\xfd" + "\xfe\xe3\xc0\x23\x20\x5f\x64\xb5" +
+       "\x28\x2b\x56\x30\x5f\x0e\x43\x76" + "\x06\xd8\xea\x36\x10\xca\x41\x67" + "\x93\x12\x7f\x93\x31\x50\x6e\xbf" + "\xf0\x9a\x29\x22\x6e\x09\xc3\x32" + "\x22\xdd\x45\x21\x61\xb1\xa3\xd6" + "\x33\x86\x5e\xd7\x57\x90\x49\x6c" + "\xbd\xc2\xf1\x39\x51\x76\x99\xa5" + "\xf5\xab\x1f\x6b\x6d\x0c\x90\x3b" +
+       "\x63\x7c\x43\xe7\x16\x68\x29\xe8" + "\x11\x4c\x16\x76\xd2\xc0\xa7\x38" + "\x0e\x84\x29\x9c\xf9\x95\x10\x1f" + "\x3f\x09\xb9\x57\xb3\xb9\x12\x19" + "\x17\xc8\x39\xf8\x04\xd5\x09\xfe" + "\xdd\x4b\xdd\xbd\x3b\xfb\x64\x1f" + "\x34\x45\x04\xdb\x5b\xed\x42\xef" + "\xc8\x21\xe8\xb4\x95\xdd\x60\x15" +
+       "\x4e\x52\xb9\x70\x50\xaf\x39\xde" + "\x68\xc8\xd1\xad\xe9\x95\x69\x79" + "\xc9\x4c\x9a\x32\x28\xb8\x90\x97" + "\x64\xae\x62\x5b\xb7\xa2\xeb\x1e" + "\x2f\xc1\xe3\xd7\xf6\xd3\x7b\x61" + "\x21\x64\x33\xdf\x1c\x71\x7e\xdb" + "\xcf\x07\x89\xd7\x37\x09\xfc\x7d" + "\xd5\x8b\x1a\x84\x99\x7a\x93\x88" +
+       "\xba\x41\x0a\x5d\x4d\xc2\xa5\xb9" + "\x1e\x86\x6c\xb6\x02\x84\x29\x58" + "\xfc\xcd\x71\x4c\xf8\x6e\xdb\x99" + "\xd9\x4c\x36\xe6\xaa\xaa\xe2\x69" + "\xd9\xc7\x8b\x64\x18\x94\xf0\x4b" + "\x6f\x3c\x71\xeb\xe9\xc2\xb3\x5a" + "\xc2\x52\x6e\x0c\x58\xd5\x75\x6a" + "\x12\x00\x60\xe5\x24\x8a\x2b\x46" +
+       "\x8e\x85\x82\xfe\x08\x42\x54\xca" + "\x90\x1a\xc2\x3e\x4a\xaf\xa3\x51" + "\xd4\x14\x76\xc2\x63\x9e\xc1\x63" + "\x39\xe7\x05\xe0\x95\x8c\x08\x32" + "\x00\x8d\x4a\x94\xf9\x25\x50\x7c" + "\x48\x2a\x94\x9a\x7d\xe3\x98\x8f" + "\xe7\x45\x5c\x53\x51\x73\x35\x53" + "\x80\x1f\x89\x44\x1c\xf1\x41\xfe" +
+       "\x90\xc3\xa2\x5d\x9c\xe1\xf9\x20" + "\x8a\x6d\xbd\xda\x2f\xe6\x69\x1f" + "\x65\xbb\xaa\x27\x2e\xb6\x9e\x1b" + "\xb5\xbb\xbb\x3d\x37\x83\x09\xbb" + "\xda\x32\x36\x82\xc9\x88\x3b\x7d" + "\xde\xe7\x59\xa7\xf3\x74\x89\x6c" + "\x6c\x87\x52\x3d\x08\x78\x65\x49" + "\xd8\xcd\x45\xe0\xbc\x73\x64\xb5" +
+       "\x47\xe7\x53\x00\x0e\x7e\xe5\x5d" + "\x53\x8a\x1c\x56\x92\x65\xd3\x04" + "\xad\x2e\x7f\xca\x78\xd3\x06\x6a" + "\xdb\x59\xf8\x14\x20\x56\x61\xb3" + "\xf8\xf8\x19\x14\x17\x91\xb1\x4e" + "\x32\x99\x3b\x60\x25\x45\xbf\xd0" + "\x98\x58\xa1\x9d\xcd\x45\x3e\xfc" + "\x14\x8d\x32\x79\x71\x9f\xe8\x5e" +
+       "\x0c\x86\x36\xee\xe8\x42\x6c\x89" + "\x2d\xc2\x13\x41\xfd\x4d\xf0\xda" + "\x13\x42\x10\x44\xb7\xb7\xdb\x1a" + "\xea\x94\xd3\x1f\xa1\x5f\xfd\xe5" + "\x51\x05\x4e\x1a\x94\x5d\x23\x68" + "\x51\x01\xd1\x18\xbe\xcf\x72\x67" + "\x23\x45\x98\x09\xe3\x71\x60\x27" + "\x98\xba\x56\x5a\xde\x79\xe8\xe4" +
+
+       "\x91\x94\x5b\x28\xb0\xaf\xaf\xaa" + "\x5e\x70\x4c\x1e\x88\xbe\xa0\x01" + "\xab\xca\xd9\x2a\x5d\x4f\x1d\xff" + "\x3f\x23\x7a\xc3\x4a\x9a\x34\x6e" + "\x16\x6a\x1c\x4a\x46\x12\x1c\xcf" + "\x60\x32\x38\x29\x66\x6b\x9e\xd9" + "\x71\x54\x6d\x5f\x66\x43\x3d\xea" + "\x9b\xc8\x8c\xff\x04\x4d\x97\x36" +
+       "\x57\x90\x92\x8f\x14\x9e\xf2\x27" + "\xdf\x53\xc8\xc0\x06\xae\x64\x7a" + "\xce\xc5\xe9\x58\x83\xd1\x6c\x25" + "\xa5\x92\xd0\xde\x82\xce\x9c\x9d" + "\xc7\xb7\x93\x6e\x79\x59\x6e\xcc" + "\x27\x9e\xbb\x31\x92\x70\xe4\xe1" + "\xa0\x29\x9e\xaa\x83\x30\x0b\xb7" + "\x44\xe6\x85\x37\x75\x1a\x18\xbf" +
+       "\x1e\x3f\x0a\x5c\xc8\xe8\xd6\x8e" + "\x7f\xc3\x87\x7c\x92\x24\xad\xbc" + "\x8d\xb7\xe3\x9e\xbb\x62\xfb\xfd" + "\x46\xba\xce\xcb\x77\xe4\xa8\xeb" + "\x4b\xde\xae\xee\xb0\x8c\xd3\x37" + "\xb6\xde\x76\x79\xe8\x98\xc4\x0b" + "\xfb\x47\x61\x6b\x04\x4c\x94\xb2" + "\x09\x96\x1f\xf7\x35\x3f\x12\x8b" +
+       "\xd0\xb9\x02\x14\x3f\xa1\xb3\xd3" + "\x63\xc8\x7b\x2c\xc3\x41\x34\x57" + "\x6e\x3e\x8c\x57\xc4\x1e\x30\x4b" + "\x7e\xf5\xda\x0a\xc4\xc9\x6f\xc2" + "\xa3\xce\x93\x74\xfd\x1b\xe7\x96" + "\x56\x14\xf8\x1a\x3f\x4b\x5d\xd0" + "\x8f\x60\x8c\x6a\x8a\x2a\xca\xda" + "\x76\xb2\x25\x07\xf6\x07\xef\x53" +
+       "\x78\x59\x43\xc7\xf0\x23\xe0\xba" + "\x19\x0e\xe3\x20\x88\xc8\x52\xb1" + "\xaf\x6f\xfa\xe3\x45\x16\x24\x9c" + "\x60\x3e\x82\x84\xc1\x95\x5d\x73" + "\x17\x53\x95\x03\x73\x75\x19\x03" + "\x95\x49\x3b\xf0\xa9\x02\x4b\x0b" + "\x00\x46\x27\x70\x59\xf5\x6b\x07" + "\x08\x75\xf5\xaa\x53\xcc\xc5\x32" +
+       "\xd2\xc5\xc7\xd5\xfd\xdb\x18\x03" + "\x2d\x34\x2b\x07\xa7\x8d\x8f\xb3" + "\x8a\xe3\x8d\x7b\xdc\xbd\x69\x35" + "\x42\x48\xc9\xa1\x87\x58\x5b\xf2" + "\x60\xad\x46\x29\x84\xb2\xd5\xb2" + "\x7e\x70\xd1\xe9\xad\x29\x4f\x85" + "\x09\x45\x6a\x2c\xdc\x59\x51\xaa" + "\x37\x98\x18\x57\xc0\x94\x9f\x89" +
+       "\xe7\x89\xce\x49\xe0\x36\xf5\x27" + "\xb5\x0c\x89\xcc\x39\x85\x90\x18" + "\xa1\x2a\x3c\xd8\xab\x09\x89\x30" + "\xd3\x3b\xb7\x1a\x2b\x14\xd3\xec" + "\x84\xab\xf5\xb3\x59\xbf\x85\x6a" + "\xc6\xa4\xbe\xf2\x68\x0a\x32\x3c" + "\x1f\x54\xa4\x6d\x38\xc5\x8d\xad" + "\x86\x11\xc4\xb7\xb0\x4e\xf3\xea" +
+       "\xd2\x49\xac\x46\xd6\xc9\xb5\xa6" + "\xa9\x7a\x13\x83\x0b\x7c\xc7\x42" + "\x38\x5a\x22\x68\xfc\x00\xd0\x24" + "\x07\xe9\xe1\x2f\xc8\xcf\x63\x0f" + "\x95\x1f\x44\xc6\x1b\xb0\xd1\x22" + "\x8f\x44\x8e\xec\x19\xf7\x38\x7d" + "\xba\xb1\x7f\x78\x5f\xfa\x33\x9b" + "\xdf\x58\x01\x19\xa1\xfd\xdc\x94" +
+       "\xca\x1a\x0a\x49\x26\x93\xc7\x63" + "\x02\x6b\x52\x41\x9c\xdd\x64\xcb" + "\x58\x92\x97\xa2\x91\x25\x77\xbb" + "\x46\x78\xd9\x48\x70\x29\x58\x3f" + "\xa7\x3b\x21\x7c\xd1\x70\x6b\xd6" + "\xd4\xce\xa0\xe8\xb5\xeb\x8f\xc2" + "\xc1\x38\x03\xc1\x31\x18\x91\x6b" + "\xf3\x26\x01\xbf\x89\xe3\x54\x0d" +
+       "\x9b\x68\x83\xb4\xfe\x2e\x24\x40" + "\x62\xc2\x3a\x51\xf6\xd3\x75\x25" + "\x72\xdb\xa6\x0c\xc8\x37\x00\xf3" + "\xe2\x4b\x86\x98\x82\xce\xfc\xc9" + "\x2d\x36\x49\x01\xff\x12\xa1\x84" + "\x71\xe9\x4a\x1c\x82\x75\xe5\x95" + "\x6c\xf8\x5c\x94\xa8\xb1\xa4\x1f" + "\x2f\x4a\x02\x0b\x34\xa7\x25\x45" +
+       "\x5f\xd8\x05\xc9\xc2\xd1\xea\xca" + "\x57\xae\x33\x07\x90\xf7\xd7\xe9" + "\x94\xdd\x7c\xf0\x5c\xa6\xc9\x24" + "\x31\x59\xb5\xa4\x9c\x35\x89\x73" + "\xf7\x45\x7e\x36\xb7\x09\x87\xf5" + "\xdc\x7a\x7e\xcb\x67\x30\x20\x1f" + "\x18\x28\xb7\xc7\xff\x4b\x44\x82" + "\x33\x80\xac\xba\x35\x3b\x30\x07" +
+       "\xfd\x09\x6f\x52\x45\xed\x7f\x05" + "\x0a\x24\x28\x81\x0c\xf1\xa4\xe8" + "\x8d\xfd\x2b\xff\xc4\xef\x32\x93" + "\x31\xaa\x35\xbd\xa0\x77\x4e\x21" + "\x0e\xa4\xfa\x14\x73\x6d\x89\x32" + "\x86\xf1\xe5\x01\xec\x67\x78\x76" + "\x3e\x81\xa1\x17\xf1\xf8\xad\xc9" + "\x95\x17\x74\x54\x78\xda\x6c\xcb" +
+       "\x85\xe1\xda\x01\x01\xd0\xb4\xb7" + "\xbc\x94\x7a\x9b\x0b\x4e\x43\x45" + "\x0b\xcb\xd8\xfb\xaf\x39\x43\xf5" + "\x9e\xf4\x8e\xe9\x9e\x56\xc4\xdc" + "\x99\x12\xa5\x09\x8a\x31\x89\x77" + "\xd8\x25\xb0\xb2\x06\xd2\xb4\x81" + "\x92\x57\xe8\xfa\x18\xa4\x4a\xf6" + "\xf7\xba\xd7\xac\x8f\x25\x50\x3e" +
+       "\x68\xd8\x9f\xa1\xd3\xeb\x72\xc0" + "\x3b\xdd\x8d\xdb\x1c\x48\x2e\x61" + "\x52\xd8\x64\x1a\x54\xd7\xe1\xb4" + "\xab\xc4\xc6\xc4\xac\x95\xef\x00" + "\x46\x6c\x0a\xaa\xed\xd2\x36\x15" + "\x90\x47\x77\x43\x86\x40\x29\x61" + "\x10\xda\x3f\x34\xe8\x25\xaf\x54" + "\xf2\xd6\x25\xfd\x8d\xd9\xf9\x9f" +
+       "\xa4\xbe\x79\x55\xdf\x96\xd2\x4c" + "\xf1\xda\xee\x5c\xc8\x5a\xe3\x10" + "\xb1\xc5\xbc\xe3\xfd\xc5\xc4\x04" + "\xf9\x2c\x41\x89\x8a\xee\xf9\x95" + "\x0f\xeb\xb6\x82\xee\x59\x94\x2c" + "\xdd\xaa\xc2\x95\x65\x57\x84\x2e" + "\xfe\xfc\x27\xd3\xae\x84\x4a\x77" + "\x76\xd4\x68\x03\x22\x37\xc9\xd8" +
+       "\xef\x36\x6c\x29\x10\xde\x1c\x21" + "\x77\xda\xc4\x82\x72\x96\xe8\x7e" + "\xda\x36\x78\xa5\x70\xd2\x17\xb6" + "\x0b\x56\xb7\x9c\x31\x9c\xcd\xf0" + "\x90\xfe\x55\xe4\xf7\xcb\xfd\x01" + "\xf3\x34\x73\x7e\xbb\x3c\xb5\x3f" + "\xec\xe4\x7d\x4e\xa4\x2e\x1e\x78" + "\xd0\x4f\x38\x0b\xad\xb3\xda\x8a" +
+       "\xb8\xb3\xba\xbb\xf2\x90\xe6\x60" + "\x6b\x81\x04\x8b\xae\xf8\x51\x48" + "\xd2\xe4\x92\x9c\xab\x46\x20\xc7" + "\x6b\x13\xf3\x7c\xa1\x74\x8c\x51" + "\x4c\x7d\x87\xf9\x0a\xb5\x4e\xff" + "\xbb\xca\x19\xa9\x90\x8d\x57\x14" + "\xb6\xb2\x5e\xac\xc4\xf8\x18\x82" + "\xe4\x16\x20\x54\x47\xc5\xcc\xa3" +
+       "\x85\x7b\xea\x1e\x6c\xa7\x3e\xe3" + "\x5e\xf8\xd4\x92\x61\xb4\x52\x23" + "\xbb\x15\xe1\xaf\x34\xd3\x01\xf1" + "\xa3\x75\x91\x88\x94\x12\xbc\xfa" + "\x25\xf9\x33\x52\xc0\xcd\x6b\x7f" + "\x55\xec\x7f\xe7\xdb\x02\xa8\xe0" + "\x59\xb6\x69\x80\x75\x7b\xb4\xbd" + "\x74\xbd\x8f\xf9\xde\x12\x5e\x1c" +
+       "\xbb\xdd\xd8\x89\x58\x46\x6c\x65" + "\xe8\x8e\xf3\x70\x6e\xb2\x30\x88" + "\xb0\x12\x12\xde\x5c\xfd\x20\x43" + "\xb2\xed\xa2\xe4\xcf\x30\x4f\xc3" + "\xb8\x64\xab\x56\xa3\x31\xb1\xab" + "\x26\x5d\x9c\xd9\xcc\xf0\x77\x7f" + "\x94\x1d\x98\xbf\x37\x6a\x85\x66" + "\x6e\xd7\x8b\x73\x09\x6d\xe7\x19" +
+       "\xc0\x18\xb6\x53\x7d\xd4\x6b\x1c" + "\x23\x79\x22\x6a\x6c\xf4\x24\xc4" + "\x64\xd9\x92\xdd\xde\xff\x03\x73" + "\xf2\xab\xb5\x71\x78\x28\x71\xe9" + "\x1d\x56\x15\xf8\x32\xa6\x48\x8f" + "\xd1\x55\xc0\xd3\xf5\x8f\xf4\x85" + "\x4f\x68\x25\x75\x27\x14\x2a\x22" + "\xc3\x0c\x36\x67\xa0\x41\xd8\xd0" +
+       "\x99\x4a\xc3\xf2\xb1\x44\x0c\x86" + "\xac\x55\x58\xbf\xa4\xac\x00\x3b" + "\xbe\x37\xaf\xfa\xa0\xaa\xf6\xab" + "\x08\xec\x53\x2a\x82\x36\xf4\x65" + "\xe1\x12\x1b\xa1\x01\x58\x9a\x1d" + "\x75\xd4\x0e\xe2\x2c\xab\xa7\x78" + "\xd5\xe0\x41\x9a\x7e\x06\xe1\x0d" + "\xea\x23\x50\x30\x5f\x3f\x47\x30" +
+       "\xc6\x68\x7f\xf9\x52\xb3\xb7\xdb" + "\x58\xcf\x02\x0b\x50\x3b\x77\x0c" + "\xd9\x96\x1f\x3c\x21\x48\x2e\xea" + "\x15\x18\xe0\xee\xb0\x57\xb3\xff" + "\x39\x80\xf2\xe0\xcd\x24\xc9\xb9" + "\xe4\xfb\xa3\x46\x5a\xc9\x36\x0b" + "\x6c\xdb\x46\x5e\xa4\xae\xaa\x1f" + "\xff\xaa\x28\x19\xc3\x75\xe5\xca" +
+       "\x6c\xb9\xcb\x70\x2a\x96\x3c\x26" + "\xa9\x24\xd1\xbc\x2a\x36\x34\xe0" + "\x8d\xe5\x2a\x3c\x28\xdb\x20\xf1" + "\x07\xd5\xf6\xfe\x49\x8d\xa3\xb9" + "\xfd\x40\xf1\x1f\x82\x2a\xfd\xb1" + "\xe0\xe7\xae\x20\x30\x2f\x16\xbd" + "\x49\x19\x25\xcb\xd4\xa5\x17\x4e" + "\x3d\x1c\x7e\x4f\x83\xcb\xeb\x2a" +
+       "\xf9\xf0\x9f\x59\x2b\x8a\x77\x01" + "\x6b\xfc\x04\x81\xd7\x23\xa9\x68" + "\xf3\x4f\x69\xda\xdf\x44\xfa\x5b" + "\x12\x7f\x66\xf7\xdb\x99\x71\x4f" + "\x79\x2a\x6f\xe4\xf6\x8f\x6d\xc0" + "\x1d\x13\xf8\xe9\xad\xde\xb5\x08" + "\x7c\xce\xb4\xab\x59\x9a\x51\x02" + "\x3e\xec\x2a\xb4\xbc\x10\xf7\xc4" +
+       "\x19\x27\xc2\xc0\xca\xd3\xbf\xd8" + "\x1e\x15\xca\xc9\xe4\x09\x02\xc6" + "\x9c\xa6\xa1\xd9\xb5\x4a\x74\x7a" + "\x8f\x7f\x93\x14\x8b\x04\xe5\x6d" + "\x04\xac\x15\xe1\xd8\x38\x19\x17" + "\xd2\x16\x6b\x1c\x40\x09\xf7\x7d" + "\xe7\x94\x8e\x7f\x63\xb6\xae\xa6" + "\x94\xf0\x2c\x2a\x8e\x38\x30\xc1" +
+       "\x7c\x33\x6f\x78\x9d\x71\xb6\xcd" + "\x7d\x39\x04\xe7\xd2\x1c\xc0\xd9" + "\xef\x2f\x5c\x55\x20\x3f\x4a\x0f" + "\x23\xf2\x0a\x7c\x09\x25\x45\x00" + "\x76\x8e\xdb\x84\x47\x80\xa5\x54" + "\x06\xaa\xc8\x93\xaa\xf1\xac\x3b" + "\x22\x94\x91\xf7\x7c\x95\xca\x11" + "\x40\xaa\xcd\x78\x53\x10\x64\x50" +
+       "\x75\xa7\x67\x6c\x31\xb7\x6e\x9f" + "\xb1\xd0\xc5\xef\x1a\x47\x10\xcb" + "\xb2\x06\xb8\xe1\x0c\x75\x33\xb4" + "\x7e\xae\xb1\x57\x4d\x71\xc5\x19" + "\x3f\xfd\x03\xed\x7b\x8b\xdc\xc0" + "\x4e\x19\xbc\x31\x4f\x34\x03\xdd" + "\xb5\x20\x63\x8c\xa7\x52\x6c\xa6" + "\x93\xfd\xb6\xd0\xe3\x2c\xc8\x8b" +
+       "\x0d\x04\x0b\x0e\x0f\xa9\x28\xb2" + "\x7f\x89\xff\x45\x82\x2d\xf0\xba" + "\x22\x61\xfa\x00\xe6\x79\xac\x2a" + "\x57\xf5\x36\x8e\x17\x88\x82\x24" + "\x56\xc3\x3e\x11\x31\x1d\x52\xb9" + "\xf8\xf1\xef\x15\x1e\x86\x48\x9e" + "\x15\x17\xd4\xe0\x12\xd4\xa1\x2a" + "\xb8\x31\xf1\x53\x03\x62\xf8\x71" +
+       "\x1e\xc5\x73\x6f\x3d\x48\x2a\x6d" + "\xdd\xc2\x0d\xea\x12\x24\xcb\xa4" + "\xff\x17\xb9\x1e\x41\x3c\x66\x50" + "\x9e\x29\xde\xea\xcf\x74\x3a\x3d" + "\x02\x92\x7a\x4a\x0f\x99\xb3\x29" + "\x3d\x5c\xb1\xa7\x59\xcf\xbc\xa9" + "\x08\x92\xdf\xa5\xdc\xcc\xa3\x66" + "\x29\xf9\xf2\x43\x14\x7c\x02\x48" +
+       "\xb4\xaf\x8c\x09\xbb\xa3\x44\xe0" + "\xaf\x8c\xd4\x60\x10\x23\xed\x27" + "\x4d\xb8\x31\x3a\x75\x56\x2b\x54" + "\xd7\xbe\xdd\xfc\x50\xdd\xf3\xcb" + "\x30\xd8\xb1\x41\x16\x1f\x03\x25" + "\x27\x1e\x0c\xcb\x1d\x85\xec\xa7" + "\xdb\x75\xae\xb5\xe0\x8f\x1c\xac" + "\x20\x21\xc5\x08\x57\x75\x4c\xb2" +
+       "\x9e\x03\x07\xd6\x71\x0e\xbb\x1f" + "\x46\x45\x3a\xcd\x15\xe2\x70\x2b" + "\x91\x40\x32\x53\x1d\xf0\xd2\x32" + "\x9b\xb1\x0a\x18\x08\xff\x96\xb7" + "\xaa\xc4\x57\x3c\x86\x7a\xd8\x32" + "\x27\x9a\xc4\xb7\xaf\x9c\xed\x2a" + "\x98\x0d\x63\x31\xac\x5e\xb3\x9f" + "\xa3\x20\x3e\x5c\xdf\x8c\x8e\x33" +
+       "\x40\x09\xd8\x4e\x8b\x36\x14\x30" + "\xdd\xce\x6f\x7a\x56\xd0\xe6\x67" + "\x9f\x57\x97\xca\x49\x8c\x20\x7c" + "\xf6\x97\x35\xa2\x81\x7a\x3d\xfe" + "\xe2\x6a\x09\x7e\x02\x32\x20\x5e" + "\x66\x93\xb3\x24\xe7\xe1\xf3\xb1" + "\xfc\xdf\xdc\x2f\xf3\x26\xda\x26" + "\x83\xbe\x97\x60\x1d\x2f\x42\x79" +
+
+       "\x81\xb3\xb3\x9d\xfb\x2c\x3a\x26" + "\x4b\x0a\xdf\xd4\xee\x2d\x3a\x9c" + "\x1f\xe6\x04\x7d\xe9\x06\x8d\x72" + "\x25\x93\x44\x42\xbc\xdf\x1a\x8b" + "\x1b\x3a\x05\x7e\x39\xd9\xc1\x6e" + "\x07\xf7\xda\x66\xc7\xe5\x2b\xee" + "\xab\xc7\x0a\x81\x14\x1e\xba\x80" + "\x74\xf1\x30\xf5\x78\xe7\x2a\xdd" +
+       "\x8b\x9d\x5b\x20\x7a\xd9\x35\x04" + "\xd4\x56\x67\x05\x64\xf0\xb8\x6e" + "\x0e\x21\xf8\xb6\x8b\x8a\xe8\xd5" + "\xea\xd9\x9f\xec\x2d\xf1\x0e\x07" + "\x6a\x87\xcc\x3b\x05\x95\x84\x4d" + "\xe3\x4c\x40\xa7\x38\x53\xa7\x12" + "\x5e\xdb\xa1\xb8\xe1\x49\x2b\xd2" + "\xad\xa5\xbf\x14\x51\x20\x1f\xec" +
+       "\x36\x8f\x82\xb6\x79\xeb\xba\xad" + "\x9e\x5b\xbd\x01\x58\x02\x7a\x9d" + "\x0c\x4b\x84\x1e\x0d\x1e\xa0\xed" + "\xc9\xdf\x7e\x88\x75\x51\x62\x4b" + "\x21\xb6\x69\x96\xdd\x9f\x10\x14" + "\x98\x7b\xf8\xf6\x56\xca\xa2\x88" + "\xbc\xf6\x0d\x17\x88\xb7\x2e\xfe" + "\xf9\x73\xa4\xff\xf4\x06\xea\x0c" +
+       "\x33\x3d\xe8\xc4\xb5\x81\xed\x43" + "\x8b\x48\xfd\x5e\x79\x58\xf3\xd9" + "\x0f\x4d\xeb\x9d\x0f\x62\x4a\x16" + "\x94\x73\x6a\xac\xdb\x7b\x92\xc6" + "\x03\x0f\x9e\x9f\xf7\x8d\xc2\x45" + "\xa9\xe1\xd7\xfc\x1e\x66\x68\x28" + "\xf1\x48\xa3\xff\xd0\xe8\xf4\x7c" + "\xe0\x38\x85\x39\x84\xc2\xd4\x6b" +
+       "\x19\x86\x9a\x28\x91\xa0\x18\x26" + "\x73\xb1\x71\x66\x60\x6e\x79\xef" + "\x32\xc6\x90\x90\xe5\x46\x4e\x66" + "\xfb\xf8\x66\x1e\xd4\x62\x80\xa3" + "\x4e\x27\x73\x05\x20\x4a\x74\x6c" + "\x94\x13\x27\xa9\xe4\x67\x7b\xd0" + "\x20\x0e\xdc\x6b\xb2\x23\x12\x39" + "\xa7\x05\x0a\xeb\xf1\x93\x2d\xbe" +
+       "\x41\xd1\x36\x3f\x53\x2e\x3e\xf2" + "\x42\xa4\xfc\x4d\xd4\xb3\x4b\xe8" + "\x3a\x02\x7c\x6b\x8d\xa4\x04\xb8" + "\x3b\x1c\x43\x76\xfa\xa8\x16\x1e" + "\xe0\x72\xd4\xdd\xad\x52\x54\x1b" + "\x27\xe1\x1e\x0d\xe7\x5e\x40\x7d" + "\x99\x75\xa2\xff\x1d\x6f\xfc\x50" + "\x35\x1b\x39\xbf\x3c\xc5\x1a\x35" +
+       "\x6b\x89\x44\x44\xb8\x14\xfa\x7e" + "\xfb\x27\x40\xf9\x2f\x4d\x97\x64" + "\x7d\x48\x84\xde\xe8\xd0\xdc\xef" + "\x9b\x98\x48\x2b\x60\xb2\x45\x8c" + "\x87\x34\x46\xd8\xc2\xbb\xfc\xa8" + "\x6c\x47\xbc\x3f\xf7\xb3\xb2\xd1" + "\xc0\x43\xf4\xc8\xb7\x05\xd0\x21" + "\x9c\x13\xc0\x40\x67\x2e\x8f\x51" +
+       "\xc1\x5f\xd7\x06\x8c\x6e\x03\x56" + "\x9f\xa8\x49\x32\xb7\x7b\xcf\x2d" + "\xdd\xe7\x45\xe2\x3d\x1d\xdd\x81" + "\xa7\xe2\xd6\xeb\x4b\xdc\x78\xf5" + "\xa0\xe7\x2c\xdf\x03\x89\x02\x4c" + "\xac\xaf\x39\x9c\x88\x62\xe3\xae" + "\xab\x04\x64\x14\x31\x7c\x84\xdc" + "\x18\x78\xe9\xa4\xd8\xc0\x04\x63" +
+       "\x91\x67\x1f\xa9\xa2\xdc\x51\xae" + "\xfc\x9e\xaa\x9b\x90\x41\xbe\x2a" + "\xc1\x7a\x9c\x55\xf4\xe2\xd2\xd9" + "\x3a\x77\x9f\xfc\x51\x4b\x2f\xe8" + "\x1c\xe8\x73\x40\x27\x30\x71\xa7" + "\xfc\x96\xb5\xfb\xac\x6f\x27\xc0" + "\x0c\xf7\x84\xa6\xc9\x9f\x81\x1d" + "\xe0\xb1\xf7\xc9\xdd\x7f\xb4\x29" +
+       "\x40\x19\x9b\x45\x03\xe1\x8d\x35" + "\x93\x3e\x01\x5b\x59\x1c\x88\xec" + "\xd3\x2a\x53\x49\x93\x4c\x57\x51" + "\xde\x46\x7b\xb3\x45\xd4\xb1\x2d" + "\xd8\x9f\x23\xdf\x87\x5b\x44\xc6" + "\xee\x24\x1d\x15\x75\xaf\x18\xc7" + "\x59\x62\x3c\xf4\xa4\xc4\xa1\xae" + "\xf7\x02\xbe\x70\xd7\xe5\xc0\x40" +
+       "\xf2\x33\x1b\x72\xf4\x90\x45\x6a" + "\xea\x04\xdf\xfe\xfb\xf1\x24\x21" + "\xe7\xef\x45\x97\xde\x3c\xe5\xf8" + "\xd9\x46\xf0\x65\x32\x04\xe1\xe7" + "\xe6\xc7\xd0\xe4\x8e\xa2\xfc\xc3" + "\x1b\x3b\x25\x87\x9a\x33\x7e\x84" + "\x43\xe6\x43\x37\x48\x53\x59\x9b" + "\xc5\x2f\xd1\x4f\x0b\x0a\x6a\xcb" +
+       "\xcc\x2d\xd0\x27\xc3\x36\x68\xfb" + "\xc2\xbc\x68\x7a\x82\x09\xd0\x5a" + "\x2d\x91\x5e\x00\x4c\xb4\x24\x1b" + "\xfe\xdc\x1f\x81\x0f\xd2\x83\xcc" + "\x0c\xba\x6f\x66\xc1\x7e\x52\x36" + "\x35\x46\x75\x14\x97\x81\x94\x69" + "\xc2\xa9\x6d\x55\xa8\xb1\xdc\xfc" + "\xb2\x32\xa7\x81\x67\x42\x93\xa5" +
+       "\x1d\x18\x14\xa7\xed\x14\x12\xec" + "\x41\xb3\x67\x60\x3b\xc1\x9a\x60" + "\x1f\xdf\x45\xa5\x97\x4c\x4b\xff" + "\x6b\x07\xd2\x34\x01\x05\x24\xa1" + "\x97\xca\x09\x14\x23\x0c\xfa\x6e" + "\x43\x8c\x63\x20\xa8\xc1\x4c\x25" + "\xcd\x46\xfb\xdc\xaf\x63\xe3\xd4" + "\x27\x2a\x94\x03\xc3\xad\xc2\x62" +
+       "\x83\x64\xe4\x56\xf0\x9d\x7b\xc6" + "\x56\x63\x73\x63\x20\xbb\x5a\xa5" + "\x52\xbc\x51\xc5\x98\xc0\x93\xab" + "\x4b\xe6\x5f\xb1\xf9\x49\x2b\x38" + "\x47\x8d\xff\x4d\xad\x21\xc2\x9e" + "\xd6\xf4\x7d\x43\x15\xf6\xca\x79" + "\x09\x65\x45\xbb\x64\xdc\x13\x5f" + "\x14\x07\x1f\x19\xd9\x89\xc5\xe4" +
+       "\x09\x0e\xd4\x3f\xab\xa8\xb6\x27" + "\xa9\x3e\x31\x77\x2e\x84\x55\xe4" + "\x8b\x98\x55\x1f\xe2\xd1\x51\x8b" + "\xfc\xbb\x2b\x06\x73\xdd\x16\x57" + "\xde\xf3\x8b\x4e\xe5\x11\x3c\x63" + "\x3b\xbe\x85\x1b\xb6\x77\x0e\x9a" + "\xa6\xcc\x11\x09\x29\x07\x51\x56" + "\x0f\x59\xa6\xef\x95\x64\xe7\x27" +
+       "\xab\x3a\x0d\x07\x33\x8b\xac\xe4" + "\xe5\xd5\x2c\x9a\x2b\x67\x43\x26" + "\x73\x91\xfc\x1c\x9b\xf7\xef\x52" + "\x3f\xc1\xa7\x90\x9b\xa4\x5c\x66" + "\x98\xb9\xef\xb3\x59\xda\x8d\x5a" + "\x41\x13\x2f\x05\x2d\x92\x5b\x8a" + "\x30\xa5\xf9\x3c\xab\xbb\x9e\xae" + "\xd7\xa4\x6d\xf5\x7b\x6e\x98\x35" +
+       "\xcc\x13\x35\xff\x5c\x6b\x63\x3a" + "\xdd\xf7\x98\x31\xba\xf8\x0c\xbb" + "\x86\x6f\xf1\x41\x22\x05\xd4\xb8" + "\xbf\xa7\x13\xde\xd8\x75\x05\x76" + "\x81\xa1\x7a\x9f\x16\x4e\xf7\x36" + "\x1c\xed\x09\xf5\xcf\x3e\x3a\x16" + "\x91\xa4\x40\x3c\x1f\xd6\xea\x6a" + "\xaa\xfc\xe8\xdf\xfc\x95\x8c\x15" +
+       "\x6f\xa4\xcd\x13\x6e\x1b\x99\xa3" + "\xd0\xae\x2f\x34\x15\x24\x48\x79" + "\x70\x59\x6b\x66\xde\x5b\xba\xf3" + "\xdd\xb6\x6a\xb2\xbc\xe6\x52\x1d" + "\x3d\xdd\x08\x86\xe7\xa1\x8b\x76" + "\x86\x65\x07\xea\x2a\xdb\x30\x49" + "\xfa\x1a\xdc\xe7\x14\x57\x57\xd9" + "\x17\x88\xc5\xf7\x7d\xbf\xc7\x1f" +
+       "\x6c\xe9\xee\xd9\xcd\xac\x47\x6b" + "\x37\xec\x8c\xe5\xfb\x77\xa2\x0c" + "\x2a\xc4\x02\xe7\x13\xe4\x3f\x11" + "\x51\xbe\x7c\xc4\xee\x64\x17\xdd" + "\x39\xd7\x3e\x7b\xde\x7c\x1e\x04" + "\xc0\xe1\xe9\x5c\x59\x74\xcb\x50" + "\x12\xb2\x25\x29\x13\x85\x56\x35" + "\x1c\x08\x1b\x00\xc4\x95\xff\x7c" +
+       "\x54\xb4\x88\x80\xbd\x4c\xee\x63" + "\x8a\x0c\x9e\x9a\xf7\x32\x7f\xdb" + "\xcb\x47\x24\x6b\x18\xd4\x77\xb3" + "\x9b\x21\x70\xd3\xaa\x82\xe9\xe3" + "\x93\xa5\xa2\xc2\xe4\xc1\xcc\x06" + "\x4f\xf2\x73\x07\x65\x68\xc3\x72" + "\x23\x94\x85\x95\xa7\x4d\x3b\xa1" + "\x8f\x0c\x04\x75\x33\x1d\xbf\x8b" +
+       "\x91\xc9\x50\xda\x73\x09\x6f\x72" + "\xe2\x6e\x2d\x82\x5b\xcd\xaf\x48" + "\x71\x77\xfd\x20\x8b\x71\xfc\xe5" + "\xa1\x07\x08\xfd\x7d\xe7\xe8\xb9" + "\x3d\x70\xa7\x99\x44\x0f\x5e\x7f" + "\xf3\x36\x8e\x61\x0e\x93\x72\x69" + "\xbe\x7b\x80\x23\xb8\x77\x7c\x2b" + "\x50\xff\x27\xcb\x05\x24\xb8\xe5" +
+       "\x62\x90\x37\xbd\xe3\x8b\x8b\xba" + "\x92\x4a\xce\x2d\x1d\x7a\x4b\xd6" + "\x37\x2e\x95\xb2\xc5\x73\x0a\x04" + "\xca\xae\x38\xd4\x2e\x25\x9e\x0a" + "\xcb\x3b\x9d\xc3\x6b\x95\x43\xdd" + "\x63\x2d\x2b\xb3\x00\xca\x31\x1a" + "\x18\x7a\x41\x5c\xb8\x33\x71\xd6" + "\xc8\x42\xf4\x2e\x90\x47\x8e\xd0" +
+       "\x80\x09\x5c\x25\xe9\x1a\xcb\x98" + "\x9f\x73\x4a\x2b\x81\x63\xd8\x4b" + "\xa1\x45\x4a\x1e\xe1\x31\x5c\x5a" + "\x2f\xdb\xb0\x9c\xfe\x55\x5d\x1e" + "\x29\xcc\xf5\x8f\x06\x1b\x66\x74" + "\xf4\xa4\xb8\x0e\x9f\x38\x6b\x02" + "\x24\x8c\x84\x58\xa4\x21\x6b\x53" + "\xb0\x72\xdc\x81\xec\xf8\x5b\x2e" +
+       "\xac\x6a\x88\xad\xd0\x87\xc1\x03" + "\x45\xb6\x71\xb7\x8a\x87\x16\x5c" + "\xab\x45\x40\xc7\x6f\xfc\x7d\xb0" + "\xed\xca\x00\x78\xbf\x60\x63\x2c" + "\xa3\x72\xc9\xb9\xb5\x5b\x29\x24" + "\xba\x6d\x9a\x7c\x8e\xf8\xe6\xc9" + "\xa6\x9a\xa7\x92\x24\xbf\xff\x90" + "\xc2\x6a\xc2\x41\x0a\xd5\x29\xde" +
+       "\xe6\xcb\x09\xd3\x83\xf4\x0a\x9f" + "\x4f\xed\xbc\xe0\x8a\x0d\x02\x5b" + "\xe3\x23\x80\xb3\x6d\x98\x6e\x60" + "\x33\x69\xbc\x1a\x9d\x2c\x8f\xad" + "\x93\x0e\x40\xe7\x1d\x2e\x29\x19" + "\x4d\x5e\xbe\x52\xa9\x18\x3e\xfe" + "\xbf\x80\x06\x2e\x1d\x77\xe9\xe8" + "\x63\xb0\x4d\xc5\x98\xec\x5b\x8c" +
+       "\x1f\x5d\xa5\x74\x2a\x66\xf9\x2a" + "\xd8\x66\x6f\x04\x8f\xf2\xfb\xe3" + "\x94\x47\xdc\xd4\xb4\x2a\xa7\xa3" + "\xd8\x2d\x7c\x5c\x45\x9f\x77\x09" + "\x8d\x9d\xd1\xc3\xaf\xbd\x93\xd8" + "\xdf\xa6\xd6\x57\x94\x50\xa7\xd5" + "\x55\x62\x2e\x95\xf9\xfe\xf8\x8c" + "\xff\x8a\x9a\xda\xfb\x7c\xa6\x3d" +
+       "\xcd\x0d\x16\x2c\x2a\xf6\x23\x4c" + "\xef\xea\x90\x8f\xe3\xc5\xe6\x34" + "\x5a\x5d\xa6\xa9\x19\x55\x86\x35" + "\x3d\x8a\xd3\x8f\xae\x8a\xc4\x07" + "\x27\x85\x06\x50\xda\xae\xe7\xb7" + "\x6a\x93\x90\x1c\x23\xef\x09\x2c" + "\x4c\x32\x79\xe8\xb6\xfe\xec\x31" + "\x38\xc9\x0e\xfb\x6b\x1f\x87\xa0" +
+       "\x5d\x83\x4d\xd8\x68\xfb\xf0\xb1" + "\xe6\xc1\x1d\x86\x39\xaf\x0c\xc9" + "\xd7\xf8\x94\x75\x46\xb0\xe5\x12" + "\x92\x2b\x01\x65\xe2\x7a\x89\x26" + "\x5d\x75\xd6\xa4\x08\x8a\xf6\xbc" + "\xda\xfb\x91\x09\x1c\xe4\x3e\x40" + "\xe8\x17\xbf\x3b\x3e\x34\x3e\x73" + "\x65\x3d\x9b\x67\x0d\x98\xc7\xd2" +
+       "\x05\x13\xe1\xd2\x32\x62\x05\x33" + "\x6f\x7a\xc0\xf3\x92\xe4\x6b\x96" + "\x9d\x50\x15\xbb\xff\x78\x88\x6a" + "\xa4\x59\x9b\x0a\x01\x11\x22\xff" + "\x29\x01\xe3\xab\x4a\x56\x9f\x6c" + "\xcf\x64\x6e\x33\x40\xc9\xf2\xc6" + "\x22\x80\x0c\x8b\x62\x52\xe7\x0f" + "\x87\xdb\xe8\x6a\xe9\x67\x02\xbe" +
+       "\x2b\x04\xbc\x93\xf1\x92\xe1\x22" + "\x58\xc4\x37\xb2\x34\xb5\x85\xf0" + "\x68\x41\x2c\x83\xbd\x92\xd1\xa0" + "\x1d\x27\xf6\xbd\xe3\xe9\x76\x7a" + "\xb5\x11\x89\xb8\xfa\x82\xa8\x52" + "\xb5\x0e\xdb\xb4\xe4\x45\x53\xc8" + "\xff\xc3\xa7\x81\xa6\x02\xbe\xa3" + "\x69\x04\xec\xf0\x8c\x9c\x88\x51" +
+       "\xe5\x29\xe8\xa5\x69\x13\x03\x9d" + "\x41\xaa\x07\x16\xfc\xc6\xb4\xcb" + "\xc1\x84\x1d\x24\xa6\x59\xac\x75" + "\xee\xe0\x29\x88\xbf\xf2\x43\xc0" + "\x85\xe1\xa5\x8e\x75\x8f\xa3\x82" + "\x9f\xbd\x7c\xd8\xb9\x40\xda\x8b" + "\x01\xc6\x8f\x2d\x5e\xe7\x65\x9e" + "\xb3\x90\x56\xa3\x74\x5f\x51\x3d" +
+       "\xac\xe5\x79\xda\x4f\xcf\x4a\x53" + "\x5f\x21\x30\x86\x3a\x3b\xb8\x68" + "\x6e\x75\x85\xd0\x2e\x8b\x74\x5c" + "\xb2\x7c\xd3\xe5\x58\x72\x31\xb0" + "\xc4\xc2\xcc\xc5\x1a\x84\x35\x67" + "\x69\x50\x9d\x3d\x6b\xc9\x7d\x7d" + "\xbd\x54\x17\xfd\x10\xe4\x47\xa1" + "\xd5\xdd\x99\xd3\x94\x6e\x29\x65" +
+
+       "\x3a\xfb\x0c\xb3\xcd\xc4\xe0\xd7" + "\xc8\xb4\x9d\x6c\xc1\xb8\x09\x6d" + "\xdf\xd9\xc8\x07\x42\x1a\xba\x40" + "\x6d\xc6\x52\x1c\xf7\x95\xd4\x6f" + "\xda\x64\x52\x27\x9f\x16\x0e\xfb" + "\x62\x83\x7d\xe5\x46\xb7\xc2\x80" + "\x22\x72\xad\x49\xf7\x87\xd9\xed" + "\x7b\xec\x98\x43\xaf\x29\xc2\xfd" +
+       "\x58\x6a\x66\x52\x84\xed\xd1\xb0" + "\xc2\xc3\xa9\xe6\x00\x6e\xcb\x4b" + "\x08\x64\x90\x26\x1c\x41\x57\x3c" + "\x00\x64\x55\x13\x55\x07\xc2\xcf" + "\xa3\xdb\x94\x52\x50\x1c\x8b\xa0" + "\x1e\xd3\x7d\x8b\x86\xa2\x0b\xa3" + "\x74\xca\x1e\x99\x0e\xa9\x0b\xd7" + "\xb9\xc2\x62\xe7\x2c\x14\x4e\x09" +
+       "\xef\x13\x7f\xac\x9b\x43\xea\x88" + "\x14\x7d\x9a\x8d\x3f\x14\xaa\x65" + "\x1a\x2f\xcb\x20\x2d\xcf\xe0\xff" + "\xd1\x6a\x1c\x38\xf1\x7b\x7b\x84" + "\x4d\x0b\xc8\x8a\x14\xb8\xf5\x56" + "\xf2\xaf\xce\x35\x18\x44\x1b\x04" + "\xef\xfc\xa5\xcd\xc0\x88\x90\xde" + "\xce\xb8\x83\xe0\x9b\x51\x68\xe6" +
+       "\x25\x39\x9f\x97\x3e\x78\x1d\xb8" + "\xa7\x89\x4c\xaf\x0a\x13\xfd\x1e" + "\xfa\xf7\x1b\xfd\x44\x21\x5c\x52" + "\x9e\x5a\x26\x1b\x04\x69\x29\x4b" + "\xb6\x65\xdb\xb9\x34\x96\x8e\xed" + "\x8a\x9d\x59\x03\x32\x2e\xc8\x35" + "\xf3\x63\x35\x40\x4f\xa5\xa7\xda" + "\xab\x38\x2c\x02\xad\x88\xf0\x9d" +
+       "\xee\x60\x62\x45\xc1\x5a\x69\x1c" + "\x93\x36\x78\x4d\xdf\xce\x3a\x4e" + "\x8f\x4a\x67\x11\x59\x52\xfd\xda" + "\xf9\x22\x7b\x6c\x40\x6d\x84\x21" + "\x55\x1f\x89\x17\xfc\x1c\x3d\x78" + "\x75\x04\x4d\xd7\x34\x3c\x17\x2a" + "\x20\xfa\x99\xb6\x7f\xbd\xfd\x3a" + "\x62\x9f\x82\xac\xb6\x8f\x24\x79" +
+       "\x0a\xd3\x3f\xbb\x66\xb0\xcf\xe5" + "\x4e\x35\xf0\xef\xda\x69\x91\x42" + "\x6c\xe3\x24\x35\x52\xf8\x9c\x80" + "\x1d\xbe\x55\x01\xb3\x4f\x6f\x13" + "\x12\xa7\xbb\x1f\x01\xaf\x26\x48" + "\xa1\xa1\x6b\x50\xb4\xf0\xf0\x6e" + "\x3e\xa7\xae\x77\x31\x8b\x92\xd9" + "\x4e\x24\xaa\x5e\xf2\x6a\xbf\xe2" +
+       "\xb2\x1d\xc8\x1a\x3a\x36\x28\x18" + "\x66\x06\x82\x48\xb3\x22\x2a\x75" + "\x6a\xab\x32\x3d\x03\x00\xc0\xcf" + "\xb1\x3c\x6a\xd9\xe1\x77\xd6\x2a" + "\x11\x30\x23\xc8\x72\xe6\xe3\xa7" + "\xb7\x03\x43\x5e\x7e\xe8\x65\x2c" + "\xcb\x04\xdf\xc6\x1b\xf7\x34\x18" + "\x34\xa8\xed\x3c\x2c\x77\xf8\x32" +
+       "\x4b\xb6\x37\x42\x12\x4f\x08\x8d" + "\x07\xfd\xec\xe3\x99\xbe\x8e\x68" + "\xd8\x5d\x84\xf6\x0c\xa7\xb8\x57" + "\x25\xa3\xa4\x5d\x9c\xc5\x8f\x80" + "\x62\x58\x58\xa3\x2b\x2b\x03\xa9" + "\x86\x93\xf2\xed\xd5\x25\x68\xb6" + "\x9b\xc2\x1e\x43\xdb\xa8\xa5\xb5" + "\xc8\x8d\x1e\x3a\x98\x3a\x14\xbb" +
+       "\xd9\xd1\xe9\xcf\x07\x6a\x35\x5b" + "\xdd\x48\x6f\x30\x3a\x68\xba\xd4" + "\xc1\x37\x64\x2c\xb5\xe7\x6a\x3b" + "\xd4\x4f\xb6\x54\xa1\xc1\xc0\xf9" + "\xd0\x52\x54\xed\xba\x0d\x66\x90" + "\x0f\x53\x50\x28\x95\x3e\x3f\x42" + "\x81\x4d\x27\x47\x06\xa2\x32\x14" + "\x74\x05\xb0\x7d\xf8\xf3\xeb\xcc" +
+       "\x1b\x38\xae\x12\xce\x94\xee\x35" + "\x90\xda\xcc\x86\x6c\x17\x7f\x3a" + "\xca\xea\x06\x46\x7e\x65\x3a\xc6" + "\xdf\x04\xcd\x43\x80\xa3\xe5\x9a" + "\x46\x1b\x25\xed\x15\x8d\xec\x9b" + "\x64\x5e\xca\xca\x30\x6d\x5d\x1f" + "\x07\x0f\xf2\x9f\x35\x3b\x7b\x34" + "\x86\xb2\xe4\xf7\x34\xf0\x65\x4d" +
+       "\x96\x29\xc8\x06\xf6\x81\x9f\xd8" + "\xfc\x92\xc5\x15\x88\x52\x73\x4f" + "\xc6\xa8\x49\xce\xa1\x03\x0c\x8c" + "\x07\x59\xf2\xb9\xe0\xff\x4d\xe0" + "\x4b\xab\xf7\x4a\x50\x21\x66\x22" + "\x4c\x5c\xa3\xf5\xf6\xff\x21\x9e" + "\x98\x91\x1e\x5a\x84\x44\x1d\x07" + "\x11\xfc\x09\x41\x5c\x95\x11\x08" +
+       "\x1e\x66\x11\xf1\x24\xba\x93\x9e" + "\x04\xeb\x05\xb1\x84\xd4\xce\xed" + "\x78\xb5\x24\xf4\xa1\x9b\xdc\x96" + "\x69\x90\x3e\xe8\xb7\x66\x8f\xbf" + "\x16\x82\xed\xd7\xf4\x4d\x2d\x87" + "\xcf\xbe\x2c\x8e\x77\xf3\x07\xbf" + "\x54\x37\xe7\x98\x99\xd8\x81\x42" + "\x08\x87\xab\x8a\xbb\x5f\xc8\xfe" +
+       "\x5b\x39\x11\x45\x1d\x41\x28\xd3" + "\xde\xf8\xcd\xe4\x79\xc0\x50\x31" + "\xd0\xbc\x34\x59\xc4\xe7\x4b\x22" + "\xae\xc9\x58\x43\x75\x71\x97\x9d" + "\x4d\xdb\x30\x22\x41\xbb\xb1\xdb" + "\xdc\x31\x8e\x0d\xbd\x84\x8e\x16" + "\xd2\x5f\x11\x1c\x34\x4f\x1b\xa6" + "\x8f\xc2\x88\x58\x15\xfa\x75\xc7" +
+       "\x0b\x5b\xba\xa5\xee\x0d\x3c\x9a" + "\x99\x52\xd0\x42\xce\x16\xa1\xe6" + "\x42\x2d\xb0\xe9\xfe\x75\x97\xae" + "\xb6\x5c\x54\xa1\x00\x52\xb0\x72" + "\xea\xb4\xa3\x31\x7d\x6f\x50\xbc" + "\x32\x9b\xbd\x8b\x78\x30\x89\xe5" + "\x97\x2a\xb1\xe4\x37\x5f\xbc\xc8" + "\x71\xb6\x73\x4a\x06\x0c\x00\x6b" +
+       "\x8a\x5f\xde\x17\x5c\x92\xc6\xf3" + "\xd5\x91\x49\xf3\x95\x4b\xcb\xa6" + "\x66\x05\xd5\x7d\xf0\x97\xbf\xa8" + "\x9e\xa0\x91\x0b\xe5\x55\x8d\x2c" + "\x20\xe7\xd7\x3a\xed\xc2\xdc\x6a" + "\x5a\xec\x93\x00\x48\x23\x4a\x73" + "\xaf\x36\xcb\x43\xbe\x8f\x1d\xfa" + "\xe4\xa7\xa8\xa4\x1c\xb8\x87\xdc" +
+       "\xd0\xa7\x5f\x76\x22\xbf\xb5\x13" + "\x70\x53\x6a\x1d\xf0\x5b\x80\x59" + "\x98\xdb\x80\x42\x9d\xe2\xa5\x67" + "\xe3\x1c\x6b\x77\x6f\x91\x53\x4f" + "\x26\xf6\xdd\x33\x1f\xf6\x4f\x71" + "\x03\xd1\x85\xa0\x8e\x23\x06\x42" + "\xe3\x9e\x80\xe5\xb7\xd4\x50\x1c" + "\x1d\xeb\xf8\x85\x0d\x45\x9f\x99" +
+       "\x25\xf3\x39\xa2\xb1\x04\x39\x5f" + "\x90\xad\x58\x1a\xf7\xa6\x26\xd0" + "\xed\x24\xb8\xd6\x36\x27\x54\x43" + "\xb8\x64\x93\x4a\x75\xa7\x41\x08" + "\xe9\x1d\xeb\xcf\x41\xcb\x97\x75" + "\x4f\x0a\x58\xbf\x7a\x2b\x25\x20" + "\x20\x8e\xc4\x17\x81\x92\x72\x37" + "\x71\xa0\xf5\xc6\x28\x1c\xdb\xda" +
+       "\x9b\x9e\xc7\xe4\x51\x60\x8a\x65" + "\xea\x9f\x6a\xc6\x73\xcb\x94\x13" + "\x23\x7b\xbe\xc6\xd5\x1e\xf3\x27" + "\xfe\xf8\xa6\x5a\x36\x8f\xc8\xf4" + "\x9e\x49\xaa\x4a\x1f\x72\xb0\x0f" + "\x6b\x2a\xfb\xe3\xd5\xa7\xb3\x68" + "\x1d\x85\x92\x3a\x7d\x09\x88\xa7" + "\x13\x49\x6f\xe9\x8a\x7f\x0e\x06" +
+       "\xc1\xfd\xdb\x88\xe2\x0c\xfa\xf1" + "\x08\xdd\xf8\xd2\x80\x74\x39\x3c" + "\xf0\x95\xdb\x4e\x8b\x0a\xf1\x0e" + "\x56\xe5\x47\x32\x75\xbc\x58\x45" + "\xa4\x4f\xc0\x0f\x5f\xef\x5c\x76" + "\x75\x3d\x6d\xd6\xe6\x2c\x9f\x72" + "\x66\xf0\x33\xb4\x5d\x27\x35\x6d" + "\x7e\x59\x4e\x36\x27\x5c\xd9\x31" +
+       "\xbc\x93\x3a\x1a\x73\xbe\xee\x82" + "\x1a\xdc\x1a\xa2\x65\xf4\xbb\x42" + "\xfd\x0e\x03\xef\xa4\x6f\x0b\xc1" + "\xbb\x97\xb0\x87\xc7\xa4\x7a\x24" + "\xda\x77\x0c\xf6\x32\xc6\x8d\x8b" + "\x3e\x52\x23\xc2\x6a\xc2\xfb\x6f" + "\xcf\x79\x45\x34\x11\xff\xf6\xa4" + "\xf6\x50\x02\x98\x3c\x65\x25\x58" +
+       "\x8b\x39\x1f\xcc\x9a\xef\xea\x88" + "\x95\x7e\x21\xf4\x25\x9a\x18\x85" + "\xef\xfc\x68\xb9\xf5\xf5\x24\x94" + "\x28\x22\x07\xd0\xf9\x8a\x5d\xc0" + "\x2a\xb2\xa1\x49\x8c\xfa\x36\x0b" + "\xce\x5f\x11\xf1\x57\x36\x1c\xe6" + "\x3f\x43\x62\x42\xc0\xf0\xcd\x06" + "\xdc\x20\xc8\x9e\x2d\xc5\x8a\x9d" +
+       "\xb9\xa2\x1a\xbc\x7e\x09\xdd\xb2" + "\x3a\x33\xa0\x37\x93\x93\x88\x07" + "\x38\xdb\xa0\x37\x71\x5e\xf5\x1c" + "\x13\x16\x2c\x79\x7f\x48\x48\x26" + "\x61\xf2\xce\x3f\x36\x13\xd0\xda" + "\x29\xf1\xab\x0e\x1d\xc8\x39\x62" + "\xe2\x6b\x27\x9d\xde\x61\xe7\x8e" + "\xd3\x6a\xda\x1e\x34\x7a\x6a\x40" +
+       "\x07\x6a\x02\xd5\xac\x10\x73\x01" + "\x1c\x28\x93\xe7\x54\xc9\x26\x35" + "\x51\xac\x00\x76\xc5\x7b\x6b\x41" + "\xa7\x44\x2b\xd4\x52\x89\x67\x09" + "\xb1\x9f\x04\xb6\xb7\x3f\xda\xab" + "\x7b\xef\xad\xdf\x59\xa6\xb0\x3c" + "\x0d\x0c\x8b\x1b\x72\x31\x79\x58" + "\x1b\x61\x9d\x4e\x6e\x47\x73\xfe" +
+       "\x31\x3b\x49\x4a\xba\x67\xf3\x4b" + "\x26\xf0\xf7\x9b\x52\x0a\xf2\x54" + "\x4b\x91\x95\x97\x62\xe0\x96\xb6" + "\xac\x36\xf2\x8b\x6d\xb9\xda\xcd" + "\x13\xea\x25\xed\x0a\xc7\xf2\x4f" + "\xe7\xbb\xcb\x81\xeb\x09\x1d\xfa" + "\xc5\x44\x85\x46\x87\x8c\xfc\x88" + "\x17\x33\x6b\x69\x0d\x67\x7a\x84" +
+       "\x59\x9a\x51\x45\xe2\xaf\x10\x84" + "\x74\xd7\x30\xbc\xaf\x39\x97\x9a" + "\x88\x4a\xf4\xd8\x03\xde\x33\x66" + "\x37\xdb\x5d\x50\xb3\x9b\x6a\xd5" + "\x14\x5e\x81\x46\x07\x7c\x66\x66" + "\xbb\x93\x44\x88\xed\xf8\x28\x22" + "\x82\x48\xab\x17\x1a\x56\xcc\x23" + "\xce\x1b\x1a\x52\x59\x07\x83\x99" +
+       "\x26\xb6\xbc\x64\x1e\x42\x33\xf1" + "\xb5\xe0\xde\x26\xc8\x38\xa6\xae" + "\x6c\x34\x10\xb3\x0b\x68\xe7\xd6" + "\xd3\xce\xd4\xd5\x97\x40\x6f\xe0" + "\x0b\xa3\x12\x75\x52\x14\x96\x09" + "\x9a\xa5\x89\xe5\xfd\x67\xd8\xf3" + "\x80\xc1\xd0\x52\x4f\x25\x73\x2e" + "\xac\x74\x3c\x33\xa3\xd8\x63\x90" +
+       "\x7a\x6f\xee\xe2\x44\x27\x14\x12" + "\x3f\x60\x21\x65\x10\x9d\x38\x63" + "\x3a\x81\x9c\x9e\xc7\x82\xcd\xa1" + "\xeb\x42\xe3\x5a\x1c\x64\x09\xc1" + "\xe9\x06\xbb\x04\x30\xfb\x85\x3c" + "\x7f\xf1\x12\xc2\x1c\x44\xed\x1f" + "\x53\x1a\xf6\x82\xac\xdf\x56\x16" + "\x5f\x8f\xd9\xce\x30\x7a\xec\x88" +
+       "\xbc\xe7\x14\xd3\x95\xc5\xa6\xed" + "\xed\x99\x78\x46\x4b\x46\xe7\x2e" + "\xd3\xd5\x1e\x0a\x3c\x42\xef\x1c" + "\x13\x76\xcc\x69\xea\x76\x7e\x21" + "\x17\xa9\xcd\xe7\x1f\xce\xcc\x27" + "\x16\x3f\x89\x8a\x6b\x01\xd8\x12" + "\x6b\x4f\xc7\x9f\x84\xde\xd6\xbc" + "\x61\x4e\x14\xf3\xe2\x17\x58\xfa" +
+       "\xce\x5e\xc5\x9b\xb5\x39\x89\x0b" + "\xff\x70\xaa\xcb\x3b\xb3\x64\xb1" + "\x91\xb7\x2a\x3f\x0f\x01\x6b\xaf" + "\x37\xcb\x52\x7b\xba\x67\xb7\x98" + "\x41\x65\xf8\xfc\x80\xf3\x0d\xbd" + "\x4a\x01\xa1\x64\x54\xf3\x94\x51" + "\x25\xf6\x35\x4c\x2e\xf2\xc1\x42" + "\x1b\xf5\xbb\xf7\xe2\xf3\x70\x9a" +
+       "\x4c\xee\x21\x08\x64\x41\x35\x1f" + "\x92\x19\xc6\x0b\xb4\xea\x83\x15" + "\x9f\x87\x72\x1d\xf6\xca\x90\x74" + "\xb2\xe7\x6a\xf7\xf3\xd9\x8a\x99" + "\xf7\x57\x11\xa4\x50\x19\x18\x1e" + "\x7e\x3a\xda\xe8\xe6\xe1\xd7\xa9" + "\x5f\xb9\x26\x84\xeb\x84\x37\x96" + "\x10\x2a\x2e\x54\x6e\xed\xe4\x0e" +
+       "\x83\xfd\x12\x96\xb8\x35\x4d\xbc" + "\xe9\x05\x40\x5c\x50\xca\x77\xf4" + "\xd1\xec\x7e\xa8\x3d\x20\x62\xb7" + "\x86\x25\x08\x38\x22\x9b\xac\x68" + "\x91\x35\x78\xcc\x59\xd6\x96\x66" + "\xb4\x52\x63\xd3\xdd\x43\x46\x25" + "\x69\x1d\xad\x9d\xd9\x70\xe3\xcd" + "\xfa\x5d\x71\x62\x6c\xf2\x7a\x9d" +
+       "\x7b\x1e\x75\xac\xc5\x4c\x9d\xb7" + "\xbd\x11\x42\xfd\x72\x64\xf9\x93" + "\xc6\x4f\xde\xc8\xd2\xd3\x72\x8c" + "\x64\xf0\x44\xdf\xf5\xcb\x69\x7b" + "\xe1\x94\xbf\xf4\xa2\x0c\xa9\x3d" + "\xe2\x94\x28\xf1\xf8\x25\x53\x1a" + "\x0b\xd6\x17\x79\x6c\x7f\x43\x0a" + "\x5d\xcb\xc9\x96\x86\x04\xe7\x9b" +
+
+       "\x26\x7c\x33\xe1\x76\x99\x9c\x94" + "\xe5\x68\x3d\xd7\xbd\xde\xaa\x6f" + "\xd9\x68\xb7\xf1\x14\x86\x15\x9e" + "\x69\xf0\xc4\x9c\x57\xa5\xdf\x22" + "\xd6\xc6\x93\xbe\x17\xda\xd6\xcc" + "\xb9\xf5\x04\xa5\x61\x6c\x86\x24" + "\xa1\x4d\x69\x8d\x3c\x35\x21\x21" + "\xc6\xb8\x40\x01\x80\xa5\x6c\x1c" +
+       "\xb8\x9b\xb7\xd4\x7d\x4a\x60\xf1" + "\xc8\x78\xc8\x52\xfb\x06\xe8\xae" + "\xe8\xb8\x47\x8d\x11\x4f\x14\x34" + "\x54\x90\x9f\x94\x2b\xf5\xed\x72" + "\x5a\x01\x27\x21\x4e\xa8\xfc\xeb" + "\xf3\xce\xb7\x9c\xc0\xd0\x51\x90" + "\xc8\xee\x6d\x29\x58\xfe\xe8\x86" + "\x74\x0d\x01\x41\x88\x81\xb2\x33" +
+       "\x40\x9f\xed\x9a\xed\x60\x56\xbd" + "\x99\x8c\x2a\x53\xd1\x6a\xca\x70" + "\xea\x71\xc3\x95\xfb\x8b\x97\xc4" + "\x9d\x10\x03\x70\x0d\x4d\x46\xe5" + "\xef\x35\xe5\xd9\xdf\x2f\xf3\x1a" + "\x5b\x18\xc9\x98\xa7\x7e\xf5\xab" + "\x88\x24\xb4\x12\x17\x74\x7a\xed" + "\xfa\x86\x72\xe9\xa7\x96\x02\x8e" +
+       "\x5f\x44\x1b\x17\x83\x93\x07\x01" + "\x4c\xad\x31\x81\xe3\x21\xcf\x9b" + "\xe8\x87\x39\xc9\x05\xe2\xdf\x8c" + "\x8f\x8c\x2e\xc9\x52\x41\x3f\xe6" + "\x3d\xd4\xad\x30\xa9\x62\x94\x72" + "\x5a\xf0\x80\xc9\x43\xb1\xeb\x62" + "\x68\xe9\x06\x3b\xe5\x54\x39\x4f" + "\xb1\xf6\x2c\x24\xad\x75\x1d\xfe" +
+       "\x5e\x7d\x01\x1f\x6e\x41\x57\x8b" + "\x9b\xe9\x74\x76\x96\x33\x53\x37" + "\xa0\x88\xf4\xe8\xc0\x94\x6d\x6e" + "\x5e\xf9\x16\xdc\x7a\x78\x3a\xb9" + "\xcc\x9c\xc9\xdc\xa2\x51\xac\xc3" + "\x1d\x7c\xa4\x9a\x13\xb4\x34\xc1" + "\xd5\xd8\xdf\xaf\xaf\xcd\x8f\xf2" + "\xed\x31\xb8\x10\x8e\xbd\x57\x0d" +
+       "\x46\xfc\xbc\xf0\xcc\xfb\x76\x92" + "\xe6\xfe\xcf\xb5\xce\x2a\x82\x3a" + "\x5b\x91\x5d\xc7\xfe\xd2\x8e\x32" + "\x6c\x47\x59\xc3\x13\xc1\x45\xa1" + "\xcd\x7b\xe1\x8b\x53\x81\x1a\xf6" + "\x8f\x3d\x6c\xaa\xc3\x67\xe8\x01" + "\x2f\xc8\x16\x65\x5d\xe1\x34\x56" + "\xb0\xb9\x48\x69\xd2\x7b\x43\xc1" +
+       "\xc7\xd4\x19\x6c\x00\xd2\xfc\xd2" + "\x76\xe9\xb1\xe1\x37\xc4\xf3\xa0" + "\xe8\x37\xf2\x94\xf6\x5f\x54\xf0" + "\xb1\x8b\xbf\xc0\x3f\xec\x10\xdd" + "\xe1\xd3\x7c\xac\x6c\x69\x89\x4f" + "\xe6\xbf\x24\x5f\xec\x14\x37\xed" + "\x06\x77\xaf\x5f\xd8\xb1\x3e\x36" + "\x32\xcc\x27\xc0\x4d\x60\xbd\xfc" +
+       "\xc8\x85\x86\xaf\xc7\xc6\x95\x5f" + "\xaa\x01\x8f\x2f\xce\xc8\xc1\xd4" + "\x2a\x69\x74\x25\x32\xbe\x4b\xc4" + "\x68\xa0\xa4\xd4\x78\x34\x00\xb8" + "\xdb\x3c\xca\x2e\xe5\xc6\x8f\x7c" + "\x99\xd3\x04\xec\x6b\xb1\x1d\xea" + "\xcf\xc5\x2b\x8f\x2e\xc8\x5b\xb0" + "\xd2\x93\x47\xf4\x7f\x51\x3d\x76" +
+       "\x3b\x36\x55\xc3\xdd\x8e\xce\x16" + "\x6e\x0d\x82\xf8\x0f\xf7\xf2\x4a" + "\x08\xa5\x61\x76\xd2\xd4\x7e\xcb" + "\x72\x54\x19\xdd\x4e\x44\xd3\x41" + "\x49\x96\xda\x38\xb4\xa2\xfe\x17" + "\x00\xa2\xb4\xae\x56\x93\xf6\x9b" + "\x3d\x9c\xb1\x6a\x91\x5f\x3b\xa1" + "\xa6\x60\x93\xdc\x14\x9c\x51\xc0" +
+       "\x71\xe1\x42\x2e\xe9\x1a\x57\xc2" + "\xf9\xcc\x41\xed\x63\xab\x31\xcb" + "\x4f\x85\xc8\xb5\x76\xc5\xf3\x37" + "\xa1\x92\x23\xc6\x1b\x19\xe5\x66" + "\x3b\x68\xd5\x6c\x1c\x5a\x56\x71" + "\x89\xe6\x6f\x60\x83\x02\x4b\x48" + "\xa6\xfd\xe2\x67\x67\x5d\xa2\xf3" + "\xa4\xc0\x65\x8a\xde\x21\xba\x87" +
+       "\xd1\x84\x06\xa7\x9c\xe4\x74\xde" + "\x3d\x0c\xe8\x33\x61\x76\xe8\x3a" + "\x4d\xc3\xa5\x16\xa9\xa2\x84\x59" + "\x35\x8c\x29\xb8\xcc\x3e\xa8\x09" + "\xc0\xa4\x4c\xaa\x7c\x86\x19\x9a" + "\xff\xb8\x75\xb3\x10\x56\x08\x02" + "\xdc\x96\x03\xf7\x8b\x32\x96\xf2" + "\x63\xae\x6f\xde\x4c\xdc\x9d\x9c" +
+       "\xd0\x98\xbd\x08\xb8\xc1\x51\x44" + "\x40\xf2\x75\x65\xd4\x1c\x4b\x64" + "\x70\xd2\x75\x73\x33\xeb\x07\x69" + "\xbd\x86\x22\xfa\xbd\xbe\xc8\x56" + "\x46\x2b\x63\xc4\xac\xd2\x13\xc7" + "\x42\x02\xd6\xaf\x7a\x42\xda\x17" + "\x46\x75\x5c\xc9\xb7\x65\x30\x31" + "\xde\xa3\x17\xbf\x98\x98\x23\xf8" +
+       "\x6e\x3b\x08\x0b\x26\x3d\x68\x94" + "\x4d\xa5\xf6\x06\xeb\x52\x37\x0a" + "\xdd\x74\x20\x75\x23\xdc\xbe\x48" + "\x93\x25\x82\x3e\xfc\x22\x76\x63" + "\x3b\x5d\xe5\x6b\x13\x05\x00\xea" + "\x6d\x00\x4d\x32\xf4\x12\x5e\x9f" + "\x70\x02\xfc\x64\xa9\x86\x94\x52" + "\xe6\x99\x33\x92\x0c\x0d\xba\x09" +
+       "\x80\x70\x97\x3a\x47\x58\x38\x36" + "\xb6\x6a\x6a\x0c\xb8\xe1\xf8\x4c" + "\x1e\x26\x82\x04\x6c\x5c\x9a\x91" + "\x06\x48\xce\xe5\xd0\x9a\x7a\x51" + "\xaa\xa7\x6a\x05\x0c\xd4\x92\x27" + "\xb0\x61\x6c\xe5\xda\x6a\x7c\x4c" + "\x0c\x9e\xb1\xa4\x78\xb1\x9c\xf1" + "\x7f\x26\xba\xe4\x4f\x5c\x6d\x04" +
+       "\xb3\x50\x15\x12\xab\x26\xe9\xd3" + "\x84\xce\x47\xc1\x4a\x5e\x97\xe4" + "\x2a\x72\xff\x5e\xf9\xe0\x8b\x7a" + "\xa0\xf2\xd4\x6f\x2c\x70\xe4\x71" + "\x80\xb2\xb7\x3c\xcf\x2a\xb9\x13" + "\x73\x2d\x27\x28\x6d\x71\x88\xc5" + "\x5c\xfe\xa9\xda\xf3\x7b\x2c\x86" + "\x42\x9e\xa7\xe2\xf2\x08\xc0\x78" +
+       "\x20\x03\x83\x4c\x3f\x96\xb7\xf3" + "\xe3\x03\x32\x90\xa0\x7a\x2c\x84" + "\xfb\x7a\x32\xe7\x0a\xca\x22\xaf" + "\xb6\x09\x76\x96\x92\x30\xe1\x38" + "\xf1\x58\x75\x75\x62\xfb\xb8\x73" + "\xc1\xa8\xec\xf7\x31\xe8\xc3\x3c" + "\x27\x16\x33\xf6\x74\x44\x17\xe4" + "\x34\x02\xc4\xc3\xca\x89\x79\xa7" +
+       "\x1f\xfa\x36\xf5\xc5\x32\x58\xed" + "\xa4\x44\x82\x92\x55\x3f\x6f\xe1" + "\x90\xe1\x5b\xbf\x21\x26\x3a\xf4" + "\x2b\x6b\x2b\xca\xc3\x72\xd6\xf7" + "\x83\x5b\x7a\x82\x45\x62\xf8\x64" + "\x72\x7f\xe9\x00\xf5\x09\xa1\xc1" + "\xbb\x27\x73\xa4\x5c\x78\x59\xc2" + "\xb6\x62\x6a\x7f\xe9\x09\xf1\xda" +
+       "\x20\x51\x56\x57\x18\xdf\xab\x88" + "\xf1\x2b\x5f\xf2\x72\xbc\x34\xbf" + "\x40\xea\x83\x62\x22\x6a\x21\x0c" + "\xe4\x18\x2e\x07\x46\x20\x3d\x57" + "\x36\x81\xbe\x11\x6a\x0f\x11\x11" + "\x1b\x86\xe4\xd6\x84\x2a\xf3\x10" + "\x31\x75\x29\xee\xe2\xde\xed\x3e" + "\x69\x42\x40\xd3\x99\x7f\xf3\xb3" +
+       "\x3a\xd4\xc1\x1c\xe9\xf5\xa3\xce" + "\xf4\x3a\x23\x6a\xdb\xca\x4a\x62" + "\xc2\xe7\xef\xd0\xa9\x18\xdf\xc9" + "\xf3\x79\xba\x79\xe8\x0b\x0d\xfe" + "\xea\xf5\x2f\x52\x56\x5a\x4c\xc7" + "\x4e\x51\x7d\x6c\xf0\x79\xc3\x4a" + "\x9f\xa2\x0e\xd7\x04\x14\x92\x64" + "\x70\xf2\x69\x02\x91\xe5\x3e\x44" +
+       "\xe0\x81\xa0\x44\xa1\x17\xfd\xe5" + "\x6a\x29\x0e\xb7\x7d\xfb\x97\xd7" + "\x9c\x71\x1f\x48\x30\x2b\x47\x2b" + "\x52\x8c\x6f\xfe\x98\x2a\x63\x0e" + "\x84\xc2\xf0\xc5\x16\xd1\xcc\x89" + "\x62\x7c\x98\x2d\xaf\x88\x10\xf5" + "\xcf\xe6\x2d\x4c\xda\xcc\x2b\x2a" + "\xf9\xf0\x79\xf6\xfe\x9e\x0f\x81" +
+       "\x39\xa5\x1e\xa6\x43\xf4\x74\x38" + "\xdf\xfe\x06\xc2\x11\xa3\xa3\x90" + "\x85\x87\xbd\x0f\x5b\x7b\x2a\x96" + "\x8b\x1c\xc3\x58\x70\xe9\x37\xfc" + "\x48\x10\x1a\x5f\x38\x55\xeb\xcd" + "\x55\x62\xcd\x8c\x22\x51\x20\x5a" + "\x8b\x1b\x4f\x9c\x96\xd4\x62\x97" + "\xde\x05\x2f\xd5\x03\x88\x3d\x21" +
+       "\xf6\x73\x4c\xe5\x7b\x37\x64\x7c" + "\xc0\xfb\x4e\x5a\x04\xfe\xbf\x65" + "\x41\x85\xf5\x36\x63\x30\xd2\xd0" + "\xf0\xbd\xcd\x25\x6f\x06\xd6\x54" + "\x5b\x6d\xf8\x5c\x63\x2d\x5f\x68" + "\xe5\xf6\x2e\xf1\xc1\xe9\x51\x8e" + "\x82\x6d\x34\xcb\x2d\x04\xaf\xa6" + "\x6f\x81\x73\x00\x79\x50\x95\x37" +
+       "\xf4\xf7\xc5\x13\xa7\xd3\x9c\xc8" + "\xed\x2e\x35\xac\x4e\xb5\x9c\x0d" + "\x88\x47\xb3\x33\xee\x7a\x2e\x46" + "\x9a\x8d\x99\x7c\x43\xf1\x1a\x83" + "\x87\x4f\xe0\x11\xc9\x02\x88\xed" + "\x69\xd9\x38\x19\x0b\xa0\xa1\x1c" + "\x10\x93\xbb\x7b\xb4\x5b\x80\x52" + "\x10\x64\xc1\x31\xe4\xcd\xa3\xca" +
+       "\x3e\x4b\xfe\x7f\xb9\x94\xf3\xb0" + "\x21\x5d\xfa\xe5\x21\x1d\x69\x0b" + "\x75\xbc\xfb\x9d\x47\x77\xbd\xb0" + "\x00\x8b\xf7\xfa\xda\x0f\x83\xd2" + "\x57\x4f\x43\x52\x9c\x24\x8c\xf7" + "\xab\x6d\x09\x98\x45\x75\x1f\x4b" + "\xb3\xc0\xf8\x8f\x94\x6f\xbf\x73" + "\x4c\x13\x4e\x45\x3d\xf0\xae\x34" +
+       "\x59\xc0\x0b\x39\xd5\x56\xb8\x2e" + "\xdf\x12\x13\x04\x5f\xbd\xea\xc0" + "\x7b\xd6\x36\x86\xdf\x45\xef\x7e" + "\xb5\x7f\xea\xdf\x1f\xe8\x09\x69" + "\x37\x77\xda\x31\x53\x8c\x8e\x62" + "\xbc\x55\x5b\x75\xe3\x8b\x2f\x1b" + "\xd7\x41\x78\x13\x12\x05\xba\x35" + "\x7d\xe5\x7c\x31\x59\x03\x55\x59" +
+       "\xc9\x6d\xd1\xf5\x07\xd4\x51\xb2" + "\x1c\xcc\x72\x4c\xaf\xaa\x1f\x54" + "\xcc\x73\x81\xe5\xac\x70\x81\xd2" + "\x5a\x1b\x0c\x7b\xc5\x57\xc0\x1c" + "\x74\x23\x06\x21\xe6\x74\xb2\x04" + "\x79\x8c\xcb\xe2\xa7\xca\xac\xef" + "\x95\x94\xea\x24\xec\xc3\x66\xc4" + "\x15\x7c\xef\x67\xf3\x6e\x51\xc3" +
+       "\x1c\x5c\x57\x45\x3b\x00\xef\x34" + "\x0c\xfe\xc2\x49\xa0\xe7\xb3\xde" + "\x63\x9c\x14\xf7\x1d\xc0\x8e\x04" + "\x6c\x98\x9a\xc7\xb9\x69\x38\x20" + "\xef\x80\x1e\x6c\x83\x40\x7c\xcf" + "\x47\x44\x29\x8e\xd5\x17\x0e\x21" + "\x1c\x60\x12\x12\x2e\x7d\x50\x2b" + "\x79\xe2\x17\x5a\xfa\xd3\xed\x98" +
+       "\xc5\x7e\xac\xb7\xf4\x51\xd1\xf8" + "\xd5\xa7\x0d\xe5\x5a\xb9\xce\xd6" + "\xb8\x0e\x3a\xdc\xb0\x92\xb4\xa1" + "\x63\x28\xdd\xb3\x69\x7b\x15\x75" + "\x62\x3d\x41\xc5\x4e\xc7\xc4\xe2" + "\xc7\xc4\x5f\xbc\xf7\x9f\x32\xbe" + "\xda\x9d\xfa\x60\xea\x2a\x5a\x83" + "\x87\xcb\x45\x74\xad\xf5\x17\xf1" +
+       "\x1d\x69\x1d\xe9\x36\x26\xf4\x9b" + "\xe4\x7b\xc0\x8f\x42\x32\xcc\x0b" + "\x90\xaa\xe9\x69\xae\x5c\x20\x5b" + "\x5e\xf7\x9c\x39\x2b\x72\x69\x6f" + "\x35\x42\x42\x79\xf6\x59\xb0\x3d" + "\x63\x54\x20\xa2\x04\xb4\x98\x6b" + "\x51\xf4\x60\x6f\xe4\xf5\xca\x68" + "\x9e\x93\x08\xad\x66\xfc\xf1\xe8" +
+       "\x1f\xb2\x46\x63\xd4\x1b\x66\x36" + "\xf0\x9d\xb6\x3c\x1d\xb0\x6f\xde" + "\x0a\xb4\x84\xa8\xe4\xa0\x05\x7d" + "\xbf\x4a\x3d\xef\xd4\x69\x25\xd9" + "\xf8\x61\xb2\xe6\xe1\xd7\x2b\x1c" + "\xef\xdb\x4d\xc7\xe5\xb0\x03\x05" + "\x37\x4c\x9a\xe0\x39\x1a\x36\x6a" + "\x73\x84\xff\xe7\x08\x75\xd5\x7f" +
+       "\xf8\xed\x76\xc7\x67\xfd\x39\x19" + "\x8a\x84\x5c\xcb\x70\x7c\x84\xd0" + "\xd1\x03\xde\x5a\x91\x53\xf5\x4f" + "\x3e\x82\xa9\xcf\x83\x4d\xb5\x8f" + "\x04\x4e\x0d\xf1\x6e\x14\x08\xb3" + "\x36\x2a\xcb\xb6\xb3\x91\xa6\x14" + "\x7f\x65\x20\xc6\x93\x9b\x41\x2f" + "\x7f\xda\xe1\xd3\xa2\xaa\xb7\x4d" +
+       "\x7a\x6f\x16\xb0\xf4\x17\x83\xae" + "\xe6\x74\xec\xce\xf7\xe3\xd3\xfb" + "\xfd\x4b\x87\xe0\xac\x16\xb5\xfd" + "\xa3\xf3\x81\xc6\x19\x60\x84\x3d" + "\xb0\x20\x16\x7c\x5c\xee\x12\x0b" + "\x01\xc5\x63\x2b\xdd\xb4\x68\xba" + "\x1e\xc5\x68\x66\x32\xcd\x03\xac" + "\x5b\xcb\x0b\x4e\xf7\x79\x62\x2a" +
+
+       "\xa8\xcd\x5f\x8f\x9f\x13\x8e\xfd" + "\xfd\x5b\xee\xbd\xc4\x58\xe5\xf3" + "\x77\x9f\x3f\xe3\xf4\xba\x6c\xd7" + "\x69\x19\x77\x71\xa4\x97\x4c\x3a" + "\xa7\xe6\xdc\xf6\x4b\xe8\x27\xda" + "\xd1\xc2\xe6\x13\x96\x3d\x37\xff" + "\xe9\xa6\x59\xd7\x3c\x19\x15\xf1" + "\x2c\x26\xd2\x63\x25\x70\x9b\x3f" +
+       "\xc8\x5c\x33\x1a\x91\x84\x31\x8c" + "\xe4\x13\x59\x6a\xba\x59\x34\x56" + "\x19\x29\xb3\xc7\x61\x0d\x92\x1b" + "\xad\x25\x24\xa0\xb6\xb8\x5a\x80" + "\x86\x60\x00\x8d\xda\x12\xc5\x2a" + "\xfd\xc0\xf5\xbc\x6a\x84\xa4\x6c" + "\xd7\x38\x21\xac\xd8\x51\xea\xaf" + "\x43\xd4\x4c\x34\x45\x75\x64\xcb" +
+       "\x85\xca\xed\xcd\x66\x24\x1b\x9f" + "\x8c\x53\x09\x1a\x10\xb7\x0b\x14" + "\x5d\x11\x11\x5e\x51\xe8\x8a\xac" + "\x9e\xf5\x03\x6f\x67\xff\x63\x0d" + "\xfb\x4a\x23\x7d\x51\x55\x5e\x75" + "\xc1\x8f\x20\x7e\x4e\xdb\xc2\x61" + "\x5d\x4b\x8a\xf2\xce\x59\x98\xaa" + "\x0f\x03\xaf\x34\xfc\xd4\xd6\xbd" +
+       "\x74\x47\x54\x53\xe4\x53\x10\x51" + "\xbc\xa2\xdb\x3a\xcc\x0e\x4d\x83" + "\xf5\x71\xe3\xba\xf7\xd7\x15\x42" + "\xbc\x63\x86\x6c\xbf\x57\xfd\xfc" + "\x1d\x1b\x90\xd6\x3d\x38\xd2\xde" + "\xc3\x7d\x58\xb5\xb4\xfb\x49\x3b" + "\x62\x5f\x62\x07\x8d\xa0\x44\xfd" + "\x62\xb7\xe9\x9d\x5b\xd6\xe4\x3e" +
+       "\xde\x15\x78\x71\x6e\x4b\x99\x5a" + "\xd1\x31\xe1\xa7\xa0\xc7\x95\xd9" + "\xaa\x23\xc0\x26\xf2\x6d\xb4\xc8" + "\xed\xfc\x2a\x70\x4d\x09\xfd\x8c" + "\x86\xa8\xd6\xce\xcd\x43\xc7\x7b" + "\x75\xbe\xca\x1f\xc4\x0e\xd7\xb7" + "\x90\x93\xac\xdd\x47\x9e\x6c\x2a" + "\x90\xaa\x10\x93\x25\x94\x06\x72" +
+       "\xeb\xd0\x64\x54\xf5\x80\x7e\xd1" + "\xa7\x13\xa6\x67\xa7\xe1\xd3\x89" + "\xad\x7d\xc9\xc8\x60\x12\x79\x77" + "\xe7\xcb\xf0\xe4\x1f\xf2\x2f\xec" + "\x10\xbc\xe6\xe9\xc2\x4a\x98\xed" + "\x05\xa3\xcb\x77\xe8\x3d\xc5\xe3" + "\xdc\x4f\x62\x83\xb2\xf9\xba\x9b" + "\xec\xc0\x85\x14\xcd\x51\x94\x5e" +
+       "\xc8\x1e\x76\xb1\x6d\x75\x13\x1f" + "\x55\x7e\xb9\xa4\x98\x8b\x3c\xe5" + "\x28\xcc\x96\x40\xf8\xe3\xae\xb2" + "\x8d\x1a\x0f\x92\xa0\x61\xc3\x48" + "\x0a\x19\x31\x8c\x2d\x67\x8b\xa9" + "\xd4\x55\x18\x00\xd1\xe7\xc1\x7b" + "\x2a\x4b\x3f\xbf\x07\xfb\x2c\x24" + "\xc4\x8b\xa2\x32\x3f\x4a\xf4\x9b" +
+       "\xfa\xd1\x63\x0d\x7d\x13\xe5\x64" + "\x9f\xd8\xa9\x02\x52\xc0\x8f\x65" + "\x09\x63\x43\x50\x74\x48\x89\x48" + "\x61\xda\x98\xd5\xf8\x30\xae\xe9" + "\x91\xaf\x8b\x81\xd1\x10\xd7\x2e" + "\x20\x0c\x6a\x8b\x06\x9e\x7e\xe2" + "\x44\x6b\x1a\x1c\xfb\xdc\x28\x1e" + "\xdc\x57\xac\xd6\x64\xcb\x3a\x88" +
+       "\xa5\x76\xe1\x42\xac\xe2\x82\x99" + "\x64\x2b\x78\xe2\x46\xba\x4e\x32" + "\xf5\x50\x83\xe1\xaf\xaa\x8c\x3d" + "\xca\x74\xd6\xf5\xf2\x2a\xd8\xf3" + "\x1e\x0d\x60\x56\xed\x0f\x09\xc2" + "\x07\xde\x50\x59\xef\xe0\x48\x45" + "\xeb\x4f\x5a\x76\x3f\x02\xf0\xb2" + "\x90\x67\xf1\x39\x33\x10\x03\xb3" +
+       "\xb3\xc8\xa3\x61\x1d\x78\x92\xa6" + "\x0e\x6d\x87\x32\x54\x38\xbc\x08" + "\x03\x7b\x02\x28\xfb\x05\xcf\xbe" + "\x2f\xe1\xb1\xa4\x7d\x68\x6c\x63" + "\x58\x7c\x21\x07\x3d\x00\xe3\x00" + "\xa3\xb2\x01\x5e\x37\xa9\x3b\x61" + "\x6e\xe1\x1d\x88\x05\x84\x8c\xa5" + "\x8b\xf4\xf8\x14\x30\xc4\x53\xc6" +
+       "\xf9\xd0\xa0\xd6\x97\x68\x1c\xbc" + "\x55\x7f\x0d\x3b\x0e\xea\xe0\xd8" + "\xad\x7a\x5b\xb8\x92\xaa\x5b\xb3" + "\xf4\x48\x4e\x67\xb7\xd1\xec\x2b" + "\xc2\x9a\x7a\x6d\x8d\xf7\xd7\xe2" + "\xd0\x95\x9c\xf9\x62\x42\x07\xf5" + "\xe9\x11\xf6\x89\x0a\x47\x52\x48" + "\xec\x9d\x86\x92\x19\x91\xaa\xf7" +
+       "\xe2\xaa\x6d\x4e\x77\x2e\x7f\xed" + "\xbc\x19\x0a\x9e\xe3\xe0\x3a\x7b" + "\x7e\x67\xae\x91\x8a\x3f\x29\xd3" + "\x1f\x61\xc8\x45\xcb\xb0\x63\xd3" + "\x3b\xe9\x9a\x30\xcf\x1c\x1d\xbe" + "\xe1\xca\x20\x39\xe7\x0b\xf8\xa3" + "\x01\xdf\x8e\x49\x74\xba\xac\xaa" + "\x90\xac\xf5\xb2\x4a\x2a\x6d\x1e" +
+       "\xf1\x50\x35\x23\x3f\xf0\xc5\x60" + "\x2e\xfd\x5a\x92\x11\x94\xd0\xd4" + "\xa6\xe5\x58\xd2\xc3\x65\x5b\xa9" + "\x6a\x2c\x90\x9f\xb5\xcf\x19\x1a" + "\x68\x5c\xad\xf5\x3a\x01\x86\xb4" + "\xf3\x38\x96\x97\x76\x67\x50\xa2" + "\x28\x0b\x8e\xa3\xd0\xb4\x32\x12" + "\x4f\x7b\x6a\xd3\xb8\x84\x47\xa6" +
+       "\x96\xa6\x66\x02\x9e\xa1\xcf\x7f" + "\x4b\xfb\xc3\x92\xfd\x64\x1f\x5e" + "\xdf\x19\x6d\x50\x11\x49\x95\x6d" + "\xa1\x3c\x7a\x69\xe1\x9f\x98\x9f" + "\x7d\xa8\x27\x23\x8c\x8d\x48\x7e" + "\x17\xa3\x7d\x03\x28\xce\x43\xa5" + "\x18\x55\x3c\xf9\x76\x1d\x07\xea" + "\x3b\x6d\x0a\x22\x48\xfd\x5f\x58" +
+       "\x03\x0e\xd7\xe7\x9d\x17\x55\x56" + "\x70\x45\xa8\x72\x5c\x0c\x78\x3e" + "\x9c\x02\x50\x1d\xcb\xb4\x02\xc1" + "\x39\xe8\x75\xf0\xd5\xbd\x71\x3e" + "\x22\xb8\x98\xb4\xf0\xf4\x60\x64" + "\xa5\x8d\x4b\x6d\x6c\xe0\x82\x26" + "\xd4\x40\xa7\x96\xc9\x53\xae\x4e" + "\x2c\x70\x89\x63\xef\x8b\x9d\xc1" +
+       "\x70\xff\xc6\xc2\x8d\x72\x35\x87" + "\x35\x22\xdc\xc5\x2f\x12\xd6\x79" + "\xf9\x77\xe2\x19\x03\xd0\xf5\x23" + "\xc7\x8c\xed\xdd\x25\x4e\xe8\x7e" + "\x0a\x88\xcd\x63\xb0\xaf\xa8\x91" + "\x60\xaf\x74\x35\xc6\xa7\x3e\x3f" + "\x42\x7f\xde\x02\x84\xdc\xfc\x0c" + "\x52\xa1\x1a\xb3\x2f\x79\xd0\x62" +
+       "\x55\x16\x3b\xee\xb2\x47\x9a\x95" + "\x5b\x3d\x88\xec\xdd\xb9\x99\xc7" + "\x04\x38\x93\xb7\x80\x9f\xc0\x2d" + "\xb8\x3d\x2d\x3d\x88\xe8\x69\xae" + "\xf4\x0a\xe7\x25\x2f\x5e\x5d\xc1" + "\x85\x00\x04\x05\xce\xd9\x5f\x87" + "\xf2\x38\x5a\x6b\xd0\xe8\x50\x28" + "\xda\xb0\xbe\x9a\x35\x7f\x22\x15" +
+       "\xf2\x23\xe5\xe0\x37\x10\x0f\x65" + "\x3b\x01\x83\x95\x43\xab\x38\x44" + "\x5e\x90\xc0\xef\xfb\x68\x42\x03" + "\x6b\x77\x06\x0c\xa2\x4b\x28\x7b" + "\x33\x11\x6c\x1b\xc4\x49\xb9\x02" + "\x4f\xef\x4b\x19\x47\x8d\x3b\x7c" + "\x35\x05\x7e\x0e\x00\x5b\xe1\x5f" + "\xb4\x26\xb1\x28\x74\x66\x26\xc3" +
+       "\x44\x11\x92\xe0\x42\x93\xb9\xf8" + "\x2c\x3e\x03\xb5\xf1\xc6\x4f\xf1" + "\x54\xcf\xda\xdc\x60\x37\xfb\x7d" + "\xa5\x7b\x8d\xd8\x31\x0a\x5a\xd2" + "\x77\x49\xf7\x68\xcb\x2f\xed\x4d" + "\x07\x40\x76\x9a\x65\x47\x88\xf1" + "\xc7\xf4\xdc\xf2\x69\xb1\x9d\x87" + "\x6a\xf9\x6d\xd1\xd5\x75\x4d\x74" +
+       "\xb5\xef\xcc\xbe\xaa\xf5\xfd\x40" + "\xc7\xd7\x21\x36\xe9\xed\x56\xcf" + "\xc1\x76\xb5\x52\xce\xa9\x32\xb6" + "\x27\x60\x6f\x9a\xe8\x3a\x40\xd3" + "\x64\x5a\x78\xe8\x0d\x05\x0a\x66" + "\x2e\x65\x82\x96\x47\xd6\xf3\x10" + "\x02\xbe\xbc\x4f\xdf\x5e\xb2\x78" + "\x5d\x31\xf9\xb4\xde\x0f\x71\xc9" +
+       "\xf9\x35\x02\x1e\x9a\x00\x88\x0f" + "\xa1\xb8\x20\x48\x27\x40\xed\x2f" + "\x40\x11\x08\x86\xac\xb7\x72\xbe" + "\xe3\x63\x11\x60\x72\x26\x16\xd4" + "\xea\x71\x0c\x75\xad\xa3\x1e\xf7" + "\xe3\x8b\xdc\xaf\x40\x71\x34\x02" + "\x6b\xa6\x5a\xc6\x29\x6f\xe6\xa5" + "\xc8\x8f\x39\x07\x64\xec\xc7\xf3" +
+       "\xa2\x38\x99\x17\x63\x67\x09\x14" + "\x77\xb8\x1c\x1c\x71\x0e\xba\x4f" + "\xcf\x7c\xcf\x7c\x2f\x2a\x6f\xda" + "\x65\xde\x1b\x09\x4e\x1a\x24\x91" + "\xd8\xfc\x71\x1e\xc3\x56\x28\xcc" + "\xc3\x1c\x44\x12\x7c\x7e\xb8\xc0" + "\xaa\x24\xf2\xe5\x1e\x68\xd1\x3d" + "\xea\x08\x73\xad\xf6\xd6\xae\x30" +
+       "\x22\x3e\xb5\x28\x17\xb0\xb8\xd4" + "\x71\x7c\x7b\x0f\x48\xd9\x94\xe3" + "\xdf\xaf\x1c\xb2\x68\x23\x1f\xe2" + "\x33\x78\xcc\x86\xb6\xfa\x11\xc9" + "\xd7\xcc\xd1\x39\xfd\xf6\x61\x0f" + "\xa9\x90\x8d\x24\x8b\xeb\x16\xe2" + "\x0d\xd2\x22\xfc\x44\x8f\x05\xa5" + "\x28\x96\xc6\x57\x92\x96\x26\x91" +
+       "\xce\x07\x58\x8a\x43\x4e\x1b\x8e" + "\x7e\x9a\x10\xe4\x93\x38\x28\xad" + "\xda\x9d\xd5\xaf\xcb\xc9\x0c\xc3" + "\x93\x80\x8d\x3d\xc6\x36\x5f\xf6" + "\xb2\x32\x0d\xa6\x9e\x46\x31\xdf" + "\xc8\x91\x81\x3e\x4b\xdf\x93\xee" + "\xb5\xde\x5b\x35\xc5\x17\x10\x9c" + "\x28\xaa\x16\x86\x85\x31\x62\xd2" +
+       "\x10\xed\x48\xa4\x64\x4f\xed\x38" + "\x8b\xb7\xef\xc4\xa8\x03\xeb\x81" + "\x52\x3b\x32\x91\x5c\x1b\xd9\xbf" + "\x2e\xff\xbe\xb6\x33\x2b\x88\xed" + "\xa1\xd7\x22\x67\x51\x45\xfb\xd0" + "\xab\xe8\x9f\x94\x1b\x44\x91\x6f" + "\xa6\x81\xc1\x3a\x99\x4a\xa4\x63" + "\x74\x6b\x0b\x95\x5f\x2b\xa6\xf4" +
+       "\xcf\xa2\x01\xe8\x46\x44\x61\x22" + "\xdf\x8c\x47\x2e\x27\x20\x3a\xfa" + "\xb3\x50\xc6\x98\x9a\x0c\x2a\x10" + "\x70\xff\x73\x48\x98\x93\x00\xc5" + "\x01\x6d\xa1\xfa\x06\x86\xec\x87" + "\x8b\x4d\xdd\x9e\x94\x27\xc1\x0f" + "\x60\xd4\x6b\x6f\x00\x7a\xa9\xe7" + "\x59\xff\xbe\x5e\x30\xd1\x9c\xf6" +
+       "\x28\xa2\xb5\x62\x86\xd1\x09\x62" + "\x26\x8b\x40\xd4\xaa\x7d\x5d\xb8" + "\x00\xb3\xb1\x8e\x0f\x11\x48\x7e" + "\xab\xaa\x64\x04\xd2\x3c\x78\x66" + "\x61\xa0\x8b\x0f\x25\x8b\xf6\x2d" + "\xeb\x8a\xa0\xb2\x61\xc4\xe0\x97" + "\x38\x0d\x64\xbd\x0e\x6f\x8f\x6f" + "\xa6\x5d\x47\x41\xe1\x22\x33\x99" +
+       "\x0e\x98\x45\x32\xe7\xad\x55\xd6" + "\x00\x72\x06\x81\x57\x96\xf5\xa6" + "\xe1\x6b\x13\xdb\xbe\x23\xfc\xe4" + "\x79\xd8\x13\xaf\xdc\x6c\x24\x9f" + "\x0e\xac\x61\xf9\x17\x31\xb9\xc2" + "\x1a\x9e\xdb\xeb\xb5\x41\xa7\xc8" + "\xd1\x3b\x69\x6c\x46\xe2\xed\x82" + "\x1e\x70\xd1\x3d\x4f\x6b\xde\xfc" +
+       "\x6f\x64\xa4\xca\x00\x4e\x80\x1f" + "\x24\x49\x94\x70\x88\xdc\x43\x86" + "\xe9\x6d\xf8\x73\xa2\x1c\x7f\xa3" + "\x98\x98\x88\x28\x92\x9f\x19\xa3" + "\xdf\x4a\x1e\x0c\x58\xba\x73\xc2" + "\xf0\x82\xbc\x65\xaf\x38\x0d\x0f" + "\x3b\xcd\xa6\xf8\xb5\x8a\xb2\xd8" + "\x8e\x4d\x89\x75\x85\xe0\xa6\xee" +
+       "\x15\x32\xc9\x0e\x98\xb9\x42\x46" + "\x9f\x34\x9d\x29\x0a\x17\x19\xb7" + "\xba\xb5\x36\xbc\x2b\x16\x2c\xb3" + "\xa2\x3c\xd2\x4b\x85\x73\x35\x06" + "\x15\x81\xf6\xdf\x92\x62\x41\xff" + "\x99\xdb\xb5\x4b\xe3\x50\xa1\xb7" + "\x55\x3d\xc1\xa3\x28\x20\x7a\xb9" + "\x06\x45\x42\xe5\xc1\x06\xf4\x86" +
+       "\xcf\x95\xcd\xb9\xb9\xc1\xb0\xfa" + "\x73\xae\xa9\x11\xb3\xab\x85\x36" + "\xa3\xa9\x96\xa9\xaf\x3e\x97\x02" + "\x1d\x57\x34\x29\xaf\x9b\x6f\xff" + "\xe8\x40\x7c\x25\x21\x81\xab\xe4" + "\xb1\x30\x2d\xd9\xe4\x28\xad\x09" + "\x82\xb5\xe4\x09\x35\xa0\x51\x7c" + "\x0f\x12\x5b\xc3\xf8\x01\xbb\x60" +
+       "\x21\x1a\xc3\xde\xf9\x83\x2c\xb0" + "\x73\xd5\xd9\x6a\x23\x8b\x8c\x98" + "\x65\xe3\x7b\xa5\xae\x83\xe9\x53" + "\x4e\x83\x6f\x64\x4d\x73\x68\xe9" + "\x9b\x30\xa6\x5d\x8f\xea\x37\x91" + "\x16\xce\xf1\xc1\x24\xa6\xf3\x10" + "\x21\x09\x44\xca\xa2\x9e\x2a\x78" + "\xb5\xf1\x46\x5b\x9e\x73\x94\xdf" +
+
+       "\x6a\xb1\xf8\xf4\x0e\x41\xf8\x56" + "\x6a\x26\x7b\xc4\xfe\x1a\x24\x97" + "\xc1\x87\x9c\x6d\x8e\x6b\x40\x0a" + "\x1b\xab\x42\xcd\x02\x3e\x3f\x80" + "\x69\xec\xdb\x04\xa8\x09\x03\x7f" + "\x5f\xd0\xba\x3b\xf7\x85\x3b\xa8" + "\x7f\x19\x8e\xad\x73\x72\x09\xc6" + "\xc1\xad\x67\x50\x0e\x44\x97\xc0" +
+       "\x8c\x89\x11\xb3\xa0\x7f\x74\x3f" + "\x65\xac\x0e\xcd\xe4\x72\xa2\xe2" + "\xbc\xd0\x14\xf9\x51\x58\xba\x4b" + "\xe3\x3e\xa4\xc4\x60\x96\x1a\x7a" + "\xe9\xcd\xc8\xa1\xce\x67\xa3\xe5" + "\xe3\xab\x71\x72\xa9\x8b\x95\x9d" + "\xcd\x15\x16\x3d\xb6\x7e\xff\xf3" + "\xb0\x20\xae\xf5\xce\x0d\x28\xa2" +
+       "\xdc\xf8\x94\x37\xa4\x44\x63\x26" + "\x36\x5c\x3c\x48\x3a\x92\xca\xdc" + "\xa0\x10\x9d\x3f\xbf\x6b\x6b\x2d" + "\xf3\xbd\xd9\x81\xca\xc5\x20\xb3" + "\x95\x0a\xb5\x47\xff\x28\x0e\x62" + "\x71\x33\xf0\xce\x01\x3b\x3e\x93" + "\x53\x01\x10\x99\x85\xbf\x81\xf0" + "\xd6\xc8\xa8\xc3\xa0\xe9\x3b\x18" +
+       "\x66\xa5\xdc\x41\xc3\x85\xc1\xb6" + "\xa3\x2a\x62\xd8\xda\xfe\xe7\x7d" + "\xfb\x6d\x1b\x90\x92\x4d\xe8\x99" + "\x88\xd2\x4a\x7c\x0e\x2b\xa0\x30" + "\x36\xcf\xd3\x2f\xaa\x1d\xc8\xc7" + "\x9f\xe5\x89\xdf\x47\x95\x31\xd1" + "\x33\x67\x49\xcd\x84\x81\xbe\xb2" + "\x2b\x41\xd3\x93\xeb\x49\xf4\xd5" +
+       "\x6b\x11\x85\xe0\xab\x0f\x47\x25" + "\x10\x53\x28\x87\x75\x33\xa4\x04" + "\x2f\xd5\xbf\xe2\x7e\x18\x39\x4e" + "\x74\xbc\x9e\x7d\x44\x6b\x16\x36" + "\x2c\x32\x4b\xfd\x3c\x43\xad\x92" + "\x51\xab\x79\xba\x17\xa8\x6a\x72" + "\xeb\x15\xdb\xc1\xd8\xac\x6e\xf9" + "\x63\xbe\x76\x04\x91\x1e\xf7\xfa" +
+       "\x16\x65\x7e\xc9\xda\x9b\x4e\xd7" + "\x9e\xf4\x30\xc2\x60\x93\x77\x88" + "\x49\xea\x74\x1e\xe3\x1d\xec\xa6" + "\xa2\x45\xb6\x3f\xe5\xce\x1d\x58" + "\x14\x3f\x48\x8f\x91\x23\xef\xba" + "\x3b\xd1\x37\xd1\xfc\xdd\x2d\x6d" + "\x42\x3a\x74\xd2\x0e\xe5\xcd\x54" + "\x67\x7e\xd9\xe4\xc5\x4f\xa3\x89" +
+       "\x68\xe1\xde\x49\xe9\xd2\xcf\x72" + "\x39\xf2\x2a\x3e\x23\x52\xe0\x1a" + "\x6a\x06\x94\x1d\xbe\x75\x9e\x00" + "\x13\xf4\xab\x38\xc7\x31\xca\x6c" + "\x08\x99\xc4\x9b\x1d\xd6\x0b\xb5" + "\x1e\xbc\xe2\xf5\x8c\x4a\x9b\x4a" + "\xac\x83\x6f\x94\xf7\xc5\x6c\xeb" + "\x28\xab\xff\xeb\xfc\x93\xda\x27" +
+       "\x4c\xf6\xd8\x4c\x64\xec\x92\xc4" + "\x51\x7b\x9d\x27\x90\xd7\xa2\x58" + "\x56\x52\xc7\x1f\xc5\x1f\xed\x0c" + "\x17\x30\x43\x8f\xed\x8a\x65\x3e" + "\xeb\x59\xda\x05\x2e\x94\x61\x0b" + "\x22\x37\xdc\x0d\xa3\x60\x3d\xba" + "\x87\x7f\x2e\x74\xd1\x1c\x31\x7c" + "\x6e\x1b\xb0\xf6\xee\xff\x73\x64" +
+       "\x51\x7c\x25\x76\xef\x19\xe5\x3c" + "\xe7\x77\xd4\x18\xd3\x18\x58\x6f" + "\xc0\xed\x63\x79\x03\x2e\x02\xab" + "\xf3\xf5\xd1\x8b\x89\x3a\x40\xf0" + "\xca\x33\x60\x49\xa0\x8d\x3b\xe4" + "\x72\xdd\xcf\xa1\x0e\xe1\x94\x09" + "\xe2\xc0\x73\xba\x20\x6d\xec\xb1" + "\xd1\xfa\xbc\xb6\xec\xc9\x29\x03" +
+       "\x9d\xbd\x84\x2c\xa1\x42\xff\xf1" + "\x4a\x67\x0c\x39\xc4\x3e\x1f\x75" + "\xca\xe0\xe5\x01\xf7\x36\xbb\x27" + "\x92\x66\xaf\x5c\x51\xff\xdf\x65" + "\x3f\xbd\x7b\xcd\xc4\x79\xf5\x5d" + "\x05\x12\x59\x85\x97\xb2\x8f\xef" + "\x32\xc7\x7a\xe4\x03\x72\xed\x1d" + "\x1a\x33\x1c\xcd\x5c\xc4\x3d\xa9" +
+       "\xd4\xd2\x18\x33\x8e\x33\xec\xbd" + "\x63\xe9\x8d\xbe\xbb\xd7\x3d\x73" + "\xbd\x7e\xc4\xa2\xba\xc3\xbc\x61" + "\xde\xcb\xef\x35\x19\xad\x21\xa8" + "\x5c\xdd\x4c\x02\x8c\x66\xac\x91" + "\x49\xfa\xcd\xc1\xe4\x58\xa5\x7b" + "\xda\xb4\x8f\x90\xe0\x4c\x1d\x49" + "\xe8\xbd\x85\xf6\xf9\x69\xa8\x7b" +
+       "\x78\x1c\xf4\x81\xcb\x0b\x2a\x7b" + "\xe1\x40\xd2\x1f\x85\x2c\x52\x5c" + "\xf6\xe3\x5c\xdf\x68\x2e\x51\xce" + "\x13\xee\xd5\xb6\x52\xb9\xd4\xa7" + "\xaf\x7e\xad\x31\x8b\x0a\xdc\x8c" + "\x20\x5e\x91\x1b\x75\x86\x5e\x16" + "\xf4\x77\x64\x5d\x9b\x26\x8c\x8e" + "\x91\x1b\x42\x44\xde\x5a\x8d\xd2" +
+       "\xba\x64\xf4\x79\xc2\x5e\x1b\xed" + "\x26\x2e\xd7\x47\x2c\xe4\x65\x2d" + "\x26\xf9\x67\x9e\x74\xe5\x98\x81" + "\x44\x7e\x74\x34\x38\x67\x06\x41" + "\x47\x54\x7e\xe3\xc1\xac\x37\x46" + "\x22\x58\xe1\xf3\xec\xc9\xcb\x02" + "\x3c\xa8\x5a\x80\x8e\xe9\xa8\x58" + "\x00\xe8\x95\x55\x6e\xcd\xfa\x73" +
+       "\x18\x23\xa9\x32\xb3\xfd\x7c\x19" + "\xb6\x87\xac\x25\x41\xa8\xbe\x9e" + "\x7a\x0c\x51\xa3\xf7\x05\xd8\x4c" + "\x8e\x42\x6e\xe0\x9a\x99\xdf\x24" + "\x9c\x45\x71\x4d\xdc\xd5\x4d\xd5" + "\x3c\xa0\xb8\x20\x4f\x32\x84\x14" + "\x27\xb9\x74\x31\xd9\xf2\x24\x79" + "\x50\xde\x3a\xf9\xbf\xac\xb8\x42" +
+       "\x07\x05\x33\x38\x03\xf8\x8f\x46" + "\x3e\xa5\x37\x40\xdf\x4d\xf3\x06" + "\xa4\x93\x69\x8d\x40\x1a\xcd\x70" + "\x22\xc0\xe5\x43\x97\x15\x5a\xf8" + "\x7d\xa6\x25\xc1\xc2\xc9\x6f\x39" + "\xcb\xbf\x64\x10\xbf\xbe\xb7\x03" + "\xcb\x6d\x80\xa9\x92\x45\x44\x7c" + "\x54\xcd\x87\x44\x4b\x61\x02\x1b" +
+       "\x42\xc5\x2a\x69\x4f\x60\x03\x83" + "\xd3\x91\x7b\x22\xe1\xff\x79\xf0" + "\xbd\xf9\xaa\x15\x63\x3e\xf6\x19" + "\xfb\x44\xf3\xf1\x65\xe5\x9e\xf9" + "\x99\x91\x21\xd6\x1f\x66\x1d\x8a" + "\x1c\xe4\x8c\xd4\xc6\x3b\x88\x8c" + "\x04\xd9\x74\x3c\x8f\x11\x65\x10" + "\x1b\x8b\xaf\x0f\xee\x89\x38\x71" +
+       "\xb6\x1b\xe2\x0d\xf7\x60\x7b\xb4" + "\xca\x36\xd8\xdc\x4f\xae\xac\x64" + "\x63\xce\x44\xc7\x6d\xea\x75\x33" + "\x5b\x95\x47\xb0\x5f\x26\x64\xb7" + "\xc3\xc2\x41\x98\x4c\x5d\x8a\xc6" + "\x60\x4f\x45\xcf\xd7\x8f\xe9\x60" + "\x0c\xea\x6a\x75\xe2\xfb\x01\xc7" + "\x79\x1c\xb2\xaa\x5e\x88\xc8\x09" +
+       "\xcf\xbd\xd1\x91\xef\x59\x13\xca" + "\x86\x25\x59\xf3\x57\x21\x08\x6a" + "\x1c\x95\x51\x39\x94\xa5\xae\xd9" + "\x06\xe7\xb7\xa2\x24\xef\xab\x57" + "\xa2\xb1\x2e\x2e\x1e\x72\xa5\x3f" + "\x98\xce\x6a\x51\xac\xee\x68\x3c" + "\xdf\x82\x87\xc2\x47\x9d\xa7\xff" + "\x7b\x57\x16\x4e\x63\x9f\xd6\xbd" +
+       "\x6c\xd4\xd2\x69\x08\x81\xbb\x45" + "\x5a\x36\xc8\x68\x39\x8b\x7c\xe4" + "\xbd\x51\x75\x26\x63\x76\xb8\xf3" + "\x7a\x54\x67\x5b\x8f\x76\x90\x15" + "\xff\xd3\x2e\xfb\xb2\x1d\x1c\x37" + "\x40\x94\xa5\x17\x19\x69\x16\xe3" + "\x14\x2c\x24\xdf\x78\xd1\xc0\x03" + "\xc1\x2a\x86\xed\xce\x3f\xc9\x40" +
+       "\xaf\x84\xbb\xc5\x60\x79\x2b\x40" + "\x39\xa6\xc8\xbc\xdc\xc7\x29\xcf" + "\x6d\x7c\x8f\x47\xff\x9d\xf1\xfa" + "\x22\xbd\x37\x33\xe4\x6a\x30\x71" + "\x7a\x9b\x59\xbf\x05\x55\x7c\xef" + "\xa8\x91\x46\x9c\x9e\x15\x9e\xe0" + "\x19\xb1\xce\x74\x18\xe8\x03\xd4" + "\x8d\xa9\x11\x52\x02\xe7\x25\x53" +
+       "\xd6\x82\xc9\x2b\x69\xda\x86\x12" + "\xe3\xe7\xda\x7b\xf2\x80\x6d\x5f" + "\xfb\x64\xf0\xa6\x47\x56\x9c\x3d" + "\x40\x15\x4c\xd7\xa1\xe6\xc8\xfd" + "\x5a\x13\x8b\xd6\xc6\x48\xda\x97" + "\xff\xbf\x6d\xd6\x79\x79\x09\xc2" + "\x1d\x53\x20\xea\xb9\xad\x96\x02" + "\xf0\xc8\xb2\x4a\x0d\x73\x33\xa3" +
+       "\x33\x19\x25\x7a\x2b\x12\x97\xaf" + "\x45\x33\x23\xc1\x9c\x34\xc7\x36" + "\xb0\x00\xf4\x73\x88\xde\x87\x56" + "\xaf\x95\x75\x70\xa3\x47\x28\x92" + "\xc1\xde\xf6\x7f\x58\x18\xe0\xb7" + "\xcb\x91\xc1\x2f\xce\x3e\x28\x6e" + "\x56\xdc\x20\x1c\x8b\xef\xc2\x78" + "\xdc\xd2\x2e\x45\x5e\x53\xe6\x51" +
+       "\xed\x7f\x84\x29\x54\x56\xb3\x0e" + "\xd0\x3d\x67\x0a\x86\x42\xc1\xfd" + "\x0b\xdd\x62\x8b\x27\x36\x1b\x72" + "\x71\x57\x1a\x71\x3e\x29\x5a\x10" + "\x27\x19\x76\x7f\xce\x1c\x00\xdf" + "\x7d\x4c\xd0\x11\xb0\x81\xb6\xf7" + "\x96\x19\xac\xa3\x92\xf7\xdf\x16" + "\x30\xae\xc4\x0f\x0b\x12\x0c\x58" +
+       "\xc7\xb8\x0e\x96\x97\xf6\x35\xc0" + "\xd3\x04\xde\xe2\x2c\x9f\x59\xf1" + "\x28\x92\xad\xd2\xf8\x50\x24\x89" + "\xab\xc1\x29\xb8\x9b\x12\x48\x7d" + "\xc9\xaf\x50\x3a\xe1\x85\xd7\x24" + "\xe0\x6e\xa9\x63\x27\xba\x45\x27" + "\x7b\x6d\xfb\x3b\x01\x34\x65\x95" + "\x42\x2a\xad\x1b\x67\x02\x62\x53" +
+       "\xbc\xd0\xe8\x7e\x4f\x3d\xea\x31" + "\xdc\xc3\x42\x0f\x2a\xf2\x32\x38" + "\xf4\xa2\x87\x1a\x1a\x06\x61\xc6" + "\x6b\x57\x45\x4b\xf6\xc9\x78\x09" + "\xd2\x5f\xfb\x6d\x3c\xac\xab\xb7" + "\x90\x1b\xe0\xb7\x00\x6a\xf3\x27" + "\x36\x9e\x42\xe9\xcd\x33\xf7\x68" + "\xcb\xe8\xbf\xdc\x81\x46\x3a\x95" +
+       "\xe3\xc2\x03\x41\x24\xff\x96\xe3" + "\xe7\xad\x06\x1b\x1c\x56\x33\x41" + "\x34\xa7\xd0\x65\xac\xb9\x20\xe1" + "\xd9\x19\x79\x92\x07\x6f\x6f\x57" + "\x5a\x95\x1f\x69\x46\xc8\xcf\xa0" + "\x65\x9d\x44\xa6\xc0\x2b\x2e\x3d" + "\x9b\xed\x67\x97\xb8\x41\xa5\x7b" + "\xc7\x15\x92\xdc\x04\x1b\xb2\xd1" +
+       "\xaf\x1e\xfe\x67\x10\xc4\xb7\xbf" + "\x85\xa7\x29\x69\x6a\x3c\x07\xa2" + "\x79\xdb\x5f\xa7\xf4\x36\x25\x6f" + "\x69\xca\x9b\x80\x6d\xd2\x9a\x85" + "\x7b\x7e\x19\x3b\x69\xc0\xf2\x06" + "\x73\xa5\xc0\x8e\xf4\xd9\x6a\x65" + "\x62\x02\x4d\x9a\x1f\x90\xc7\xe7" + "\x2b\x60\x38\xb9\x43\x94\xc2\xbe" +
+       "\xa4\x73\x00\x0f\xfc\x97\x03\xd0" + "\x5f\x67\x8d\x6f\xa4\x8f\x66\x5b" + "\x8c\x10\x22\x15\xc9\x4a\x37\x14" + "\x2e\xe4\x83\x02\xd1\xa7\xef\x92" + "\x4a\x02\x6d\x0b\xf9\x6d\x3e\x67" + "\x26\x1f\x58\x57\xd4\x14\xf9\x05" + "\x12\x8c\xdf\x67\x62\x51\xc8\xf5" + "\x62\x24\x6c\xe0\xb4\xf1\x97\x11" +
+       "\xc1\x90\x9c\xdd\xb3\x1c\x2d\x6e" + "\x9e\x57\x90\x79\x5a\x2d\xf8\x28" + "\x95\x61\x22\x06\xcd\x89\xe1\x90" + "\x74\xdc\xb0\x19\xdf\x39\x29\xbd" + "\x77\x71\x91\xc0\x05\x85\xb1\x18" + "\xc4\xd9\x17\x31\x0d\x47\xd5\xee" + "\xa0\x3c\x89\x6c\xeb\x92\xef\x39" + "\x40\x19\xa4\x44\x82\xef\x33\x45" +
+       "\x95\x75\x2d\x2d\x3c\x85\xac\x62" + "\x54\xad\x8f\x59\xb7\xda\x83\x48" + "\xa4\xd7\x32\x6d\xd1\xf5\xf7\xbb" + "\x81\xd8\x1d\xfd\x2d\x4f\xfb\x95" + "\x80\xc5\x5d\x54\xf2\xae\x39\xe2" + "\xb9\x39\x1e\x4d\x0a\xa7\x09\x46" + "\xb2\xbb\x8e\x33\x3e\xb3\xd3\x61" + "\x61\x54\xbd\x15\xc2\x1d\x05\x06" +
+       "\xda\x3d\x94\x34\xec\x9d\xee\xca" + "\x82\x67\x4b\x8b\x8e\xe9\x50\x8e" + "\x1f\x3a\xea\x91\xa5\x8e\x35\x24" + "\x94\xc1\xe1\xa9\x27\xc8\xc4\x71" + "\x94\x7a\xbb\x09\x5d\xaa\x8b\xa3" + "\x9c\x8f\xb5\x57\xc0\xb4\x4a\xfb" + "\x19\xee\xe0\x24\x5e\x06\x01\x4a" + "\xbf\x77\xb8\x07\x51\x80\xcf\xb9" +
+       "\xbe\xb3\xa1\x81\x8f\x3f\x2b\x97" + "\xa0\x64\x27\xce\x45\xe1\x3c\x4f" + "\xf7\xf5\xc4\x28\xcc\xf1\xd0\xe2" + "\x5b\x98\xf3\xc7\x0d\x0c\xee\xde" + "\xc3\x25\x9e\xd3\xc0\xad\xf4\x7d" + "\x80\xa0\x67\xc4\x20\x98\x61\x40" + "\x58\x5a\xcf\x61\x93\xbc\x0e\x44" + "\x00\xd6\x2a\x42\xa6\x29\x77\x52" +
+
+       "\x49\xf4\x73\x3f\x75\x6a\xb2\xef" + "\x79\xfc\x44\x8d\xf8\x94\x1c\x1d" + "\x4d\xdc\xc0\x3b\xc5\xfb\xf0\x49" + "\xd0\xa0\x98\x36\x0b\xea\x47\xb7" + "\x1e\x29\x8d\x22\xfe\xc3\x18\x52" + "\xd6\x29\xc1\x43\xb5\x04\xb8\x35" + "\x16\xc5\xac\xd1\xb8\x59\xc8\xfa" + "\x68\xe6\xd6\x95\x7d\x69\x10\x6c" +
+       "\xdb\x2f\x45\xcb\x1a\x25\x30\x6e" + "\x50\x06\xf3\x50\x65\x69\xee\x31" + "\xd9\x48\x35\x93\x08\xe5\xb3\xb0" + "\x5b\xef\xb0\xf4\x4f\x9a\x94\xb8" + "\xbd\xf3\x88\x3c\x26\x83\x8b\x20" + "\x89\x99\x1d\xdb\x30\x7c\x14\xab" + "\x03\xdf\xd4\x44\xfd\x15\x65\xed" + "\xc5\xb0\x2e\xe7\x75\x2f\xa1\x17" +
+       "\x89\xfe\xe3\x28\xe0\xbb\x6c\x7a" + "\xeb\xc0\xaa\xc5\xe4\xfe\xe1\xe7" + "\x40\x51\x7e\x69\xa5\xed\x47\x7f" + "\x1f\x92\x54\xb4\x37\x01\x45\x4f" + "\x85\x81\xcd\x95\x84\x5f\x62\xdb" + "\x83\xe5\xb2\xcd\xa1\x0b\xbe\x74" + "\xe4\x6d\x5e\xdd\x7c\xfd\xe4\xae" + "\x39\x17\x10\xe8\x7d\x43\x51\x42" +
+       "\x90\xad\xfd\x81\x78\x4f\x91\x25" + "\xab\xf6\x2c\x0d\x56\x8f\x63\xcf" + "\xe5\x4d\x05\xcc\x3f\xc0\x0b\xb9" + "\x50\x63\xb0\x18\xa7\x11\x28\x93" + "\xff\x11\xbd\x9b\x30\xb3\x00\x2f" + "\x74\x49\x04\xb4\x6f\x8a\x10\x76" + "\x66\xd2\x51\xa8\xe0\xb9\x1b\x80" + "\xc1\x90\x89\xbf\xbe\x99\xd0\x0d" +
+       "\x61\x70\x7d\x51\x0a\xb2\x5e\x11" + "\x83\xf6\x2d\x6c\x33\x34\xfe\x77" + "\x67\xfc\xc6\xcd\xc7\xdd\x70\x68" + "\x83\xde\x87\x0b\x88\x05\x61\xb1" + "\xbe\xdd\xc4\xd9\xca\x84\x35\x34" + "\xe2\x4b\x75\x3d\x1c\x4f\x16\xb3" + "\x94\xc8\xe6\xc1\x3a\xed\x31\x07" + "\x4c\x90\x6b\x4f\xec\x7d\x32\x26" +
+       "\x55\x38\x1c\xc6\xae\x7b\x26\x29" + "\x3b\xfd\xc1\x58\x9d\x42\xff\xeb" + "\xb8\x93\x0b\x8c\xc0\x86\xd8\x22" + "\x53\x89\xdb\x2d\xb2\x00\x5e\xca" + "\xb7\xd8\xfe\xc3\x17\x01\x33\xcf" + "\xf6\x01\x9c\x81\xfa\xc6\x9a\xd4" + "\x54\xbd\x0f\x3c\xbd\xa6\xda\x6d" + "\xcf\xa2\x49\x80\x68\x30\x74\x91" +
+       "\x5a\x76\x72\x76\x3c\x06\x6a\x0a" + "\xbf\xb9\x47\x05\x64\xce\xa3\x37" + "\x33\xa6\xb1\x98\xc8\x99\xc0\x42" + "\x61\x69\xee\x05\x0d\x80\xab\xb5" + "\xd6\xac\xa5\x11\x59\x3f\x96\xf1" + "\x63\x10\x20\x46\x57\x61\xee\xba" + "\x0a\x21\x96\xa5\x49\xa6\xd9\x36" + "\x8c\x13\xa7\x1b\x63\x43\xd0\xae" +
+       "\x46\xcd\xd6\x58\x8a\xdd\xc6\x14" + "\xd2\x34\x66\x8e\xb5\x33\xb6\x9c" + "\x28\xc3\x1b\xf8\x47\x50\x30\xc1" + "\xe5\x77\xa1\x26\xe2\xe0\xed\x12" + "\x4f\x6f\x5a\x06\x62\xca\x2c\x33" + "\x7b\x48\xbe\x67\xcd\x7e\xa4\xc3" + "\x1c\xed\x47\x0f\x87\xb1\x1e\x74" + "\x14\x8b\x59\xe7\x58\x6e\xe6\x99" +
+       "\x6e\xe7\x1f\xf5\x76\x28\x82\x36" + "\x89\x25\xd6\x11\xcc\x11\x68\x8a" + "\x18\x57\x22\x46\x65\x7e\xfc\xc3" + "\xcd\xdb\x2f\xc8\x9f\x2c\xdf\xb7" + "\x5b\x20\x7b\xdd\x52\x4e\x1d\x3b" + "\x14\xe4\xa2\x47\x78\x94\x95\xb6" + "\x48\x11\xa9\xef\x93\xd7\xe4\x05" + "\x75\x96\x2e\xfd\x46\xd4\x7e\xb4" +
+       "\x2f\x23\xf3\xeb\xe2\xd0\x0e\x8f" + "\xdd\x2e\x2a\xc5\x9e\x0f\xf8\xff" + "\xdb\x5f\xb5\x75\x33\xb4\x9a\xad" + "\x11\x0c\x2e\xe4\x20\x78\xca\x73" + "\x46\x1b\x25\xe6\xa0\xe0\xac\x6d" + "\x2d\x93\x0d\x4c\x5c\x6b\xbc\x89" + "\x9a\xa1\x5d\x09\x77\xcd\x38\x34" + "\xfb\xbd\x48\x8d\x39\xa9\x24\x2f" +
+       "\x92\xb8\x41\x55\x51\xc4\x5d\x1d" + "\x54\x9e\x9d\xfc\x41\xee\x86\xb1" + "\x0d\x61\xbf\xd5\x5e\x34\x9f\x9d" + "\x9f\xca\xac\xf6\x5d\xa6\x7b\x3e" + "\x86\x94\x36\xa8\x7a\x78\xda\x9d" + "\x53\xba\xb5\x8e\xb7\xda\xf9\x09" + "\xc3\x1b\x48\xd6\x33\x20\xfb\x5a" + "\x04\x21\xa6\xaf\x30\xce\xf4\x76" +
+       "\x3d\xc9\x0a\x7b\x77\xa6\xd6\xeb" + "\xd7\xe0\xf5\x78\x0d\x7b\xe3\xa6" + "\x2b\x49\xf5\x76\x96\xc0\x16\x25" + "\x3a\x5f\xc0\x9a\x88\xf8\x4b\x1e" + "\x2b\xba\xf0\x4d\xe0\x2c\xb4\xcd" + "\x1b\x34\x62\x50\xfd\x5c\x5d\x93" + "\x20\xac\xac\x82\x33\x33\x30\x8a" + "\x0e\xb0\x98\x51\xc4\x38\x94\x42" +
+       "\x24\x8e\x1f\x5a\x3c\x18\x99\x3f" + "\xf0\x55\xd2\x9d\xfa\x18\xb1\xfd" + "\xa6\x62\x7f\xc2\x90\x8b\xb1\xb9" + "\x91\xc1\x6e\x39\xf7\x32\xf7\xe8" + "\xab\x86\xe7\x0b\x91\x2d\x4a\x52" + "\xf5\xa0\xc5\x0a\xef\xad\x32\x5d" + "\x94\xf6\x25\x97\xd6\xd4\x53\x9b" + "\x89\xba\x10\x05\xc6\x76\x2a\x03" +
+       "\x1c\xb1\x58\x57\x59\x5d\x9b\xa4" + "\x40\x4f\x65\xc8\x93\x28\x85\x0b" + "\x47\x94\x37\x52\xf4\xf6\x3e\xb6" + "\x0c\x69\x5e\x10\x29\x7d\x95\xd4" + "\xb0\x59\x65\x64\x63\x43\x48\x7d" + "\x8e\x8a\x78\x49\x3c\x27\xa8\xf4" + "\xa9\x54\xce\x34\xb8\x6c\x40\xee" + "\x9b\xda\x6f\xf8\x0f\x26\x1c\x1e" +
+       "\x50\x47\x95\x0e\x74\x79\xbd\x9d" + "\xc6\xd2\xf9\x64\x88\xde\x21\x01" + "\x2e\x23\x85\xd9\x42\x7b\x59\x2e" + "\x77\x17\x45\x53\xc5\xc3\xb6\x55" + "\xfb\xb9\x9c\x51\x47\xe5\x53\xbb" + "\x0d\x60\x28\x84\x9f\x01\x34\xf1" + "\x1a\x79\x81\xe0\x76\x31\x47\x5a" + "\x08\x0c\xfb\x35\x63\x22\x3e\x2f" +
+       "\xe0\x73\xe5\x67\xbe\x38\x28\xfb" + "\x4b\xc4\x84\x40\xb9\x1d\x89\x05" + "\xc5\xc2\xc1\x96\x73\x13\x31\x91" + "\x4b\x44\x58\xd9\x3f\xfa\xeb\x6a" + "\xc1\x55\x6e\xe5\xe9\xdc\x9c\xac" + "\xd0\x46\xaa\x2c\xd3\xce\x48\x71" + "\xeb\xe8\x1f\xb6\xef\xc7\x10\x2e" + "\x4d\xcf\x97\xff\xda\x35\xd8\x9f" +
+       "\xdd\x99\x1d\x43\x8d\xa1\xed\x9b" + "\xe1\xcc\xd5\xf3\x3d\x0b\x69\xf7" + "\xc9\x6e\x32\xb7\x6d\x65\xfb\x97" + "\x9c\x73\x95\x8c\x44\x71\xb2\xc1" + "\x98\xe2\x21\x9c\x89\xea\xec\x65" + "\x34\x57\x35\x37\x91\x72\xe5\xd0" + "\x3d\xeb\x65\x21\x2b\x7c\xbd\x80" + "\xc0\xf1\xc0\xdc\xe7\x16\x1e\xdf" +
+       "\x32\xc8\x07\x0c\xad\x8f\xe5\x97" + "\x9b\x43\xc3\x41\xa4\x50\xee\x73" + "\x20\x0e\x1f\x8e\xa4\x43\x06\x23" + "\xa3\xc6\xeb\xce\x8b\x7f\x3c\x53" + "\xb5\xe1\x63\x71\xb3\x47\xa6\x4d" + "\xfa\x26\x0b\x41\x4c\x0d\x65\x1a" + "\xfb\xfd\xe8\xdd\x64\x3a\xa5\x0d" + "\x73\x0c\xd8\x88\xdf\x86\xe7\x0c" +
+       "\xca\x0a\x8f\x23\x27\x92\xcf\x19" + "\xfd\x4c\xac\xab\xd4\xad\x86\x63" + "\x7f\xde\x5c\x5e\xa0\xc4\xb6\x17" + "\x07\x56\xaa\xc9\x58\x57\x2b\x17" + "\x8c\xe7\x01\x5f\xc5\x65\xa2\x0f" + "\x1e\x4d\x12\xdc\xfb\xfd\xb2\x1f" + "\xf8\x23\xf2\x9b\x3c\x8d\x23\xcf" + "\x6b\xbb\x94\x03\x8d\x2c\x5c\x3c" +
+       "\x16\x06\x77\xc1\x56\x6f\x62\x6c" + "\x2d\x9a\xda\x09\x9e\x90\x51\x53" + "\x45\x0e\x73\xa3\x25\x68\x8e\xe5" + "\x79\x0a\xef\x03\xc0\x8b\x8c\x9d" + "\xfd\xec\x6b\x05\xb6\x78\x3f\x54" + "\x6d\xb3\x90\xa0\x53\x32\xf1\x33" + "\xf9\x32\x44\x79\x97\x49\xad\x82" + "\x02\xf5\x21\x47\x3c\x49\x86\x13" +
+       "\x14\xd7\x9e\xd4\xf1\x13\xc4\xdc" + "\xd8\xb4\xc2\x6a\x27\xd6\xd3\x18" + "\xf8\xbc\x47\x53\x45\x7a\x15\x0f" + "\x44\xc9\x94\x26\x12\xf4\x13\x4a" + "\xdd\x00\x77\x39\x7c\xbf\xab\xe3" + "\x39\xef\x4e\x6c\x91\x8a\xa8\x72" + "\x9c\x47\x06\x46\xdb\xf8\x49\xb1" + "\xb3\xd3\xc2\x54\xab\xb1\x44\xff" +
+       "\x09\x3d\x83\x4b\x36\xac\x75\x88" + "\x9b\x5c\xed\xf0\x12\x77\xc9\xca" + "\x0d\x52\x81\x02\x8f\x5d\xf5\x7a" + "\x37\x62\x93\x46\x3b\x47\xf7\x06" + "\xd6\x84\x6f\xfe\x51\xca\x5b\x8a" + "\xa7\x4f\x27\x84\x4b\x6f\x4b\x76" + "\x1d\xc0\x64\xb9\xdc\x91\x30\xfa" + "\x46\xb8\x3a\x0a\xf6\x26\x1f\x6d" +
+       "\xf0\xcf\xc0\x8a\x5f\xf5\x0b\x0d" + "\x54\xeb\x50\xc1\x82\x88\x59\xd9" + "\xd0\x93\xc2\x51\x2c\xa7\xa4\x22" + "\x8a\x19\x3c\x64\xf6\x57\x6c\xf8" + "\x10\x57\x39\x20\xb0\x91\xab\x97" + "\xc0\xdb\x70\x19\x6c\x71\xe1\x9a" + "\xf8\x3d\xe5\xcc\xa2\x2b\x7a\x5b" + "\x4c\xd6\x85\xfc\x99\x9a\x79\xb2" +
+       "\x2a\xa8\xbe\x5a\xfa\xee\x94\x37" + "\xd4\x62\xfe\x93\xb9\x11\xc6\x8d" + "\x06\xf6\x1e\x28\x37\xaf\xf1\x69" + "\x69\x9e\x83\x39\xc8\x46\xf5\x6a" + "\x23\xec\x77\xc9\xc7\x78\x55\x62" + "\x76\x05\x5c\xbd\x4c\x29\xde\xa8" + "\xc0\xa4\xd1\x7c\x0f\xaf\xdd\xe2" + "\xd4\xf4\x95\x4f\x70\xfc\x43\x82" +
+       "\x12\x18\xe7\x50\xda\xab\xc5\x94" + "\x7c\x6a\xbb\x03\x35\x74\x94\x02" + "\x14\xbf\x8f\x79\xab\x53\xa1\x02" + "\x4e\x28\x2f\x7a\xc8\x26\xef\xf8" + "\xdc\x9e\xf9\x05\x5d\x92\x3c\x86" + "\xdd\x35\x9b\x40\xe6\x81\x6d\x97" + "\x70\x91\xe9\xdc\x99\x5a\x3a\xef" + "\xe6\x1d\x13\x53\xec\x80\xbc\xaa" +
+       "\x35\xb3\x40\xc9\x64\x7c\x41\x19" + "\xe9\x97\x6e\xaf\xf5\x4e\x45\x51" + "\x9c\x30\x16\xed\xac\x9b\x3c\x76" + "\x04\x48\x46\x81\x4d\x17\x6d\xe2" + "\x97\x74\x19\x35\x86\x42\x5a\xa0" + "\x09\xb1\xed\xad\x71\xfa\x10\xa4" + "\x6e\xf7\x95\xda\xb7\xca\x19\x72" + "\x1f\xd1\x88\xbe\xe7\x23\xc3\x74" +
+       "\x3c\x10\xdb\xb2\xd6\x91\xbb\xe1" + "\xe3\xc2\xe2\x92\xb1\x3d\x59\xbe" + "\xc1\x25\x5e\xb4\xca\x49\xf9\x53" + "\x23\x2f\x6e\x0a\x16\xe6\x39\x6a" + "\x0a\xd7\x57\x13\x6e\xe2\x13\x02" + "\x9c\x3e\x62\x8e\x1a\x1c\x74\x73" + "\xb2\x99\x93\x8d\xba\xa9\xdf\x54" + "\x32\x8c\x59\x0c\x40\x0c\x31\x86" +
+       "\x3a\x73\x08\xb0\x00\xf4\x66\xe5" + "\x57\x1f\x2e\x51\x7d\x69\xa0\xcb" + "\xd0\x9c\x50\x40\xb2\xc2\x37\x95" + "\x8c\x3d\x35\x57\x69\x9c\x98\x5f" + "\x2f\x2b\x3c\x4c\x72\xc9\xbe\x7d" + "\xa8\x1f\x03\xff\xa8\x2f\xe0\x90" + "\x1f\xd1\xd5\xcf\x53\x5c\xd1\xf4" + "\xfc\x4d\x31\x48\xae\x4f\x40\xb3" +
+       "\xef\x5f\xca\xb4\xa3\xbb\xf0\xb6" + "\x08\x90\xd1\x0f\xe2\xfc\x19\x49" + "\xdc\x2a\xd1\x1b\x8d\xd1\xb4\x18" + "\x9c\x8e\x1c\xc8\x88\x3a\x2f\xb2" + "\x49\x29\x7c\xcc\x2c\xb1\xf5\x86" + "\x7f\x98\xde\x05\xd8\x1a\xf6\xa2" + "\x70\x79\x72\xed\x72\x21\x74\x69" + "\xc7\x4e\x43\xd7\x8e\x2c\x9f\x3e" +
+       "\xb4\x52\x2c\x21\xf8\x0e\x49\xd1" + "\x7b\x5a\xb7\x00\xea\xfd\x2f\x5b" + "\xa1\x8b\x95\xbf\x3e\xb2\xc7\xf2" + "\xaa\xba\x6c\x69\x39\x20\xb4\x43" + "\x96\x34\xbe\x02\x94\xde\x5b\x1f" + "\xc4\xa5\xef\x39\x6b\x9d\xbe\x3a" + "\x82\x7e\x07\x47\xde\x7f\x20\x2a" + "\x28\x29\x86\x65\xfc\x74\xc3\x3b" +
+       "\xc4\x04\x06\x54\x1d\x0e\xd4\x35" + "\xed\x6f\x48\x3a\x3a\xb3\xa4\x16" + "\xa1\xa4\x43\xee\x6c\x49\x70\x91" + "\xaf\x8a\x94\xad\xe1\xdb\x4a\x17" + "\x99\xdf\x51\x54\x0a\xa3\x47\x8a" + "\xa1\x91\x17\x9e\xd1\xbd\xca\x7c" + "\x2a\xf1\xfc\xec\x3a\xb5\x12\x71" + "\xd2\xc6\xb5\xfa\x95\xb3\x1e\x56" +
+       "\x87\x93\x1e\x08\x09\xa1\x6d\xa3" + "\x28\x58\x93\x8c\xd7\x80\x97\xfb" + "\x15\xb0\x40\xe5\x32\x03\x94\xd5" + "\xfa\x66\xf4\xe0\x1b\xb5\xd7\xc9" + "\x71\xf6\xd9\xd6\x41\xcd\xad\xfa" + "\x17\xac\xa2\xb1\x28\x1e\x6c\xba" + "\x5f\x1e\x20\xed\x33\x78\x6a\x06" + "\x2b\x46\x0f\xf9\x19\x97\xd9\x19" +
+
+       "\x61\x5f\x0b\x06\x62\xf4\x31\xf4" + "\xc2\x57\xd0\x7b\xb4\x46\x6f\xa5" + "\x65\xbf\xe1\x47\x6c\xca\x8d\x34" + "\xff\xf1\xbc\x41\x3e\x78\x38\x9a" + "\x18\x07\x71\xda\xa9\x33\x5d\x7a" + "\xf6\xea\x0a\x2e\x87\x99\x77\x5a" + "\x87\xd1\x29\x2d\x4d\x31\x87\xca" + "\x33\xd7\x87\xc6\x3e\xdc\x0e\xfa" +
+       "\xc7\x8a\x19\xcb\x49\x48\x89\x1c" + "\x65\x46\x26\x0f\x3d\xa9\x84\xa8" + "\x78\x06\x20\x9b\xef\x64\xa9\x2d" + "\xe6\x34\x98\x00\x87\x1b\x35\x3c" + "\x4b\xb4\xc4\xe2\x9f\xef\xb2\xaf" + "\x0c\x79\x26\x33\x47\x6c\x0f\x58" + "\x4a\x26\x02\x0b\x21\x05\x48\xb8" + "\xe2\x94\xa1\x42\xe2\xf9\xa6\x8b" +
+       "\x0e\x3c\xb0\x5e\xb6\x6a\x9b\x49" + "\xde\x3f\xbc\x72\x54\x79\x9b\xf1" + "\xd2\x80\x3a\x6e\x9c\x5b\x6b\xa8" + "\x9f\x81\x42\x6d\x08\x75\x37\xe4" + "\xa3\xe8\x3e\xbb\x50\x36\x66\xc1" + "\x5f\x07\x32\xb1\xfc\x14\xeb\x75" + "\xf6\x34\xd8\x7a\x06\xc9\xcc\xa8" + "\xfd\x2f\xe9\xe6\x74\x24\x6a\xea" +
+       "\xf1\x95\xc0\xd3\xab\x34\xd9\x39" + "\x71\x6d\xb7\xe4\xbe\x61\xb2\x04" + "\x84\x69\x3e\xe7\x70\x69\x2e\x1d" + "\x11\xcb\x5f\x5e\x3b\xb2\x9f\x87" + "\x90\x54\xd7\xdf\x72\x6c\x50\x11" + "\xc1\xf1\xbc\x61\x85\xd0\x97\x3a" + "\x07\x70\x5e\xbf\x82\x1d\x20\x43" + "\xa7\x32\x82\x79\x2f\xc5\x0a\x7f" +
+       "\x36\x91\x04\x4b\xee\x20\x4d\xcb" + "\x13\x46\x6a\x35\x12\xbf\x63\x8b" + "\x28\x81\xe0\x70\xf6\xae\x21\x12" + "\x16\x6b\xcb\x4a\x51\x8c\x2d\xe6" + "\x96\x78\x9e\x37\x67\x4a\xf6\x71" + "\xa5\x7f\xfd\xca\xa2\x37\x52\xb2" + "\x6a\xba\x41\x38\x98\xbd\x77\xf0" + "\x7e\x6e\xd1\x3c\x44\x02\xac\xc4" +
+       "\x82\x76\x9d\x31\xfb\x01\x51\xb2" + "\xee\x2f\x98\x0a\x29\x31\x29\xb0" + "\x44\xb3\x61\x02\xb9\xc9\xc1\x51" + "\xfa\x71\xd3\xbf\x5b\x8c\x00\x0e" + "\x33\xca\x78\x02\x1c\xdd\x66\xd8" + "\xb1\x53\xaa\xe5\xa6\x76\x6f\x66" + "\xcf\xa2\x13\x60\x79\xb7\xcf\xe5" + "\x36\x18\x52\xa3\xad\x1a\x3a\x1d" +
+       "\x9c\x5f\xf7\x50\xff\x04\x56\x3c" + "\x22\x2b\x75\x7e\xf3\xdd\x8e\x1d" + "\x18\x11\x9a\x3c\xdd\x74\xf0\x0e" + "\x7b\x6d\xb8\xcc\x72\xc1\xff\xd0" + "\xf2\x90\x7d\x03\xe3\xec\xd1\xab" + "\x6c\x85\x55\x60\xd6\x07\xf3\xe3" + "\xaf\x6d\x4c\x7e\x28\x93\x2f\x42" + "\xa0\x79\x48\x33\x66\xac\x2a\x90" +
+       "\xec\x93\x71\x56\x1a\x13\xb4\x76" + "\x0b\xe7\xf6\xe5\x5a\x30\x3c\xaf" + "\xdd\xeb\x1e\x03\x39\xbd\x87\x95" + "\x31\xe8\xbb\x71\xf8\xde\x09\x57" + "\x69\xb6\xb2\x0e\x83\x99\x05\x57" + "\x29\x70\x5b\x87\x1b\xce\x80\x4d" + "\x16\xac\x64\x03\xa8\x7d\x8a\x83" + "\xab\x83\x1c\xbe\x23\x1d\x43\x2f" +
+       "\x1e\xc7\x40\xb9\x4c\x87\x52\x8e" + "\x3a\x4b\x5f\xdb\xa9\x35\x19\x21" + "\xc3\x1d\x1b\x30\x92\x04\x35\x94" + "\x20\x86\x95\x29\x6d\x64\xd2\x33" + "\x04\x14\x91\xef\x4b\xd6\xb0\x16" + "\xf4\x5e\x3c\x9a\xea\x25\x1f\x9d" + "\x78\x2c\x35\x4a\xeb\x00\xf2\x20" + "\x28\xb4\xd0\x4b\x2c\x9f\x92\x43" +
+       "\x4e\x5d\x23\x38\x66\x27\x81\xe7" + "\x98\x32\x6e\x49\x67\xbd\x62\x1c" + "\xc8\x5b\x17\x3f\x0c\x66\x78\x83" + "\x4d\xdd\xaf\x17\x89\xe1\x04\x4d" + "\x8c\x06\xa8\x85\x01\x16\xa8\x32" + "\x85\x9a\xb2\x92\xe1\xe4\x58\xdb" + "\x3b\x8a\x0d\xc7\x86\x5b\xa6\xe8" + "\x3b\x40\xa0\x98\x4e\x6f\x0e\x5f" +
+       "\x9e\x9f\x2c\xe8\xe6\x36\x46\xd4" + "\x43\x10\x3a\xc3\x7c\xb8\x1d\x71" + "\x05\xec\x8a\xaa\x63\x12\x43\x6f" + "\xaa\xa4\x44\x27\x0d\x12\xff\x43" + "\x9b\x77\x77\xae\x2f\x89\xbd\xd3" + "\x82\x9f\xdc\x8c\xc9\x0c\xfe\xf0" + "\xbc\xb1\xc5\xf1\xe6\x7f\x5f\xca" + "\x72\x9a\x92\x44\x82\xa6\x63\xcc" +
+       "\xe0\x4a\x89\x3f\xb7\x92\x24\x2c" + "\xce\x18\x5f\xb7\xe5\xf3\x9d\xf5" + "\xd0\xca\x53\x8f\xd2\x40\xb7\x7c" + "\x94\x12\xf0\xc4\xfb\x85\xb5\x3e" + "\x17\xf7\xc7\x32\x86\x0c\xda\x17" + "\x4c\x3f\x94\xaf\x5b\x79\x8c\xeb" + "\xd2\x51\x7c\xf6\xb5\x3f\xe2\x4e" + "\x49\x99\x88\x68\x75\x75\x18\xef" +
+       "\x6f\xff\x8d\xb3\x3e\xda\x34\x28" + "\xe8\x6b\x63\xea\x52\x2c\x01\xbe" + "\xf8\x37\xdd\x61\x8c\x23\x2d\x29" + "\xdb\x42\x81\x8f\x3f\x52\x54\x0e" + "\xd8\x05\x6a\x03\x36\xb4\x1e\xe3" + "\xff\xc0\x93\x1e\xff\xcd\xe3\x83" + "\xdf\x1d\x82\x50\x0f\xfe\xd2\x3f" + "\x3b\xb3\x9e\xff\x0d\x9b\xe1\xc8" +
+       "\xd0\xf0\x22\xe8\xa4\x11\xa0\x3e" + "\xf8\x04\x87\x5a\xd1\x7a\x64\xbc" + "\x0f\x82\xc6\x50\x35\x5b\x31\xbb" + "\xec\x6b\xe7\xb7\x3d\xec\x3d\x86" + "\xc7\xbf\x17\xf0\x3a\x5d\xff\x01" + "\x29\x82\x6b\x97\x39\x44\x05\x20" + "\x3b\x0d\xbd\x0b\x37\xca\x7f\x06" + "\x0f\x3d\x5e\x7f\x64\xde\x3d\xf6" +
+       "\x95\xa8\x9c\x5e\x52\x90\x7d\x14" + "\xdf\x72\x20\x97\x1e\xd3\x4d\x2f" + "\x5c\x75\xc6\xe6\x8e\xda\x6f\xa1" + "\x58\x65\x19\xcf\xff\x26\x68\xc6" + "\x95\x38\xf4\x0c\xa3\x76\x1a\x1f" + "\x7b\x09\xc3\x83\xe0\x04\xd6\xa9" + "\x0e\x0e\x39\x66\x09\x83\x90\xe1" + "\xff\x5e\xc8\xb3\x53\xf7\x0b\xa5" +
+       "\xcf\xcc\xf7\xad\x15\xbc\xd9\x75" + "\xb0\xe1\xa1\xdf\xd6\xe5\xa3\x81" + "\x7e\xc1\x9b\x24\x44\xe4\x39\x8c" + "\x43\xfd\xa7\x8e\xb2\xcc\x7d\xf3" + "\x12\xba\x7f\x90\x73\x48\x65\xda" + "\x04\x29\x37\x4a\xda\xa6\xda\x35" + "\xc5\xa6\x83\x62\xc6\xcf\x64\x05" + "\xbf\x95\x93\x4a\xf6\xa4\x9f\xd0" +
+       "\x31\x84\x56\x6f\xa7\xf9\x64\x0d" + "\x8c\x89\xf8\x02\x7c\xc2\x48\xf8" + "\xd5\x5b\x0b\x26\xe1\xad\x18\xf4" + "\xe8\xde\x73\x69\x23\xe3\xf3\xc1" + "\xdd\x85\xc1\x26\x9c\x31\xe9\x46" + "\xc4\x0a\x6f\x54\xd8\xb7\x85\x6d" + "\x57\x9d\x7f\x24\xf2\x65\x79\x42" + "\x48\x5f\x03\xb0\x36\xb6\x19\xb5" +
+       "\xff\x9d\xa3\x6a\xb5\xb3\x10\xb5" + "\x8c\x4d\x8e\x9f\xa2\x3d\xb4\x59" + "\x9f\x4b\x4c\x9e\xfd\x31\xce\xa8" + "\x01\x3c\x30\xc1\x26\xbe\x20\x0e" + "\xc9\x47\xee\xe8\x82\x71\x18\x18" + "\x01\x81\xb9\x7d\xdb\x7c\x68\xd9" + "\xf6\x4f\xe1\xa1\x4d\x0e\x52\x7a" + "\x72\xd5\x36\x88\xba\x08\x98\x42" +
+       "\xc6\xe5\xa9\xdd\xe5\xc1\x2a\x68" + "\x95\xfc\xa9\xca\x72\x3c\x0d\x4e" + "\x44\xea\x2b\x77\xde\xaa\xfa\x17" + "\xc8\x09\x00\xab\x8c\x42\xf8\x5e" + "\x16\xf0\x0f\x46\x7a\xe4\x4c\xcc" + "\xcb\x81\x52\x72\xbf\x12\x6d\xda" + "\xd2\xaa\x23\x02\x48\x78\xc6\x44" + "\x28\x6e\x25\x36\xfa\x2a\x34\x6e" +
+       "\x8e\x76\x16\x6d\x99\x46\x4d\x17" + "\x17\xf2\x8b\x62\x6a\xff\xc4\x9f" + "\x0d\x49\x4e\x15\x94\x5a\x70\x77" + "\x7a\x99\x2d\x8d\x28\xdd\x96\x9d" + "\xc4\x72\x5d\xce\xd8\xd9\xe2\x77" + "\x4f\x71\x1c\xc1\xa4\xc5\x06\x9d" + "\x3e\xa0\xe4\x79\x36\x51\xaa\x02" + "\x8b\xf2\x0f\x03\xc2\xb3\x86\x13" +
+       "\xc2\xc9\xce\x8b\xb6\x86\x61\xb8" + "\x06\x9f\x0b\x68\xf9\x4d\xf2\x7c" + "\x81\x92\xd2\xc0\xea\x45\x6b\xc4" + "\x12\x0e\xb1\x07\xc5\x2b\xf4\xff" + "\x27\x94\x28\x4d\x40\x3c\x26\x12" + "\xc4\x8e\x84\xb4\x99\x18\x5f\x3d" + "\x0c\x80\x40\xd0\x10\x70\xf9\x11" + "\x20\xeb\x0f\x30\x29\xf5\xc5\xb4" +
+       "\x3a\xdc\x40\xea\x69\x2d\xa4\x26" + "\x8f\x01\xcc\xae\x22\xad\x84\xdc" + "\x4a\xf0\x70\x32\x7b\x6c\xc3\x25" + "\xed\x72\xfa\x50\x47\x6d\xba\x46" + "\x8e\x8a\xe5\x93\xc5\xd1\x37\x6c" + "\x8c\x08\x0c\x12\x31\x47\x39\xa2" + "\xda\x86\x6e\xcb\x63\x42\xbe\xc3" + "\x38\xd0\x26\x71\x36\x7d\x41\x2c" +
+       "\xd0\x59\x71\xb0\x6d\x11\x3d\x9d" + "\x10\x62\x89\xc1\x7f\xa6\x07\xae" + "\x79\x15\x96\xbb\x87\x4d\xc8\x8f" + "\xd6\x8d\x1f\x1c\x49\x9e\x00\x30" + "\x19\x28\x13\xe3\x22\xaf\x8c\x8a" + "\xff\xb4\x3a\xf2\x7c\x19\xfa\xcf" + "\x87\xd6\x5d\x20\x44\x3a\x10\x58" + "\xa2\x67\xed\x0d\xc3\x96\xb7\x57" +
+       "\x29\x22\x0e\x44\xbb\x23\xa5\xcc" + "\x04\x4d\xef\x73\xa2\x73\x46\x32" + "\x39\xec\x11\x3e\x34\xdf\x3a\xaf" + "\xd3\x68\x59\xdc\xf1\xd7\x36\x61" + "\x27\xa9\x53\xb0\x99\x28\x7b\x7a" + "\xcd\x7e\x06\xae\x61\x26\xaa\x3e" + "\xd9\x9c\x77\x02\xc8\xb9\x49\x85" + "\xea\x85\x33\xc5\x40\x79\x1d\x06" +
+       "\xe7\x3c\xe9\xb3\x89\x7a\xd2\xd7" + "\x1b\x2c\x3a\x5d\x75\xa8\xb5\xf7" + "\x8a\x21\x5b\x25\xa0\x68\x9e\xb2" + "\x54\x67\xf7\x8a\x7e\x83\x33\xb5" + "\x2e\xab\x9f\x57\x73\x5a\xb0\xd1" + "\x85\x43\xd7\xec\xa1\x55\x10\xb4" + "\x15\x91\x5e\x44\x74\x92\x36\xb2" + "\x4e\x27\x20\xf5\xc4\xa7\x72\x29" +
+       "\x2b\x90\xa2\xaa\xfc\x41\x71\xe0" + "\xd3\x9a\xf6\xe4\x99\xd7\x9a\x53" + "\xfd\x9f\x3f\x81\x94\x3f\x45\xa6" + "\xf7\xc2\x5b\x37\x48\x3c\x8d\xc5" + "\x96\x4e\xc6\x5d\xad\x6f\x32\xb3" + "\x54\xe3\x40\xb2\xa9\xca\xaf\x3a" + "\xa9\xe7\xa1\xac\x03\x09\x1b\x1d" + "\xa0\xb8\x11\x12\x67\x97\xeb\x4c" +
+       "\xa0\x10\x17\xc8\x79\x2e\x94\x5e" + "\xd4\xad\xcc\x27\x36\x4a\x7e\x55" + "\x0c\x6d\xcf\x4b\x56\xbc\xa2\x72" + "\x0c\xb8\xd7\x26\x43\x5f\xee\x09" + "\x19\x2f\x29\xd4\xe9\xdb\x70\x6b" + "\x18\x6b\xf1\x63\x26\x4c\xf7\x56" + "\x2a\xb4\xfb\x35\xf7\xb0\x3d\xc2" + "\x40\x00\xe1\x6a\xf6\xbd\x06\xb6" +
+       "\x58\x2d\x03\x87\x46\xde\xb4\x1e" + "\xe0\x79\x2c\x5e\x83\x3d\x4f\xc5" + "\x23\xef\x04\x5d\xf4\x8d\x81\x07" + "\xb4\x41\x3d\x67\xc8\xa9\xfa\x55" + "\x55\x53\xb9\x89\x6f\x4f\xd6\xce" + "\x84\x5c\x41\xb7\xea\xd2\x60\x48" + "\xd3\xba\x0e\x05\xd2\x9b\xdb\x5f" + "\xbf\xa5\x85\x66\xcc\xe0\x53\xdb" +
+       "\xb3\xa7\x1e\x8b\xa0\xd2\x61\x9a" + "\x85\x14\x8b\xae\x63\xab\x95\xd4" + "\x99\x2f\x05\x87\x84\x0f\x74\x38" + "\xea\x4e\x97\xb2\x5b\xbe\x8e\x17" + "\x7f\xd1\x36\x5b\xca\xbc\x0b\x03" + "\xea\x6e\xf8\xaa\xe3\xcc\xe4\xb5" + "\xe0\xe9\xf8\x68\x20\x02\x1a\xb5" + "\x75\x3e\xeb\x09\x96\x87\x34\xa4" +
+       "\xca\xe1\xfa\xab\x5f\xca\x9f\x91" + "\x9b\x45\x21\x1a\xac\xfa\x7a\x93" + "\xd2\xa4\x66\x1f\x1c\xa9\x0c\x9e" + "\x31\x13\xec\x23\xf3\xc7\x4c\x19" + "\x90\x16\xa1\x8a\x3a\x14\x25\xad" + "\x08\x9e\xb5\x09\x8d\xad\x40\xbe" + "\x0a\x86\x50\xe7\x9b\x0d\xd6\x37" + "\x4c\x43\xbf\xc6\x08\xb0\x53\x6c" +
+       "\x17\xc5\x3e\x1d\xd0\xa0\x61\xa6" + "\xae\x21\x23\x51\x52\x46\x74\x98" + "\x98\x25\xa9\xec\x91\xa5\x4c\x08" + "\xeb\x3f\xcb\x1d\xc9\x9d\xbb\xa9" + "\x40\xc2\xb4\x78\x55\x43\xc5\x14" + "\xdc\xaf\x0c\x61\x3b\x2a\xd6\x5e" + "\x6b\x84\x38\x1b\x37\x2f\x51\x07" + "\x61\x81\xe3\xb0\x0a\xb7\x1b\x57" +
+       "\x2d\x24\x6b\xeb\x80\x70\x2d\x83" + "\x46\xe2\x71\x3b\x23\xd0\x0b\xd3" + "\x9d\x13\x31\xbe\x1b\x99\x27\x70" + "\x53\x4e\x2e\x46\x91\x7e\x79\x68" + "\x5a\x18\x4e\x6b\x0a\xe2\x3f\x42" + "\x07\xb7\xd9\x42\x7e\xc6\xf2\x82" + "\x1b\x81\xf7\x4c\x68\x17\xc8\x25" + "\x5d\xb9\x5b\x04\x5e\x00\x53\xbd" +
+
+       "\xfd\x68\x8e\x9d\xbe\x49\xf6\xe5" + "\x20\x43\x04\x1b\x33\x05\x0f\xdb" + "\x98\x33\xc3\xe0\xb3\xe9\xfd\xf6" + "\xae\xcf\xc8\x66\x9b\x20\xf4\x92" + "\x4b\x9d\x73\x1a\xcc\xaf\xd1\xe9" + "\xde\xb8\x8a\xa2\x5f\xa7\xae\x09" + "\xd0\xf1\xc6\xea\xb5\x5f\x37\x14" + "\xa5\x7a\x8f\x70\x60\xb5\x20\x64" +
+       "\x41\xdc\x54\x62\x9c\x49\xae\x9e" + "\x7e\x7e\x83\x7a\x24\x39\x29\x7e" + "\xa7\x24\x05\x09\x8c\xc0\xae\x74" + "\xf2\x55\x6f\x8d\x19\x92\x2b\xf8" + "\xc5\xce\x02\x14\x2e\x96\x3c\x49" + "\xe7\x30\x2f\xfa\x17\xca\x17\x9f" + "\xcb\x79\xb8\xe9\xe8\x83\xd7\xbc" + "\x5f\x14\x6f\x5a\x14\x8c\x3d\xea" +
+       "\x6e\xee\x0d\x5e\xe7\x15\xde\xde" + "\xa2\x8a\x62\xdc\x72\x48\xf2\x74" + "\x93\xbb\x61\x78\xfe\xc4\xe9\xd3" + "\xe0\xb2\x87\x61\x2a\x82\xd4\x56" + "\xf9\x26\x98\xc5\xcf\x17\x64\xb6" + "\x9e\x16\x08\x24\x69\x09\x26\xca" + "\x85\xf8\x9e\xc7\x06\x9d\xf6\xed" + "\x8f\x13\x7d\xdc\x8a\x1f\x03\x00" +
+       "\x26\xf7\xbc\x0e\xe6\x46\x3c\x10" + "\x0e\x47\x31\x62\x31\xb8\x82\x44" + "\x09\x21\x7c\x48\xca\xfa\x6d\x6f" + "\xef\x66\xe6\x62\x97\xce\x0a\x2e" + "\x42\x1f\x8d\x1f\xd3\xa9\x46\x32" + "\xd2\x44\x49\x57\xf1\x83\x1e\x1b" + "\x4b\x33\x7f\xa5\x3a\xa6\xdf\x13" + "\x81\x5d\x02\x9f\xed\xda\xf8\x0c" +
+       "\xc1\x11\xee\x00\xa8\x8e\xd7\x30" + "\x75\xdd\xe3\xb5\xd4\x3c\x05\xeb" + "\xc5\x43\x8c\xd5\x3e\xb1\x65\x9b" + "\x63\x16\x15\xbd\xbd\x49\xad\xc3" + "\x90\x79\x42\xb6\x41\x8e\xfd\x99" + "\x1e\xae\x7e\x70\xbd\x15\xcf\x12" + "\x1e\xb7\xab\x1a\x1b\x4f\xad\x29" + "\x0e\x5d\x54\x07\x4d\xe7\x43\x51" +
+       "\xe1\xde\x8b\xc8\x36\x63\x26\x30" + "\x7c\x76\x76\x58\x06\x93\xf2\x25" + "\x96\x19\x73\xc6\x71\x85\x07\x9c" + "\x51\x29\x55\xed\xb2\x90\x86\xc8" + "\xb4\x05\x27\x85\x2d\x2c\x4f\x27" + "\x2d\x55\x09\x4e\x44\x8d\xbf\xb0" + "\xd1\x75\x65\x98\xeb\xbe\x28\x76" + "\x51\x46\x86\x7f\x38\xe2\x7b\x40" +
+       "\x6b\xfc\x39\xa6\x49\x30\x5e\x0e" + "\x25\x36\x00\x86\xd9\x35\x5c\xe7" + "\x46\x16\xcc\x5d\xd8\x5b\xf3\x0c" + "\x3a\x27\x26\x6c\xd2\xce\xca\x8b" + "\x42\x67\x53\xb5\x1d\xcf\x2e\xe2" + "\x8b\x06\x9e\x1a\x97\xd8\x3d\x01" + "\xc5\x09\x79\x8a\xcb\x11\xf4\x17" + "\x06\xd5\x1d\x86\x98\xac\x57\x57" +
+       "\xbb\x5a\x93\x1e\x0d\x1f\xde\x85" + "\x7a\xe3\x4d\x15\xb4\x10\xfd\xde" + "\xb5\xeb\x9c\x36\x92\xe3\xd9\xb8" + "\xbe\x24\x13\x76\x9b\xef\xd5\x54" + "\x26\x7e\xf1\x74\xba\x41\x63\x4d" + "\xe4\xdd\xc1\x78\xc8\xe3\xa0\xc0" + "\xfd\x18\xd9\x87\x81\x75\xd7\xa6" + "\x13\x3a\xca\x02\x15\x60\x87\x66" +
+       "\xf0\x58\x66\xf3\x9c\x3e\x31\xc7" + "\x7e\x05\xf8\x71\x1c\xef\x33\xc4" + "\x5a\x83\x6a\x1b\x46\x62\x32\x85" + "\x4c\x39\x86\x7c\x98\x53\xf0\xc8" + "\xa1\xc4\x83\xe9\xdf\x8c\x39\xff" + "\x31\xb9\xb7\x03\x62\x81\x5e\xbf" + "\x5b\x04\xb9\xb7\x46\x3c\x19\x93" + "\x6b\xe4\xa6\xa4\x5d\xbf\x4e\x1e" +
+       "\xe7\x4f\xa2\x43\x60\x2a\x94\xf9" + "\x2b\x49\xb3\xff\x1e\x19\xc1\x29" + "\x05\xde\x2f\x90\x49\x24\x66\x9f" + "\x2d\xc3\x13\x67\xac\xa7\x92\xc7" + "\x2c\x98\x37\xb7\xd8\x8a\xd8\x2f" + "\xe3\x60\x1e\xa2\x19\x03\x3a\x7e" + "\x1a\x59\x83\x73\x44\xde\xb0\x09" + "\x56\xa4\x10\x83\xee\x41\xf1\x6d" +
+       "\x71\xf4\xd6\xe6\x39\xa0\xc1\xae" + "\x2e\xd1\x98\x11\x0f\xba\xb2\x14" + "\xac\xe5\xee\x3a\x60\xa1\xc1\xeb" + "\xce\x64\xb9\xe0\x36\x48\x1f\x40" + "\x66\x3f\xd0\x4f\x96\x37\xe4\x2e" + "\x12\x3f\x8f\xdd\x49\x4e\xdb\x3f" + "\x18\x0f\x38\x29\xf6\x67\xf2\x6e" + "\x16\x4d\xa6\x8d\x70\x96\x8e\x3e" +
+       "\xf1\x74\x76\x20\x0c\x18\x19\xbc" + "\xdb\x8f\xae\x33\xa7\x09\x2e\x11" + "\x1e\xb7\xae\x6a\x54\x75\x66\x99" + "\xc7\xb1\x01\xe1\xf1\x2a\x43\x79" + "\xc6\xde\x2d\xde\x8f\x55\xeb\xd5" + "\x3f\x75\x57\x53\x1f\x2d\x39\x81" + "\x8a\x15\xe1\x3a\x97\x6b\xa7\xa7" + "\x91\x99\x89\x4a\xff\xbb\x6f\x41" +
+       "\xcf\x9d\x4a\x0d\xfd\xfd\x65\x9e" + "\x12\xdf\x4d\x94\x48\x9e\xc2\x7b" + "\x66\x68\x85\x3c\xd9\x92\x1a\xbc" + "\xe2\xdf\x98\x6e\x05\x69\x3c\x27" + "\xb8\xa6\xfa\xcd\x18\xe4\xfc\x69" + "\x9f\xc6\x61\x50\x23\xd8\x6b\x60" + "\x27\x5e\xf7\x6a\xa0\x95\xd4\x42" + "\x1f\x3a\x87\x6d\x05\xd5\xd3\x8e" +
+       "\x6a\x5b\xb2\x6a\x41\x28\x55\xaf" + "\x23\x45\x1a\x2b\xc7\xff\xc0\xc6" + "\x03\x9e\xc9\x21\x7b\x82\x18\xab" + "\x1b\x69\x34\x90\x48\x86\x0e\x06" + "\x98\xf3\xc7\x93\x0f\xf9\x07\x52" + "\x0b\xd1\xf8\x82\xcb\x96\x4a\x9f" + "\xe3\xf9\xd0\x3a\x79\xcd\x71\xdd" + "\xf5\x54\x3a\xfc\xd2\x35\xf4\x84" +
+       "\x7f\x78\x33\x8e\x5b\xc5\x03\x4b" + "\x73\x46\x38\xa6\x75\xf9\x42\xef" + "\xf0\xb9\x51\x50\xf7\x04\x73\xff" + "\xc2\x87\x1c\x74\xdc\xa1\xac\x18" + "\x80\xfe\x4b\x2d\xa7\x20\xf1\x56" + "\x2c\x73\x3e\x05\x3d\x3b\x82\xfd" + "\x16\xca\x37\x75\xe4\xcf\xbc\x11" + "\x6b\x99\x5a\x1b\x74\x9c\x6c\xdf" +
+       "\xfa\xc3\x4f\x90\xc7\x32\x73\xee" + "\x6a\x63\xe3\xc7\x45\x3f\xa2\x14" + "\xaa\xd9\x91\xf0\xc3\x59\x86\xc3" + "\x40\x85\x2d\xb1\x5d\x5e\x99\x4a" + "\x8a\x59\xa5\xf3\xec\x3b\xa5\x20" + "\x95\xa9\xea\xb1\x17\x4b\x53\x56" + "\x3c\xe0\x04\xbf\xa4\xdc\xd3\x9e" + "\x68\x62\xd5\xd8\x3a\x56\x6c\x71" +
+       "\xe7\x78\x61\x1d\xa4\x77\xba\x27" + "\x8e\xff\xa1\x68\x40\x0c\xc8\xe4" + "\x3d\xf6\x13\x0a\x99\x10\x01\x75" + "\xf3\x46\x1d\xa6\x21\x35\xf3\x7b" + "\xbb\x65\xb3\x10\x8e\x21\xff\x0a" + "\x75\xea\xd7\x0f\x04\x18\x02\x81" + "\x25\xa9\xb3\xa4\x8a\xfd\xa3\x05" + "\xe6\xb4\x3d\x9b\x5f\xe7\x29\xb8" +
+       "\xfb\xe5\x53\x4d\xa5\x75\xdc\x6b" + "\xe3\x17\x27\xd5\x02\xdc\xa5\x04" + "\xc2\x2e\xa4\xe9\x2f\x50\xaf\x86" + "\x82\xe3\x30\x26\xfb\xe8\x67\x88" + "\x9b\x88\xc9\xbe\x6e\x5c\x84\xbf" + "\x8d\xc9\x47\xcb\xf2\x91\xf4\x54" + "\x12\x2a\x0c\x79\xba\x1f\x09\xa3" + "\x8b\x70\x0f\xc2\x78\xfd\xf6\xd7" +
+       "\x17\x5e\xde\xac\x30\xac\x69\xa5" + "\xd7\xb4\x52\x68\xd0\x96\xf9\xd0" + "\x54\xae\x09\x46\xb5\x4b\x1d\xe5" + "\x61\xd0\xae\x0d\x17\x7d\xa3\x3f" + "\x41\xfb\xb8\x34\x84\x86\xa8\x62" + "\xf1\x64\xfb\x9e\xbd\xac\xa2\x99" + "\xf2\xe1\x48\x64\x5e\x1a\x5c\xb7" + "\x69\xa0\xb5\x42\x1a\x95\x99\xfa" +
+       "\xe7\x26\x3b\x2f\x89\x6e\x95\x6d" + "\x47\x52\x87\xda\x60\x98\x70\xf4" + "\xa3\xdd\x82\x24\x79\x51\xd1\x3a" + "\xf0\x82\x7d\x01\xe3\x10\x41\xd6" + "\xe4\x14\xd4\xfa\x2c\x8d\x92\x14" + "\x24\x2b\xd0\x2e\x58\x5f\x15\x2b" + "\xf1\x1b\x82\xcb\x1b\x14\x1a\x48" + "\xda\xf5\x81\x4f\x70\xc7\xe3\x12" +
+       "\x81\x83\xff\x9f\xe5\x5d\x9c\xe4" + "\x94\xc8\xbe\x5b\x32\x32\x05\x11" + "\xc4\x88\x4d\x45\xcc\x51\xd0\xa0" + "\x1b\x53\x8e\x1f\x9c\xb8\x6d\x4f" + "\x44\x3a\x56\xca\xd6\x3f\xfe\x34" + "\xb9\x8a\xda\x58\x15\x22\x5c\x7f" + "\xa1\xf0\x74\x94\x6d\x01\x45\x84" + "\x0a\x8a\x7d\xcb\x61\x4d\xd3\x17" +
+       "\x19\x40\x47\x1c\x10\x39\x9d\x8e" + "\xfb\xee\x2c\xd5\x29\x26\xff\xca" + "\x2b\x2c\x62\xc1\x32\x3e\xcf\xf9" + "\x05\x1a\x07\xe9\x3c\x5e\xb9\xd4" + "\x8c\x43\x94\x15\x1f\xa6\xbc\xfb" + "\xdf\xde\xaa\x04\xa6\xe6\xb6\x1e" + "\x40\x49\xe1\x68\xf4\x27\x30\x85" + "\x9c\xda\xab\xdf\x2a\x32\x1d\x22" +
+       "\x9a\x17\xcb\xb7\xf6\xa9\x8e\xed" + "\xcc\x4d\x93\xb7\x4d\x76\x7b\xdc" + "\x0d\x18\x09\x5e\x40\x39\xb1\xfc" + "\xdd\xc2\x7d\xb4\xbf\xa6\x29\x66" + "\x5e\x91\x5a\x9f\x4e\x5e\xc5\xbf" + "\x1e\x44\x04\x62\x37\x9d\xdb\xb1" + "\x53\x5f\x0c\x93\xcf\x68\x2d\xf8" + "\xb1\x05\xb6\xcb\x42\xa1\xd3\x17" +
+       "\xf2\x80\x87\x30\xea\x44\x59\xdd" + "\xe4\xf5\x45\x38\x61\xe7\x8d\xdc" + "\xa3\xd7\x24\x76\x7d\xba\xea\x6b" + "\x1e\xf1\x4d\x30\xfd\x9a\x70\x1e" + "\x56\x04\x17\x02\x76\x43\x36\x95" + "\x64\x4b\xf9\xc8\x3a\x4b\x20\xbf" + "\x68\xca\x80\x56\x7c\xaf\x53\x4e" + "\x74\x75\xc6\xe0\x4a\x07\x26\x05" +
+       "\xf6\x2a\xd9\xec\xf8\xce\xd8\x95" + "\x5a\x74\xd1\x6c\x7a\xfa\xb9\xe6" + "\xe4\xc3\x25\xa3\x3d\x6d\x54\x3d" + "\xae\x3a\xe9\x9a\x1d\x69\x57\x1f" + "\x33\x1a\x2e\x9d\xfe\xf3\x91\xe8" + "\x35\x3d\x06\xac\x3f\x09\x30\xd4" + "\x27\xa3\x13\x55\x12\x9b\xa5\xed" + "\x8f\xf1\x36\x55\xf3\x34\x21\xdc" +
+       "\x86\x02\x21\x5c\x2c\xfe\x51\xaa" + "\x8c\x65\xab\x1c\xee\xaa\x68\x3f" + "\x92\x72\x35\xf9\x0b\xa0\x23\x5a" + "\xed\xab\xfd\x7e\x39\x6f\x62\x9a" + "\xe3\x78\x9d\x19\xf3\x3b\x2b\xfe" + "\x45\xc3\xbb\x71\x77\xaf\xa2\xb7" + "\x2c\x80\x59\x1e\x7a\x82\x19\x3d" + "\x1c\xa5\x87\xb4\x15\xbc\x3b\x82" +
+       "\x22\xa4\xd0\x99\xf2\x39\x61\x85" + "\xfb\xc6\x56\xf4\x65\xdf\xc3\x9a" + "\xd6\x8b\x1f\x70\xc6\x65\xdf\xad" + "\x87\xdf\x58\x37\x1e\x32\x9f\x14" + "\xba\x7e\x1b\x72\x14\xf7\xec\xb1" + "\x2a\x31\xa3\x31\x98\xf0\x7d\xe1" + "\x81\xd5\xc4\xd5\xec\xd6\x2f\xdb" + "\xb3\xa1\xce\x8f\x6f\x99\x02\xfd" +
+       "\x4f\xf1\x82\x78\x3e\xa6\x9f\xe2" + "\xdc\xca\xc6\x07\x35\xdc\xf6\xc9" + "\xd0\xbe\x82\xb8\x6f\x2d\xf2\x46" + "\x2c\xe5\x18\xd1\x5b\x75\x45\x1a" + "\xcf\x08\x46\x7c\x27\x7c\x2c\x9f" + "\xc2\x12\x80\x56\x32\xdf\xcb\x7c" + "\x0e\x9b\x72\x61\xdd\xae\xb0\xfc" + "\xbf\x5d\xd7\xf7\x9e\xca\xa2\x7c" +
+       "\x62\x0f\x64\x6f\xb1\xec\x8f\xf5" + "\x46\x19\xf5\x39\x2b\xb9\x74\xe2" + "\x44\xaf\x88\x62\x04\xfc\x4d\x7f" + "\xe5\x29\xc3\xea\x2a\xf3\x91\x0a" + "\x31\xba\xaa\xd6\x4b\x27\xad\x43" + "\xf9\x84\x68\x0f\x40\x16\x9a\x71" + "\x20\x1e\xf9\xda\xf6\x29\x5d\x68" + "\x52\x9d\xe4\x27\x33\xcc\xc1\x5e" +
+       "\x59\xa0\x54\x3b\x96\xde\xf4\x38" + "\xb3\xfd\xbc\xef\xe5\x15\x00\x0e" + "\xa6\x8d\xbb\x4d\xd9\x23\x7d\x17" + "\xad\x17\xa6\x97\xa2\x4a\x72\x98" + "\x8e\x55\xb6\xfd\x5b\x88\xf0\x30" + "\x96\x9a\x89\xc7\x8a\xa2\xf7\xf9" + "\x12\xc1\x2d\x87\xc8\x8a\xae\xd2" + "\x59\xc4\xc3\x73\xca\x42\x06\xfa" +
+       "\xd6\xc8\xdf\xe7\x81\x69\x29\x15" + "\x4a\xb9\xb5\x1f\x50\x44\xcd\x67" + "\x37\xfd\xdd\x0e\xf1\x1c\xc7\x0e" + "\xc7\xdd\x8e\x9a\xb3\xee\xe5\xc7" + "\x28\x50\xd9\x81\x3d\x8e\xac\x02" + "\x5d\xe3\xb0\x70\x72\xf1\x88\x00" + "\xe3\x1f\x88\xe1\xab\x1f\x04\xec" + "\xaa\x7f\x9e\xd9\xb8\x71\xcf\x62" +
+       "\xc2\x22\xf2\xe0\xa7\xde\x43\x50" + "\x42\x51\xe6\x72\xac\x42\x9d\x30" + "\x30\xcd\x16\x92\xdd\x9d\xfe\x94" + "\xec\xfe\x87\x0f\x7d\x9c\x53\xd6" + "\xd7\xc7\x2a\x43\x7c\xa5\xc5\x03" + "\x10\xda\x7f\x32\xf0\x2c\x69\x72" + "\xde\x98\x06\x28\x5f\xc8\x28\xec" + "\xb1\x83\xc2\x7e\x46\xfb\x31\x23" +
+
+       "\x77\xa4\x57\xe4\xea\x8e\x15\xa0" + "\x05\xdc\x6d\xee\xdb\x57\x98\xd1" + "\x71\x16\xc4\x18\x24\x52\x26\xb3" + "\x58\x0d\x2c\x3c\x7e\xfc\xfd\x3f" + "\xda\x7c\xee\x26\x54\x52\x3a\x3a" + "\xa8\xc3\x02\xdf\x69\x08\x1b\x34" + "\xc8\xbf\x3b\x72\x42\xbf\x23\xa0" + "\x91\x26\x45\x14\x2a\x00\x15\x3d" +
+       "\x30\xfa\xed\x85\x4c\x32\xf7\x5e" + "\xda\xf3\xd4\x87\x54\x65\x97\x25" + "\x86\x0c\xb5\xdc\xc0\x5b\x2f\x35" + "\x6c\xa9\x32\x48\xb0\x27\x69\x8f" + "\x4c\xf9\xf2\x55\xba\xe1\x8e\xd0" + "\xfa\x45\x4b\x34\x99\x6f\x99\x6a" + "\x5d\x45\xaa\xa8\x8d\xcb\x33\xe1" + "\xf7\xc1\x8d\x75\xec\x21\x07\x5d" +
+       "\x39\x35\x2a\x26\xe9\xe7\xca\xf3" + "\x9e\xd5\x70\x66\x1d\x9d\xa4\x78" + "\xb9\xe1\xc5\xc1\x63\x0f\xde\x37" + "\x1c\x7c\xcb\x69\x0c\xc3\x72\x30" + "\xe6\x50\xc8\x77\x52\x8a\x27\x1d" + "\xe6\x3d\x6a\x1f\x8f\x5f\xf1\x84" + "\xad\xa7\x2c\x59\x45\xbb\xa8\x46" + "\xb8\x24\xd4\xe4\xee\xe3\x12\x19" +
+       "\x67\xfb\xe5\x79\x20\xa9\xa7\x6b" + "\x5e\x72\xaa\x70\xeb\x1f\x33\xe1" + "\x37\xd8\xf5\x7d\xf5\xcc\x80\x50" + "\x21\x2e\xf7\x7f\x1d\xe0\xca\xe4" + "\x7d\xa7\x12\x04\xe6\x3e\x24\xd9" + "\x25\x90\x44\xdf\xac\x7c\xff\x06" + "\x31\x5a\xef\x23\xcd\xf7\x75\xbe" + "\xa8\xf7\xde\x0d\x22\x78\x95\xbc" +
+       "\x8b\x66\x5e\x36\x86\x80\x98\xdc" + "\xfb\xa5\xbd\xaa\xda\xdc\xa8\xad" + "\xbe\x1f\x5f\x25\x4c\x6b\x14\xbc" + "\xc3\xcf\x34\xcf\x29\xde\xfc\x9c" + "\xe4\xd1\x85\x7e\x3e\x45\xbb\xac" + "\xb5\x58\x23\xf9\x79\x96\xa0\x9c" + "\xff\x23\x08\x24\x96\x2d\xfc\x15" + "\x1e\xd1\x11\x0c\xf7\xad\x65\x8d" +
+       "\x55\x1c\xce\xb0\x0c\x23\xf7\x8c" + "\x07\xb6\xbf\x0b\x05\x4d\x53\x5b" + "\x3b\x36\x16\x0e\x13\xf1\x1e\xee" + "\x82\x9e\x99\xb4\x7a\xaa\xe0\x27" + "\x41\x2c\x36\x79\x2d\xac\x1d\xce" + "\xb0\x6c\xbb\x91\x90\x0c\x92\x67" + "\x24\xdf\x23\x22\x63\x8d\x64\x1e" + "\x28\x8f\x2e\xe3\xef\x9e\x7d\x0f" +
+       "\xfd\xf4\x96\x02\xf1\x57\x55\x77" + "\x36\xb4\x51\xea\xa3\x76\xca\x1d" + "\x05\x08\x95\xfb\x60\x8f\xe9\xf3" + "\xf1\xf7\x1c\x83\xea\x32\xff\x31" + "\x4b\x71\x2c\x8d\xf1\x7b\x3e\x64" + "\xca\x2a\x9d\x2e\x39\xc3\xb5\x64" + "\x23\x2d\xdc\x6a\xcc\x9c\xfd\xa9" + "\x9b\x1b\x72\xcc\xec\x97\x23\xfc" +
+       "\x34\x38\x83\xfa\x9a\xf3\x43\x69" + "\x62\x85\x32\xa6\x22\x17\x95\x22" + "\x10\xfc\x70\x41\xd5\x3d\xd6\x81" + "\x6d\x2e\xcc\xae\x8f\xa5\x5f\x9f" + "\x3b\x9a\x7d\xe7\x25\x87\x6c\xb6" + "\xe0\xeb\x84\x63\xea\x5c\x23\x11" + "\x4a\xe2\x45\x58\x18\xc1\xa8\x06" + "\xb1\x93\xd0\xeb\x86\xb2\x37\x01" +
+       "\x7d\xc5\x8e\xb4\x2d\x18\x31\xf0" + "\xb9\x33\xb2\x04\xf8\x32\x5d\x51" + "\x26\xad\x3a\x09\xd4\xb1\xbb\x06" + "\xec\xd1\x83\x0d\xfe\x42\xa1\x88" + "\xf8\x73\x5c\x24\x99\xc0\x95\x3b" + "\x32\xcd\xed\x52\xaf\xd4\x26\xb1" + "\xe6\x52\xcb\x8f\x1e\x2c\x02\xf8" + "\x39\xd3\x06\x01\x4c\xac\x51\x5a" +
+       "\x50\xe1\xac\x44\xce\xe1\x89\xc5" + "\x7c\xe9\x81\x43\xd9\xd3\xf8\xe0" + "\xb8\xa4\xc5\x62\x11\x9b\xe9\x59" + "\xf9\xc9\x0e\xfd\xf7\x62\xd2\x90" + "\xc9\x13\x3e\x28\xc9\x54\xc8\xfb" + "\x85\x70\xdc\xae\xe7\xfd\x04\x2d" + "\xcb\xbe\xdc\x47\x65\x77\x7d\x05" + "\x5f\xfa\x76\x9a\x91\xf5\xbd\x8d" +
+       "\x54\xa0\x64\x7c\x1a\x0a\xf7\xb7" + "\x79\x3e\xb4\x9d\xdf\xc0\xc1\x0d" + "\xd6\x63\xfe\x51\xe2\x4a\x0a\x6d" + "\xbf\x8a\x0c\x7f\x32\xe3\xd5\xe0" + "\xe8\xce\x7e\x2b\x36\x00\x55\xff" + "\x08\x50\x05\x5d\xf7\xe6\xa0\x3e" + "\x4f\xc8\x4a\xf2\x2f\xb6\xde\x30" + "\xb7\x16\x71\x5d\xfd\x69\x69\x93" +
+       "\x78\xe5\xe1\x0d\x95\x06\x15\xd0" + "\xc6\x2b\xf7\xe9\xe7\x63\x14\x2e" + "\xa5\xec\x39\x1b\x41\x84\xa6\xff" + "\x2f\x7f\x03\x7c\x30\x85\x3c\x67" + "\xda\x91\x7f\x74\x00\xa6\xd6\xd0" + "\xe9\x78\xcb\xc9\xe1\x43\x8d\xb0" + "\xf5\xce\xb5\x27\x44\xc6\xc0\x0f" + "\xd6\x2f\x0a\xa6\x0a\x16\x1d\x5c" +
+       "\x7f\xcf\x17\x26\x12\x76\xda\x02" + "\x60\x52\xe3\xee\x4e\x5d\xe2\xd6" + "\xe9\x33\x35\xfd\x0a\x5b\xfa\xb2" + "\x88\x6f\x12\xb9\xb0\xb7\x6b\xe7" + "\x66\x68\x85\x88\x99\x6a\x2e\x69" + "\xca\x65\xdb\x49\x4f\x39\xdf\x3f" + "\x06\xd6\xd8\x22\x91\x69\x29\x25" + "\xcf\xc4\xd7\x3d\xbf\xbf\x15\xe8" +
+       "\x3b\xe1\xc8\x28\x53\xae\x8c\xf9" + "\xd1\xdc\xed\xb2\xc4\x10\x5f\x37" + "\xad\x06\xce\x5c\x7f\x8b\xeb\xd4" + "\xef\xe1\xa2\x80\x45\x9f\x66\xb4" + "\x99\x86\xbd\x5b\xd0\xf9\x93\xd5" + "\x13\x6d\x97\xe7\xc9\xa4\x28\x55" + "\xd3\x28\x7e\x1c\x95\xe0\x23\x39" + "\x77\xb5\x6b\x3f\x90\x37\x29\xb9" +
+       "\x7f\x4e\x84\x4d\xed\x84\xc9\x69" + "\x82\x8a\x2e\x4a\x17\xb2\x54\xd3" + "\x36\x41\x2c\xfb\xdd\x4a\xbd\x25" + "\xe1\x26\x4b\x14\xde\xf4\x2d\xf7" + "\xfd\x1a\x10\xe6\xb0\x9d\xaa\xd0" + "\xb8\xd1\x9b\xe4\xaa\xef\x45\x44" + "\xb2\x93\x15\x33\xee\x4e\xc5\x5d" + "\x0b\xf1\x4b\x09\xb9\xe3\x35\xfa" +
+       "\xd2\xd6\x2b\xc4\x6a\x7d\x56\xdb" + "\xae\x96\x1f\xbb\x68\x64\xf8\x6d" + "\x8e\xb2\x43\x48\x1a\x5b\xfe\x0e" + "\x40\xb2\x79\x63\x05\xbb\x1b\x96" + "\x6b\xa2\xa6\x70\xf0\xf5\xca\xb6" + "\x39\x6e\x8e\x32\x0d\x6c\x68\x70" + "\xd3\xc8\x5f\x89\xcf\x06\xda\x80" + "\xc9\xfd\x63\xb3\x10\x88\x4d\x80" +
+       "\xc3\x89\xa0\x3e\x89\x0f\x0a\x66" + "\x09\x9b\x00\xc9\xaa\x23\x58\xa2" + "\xe5\xf5\x81\xa6\x7b\x2d\x26\xb2" + "\x3a\x86\x13\x34\x8c\x0c\xc3\x4f" + "\xf7\x59\x20\xc3\xb7\x44\x15\x69" + "\x34\x61\x1c\xb2\x76\xf2\x5c\xf6" + "\xba\xda\x04\x51\x2a\x6b\xa9\xe3" + "\x2f\xe4\x3e\xa4\x09\xd1\x08\xbb" +
+       "\x70\x16\x7f\x20\x7b\x87\x22\xbe" + "\x91\x52\x61\x4e\x88\xd1\x0d\x9b" + "\xbf\xc2\xa3\x97\xdc\xe8\x5a\x62" + "\xe8\x86\x9b\x43\xf7\x4e\x58\x08" + "\xff\x98\xd8\xdc\xa5\x90\x71\xde" + "\x3d\xee\x58\x20\x40\x6c\x28\x26" + "\xc1\xb1\x87\x5f\x17\xb2\xb0\x3d" + "\xb5\x6d\x2a\x10\x71\x47\x33\xcc" +
+       "\x61\x68\x91\xf9\x69\x2d\xa5\x85" + "\x13\xa8\x4f\xda\xa4\x69\x54\x59" + "\x2f\x50\x38\x33\x6e\x78\xd7\x1d" + "\xc5\x3a\x96\x53\x28\xef\xb8\x34" + "\x25\x1b\x89\x1a\xf8\x19\xf0\xc0" + "\x75\xd7\x4b\x4f\x0c\x97\x19\xb6" + "\x81\xf6\x19\xbe\xf3\x5a\x2a\x8c" + "\x28\x17\xec\x98\x04\xdb\x63\x94" +
+       "\xb1\x0f\x77\x2f\x54\xe9\x9d\xd9" + "\x5e\x53\xd7\x4c\x20\xc6\xc1\x97" + "\xfc\xce\x09\x3f\x48\xc4\xb6\xd3" + "\xf8\xb4\x63\x5a\x15\xaf\x25\xd7" + "\xec\x20\x1e\xc0\x4f\xd2\x95\x0c" + "\x1f\x12\xe7\x9a\x94\x74\xd3\xdf" + "\xec\xb7\x77\xec\x72\xdb\x6d\x7d" + "\xae\xa4\x53\x03\x3b\x9d\x07\xfe" +
+       "\xab\x9e\xf3\x01\x78\xc2\x62\xeb" + "\xaa\xa4\xb3\x0a\x34\x39\xde\x27" + "\x8d\xca\x82\xa9\x20\x75\xd1\xfb" + "\xed\xc6\xbd\xe4\xc2\x7e\x81\x58" + "\x13\xac\xc6\x31\xde\x78\x2d\x31" + "\xa6\x2e\x20\x09\x76\xbf\x83\x94" + "\xe1\xd8\xc6\x22\xb6\xb8\x4a\xf6" + "\x74\xde\x80\xe5\x9c\x58\xdf\xdd" +
+       "\xd2\xc8\x6a\x2e\x0a\xe7\x66\x30" + "\x05\x5c\x6e\x10\x43\x5a\x6b\x9c" + "\x8c\x9b\xe5\xed\xf5\xc6\xd3\x52" + "\xae\xc9\xce\xfc\xc3\xa5\xd6\x30" + "\xef\xa9\xc0\x4f\x22\x7c\xec\xed" + "\xed\x6c\xc1\x95\x83\xf0\x0f\x19" + "\xde\x0f\xde\x94\x8f\xec\x12\xbe" + "\x33\x34\x2d\x85\xb8\x1a\x13\x0d" +
+       "\x2a\xa9\x98\xee\x36\x33\xfa\xe0" + "\x45\xd7\xa4\x66\xef\xee\x80\x7d" + "\xd3\x19\x01\xba\x1b\x53\x12\xb6" + "\x15\xfe\x51\xb3\xc1\x70\xe7\x86" + "\x97\xa3\xd5\x82\xf8\xd6\xba\xaf" + "\x10\x01\xbf\x0d\xb8\x1c\x5f\x1e" + "\x3d\x06\x79\x9f\xc0\x8a\x13\x25" + "\x56\xa1\x46\x27\x2f\xd2\x9e\x08" +
+       "\x91\x12\x70\x85\x7e\xe0\xac\x42" + "\xa8\x61\x40\x19\xd9\x3e\x79\x94" + "\x85\xa4\xf4\xd7\xd6\x3e\xe8\x30" + "\x4d\xff\xee\xf9\x69\x72\xec\x9e" + "\x05\x80\x9d\x0c\x59\xba\xac\x90" + "\xd1\xb9\x79\x1e\x58\xa4\xec\x5f" + "\x1e\x6a\x50\x1d\x27\x54\xbe\x8f" + "\xa7\xcf\x39\x24\x8e\x2c\x2b\xa3" +
+       "\xde\x8d\x8b\x7d\x5d\x1b\x8d\x19" + "\xfb\x37\xab\x8d\x07\x11\x2c\xf3" + "\x74\x38\xb9\x42\x6d\xcb\x5f\xf1" + "\x84\x4f\xf9\x41\x4f\xb7\xdd\x91" + "\xb2\x24\x15\x27\x0a\x54\x64\x6a" + "\x64\x5a\x8b\x75\x12\x0c\x0a\x95" + "\x80\x95\xce\x3d\x93\x37\xf2\xf9" + "\x32\xce\xf8\x2c\xab\xd0\xed\xc8" +
+       "\x4e\x0b\xdd\x73\x73\xc1\x71\x16" + "\xc6\x54\xa0\x44\x14\x82\xa2\x37" + "\xf1\x53\x8b\x4e\x1b\x0a\x76\x81" + "\x9e\x3b\xf9\xf9\x24\x42\xc0\xa6" + "\x3c\x1e\x67\xcf\x34\x4b\x78\x18" + "\x94\xb9\xa9\xcd\xd2\xec\xbb\x81" + "\x48\x38\xab\xb2\x79\x19\x83\x38" + "\x2d\x3c\xe0\xf2\xb7\xfe\x54\xef" +
+       "\xb7\x46\x10\xae\x7e\x35\xc6\xef" + "\xe4\x32\x29\x61\x29\x49\x70\xe6" + "\x17\x5b\x35\xb1\xd4\x05\x03\xa2" + "\x56\xa1\xb4\x58\x6a\x13\xa9\x88" + "\xec\x75\xd2\xb4\x85\x99\x37\xbc" + "\x8b\x33\xaf\x6e\x31\x91\x8b\x71" + "\x09\xa5\x52\xd1\x7a\x9a\x22\x61" + "\xe9\x7a\x15\x45\xc4\xf7\x09\x11" +
+       "\xfa\x88\x80\xfb\xa7\x7c\x19\xcf" + "\xc5\x96\xdc\x4d\x47\x72\x42\x01" + "\x76\x71\x77\x30\x0a\x55\xd2\xa2" + "\x1d\xf7\x0c\x4d\x98\x98\x46\x53" + "\xc6\xaa\x2a\x3a\xb8\x37\xe9\x6c" + "\x9b\x8d\xf3\x5a\xc3\x1d\xf9\xe9" + "\x99\x28\xbf\xc8\x83\xad\x98\x25" + "\x16\x6c\x53\xb5\xc9\x6a\x70\x8e" +
+       "\x2c\x5c\xf8\x0d\x14\x42\xde\x2b" + "\x63\x7a\x8a\x05\xf4\x39\xb8\x4f" + "\x31\x12\xf5\x47\x2a\x57\x10\x7c" + "\x4e\x82\x89\x19\x23\x26\x88\x87" + "\x4a\x56\xe1\x16\x20\x3d\x29\xa8" + "\x76\x45\xc0\x18\xf8\xc0\x11\xcb" + "\x31\xc6\x40\x97\x7d\x1e\xb9\x83" + "\xa0\xce\xff\xcb\xd0\x23\xcb\xbd" +
+       "\x98\xdc\x88\xf6\x95\x74\xdc\x40" + "\xfc\x4a\x4c\x12\xd7\x0c\x49\x26" + "\x5c\x77\x18\x1f\x84\xec\x51\xe6" + "\x4a\xaf\xfd\xb4\xc3\xa6\x3e\x39" + "\x0d\x8e\x33\x7f\x43\x33\x1f\x1e" + "\xb5\xe7\x53\x60\x2b\x83\xfb\x39" + "\xd5\x14\x9e\x61\xda\x02\xe7\x46" + "\xe0\xf6\xee\xcd\xd1\xac\x9c\x85" +
+       "\xc8\xbf\x94\x90\x2a\xfd\xbd\x64" + "\x1e\x4d\xc5\x0f\xc6\xac\x58\x85" + "\x1e\x72\x27\xaf\x8f\x84\x92\x39" + "\x09\xd0\x4c\xa1\xda\xcb\x8f\x7a" + "\xc2\xb9\xa4\x00\x09\x12\xe6\x6d" + "\x28\x8f\xcf\x20\x1b\x2b\x19\xbd" + "\x83\xbe\xd9\x68\x01\xb9\x56\x23" + "\x8a\xa4\x49\x4a\x94\x7a\x1e\xce" +
+       "\x7d\x00\x62\x44\xe7\x9c\xb9\x63" + "\xb7\xf5\xb5\x4c\xa5\x48\xab\xb8" + "\xe7\xdd\x5e\xf5\xd2\x73\xc6\x9e" + "\xda\xef\xfa\x8c\x74\x7f\x56\xd1" + "\xec\xbc\x87\x08\x6b\x1b\x38\x46" + "\xc2\xf3\x78\xe1\xce\x97\x44\x69" + "\xcb\x66\x62\x1e\xe3\x25\x65\x5e" + "\x13\x64\x7d\x69\x26\xde\x31\x59" +
+
+       "\x7a\x50\x93\x1a\x02\x55\x2b\x14" + "\xcf\x06\x3c\x8d\x87\x11\xcd\xb4" + "\x40\x3f\xec\x91\x6a\xe7\x70\xdf" + "\xc2\x53\x75\x4e\xad\x81\x4e\x48" + "\x6e\x9d\x2e\x27\xb5\x87\x0f\x83" + "\x4a\x51\xff\xc6\xe5\x93\x1c\xea" + "\x8e\x2a\x19\xc4\xdc\x2a\xcc\x67" + "\x5a\x53\xf4\x42\xe2\x27\x7e\xc7" +
+       "\x99\x51\xc0\xd0\xf2\x9c\xda\x8c" + "\x54\x84\xe7\xfa\x22\xbc\x2f\x50" + "\x82\xa1\x72\xf5\xdf\xa9\xbd\xc0" + "\x72\xb3\x58\x61\xb8\x71\x9b\x5f" + "\x07\xdd\x82\x2b\x59\x3a\xf3\xe0" + "\x2e\x03\x23\x95\x35\x27\x30\x76" + "\x32\x5a\x50\xc4\x21\xa7\xe1\x7f" + "\x9f\x40\x96\xf7\x82\x3e\x6e\x7b" +
+       "\x9e\xba\x37\xea\x56\x63\xc6\xb4" + "\x5d\xf5\xff\x0a\x15\x84\xdc\x1a" + "\x62\xc8\x6c\x59\xf9\x0e\x08\xf0" + "\xb6\x7a\x64\x6d\xb8\x85\x6c\x75" + "\x15\xc2\xb9\x1d\xaa\x94\xdb\xc9" + "\xa5\xb1\x13\x20\xb1\x6d\xd3\x2d" + "\x03\xc9\x86\x42\x1c\xc6\x6a\xde" + "\x84\xf8\x6c\xc7\x88\x2f\xd3\x3f" +
+       "\x4a\xb3\xd0\x35\xc0\x7b\x41\xe3" + "\xa7\xc0\x27\x83\x6b\x38\x0b\x44" + "\xd1\x62\x03\xac\x2d\x26\xb7\x8f" + "\x43\xf9\xcd\xe0\x4c\x11\x41\x2c" + "\xb1\xa0\x95\xad\xf1\xce\xa5\x2b" + "\x62\x43\xd5\x67\xa8\x37\x9b\xc0" + "\xc9\x86\xe4\x01\xd2\xcd\xd6\x26" + "\x97\x92\xff\x42\xbf\x7a\x47\x20" +
+       "\x8d\x46\xe9\x11\xec\x82\xca\x31" + "\xa0\x5f\xa0\x1c\xb6\x0e\x5d\xcf" + "\x73\x2e\x96\xaa\x05\xa3\xba\x49" + "\x56\xe4\x15\x40\xb9\x61\x2b\xad" + "\x35\x38\x21\x6c\x5f\x8e\x2b\x6d" + "\x63\x47\xf7\x48\x2b\x1c\xf1\x0e" + "\x68\xa7\x8b\xc1\x5e\x7b\xcd\xa8" + "\xec\xcc\x7e\x15\xef\x4d\xc8\x73" +
+       "\x7d\x1e\x58\x51\xf6\x6a\x54\x13" + "\x2e\xdb\xc7\x39\x87\x0b\xe2\x0c" + "\x46\x7c\x12\xd9\xed\xe2\xb1\xfa" + "\xa8\xe6\x35\x6f\xc4\x1d\x9a\xba" + "\x7b\x0e\x69\x80\x6f\x66\x69\x1b" + "\xa0\x90\x88\x64\x3d\x0e\x53\xd6" + "\x00\x3e\xc2\x99\xb1\x4c\xbd\x37" + "\x00\x7a\xba\xb7\x2c\x4e\x27\xe7" +
+       "\x3a\x24\x57\x67\xb6\x50\xac\x9f" + "\x72\x24\xf3\x23\x61\x79\x41\x8f" + "\xf4\xcb\x72\xb3\x56\x7a\x36\xeb" + "\x03\x92\x79\xb7\x5c\xe1\x37\xbe" + "\xdd\x33\x40\xdc\xdf\x1f\x52\x1b" + "\x7f\x8d\x8d\xae\xed\x10\xf4\x21" + "\x47\x75\xdc\xbd\x4e\xf2\x6a\xbe" + "\x4d\xa7\x18\x6e\x84\xae\x65\x99" +
+       "\x87\x92\x2a\x29\xb3\xdc\x04\xa0" + "\xc7\x92\xb0\x77\xf6\x5c\xc1\xdd" + "\x05\x06\x6c\x80\x64\x84\x3a\x08" + "\xb0\x97\xb9\x3d\x70\xdf\x68\x4a" + "\xd0\x7d\xbf\x05\x45\x4e\x13\x9c" + "\x8c\x7f\xcf\x8c\x39\x3d\xe6\xa4" + "\xaf\xf8\xb5\x41\x7f\x51\xe6\xa6" + "\xcc\xc1\x7b\xad\x42\x93\x8b\xaa" +
+       "\xc1\x5a\x89\x16\xcd\xb0\xa9\x6a" + "\x37\x4c\x8e\xf2\x53\xd3\xdc\xad" + "\x0a\xae\x90\x6f\xbd\x3a\x47\xff" + "\x8e\x14\x8a\x31\x09\x24\x48\x76" + "\x21\x27\x19\xca\xcc\x5e\xeb\xc5" + "\xae\x22\xd2\xfb\x27\x25\x54\x58" + "\x94\x0d\xb5\x81\xa9\x52\x48\x59" + "\xba\x8c\x6a\xe2\x03\x4e\x1f\xa0" +
+       "\x4a\xf9\xe0\xc2\xf5\xc5\x1d\xe1" + "\xc7\x6c\x98\x71\x4e\xfa\xb6\x1f" + "\x02\x8d\xb3\xa5\x96\x19\xfc\x0f" + "\x3f\x40\x85\x93\x8e\x26\x06\x0e" + "\x95\x61\x1a\xd0\x09\x1f\xd1\x93" + "\x17\x65\x46\x5d\x40\x96\xeb\x05" + "\xdf\x5a\xed\x77\xcc\x85\xa8\x63" + "\x72\xea\xa0\x35\x25\xdc\x07\xd5" +
+       "\x38\xc3\x4f\xa9\x81\xad\xe7\x68" + "\x9d\x4d\x22\x5a\x4b\x70\x6c\x31" + "\x5f\x59\x26\x4f\x38\xa9\x4f\xe3" + "\x36\x18\x96\x98\xe9\x1f\x17\x86" + "\x6c\x49\x27\x39\xc4\x1b\x99\x98" + "\xd7\x61\x87\xc6\x5a\xdb\x6f\xce" + "\xd6\x96\x9e\xb2\xfc\xfe\x24\x0a" + "\xa3\x66\xac\xe5\xa6\xff\x2d\xc7" +
+       "\xd9\x6a\x70\x1e\xb5\x35\x6f\x12" + "\xdf\xeb\xa9\xc3\xb4\xeb\x9c\xb9" + "\x90\x8d\x60\xbf\xaf\x89\x53\xa7" + "\x58\x98\xc8\xc6\x4f\x3c\x11\x76" + "\xaa\xb5\xe2\x97\xb0\x8e\xde\x80" + "\x04\x13\xb9\x63\xcc\x22\x10\x7e" + "\x6c\x06\xcc\x6c\x05\xb6\xda\x3b" + "\x00\xf9\xed\xb2\x44\xb1\xcb\x33" +
+       "\x5b\x8a\xe0\x8a\x3a\x14\x83\xb4" + "\xa6\x2b\x0b\xe6\xa1\x8f\x27\x4e" + "\xfb\x42\x78\x31\x25\x1c\xb3\x24" + "\x08\x38\xcd\x90\x7c\xcf\xe4\xd4" + "\x78\xf8\x5e\x69\x86\x4d\xdf\x5c" + "\xe8\x3a\x9a\x59\x50\xab\x2a\x36" + "\xfc\x44\x58\xb3\x76\x00\xe0\x22" + "\x04\x1a\xe7\xc8\xb1\x6e\x87\xa6" +
+       "\xd9\x0d\x72\xce\xff\x4b\x34\x73" + "\xa1\xe6\x3b\xfe\xc0\x16\xa6\x62" + "\x2a\x16\xec\x41\xbc\x17\x41\x30" + "\x0d\x67\x13\x3e\xf6\xb1\xbe\x79" + "\x6d\x3a\x90\x68\xc5\x3f\xaa\xcc" + "\xaf\xfe\x31\xf5\xac\x57\x9b\x99" + "\x55\x30\x17\xdf\xd7\x95\x63\xab" + "\x0f\xf8\x72\xfc\x97\x1d\x7f\x7b" +
+       "\xe6\x4a\x28\xa6\xd9\x91\x9a\x48" + "\x6b\x86\xad\x69\x31\xd4\xe6\x47" + "\x97\x7f\x17\x39\x33\xe5\xe5\x93" + "\x80\xeb\x59\x2c\x8a\x2c\x5d\x23" + "\x46\xc5\xe9\x94\x77\x69\xde\xed" + "\x83\x43\x93\xd5\xbc\x75\x42\xf9" + "\x53\x46\x82\xec\xbf\x71\x2f\xac" + "\x8a\x3d\xd0\x17\x67\x09\x52\x14" +
+       "\xd2\x15\xf7\x7a\x71\x64\x17\xc4" + "\x96\x4a\x13\xd0\x94\xf5\xf7\xe2" + "\x56\xc9\x1e\xa4\xef\x73\x18\x2c" + "\x04\x13\x82\x77\xf6\xb4\xe7\xe4" + "\x4a\x37\xd5\x88\x97\xff\xc8\xe5" + "\x5b\x3d\x82\x80\x63\x5e\x91\x2b" + "\xe2\x8f\xee\xb2\x55\xc7\x6b\xea" + "\x51\x26\x11\xe7\x4c\x62\x57\x66" +
+       "\x15\x49\xcb\x8a\xac\xb3\x30\xfd" + "\x60\x4b\x00\xe1\xbf\x18\x22\x8c" + "\xcc\x5d\xc2\x4d\xfe\x4c\xa6\x80" + "\xda\xb9\xd0\x95\x6e\xf2\x06\x05" + "\x37\xef\xc3\x41\xfd\x94\xaa\xab" + "\x26\xef\xbc\x89\x9d\xd2\x66\x23" + "\x63\xea\xe4\x4b\x8f\xe7\xd0\x6b" + "\x1f\x33\x21\x2e\x5f\xf3\x86\x06" +
+       "\xce\xd9\x90\x05\xf3\xc7\x0f\xcb" + "\x3b\xd5\x0a\xea\xd9\xc3\x22\xc0" + "\x33\x29\xba\x84\xb3\x29\xc4\xa9" + "\xcf\x92\xb8\x9d\x36\x52\xe6\xfc" + "\x52\x8d\x51\x1f\x62\x28\x70\x48" + "\x32\x31\x38\x10\x1e\x7d\xdf\x25" + "\x5b\x79\x36\xaa\xbd\x0e\x17\x3f" + "\x47\x7e\x95\x34\x4f\x88\x31\xa9" +
+       "\x4a\xf1\x33\x58\xea\xfb\x39\xdc" + "\x33\x0f\xd5\x88\xc1\xa3\x10\xb0" + "\x2c\x75\xf5\x76\xbc\x45\x61\xcd" + "\x77\xde\x12\x7e\x21\x25\x3b\x11" + "\xa5\x39\x18\x04\x66\x78\x41\x62" + "\xd7\x09\xf3\x0e\xcb\x58\xca\x95" + "\x49\x22\xd0\xa2\x9d\xcc\x02\x6d" + "\xbb\x3a\xfd\xb8\x4b\xb5\x45\x87" +
+       "\xca\x5a\xce\xda\x01\xf1\x7a\x15" + "\x67\xa2\xa6\x11\xf2\xbc\xfd\xc4" + "\x09\x86\x9c\xc4\x40\xf3\xdd\xda" + "\x65\x4a\x60\xe9\x52\x9f\xe4\x97" + "\xd5\x2a\x7e\x93\x90\xe7\xe8\x9b" + "\xf1\x17\x6e\x32\x08\x25\x6e\x84" + "\xdc\xc0\xbb\x0b\x7a\x00\x38\x3f" + "\xd6\x16\x1e\xb1\x3f\x60\x03\xcf" +
+       "\xfe\xbc\xd3\x4e\x0a\x15\x89\x05" + "\xb9\x0c\xd8\x6c\x5c\xb6\x62\xf4" + "\x5d\x1c\x53\x29\xa8\xad\x12\x34" + "\x75\xa6\x14\x2f\xe7\x69\xe9\x90" + "\x4c\x5b\xb9\xc7\x06\x89\x6c\x48" + "\x0c\x78\xb4\xbc\x4c\xa9\x67\x5a" + "\x85\xf9\x2d\xd2\x13\x15\x61\xde" + "\x0c\xe0\x1b\x48\x9a\x86\xb4\xba" +
+       "\x1f\x8f\xd9\xb8\xc5\xa4\xea\x2f" + "\x50\x02\x05\x41\x9c\x02\x09\x7c" + "\x2f\x13\x56\x1b\x77\x42\xfa\xd4" + "\xe5\x35\x12\xda\xf1\x57\xb2\xec" + "\xaf\xae\x46\x6a\x58\x21\x7e\x61" + "\xae\x3e\x65\xd4\x00\xf3\xef\x65" + "\x01\x2a\x56\x03\xad\x13\x7a\xf6" + "\x27\x70\xc7\x70\x87\xfa\x7f\x95" +
+       "\x2f\x1c\xc1\x46\x90\xc4\xf2\x89" + "\x18\x08\xd5\xd7\xd6\x06\xbc\xbd" + "\xe2\x51\xbe\x82\x60\xc1\xdf\x13" + "\x95\x98\x71\xc1\xf6\x3a\x0b\x71" + "\x75\x84\xdd\x61\x43\x46\xd5\x0b" + "\x29\xe0\x44\x45\xd3\x8e\x8a\xa1" + "\x7d\xbb\x3f\xdc\xcf\xd2\x1a\xe1" + "\x8a\x78\xe8\x79\x9b\xd7\x77\xb1" +
+       "\xd5\xf1\x42\x74\xe0\x00\xf8\xd6" + "\xab\xe3\xe0\x66\xd1\x07\x56\x47" + "\x47\x40\xc6\xb7\x16\x7f\x80\x82" + "\x3d\x88\x49\xa7\xe3\xe1\x58\x88" + "\x10\xee\x31\x82\x0b\x12\x59\x58" + "\xce\x1e\x8a\x63\xeb\xe7\x80\x1b" + "\xa4\x73\xaa\xc6\x5a\x52\x72\xcb" + "\xac\x23\x44\x84\x3d\xea\xcd\xa7" +
+       "\x3e\xed\x80\x6b\xb0\x8d\x3a\x86" + "\x13\xfa\xd3\x75\xe3\x47\xa7\x19" + "\x01\xf7\xc8\x69\x2e\xcf\x35\x5a" + "\xe9\xbb\xe5\xf8\x13\x04\x9f\x76" + "\x6a\xe5\x64\x1d\xc0\x36\x6d\x3b" + "\x96\x98\x6a\x45\x32\x2b\xd9\xb9" + "\xda\x9c\x8e\xcf\x70\xce\x47\x0d" + "\x64\x98\x01\x6c\x5e\x35\xe3\x19" +
+       "\xed\x23\x51\x02\xac\x1a\x10\x7f" + "\x06\x06\xad\x93\xef\x93\x6e\xf1" + "\xd1\x85\xcf\x46\x48\x89\xfe\x89" + "\x0e\x91\x8e\xf7\xcb\x0c\x1d\xe3" + "\x78\xf6\x61\xd5\x1c\xab\xab\xbc" + "\x33\x28\xc9\x87\xc8\xe5\x31\x73" + "\x8d\xf6\x72\x0e\x26\xad\x38\x63" + "\xc3\x05\xdb\x35\x3e\x05\x0c\x80" +
+       "\x08\x6b\xb0\xa1\x76\xeb\xe2\x81" + "\xc9\x82\x7e\x8d\x78\x55\xae\x81" + "\x96\x8a\xf7\x48\x38\x3e\xec\x03" + "\x01\x9b\xa3\x81\x53\xf7\xb4\x1b" + "\x26\x8a\xee\xeb\x1c\xb0\x4e\x42" + "\x2c\x8f\xae\xd4\xf5\xf7\x11\x13" + "\xf1\x01\x8c\xaf\x76\xb0\x3a\x15" + "\x77\xc1\x02\x5e\x83\x4c\xc9\x2e" +
+       "\x38\x7c\xae\xf8\x07\xc0\xd0\x5e" + "\x92\x01\x74\x3d\x5c\x7a\xb0\x6d" + "\xb3\x6d\xe3\x5f\x2a\x9c\x5e\xbe" + "\x46\x50\xe9\x76\x7a\xd5\xb9\xd5" + "\xf2\x20\xba\x8e\xe7\x32\xac\x54" + "\x52\xa3\xb9\x71\x8f\xca\x11\xef" + "\x58\xa6\x98\xff\x3e\x37\x5e\x30" + "\x67\xb6\x3e\x82\x00\xa1\xe5\xff" +
+       "\xcf\xee\x8c\xdc\x00\xc8\xb7\x46" + "\xa5\x94\x59\x81\x2d\x9c\xe4\xd6" + "\xea\x56\x62\xbb\xfc\x14\x78\x6b" + "\x22\x10\x6e\x4a\xfc\x51\x8f\x7e" + "\x38\x20\xde\xca\x83\x53\x80\xf9" + "\xea\xfb\x54\x74\x31\x2f\x76\x9f" + "\x68\x80\x38\x65\x29\x0c\xba\x5a" + "\x51\xb2\x1c\x72\xfa\x61\x75\xa2" +
+       "\xcf\x32\x5e\x94\x38\x49\x14\x5c" + "\xa6\x91\x82\x5a\x75\x7e\x99\x9e" + "\xd6\x07\x6e\xfc\x46\xe8\x70\x05" + "\x7d\x44\x74\x1e\x64\x13\x68\xe2" + "\xe2\xf2\x1f\x72\xce\x10\x17\xbf" + "\x3d\xe8\x14\xf8\x19\x08\x45\xea" + "\xd2\x7a\x69\xed\x0b\xa7\xf0\x27" + "\x36\x3f\x6b\x08\x99\x98\x36\x90" +
+       "\xdb\xcf\x46\xdb\xfc\x40\xff\xe9" + "\xc4\x94\x7e\x5e\x15\x67\x52\x1b" + "\xbf\xb3\x00\x97\xc5\x6b\x98\xb8" + "\x28\x31\x8c\x0c\x59\xaf\x8c\xc9" + "\xeb\xbb\x1b\x30\x5d\x01\xfb\xd1" + "\xa9\xd1\x2f\xba\x28\x4f\xe6\x18" + "\x70\x5b\x36\xc0\x7e\x78\x12\x92" + "\x04\x6c\x38\x98\xd0\x51\x4b\xc6" +
+       "\xd2\x32\x17\xe5\x11\x7b\x47\x57" + "\x0e\xfc\x38\x25\x28\xeb\xd6\xdf" + "\xc5\xee\x39\x3b\xcc\xb0\x43\x5c" + "\x57\xcc\x36\xcb\x78\x27\xf1\x6a" + "\xae\x25\xc4\x06\x2d\x85\xb0\x70" + "\x9b\x1b\x22\x5c\x8c\x2f\xf9\x6d" + "\x9c\x6d\x82\xce\x9e\x4f\x8d\x6c" + "\xc3\x59\x93\xb4\x7b\xba\x9a\xf5" +
+
+       "\xa4\x3a\x1d\x42\x2e\x2c\x7e\xc3" + "\x40\xa8\x4f\xe8\x7c\x40\x26\xf9" + "\x1c\xe4\x54\x14\x3d\xc0\xab\x18" + "\x44\xf6\x7a\x3f\xcd\x5e\x60\x26" + "\xbf\xea\xa5\xd6\xa6\x41\x23\x24" + "\x8e\x66\x6b\x21\xf4\x84\xdb\x1e" + "\x02\x01\x01\x04\xb8\xed\x36\xd8" + "\x8c\x1d\x5e\x94\xe7\x7c\x33\x5b" +
+       "\x82\xdc\x3d\xd2\x86\x6b\x07\x4c" + "\xf0\x43\x01\x7e\x4c\x34\xfd\x03" + "\xc5\xf2\x7a\x31\xff\x62\x53\xa9" + "\x4f\x7a\x8b\xe1\xb7\x3d\xdd\x0a" + "\x1b\xe0\x60\x82\x3f\x3e\x67\x9c" + "\x91\xcc\xa1\x54\xe5\x49\xeb\xfb" + "\x33\xe4\xf2\x92\xf2\x1b\x35\x91" + "\xeb\x41\x11\x85\xec\xe7\x55\xc7" +
+       "\x04\x38\x9f\xda\x68\xe3\x9a\x34" + "\x9c\x34\x64\xa1\xfe\x07\x0f\x47" + "\xa5\xba\x62\x85\xc9\x4c\x2f\xd5" + "\xf3\x0d\x29\x2b\x86\x9e\x4a\xc7" + "\x24\x1a\x47\x43\x35\xaa\xa1\xd3" + "\x11\x45\x19\xb8\xbe\x46\x94\x23" + "\x4d\xd4\xdc\x81\x00\xdd\xc2\xbe" + "\x2d\xc8\x2a\xc4\x0f\x7f\x3d\xca" +
+       "\xd5\x06\x32\xf2\x47\xdb\xf5\x2b" + "\x52\x01\x26\x1d\x20\x34\x6d\x2f" + "\x9a\xf8\x8f\x3f\x53\x76\xb8\x17" + "\x58\xa4\x8f\x37\x0c\xc3\x57\x51" + "\x36\xb9\x4f\x2d\xc5\xc5\x17\x75" + "\xdc\x8c\x51\xe6\xac\xf7\x22\xef" + "\x64\x7a\x84\xbf\xe6\x83\xb4\xde" + "\x89\xfa\xe0\x92\x58\x45\x08\xf5" +
+       "\x60\x31\x58\x9b\xa6\xc2\x18\xb4" + "\x94\x91\xe5\xb4\xd4\xfc\x74\xbe" + "\xff\xe3\x83\x3c\xaa\xee\x78\xf1" + "\x9b\xf2\x96\xe2\x95\xf8\x51\xe0" + "\x4a\xb8\xce\x06\x38\x52\x23\xd0" + "\x6b\xfe\x11\xe1\xce\x48\xce\x5a" + "\x45\x55\x04\x1c\x49\x3a\xe4\x40" + "\x46\x21\x52\xdd\xdd\x86\xfa\xf3" +
+       "\xb5\xc5\x8e\x90\xfa\x16\x96\x95" + "\x2d\xb1\x1a\xa0\x1d\x66\x2d\x88" + "\x8a\xae\x82\x43\x82\x60\x9f\xc4" + "\x5e\x3f\x13\x5d\xeb\x92\xdf\x5c" + "\xc1\xc9\xf6\x5e\x42\xcc\xce\x98" + "\xee\x84\x4d\x66\x82\x66\x2d\xb5" + "\xc4\xb8\x25\x6f\xd8\x5e\x28\x9e" + "\x88\xbe\xde\x48\xc7\xcd\x80\xeb" +
+       "\xa0\x2b\x22\xec\xc1\x94\x97\x2d" + "\x48\x5d\x3e\x52\x2f\xf4\xdf\xc3" + "\x6b\x84\xe4\x0f\x70\xd5\x7c\x4a" + "\x74\x51\x13\xff\x13\xb1\xc5\xef" + "\x85\x5e\xb0\xc6\x5b\xb2\x30\x26" + "\x77\xd0\x4c\x65\x29\x30\x6d\x0a" + "\x9d\xb8\xd8\x32\x4f\xf5\xf1\xb4" + "\x27\xfc\x27\x16\xf2\xaf\x3b\xde" +
+       "\xd4\x04\x73\xdf\xd8\x59\x96\xab" + "\x8e\x0e\x21\xff\x1b\xcf\x1b\xb7" + "\x60\xbd\x3f\xd7\x8b\x43\xa2\xa9" + "\xde\xb4\x11\x5d\x1f\xcd\x95\x45" + "\x9d\x85\x35\x48\x9a\x32\x0d\x9c" + "\x56\x6e\xbb\x7d\x2d\x0d\x0f\x4a" + "\x4e\x8a\x92\xdf\x5e\x8e\x03\xc6" + "\x54\xd1\x5a\x8f\x21\x96\x42\xc9" +
+       "\x3e\xdf\xa2\xa4\x3b\xb8\x83\xb8" + "\x63\xa3\xe5\x44\xc2\x7c\x5b\x04" + "\xde\x96\x0d\x4e\x73\xd7\x2b\xa4" + "\x65\xc1\x93\x8d\x47\x75\x25\xb9" + "\x8e\x13\xc8\x73\x26\x01\xf9\xe8" + "\xbf\x84\x7d\x60\x4d\xe7\x8e\x5a" + "\x63\x43\xea\x49\x50\xbb\xec\x1b" + "\x86\x32\xda\x5a\x14\x61\x4b\x1d" +
+       "\x15\x3b\x09\xaa\xb5\x78\xb6\xeb" + "\x0c\xb4\xe2\xd3\x44\xdf\xac\x0e" + "\x9f\x19\x89\x20\xc4\x23\x42\xbc" + "\xa4\x06\x0a\x49\xb4\x2b\x25\x0e" + "\xf7\x5d\x2c\xcc\xb5\x79\x64\x1e" + "\x8a\x32\x94\xba\xd2\x22\x69\x8b" + "\x8c\x94\x8b\x21\xe7\xcc\x78\x42" + "\x39\x4f\x06\xe6\x5c\x99\x7e\x94" +
+       "\x94\x69\xd9\xf1\x65\x2d\xf3\xcd" + "\x18\x2b\x5b\xb7\xf3\xd8\xb3\x8b" + "\x98\x77\x30\xcb\xa3\xd2\x95\x5a" + "\xb5\xa8\x15\xcb\xcc\x29\x86\xdf" + "\x26\x49\x8c\x54\xbe\xdc\x5b\x37" + "\xa6\xb3\x25\x3c\xc6\x58\xad\x94" + "\x88\x48\xac\x8f\x52\x0d\x4e\xe9" + "\xe3\x5b\xba\x69\x46\x77\xbe\x9c" +
+       "\xc4\x6e\x0c\xa7\x40\x38\xa3\x08" + "\x95\x11\x31\xe0\xf7\x19\x88\x9e" + "\x02\xb2\x8a\x70\x96\x9d\x20\xed" + "\x27\x3a\x94\xce\xe7\xc4\xd7\x10" + "\xa1\x49\x9b\xa2\x17\xb3\x2f\x37" + "\x1f\x7d\x62\x46\xb3\x7f\xa6\x57" + "\xec\x39\xdf\x7c\x1e\x56\x12\xf9" + "\x17\x8f\x7c\x6f\xf2\xe6\x3c\xfa" +
+       "\xc1\xed\x2f\x78\xe7\x6d\xc1\x04" + "\xc4\xe7\x3a\x09\x1a\xc1\xe2\xfe" + "\xb1\x90\xde\x3d\x85\x7d\x7a\x35" + "\xdc\x23\x69\xce\xf2\x6a\x13\x68" + "\x36\x45\x86\x8e\x44\x9b\xaa\x0a" + "\x2f\x1c\xaa\xfe\x52\x34\xb5\x16" + "\x55\xd9\x46\x59\xd1\x94\xf4\xe8" + "\xe3\x69\x15\x3b\x51\x16\x31\xb5" +
+       "\xe7\xe3\x51\xbe\x7d\xfd\xeb\xdd" + "\x31\x68\x02\x7f\x40\xfc\x25\x0b" + "\xd1\x5f\xe4\xac\x3b\xad\x3b\x4f" + "\xa7\x09\x68\x70\xba\x32\xb3\x8c" + "\xca\x3f\xb9\xd6\xb1\x60\xe1\x40" + "\xed\xbd\x28\x8b\xdf\x8e\x36\x85" + "\xfd\xc2\xb4\x90\x8c\x0a\x6f\x26" + "\x4f\xd2\xaa\xff\xf6\x87\xd9\xaa" +
+       "\x3b\x62\x1b\x4e\x42\x0d\x31\x9f" + "\xa5\x66\x62\x81\x9b\x74\x45\xf0" + "\x27\x78\xdb\xa0\x51\xd7\x4f\x94" + "\x59\x72\x1d\x68\xa6\x0d\x12\x80" + "\x88\xc5\xa9\x31\x0d\xd2\xcd\x00" + "\xf1\x4b\xae\x97\xd3\xab\xf2\x7b" + "\x6a\xc0\x08\x6b\x90\x22\x5a\xf7" + "\x8b\xdc\x12\x4a\x84\xe5\xa3\x0f" +
+       "\x92\x2d\x3f\xf2\x62\x34\x21\x91" + "\x78\x40\xb9\x60\xbd\x71\xab\x6c" + "\x20\xde\x6c\x17\x63\x0a\xdd\x6b" + "\xbc\x54\x4d\xee\x0c\xb2\xc9\x54" + "\x2f\xc0\x2a\x9f\xaa\xd8\xd2\x3c" + "\xb0\xed\x6e\x20\x17\xe6\xf8\x03" + "\x34\x64\x08\x93\x16\x8e\xf6\xc7" + "\xb9\x3d\xdd\x92\xc5\x69\x14\x83" +
+       "\x41\x22\xba\x69\xfe\x2c\x5e\xf3" + "\xbd\xd5\xf4\x8c\xe0\x6c\x44\x95" + "\x92\x4f\xdb\xb8\xcd\x1b\xba\xdc" + "\x58\xd9\x70\x59\x8e\xae\x79\x96" + "\x4b\xb9\xd5\x40\x45\xb4\x9c\x95" + "\xd2\x1f\xa3\x33\x14\x78\x56\xad" + "\xc1\x2b\x00\x1b\xd1\xc3\xd4\xc7" + "\xe3\x53\xc8\x8a\xcc\x81\xa2\x59" +
+       "\xcd\xb1\x28\xdd\xc0\xae\x75\xfd" + "\xc2\x4d\x37\x7a\x05\x02\x12\xc7" + "\x2f\x62\xf0\x08\xe4\x2b\x6a\xab" + "\x58\x8b\x26\x12\xa1\xd0\x4a\xcb" + "\x94\x3a\x19\xf5\x7c\xed\xf8\x34" + "\x2b\x9c\x45\x1c\x7e\x16\xcd\xba" + "\x74\xe2\xbc\x57\x54\x62\xcc\x24" + "\xec\x60\x40\x2d\xa8\x64\x71\xf4" +
+       "\x1b\x75\xac\xe2\x5a\x6e\x5d\x0f" + "\x69\x45\x4d\xd4\xf3\xb3\x09\xc6" + "\x33\x4c\x96\x0b\x80\xac\xc4\x38" + "\x05\xc5\x43\xc1\x1b\x45\xf9\xde" + "\x86\x75\x4d\x39\x95\x92\x1f\x98" + "\xd1\xa6\x58\xd0\x9b\x1e\x0d\x4c" + "\x3d\x80\xe8\x07\x1c\xcf\xa4\x76" + "\xd6\x01\xdd\x4d\x33\x76\x5f\x2b" +
+       "\x5f\x3c\x3f\x65\x65\x74\x7d\xfe" + "\xb1\xfe\x40\xf0\x5e\xd4\x3d\x28" + "\xfe\xed\xb7\xf3\x9b\x59\xfe\x91" + "\x11\x93\x37\x80\xad\x39\xf0\x5f" + "\x49\xfa\x96\x4e\x5b\x99\x76\xbf" + "\x94\x50\xe2\xa3\xb2\xb6\x40\x26" + "\x74\x3f\xc8\xc1\x41\x63\x09\x8b" + "\xc3\x0a\x56\xfa\x84\xc8\xbe\xd2" +
+       "\x05\x14\xf3\xb9\x6b\x57\x6b\x09" + "\x5e\x2b\xb0\x62\x87\x22\xfc\x40" + "\x18\x61\x2f\xe6\xbb\xbd\xb2\x42" + "\x1a\x49\x03\x73\xf7\x80\x8d\x62" + "\x96\xbe\x33\x8f\xfd\xd8\x7e\x89" + "\x0a\x8d\x49\x48\xca\x69\x56\x4d" + "\xef\x9d\x9c\xe9\x1a\x40\x4c\xf7" + "\x5a\xb8\x44\x65\x5b\xeb\x38\x79" +
+       "\x88\x12\xf2\xe7\x12\xd3\x0b\x43" + "\x33\xe3\x94\x87\x25\xa7\x81\x73" + "\xfc\xd2\x53\xb2\x8b\x2f\x5d\x94" + "\x9e\xff\xa3\xbe\x85\x35\x59\x79" + "\x06\x60\xaf\x8d\x7f\xf6\xc3\xb0" + "\x77\xd8\xa6\x19\x85\xd0\x48\x78" + "\x4f\x1b\x21\x62\x1b\x70\x38\x6e" + "\x6d\x39\x06\x05\x6e\xf0\x07\xaf" +
+       "\xff\xb8\xfa\x91\x8d\xc8\x9a\xe5" + "\xed\x96\x7c\x3f\x0e\x1c\x5e\x2f" + "\x79\x50\x08\xb4\x16\x8a\xf2\xff" + "\x9f\xc0\xe0\x94\x9e\x5f\x76\x8d" + "\xbe\x37\x03\xa0\xce\x3e\xa5\xd2" + "\x88\xd0\xfa\x4a\xbd\x5d\x21\x98" + "\x20\x89\x23\xa9\xa9\x6f\x2b\xa3" + "\x2a\xed\xd9\x64\x15\x80\x65\xe1" +
+       "\x54\x13\x98\x8f\x24\xdf\x21\x85" + "\x59\xa2\x88\x35\xec\x23\x7e\x58" + "\x2c\x99\xa0\xd7\x81\xf2\xed\xcb" + "\x07\x14\x96\x38\x55\x0a\x93\x06" + "\x21\xbe\x5b\xbe\xeb\x0d\x32\x09" + "\x7f\x81\x91\x24\xb5\xa5\xff\xa7" + "\x60\x51\x06\x09\xd9\xb4\xc8\xe6" + "\xa9\xd2\xf6\xff\x92\x39\x4f\xac" +
+       "\x76\x9c\x7b\x56\xf5\xc8\x5d\x5c" + "\xc6\x9a\xd1\x96\xbe\xcc\xe0\xaa" + "\x5f\xa2\x26\xcf\xa8\xf8\x71\xd4" + "\x08\x52\x36\x37\x4a\x70\xf9\x1d" + "\x05\xda\x45\xa1\x1b\x54\xbc\xab" + "\xaf\xd8\xb7\xf5\x3d\x32\x43\x9d" + "\xdd\x53\xe2\xf1\x92\xb0\xaf\xa3" + "\xcf\x36\xcb\xdb\x79\xeb\xa7\xc4" +
+       "\x23\x91\xaa\xa3\x15\x6f\x4d\x2e" + "\x42\xd3\x4d\x38\x8c\x9c\xff\x33" + "\x0c\x1b\x2d\x8f\x17\x86\x16\xb0" + "\x62\x05\x6d\xbd\x7d\xd8\xae\x66" + "\xe8\x66\xa4\x4e\xac\x76\x31\x40" + "\x7b\xbe\x10\x1e\x0c\x8f\x4d\x15" + "\x4b\xa4\xd1\x58\x76\xf7\x75\x5f" + "\x05\x39\xa5\x33\x10\x98\xb2\xc9" +
+       "\x01\xb1\x7f\xa4\xf5\x73\xbd\x56" + "\xfb\x59\xbf\xfb\x84\x86\x25\x36" + "\x2b\x84\x4c\x86\x38\xdd\xc8\x43" + "\x03\x87\x4e\xf5\x92\x65\x46\xf1" + "\xc5\x78\x06\xd1\x92\xc3\x37\x11" + "\x8a\x91\xd5\xf0\xde\x82\xa8\x86" + "\xd0\x33\x10\x2d\x4d\xd2\xe1\x8e" + "\x26\xe9\x76\xe3\x62\xe1\x9c\x64" +
+       "\x66\xda\x53\xcc\xa3\xb2\x4e\x2e" + "\x4e\x9b\x7a\xf1\x71\x8a\x70\x04" + "\x2c\x5b\xe0\x0d\xb2\xc7\xfd\xdb" + "\x01\xa2\x07\x49\xee\x9a\xdc\x4c" + "\x66\x55\x47\x6c\xfc\x8d\xcc\xe5" + "\x91\x16\xbe\x47\xfb\xcb\x83\x2b" + "\xfd\xc3\x05\x4c\xa7\x33\x58\x69" + "\xb0\xde\xb0\x43\x72\x8a\x93\xee" +
+       "\x0f\x8f\x42\x3f\x77\x25\x86\x07" + "\x1f\xed\x3d\x4c\xa9\xdb\x63\x9b" + "\xbd\x51\x67\x35\x44\xae\x2a\x85" + "\x80\x1c\x2f\x3b\x11\x49\xec\xe2" + "\xfb\x20\xc4\x73\x54\xf3\xb0\xed" + "\xc3\x55\xc2\x0b\xab\xcc\x63\xd6" + "\xa9\x46\xae\xcf\x5d\x01\x3e\x1c" + "\x84\x7d\x18\x1f\x99\x89\x55\x98" +
+       "\x1a\x3d\x8b\xb7\x1e\x4f\xd3\x2c" + "\x0e\x4c\xf8\x5f\xc6\xfa\x13\x17" + "\x60\xec\x9c\xc2\xc9\xfa\xe9\xde" + "\x52\xa5\x7a\xb2\xfd\x7b\x91\x53" + "\x9f\x12\x64\xee\x4d\x53\x6f\x89" + "\xe0\x1e\xeb\xdb\xf2\x23\xa5\x76" + "\x27\x11\x59\xd2\x09\x33\xc1\xe1" + "\x6c\xf6\x4c\xad\x57\x1d\x6f\x87" +
+       "\xa9\xa3\x76\xb5\x89\xc7\x32\xc6" + "\xc8\xd7\x0d\x69\xf2\x21\xc0\xcf" + "\x6d\xad\x84\xeb\x32\xea\x55\xcf" + "\x66\x95\x05\x72\x2b\xb7\x70\x61" + "\x28\xf2\xa5\xcf\x10\x56\xa0\xfb" + "\x1a\xbf\x4c\x89\x15\xdd\xb3\xc1" + "\x36\xf4\x4f\x31\xf0\x24\xc5\xc6" + "\xdd\xff\xa1\x07\x61\x0c\x7e\xb2" +
+       "\xbd\xc1\xe9\x3a\x58\xa1\xa7\x7a" + "\x40\xe2\x7c\xe3\x98\x6d\xaf\xe0" + "\xb4\x38\xab\x28\xd9\x42\x43\xe5" + "\xca\x98\x1c\x0a\x07\x50\xb7\xe8" + "\xf2\x58\x23\xe0\xaf\x86\xce\xef" + "\x28\x12\x92\xea\x56\xb8\xb8\x31" + "\xfc\x67\x1c\x0a\x12\x19\x2a\x05" + "\x59\xad\xae\xe3\xa4\x9e\x06\xb4" +
+
+       "\x19\xf0\x8d\x55\x9e\x43\x51\x9f" + "\x27\x2b\x71\xac\xba\xa4\x0d\x23" + "\x24\x5a\x18\x55\xe3\x19\x89\x51" + "\x50\x8f\xb7\x84\xdd\xfc\xce\x4d" + "\x5a\x4c\x7d\xa4\xb2\x0f\xd9\xa7" + "\x9e\x00\x0e\xb3\xbf\x9a\xac\x55" + "\x73\xd2\xee\x74\x59\xc3\x2f\xfd" + "\xaf\x8f\xea\xdb\x4c\x82\x2d\xb7" +
+       "\x89\x92\x7d\xef\xb5\xb2\x9d\x54" + "\x5a\x01\x7f\x19\xa8\xd4\x80\x24" + "\xb6\x93\x04\xc4\x0b\x59\xd5\x61" + "\x31\x03\x78\x6f\x2e\xb5\x55\x3a" + "\xb0\xad\x9e\x30\x15\x81\xeb\x40" + "\x25\xc6\xe5\x92\x5a\xde\xa7\xde" + "\x5a\x3d\x6a\xcc\xf0\x31\xd6\x64" + "\x61\xdd\xe8\x93\x7c\x9d\x5e\x9d" +
+       "\xdd\x2b\xc8\x04\x8d\x58\x7a\x1b" + "\xfd\x9d\x31\xf8\x34\x55\x00\x68" + "\x80\x95\xeb\xd8\xb5\x55\x8a\xde" + "\x81\xca\x5b\x8d\xda\x86\xa8\x5e" + "\x4d\x0b\x2a\x25\x01\x0a\x53\xe8" + "\xa1\xa0\xea\x35\xfe\xb4\xff\x1b" + "\x63\x95\xe9\xd8\xb1\x28\xd8\x2a" + "\x87\xcd\xf9\x95\xf5\x6e\xe9\x7d" +
+       "\xe5\xe0\x84\x1e\x41\x60\x68\x19" + "\x93\x4c\xa3\xae\xd3\x84\xdb\xa5" + "\x32\xa7\x73\x70\x19\xbb\xd5\xf9" + "\xc0\xd7\xcf\x6b\x56\xfe\xd2\xb8" + "\xfa\x82\xeb\xf3\x36\x5f\x77\x45" + "\x58\x8b\xff\xfd\xcc\x0c\xb2\x8c" + "\x10\xc1\x74\x83\x5f\xb6\x59\x16" + "\x9a\x78\x0c\x33\x22\xa4\xb4\xb8" +
+       "\xdc\x73\xa9\x7e\xe5\x41\x57\x74" + "\x2e\x8f\x88\x20\x70\xca\x00\x5c" + "\xf1\x9c\xfd\x45\xcf\xe3\xdc\x7c" + "\x72\xf8\x07\x55\xf1\x1e\x74\x8a" + "\xec\x4c\x6b\x19\x2f\x1c\xc5\x47" + "\x18\xa6\x7e\xc9\x43\x8e\xd0\x70" + "\x2b\x8a\xb1\x15\x5c\xa1\x0d\x93" + "\x14\x05\x61\x2f\x78\xc6\xb6\x33" +
+       "\x9f\xae\xdb\xae\x87\xff\x25\xc9" + "\x54\x0a\x88\x36\xb9\x0e\xaf\x7d" + "\x71\x0e\x4d\x9c\xf5\xdd\x84\x92" + "\xf5\x8c\x6f\x31\x93\xcf\x81\x15" + "\x52\xf4\xc1\x3a\x87\xa8\xec\x3e" + "\xfe\xef\x6a\xfb\xe9\xfc\x17\xb4" + "\xc3\x8d\xfb\xee\x46\x80\x91\xa5" + "\x00\x94\x20\x02\xac\x18\xd3\x73" +
+       "\x8b\x78\x85\x9a\xda\x35\xa5\x6b" + "\xd4\x26\x06\xbd\xae\x03\x1f\xd2" + "\x64\xdc\x73\xe8\x47\x8c\x9f\x09" + "\x7e\xc9\x8e\x01\x4d\x56\xa8\xcd" + "\x8c\xc6\x92\xde\x5c\x7a\x8d\x3e" + "\xc4\x3c\x32\x73\xa1\x35\xe0\x78" + "\x7c\xff\x80\xf8\x75\x62\xf2\x3e" + "\xaa\xed\x3e\x27\xff\x3d\xee\xa4" +
+       "\x2f\xbc\x2e\xaf\xa3\xcd\xf4\xc4" + "\x24\xfe\x4e\xcb\x3d\x84\xaf\xa0" + "\xb1\x10\xcd\x9c\xc1\x57\xb8\x53" + "\x04\x3e\x4d\x91\xeb\xd1\xc9\xdd" + "\xeb\x1d\x77\x62\xbb\xc8\xde\x7b" + "\x81\xaa\xc5\x91\xaa\x77\x92\x82" + "\xae\x91\x23\x83\xd6\x8d\xf1\x7a" + "\xca\x84\x1a\xc7\x16\xf3\x40\x17" +
+       "\xed\x73\x6d\xa5\x88\x5c\x9e\xba" + "\xd3\x54\xa0\x2c\x71\xf7\x24\x6c" + "\xe1\xea\x3b\x08\x35\xc2\x37\x4a" + "\xfd\xe9\x83\x64\xb2\x83\xa8\x04" + "\x5d\x2c\x7c\xe2\xae\xf3\x63\x0c" + "\xf1\x71\x46\xae\x8d\xa8\x1d\x0e" + "\xdb\xe1\x95\x59\xe2\xe8\x77\xa5" + "\x6a\x06\xd6\x6e\xb1\xb1\xc4\xbf" +
+       "\xf8\x31\x2b\xe1\xd8\x12\x4a\xdd" + "\xe6\x36\x77\x17\xbc\x29\x7e\x57" + "\xe8\x35\x89\xa8\x2b\x72\x53\x23" + "\x6d\x28\x5f\x01\x29\x37\x1d\xca" + "\x35\xe0\xa3\x39\xa2\xb6\xc7\x86" + "\x9f\x3a\xb0\xd3\xbf\x50\x52\x6e" + "\x6e\x53\x0d\xfd\x30\x89\xd9\x79" + "\x32\x38\x0c\xfa\xab\xbb\x4c\x8c" +
+       "\x39\x23\x3b\xa4\xc9\x38\x9b\x16" + "\xab\xbf\x32\x17\xd9\x08\x43\x88" + "\xdd\x02\xf2\x8f\xa2\x93\xb5\xe4" + "\x6c\x37\x65\x1e\x1f\xd1\x51\xaf" + "\xff\x25\x15\x74\xde\x48\xc6\x6e" + "\x28\xc6\xf4\x9f\x36\xbd\x3c\xf9" + "\x79\x9c\x12\xb1\xef\xf9\x6d\xc7" + "\x94\x72\xa6\xb7\xe2\xf2\xa5\x31" +
+       "\x1e\x1f\xb9\xca\x10\x09\x50\x2d" + "\x16\xd2\x1c\x4d\x44\x9e\xdd\xbe" + "\x52\x22\xd0\xed\x4f\xb7\x34\xd6" + "\x7a\x61\x58\x12\xe1\xf8\x60\xbd" + "\x4a\x61\x05\x9e\x7b\x53\xc7\xd8" + "\xc5\x5f\xaf\xe7\x66\xc7\x26\xfd" + "\x26\xd9\x2b\x58\x81\xb5\x60\x06" + "\xc8\x7f\xf0\xac\x44\x92\x01\x87" +
+       "\x8e\xfe\xdc\xba\x22\x73\x3b\x2c" + "\x04\x5a\xe2\xc5\xfa\x16\x06\x6e" + "\xa2\xe4\xa6\x3d\x75\x12\x3c\x0a" + "\x01\xca\x7b\x07\x7e\x95\x6c\xe4" + "\x4b\xe6\x4b\xda\xe3\xa4\x6c\xb4" + "\x78\xee\x75\x8e\x66\xda\x9b\xa5" + "\xf2\x98\xde\xa4\x84\x51\x83\x41" + "\x68\xa5\xd6\x4e\x92\x1f\xfb\x6e" +
+       "\xb6\xec\x64\xaf\xcf\x6c\xa2\xaf" + "\x75\x27\xd7\x4b\x97\x4f\x05\xe6" + "\x5a\x69\x0f\x14\x5b\xab\xcb\xbb" + "\xde\xef\x48\xe3\xa4\xb4\x71\xbc" + "\x63\xd9\x96\xcc\xbe\x52\x2e\xfc" + "\x18\x90\x5d\x5e\x5f\xbf\x0a\x15" + "\x71\x87\x56\x04\xa6\x2f\x18\xbd" + "\x83\x9f\x33\x70\x61\xc0\xb4\x35" +
+       "\x05\x06\x37\x11\xb3\xb9\x41\x47" + "\x55\xb3\x09\x5d\xf7\x72\xfa\x47" + "\x6a\x4c\x14\x7a\xac\x71\x1a\x39" + "\xca\xe3\xb6\x98\xf4\xc0\x08\x08" + "\x00\x39\xe5\x7f\xef\xd9\xae\x7e" + "\xba\x30\xa8\xe5\xa5\xa2\x57\xf1" + "\xfc\x4a\x97\x27\x91\xc0\x3e\xd1" + "\x7d\x99\x87\x0b\xa7\x10\xd7\x78" +
+       "\x49\x8c\xaf\xee\x9a\xe9\x28\x89" + "\x28\xd7\x24\x6e\x3d\xa7\x7a\xee" + "\x6c\x15\x2b\xe7\xc2\x07\x50\x4c" + "\x1d\x8a\x40\xed\xc5\x57\xcf\x5f" + "\x04\x76\x05\xb6\x39\x9e\x71\x9f" + "\xbf\x8b\x86\xc2\x01\x3c\x34\x7d" + "\x2d\x3e\x10\x7e\x4b\x25\xca\x2c" + "\xa2\xbe\x31\xf1\xa9\x38\xeb\xe6" +
+       "\x11\x19\x20\xcd\xec\xd3\xe1\x27" + "\xeb\xc0\x72\xad\x70\x9a\x11\xb1" + "\xfb\x7f\xb5\x6a\xaf\xe3\xb3\xf8" + "\x2b\xc4\x92\x5b\x5b\x68\xc1\x23" + "\xaf\x7a\x8d\xd0\xb9\xb7\x27\x2c" + "\x1c\x59\x9a\x18\xc3\x0d\x66\x0f" + "\xca\x43\xc8\xad\x02\xa1\xca\x7b" + "\x52\x76\xb2\x1a\xb4\x8b\xd3\xde" +
+       "\x52\xff\x40\x5f\x4e\xa0\x24\xc6" + "\x4a\x91\xd2\xfc\xcf\xd7\x11\x36" + "\xd6\xbf\xd3\x1f\x2b\xb4\xe8\xb7" + "\x3a\x06\x85\xfa\xfd\x40\xde\x6c" + "\x5b\x7e\x8b\x17\x49\xc4\x11\x78" + "\x13\xcc\x72\x29\x31\x09\xb6\x4c" + "\x35\x61\xb4\x33\x5e\x12\x79\xf5" + "\x6e\xe5\xa4\x88\xf7\x2e\x10\xca" +
+       "\x84\x0b\xef\x5d\x7f\x67\xbd\x96" + "\xb9\x99\xde\x97\x7b\xa8\x6f\xe9" + "\x53\x15\xbe\x4e\xc1\xfe\xd3\x5d" + "\xcd\x75\x42\x7e\xe6\x43\x57\x31" + "\x23\x83\xb4\xb1\x25\x31\xf1\x81" + "\x75\x8e\x49\x4d\xdd\xb1\xaf\xc4" + "\xd9\xda\x15\x3f\x7d\x8e\x56\x84" + "\xb8\x73\xae\xa3\x1b\xa6\xe3\xd8" +
+       "\x0d\x1b\x98\x0a\x52\xe3\xa4\x0b" + "\xa4\x41\x1a\xbd\xb3\x4c\x35\x1c" + "\x9c\xab\x9f\xdf\x3a\xaa\xab\x1a" + "\xd5\x18\xc4\x53\xd1\xa7\x01\x07" + "\x21\xb9\xf2\xdc\xef\x7c\x1a\xdd" + "\x61\x80\xf4\xbc\xb3\xf0\xee\x6c" + "\xe6\xcc\x25\xde\x98\xb5\x83\x10" + "\x34\x5e\x0a\xe9\xc7\x54\x0a\x89" +
+       "\xf4\xca\x02\x1c\x42\xb4\x2b\xa6" + "\x5a\x7b\x62\xdb\x1d\x48\x74\x6a" + "\x2d\xf5\x6b\x2c\xf6\x25\x56\x1d" + "\xa0\x46\xb2\x73\x4c\xfd\xc5\x1f" + "\x3d\x81\x31\x17\x62\xfc\x6d\x3f" + "\xbe\x54\x88\xe5\x79\xdf\x22\x83" + "\xe4\x2e\x8b\xfa\xb2\x38\x14\xe5" + "\xa0\xcd\x4a\x2d\x48\x78\x73\xbe" +
+       "\x07\x18\xac\x40\x66\x95\x35\xc5" + "\x1e\x0b\xda\x84\x66\xe5\xc1\xd4" + "\x21\x24\xb8\xe0\x97\x3f\xb3\xc4" + "\x00\xbe\x41\x7b\x17\x23\xbd\xd0" + "\xe1\x72\x7b\x14\x2e\xb4\xa4\x53" + "\x4c\x10\x77\xf7\x5f\x9f\xd3\xf8" + "\x0d\x53\xfb\xd3\x64\x4e\xe6\x36" + "\xdd\x4f\x07\x56\x67\xba\xa6\xa7" +
+       "\x71\x7c\xca\x1e\xe3\x8f\x65\x1b" + "\xb8\xda\xad\xe4\x14\x52\x94\x20" + "\x99\xc2\xf9\x11\x3f\x5d\x4e\x7d" + "\x04\x50\x84\x2f\xe7\x2a\xf6\xd7" + "\x92\x1e\x2a\xe2\x6a\x6d\x7e\x41" + "\x41\x71\x4c\xca\x85\x7f\xb6\x1a" + "\xed\xb5\x9a\x27\xc0\xd9\xb2\x44" + "\x11\xce\x57\xfa\xb8\xf0\x0b\x2d" +
+       "\xb1\x01\x6d\x4f\xdb\x18\x57\x40" + "\xa0\xe8\x11\x8f\xc2\x6b\x3c\xe7" + "\x3b\x1a\x59\xa0\x8c\xbb\x11\xac" + "\x31\x45\xcc\x0a\x5a\x9a\xd0\x12" + "\xf4\x13\xde\xe7\xee\x74\xf1\xcb" + "\x82\xd6\x4f\x04\xe6\x2b\x7e\x17" + "\x70\xaf\x48\x1c\xcb\x74\xf5\x65" + "\x7c\xcb\x61\x99\x92\x66\x59\xce" +
+       "\xe9\xba\xf6\x10\xfc\x6b\x83\x64" + "\x08\x76\x08\x0a\x6e\x61\xd5\x6b" + "\x07\x78\x0b\x2f\x63\xc4\xd5\xcf" + "\x78\x85\xa0\x61\x12\x27\x68\x05" + "\xcd\x2c\x0f\x63\x77\x37\x30\x30" + "\x40\xab\xe2\xc2\x32\xa7\xfd\x9e" + "\x92\x95\x0f\x6b\xc5\xb1\x95\xca" + "\xd8\xf2\xf2\xd0\x3e\xb2\x8f\xf7" +
+       "\x9f\xab\x6f\xbc\x4e\xe8\x9f\x98" + "\x74\x64\x0f\xc8\xb1\xe6\x0c\xe7" + "\xbc\xa1\x02\x3b\x05\xf3\x9f\xbe" + "\xd3\xaf\xc0\x99\x66\x48\xef\x12" + "\x26\x1a\x41\xe3\xf9\x57\xd9\x22" + "\x98\x5b\x48\x7b\x81\xd8\x41\x0b" + "\x19\x01\xe2\x4a\xd0\x56\x0e\x82" + "\xe0\x28\x85\x32\x1f\xd0\xe3\x81" +
+       "\x8a\x7c\x82\xbe\x77\xd4\x7d\xd4" + "\x4d\xe4\x10\xec\xe7\x69\x4a\xee" + "\x7c\xd7\x0e\x13\x38\x60\x23\xaf" + "\xf0\x65\x4c\x80\xce\x5c\x04\xf2" + "\xdb\x70\x4b\x2a\x03\x19\x87\xfb" + "\xf5\x9f\x3c\xb3\xcc\xb3\x36\xff" + "\x3d\x78\xd2\x1f\xe6\xf2\x37\x4c" + "\xd6\x71\x00\x91\xde\x7e\x11\xe5" +
+       "\xa1\x52\x87\x04\x6c\xed\x9e\xc5" + "\xb4\x41\x13\xa0\x2e\x70\xf2\x41" + "\x92\xb0\xc6\x9d\x3b\x90\x35\x6e" + "\x23\x5b\x5b\x1f\xa8\xab\x91\x42" + "\x1d\xd6\x53\xa6\x70\xaa\x73\x81" + "\x1e\xb5\x2e\x4f\xd4\x48\xb6\xd1" + "\x8f\x3f\xb9\x5a\x06\xce\xb7\x31" + "\xfe\xf4\xe2\x99\xee\x08\x54\xa5" +
+       "\x04\x44\xdc\xda\x8b\xfa\xc4\x1b" + "\xe3\x2e\xa1\xda\x34\x95\xdb\x0e" + "\x9c\x28\xf7\xa5\xb6\x81\x44\x08" + "\xd2\xb3\x8f\x9d\x1d\x46\x42\x7f" + "\x70\x3c\x29\x12\x32\x1d\x3f\xf9" + "\xa3\x3e\xb7\x6b\x59\x06\x47\xc1" + "\xad\x9c\x33\xde\xaf\x34\x08\xf8" + "\x53\x29\xf2\x81\x00\xfc\xdc\x99" +
+       "\x60\x41\xe3\x85\x09\xed\xa4\x1f" + "\xe2\xcd\x03\x7a\xc3\x7d\x6d\xa2" + "\x2d\xdf\x84\xfa\x48\x08\xac\x1d" + "\x08\x71\x69\x1b\xd6\x28\x9a\x5e" + "\xa1\x0e\xea\x14\xd9\x04\x80\xa8" + "\x20\x55\xfe\x3f\x28\x54\xd1\xa8" + "\x9c\x13\x9b\x63\xae\x2d\x42\x4f" + "\x61\xa8\xb5\xd4\x0d\xcc\xdc\xee" +
+       "\xcd\x8e\x74\xd7\x36\x16\x1d\x54" + "\x2e\x5c\x86\x7b\xf0\xab\x5a\x38" + "\x31\xe4\xdc\xe1\xec\xf9\xc2\xd2" + "\x52\xe0\x95\x8b\x25\x03\x16\xff" + "\x7a\x07\x33\x7a\x3f\x4c\xde\x0c" + "\x97\x1f\xe4\x12\x56\xdd\x5b\x67" + "\xf1\xa6\xf5\x71\xae\x81\x51\xc3" + "\xf8\x3e\x75\xae\xc8\x00\x56\xd5" +
+       "\xb4\x62\xe7\x8b\x4f\x62\x3e\xb3" + "\x13\x34\x8e\x05\xd1\xe4\x9e\x2a" + "\xfa\x05\xd8\x67\x69\x63\x8e\x96" + "\xd7\xbf\xb8\x7d\x9b\x94\x48\x98" + "\x17\x84\x3a\xd2\xe5\xd7\x08\x53" + "\xa5\x9d\xe2\xf3\x1d\x3b\x2f\x89" + "\x1f\x47\xee\x3d\x9e\x13\x5c\xc9" + "\x89\xe0\x57\xd7\x4d\x59\x31\x86" +
+
+       "\x15\x56\x09\x1f\xea\xe2\x83\x10" + "\x33\x8c\xe6\x14\x77\xad\x28\x0a" + "\xbe\x18\x88\x3d\x52\x02\xfc\x6b" + "\xcd\x50\x58\xf3\x3a\x11\x85\xb5" + "\xa1\x8a\xdf\x30\x0b\x5f\x93\x7d" + "\xac\xe3\xb7\x4a\x7c\xa0\xdd\xad" + "\xcb\x00\x2f\x55\x99\x42\xc3\x92" + "\x6c\xdf\x09\x29\xde\xd1\x3e\xc3" +
+       "\x3c\x11\x07\x3e\x48\x0d\xc4\x2d" + "\xae\x63\x8b\x7d\x39\x5d\x4a\x6e" + "\x2b\x4c\x68\x79\x4b\xa9\x82\x55" + "\x6c\xa2\x2d\x62\xd4\x33\x2b\x93" + "\x8d\xf0\xbb\x0d\x51\xf6\x34\xf5" + "\x52\x3a\xc2\x64\xc9\x07\x1d\x21" + "\x9b\xdc\x5b\xee\x0f\xce\xee\x0e" + "\x58\x55\x01\xf7\x68\x81\x17\xdf" +
+       "\x0e\xd6\xcd\x83\x5a\x90\xe7\xab" + "\x84\x01\x17\xa1\xb5\x2f\x60\x50" + "\x2a\x64\x23\xb0\xcd\x86\x98\x68" + "\x00\xfb\xe1\xa6\x90\xd0\x68\xd5" + "\x7f\x21\x59\x02\xc7\x22\x19\x5b" + "\xe4\x41\x31\xc4\xd9\x1c\x83\x93" + "\x6e\xf8\x95\x0c\x87\x35\xca\xdf" + "\x28\xe8\x8a\x56\x7a\x05\xc2\xde" +
+       "\x6d\xc1\x3c\x91\x25\x89\x8f\x56" + "\x5a\x6f\xa2\xe1\x6d\x5b\xbc\x18" + "\xae\x99\xf4\xf5\xbe\x13\xa4\xdf" + "\x84\xae\xf0\xc3\xec\x5d\x83\xf8" + "\xb0\x0a\xa4\x65\xd8\x0b\xe6\xb6" + "\x7e\x37\x4b\x19\x39\x64\x59\x65" + "\x69\x4a\x08\x92\x25\x56\xd8\xbc" + "\xe0\xed\x23\x4f\xb9\x33\xe4\x5c" +
+       "\x89\x61\xe0\x42\x3d\x52\x0d\x86" + "\x13\xff\x3a\x4e\x41\x79\x07\xbf" + "\x50\x06\xb2\xc1\xca\x6d\x61\x0b" + "\x0d\x30\x31\x21\xd1\xd6\x6d\xe6" + "\xde\xab\x99\xff\x67\xfd\xa0\xd4" + "\x0d\xc5\xaa\xc7\x50\x35\x90\xc9" + "\xd7\xb2\x46\x7c\x8b\xcf\x2e\x02" + "\xaf\x92\xbf\x3a\xe8\xb1\x33\x33" +
+       "\x5d\x36\xd6\x84\xe7\x65\xda\xc0" + "\xb8\x9f\x75\x8f\x3f\x44\xb7\xbc" + "\x30\x19\xe8\x7a\xb1\x12\xc7\x35" + "\xab\x08\x6e\x4c\xff\x8d\x42\x80" + "\x43\xf8\xfa\xa4\xef\xaf\x9d\xf1" + "\x5f\x85\xa9\xff\x8d\x53\xd8\xce" + "\xce\xc7\x3a\xbe\x9c\x40\xac\x20" + "\x1e\xa7\x2d\x88\xb6\x1f\x8c\x35" +
+       "\x82\xa5\x42\xbe\xf7\xde\xec\xef" + "\xe6\x6b\x04\x65\x80\x60\xfc\xd3" + "\xa9\xdb\xe8\x09\xc8\x13\xaf\xc9" + "\xff\x91\x14\x64\x47\x98\x6c\x1e" + "\xf7\x31\x0c\xd3\x25\x49\x57\x3b" + "\x22\x21\x2a\xac\xba\x72\xeb\xb7" + "\xe7\x59\x08\xef\xac\x0d\x6a\x77" + "\x42\x09\x90\x21\x14\xc3\xfe\x06" +
+       "\x2b\x12\x50\x7e\xb0\x94\x47\x32" + "\xa5\x7c\xf0\x4a\x8b\x4f\x74\xdd" + "\x7b\xc9\x3f\xd6\x08\x2f\xa1\x30" + "\x9d\x6d\x62\x76\x1a\x0f\x65\x39" + "\x77\x84\xa3\x1f\xf7\x47\x1b\x10" + "\x4f\x12\xdc\xd4\x19\x5f\x81\x3d" + "\x8a\xb5\x6e\xb2\x95\xae\x69\x15" + "\x87\x18\xfb\x95\x88\xe1\xcd\xc3" +
+       "\x21\x7f\x73\xf4\xbb\x2f\xc6\x7e" + "\xac\xf5\x09\x62\xab\xa5\xdb\xd8" + "\xbe\xad\xf9\xa5\xa9\xd7\xb5\x24" + "\x68\xc7\x1d\xa6\xf7\x28\x7d\x70" + "\xea\x99\xa9\xca\x0b\x46\x11\x77" + "\xcc\xe4\x92\x1c\x4d\x17\x7b\xba" + "\x2d\xbf\xd4\x18\x66\xab\x4b\x3c" + "\x79\xd2\x8b\xeb\x80\xc9\xf0\xb8" +
+       "\xbf\x91\x06\x79\x32\x89\x65\x9d" + "\xae\x36\xb7\x06\x89\x05\x61\xed" + "\x6e\x3b\xd6\xc0\x04\x2f\x2c\x71" + "\x8f\x48\x3d\xc6\xd5\x6f\xf0\x5c" + "\x41\x8e\x58\xd9\xac\x3f\x36\x97" + "\x7e\x25\x93\x2b\x62\xf7\x9b\x1f" + "\xce\xca\x7a\x66\xc4\xff\xd1\xa9" + "\xcf\x1e\x06\x0a\xaa\xa1\xf4\x1c" +
+       "\x23\x9a\x51\xc0\xb2\x75\xd6\x28" + "\xe3\x52\x69\x4f\xfe\x94\xbf\x9e" + "\x8a\x4a\x29\xa2\x67\xb7\x8b\xf2" + "\xf5\xf3\x0a\xfe\x4d\x2b\x51\x85" + "\x0d\x6a\xb1\x99\xa8\x8b\x95\x18" + "\xa7\x48\x75\xba\x0c\x43\xc2\x95" + "\x15\xe6\x6b\xa1\x10\x1b\x0d\xb3" + "\x4c\xb7\xbf\x85\x97\xbb\xeb\xe3" +
+       "\x45\x36\xe6\xb2\x5e\x3f\xb5\x07" + "\x32\x42\xc8\x84\x47\xe5\x57\xbe" + "\xcf\xd5\x14\x72\x16\xc2\x79\xd7" + "\xca\x3a\x9a\x02\xcd\x69\x79\x61" + "\xa0\x17\x70\x8a\xcd\x68\x76\xd1" + "\xe8\x7e\x9b\xbe\x9a\xd1\xb4\x77" + "\x76\x17\x16\x9c\x93\x0e\xfd\x58" + "\x72\x8a\x96\xd5\xef\xf4\xc4\xa8" +
+       "\x23\xca\xfd\xd2\x65\xb8\xee\x81" + "\x95\xf8\x8e\xcc\x08\xee\x15\x5a" + "\x14\x56\x90\x01\x0a\xa1\x8f\x76" + "\x9b\xe1\x0e\x88\xef\xb8\xf5\xef" + "\x0e\x8a\x1c\xcb\xbb\xca\xc0\xf0" + "\xf9\x38\xc8\xb8\xcd\xe9\x1e\x2e" + "\xc0\x14\x4a\x8a\xb8\xd8\x87\x05" + "\xe5\x98\xf6\x2f\x96\x78\xf2\xf6" +
+       "\x80\xda\x44\xbf\xb3\x34\x9d\x51" + "\x66\x2e\xb3\x5a\xf9\x34\x38\x28" + "\x00\xa0\x78\x62\x97\x87\x60\x6e" + "\xf6\x12\x73\x62\x0e\x96\x62\x1e" + "\x55\x1c\x90\xe6\x7b\xb2\x87\x9b" + "\x1f\xbc\xfd\x24\x38\x85\xe7\x80" + "\x7d\xc2\xac\x2f\x51\x09\xbc\xbb" + "\x5a\x3b\x14\xac\x39\x42\x39\x06" +
+       "\x99\xce\x2f\x9e\x6e\x64\x4b\x9c" + "\x7f\x85\x80\x1e\x81\x10\xa2\x68" + "\x2a\xb5\x43\x36\x44\x4e\xd5\x06" + "\x43\xb8\x8e\x0d\x63\x6d\x8d\xde" + "\x0a\x6a\x14\x42\x63\x15\x32\x70" + "\x22\x36\xaa\x5e\xf2\x26\xa8\x8b" + "\x87\x87\x13\x86\xbd\x58\x7a\x22" + "\x37\x1d\x28\x10\x3c\xc0\xb6\x43" +
+       "\xff\xde\x41\x2f\x95\x7a\xb3\x02" + "\xb7\x89\x3b\xe6\x9a\xa5\x44\x0e" + "\x51\xf9\x3f\x14\xdc\x57\x32\x67" + "\xf4\xba\x52\xd7\x05\x22\xc0\x19" + "\x92\xd6\xb7\xc4\x69\x30\xc2\x46" + "\xac\x02\x15\xfd\xc3\x92\x63\x2e" + "\x46\x08\x22\x1b\xa2\xb1\x57\x60" + "\x63\x5b\x1b\x0c\x46\xf9\x1f\xe5" +
+       "\xf0\xc0\x2f\xf0\x32\x26\xca\x7a" + "\x86\x1c\xf0\xc7\x7d\x33\x2b\xb9" + "\x7d\xdc\xfb\x5a\xbf\xc4\x4b\x62" + "\x5e\x1a\xe2\x4d\xbc\x07\x2b\x81" + "\xcc\x90\x20\x0b\x24\x37\xd1\x29" + "\x32\x21\x1b\x5a\x09\xc5\x03\x04" + "\x15\xe0\x35\x0e\xd5\x34\xca\x1d" + "\x6f\xb6\xbb\x3b\x7d\xed\x85\xf0" +
+       "\x35\x57\xae\x2e\x86\x66\xc8\xbe" + "\x3e\xf0\xb6\xf9\xf2\x01\x05\x58" + "\xc2\x74\x0e\x99\x63\x20\xff\x8b" + "\x40\xc8\x40\x9f\x3d\x4e\xdc\xfa" + "\x2a\x6f\xeb\x32\xa0\xd3\x57\x03" + "\x8a\xc9\xf1\x0d\x2e\xb2\x18\xe3" + "\x38\xdd\x2a\x50\x8d\x2d\x9a\xbb" + "\x6a\xce\x84\x4a\x7a\x95\x7e\x6f" +
+       "\x65\xe8\x81\xf7\xf9\x98\x7b\xc2" + "\x45\x13\x4e\x99\x92\xf6\xe1\x51" + "\xee\x61\x93\xe1\x16\xd5\x07\x08" + "\xef\x8a\x99\xfb\xef\x5c\x88\x13" + "\x17\x8a\x0f\x2f\xe9\xd5\x23\xd2" + "\x80\x02\xd2\xe8\x10\x20\x67\x48" + "\x98\xac\x7e\x23\x60\xfd\x02\x6f" + "\xe7\x7e\xda\x9a\xad\xbf\x51\xcc" +
+       "\x48\x36\x1f\x3d\x67\x8d\xe7\x0b" + "\x44\x26\xf8\x26\xbf\xae\x70\xb1" + "\xf5\xa6\xaa\x11\xaf\xb5\x88\x9d" + "\xb2\x0e\x93\x40\xb2\x4e\x44\x57" + "\x06\x29\xd9\x4a\x76\x4a\x96\xd0" + "\x5f\x7e\xf8\xbf\xe3\x5d\xa0\x4c" + "\x84\x90\x86\x0b\xc8\xa6\x41\x11" + "\x8d\x94\xda\x4a\xa3\xfc\x83\x31" +
+       "\x1d\x70\x09\x1e\xdd\xbc\x56\x27" + "\x80\x5c\xd4\x90\xb9\x1d\xe3\x94" + "\x84\xe5\x66\x85\xa9\x56\xe8\xb9" + "\xf3\xe3\x10\xab\xde\xd9\x87\x4f" + "\xb2\x9c\xed\x3d\x37\xcb\x6e\x16" + "\x3e\x3d\x65\x3f\x07\xc7\x14\xfd" + "\x25\xc4\xae\x92\x9b\x04\x5d\x10" + "\x11\x2e\xa4\x09\x49\x7e\x65\x7f" +
+       "\xa1\x09\xd6\xa5\x9b\xa3\x80\xc3" + "\xcb\x0e\xc1\x24\x77\x1e\x71\x6c" + "\x70\xd0\x22\xb9\xc6\x3c\xd5\xe8" + "\x84\x7d\xb5\x0a\x81\x7b\xc3\xea" + "\xa7\xca\x70\xa7\x78\xc9\x60\xe2" + "\xb5\xf4\x71\xaa\x29\x61\xf2\xdb" + "\x30\x8e\x9a\x48\xb6\xd9\xee\xe2" + "\xfe\x75\x3f\xeb\x7f\xd2\x8f\x48" +
+       "\x94\x95\x15\x6a\x07\x90\x64\xea" + "\x52\xce\x97\x1f\x6b\x4d\x42\x3e" + "\xcb\x8c\x5e\x18\x0a\xf3\x6d\xac" + "\xbf\x47\x77\x51\x80\xec\x56\xad" + "\x93\xfe\x91\x43\xcf\x5c\x93\xf0" + "\x40\x1d\x81\x03\x0f\x26\x6b\x86" + "\xbe\x9a\x7b\x9f\xb9\x47\x20\x79" + "\x84\x2d\xe4\x8e\xc8\x0b\x60\xb1" +
+       "\x23\x71\xa3\x7c\x92\x45\x58\xdd" + "\xd5\xbd\x8b\x08\x11\x13\x3f\x90" + "\x2e\x27\xc2\xa2\x65\xcf\xde\xdc" + "\xe0\x6f\x1f\xd6\x26\x6e\x35\x9e" + "\xc0\x0d\x48\x54\x9d\x9f\xad\xee" + "\x5a\xbe\x46\x14\x40\xa1\xca\x91" + "\xd1\x75\xc0\xc4\x8d\xcc\x66\x9c" + "\xb8\xc9\x85\xbc\x62\x9a\x52\x5e" +
+       "\x5f\xa8\x68\x77\xdb\xb3\x97\x2d" + "\x38\xe0\x87\x42\x33\xf6\x78\x2b" + "\xb1\x2b\x89\x6f\x67\x47\xc9\x86" + "\x00\xc2\xa9\xc0\x1a\xfb\x0b\x92" + "\xb2\x41\x20\x33\xec\xf6\x92\x42" + "\x54\x9d\x98\xc9\x37\xb9\x0b\xa3" + "\x9e\x87\xd5\xc6\xeb\x41\xf9\x39" + "\x87\xb1\xdb\xdf\xfc\x50\xa4\x76" +
+       "\x90\xa8\x29\x9c\xc3\x93\xb7\x5f" + "\xb1\x11\xa8\x87\xfd\x3b\xa0\xb0" + "\xd3\x28\xf1\x12\x49\x9e\x24\xb0" + "\xde\x3e\xed\x5a\x13\x3a\x7b\x10" + "\x32\xd9\x34\x20\x56\x99\xe1\x98" + "\x1c\xd7\xc7\x0d\x71\xc7\xce\xd8" + "\xb2\xe0\x31\xb2\x13\x37\x56\xe7" + "\x02\x8c\x96\xac\x85\xd2\x84\x62" +
+       "\xb6\x0d\x43\xee\x89\x60\x25\x31" + "\x56\x6f\x83\xf6\xd8\x9b\xce\xae" + "\x46\xa0\x85\xfb\x4b\xfc\x4c\x48" + "\xb9\xb2\x99\x15\x2c\x3e\x1e\xee" + "\xaf\x2e\x12\x3d\x90\x38\x3c\x7e" + "\x6c\x55\x70\xc7\xe0\x0c\x94\xaa" + "\xe8\xfa\x08\x1b\x63\xd6\x02\x48" + "\xba\xf8\x69\x7f\x80\x85\x8a\xb0" +
+       "\xae\x1e\x41\x05\x04\x0a\xed\x70" + "\x66\x4c\x49\x16\x8f\xb0\xde\x60" + "\xbb\x97\x37\x13\xc6\x0f\xf2\x8c" + "\x10\xc3\x6b\x0c\xf5\xf4\x30\x3e" + "\xc7\x46\x9c\x74\x29\x7c\x67\x1a" + "\x1c\x98\x1e\xf1\xf4\x93\x1d\xfe" + "\x8b\x68\x3e\x2e\xd8\x03\x73\x93" + "\x85\x9e\xaa\xa6\xa7\xf5\xae\x01" +
+       "\x20\xb9\x59\xb9\x95\xf4\x02\x49" + "\x85\xd8\xa2\xfc\xbd\xfd\xb0\x13" + "\xfa\xf0\xa2\xb6\xe7\xd9\xcb\x41" + "\x87\x0b\x43\x56\x10\xf1\xbd\xf9" + "\xb9\x19\x4d\x95\x23\xa2\x05\xd7" + "\xde\x4f\x2a\x97\x5c\xfc\xd0\x74" + "\xea\x77\x29\x91\xd6\xfe\xcb\xcb" + "\xaf\xa5\x59\xcc\xfd\x11\x06\x87" +
+       "\x57\x2f\x30\xbb\xab\x19\x72\xba" + "\x30\x27\xb3\xfa\x59\x00\xce\x28" + "\x22\x43\xf5\xa8\xa0\xdc\x26\xfd" + "\xcf\xbd\x6b\xb2\x6b\x0d\xa9\x69" + "\x8b\x63\x49\x89\xbc\xd3\x5d\xe9" + "\x2d\x6a\x2b\x92\xf1\xa4\xe1\x76" + "\xfd\x2c\x87\xd5\xb1\x3c\xf7\x99" + "\xce\xa3\x32\xdb\x9a\x14\x2b\x75" +
+       "\x6a\x23\x89\x40\xd0\x9b\xf1\xf4" + "\x0b\x0e\x3d\x31\x12\x6c\x20\x3b" + "\xb2\xae\xfe\x03\xf3\x0d\xe7\x73" + "\xe0\xef\xd1\x9b\xeb\xa0\xdb\x09" + "\x05\x53\x4e\xfc\x32\xd5\x7f\x4c" + "\x7a\x78\x3d\xe9\xed\xff\x92\xd7" + "\x10\x50\x24\xe4\xe2\xc4\x2d\xc7" + "\xbd\xbb\x66\x04\x7d\xd4\xe0\xe7" +
+       "\x43\x5c\x6c\x56\x51\xcb\x85\x6e" + "\x46\xf0\x97\x35\x19\xc9\xf9\xcf" + "\x4a\xd9\x94\x49\x0c\xe9\x54\x93" + "\x7d\x92\x47\x21\x32\x93\xa3\xe0" + "\x2b\xeb\xc1\x0d\xc1\xfa\x27\x84" + "\xfa\x19\xf3\x2f\xc2\xd8\xcf\x88" + "\x74\x52\x96\x01\x84\xe6\xd4\xe2" + "\x46\xa7\xaa\x67\x7d\x06\x2e\xfa" +
+
+       "\x11\x9f\x5f\x3e\x7f\x2a\xd9\xb6" + "\x8e\x3b\xcb\xd6\x3a\x15\xfe\x9a" + "\xbd\x00\xf8\xdd\xd7\x6d\x1a\x4d" + "\x19\x7e\xf1\xca\xc0\x3c\xc1\xf6" + "\xee\xc3\x5f\x32\x8e\xc5\xf6\x15" + "\xb2\xc3\x1d\xa3\x00\x54\x09\x71" + "\xe7\xd3\xa3\xaf\x07\x7c\x8e\x16" + "\x2d\xae\xc7\x94\xa1\x17\x84\x3f" +
+       "\xc3\x40\x95\x31\x9b\x58\x42\x28" + "\xf8\xd6\x83\xa2\x59\x0f\x49\x18" + "\xcb\x9f\xae\xda\x84\x1f\x73\xa2" + "\xa0\x3b\x68\xc3\x60\xd9\xb6\x3d" + "\x69\x10\x61\x14\xbb\x63\x5c\xc8" + "\x05\xbf\x88\x07\xaf\x36\x94\xb1" + "\xd2\x60\x74\x34\xdf\x59\x54\x90" + "\xb1\x7d\x1a\xe1\x94\xe0\xf6\x73" +
+       "\x38\x9c\x1b\xc3\x91\xbb\x85\x7b" + "\xb5\x57\xef\x48\x0b\xa9\x5a\x0c" + "\x6f\xab\x3b\xaf\x69\xb1\xde\xde" + "\x85\x36\x37\x2d\x73\xad\x10\xe6" + "\x15\x8e\xba\x02\xdf\x70\x38\xf1" + "\x71\xf7\xa7\x8c\xb6\xed\x37\x03" + "\x6c\x03\x2c\xb6\x47\xf7\xac\xe4" + "\x81\x4e\xb9\xb6\x76\xd5\x21\xd9" +
+       "\xcb\x76\x3c\xee\xc8\xa3\x06\xf3" + "\x6e\x1f\x2a\xd3\x23\x16\xf1\x3c" + "\x56\xe9\x63\x68\x64\xab\xd5\xe6" + "\x26\x5c\x00\x5c\xbe\x4c\x8a\x3b" + "\x27\xbb\xe6\x9c\xa5\x29\xd5\xdc" + "\x6f\xb1\xd4\x04\x52\xaa\xaf\xc4" + "\x8d\x79\x23\x79\x26\x4a\x62\xb0" + "\xab\x7f\x30\x6b\xf6\x6d\xe5\x85" +
+       "\x14\xd6\x9d\x85\x34\x53\x3e\x3a" + "\xee\xc8\xd0\x18\x5b\x5b\x47\x9c" + "\xd5\x51\xcd\x07\x1f\x0d\x08\x63" + "\x26\x43\x8b\xb8\xa6\xd0\xc0\xc9" + "\x6f\x29\x34\xc2\x91\x86\xc9\x1a" + "\xb6\x7f\x88\x94\xa4\x83\x0a\x2a" + "\xf2\x9c\xea\x0c\x27\x14\x51\x56" + "\xf5\x02\x48\xa2\xe8\xa6\x30\x52" +
+       "\xaf\x13\xe9\xbc\x3d\xc7\x0f\xad" + "\xcb\x07\x8a\x45\x7b\x58\x9e\x90" + "\x8a\x0c\xf0\xd4\x84\xda\x00\x13" + "\xac\x66\x44\xb5\x48\xd0\x5c\x42" + "\xbf\xd8\xe9\x90\xbe\xb9\x9c\xb5" + "\x0e\x1b\x43\x3e\xdb\x16\x16\x99" + "\xff\xec\x1a\x53\x7a\x11\xaa\xd3" + "\x3b\xdc\xf4\x59\xd3\x92\xaf\x91" +
+       "\x36\x5c\x44\x20\x07\xe2\x3e\x7a" + "\x74\x71\x87\x59\x82\xac\xd1\x71" + "\xe9\x73\x9f\x94\xf7\x39\xc5\x0f" + "\x81\x30\x2e\x98\xd7\xf3\x5c\xd0" + "\x29\x71\x1c\x7b\x0b\xe2\x58\x87" + "\xf2\x61\x9e\x56\x20\xcc\xad\xff" + "\x2d\x4c\x54\x59\x2f\x3a\x5d\xb0" + "\x53\x5e\xff\x9f\xc1\xf5\x16\xbe" +
+       "\x63\xa4\x4c\x4e\xef\x0f\x33\xb2" + "\x63\xcc\x66\x35\x87\x72\xef\xbc" + "\x00\x09\x78\xcf\xca\xd2\x61\xd1" + "\x7d\x82\x54\x5b\x39\xc5\x5d\x13" + "\xc6\x1b\xbf\x27\x2e\x05\x8f\x63" + "\x6c\xa0\xdf\x07\xf0\x24\xa2\x10" + "\xda\x21\x33\x6d\x6d\x58\x73\xe9" + "\x8f\x2c\x15\x26\x38\x57\x0c\x8b" +
+       "\x98\x60\x55\xb9\x8b\x17\x43\x70" + "\x86\x38\x1c\x80\xdf\xa1\x90\x40" + "\x12\xb9\x67\x9b\xff\x00\x98\x75" + "\xc8\x20\x26\x23\x04\x03\x5c\x3e" + "\xca\xee\xdc\x70\x4b\x3c\x9d\x4b" + "\x8e\x64\x1f\x18\x15\x3c\x2d\xbb" + "\x5c\x34\x33\x6e\x37\xd8\x81\xf9" + "\x7a\x29\xf2\x0c\x9b\x28\x26\xb6" +
+       "\x0f\x5e\xbe\x32\xbd\x4c\xc7\x9d" + "\x75\x13\xa0\x17\xb7\xbc\x75\x74" + "\xb1\x72\xd8\x50\xc9\x77\x84\x43" + "\x3d\xd6\xe1\xff\x79\x78\xc6\xce" + "\x70\x8c\x57\xd8\x14\x60\x00\x9b" + "\x8b\x6b\xbb\x78\xa8\x99\xad\xc9" + "\x06\x38\xfb\x11\x8e\x00\x99\x67" + "\xb3\xca\x44\xcd\x35\x14\xe8\xcf" +
+       "\xe4\xd2\xf2\x9e\xc1\xfe\x3f\x11" + "\x7f\xea\xa0\xd5\x7e\x76\xf6\x1b" + "\x0a\x4c\x71\x03\x5e\xf7\xff\x57" + "\xee\xe9\x23\x0a\x2e\x42\x3c\xa2" + "\xaf\x83\x0f\x54\x2d\x6b\x5f\xdd" + "\xa7\x46\xea\x55\x7e\xc2\xc2\xc2" + "\x08\x12\x2a\x67\x46\x42\x6b\xeb" + "\x7a\x4f\x63\xae\xf7\x99\x35\xd1" +
+       "\xf7\xaa\x84\x98\x95\x95\x68\x89" + "\xa6\x48\xb3\x07\xe3\x9b\x95\xb1" + "\x87\x7c\x14\x3c\x57\x0e\x25\x96" + "\xf8\x61\x0c\xdd\x3a\xfb\x0e\xae" + "\x5e\x32\x8c\xca\x5e\x74\x00\xed" + "\x70\x3f\xff\xec\x96\x16\x91\x3c" + "\x1d\xd4\x9a\x31\x65\xbc\xac\x73" + "\xef\xc7\xb1\xf0\x20\xa0\x01\x7b" +
+       "\x6e\x04\x79\x9d\x0d\x79\x89\xaf" + "\x76\x09\xee\x6c\x2d\x0f\x65\x4d" + "\xca\x1e\x07\x43\x9a\x5d\x93\xa3" + "\xfe\x0b\x3b\x28\xc9\xd2\xfc\x66" + "\xf1\x05\x66\x69\xb5\x5e\x66\x0e" + "\x8d\xd3\x4c\xa5\x07\x5d\x7e\xe7" + "\xcf\x50\xd9\x43\x0a\x05\xee\x90" + "\xb5\x69\x2e\xd3\xda\xeb\xdd\x86" +
+       "\xe8\x31\x86\x3a\x9b\xb8\xed\xd2" + "\x46\x37\x21\x7a\xde\x55\xe8\x8d" + "\x11\x5f\x0c\xb0\xb7\x6c\x05\xb2" + "\xe4\x85\x9b\x2c\xd0\xfb\xae\xde" + "\x2d\x89\x50\xd1\x8d\x9a\xf3\x03" + "\x85\x79\x8b\x21\x86\x46\xb8\x37" + "\x1a\x5f\x37\xb7\xd8\x6d\x29\x36" + "\x8e\x89\x8e\xb7\xb1\xd4\x2c\x47" +
+       "\x93\xbd\x8f\x30\x53\xae\x45\xeb" + "\xda\x6f\xc3\x02\x2e\x5a\xcd\x46" + "\x85\x83\xa4\xba\x90\x4e\x3d\x6a" + "\x60\x99\xbe\x9d\x2e\xe6\x55\xdd" + "\xe7\xed\x81\x2a\xa0\x6a\x40\xa1" + "\xa7\x4e\x27\xf9\x14\xdd\x60\x68" + "\x86\x4f\x41\x80\xc2\xb0\xdc\xcf" + "\x27\x43\xf9\x22\x10\x0b\x41\xff" +
+       "\x96\xd8\xa5\x23\x6b\xba\x10\x99" + "\x4e\x36\xe4\x7f\x35\x9e\xe1\x1f" + "\x77\xc6\x33\x9a\xc3\xa8\x1d\x6e" + "\xd0\x9f\xfd\x29\x8b\x48\xb4\x15" + "\xbf\x22\x1f\x1a\x54\x92\x43\x1f" + "\xe8\x63\x81\xab\x70\x8a\x0a\x92" + "\x8e\x65\xe5\x07\x49\xb2\xd1\x3f" + "\x9b\x83\xec\xb6\x9c\xf7\xc4\xf2" +
+       "\x84\x3f\x4a\xb4\xe3\x5d\xd5\x17" + "\x90\xc6\xc6\x17\x44\xf3\xb2\xac" + "\x90\x23\x23\x10\x68\x81\x08\x32" + "\xf7\x3b\x73\x6c\x1f\xa6\xe8\xf2" + "\x52\x76\x2d\x9c\xb6\xaa\x74\xa7" + "\xbc\xc5\x95\xed\xe3\x07\x53\xfb" + "\x10\xf1\x81\x49\xc2\x73\x5c\xa0" + "\xc9\x58\x94\xa3\x1c\xe3\xaa\x1b" +
+       "\x8b\x2d\x5d\xc5\xbb\xb2\x1d\xce" + "\x56\xca\xf6\xf4\xb7\x8b\xd5\x41" + "\x14\x76\x87\x8f\x80\xb6\x50\x76" + "\xed\x49\xc3\xf4\xba\x16\x5e\x90" + "\xac\xac\x61\xf6\x40\x51\x41\xed" + "\xaf\x70\x22\xcb\xf0\x84\x87\x3b" + "\xba\x2c\x40\x8a\xac\x80\xc2\x3b" + "\x1a\x92\x37\x09\x46\x71\x3f\xd5" +
+       "\x30\x17\x34\x78\x6c\xd8\x1e\x7f" + "\x48\xe2\x25\xb5\xb8\xbe\xf5\x8e" + "\x38\xbf\x4f\xb7\xfd\x89\xc4\xbb" + "\x82\xb3\xa0\x91\x0e\x2a\xa9\x38" + "\xcf\x3c\x43\x22\x3f\xba\x77\x7a" + "\xa9\x05\x9f\xa2\xd6\x62\x83\xde" + "\xfc\x9a\x18\x61\xea\x30\x6a\x7f" + "\x4f\x11\xef\x59\x05\x55\x3b\x69" +
+       "\xdc\x08\x4c\x22\xb5\x43\x21\x26" + "\x91\x0c\xb5\x81\xb4\x09\xbb\x2b" + "\x4f\xc8\xa8\xac\x09\xd7\x6e\xc1" + "\xa8\x0c\x85\xb2\x9d\x0d\x21\xa6" + "\xd6\x54\xcb\x09\x7a\xf6\x8d\x6d" + "\xa4\x19\x09\x50\xe0\xf6\xee\x91" + "\x57\x28\x13\x0f\x81\x13\xf6\x90" + "\x8b\x02\xd5\xf8\x47\xde\xce\x9a" +
+       "\xb8\x06\xd8\xce\xa8\x2f\x1a\x07" + "\x78\x14\x7f\x69\x34\x61\x2e\x22" + "\xbf\xdb\xfc\xab\x5d\xfd\x16\xdc" + "\xb8\x53\x1b\x12\xbf\x2e\x91\x44" + "\x7c\xc2\x96\x24\x74\x36\x94\xac" + "\xb0\x26\xfc\x1f\x6c\x17\xa3\x8e" + "\x2c\xbf\xde\x13\xac\x24\xe2\xb6" + "\x32\xa8\x72\xf3\x35\xc2\x4c\x52" +
+       "\x2f\x96\x67\x35\x7d\x36\x98\x7e" + "\xfb\xbf\x88\x81\x1f\xd6\x9e\x37" + "\xa1\x30\xf1\xfa\x48\xa3\xbb\x73" + "\x34\xd7\x4e\x90\xe1\x75\x1f\x6c" + "\xfc\x79\x4a\x3b\x42\x66\x95\x18" + "\x93\x44\xef\x54\x3d\xc8\x0b\xf2" + "\xa1\xec\x11\x91\x5d\x42\x6d\x83" + "\xcf\x8d\x9a\x00\x18\xc3\xb5\xe5" +
+       "\x34\xd5\x85\xda\xbd\xa5\x71\x27" + "\xea\x0e\x98\xff\x1f\x8c\xe7\x53" + "\xe7\x85\x03\x90\x84\xcf\xf1\xad" + "\x62\x7b\x38\xc9\xf6\x14\x3b\x7d" + "\xd2\x2b\x8f\xcb\xb0\x74\x0e\x17" + "\x93\xa9\x7f\x82\x86\xb4\x50\x2d" + "\xab\x2b\xf3\xf6\x9a\x8c\xbe\xcd" + "\xb8\x3a\xb9\xc3\xb0\x06\xe9\x55" +
+       "\xa5\xa6\x16\x14\x69\xa0\xce\x84" + "\x1c\x88\xef\x43\x79\x0c\x86\x8f" + "\x5d\x8a\x03\x38\x8a\x1f\x31\x41" + "\x67\x20\x61\xfc\xc0\x2e\x8c\xe7" + "\x81\x35\xd7\x5a\x81\x2e\x4d\x49" + "\x97\x40\x60\x59\x00\x9e\xcc\xb4" + "\xba\x2c\x61\xf3\xec\x8a\x55\xff" + "\x9e\xc3\x36\x9e\x7a\xef\xbe\x35" +
+       "\xee\x06\xba\x36\xcc\xc0\x4e\x32" + "\x0c\xcc\xd2\x3d\x15\x31\xce\xfa" + "\x1f\xe9\x33\xf3\xbe\xf3\x64\xb3" + "\xb0\x32\xe8\x28\x73\xff\x8a\xef" + "\x1b\x84\x05\x2d\x04\xad\x9b\x1e" + "\xe2\x21\x6a\x35\xdf\xe3\xf0\x42" + "\x7e\x62\xdd\x4a\xcb\x0b\x27\xa3" + "\x11\xe7\x22\xd3\x58\x81\x9a\xb0" +
+       "\x04\x6e\x92\x66\xcd\x8e\x3f\x32" + "\xba\xc1\x10\x81\x8f\xe3\x01\x00" + "\x07\x7f\x6a\xfc\x12\xac\xbc\x8d" + "\x27\x08\xec\x0c\x58\x1d\x5e\xd6" + "\x2d\xca\x76\xbe\x41\x41\xcd\xd2" + "\x3a\xf3\x92\xe8\x5c\xcf\x95\x78" + "\xd2\x39\x71\x36\x0d\x23\x6d\x95" + "\xc1\xc4\x12\xd0\x3e\xbd\x1a\xa9" +
+       "\x26\xd4\x95\x62\x9d\x77\xff\x28" + "\x7b\xad\xa3\x3f\xc7\x6a\x4f\x0c" + "\x04\x26\x8e\x8b\x54\xd0\x44\xec" + "\xe1\x50\x00\x8b\x6d\xa6\x32\x9b" + "\xe2\x6c\x47\xf0\x66\x33\x94\x1f" + "\xb4\xc7\x02\xa6\x53\xd9\x54\x75" + "\x09\x28\x4f\x52\xa6\xac\x35\xbe" + "\xea\xdb\x4e\xfd\x29\x12\x88\xb6" +
+       "\x29\x36\x67\xde\x46\x14\xe2\x45" + "\x21\x2d\x3c\x70\x1e\xaa\xf7\x57" + "\xc7\x68\xc8\x98\x7f\x9b\xe9\xa0" + "\x76\x16\x64\x8b\x6d\xf6\x42\x4e" + "\x96\x78\x07\x91\xdc\x84\x28\x60" + "\x5b\x88\xc9\xc2\xcf\x90\xd6\xa0" + "\x87\x51\x9a\x3b\x33\xda\xb4\xfe" + "\xee\x87\x3c\x15\x98\x95\x78\x5f" +
+       "\x90\x96\xf0\x15\xe7\xdc\x82\xb7" + "\xc9\x0f\xfc\x2d\x12\x9b\x8b\x50" + "\xc6\x9f\xd8\x65\x4b\xab\x15\x90" + "\x0f\xbb\xd5\xd6\xb7\xda\x79\x5e" + "\xa2\x5a\x77\x6c\xf0\x21\xf0\x64" + "\xa1\xec\xc7\x37\xcc\xd8\x09\xdf" + "\x06\xa5\x2f\xef\x67\x13\x76\x9a" + "\xc6\xee\x81\x5b\x76\xa4\x4c\xed" +
+       "\x7c\x86\xb0\x67\x19\x71\x83\x3b" + "\x20\x45\x36\x9d\x08\x0d\x5e\x8d" + "\xe3\xf0\x30\xd9\x1e\xcc\xdc\x52" + "\xaf\xbb\x20\xbf\xc7\xce\xbb\xef" + "\x10\xad\x63\x02\xab\xfc\xcf\x99" + "\x8a\x8f\xd1\xfc\x6d\x9e\x19\xd8" + "\x17\x06\xf1\xe9\x3f\x77\xe2\x64" + "\x48\x48\x70\x08\xe1\xe8\x79\x00" +
+       "\x2b\x34\x2f\x5c\x4d\xce\x9c\xbb" + "\xae\x7a\x2d\xb5\x7a\x90\x80\xbf" + "\xd0\xbc\x61\x21\xcd\xd3\xf3\x97" + "\x4d\x74\x62\x09\x34\x08\x5b\xb2" + "\xda\x1d\x3a\x6c\xa5\x8e\xb1\xc5" + "\x17\x23\xc9\x06\xeb\xc7\x4e\xfe" + "\xfe\x4a\x1c\xad\x90\xb8\x87\xb7" + "\x1a\x80\xde\x0e\x92\x9a\xcd\xdc" +
+       "\xe8\x7e\x49\x76\x9c\x61\x5c\x8b" + "\x0e\x37\x17\xc7\xc6\x0a\x2b\x5d" + "\xe1\x68\xcf\x4f\xb6\x4c\x20\x98" + "\x92\x67\xbc\x62\x11\xc2\xde\x0b" + "\x11\x10\x3b\xa6\xef\xcc\x73\x69" + "\xc5\x1a\xde\xe0\x97\xfa\xe3\xf9" + "\x8b\x0c\x0e\x3d\x3e\x69\xfb\x5e" + "\xb4\xfc\xd4\xd2\xe9\x48\x72\x03" +
+
+       "\x9e\x4f\xc3\x1e\xc9\x2d\x80\x80" + "\x03\x06\x81\x33\x35\x2d\x77\xd8" + "\xf3\xb4\x0c\x53\x6c\xd6\x06\x3f" + "\x29\xc1\x75\xc4\x0d\xed\xe5\x7b" + "\x10\x2b\xe8\x31\x19\x3c\x9e\xcb" + "\x4c\x6b\xff\xc9\x57\x28\x3d\xc6" + "\x5e\xb4\xa1\x92\xc6\x18\x21\xb9" + "\xca\xbb\x85\x72\x14\x44\xec\x0a" +
+       "\xef\xa3\x29\x1e\xe7\x9a\x18\xfc" + "\x2e\x30\x93\x4c\xf0\x06\xe9\xcb" + "\x0e\xe1\xaa\xce\x14\x79\x10\xd0" + "\xf8\x19\x8e\xb6\x34\x3f\xa2\xb7" + "\x9d\x11\xd2\xef\xc2\x75\xd8\xe9" + "\xc8\xc9\xad\xfc\x6e\x8c\x19\x03" + "\x13\x71\xa1\x4d\xf6\x1b\x59\x65" + "\x38\x30\x44\x3d\xf8\xbb\xf0\x3c" +
+       "\x59\x47\x72\x2b\xb7\x5b\x48\xae" + "\x3a\xc6\xd4\xb2\xe1\x53\x53\x94" + "\x2c\x6f\x7d\xde\x07\x9d\x15\x82" + "\x09\xb1\xc5\x4e\xf3\xae\x9c\x38" + "\x14\xef\x65\xdb\x53\xbb\x8e\x4a" + "\x43\xde\x99\xdd\x7e\xcb\xc2\x2d" + "\x5f\x40\xf2\x83\xed\xa3\x6f\x81" + "\xa3\x08\x42\xc1\xb9\x9b\x42\x73" +
+       "\x27\x6e\x1e\xb0\x90\xd5\x18\xb6" + "\xdc\xb2\x80\xe1\xcd\x2c\x7e\x04" + "\xa9\xa4\xae\x04\xb5\x99\xb2\xd1" + "\xa4\x03\xa4\x9f\x1e\x9e\x2c\x41" + "\x52\x75\x40\x79\x36\x8a\xd2\x88" + "\xe3\xb8\x32\xf3\x36\x01\xc5\x49" + "\x19\xde\x68\xe6\xcc\x6f\x1b\x3a" + "\x97\x2b\x12\x75\xbc\x51\x88\x17" +
+       "\x4c\xfa\x85\xfb\x52\x37\xe1\xb1" + "\xe9\x8c\x3c\x38\xce\x57\x12\xd6" + "\xae\x4d\xf7\xd2\x70\xa6\x3d\xd4" + "\xbb\x6b\x84\xbf\x3f\xa2\x5a\xa3" + "\x83\xfc\x21\x44\x5d\x23\x74\x5e" + "\x3b\x47\x63\xc3\xe0\x8e\xdf\xf6" + "\x58\xa1\x4a\x3c\x2a\xf5\xd7\x34" + "\x2e\xd2\xc6\x9b\xab\x5a\xd0\x50" +
+       "\xf4\x85\x47\xa6\x35\xe7\x56\x8c" + "\x07\xcd\x29\x5f\x7b\x63\x56\xbc" + "\x67\x50\xe3\x3e\x80\xbb\xb2\x53" + "\x70\x92\x91\xdc\x0f\x5a\x23\x50" + "\x65\xaa\xc4\xf2\xd8\xb6\x1a\x19" + "\x3b\x02\x96\x83\x31\x58\x47\xc3" + "\xba\x05\xf8\xf0\xa5\x0b\x40\x80" + "\x0f\xf8\xc0\x5e\x5b\x06\x81\x88" +
+       "\x83\x5e\x1b\xcc\x22\xe5\x70\xc3" + "\xfb\x8b\x0b\x86\xd1\x4a\x2d\xde" + "\xdf\x56\xb2\x67\xf0\x4d\x36\xad" + "\x97\x89\x13\xe0\x2e\x50\x12\x8f" + "\x0a\x92\x83\x77\xdc\xa0\x3f\x50" + "\x6a\x86\xbc\xc0\xad\x14\x00\xe8" + "\xa6\x4b\x06\xd3\x44\xb7\x89\x3f" + "\xa5\xdb\xa5\xcb\xcd\x1d\x51\x03" +
+       "\xa2\xb1\xa7\x95\x6d\xd4\x7d\x19" + "\xfb\x41\x63\x3c\xd6\x7a\x4e\x9c" + "\xce\x2e\x4c\x48\x29\xca\x6e\x42" + "\x8a\x4f\x7f\xde\x89\xe4\x11\x92" + "\xf4\xf1\x8e\xc7\x6e\x7f\x99\x14" + "\x86\x45\x57\x06\x10\x09\x2c\x2b" + "\xe8\xed\x3e\x1c\x6e\x6a\x28\x17" + "\x18\xe0\x60\x0f\x47\x2e\xf9\x25" +
+       "\x36\x0a\x89\x31\x46\x56\x5c\x80" + "\x5b\xea\xfe\x57\x00\xf6\x3e\x70" + "\x30\x30\x3c\xaf\x7c\x74\x9f\x38" + "\x39\x37\xdd\x54\xeb\xda\xe5\xe0" + "\x55\xf1\xc9\xc9\xc3\xa4\x24\xfe" + "\x62\x39\x39\xb5\x76\xf1\x4b\x7e" + "\x29\xbf\x20\xaf\xe2\x3d\x18\x37" + "\x3b\x8c\x5a\xf9\xb5\xd7\x1b\x4a" +
+       "\x3d\x1d\x19\x46\x99\x96\x3b\xa8" + "\x57\xf2\x87\x7b\xdd\xc8\x1f\x28" + "\x88\x75\x10\x54\x13\x2c\x8e\xb1" + "\xe8\xaf\x2b\x9b\xf7\xde\x72\x63" + "\xca\x72\x89\x0d\x48\xbb\xf4\xda" + "\x3f\x7a\x16\x56\xb7\xd4\x2d\x3f" + "\xf4\x0c\x31\x84\x2d\xe3\xac\x1e" + "\xaa\x00\x27\xe4\xaf\xef\xbc\xe3" +
+       "\x3d\xe7\x85\xd7\x1e\x69\xe5\x5f" + "\x67\x04\xa6\x2e\xb6\x5a\xdb\xa5" + "\x4a\x51\xc6\xdf\x41\x3d\xe2\x02" + "\x65\x36\x3c\xe0\x8e\x04\xe8\x35" + "\xf8\xa0\xda\x1a\x8f\x11\x8b\x3f" + "\x5a\x1a\xce\x84\x45\x3b\xec\x28" + "\xb8\x46\x66\x2c\x6e\xcc\xca\xe8" + "\x0f\xe4\xd0\xdb\x85\xd1\x43\x13" +
+       "\x8c\x35\xaa\xca\x44\xf8\xd7\xe5" + "\x2a\x18\x24\x99\xe4\xb7\x1d\x1a" + "\x9a\x5d\x87\x9c\x2d\xd4\x4c\xd6" + "\xc8\xee\x2e\x04\x5f\x51\x7b\xb3" + "\xbe\x5f\x16\x7b\x09\xd4\x4d\x4d" + "\xf3\xef\x06\xe2\xd9\x2e\x32\xfc" + "\x7e\xe1\xb7\x59\x02\x41\xee\x7d" + "\x00\xca\x36\x82\xc0\x81\xa4\x55" +
+       "\x75\xc9\x3f\xc2\x12\x53\x88\x8c" + "\x7b\x29\xd6\x05\x06\x58\x71\x15" + "\x39\xdd\x8e\xf7\x8e\x86\x78\xa0" + "\x52\x5e\xc4\x03\xe0\x31\x6b\x95" + "\xa6\x33\x7b\xff\xd5\x75\x02\x47" + "\x3f\x67\x7e\x0c\x3a\xdc\xd5\xc8" + "\x98\x25\x2f\x7e\xb4\x27\x92\x41" + "\x75\xa9\x14\x4c\x34\xb6\x37\x8b" +
+       "\x8c\x88\x11\x8b\xd6\x7e\x66\xd0" + "\xdc\x25\x3e\x80\x3e\x8c\x0e\x5e" + "\x4a\xa2\x87\xb9\xdc\xd0\xe5\x34" + "\x23\x03\x92\xae\x3b\xac\x40\x9f" + "\x3a\xf6\xe0\x34\x95\xde\x63\x54" + "\xf9\x28\x63\x6b\x92\xbf\x28\xa1" + "\xb7\xf1\x64\xda\x7c\xcd\x1c\x49" + "\x35\xde\x7b\xc4\x27\xec\xf1\x7e" +
+       "\x37\x27\x6a\xa3\x0f\x24\x57\xa8" + "\xc1\x1b\x62\x63\x66\x13\xdc\x35" + "\x97\x68\xfb\xd4\x53\x64\x3a\x7a" + "\x9d\x31\x29\xc9\x39\xa4\xf1\x80" + "\xa0\x0b\xcb\xf8\x4b\x27\x18\xfc" + "\xeb\xc5\x78\x80\x66\x37\xb5\xb0" + "\xef\xd0\x01\x1e\x24\x49\x0d\xfb" + "\x9c\xb0\x2a\x37\x7d\xc6\xd7\x50" +
+       "\x68\xc9\xea\x3a\xaf\x70\xe3\xb4" + "\x66\x32\xb6\xc4\xe9\xfe\xf7\xe4" + "\x64\x56\xac\xe3\xc2\xd4\xac\xb4" + "\xbf\x8c\xb3\xce\xd2\x0b\x91\xf8" + "\x6e\x72\xc0\xc9\x0c\xe5\x3a\x1c" + "\xbf\x40\x7b\xd9\x69\x95\x30\x15" + "\x1b\x5a\x5a\xfd\x7f\x4b\x88\x70" + "\xcd\x14\x83\xef\x6a\x89\x90\x38" +
+       "\x93\x8c\x61\xa5\x5c\x51\xe1\x58" + "\xd1\x42\xd9\x77\x2b\x43\x65\xe6" + "\xa8\x67\xf7\xb6\xbf\x81\x21\xb3" + "\x10\x41\x60\x3a\xe8\x94\x37\x75" + "\xcc\xdb\xc0\xe8\x7c\xeb\xaf\x09" + "\xa3\x73\x86\x59\x13\x26\xe0\x31" + "\x00\xdb\x46\x7d\x57\xe5\x98\x5d" + "\x28\x5b\x98\x9d\x8c\xfb\x21\xfc" +
+       "\x0b\x3e\x84\xb0\x16\x01\x04\xc9" + "\x31\x45\xb0\x69\xa8\xb3\xb1\x53" + "\x30\xd8\xd7\x85\xf0\x49\x16\xdd" + "\xe8\x27\x74\xcb\x87\xcc\x3b\xbb" + "\x83\xce\x3d\xc9\x00\x11\x26\x77" + "\x2a\x2a\x92\xa1\x61\xda\x79\x7e" + "\xe8\x9c\x14\xf3\x02\x2b\x7a\x58" + "\x83\xec\x92\xde\x84\x13\x7e\x14" +
+       "\x30\x7f\x07\xaf\xd3\x83\x4c\x48" + "\x3a\xb5\x58\x06\x44\xf8\x78\xea" + "\x53\xec\x7a\x02\xc2\x76\x20\x91" + "\x7d\x17\xc8\x93\xe3\x14\x47\xf3" + "\x84\x6c\x37\xc2\x15\x5d\xef\x37" + "\x83\xa7\x1a\x3d\x59\xb6\x15\x83" + "\x90\x2a\x85\xef\x84\xc4\x75\x3a" + "\xd4\x6b\x08\x16\x8a\xc5\xa0\x0b" +
+       "\x48\x6d\x9a\x52\x7a\x8d\x68\x29" + "\x03\x92\xf1\xc2\x0d\x25\x7f\x9c" + "\xf9\x2d\x2e\x68\xfb\x42\x30\x12" + "\xbc\x21\x81\xad\xe7\x87\x75\x2b" + "\x65\x2a\x18\xe0\x33\x02\xfc\x30" + "\x8a\x12\xe1\xe3\x87\xcf\x2e\xb8" + "\x8f\x09\xfb\x93\x61\x28\x68\x71" + "\xa7\xe6\xe9\x85\xae\x21\x3e\x04" +
+       "\xea\x34\xc8\x66\xd6\x49\x5b\xab" + "\x87\x42\x41\x47\x18\x3e\xe4\x3b" + "\x47\x2a\x9a\x21\x59\xb8\x0f\xf4" + "\x3c\xdf\x58\xcc\xe9\x59\x65\x0e" + "\xb4\x15\x66\x0c\x8e\xfe\x1d\xfe" + "\x70\x9d\x45\x56\xfd\xc8\xab\x14" + "\x86\x03\xde\x05\x8e\xfa\xe0\x7b" + "\x7c\x5c\x03\xe9\x68\xef\x63\x8e" +
+       "\x91\x1e\xb3\x53\xb4\x01\x64\x11" + "\xd8\xb4\x36\x44\xd4\x7a\xba\x0c" + "\x66\xfd\x7a\x10\xa0\xf9\x51\x91" + "\xc4\xe4\x0e\x1f\xd0\xa8\xac\xaf" + "\x1c\x76\xe9\x9e\x1d\x5c\xfe\x75" + "\x8f\x58\xc0\xf0\x6b\xa1\x97\x34" + "\x4c\x80\x04\x03\xbd\xbe\xe2\x3e" + "\xb9\x90\xc9\xc2\x60\x9a\xfb\xa8" +
+       "\x14\x11\x25\x39\xfe\x32\x4d\xd1" + "\x66\x33\xc7\xca\xbc\x25\xbf\x36" + "\x5c\x49\xa7\xdb\x66\x2c\x56\xc9" + "\x8b\x34\xad\x46\x1b\x30\x4d\x32" + "\x7e\x40\x70\xd6\x0c\x62\x46\x9f" + "\x01\x3a\x73\xe3\xf1\xd4\xa8\x0e" + "\xe0\x24\xc3\xb0\x32\xd5\x96\xd3" + "\xcd\x17\xc3\x03\x0e\x1a\x21\x5b" +
+       "\x37\x7b\xfe\x5f\x20\x7d\x0d\x09" + "\xda\xd2\x47\x17\xfb\x3e\x7f\x3b" + "\x19\xc5\x4f\xb5\x5f\x52\xcb\xa2" + "\x1e\x97\x6a\xf6\x32\x09\x22\x6e" + "\x40\xd4\x86\xb4\xdf\x60\xc1\xdd" + "\x65\x34\xe1\x3f\x46\xec\xcf\x7f" + "\x51\xc1\xe4\x76\x4e\x7e\xda\x83" + "\xb5\x02\xd3\xd8\xa1\x48\xfa\xd6" +
+       "\x88\xcd\x72\x58\x26\x4f\x30\xc6" + "\xa1\x90\x8b\x27\x3c\x1d\x6c\x80" + "\x1c\xbc\xf0\xca\x25\xe7\x53\x35" + "\x5c\x8d\x9d\xbb\x03\xe6\x59\xff" + "\xdd\x85\x0b\x7a\x32\x0f\x55\xa4" + "\x17\xc2\xec\x93\x0a\x72\xc5\xde" + "\x13\x22\xd6\x69\x41\xb7\x88\x0b" + "\x55\x59\x36\x5b\x45\xf2\x12\x72" +
+       "\x87\xe7\xca\xb5\x11\x41\x76\x20" + "\x24\x31\xfd\x1d\x58\x7f\xcb\x13" + "\xfb\xae\x75\x11\xda\x77\xca\x2d" + "\x75\xe7\xaa\xff\x6b\x46\x75\xeb" + "\x32\xff\x6c\xdb\x3b\x6f\xd7\x74" + "\x9a\xda\xfc\x61\x7a\xf3\x40\x74" + "\x8b\x02\x25\xb5\x92\xac\xb3\x1b" + "\x29\x5f\x97\xa1\xf7\xf8\xfb\x20" +
+       "\x7f\x09\x83\xdf\xe1\x92\x26\x98" + "\x00\x08\x4b\x55\x6c\x8f\x73\x28" + "\x2f\x2f\xce\xa2\x17\x37\x70\xdc" + "\x94\x41\x81\x40\x3c\xb9\x13\x79" + "\x36\x96\xe8\x1f\x93\x45\x92\x04" + "\xa6\x34\x88\xf7\x3f\x44\x98\x7b" + "\xa1\xa5\x14\x51\x01\xab\xc6\x11" + "\x4c\x5f\xba\xff\x83\xb3\xde\x60" +
+       "\xe6\x82\xa9\x01\xc6\x54\xaa\x4c" + "\x26\xcd\x91\x34\x11\x5e\xd3\x1d" + "\x05\x6b\xbd\x7c\x5f\x31\x3c\x97" + "\x24\x47\x49\x52\x75\x07\xb0\xca" + "\x5a\xe1\x65\x65\x1f\x9b\x65\x04" + "\x26\xb0\x8f\x8c\x29\xf5\x30\xbf" + "\x37\xde\xa0\xa8\x1b\x64\x21\xfc" + "\x14\x51\x5e\xfa\x66\xa3\xc7\xe9" +
+       "\xd8\x3a\xf0\x52\xa5\x9c\x84\xdb" + "\xc0\x35\x4e\x02\xe9\xdb\xe8\xc7" + "\x89\xc7\xc3\xcf\xac\xbb\xa2\xa1" + "\x62\xf2\x26\x9c\x7d\x3e\x73\xbf" + "\x23\x48\x44\xb8\xf5\xfb\x2f\x88" + "\x3b\x48\xf8\x6b\x88\x4e\x22\xb7" + "\x40\xf6\xbe\x65\x8b\x3b\x02\x53" + "\xcd\xf8\xd5\xd4\x91\xec\xbf\xaa" +
+       "\xbd\xa1\x9e\x07\x10\x15\x0e\xa4" + "\x26\x5d\x5d\xd0\xdc\xad\xd9\x1a" + "\x4f\x8d\xe6\x13\xab\x2e\x3f\xdb" + "\x3f\x80\x0f\x64\xe2\x1a\xff\x1c" + "\x17\xe1\xce\xd4\x49\xb7\xe7\xe0" + "\x09\xd9\x36\x40\x5b\x27\x9f\x8e" + "\x38\x4c\x4d\x8f\x1d\xe3\x34\xce" + "\xfc\x30\x51\xd7\x69\x7f\xb3\x22" +
+       "\x04\x46\x01\xb4\xfd\xf1\xe0\x83" + "\x78\x50\x41\x89\x19\x99\xce\xa8" + "\xfe\x2e\x79\x41\x75\x5b\x37\x82" + "\x5b\x51\xd4\x97\x5c\xbf\x59\x4f" + "\x7d\x27\x3a\x92\x4f\x32\x4f\xac" + "\x06\x34\x0f\x65\x7d\x9b\xbc\xd9" + "\x51\xbc\x39\x8a\xd1\x87\xfa\xc6" + "\x8f\x10\xcc\x5c\x30\x85\x58\x82" +
+       "\x34\xc6\xe4\x82\x9f\x3c\xed\x5c" + "\xf8\x64\x44\x3a\x14\x83\xfb\x8e" + "\x25\xca\x1d\x7a\x1b\x38\x06\xe7" + "\x2b\x41\x2a\x5a\x3c\x5a\xd1\x6c" + "\xb5\x8f\xcd\xbf\xfd\xa8\x47\x93" + "\x22\xcd\x54\x6e\xef\x2e\xdb\x31" + "\x2f\x93\xd8\xf8\x1e\xb1\xae\xc4" + "\xaf\x11\x44\x34\xed\xc1\xe7\x11"
index 6b64f26286e506c62e0d6f06fcafd8a32f806940..6abd8cb11bc5ab21c9dea568729de1a2daf76758 100644 (file)
@@ -3,11 +3,11 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64
-// +build amd64 arm64
 
 package elliptic
 
 import (
+       "encoding/binary"
        "reflect"
        "testing"
 )
@@ -45,7 +45,12 @@ func TestP256PrecomputedTable(t *testing.T) {
 
                        copy(t1[8:12], basePoint[8:12])
 
-                       if got, want := p256Precomputed[i][j*8:(j*8)+8], t1[:8]; !reflect.DeepEqual(got, want) {
+                       buf := make([]byte, 8*8)
+                       for i, u := range t1[:8] {
+                               binary.LittleEndian.PutUint64(buf[i*8:i*8+8], u)
+                       }
+                       start := i*32*8*8 + j*8*8
+                       if got, want := p256Precomputed[start:start+64], string(buf); !reflect.DeepEqual(got, want) {
                                t.Fatalf("Unexpected table entry at [%d][%d:%d]: got %v, want %v", i, j*8, (j*8)+8, got, want)
                        }
                }
index 25762a8f768b3b4825c0e59de47ffac0b68e9da8..7f8fab5398ecf825489cc5aa2ec09c966a50f4b2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !s390x && !arm64 && !ppc64le
-// +build !amd64,!s390x,!arm64,!ppc64le
 
 package elliptic
 
index 40d9ed9d40fdc3fa99a5ce0845365d1efb8c97aa..e9a6a067a2258a23e90e8071ba183b699e7fab76 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64le
-// +build ppc64le
 
 package elliptic
 
index 91e613b6310e1d76857700adbe14b502bd9ac919..735e9f57f1294019606a4756f02c128318f96694 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build s390x
-// +build s390x
 
 package elliptic
 
index 3d355943ec7fae1545ea804c20a9e63b398dcf47..e64007dfe35aad3a17906a054953a6d68280be88 100644 (file)
 package elliptic
 
 import (
-       "crypto/elliptic/internal/fiat"
+       "crypto/elliptic/internal/nistec"
+       "crypto/rand"
        "math/big"
 )
 
+// p521Curve is a Curve implementation based on nistec.P521Point.
+//
+// It's a wrapper that exposes the big.Int-based Curve interface and encodes the
+// legacy idiosyncrasies it requires, such as invalid and infinity point
+// handling.
+//
+// To interact with the nistec package, points are encoded into and decoded from
+// properly formatted byte slices. All big.Int use is limited to this package.
+// Encoding and decoding is 1/1000th of the runtime of a scalar multiplication,
+// so the overhead is acceptable.
 type p521Curve struct {
-       *CurveParams
+       params *CurveParams
 }
 
 var p521 p521Curve
-var p521Params *CurveParams
+var _ Curve = p521
 
 func initP521() {
-       // See FIPS 186-3, section D.2.5
-       p521.CurveParams = &CurveParams{Name: "P-521"}
-       p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
-       p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
-       p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
-       p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16)
-       p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16)
-       p521.BitSize = 521
+       p521.params = &CurveParams{
+               Name:    "P-521",
+               BitSize: 521,
+               // FIPS 186-4, section D.1.2.5
+               P: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
+                       "0540939446345918554318339765605212255964066145455497729631139148" +
+                       "0858037121987999716643812574028291115057151"),
+               N: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
+                       "0540939446345918554318339765539424505774633321719753296399637136" +
+                       "3321113864768612440380340372808892707005449"),
+               B: bigFromHex("0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8" +
+                       "b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef" +
+                       "451fd46b503f00"),
+               Gx: bigFromHex("00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f8" +
+                       "28af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf9" +
+                       "7e7e31c2e5bd66"),
+               Gy: bigFromHex("011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817" +
+                       "afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088" +
+                       "be94769fd16650"),
+       }
 }
 
 func (curve p521Curve) Params() *CurveParams {
-       return curve.CurveParams
+       return curve.params
 }
 
 func (curve p521Curve) IsOnCurve(x, y *big.Int) bool {
-       x1 := bigIntToFiatP521(x)
-       y1 := bigIntToFiatP521(y)
-       b := bigIntToFiatP521(curve.B) // TODO: precompute this value.
-
-       // x³ - 3x + b.
-       x3 := new(fiat.P521Element).Square(x1)
-       x3.Mul(x3, x1)
-
-       threeX := new(fiat.P521Element).Add(x1, x1)
-       threeX.Add(threeX, x1)
-
-       x3.Sub(x3, threeX)
-       x3.Add(x3, b)
-
-       // y² = x³ - 3x + b
-       y2 := new(fiat.P521Element).Square(y1)
-
-       return x3.Equal(y2) == 1
-}
-
-type p521Point struct {
-       x, y, z *fiat.P521Element
-}
-
-func fiatP521ToBigInt(x *fiat.P521Element) *big.Int {
-       xBytes := x.Bytes()
-       for i := range xBytes[:len(xBytes)/2] {
-               xBytes[i], xBytes[len(xBytes)-i-1] = xBytes[len(xBytes)-i-1], xBytes[i]
+       // IsOnCurve is documented to reject (0, 0), the conventional point at
+       // infinity, which however is accepted by p521PointFromAffine.
+       if x.Sign() == 0 && y.Sign() == 0 {
+               return false
        }
-       return new(big.Int).SetBytes(xBytes)
+       _, ok := p521PointFromAffine(x, y)
+       return ok
 }
 
-// affineFromJacobian brings a point in Jacobian coordinates back to affine
-// coordinates, with (0, 0) representing infinity by convention. It also goes
-// back to big.Int values to match the exposed API.
-func (curve p521Curve) affineFromJacobian(p *p521Point) (x, y *big.Int) {
-       if p.z.IsZero() == 1 {
-               return new(big.Int), new(big.Int)
+func p521PointFromAffine(x, y *big.Int) (p *nistec.P521Point, ok bool) {
+       // (0, 0) is by convention the point at infinity, which can't be represented
+       // in affine coordinates. Marshal incorrectly encodes it as an uncompressed
+       // point, which SetBytes would correctly reject. See Issue 37294.
+       if x.Sign() == 0 && y.Sign() == 0 {
+               return nistec.NewP521Point(), true
        }
-
-       zinv := new(fiat.P521Element).Invert(p.z)
-       zinvsq := new(fiat.P521Element).Mul(zinv, zinv)
-
-       xx := new(fiat.P521Element).Mul(p.x, zinvsq)
-       zinvsq.Mul(zinvsq, zinv)
-       yy := new(fiat.P521Element).Mul(p.y, zinvsq)
-
-       return fiatP521ToBigInt(xx), fiatP521ToBigInt(yy)
-}
-
-func bigIntToFiatP521(x *big.Int) *fiat.P521Element {
-       xBytes := new(big.Int).Mod(x, p521.P).FillBytes(make([]byte, 66))
-       for i := range xBytes[:len(xBytes)/2] {
-               xBytes[i], xBytes[len(xBytes)-i-1] = xBytes[len(xBytes)-i-1], xBytes[i]
+       if x.BitLen() > 521 || y.BitLen() > 521 {
+               return nil, false
        }
-       x1, err := new(fiat.P521Element).SetBytes(xBytes)
+       p, err := nistec.NewP521Point().SetBytes(Marshal(P521(), x, y))
        if err != nil {
-               // The input is reduced modulo P and encoded in a fixed size bytes
-               // slice, this should be impossible.
-               panic("internal error: bigIntToFiatP521")
+               return nil, false
        }
-       return x1
+       return p, true
 }
 
-// jacobianFromAffine converts (x, y) affine coordinates into (x, y, z) Jacobian
-// coordinates. It also converts from big.Int to fiat, which is necessarily a
-// messy and variable-time operation, which we can't avoid due to the exposed API.
-func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p521Point {
-       // (0, 0) is by convention the point at infinity, which can't be represented
-       // in affine coordinates, but is (0, 0, 0) in Jacobian.
-       if x.Sign() == 0 && y.Sign() == 0 {
-               return &p521Point{
-                       x: new(fiat.P521Element),
-                       y: new(fiat.P521Element),
-                       z: new(fiat.P521Element),
-               }
+func p521PointToAffine(p *nistec.P521Point) (x, y *big.Int) {
+       out := p.Bytes()
+       if len(out) == 1 && out[0] == 0 {
+               // This is the correct encoding of the point at infinity, which
+               // Unmarshal does not support. See Issue 37294.
+               return new(big.Int), new(big.Int)
        }
-       return &p521Point{
-               x: bigIntToFiatP521(x),
-               y: bigIntToFiatP521(y),
-               z: new(fiat.P521Element).One(),
+       x, y = Unmarshal(P521(), out)
+       if x == nil {
+               panic("crypto/elliptic: internal error: Unmarshal rejected a valid point encoding")
        }
+       return x, y
 }
 
-func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
-       p1 := curve.jacobianFromAffine(x1, y1)
-       p2 := curve.jacobianFromAffine(x2, y2)
-       return curve.affineFromJacobian(p1.addJacobian(p1, p2))
+// p521RandomPoint returns a random point on the curve. It's used when Add,
+// Double, or ScalarMult are fed a point not on the curve, which is undefined
+// behavior. Originally, we used to do the math on it anyway (which allows
+// invalid curve attacks) and relied on the caller and Unmarshal to avoid this
+// happening in the first place. Now, we just can't construct a nistec.P521Point
+// for an invalid pair of coordinates, because that API is safer. If we panic,
+// we risk introducing a DoS. If we return nil, we risk a panic. If we return
+// the input, ecdsa.Verify might fail open. The safest course seems to be to
+// return a valid, random point, which hopefully won't help the attacker.
+func p521RandomPoint() (x, y *big.Int) {
+       _, x, y, err := GenerateKey(P521(), rand.Reader)
+       if err != nil {
+               panic("crypto/elliptic: failed to generate random point")
+       }
+       return x, y
 }
 
-// addJacobian sets q = p1 + p2, and returns q. The points may overlap.
-func (q *p521Point) addJacobian(p1, p2 *p521Point) *p521Point {
-       // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
-       z1IsZero := p1.z.IsZero()
-       z2IsZero := p2.z.IsZero()
-
-       z1z1 := new(fiat.P521Element).Square(p1.z)
-       z2z2 := new(fiat.P521Element).Square(p2.z)
-
-       u1 := new(fiat.P521Element).Mul(p1.x, z2z2)
-       u2 := new(fiat.P521Element).Mul(p2.x, z1z1)
-       h := new(fiat.P521Element).Sub(u2, u1)
-       xEqual := h.IsZero() == 1
-       i := new(fiat.P521Element).Add(h, h)
-       i.Square(i)
-       j := new(fiat.P521Element).Mul(h, i)
-
-       s1 := new(fiat.P521Element).Mul(p1.y, p2.z)
-       s1.Mul(s1, z2z2)
-       s2 := new(fiat.P521Element).Mul(p2.y, p1.z)
-       s2.Mul(s2, z1z1)
-       r := new(fiat.P521Element).Sub(s2, s1)
-       yEqual := r.IsZero() == 1
-       if xEqual && yEqual && z1IsZero == 0 && z2IsZero == 0 {
-               return q.doubleJacobian(p1)
+func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+       p1, ok := p521PointFromAffine(x1, y1)
+       if !ok {
+               return p521RandomPoint()
        }
-       r.Add(r, r)
-       v := new(fiat.P521Element).Mul(u1, i)
-
-       x := new(fiat.P521Element).Set(r)
-       x.Square(x)
-       x.Sub(x, j)
-       x.Sub(x, v)
-       x.Sub(x, v)
-
-       y := new(fiat.P521Element).Set(r)
-       v.Sub(v, x)
-       y.Mul(y, v)
-       s1.Mul(s1, j)
-       s1.Add(s1, s1)
-       y.Sub(y, s1)
-
-       z := new(fiat.P521Element).Add(p1.z, p2.z)
-       z.Square(z)
-       z.Sub(z, z1z1)
-       z.Sub(z, z2z2)
-       z.Mul(z, h)
-
-       x.Select(p2.x, x, z1IsZero)
-       x.Select(p1.x, x, z2IsZero)
-       y.Select(p2.y, y, z1IsZero)
-       y.Select(p1.y, y, z2IsZero)
-       z.Select(p2.z, z, z1IsZero)
-       z.Select(p1.z, z, z2IsZero)
-
-       q.x.Set(x)
-       q.y.Set(y)
-       q.z.Set(z)
-       return q
+       p2, ok := p521PointFromAffine(x2, y2)
+       if !ok {
+               return p521RandomPoint()
+       }
+       return p521PointToAffine(p1.Add(p1, p2))
 }
 
 func (curve p521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
-       p := curve.jacobianFromAffine(x1, y1)
-       return curve.affineFromJacobian(p.doubleJacobian(p))
-}
-
-// doubleJacobian sets q = p + p, and returns q. The points may overlap.
-func (q *p521Point) doubleJacobian(p *p521Point) *p521Point {
-       // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
-       delta := new(fiat.P521Element).Square(p.z)
-       gamma := new(fiat.P521Element).Square(p.y)
-       alpha := new(fiat.P521Element).Sub(p.x, delta)
-       alpha2 := new(fiat.P521Element).Add(p.x, delta)
-       alpha.Mul(alpha, alpha2)
-       alpha2.Set(alpha)
-       alpha.Add(alpha, alpha)
-       alpha.Add(alpha, alpha2)
-
-       beta := alpha2.Mul(p.x, gamma)
-
-       q.x.Square(alpha)
-       beta8 := new(fiat.P521Element).Add(beta, beta)
-       beta8.Add(beta8, beta8)
-       beta8.Add(beta8, beta8)
-       q.x.Sub(q.x, beta8)
-
-       q.z.Add(p.y, p.z)
-       q.z.Square(q.z)
-       q.z.Sub(q.z, gamma)
-       q.z.Sub(q.z, delta)
-
-       beta.Add(beta, beta)
-       beta.Add(beta, beta)
-       beta.Sub(beta, q.x)
-       q.y.Mul(alpha, beta)
-
-       gamma.Square(gamma)
-       gamma.Add(gamma, gamma)
-       gamma.Add(gamma, gamma)
-       gamma.Add(gamma, gamma)
-
-       q.y.Sub(q.y, gamma)
-
-       return q
+       p, ok := p521PointFromAffine(x1, y1)
+       if !ok {
+               return p521RandomPoint()
+       }
+       return p521PointToAffine(p.Double(p))
 }
 
 func (curve p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
-       B := curve.jacobianFromAffine(Bx, By)
-       p, t := &p521Point{
-               x: new(fiat.P521Element),
-               y: new(fiat.P521Element),
-               z: new(fiat.P521Element),
-       }, &p521Point{
-               x: new(fiat.P521Element),
-               y: new(fiat.P521Element),
-               z: new(fiat.P521Element),
+       p, ok := p521PointFromAffine(Bx, By)
+       if !ok {
+               return p521RandomPoint()
        }
+       return p521PointToAffine(p.ScalarMult(p, scalar))
+}
 
-       for _, byte := range scalar {
-               for bitNum := 0; bitNum < 8; bitNum++ {
-                       p.doubleJacobian(p)
-                       bit := (byte >> (7 - bitNum)) & 1
-                       t.addJacobian(p, B)
-                       p.x.Select(t.x, p.x, int(bit))
-                       p.y.Select(t.y, p.y, int(bit))
-                       p.z.Select(t.z, p.z, int(bit))
-               }
-       }
+func (curve p521Curve) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
+       p := nistec.NewP521Generator()
+       return p521PointToAffine(p.ScalarMult(p, scalar))
+}
 
-       return curve.affineFromJacobian(p)
+func bigFromDecimal(s string) *big.Int {
+       b, ok := new(big.Int).SetString(s, 10)
+       if !ok {
+               panic("invalid encoding")
+       }
+       return b
 }
 
-func (curve p521Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
-       return curve.ScalarMult(curve.Gx, curve.Gy, k)
+func bigFromHex(s string) *big.Int {
+       b, ok := new(big.Int).SetString(s, 16)
+       if !ok {
+               panic("invalid encoding")
+       }
+       return b
 }
index 86e0f3cfe70b70d70d300c405536af4b79ee357d..16e2fcab124814cc809f8fb4afdfa8c1ac07ee99 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !appengine
-// +build !appengine
 
 // Package subtle implements functions that are often useful in cryptographic
 // code but require careful thought to use correctly.
index 35b442f7a2321e77fea5e0bfaf7bf8b22f804b91..90ac4b61cc2ebd67b8ef56e772445086a177bec4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build appengine
-// +build appengine
 
 // Package subtle implements functions that are often useful in cryptographic
 // code but require careful thought to use correctly.
index 29729fad015e3de3ae0dec6e2010c1f7d02c17aa..cd2700a5cfeb8b07eb2c4f33421d1a4d84c8a9f5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // This program generates md5block.go
 // Invoke as
index acd456af2151782686a90f6acb20b4a736cde8a3..851e7fb10d42f59530d8a5dd9d6933d71dff908a 100644 (file)
@@ -211,6 +211,20 @@ func TestLargeHashes(t *testing.T) {
        }
 }
 
+func TestAllocations(t *testing.T) {
+       in := []byte("hello, world!")
+       out := make([]byte, 0, Size)
+       h := New()
+       n := int(testing.AllocsPerRun(10, func() {
+               h.Reset()
+               h.Write(in)
+               out = h.Sum(out[:0])
+       }))
+       if n > 0 {
+               t.Errorf("allocs = %d, want 0", n)
+       }
+}
+
 var bench = New()
 var buf = make([]byte, 1024*1024*8+1)
 var sum = make([]byte, bench.Size())
index bc2d58c06940b3b5401512b5e2539c32eb072426..6716a0c9db7db68c798a333b1963f6a66d757c75 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || 386 || arm || ppc64le || ppc64 || s390x || arm64
-// +build amd64 386 arm ppc64le ppc64 s390x arm64
 
 package md5
 
index ea4fbcd0b41012630b43ca7e584ccfb2c0efd02a..c929c2b84aca519cece6c9508c792b52ee60030c 100644 (file)
@@ -3,10 +3,11 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !386 && !arm && !ppc64le && !ppc64 && !s390x && !arm64
-// +build !amd64,!386,!arm,!ppc64le,!ppc64,!s390x,!arm64
 
 package md5
 
 const haveAsm = false
 
-var block = blockGeneric
+func block(dig *digest, p []byte) {
+       blockGeneric(dig, p)
+}
index 85d4d9d47f9db4bc0025c183d51fc3db2efe6e34..f018e759312c3ad2741435984ca55be7a232b91b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package rand
 
index fddd1147e6e3c692b3f2d4da69f427a10e8eb6fb..b6248a443874df146ac71757fbdeed19660ed66c 100644 (file)
@@ -11,8 +11,9 @@ import "io"
 // Reader is a global, shared instance of a cryptographically
 // secure random number generator.
 //
-// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
-// On OpenBSD, Reader uses getentropy(2).
+// On Linux, FreeBSD, Dragonfly and Solaris, Reader uses getrandom(2) if
+// available, /dev/urandom otherwise.
+// On OpenBSD and macOS, Reader uses getentropy(2).
 // On other Unix-like systems, Reader reads from /dev/urandom.
 // On Windows systems, Reader uses the RtlGenRandom API.
 // On Wasm, Reader uses the Web Crypto API.
index d7c5bf3562d54747f0ab5db368f90a219dae964c..3e8e62038292040a38b4826eb3e8cc4448515f61 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux || freebsd || dragonfly || solaris
-// +build linux freebsd dragonfly solaris
 
 package rand
 
index 2d20922c8253098f59eac79fe913c28ff9631cf1..28e45aa689ec185976c02a4b69caf54983a7fc28 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux || freebsd || dragonfly || solaris
-// +build linux freebsd dragonfly solaris
 
 package rand
 
index f82018a4951c743c82f15c28b82262b601112f27..2bf2f520324438acf005b0364c85eaec01baa6f4 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build darwin || openbsd
-// +build darwin openbsd
+//go:build (darwin && !ios) || openbsd
 
 package rand
 
index 7ddc2b6169cbe6d7f2587947ad150b68c6cc1739..91e69fae5d63fa778db48430429dc72d9be73268 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package rand
 
index 34f4481a9bd52defd9e639d9667608ad534d16a0..28f2f5b58b17baeb1dc1abafa14d362781abc190 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || plan9 || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd plan9 solaris
 
 // Unix cryptographically secure pseudorandom number
 // generator.
index 4bb8b3324f293b7f27493ccfded6305e4938d2bc..45d1f57d39cfd352d678c07e69e3dfb9658d2f6f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build s390x
-// +build s390x
 
 package sha1
 
index 436f78c74534d40f4fef63a31bebb354baad4edf..df4e28f64eee9e149bb1df5fa9faa224a08986d6 100644 (file)
@@ -1,6 +1,4 @@
 //go:build amd64 && (linux || darwin)
-// +build amd64
-// +build linux darwin
 
 // Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index e369c3b7f491eee1e7cc2f30d1b6aa616b202fa9..f1a5448dd2dd75eb18b405c4237b9cf2dc93f063 100644 (file)
@@ -218,6 +218,23 @@ func TestLargeHashes(t *testing.T) {
        }
 }
 
+func TestAllocations(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("BoringCrypto doesn't allocate the same way as stdlib")
+       }
+       in := []byte("hello, world!")
+       out := make([]byte, 0, Size)
+       h := New()
+       n := int(testing.AllocsPerRun(10, func() {
+               h.Reset()
+               h.Write(in)
+               out = h.Sum(out[:0])
+       }))
+       if n > 0 {
+               t.Errorf("allocs = %d, want 0", n)
+       }
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
index 93054efa7c1827e1c117fe22a37f18bd6a03dafc..518a4b6b67871d32872a5c66acf100c2eac48811 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm || 386 || s390x
-// +build arm 386 s390x
 
 package sha1
 
index feaba5a23abab38cb230443280f0fbfdf45b6f20..ba35155d0b92ef4d4c801f8dea8d70d5ec36775d 100644 (file)
@@ -3,8 +3,9 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !386 && !arm && !s390x && !arm64
-// +build !amd64,!386,!arm,!s390x,!arm64
 
 package sha1
 
-var block = blockGeneric
+func block(dig *digest, p []byte) {
+       blockGeneric(dig, p)
+}
index 7ce88cbb2a8b2f525e6e0123c035b1dda8d3d19e..3f561aadd65ee62154795788d5aed97d165372ac 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build s390x
-// +build s390x
 
 package sha256
 
index 91a4edde047f68bb85ea9f635f746e45bb454ff7..a762afc4d9e8ff6878ec0ed1202e36972d47e8eb 100644 (file)
@@ -294,6 +294,23 @@ func TestLargeHashes(t *testing.T) {
        }
 }
 
+func TestAllocations(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("BoringCrypto doesn't allocate the same way as stdlib")
+       }
+       in := []byte("hello, world!")
+       out := make([]byte, 0, Size)
+       h := New()
+       n := int(testing.AllocsPerRun(10, func() {
+               h.Reset()
+               h.Write(in)
+               out = h.Sum(out[:0])
+       }))
+       if n > 0 {
+               t.Errorf("allocs = %d, want 0", n)
+       }
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
index a6bb396f1339c2e2601f5d29629669d32c88bfa5..c9c11944876d49d4c2e4efdee5982d555586729d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64 || s390x || ppc64le
-// +build 386 amd64 s390x ppc64le
 
 package sha256
 
index 620c048b93c0672c3957e0a9374a2ceb4b82b220..a8878c2eeea21fe34f4ebc84de8e9ad4066582b0 100644 (file)
@@ -3,8 +3,9 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !386 && !s390x && !ppc64le && !arm64
-// +build !amd64,!386,!s390x,!ppc64le,!arm64
 
 package sha256
 
-var block = blockGeneric
+func block(dig *digest, p []byte) {
+       blockGeneric(dig, p)
+}
index faf732670adf220ed938c22e758428ea27be5071..db5b13c38c4f080cd179dac7bb9bd183e47f9965 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build s390x
-// +build s390x
 
 package sha512
 
index 966cd51d157ae31d3932a670f92586848e7fdc5e..99d1423527bb5ee37f5b0cc4de99f8bfeeef4aa9 100644 (file)
@@ -893,6 +893,23 @@ func TestLargeHashes(t *testing.T) {
        }
 }
 
+func TestAllocations(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("BoringCrypto doesn't allocate the same way as stdlib")
+       }
+       in := []byte("hello, world!")
+       out := make([]byte, 0, Size)
+       h := New()
+       n := int(testing.AllocsPerRun(10, func() {
+               h.Reset()
+               h.Write(in)
+               out = h.Sum(out[:0])
+       }))
+       if n > 0 {
+               t.Errorf("allocs = %d, want 0", n)
+       }
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
index e2386f29ab6fe2d90f3a3f246d18b0200163ec97..8da3e1473f6c45289a690dd6af8783c85d63beab 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64
-// +build amd64
 
 package sha512
 
index 6c22f44801beb9cf014ad40ce4492cfa054a07d0..c6dcdf5db624461bf7af68dcf7478c25c39e89f0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build s390x || ppc64le
-// +build s390x ppc64le
 
 package sha512
 
index 865a7356f1ef75adb185458c83dffa1feb96d68e..62ea237867bce0ce270981405eae9a433955bf68 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !s390x && !ppc64le
-// +build !amd64,!s390x,!ppc64le
 
 package sha512
 
index 3e24d746bcfcace81dcbae75e1d85528dd1bc85e..0da93677b52a6d2aec3386995e2eb7569e708810 100644 (file)
@@ -659,7 +659,7 @@ type Config struct {
        // cipher suite based on logic that takes into account inferred client
        // hardware, server hardware, and security.
        //
-       // Deprected: PreferServerCipherSuites is ignored.
+       // Deprecated: PreferServerCipherSuites is ignored.
        PreferServerCipherSuites bool
 
        // SessionTicketsDisabled may be set to true to disable session ticket and
index 969f357834c0a5c1733b7b939248ebf07d514510..300e9a233c6c0ae9acca734142e82341ed609f55 100644 (file)
@@ -151,6 +151,13 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
        return c.conn.SetWriteDeadline(t)
 }
 
+// NetConn returns the underlying connection that is wrapped by c.
+// Note that writing to or reading from this connection directly will corrupt the
+// TLS session.
+func (c *Conn) NetConn() net.Conn {
+       return c.conn
+}
+
 // A halfConn represents one direction of the record layer
 // connection, either sending or receiving.
 type halfConn struct {
index 7ea90f8a7b51c32f0d7e595a94d96db724872233..58fdd025db7dcf190081b011bacc0f9f69220bda 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Generate a self-signed X.509 certificate for a TLS server. Outputs to
 // 'cert.pem' and 'key.pem' and will overwrite existing files.
index b6eb488a4d7899bc19ad2c6e330ff8c60bf4beb4..2158f3247b941dba3890756dd2e946b2e8dc9e61 100644 (file)
@@ -97,18 +97,18 @@ func (o *opensslOutputSink) Write(data []byte) (n int, err error) {
        o.all = append(o.all, data...)
 
        for {
-               i := bytes.IndexByte(o.line, '\n')
-               if i < 0 {
+               line, next, ok := bytes.Cut(o.line, []byte("\n"))
+               if !ok {
                        break
                }
 
-               if bytes.Equal([]byte(opensslEndOfHandshake), o.line[:i]) {
+               if bytes.Equal([]byte(opensslEndOfHandshake), line) {
                        o.handshakeComplete <- struct{}{}
                }
-               if bytes.Equal([]byte(opensslReadKeyUpdate), o.line[:i]) {
+               if bytes.Equal([]byte(opensslReadKeyUpdate), line) {
                        o.readKeyUpdate <- struct{}{}
                }
-               o.line = o.line[i+1:]
+               o.line = next
        }
 
        return len(data), nil
index b5f81e443668a1ead5e0c9c5e8806437b32f7a6c..17cf85910fafd8603949d68a6360b972e3aa5802 100644 (file)
@@ -329,8 +329,7 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
        m.pskBinders = pskBinders
        if m.raw != nil {
                lenWithoutBinders := len(m.marshalWithoutBinders())
-               // TODO(filippo): replace with NewFixedBuilder once CL 148882 is imported.
-               b := cryptobyte.NewBuilder(m.raw[:lenWithoutBinders])
+               b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders])
                b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
                        for _, binder := range m.pskBinders {
                                b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
@@ -338,7 +337,7 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
                                })
                        }
                })
-               if len(b.BytesOrPanic()) != len(m.raw) {
+               if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) {
                        panic("tls: internal error: failed to update binders")
                }
        }
index 9bfb1177f27d04402ae687e2e1365154bbc8a818..90ac9bd11ee2ae31d1ec654f1f9776cf5c7ed834 100644 (file)
@@ -191,18 +191,17 @@ func parseTestData(r io.Reader) (flows [][]byte, err error) {
                // Otherwise the line is a line of hex dump that looks like:
                // 00000170  fc f5 06 bf (...)  |.....X{&?......!|
                // (Some bytes have been omitted from the middle section.)
-
-               if i := strings.IndexByte(line, ' '); i >= 0 {
-                       line = line[i:]
-               } else {
+               _, after, ok := strings.Cut(line, " ")
+               if !ok {
                        return nil, errors.New("invalid test data")
                }
+               line = after
 
-               if i := strings.IndexByte(line, '|'); i >= 0 {
-                       line = line[:i]
-               } else {
+               before, _, ok := strings.Cut(line, "|")
+               if !ok {
                        return nil, errors.New("invalid test data")
                }
+               line = before
 
                hexBytes := strings.Fields(line)
                for _, hexByte := range hexBytes {
index 19fc6986769f62fdb5eb29ca1c84694b51e8013b..b61e7c24efb2049429a3051dbfc7e7c8d9e924d9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package tls
 
index fcfbc1e561573d9ae59a7a4feb0704de5e06d975..a91131ac984ad3e8d0b3035c62bf39391e52c754 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin && !ios
-// +build darwin,!ios
 
 // Package macOS provides cgo-less wrappers for Core Foundation and
 // Security.framework, similarly to how package syscall provides access to
index 0f6fa42b7bf61baad76663f566719297bc953d6c..a560248e8b760d1f5b16cbaf3fa2cc2fcae7762c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin && !ios
-// +build darwin,!ios
 
 package macOS
 
index c59a7dc1a62c7343fbc7126a9a965a6613b4e548..a6b5aa1ee65202259acec545dde1a5271bb21b62 100644 (file)
@@ -1279,8 +1279,8 @@ var nameConstraintsTests = []nameConstraintsTest{
                expectedError: "incompatible key usage",
        },
 
-       // #67: in order to support COMODO chains, SGC key usages permit
-       // serverAuth and clientAuth.
+       // #67: SGC key usages used to permit serverAuth and clientAuth,
+       // but don't anymore.
        {
                roots: []constraintsSpec{
                        {},
@@ -1296,10 +1296,11 @@ var nameConstraintsTests = []nameConstraintsTest{
                        sans: []string{"dns:example.com"},
                        ekus: []string{"serverAuth", "clientAuth"},
                },
+               expectedError: "incompatible key usage",
        },
 
-       // #68: in order to support COMODO chains, SGC key usages permit
-       // serverAuth and clientAuth.
+       // #68: SGC key usages used to permit serverAuth and clientAuth,
+       // but don't anymore.
        {
                roots: make([]constraintsSpec, 1),
                intermediates: [][]constraintsSpec{
@@ -1313,6 +1314,7 @@ var nameConstraintsTests = []nameConstraintsTest{
                        sans: []string{"dns:example.com"},
                        ekus: []string{"serverAuth", "clientAuth"},
                },
+               expectedError: "incompatible key usage",
        },
 
        // #69: an empty DNS constraint should allow anything.
@@ -1437,7 +1439,8 @@ var nameConstraintsTests = []nameConstraintsTest{
                expectedError: "incompatible key usage",
        },
 
-       // #76: However, MSSGC in a leaf should match a request for serverAuth.
+       // #76: MSSGC in a leaf used to match a request for serverAuth, but doesn't
+       // anymore.
        {
                roots: make([]constraintsSpec, 1),
                intermediates: [][]constraintsSpec{
@@ -1450,6 +1453,7 @@ var nameConstraintsTests = []nameConstraintsTest{
                        ekus: []string{"msSGC"},
                },
                requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+               expectedError: "incompatible key usage",
        },
 
        // An invalid DNS SAN should be detected only at validation time so
index f085162a4e88be3d998cdb1bdfebb61282cdee0f..c2770f3f08dc0a2812ee93627a4662f1c1d7c95f 100644 (file)
@@ -214,16 +214,16 @@ func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) {
 func parseExtension(der cryptobyte.String) (pkix.Extension, error) {
        var ext pkix.Extension
        if !der.ReadASN1ObjectIdentifier(&ext.Id) {
-               return ext, errors.New("x509: malformed extention OID field")
+               return ext, errors.New("x509: malformed extension OID field")
        }
        if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) {
                if !der.ReadASN1Boolean(&ext.Critical) {
-                       return ext, errors.New("x509: malformed extention critical field")
+                       return ext, errors.New("x509: malformed extension critical field")
                }
        }
        var val cryptobyte.String
        if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) {
-               return ext, errors.New("x509: malformed extention value field")
+               return ext, errors.New("x509: malformed extension value field")
        }
        ext.Value = val
        return ext, nil
index 781cb3de834d94c02eaad1abe3ce362e1ca7af73..682923ac531fdaca2bbcef78d2598ffcdb1dbe8e 100644 (file)
@@ -127,12 +127,11 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
                return nil, errors.New("x509: no DEK-Info header in block")
        }
 
-       idx := strings.Index(dek, ",")
-       if idx == -1 {
+       mode, hexIV, ok := strings.Cut(dek, ",")
+       if !ok {
                return nil, errors.New("x509: malformed DEK-Info header")
        }
 
-       mode, hexIV := dek[:idx], dek[idx+1:]
        ciph := cipherByName(mode)
        if ciph == nil {
                return nil, errors.New("x509: unknown encryption mode")
index 6712ea32a68414681c5cd0658dc12f930107327f..8ac205faa95d9a44398b8e634bb5d31b4d29b62a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || netbsd || openbsd
-// +build dragonfly freebsd netbsd openbsd
 
 package x509
 
index 05593bb1055b50d06df34ec12455385621f3b856..ef051efd31556ef8e4bc952b23afa9bedebb77c3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !ios
-// +build !ios
 
 package x509
 
@@ -11,11 +10,11 @@ import (
        "bytes"
        macOS "crypto/x509/internal/macos"
        "fmt"
+       "internal/godebug"
        "os"
-       "strings"
 )
 
-var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
+var debugDarwinRoots = godebug.Get("x509roots") == "1"
 
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
        return nil, nil
index 9bc62f8abb6802747da47494632341f5c37a7d73..c5e3fc0b729a15aa9e0db54d86893401ff9038f0 100644 (file)
@@ -2,7 +2,6 @@
 // Update the version in root.go and regenerate with "go generate".
 
 //go:build ios && !x509omitbundledroots
-// +build ios,!x509omitbundledroots
 
 package x509
 
index 05bd672d5d8355a4bb32fd70e64c121edbdf5614..15eb1592ca6759b099cad9ee2ad1b87e64bd740c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Generates root_ios.go.
 //
@@ -164,8 +163,8 @@ func main() {
 const header = `// Code generated by root_ios_gen.go -version %s; DO NOT EDIT.
 // Update the version in root.go and regenerate with "go generate".
 
-// +build ios
-// +build !x509omitbundledroots
+//go:build ios && !x509omitbundledroots
+// +build ios,!x509omitbundledroots
 
 package x509
 
index f2c2c0af3803851cca5811c627cff5f1979366d8..95930385177847fd914ded89619715d2954afdc5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package x509
 
index 81f2f112d07da5e2933a008d5518e76d774135d8..299d74835efc238541c5526e01bc1ed292b808ff 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ((darwin && arm64) || (darwin && amd64 && ios)) && 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,
index 158bd7f91aebedc7195d4cbbd96f6fd6446ca612..1709e2ea8b5d80170f575456df5fb0ff48449125 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ((darwin && arm64) || (darwin && amd64 && ios)) && x509omitbundledroots
-// +build darwin,arm64 darwin,amd64,ios
-// +build x509omitbundledroots
 
 package x509
 
index 2bdb2fe7136aced8f87c1a344ffe77bd9c737050..3bd06fe50d85bf2f2e6eba64d126759b718de102 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package x509
 
index dede825eddf4967fee4e2cbf9be06593c69f3d02..aa54f891ca003a6c9dcaedc50a95a8c28569fa85 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package x509
 
index 7118f12d744cdf5e4a8515d47496652eb3297f6a..7197a0de3b185c26e597b894ee2fc56b426daea1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build dragonfly freebsd linux netbsd openbsd solaris
 
 package x509
 
index 1e9be80b7dd67d35c73cfb01ec743a23c879da3a..f77ea3a69840f61a3979a6ae5cbdf163625605b9 100644 (file)
@@ -218,11 +218,6 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
                if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
                        oids = append(oids, &oid[0])
                }
-               // Like the standard verifier, accept SGC EKUs as equivalent to ServerAuth.
-               if eku == ExtKeyUsageServerAuth {
-                       oids = append(oids, &syscall.OID_SERVER_GATED_CRYPTO[0])
-                       oids = append(oids, &syscall.OID_SGC_NETSCAPE[0])
-               }
        }
        if oids != nil {
                para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
index 1f9636a550f038eefd466682911d29f27e5e9c67..25a526181ced3905a36629927ee2c7d1cf52fa84 100644 (file)
@@ -1097,14 +1097,6 @@ NextCert:
                        for _, usage := range cert.ExtKeyUsage {
                                if requestedUsage == usage {
                                        continue NextRequestedUsage
-                               } else if requestedUsage == ExtKeyUsageServerAuth &&
-                                       (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
-                                               usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
-                                       // In order to support COMODO
-                                       // certificate chains, we have to
-                                       // accept Netscape or Microsoft SGC
-                                       // usages as equal to ServerAuth.
-                                       continue NextRequestedUsage
                                }
                        }
 
index 9954a670da0bd16cfd3b5e594c6e2b63da5941f6..df78abd77e30c90f8c02fddea8c1403a60f2ea38 100644 (file)
@@ -203,19 +203,6 @@ var verifyTests = []verifyTest{
                        {"CORPORATIVO FICTICIO ACTIVO", "EAEko Herri Administrazioen CA - CA AAPP Vascas (2)", "IZENPE S.A."},
                },
        },
-       {
-               name:          "SGCIntermediate",
-               leaf:          megaLeaf,
-               intermediates: []string{comodoIntermediate1},
-               roots:         []string{comodoRoot},
-               currentTime:   1360431182,
-
-               // CryptoAPI can find alternative validation paths.
-               systemLax: true,
-               expectedChains: [][]string{
-                       {"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"},
-               },
-       },
        {
                // Check that a name constrained intermediate works even when
                // it lists multiple constraints.
@@ -932,93 +919,6 @@ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
 QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
 -----END CERTIFICATE-----`
 
-var megaLeaf = `-----BEGIN CERTIFICATE-----
-MIIFOjCCBCKgAwIBAgIQWYE8Dup170kZ+k11Lg51OjANBgkqhkiG9w0BAQUFADBy
-MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
-VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEYMBYGA1UE
-AxMPRXNzZW50aWFsU1NMIENBMB4XDTEyMTIxNDAwMDAwMFoXDTE0MTIxNDIzNTk1
-OVowfzEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMS4wLAYDVQQL
-EyVIb3N0ZWQgYnkgSW5zdHJhIENvcnBvcmF0aW9uIFB0eS4gTFREMRUwEwYDVQQL
-EwxFc3NlbnRpYWxTU0wxEzARBgNVBAMTCm1lZ2EuY28ubnowggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDcxMCClae8BQIaJHBUIVttlLvhbK4XhXPk3RQ3
-G5XA6tLZMBQ33l3F9knYJ0YErXtr8IdfYoulRQFmKFMJl9GtWyg4cGQi2Rcr5VN5
-S5dA1vu4oyJBxE9fPELcK6Yz1vqaf+n6za+mYTiQYKggVdS8/s8hmNuXP9Zk1pIn
-+q0pGsf8NAcSHMJgLqPQrTDw+zae4V03DvcYfNKjuno88d2226ld7MAmQZ7uRNsI
-/CnkdelVs+akZsXf0szefSqMJlf08SY32t2jj4Ra7RApVYxOftD9nij/aLfuqOU6
-ow6IgIcIG2ZvXLZwK87c5fxL7UAsTTV+M1sVv8jA33V2oKLhAgMBAAGjggG9MIIB
-uTAfBgNVHSMEGDAWgBTay+qtWwhdzP/8JlTOSeVVxjj0+DAdBgNVHQ4EFgQUmP9l
-6zhyrZ06Qj4zogt+6LKFk4AwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAw
-NAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglghkgB
-hvhCBAEwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQICBzArMCkGCCsGAQUFBwIBFh1o
-dHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAIBgZngQwBAgEwOwYDVR0fBDQw
-MjAwoC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vRXNzZW50aWFsU1NMQ0Eu
-Y3JsMG4GCCsGAQUFBwEBBGIwYDA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21v
-ZG9jYS5jb20vRXNzZW50aWFsU1NMQ0FfMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6
-Ly9vY3NwLmNvbW9kb2NhLmNvbTAlBgNVHREEHjAcggptZWdhLmNvLm56gg53d3cu
-bWVnYS5jby5uejANBgkqhkiG9w0BAQUFAAOCAQEAcYhrsPSvDuwihMOh0ZmRpbOE
-Gw6LqKgLNTmaYUPQhzi2cyIjhUhNvugXQQlP5f0lp5j8cixmArafg1dTn4kQGgD3
-ivtuhBTgKO1VYB/VRoAt6Lmswg3YqyiS7JiLDZxjoV7KoS5xdiaINfHDUaBBY4ZH
-j2BUlPniNBjCqXe/HndUTVUewlxbVps9FyCmH+C4o9DWzdGBzDpCkcmo5nM+cp7q
-ZhTIFTvZfo3zGuBoyu8BzuopCJcFRm3cRiXkpI7iOMUIixO1szkJS6WpL1sKdT73
-UXp08U0LBqoqG130FbzEJBBV3ixbvY6BWMHoCWuaoF12KJnC5kHt2RoWAAgMXA==
------END CERTIFICATE-----`
-
-var comodoIntermediate1 = `-----BEGIN CERTIFICATE-----
-MIIFAzCCA+ugAwIBAgIQGLLLuqME8aAPwfLzJkYqSjANBgkqhkiG9w0BAQUFADCB
-gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
-BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
-MDBaFw0xOTEyMzEyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVh
-dGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9E
-TyBDQSBMaW1pdGVkMRgwFgYDVQQDEw9Fc3NlbnRpYWxTU0wgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt8AiwcsargxIxF3CJhakgEtSYau2A1NHf
-5I5ZLdOWIY120j8YC0YZYwvHIPPlC92AGvFaoL0dds23Izp0XmEbdaqb1IX04XiR
-0y3hr/yYLgbSeT1awB8hLRyuIVPGOqchfr7tZ291HRqfalsGs2rjsQuqag7nbWzD
-ypWMN84hHzWQfdvaGlyoiBSyD8gSIF/F03/o4Tjg27z5H6Gq1huQByH6RSRQXScq
-oChBRVt9vKCiL6qbfltTxfEFFld+Edc7tNkBdtzffRDPUanlOPJ7FAB1WfnwWdsX
-Pvev5gItpHnBXaIcw5rIp6gLSApqLn8tl2X2xQScRMiZln5+pN0vAgMBAAGjggGD
-MIIBfzAfBgNVHSMEGDAWgBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAdBgNVHQ4EFgQU
-2svqrVsIXcz//CZUzknlVcY49PgwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
-MAYBAf8CAQAwIAYDVR0lBBkwFwYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMD4GA1Ud
-IAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21v
-ZG8uY29tL0NQUzBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2Nh
-LmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBsBggrBgEFBQcB
-AQRgMF4wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NvbW9k
-b1VUTlNHQ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2Eu
-Y29tMA0GCSqGSIb3DQEBBQUAA4IBAQAtlzR6QDLqcJcvgTtLeRJ3rvuq1xqo2l/z
-odueTZbLN3qo6u6bldudu+Ennv1F7Q5Slqz0J790qpL0pcRDAB8OtXj5isWMcL2a
-ejGjKdBZa0wztSz4iw+SY1dWrCRnilsvKcKxudokxeRiDn55w/65g+onO7wdQ7Vu
-F6r7yJiIatnyfKH2cboZT7g440LX8NqxwCPf3dfxp+0Jj1agq8MLy6SSgIGSH6lv
-+Wwz3D5XxqfyH8wqfOQsTEZf6/Nh9yvENZ+NWPU6g0QO2JOsTGvMd/QDzczc4BxL
-XSXaPV7Od4rhPsbXlM1wSTz/Dr0ISKvlUhQVnQ6cGodWaK2cCQBk
------END CERTIFICATE-----`
-
-var comodoRoot = `-----BEGIN CERTIFICATE-----
-MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
-gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
-BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
-MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
-YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
-RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
-UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
-2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
-Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
-+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
-DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
-nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
-/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
-PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
-QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
-SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
-IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
-RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
-zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
-BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
-ZQ==
------END CERTIFICATE-----`
-
 var nameConstraintsLeaf = `-----BEGIN CERTIFICATE-----
 MIIHMTCCBRmgAwIBAgIIIZaV/3ezOJkwDQYJKoZIhvcNAQEFBQAwgcsxCzAJBgNV
 BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEj
index ef3ee807bf0c5d037d7ce8beea4a7d8be9f39acb..2474e3d810edfd4a591c48226cf4b0bad2f6a3ea 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // This file is run by the x509 tests to ensure that a program with minimal
 // imports can sign certificates without errors resulting from missing hash
index b966ef970c17047731eed681d5a6729de15e3e54..c0997b7fc5d3320d62e8d209f521051e96a77d11 100644 (file)
@@ -386,7 +386,7 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
        }
 
        dpv := reflect.ValueOf(dest)
-       if dpv.Kind() != reflect.Ptr {
+       if dpv.Kind() != reflect.Pointer {
                return errors.New("destination not a pointer")
        }
        if dpv.IsNil() {
@@ -419,7 +419,7 @@ func convertAssignRows(dest, src interface{}, rows *Rows) error {
        // This also allows scanning into user defined types such as "type Int int64".
        // For symmetry, also check for string destination types.
        switch dv.Kind() {
-       case reflect.Ptr:
+       case reflect.Pointer:
                if src == nil {
                        dv.Set(reflect.Zero(dv.Type()))
                        return nil
@@ -551,7 +551,7 @@ var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
 //
 // This function is mirrored in the database/sql/driver package.
 func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
-       if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+       if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Pointer &&
                rv.IsNil() &&
                rv.Type().Elem().Implements(valuerReflectType) {
                return nil, nil
index 2668a5ed5e76b15313142ac6a6df2e8a76e1123e..400da7ea577231b455c42167c7e225a2b34e026c 100644 (file)
@@ -51,9 +51,6 @@ var (
        scanbytes  []byte
        scanraw    RawBytes
        scanint    int
-       scanint8   int8
-       scanint16  int16
-       scanint32  int32
        scanuint8  uint8
        scanuint16 uint16
        scanbool   bool
index f09396175acf86099e5d902fb944d1f8131210e2..ea1de5a8fb6a8b4f056b2b83f99c5ee985a5fce5 100644 (file)
@@ -156,6 +156,9 @@ var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
 // if there's a possibility that the database server might have
 // performed the operation. Even if the server sends back an error,
 // you shouldn't return ErrBadConn.
+//
+// Errors will be checked using errors.Is. An error may
+// wrap ErrBadConn or implement the Is(error) bool method.
 var ErrBadConn = errors.New("driver: bad connection")
 
 // Pinger is an optional interface that may be implemented by a Conn.
index 24c3a45483637816365a6b5682394d8c600e334e..3337c2e0bc92ae7414cf73a1343b5d737fe5f141 100644 (file)
@@ -225,7 +225,7 @@ var valuerReflectType = reflect.TypeOf((*Valuer)(nil)).Elem()
 //
 // This function is mirrored in the database/sql package.
 func callValuerValue(vr Valuer) (v Value, err error) {
-       if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+       if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Pointer &&
                rv.IsNil() &&
                rv.Type().Elem().Implements(valuerReflectType) {
                return nil, nil
@@ -256,7 +256,7 @@ func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
 
        rv := reflect.ValueOf(v)
        switch rv.Kind() {
-       case reflect.Ptr:
+       case reflect.Pointer:
                // indirect pointers
                if rv.IsNil() {
                        return nil, nil
index 4b68f1cba9fe1aa7f9b2806494a8eb4c6c9e066f..34e97e012b1a363d703aafae3a24e2642fe2a8e5 100644 (file)
@@ -96,6 +96,19 @@ type fakeDB struct {
        allowAny bool
 }
 
+type fakeError struct {
+       Message string
+       Wrapped error
+}
+
+func (err fakeError) Error() string {
+       return err.Message
+}
+
+func (err fakeError) Unwrap() error {
+       return err.Wrapped
+}
+
 type table struct {
        mu      sync.Mutex
        colname []string
@@ -368,7 +381,7 @@ func (c *fakeConn) isDirtyAndMark() bool {
 
 func (c *fakeConn) Begin() (driver.Tx, error) {
        if c.isBad() {
-               return nil, driver.ErrBadConn
+               return nil, fakeError{Wrapped: driver.ErrBadConn}
        }
        if c.currTx != nil {
                return nil, errors.New("fakedb: already in a transaction")
@@ -401,7 +414,7 @@ func (c *fakeConn) ResetSession(ctx context.Context) error {
        c.dirtySession = false
        c.currTx = nil
        if c.isBad() {
-               return driver.ErrBadConn
+               return fakeError{Message: "Reset Session: bad conn", Wrapped: driver.ErrBadConn}
        }
        return nil
 }
@@ -629,7 +642,7 @@ func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stm
        }
 
        if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) {
-               return nil, driver.ErrBadConn
+               return nil, fakeError{Message: "Preapre: Sticky Bad", Wrapped: driver.ErrBadConn}
        }
 
        c.touchMem()
@@ -756,7 +769,7 @@ func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (d
        }
 
        if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) {
-               return nil, driver.ErrBadConn
+               return nil, fakeError{Message: "Exec: Sticky Bad", Wrapped: driver.ErrBadConn}
        }
        if s.c.isDirtyAndMark() {
                return nil, errFakeConnSessionDirty
@@ -870,7 +883,7 @@ func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (
        }
 
        if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) {
-               return nil, driver.ErrBadConn
+               return nil, fakeError{Message: "Query: Sticky Bad", Wrapped: driver.ErrBadConn}
        }
        if s.c.isDirtyAndMark() {
                return nil, errFakeConnSessionDirty
@@ -1031,7 +1044,7 @@ var hookCommitBadConn func() bool
 func (tx *fakeTx) Commit() error {
        tx.c.currTx = nil
        if hookCommitBadConn != nil && hookCommitBadConn() {
-               return driver.ErrBadConn
+               return fakeError{Message: "Commit: Hook Bad Conn", Wrapped: driver.ErrBadConn}
        }
        tx.c.touchMem()
        return nil
@@ -1043,7 +1056,7 @@ var hookRollbackBadConn func() bool
 func (tx *fakeTx) Rollback() error {
        tx.c.currTx = nil
        if hookRollbackBadConn != nil && hookRollbackBadConn() {
-               return driver.ErrBadConn
+               return fakeError{Message: "Rollback: Hook Bad Conn", Wrapped: driver.ErrBadConn}
        }
        tx.c.touchMem()
        return nil
index 68fb392e0dbb45f5f4246fa8f95797250dee0735..5131c08b511f4d14c22ebf0f8014b351dcf224f0 100644 (file)
@@ -464,8 +464,8 @@ type DB struct {
        // connections in Stmt.css.
        numClosed uint64
 
-       mu           sync.Mutex // protects following fields
-       freeConn     []*driverConn
+       mu           sync.Mutex    // protects following fields
+       freeConn     []*driverConn // free connections ordered by returnedAt oldest to newest
        connRequests map[uint64]chan connRequest
        nextRequest  uint64 // Next key to use in connRequests.
        numOpen      int    // number of opened and pending open connections
@@ -848,14 +848,15 @@ func (db *DB) pingDC(ctx context.Context, dc *driverConn, release func(error)) e
 func (db *DB) PingContext(ctx context.Context) error {
        var dc *driverConn
        var err error
-
+       var isBadConn bool
        for i := 0; i < maxBadConnRetries; i++ {
                dc, err = db.conn(ctx, cachedOrNewConn)
-               if err != driver.ErrBadConn {
+               isBadConn = errors.Is(err, driver.ErrBadConn)
+               if !isBadConn {
                        break
                }
        }
-       if err == driver.ErrBadConn {
+       if isBadConn {
                dc, err = db.conn(ctx, alwaysNewConn)
        }
        if err != nil {
@@ -1079,7 +1080,7 @@ func (db *DB) connectionCleaner(d time.Duration) {
                        return
                }
 
-               closing := db.connectionCleanerRunLocked()
+               d, closing := db.connectionCleanerRunLocked(d)
                db.mu.Unlock()
                for _, c := range closing {
                        c.Close()
@@ -1088,45 +1089,74 @@ func (db *DB) connectionCleaner(d time.Duration) {
                if d < minInterval {
                        d = minInterval
                }
+
+               if !t.Stop() {
+                       select {
+                       case <-t.C:
+                       default:
+                       }
+               }
                t.Reset(d)
        }
 }
 
-func (db *DB) connectionCleanerRunLocked() (closing []*driverConn) {
-       if db.maxLifetime > 0 {
-               expiredSince := nowFunc().Add(-db.maxLifetime)
-               for i := 0; i < len(db.freeConn); i++ {
+// connectionCleanerRunLocked removes connections that should be closed from
+// freeConn and returns them along side an updated duration to the next check
+// if a quicker check is required to ensure connections are checked appropriately.
+func (db *DB) connectionCleanerRunLocked(d time.Duration) (time.Duration, []*driverConn) {
+       var idleClosing int64
+       var closing []*driverConn
+       if db.maxIdleTime > 0 {
+               // As freeConn is ordered by returnedAt process
+               // in reverse order to minimise the work needed.
+               idleSince := nowFunc().Add(-db.maxIdleTime)
+               last := len(db.freeConn) - 1
+               for i := last; i >= 0; i-- {
                        c := db.freeConn[i]
-                       if c.createdAt.Before(expiredSince) {
-                               closing = append(closing, c)
-                               last := len(db.freeConn) - 1
-                               db.freeConn[i] = db.freeConn[last]
-                               db.freeConn[last] = nil
-                               db.freeConn = db.freeConn[:last]
-                               i--
+                       if c.returnedAt.Before(idleSince) {
+                               i++
+                               closing = db.freeConn[:i]
+                               db.freeConn = db.freeConn[i:]
+                               idleClosing = int64(len(closing))
+                               db.maxIdleTimeClosed += idleClosing
+                               break
+                       }
+               }
+
+               if len(db.freeConn) > 0 {
+                       c := db.freeConn[0]
+                       if d2 := c.returnedAt.Sub(idleSince); d2 < d {
+                               // Ensure idle connections are cleaned up as soon as
+                               // possible.
+                               d = d2
                        }
                }
-               db.maxLifetimeClosed += int64(len(closing))
        }
 
-       if db.maxIdleTime > 0 {
-               expiredSince := nowFunc().Add(-db.maxIdleTime)
-               var expiredCount int64
+       if db.maxLifetime > 0 {
+               expiredSince := nowFunc().Add(-db.maxLifetime)
                for i := 0; i < len(db.freeConn); i++ {
                        c := db.freeConn[i]
-                       if db.maxIdleTime > 0 && c.returnedAt.Before(expiredSince) {
+                       if c.createdAt.Before(expiredSince) {
                                closing = append(closing, c)
-                               expiredCount++
+
                                last := len(db.freeConn) - 1
-                               db.freeConn[i] = db.freeConn[last]
+                               // Use slow delete as order is required to ensure
+                               // connections are reused least idle time first.
+                               copy(db.freeConn[i:], db.freeConn[i+1:])
                                db.freeConn[last] = nil
                                db.freeConn = db.freeConn[:last]
                                i--
+                       } else if d2 := c.createdAt.Sub(expiredSince); d2 < d {
+                               // Prevent connections sitting the freeConn when they
+                               // have expired by updating our next deadline d.
+                               d = d2
                        }
                }
-               db.maxIdleTimeClosed += expiredCount
+               db.maxLifetimeClosed += int64(len(closing)) - idleClosing
        }
-       return
+
+       return d, closing
 }
 
 // DBStats contains database statistics.
@@ -1272,11 +1302,12 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
        lifetime := db.maxLifetime
 
        // Prefer a free connection, if possible.
-       numFree := len(db.freeConn)
-       if strategy == cachedOrNewConn && numFree > 0 {
-               conn := db.freeConn[0]
-               copy(db.freeConn, db.freeConn[1:])
-               db.freeConn = db.freeConn[:numFree-1]
+       last := len(db.freeConn) - 1
+       if strategy == cachedOrNewConn && last >= 0 {
+               // Reuse the lowest idle time connection so we can close
+               // connections which remain idle as soon as possible.
+               conn := db.freeConn[last]
+               db.freeConn = db.freeConn[:last]
                conn.inUse = true
                if conn.expired(lifetime) {
                        db.maxLifetimeClosed++
@@ -1287,9 +1318,9 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
                db.mu.Unlock()
 
                // Reset the session if required.
-               if err := conn.resetSession(ctx); err == driver.ErrBadConn {
+               if err := conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) {
                        conn.Close()
-                       return nil, driver.ErrBadConn
+                       return nil, err
                }
 
                return conn, nil
@@ -1351,9 +1382,9 @@ func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn
                        }
 
                        // Reset the session if required.
-                       if err := ret.conn.resetSession(ctx); err == driver.ErrBadConn {
+                       if err := ret.conn.resetSession(ctx); errors.Is(err, driver.ErrBadConn) {
                                ret.conn.Close()
-                               return nil, driver.ErrBadConn
+                               return nil, err
                        }
                        return ret.conn, ret.err
                }
@@ -1412,7 +1443,7 @@ const debugGetPut = false
 // putConn adds a connection to the db's free pool.
 // err is optionally the last error that occurred on this connection.
 func (db *DB) putConn(dc *driverConn, err error, resetSession bool) {
-       if err != driver.ErrBadConn {
+       if !errors.Is(err, driver.ErrBadConn) {
                if !dc.validateConnection(resetSession) {
                        err = driver.ErrBadConn
                }
@@ -1426,7 +1457,7 @@ func (db *DB) putConn(dc *driverConn, err error, resetSession bool) {
                panic("sql: connection returned that was never out")
        }
 
-       if err != driver.ErrBadConn && dc.expired(db.maxLifetime) {
+       if !errors.Is(err, driver.ErrBadConn) && dc.expired(db.maxLifetime) {
                db.maxLifetimeClosed++
                err = driver.ErrBadConn
        }
@@ -1441,7 +1472,7 @@ func (db *DB) putConn(dc *driverConn, err error, resetSession bool) {
        }
        dc.onPut = nil
 
-       if err == driver.ErrBadConn {
+       if errors.Is(err, driver.ErrBadConn) {
                // Don't reuse bad connections.
                // Since the conn is considered bad and is being discarded, treat it
                // as closed. Don't decrement the open count here, finalClose will
@@ -1521,13 +1552,15 @@ const maxBadConnRetries = 2
 func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
        var stmt *Stmt
        var err error
+       var isBadConn bool
        for i := 0; i < maxBadConnRetries; i++ {
                stmt, err = db.prepare(ctx, query, cachedOrNewConn)
-               if err != driver.ErrBadConn {
+               isBadConn = errors.Is(err, driver.ErrBadConn)
+               if !isBadConn {
                        break
                }
        }
-       if err == driver.ErrBadConn {
+       if isBadConn {
                return db.prepare(ctx, query, alwaysNewConn)
        }
        return stmt, err
@@ -1597,13 +1630,15 @@ func (db *DB) prepareDC(ctx context.Context, dc *driverConn, release func(error)
 func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
        var res Result
        var err error
+       var isBadConn bool
        for i := 0; i < maxBadConnRetries; i++ {
                res, err = db.exec(ctx, query, args, cachedOrNewConn)
-               if err != driver.ErrBadConn {
+               isBadConn = errors.Is(err, driver.ErrBadConn)
+               if !isBadConn {
                        break
                }
        }
-       if err == driver.ErrBadConn {
+       if isBadConn {
                return db.exec(ctx, query, args, alwaysNewConn)
        }
        return res, err
@@ -1670,13 +1705,15 @@ func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), q
 func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
        var rows *Rows
        var err error
+       var isBadConn bool
        for i := 0; i < maxBadConnRetries; i++ {
                rows, err = db.query(ctx, query, args, cachedOrNewConn)
-               if err != driver.ErrBadConn {
+               isBadConn = errors.Is(err, driver.ErrBadConn)
+               if !isBadConn {
                        break
                }
        }
-       if err == driver.ErrBadConn {
+       if isBadConn {
                return db.query(ctx, query, args, alwaysNewConn)
        }
        return rows, err
@@ -1805,13 +1842,15 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 func (db *DB) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
        var tx *Tx
        var err error
+       var isBadConn bool
        for i := 0; i < maxBadConnRetries; i++ {
                tx, err = db.begin(ctx, opts, cachedOrNewConn)
-               if err != driver.ErrBadConn {
+               isBadConn = errors.Is(err, driver.ErrBadConn)
+               if !isBadConn {
                        break
                }
        }
-       if err == driver.ErrBadConn {
+       if isBadConn {
                return db.begin(ctx, opts, alwaysNewConn)
        }
        return tx, err
@@ -1884,13 +1923,15 @@ var ErrConnDone = errors.New("sql: connection is already closed")
 func (db *DB) Conn(ctx context.Context) (*Conn, error) {
        var dc *driverConn
        var err error
+       var isBadConn bool
        for i := 0; i < maxBadConnRetries; i++ {
                dc, err = db.conn(ctx, cachedOrNewConn)
-               if err != driver.ErrBadConn {
+               isBadConn = errors.Is(err, driver.ErrBadConn)
+               if !isBadConn {
                        break
                }
        }
-       if err == driver.ErrBadConn {
+       if isBadConn {
                dc, err = db.conn(ctx, alwaysNewConn)
        }
        if err != nil {
@@ -2002,7 +2043,7 @@ func (c *Conn) PrepareContext(ctx context.Context, query string) (*Stmt, error)
 // Raw executes f exposing the underlying driver connection for the
 // duration of f. The driverConn must not be used outside of f.
 //
-// Once f returns and err is nil, the Conn will continue to be usable
+// Once f returns and err is not driver.ErrBadConn, the Conn will continue to be usable
 // until Conn.Close is called.
 func (c *Conn) Raw(f func(driverConn interface{}) error) (err error) {
        var dc *driverConn
@@ -2054,7 +2095,7 @@ func (c *Conn) BeginTx(ctx context.Context, opts *TxOptions) (*Tx, error) {
 // as the sql operation is done with the dc.
 func (c *Conn) closemuRUnlockCondReleaseConn(err error) {
        c.closemu.RUnlock()
-       if err == driver.ErrBadConn {
+       if errors.Is(err, driver.ErrBadConn) {
                c.close(err)
        }
 }
@@ -2248,7 +2289,7 @@ func (tx *Tx) Commit() error {
        withLock(tx.dc, func() {
                err = tx.txi.Commit()
        })
-       if err != driver.ErrBadConn {
+       if !errors.Is(err, driver.ErrBadConn) {
                tx.closePrepared()
        }
        tx.close(err)
@@ -2280,7 +2321,7 @@ func (tx *Tx) rollback(discardConn bool) error {
        withLock(tx.dc, func() {
                err = tx.txi.Rollback()
        })
-       if err != driver.ErrBadConn {
+       if !errors.Is(err, driver.ErrBadConn) {
                tx.closePrepared()
        }
        if discardConn {
@@ -2323,8 +2364,8 @@ func (tx *Tx) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
 
 // Prepare creates a prepared statement for use within a transaction.
 //
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
+// The returned statement operates within the transaction and will be closed
+// when the transaction has been committed or rolled back.
 //
 // To use an existing prepared statement on this transaction, see Tx.Stmt.
 //
@@ -2586,7 +2627,7 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, er
                }
                dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
                if err != nil {
-                       if err == driver.ErrBadConn {
+                       if errors.Is(err, driver.ErrBadConn) {
                                continue
                        }
                        return nil, err
@@ -2594,7 +2635,7 @@ func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, er
 
                res, err = resultFromStatement(ctx, dc.ci, ds, args...)
                releaseConn(err)
-               if err != driver.ErrBadConn {
+               if !errors.Is(err, driver.ErrBadConn) {
                        return res, err
                }
        }
@@ -2734,7 +2775,7 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
                }
                dc, releaseConn, ds, err := s.connStmt(ctx, strategy)
                if err != nil {
-                       if err == driver.ErrBadConn {
+                       if errors.Is(err, driver.ErrBadConn) {
                                continue
                        }
                        return nil, err
@@ -2768,7 +2809,7 @@ func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, er
                }
 
                releaseConn(err)
-               if err != driver.ErrBadConn {
+               if !errors.Is(err, driver.ErrBadConn) {
                        return nil, err
                }
        }
index f771dee4a9772a37444ef9b65d27de9b12af887a..889adc3164ed4d6294fb70912af5df7622ee918c 100644 (file)
@@ -2399,10 +2399,14 @@ func TestConnMaxLifetime(t *testing.T) {
        tx.Commit()
        tx2.Commit()
 
-       driver.mu.Lock()
-       opens = driver.openCount - opens0
-       closes = driver.closeCount - closes0
-       driver.mu.Unlock()
+       // Give connectionCleaner chance to run.
+       for i := 0; i < 100 && closes != 1; i++ {
+               time.Sleep(time.Millisecond)
+               driver.mu.Lock()
+               opens = driver.openCount - opens0
+               closes = driver.closeCount - closes0
+               driver.mu.Unlock()
+       }
 
        if opens != 3 {
                t.Errorf("opens = %d; want 3", opens)
@@ -2410,6 +2414,10 @@ func TestConnMaxLifetime(t *testing.T) {
        if closes != 1 {
                t.Errorf("closes = %d; want 1", closes)
        }
+
+       if s := db.Stats(); s.MaxLifetimeClosed != 1 {
+               t.Errorf("MaxLifetimeClosed = %d; want 1 %#v", s.MaxLifetimeClosed, s)
+       }
 }
 
 // golang.org/issue/5323
@@ -3151,7 +3159,7 @@ func TestTxEndBadConn(t *testing.T) {
                        return broken
                }
 
-               if err := op(); err != driver.ErrBadConn {
+               if err := op(); !errors.Is(err, driver.ErrBadConn) {
                        t.Errorf(name+": %v", err)
                        return
                }
@@ -3896,14 +3904,48 @@ func TestStatsMaxIdleClosedTen(t *testing.T) {
        }
 }
 
+// testUseConns uses count concurrent connections with 1 nanosecond apart.
+// Returns the returnedAt time of the final connection.
+func testUseConns(t *testing.T, count int, tm time.Time, db *DB) time.Time {
+       conns := make([]*Conn, count)
+       ctx := context.Background()
+       for i := range conns {
+               c, err := db.Conn(ctx)
+               if err != nil {
+                       t.Error(err)
+               }
+               conns[i] = c
+       }
+
+       for _, c := range conns {
+               tm = tm.Add(time.Nanosecond)
+               nowFunc = func() time.Time {
+                       return tm
+               }
+               if err := c.Close(); err != nil {
+                       t.Error(err)
+               }
+       }
+
+       return tm
+}
+
 func TestMaxIdleTime(t *testing.T) {
+       usedConns := 5
+       reusedConns := 2
        list := []struct {
                wantMaxIdleTime time.Duration
+               wantNextCheck   time.Duration
                wantIdleClosed  int64
                timeOffset      time.Duration
        }{
-               {time.Nanosecond, 1, 10 * time.Millisecond},
-               {time.Hour, 0, 10 * time.Millisecond},
+               {
+                       time.Millisecond,
+                       time.Millisecond - time.Nanosecond,
+                       int64(usedConns - reusedConns),
+                       10 * time.Millisecond,
+               },
+               {time.Hour, time.Second, 0, 10 * time.Millisecond},
        }
        baseTime := time.Unix(0, 0)
        defer func() {
@@ -3917,23 +3959,38 @@ func TestMaxIdleTime(t *testing.T) {
                        db := newTestDB(t, "people")
                        defer closeDB(t, db)
 
-                       db.SetMaxOpenConns(1)
-                       db.SetMaxIdleConns(1)
+                       db.SetMaxOpenConns(usedConns)
+                       db.SetMaxIdleConns(usedConns)
                        db.SetConnMaxIdleTime(item.wantMaxIdleTime)
                        db.SetConnMaxLifetime(0)
 
                        preMaxIdleClosed := db.Stats().MaxIdleTimeClosed
 
-                       if err := db.Ping(); err != nil {
-                               t.Fatal(err)
+                       // Busy usedConns.
+                       tm := testUseConns(t, usedConns, baseTime, db)
+
+                       tm = baseTime.Add(item.timeOffset)
+
+                       // Reuse connections which should never be considered idle
+                       // and exercises the sorting for issue 39471.
+                       testUseConns(t, reusedConns, tm, db)
+
+                       db.mu.Lock()
+                       nc, closing := db.connectionCleanerRunLocked(time.Second)
+                       if nc != item.wantNextCheck {
+                               t.Errorf("got %v; want %v next check duration", nc, item.wantNextCheck)
                        }
 
-                       nowFunc = func() time.Time {
-                               return baseTime.Add(item.timeOffset)
+                       // Validate freeConn order.
+                       var last time.Time
+                       for _, c := range db.freeConn {
+                               if last.After(c.returnedAt) {
+                                       t.Error("freeConn is not ordered by returnedAt")
+                                       break
+                               }
+                               last = c.returnedAt
                        }
 
-                       db.mu.Lock()
-                       closing := db.connectionCleanerRunLocked()
                        db.mu.Unlock()
                        for _, c := range closing {
                                c.Close()
@@ -3945,7 +4002,7 @@ func TestMaxIdleTime(t *testing.T) {
                        st := db.Stats()
                        maxIdleClosed := st.MaxIdleTimeClosed - preMaxIdleClosed
                        if g, w := maxIdleClosed, item.wantIdleClosed; g != w {
-                               t.Errorf(" got: %d; want %d max idle closed conns", g, w)
+                               t.Errorf("got: %d; want %d max idle closed conns", g, w)
                        }
                })
        }
diff --git a/src/debug/buildinfo/buildinfo.go b/src/debug/buildinfo/buildinfo.go
new file mode 100644 (file)
index 0000000..f84429a
--- /dev/null
@@ -0,0 +1,375 @@
+// Copyright 2021 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 buildinfo provides access to information embedded in a Go binary
+// about how it was built. This includes the Go toolchain version, and the
+// set of modules used (for binaries built in module mode).
+//
+// Build information is available for the currently running binary in
+// runtime/debug.ReadBuildInfo.
+package buildinfo
+
+import (
+       "bytes"
+       "debug/elf"
+       "debug/macho"
+       "debug/pe"
+       "encoding/binary"
+       "errors"
+       "fmt"
+       "internal/xcoff"
+       "io"
+       "io/fs"
+       "os"
+       "runtime/debug"
+)
+
+// Type alias for build info. We cannot move the types here, since
+// runtime/debug would need to import this package, which would make it
+// a much larger dependency.
+type BuildInfo = debug.BuildInfo
+
+var (
+       // errUnrecognizedFormat is returned when a given executable file doesn't
+       // appear to be in a known format, or it breaks the rules of that format,
+       // or when there are I/O errors reading the file.
+       errUnrecognizedFormat = errors.New("unrecognized file format")
+
+       // errNotGoExe is returned when a given executable file is valid but does
+       // not contain Go build information.
+       errNotGoExe = errors.New("not a Go executable")
+
+       // The build info blob left by the linker is identified by
+       // a 16-byte header, consisting of buildInfoMagic (14 bytes),
+       // the binary's pointer size (1 byte),
+       // and whether the binary is big endian (1 byte).
+       buildInfoMagic = []byte("\xff Go buildinf:")
+)
+
+// ReadFile returns build information embedded in a Go binary
+// file at the given path. Most information is only available for binaries built
+// with module support.
+func ReadFile(name string) (info *BuildInfo, err error) {
+       defer func() {
+               if pathErr := (*fs.PathError)(nil); errors.As(err, &pathErr) {
+                       err = fmt.Errorf("could not read Go build info: %w", err)
+               } else if err != nil {
+                       err = fmt.Errorf("could not read Go build info from %s: %w", name, err)
+               }
+       }()
+
+       f, err := os.Open(name)
+       if err != nil {
+               return nil, err
+       }
+       defer f.Close()
+       return Read(f)
+}
+
+// Read returns build information embedded in a Go binary file
+// accessed through the given ReaderAt. Most information is only available for
+// binaries built with module support.
+func Read(r io.ReaderAt) (*BuildInfo, error) {
+       vers, mod, err := readRawBuildInfo(r)
+       if err != nil {
+               return nil, err
+       }
+       bi := &BuildInfo{}
+       if err := bi.UnmarshalText([]byte(mod)); err != nil {
+               return nil, err
+       }
+       bi.GoVersion = vers
+       return bi, nil
+}
+
+type exe interface {
+       // ReadData reads and returns up to size bytes starting at virtual address addr.
+       ReadData(addr, size uint64) ([]byte, error)
+
+       // DataStart returns the virtual address of the segment or section that
+       // should contain build information. This is either a specially named section
+       // or the first writable non-zero data segment.
+       DataStart() uint64
+}
+
+// readRawBuildInfo extracts the Go toolchain version and module information
+// strings from a Go binary. On success, vers should be non-empty. mod
+// is empty if the binary was not built with modules enabled.
+func readRawBuildInfo(r io.ReaderAt) (vers, mod string, err error) {
+       // Read the first bytes of the file to identify the format, then delegate to
+       // a format-specific function to load segment and section headers.
+       ident := make([]byte, 16)
+       if n, err := r.ReadAt(ident, 0); n < len(ident) || err != nil {
+               return "", "", errUnrecognizedFormat
+       }
+
+       var x exe
+       switch {
+       case bytes.HasPrefix(ident, []byte("\x7FELF")):
+               f, err := elf.NewFile(r)
+               if err != nil {
+                       return "", "", errUnrecognizedFormat
+               }
+               x = &elfExe{f}
+       case bytes.HasPrefix(ident, []byte("MZ")):
+               f, err := pe.NewFile(r)
+               if err != nil {
+                       return "", "", errUnrecognizedFormat
+               }
+               x = &peExe{f}
+       case bytes.HasPrefix(ident, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(ident[1:], []byte("\xFA\xED\xFE")):
+               f, err := macho.NewFile(r)
+               if err != nil {
+                       return "", "", errUnrecognizedFormat
+               }
+               x = &machoExe{f}
+       case bytes.HasPrefix(ident, []byte{0x01, 0xDF}) || bytes.HasPrefix(ident, []byte{0x01, 0xF7}):
+               f, err := xcoff.NewFile(r)
+               if err != nil {
+                       return "", "", errUnrecognizedFormat
+               }
+               x = &xcoffExe{f}
+       default:
+               return "", "", errUnrecognizedFormat
+       }
+
+       // Read the first 64kB of dataAddr to find the build info blob.
+       // On some platforms, the blob will be in its own section, and DataStart
+       // returns the address of that section. On others, it's somewhere in the
+       // data segment; the linker puts it near the beginning.
+       // See cmd/link/internal/ld.Link.buildinfo.
+       dataAddr := x.DataStart()
+       data, err := x.ReadData(dataAddr, 64*1024)
+       if err != nil {
+               return "", "", err
+       }
+       const (
+               buildInfoAlign = 16
+               buildinfoSize  = 32
+       )
+       for ; !bytes.HasPrefix(data, buildInfoMagic); data = data[buildInfoAlign:] {
+               if len(data) < 32 {
+                       return "", "", errNotGoExe
+               }
+       }
+
+       // Decode the blob.
+       // The first 14 bytes are buildInfoMagic.
+       // The next two bytes indicate pointer size in bytes (4 or 8) and endianness
+       // (0 for little, 1 for big).
+       // Two virtual addresses to Go strings follow that: runtime.buildVersion,
+       // and runtime.modinfo.
+       // On 32-bit platforms, the last 8 bytes are unused.
+       ptrSize := int(data[14])
+       bigEndian := data[15] != 0
+       var bo binary.ByteOrder
+       if bigEndian {
+               bo = binary.BigEndian
+       } else {
+               bo = binary.LittleEndian
+       }
+       var readPtr func([]byte) uint64
+       if ptrSize == 4 {
+               readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) }
+       } else {
+               readPtr = bo.Uint64
+       }
+       vers = readString(x, ptrSize, readPtr, readPtr(data[16:]))
+       if vers == "" {
+               return "", "", errNotGoExe
+       }
+       mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:]))
+       if len(mod) >= 33 && mod[len(mod)-17] == '\n' {
+               // Strip module framing: sentinel strings delimiting the module info.
+               // These are cmd/go/internal/modload.infoStart and infoEnd.
+               mod = mod[16 : len(mod)-16]
+       } else {
+               mod = ""
+       }
+
+       return vers, mod, nil
+}
+
+// readString returns the string at address addr in the executable x.
+func readString(x exe, ptrSize int, readPtr func([]byte) uint64, addr uint64) string {
+       hdr, err := x.ReadData(addr, uint64(2*ptrSize))
+       if err != nil || len(hdr) < 2*ptrSize {
+               return ""
+       }
+       dataAddr := readPtr(hdr)
+       dataLen := readPtr(hdr[ptrSize:])
+       data, err := x.ReadData(dataAddr, dataLen)
+       if err != nil || uint64(len(data)) < dataLen {
+               return ""
+       }
+       return string(data)
+}
+
+// elfExe is the ELF implementation of the exe interface.
+type elfExe struct {
+       f *elf.File
+}
+
+func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
+       for _, prog := range x.f.Progs {
+               if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {
+                       n := prog.Vaddr + prog.Filesz - addr
+                       if n > size {
+                               n = size
+                       }
+                       data := make([]byte, n)
+                       _, err := prog.ReadAt(data, int64(addr-prog.Vaddr))
+                       if err != nil {
+                               return nil, err
+                       }
+                       return data, nil
+               }
+       }
+       return nil, errUnrecognizedFormat
+}
+
+func (x *elfExe) DataStart() uint64 {
+       for _, s := range x.f.Sections {
+               if s.Name == ".go.buildinfo" {
+                       return s.Addr
+               }
+       }
+       for _, p := range x.f.Progs {
+               if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W {
+                       return p.Vaddr
+               }
+       }
+       return 0
+}
+
+// peExe is the PE (Windows Portable Executable) implementation of the exe interface.
+type peExe struct {
+       f *pe.File
+}
+
+func (x *peExe) imageBase() uint64 {
+       switch oh := x.f.OptionalHeader.(type) {
+       case *pe.OptionalHeader32:
+               return uint64(oh.ImageBase)
+       case *pe.OptionalHeader64:
+               return oh.ImageBase
+       }
+       return 0
+}
+
+func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
+       addr -= x.imageBase()
+       for _, sect := range x.f.Sections {
+               if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
+                       n := uint64(sect.VirtualAddress+sect.Size) - addr
+                       if n > size {
+                               n = size
+                       }
+                       data := make([]byte, n)
+                       _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
+                       if err != nil {
+                               return nil, errUnrecognizedFormat
+                       }
+                       return data, nil
+               }
+       }
+       return nil, errUnrecognizedFormat
+}
+
+func (x *peExe) DataStart() uint64 {
+       // Assume data is first writable section.
+       const (
+               IMAGE_SCN_CNT_CODE               = 0x00000020
+               IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
+               IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
+               IMAGE_SCN_MEM_EXECUTE            = 0x20000000
+               IMAGE_SCN_MEM_READ               = 0x40000000
+               IMAGE_SCN_MEM_WRITE              = 0x80000000
+               IMAGE_SCN_MEM_DISCARDABLE        = 0x2000000
+               IMAGE_SCN_LNK_NRELOC_OVFL        = 0x1000000
+               IMAGE_SCN_ALIGN_32BYTES          = 0x600000
+       )
+       for _, sect := range x.f.Sections {
+               if sect.VirtualAddress != 0 && sect.Size != 0 &&
+                       sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE {
+                       return uint64(sect.VirtualAddress) + x.imageBase()
+               }
+       }
+       return 0
+}
+
+// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface.
+type machoExe struct {
+       f *macho.File
+}
+
+func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
+       for _, load := range x.f.Loads {
+               seg, ok := load.(*macho.Segment)
+               if !ok {
+                       continue
+               }
+               if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 {
+                       if seg.Name == "__PAGEZERO" {
+                               continue
+                       }
+                       n := seg.Addr + seg.Filesz - addr
+                       if n > size {
+                               n = size
+                       }
+                       data := make([]byte, n)
+                       _, err := seg.ReadAt(data, int64(addr-seg.Addr))
+                       if err != nil {
+                               return nil, err
+                       }
+                       return data, nil
+               }
+       }
+       return nil, errUnrecognizedFormat
+}
+
+func (x *machoExe) DataStart() uint64 {
+       // Look for section named "__go_buildinfo".
+       for _, sec := range x.f.Sections {
+               if sec.Name == "__go_buildinfo" {
+                       return sec.Addr
+               }
+       }
+       // Try the first non-empty writable segment.
+       const RW = 3
+       for _, load := range x.f.Loads {
+               seg, ok := load.(*macho.Segment)
+               if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW {
+                       return seg.Addr
+               }
+       }
+       return 0
+}
+
+// xcoffExe is the XCOFF (AIX eXtended COFF) implementation of the exe interface.
+type xcoffExe struct {
+       f *xcoff.File
+}
+
+func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) {
+       for _, sect := range x.f.Sections {
+               if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
+                       n := uint64(sect.VirtualAddress+sect.Size) - addr
+                       if n > size {
+                               n = size
+                       }
+                       data := make([]byte, n)
+                       _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
+                       if err != nil {
+                               return nil, err
+                       }
+                       return data, nil
+               }
+       }
+       return nil, fmt.Errorf("address not mapped")
+}
+
+func (x *xcoffExe) DataStart() uint64 {
+       return x.f.SectionByType(xcoff.STYP_DATA).VirtualAddress
+}
diff --git a/src/debug/buildinfo/buildinfo_test.go b/src/debug/buildinfo/buildinfo_test.go
new file mode 100644 (file)
index 0000000..44d78a6
--- /dev/null
@@ -0,0 +1,225 @@
+// Copyright 2021 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 buildinfo_test
+
+import (
+       "bytes"
+       "debug/buildinfo"
+       "flag"
+       "internal/testenv"
+       "os"
+       "os/exec"
+       "path"
+       "path/filepath"
+       "regexp"
+       "runtime"
+       "strings"
+       "testing"
+)
+
+var flagAll = flag.Bool("all", false, "test all supported GOOS/GOARCH platforms, instead of only the current platform")
+
+// TestReadFile confirms that ReadFile can read build information from binaries
+// on supported target platforms. It builds a trivial binary on the current
+// platforms (or all platforms if -all is set) in various configurations and
+// checks that build information can or cannot be read.
+func TestReadFile(t *testing.T) {
+       if testing.Short() {
+               t.Skip("test requires compiling and linking, which may be slow")
+       }
+       testenv.MustHaveGoBuild(t)
+
+       type platform struct{ goos, goarch string }
+       platforms := []platform{
+               {"aix", "ppc64"},
+               {"darwin", "amd64"},
+               {"darwin", "arm64"},
+               {"linux", "386"},
+               {"linux", "amd64"},
+               {"windows", "386"},
+               {"windows", "amd64"},
+       }
+       runtimePlatform := platform{runtime.GOOS, runtime.GOARCH}
+       haveRuntimePlatform := false
+       for _, p := range platforms {
+               if p == runtimePlatform {
+                       haveRuntimePlatform = true
+                       break
+               }
+       }
+       if !haveRuntimePlatform {
+               platforms = append(platforms, runtimePlatform)
+       }
+
+       buildWithModules := func(t *testing.T, goos, goarch string) string {
+               dir := t.TempDir()
+               gomodPath := filepath.Join(dir, "go.mod")
+               gomodData := []byte("module example.com/m\ngo 1.18\n")
+               if err := os.WriteFile(gomodPath, gomodData, 0666); err != nil {
+                       t.Fatal(err)
+               }
+               helloPath := filepath.Join(dir, "hello.go")
+               helloData := []byte("package main\nfunc main() {}\n")
+               if err := os.WriteFile(helloPath, helloData, 0666); err != nil {
+                       t.Fatal(err)
+               }
+               outPath := filepath.Join(dir, path.Base(t.Name()))
+               cmd := exec.Command("go", "build", "-o="+outPath)
+               cmd.Dir = dir
+               cmd.Env = append(os.Environ(), "GO111MODULE=on", "GOOS="+goos, "GOARCH="+goarch)
+               stderr := &bytes.Buffer{}
+               cmd.Stderr = stderr
+               if err := cmd.Run(); err != nil {
+                       t.Fatalf("failed building test file: %v\n%s", err, stderr.Bytes())
+               }
+               return outPath
+       }
+
+       buildWithGOPATH := func(t *testing.T, goos, goarch string) string {
+               gopathDir := t.TempDir()
+               pkgDir := filepath.Join(gopathDir, "src/example.com/m")
+               if err := os.MkdirAll(pkgDir, 0777); err != nil {
+                       t.Fatal(err)
+               }
+               helloPath := filepath.Join(pkgDir, "hello.go")
+               helloData := []byte("package main\nfunc main() {}\n")
+               if err := os.WriteFile(helloPath, helloData, 0666); err != nil {
+                       t.Fatal(err)
+               }
+               outPath := filepath.Join(gopathDir, path.Base(t.Name()))
+               cmd := exec.Command("go", "build", "-o="+outPath)
+               cmd.Dir = pkgDir
+               cmd.Env = append(os.Environ(), "GO111MODULE=off", "GOPATH="+gopathDir, "GOOS="+goos, "GOARCH="+goarch)
+               stderr := &bytes.Buffer{}
+               cmd.Stderr = stderr
+               if err := cmd.Run(); err != nil {
+                       t.Fatalf("failed building test file: %v\n%s", err, stderr.Bytes())
+               }
+               return outPath
+       }
+
+       damageBuildInfo := func(t *testing.T, name string) {
+               data, err := os.ReadFile(name)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               i := bytes.Index(data, []byte("\xff Go buildinf:"))
+               if i < 0 {
+                       t.Fatal("Go buildinf not found")
+               }
+               data[i+2] = 'N'
+               if err := os.WriteFile(name, data, 0666); err != nil {
+                       t.Fatal(err)
+               }
+       }
+
+       goVersionRe := regexp.MustCompile("(?m)^go\t.*\n")
+       buildRe := regexp.MustCompile("(?m)^build\t.*\n")
+       cleanOutputForComparison := func(got string) string {
+               // Remove or replace anything that might depend on the test's environment
+               // so we can check the output afterward with a string comparison.
+               // We'll remove all build lines except the compiler, just to make sure
+               // build lines are included.
+               got = goVersionRe.ReplaceAllString(got, "go\tGOVERSION\n")
+               got = buildRe.ReplaceAllStringFunc(got, func(match string) string {
+                       if strings.HasPrefix(match, "build\tcompiler\t") {
+                               return match
+                       }
+                       return ""
+               })
+               return got
+       }
+
+       cases := []struct {
+               name    string
+               build   func(t *testing.T, goos, goarch string) string
+               want    string
+               wantErr string
+       }{
+               {
+                       name: "doesnotexist",
+                       build: func(t *testing.T, goos, goarch string) string {
+                               return "doesnotexist.txt"
+                       },
+                       wantErr: "doesnotexist",
+               },
+               {
+                       name: "empty",
+                       build: func(t *testing.T, _, _ string) string {
+                               dir := t.TempDir()
+                               name := filepath.Join(dir, "empty")
+                               if err := os.WriteFile(name, nil, 0666); err != nil {
+                                       t.Fatal(err)
+                               }
+                               return name
+                       },
+                       wantErr: "unrecognized file format",
+               },
+               {
+                       name:  "valid_modules",
+                       build: buildWithModules,
+                       want: "go\tGOVERSION\n" +
+                               "path\texample.com/m\n" +
+                               "mod\texample.com/m\t(devel)\t\n" +
+                               "build\tcompiler\tgc\n",
+               },
+               {
+                       name: "invalid_modules",
+                       build: func(t *testing.T, goos, goarch string) string {
+                               name := buildWithModules(t, goos, goarch)
+                               damageBuildInfo(t, name)
+                               return name
+                       },
+                       wantErr: "not a Go executable",
+               },
+               {
+                       name:  "valid_gopath",
+                       build: buildWithGOPATH,
+                       want:  "go\tGOVERSION\n",
+               },
+               {
+                       name: "invalid_gopath",
+                       build: func(t *testing.T, goos, goarch string) string {
+                               name := buildWithGOPATH(t, goos, goarch)
+                               damageBuildInfo(t, name)
+                               return name
+                       },
+                       wantErr: "not a Go executable",
+               },
+       }
+
+       for _, p := range platforms {
+               p := p
+               t.Run(p.goos+"_"+p.goarch, func(t *testing.T) {
+                       if p != runtimePlatform && !*flagAll {
+                               t.Skipf("skipping platforms other than %s_%s because -all was not set", runtimePlatform.goos, runtimePlatform.goarch)
+                       }
+                       for _, tc := range cases {
+                               tc := tc
+                               t.Run(tc.name, func(t *testing.T) {
+                                       t.Parallel()
+                                       name := tc.build(t, p.goos, p.goarch)
+                                       if info, err := buildinfo.ReadFile(name); err != nil {
+                                               if tc.wantErr == "" {
+                                                       t.Fatalf("unexpected error: %v", err)
+                                               } else if errMsg := err.Error(); !strings.Contains(errMsg, tc.wantErr) {
+                                                       t.Fatalf("got error %q; want error containing %q", errMsg, tc.wantErr)
+                                               }
+                                       } else {
+                                               if tc.wantErr != "" {
+                                                       t.Fatalf("unexpected success; want error containing %q", tc.wantErr)
+                                               } else if got, err := info.MarshalText(); err != nil {
+                                                       t.Fatalf("unexpected error marshaling BuildInfo: %v", err)
+                                               } else if got := cleanOutputForComparison(string(got)); got != tc.want {
+                                                       if got != tc.want {
+                                                               t.Fatalf("got:\n%s\nwant:\n%s", got, tc.want)
+                                                       }
+                                               }
+                                       }
+                               })
+                       }
+               })
+       }
+}
index 4780a0b2bad80e94b7fec5e6d187faceb8b370cc..3e7e008621e832d81af45f1e77f8d1fcdc645d44 100644 (file)
@@ -8,6 +8,7 @@ gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
 
 OS X Mach-O:
 gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
+gcc -gdwarf-4 -m64 -c typedef.c -o typedef.macho4
 */
 #include <complex.h>
 
diff --git a/src/debug/dwarf/testdata/typedef.macho4 b/src/debug/dwarf/testdata/typedef.macho4
new file mode 100644 (file)
index 0000000..093ff37
Binary files /dev/null and b/src/debug/dwarf/testdata/typedef.macho4 differ
index eb5a666ed38d3bcaf1cc42a0b54c5e28ef63453a..2e5a605174c378f29ab89acad9a28240555f133a 100644 (file)
@@ -516,7 +516,10 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                }).Basic()
                t.Name = name
                t.BitSize, _ = e.Val(AttrBitSize).(int64)
-               t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
+               haveBitOffset := false
+               if t.BitOffset, haveBitOffset = e.Val(AttrBitOffset).(int64); !haveBitOffset {
+                       t.BitOffset, _ = e.Val(AttrDataBitOffset).(int64)
+               }
 
        case TagClassType, TagStructType, TagUnionType:
                // Structure, union, or class type.  (DWARF v2 §5.5)
@@ -578,7 +581,9 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
                        haveBitOffset := false
                        f.Name, _ = kid.Val(AttrName).(string)
                        f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
-                       f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64)
+                       if f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64); !haveBitOffset {
+                               f.BitOffset, haveBitOffset = kid.Val(AttrDataBitOffset).(int64)
+                       }
                        f.BitSize, _ = kid.Val(AttrBitSize).(int64)
                        t.Field = append(t.Field, f)
 
index fda03fdbb09cf22230a006747a2a80e000f11898..431d0853e0546d0361dc627d6920e25065a37bcd 100644 (file)
@@ -228,3 +228,54 @@ func TestUnsupportedTypes(t *testing.T) {
                }
        }
 }
+
+func TestBitOffsetsELF(t *testing.T) { testBitOffsets(t, elfData(t, "testdata/typedef.elf")) }
+
+func TestBitOffsetsMachO(t *testing.T) {
+       testBitOffsets(t, machoData(t, "testdata/typedef.macho"))
+}
+
+func TestBitOffsetsMachO4(t *testing.T) {
+       testBitOffsets(t, machoData(t, "testdata/typedef.macho4"))
+}
+
+func TestBitOffsetsELFDwarf4(t *testing.T) {
+       testBitOffsets(t, elfData(t, "testdata/typedef.elf4"))
+}
+
+func testBitOffsets(t *testing.T, d *Data) {
+       r := d.Reader()
+       for {
+               e, err := r.Next()
+               if err != nil {
+                       t.Fatal("r.Next:", err)
+               }
+               if e == nil {
+                       break
+               }
+
+               if e.Tag == TagStructType {
+                       typ, err := d.Type(e.Offset)
+                       if err != nil {
+                               t.Fatal("d.Type:", err)
+                       }
+
+                       t1 := typ.(*StructType)
+
+                       for _, field := range t1.Field {
+                               // We're only testing for bitfields
+                               if field.BitSize == 0 {
+                                       continue
+                               }
+
+                               // Ensure BitOffset is not zero
+                               if field.BitOffset == 0 {
+                                       t.Errorf("bit offset of field %s in %s %s is not set", field.Name, t1.Kind, t1.StructName)
+                               }
+                       }
+               }
+               if e.Tag != TagCompileUnit {
+                       r.SkipChildren()
+               }
+       }
+}
index b25d8209e36f95a90e91beecdcf1176cc5ec9742..e265796ddc3be019e551a68f009365c2538ecd61 100644 (file)
@@ -494,7 +494,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
 
        data, err := symtabSection.Data()
        if err != nil {
-               return nil, nil, errors.New("cannot load symbol section")
+               return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
        }
        symtab := bytes.NewReader(data)
        if symtab.Len()%Sym32Size != 0 {
@@ -503,7 +503,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
 
        strdata, err := f.stringTable(symtabSection.Link)
        if err != nil {
-               return nil, nil, errors.New("cannot load string table section")
+               return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
        }
 
        // The first entry is all zeros.
@@ -537,7 +537,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
 
        data, err := symtabSection.Data()
        if err != nil {
-               return nil, nil, errors.New("cannot load symbol section")
+               return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
        }
        symtab := bytes.NewReader(data)
        if symtab.Len()%Sym64Size != 0 {
@@ -546,7 +546,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
 
        strdata, err := f.stringTable(symtabSection.Link)
        if err != nil {
-               return nil, nil, errors.New("cannot load string table section")
+               return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
        }
 
        // The first entry is all zeros.
index a72f9847d7cc08f371e041d89959acd9171492f3..a687c406b2af83fd6735887dcb3e5c9fc045a649 100644 (file)
@@ -11,6 +11,7 @@ package gosym
 import (
        "bytes"
        "encoding/binary"
+       "sort"
        "sync"
 )
 
@@ -22,6 +23,7 @@ const (
        ver11
        ver12
        ver116
+       ver118
 )
 
 // A LineTable is a data structure mapping program counters to line numbers.
@@ -48,10 +50,11 @@ type LineTable struct {
        // Contains the version of the pclntab section.
        version version
 
-       // Go 1.2/1.16 state
+       // Go 1.2/1.16/1.18 state
        binary      binary.ByteOrder
        quantum     uint32
        ptrsize     uint32
+       textStart   uintptr // address of runtime.text symbol (1.18+)
        funcnametab []byte
        cutab       []byte
        funcdata    []byte
@@ -166,8 +169,11 @@ func (t *LineTable) isGo12() bool {
        return t.version >= ver12
 }
 
-const go12magic = 0xfffffffb
-const go116magic = 0xfffffffa
+const (
+       go12magic  = 0xfffffffb
+       go116magic = 0xfffffffa
+       go118magic = 0xfffffff0
+)
 
 // uintptr returns the pointer-sized value encoded at b.
 // The pointer size is dictated by the table being read.
@@ -193,10 +199,12 @@ func (t *LineTable) parsePclnTab() {
        // Error paths through this code will default the version to 1.1.
        t.version = ver11
 
-       defer func() {
-               // If we panic parsing, assume it's a Go 1.1 pclntab.
-               recover()
-       }()
+       if !disableRecover {
+               defer func() {
+                       // If we panic parsing, assume it's a Go 1.1 pclntab.
+                       recover()
+               }()
+       }
 
        // Check header: 4-byte magic, two zeros, pc quantum, pointer size.
        if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
@@ -217,30 +225,49 @@ func (t *LineTable) parsePclnTab() {
                t.binary, possibleVersion = binary.LittleEndian, ver116
        case beMagic == go116magic:
                t.binary, possibleVersion = binary.BigEndian, ver116
+       case leMagic == go118magic:
+               t.binary, possibleVersion = binary.LittleEndian, ver118
+       case beMagic == go118magic:
+               t.binary, possibleVersion = binary.BigEndian, ver118
        default:
                return
        }
+       t.version = possibleVersion
 
-       // quantum and ptrSize are the same between 1.2 and 1.16
+       // quantum and ptrSize are the same between 1.2, 1.16, and 1.18
        t.quantum = uint32(t.Data[6])
        t.ptrsize = uint32(t.Data[7])
 
+       offset := func(word uint32) uint64 {
+               return t.uintptr(t.Data[8+word*t.ptrsize:])
+       }
+       data := func(word uint32) []byte {
+               return t.Data[offset(word):]
+       }
+
        switch possibleVersion {
+       case ver118:
+               t.nfunctab = uint32(offset(0))
+               t.nfiletab = uint32(offset(1))
+               t.textStart = uintptr(offset(2))
+               t.funcnametab = data(3)
+               t.cutab = data(4)
+               t.filetab = data(5)
+               t.pctab = data(6)
+               t.funcdata = data(7)
+               t.functab = data(7)
+               functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize()
+               t.functab = t.functab[:functabsize]
        case ver116:
-               t.nfunctab = uint32(t.uintptr(t.Data[8:]))
-               t.nfiletab = uint32(t.uintptr(t.Data[8+t.ptrsize:]))
-               offset := t.uintptr(t.Data[8+2*t.ptrsize:])
-               t.funcnametab = t.Data[offset:]
-               offset = t.uintptr(t.Data[8+3*t.ptrsize:])
-               t.cutab = t.Data[offset:]
-               offset = t.uintptr(t.Data[8+4*t.ptrsize:])
-               t.filetab = t.Data[offset:]
-               offset = t.uintptr(t.Data[8+5*t.ptrsize:])
-               t.pctab = t.Data[offset:]
-               offset = t.uintptr(t.Data[8+6*t.ptrsize:])
-               t.funcdata = t.Data[offset:]
-               t.functab = t.Data[offset:]
-               functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
+               t.nfunctab = uint32(offset(0))
+               t.nfiletab = uint32(offset(1))
+               t.funcnametab = data(2)
+               t.cutab = data(3)
+               t.filetab = data(4)
+               t.pctab = data(5)
+               t.funcdata = data(6)
+               t.functab = data(6)
+               functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize()
                t.functab = t.functab[:functabsize]
        case ver12:
                t.nfunctab = uint32(t.uintptr(t.Data[8:]))
@@ -248,7 +275,7 @@ func (t *LineTable) parsePclnTab() {
                t.funcnametab = t.Data
                t.functab = t.Data[8+t.ptrsize:]
                t.pctab = t.Data
-               functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
+               functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize()
                fileoff := t.binary.Uint32(t.functab[functabsize:])
                t.functab = t.functab[:functabsize]
                t.filetab = t.Data[fileoff:]
@@ -257,59 +284,50 @@ func (t *LineTable) parsePclnTab() {
        default:
                panic("unreachable")
        }
-       t.version = possibleVersion
 }
 
-// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
+// go12Funcs returns a slice of Funcs derived from the Go 1.2+ pcln table.
 func (t *LineTable) go12Funcs() []Func {
        // Assume it is malformed and return nil on error.
-       defer func() {
-               recover()
-       }()
+       if !disableRecover {
+               defer func() {
+                       recover()
+               }()
+       }
 
-       n := len(t.functab) / int(t.ptrsize) / 2
-       funcs := make([]Func, n)
+       ft := t.funcTab()
+       funcs := make([]Func, ft.Count())
+       syms := make([]Sym, len(funcs))
        for i := range funcs {
                f := &funcs[i]
-               f.Entry = t.uintptr(t.functab[2*i*int(t.ptrsize):])
-               f.End = t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])
-               info := t.funcdata[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
+               f.Entry = ft.pc(i)
+               f.End = ft.pc(i + 1)
+               info := t.funcData(uint32(i))
                f.LineTable = t
-               f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
-               f.Sym = &Sym{
+               f.FrameSize = int(info.deferreturn())
+               syms[i] = Sym{
                        Value:  f.Entry,
                        Type:   'T',
-                       Name:   t.funcName(t.binary.Uint32(info[t.ptrsize:])),
+                       Name:   t.funcName(info.nameoff()),
                        GoType: 0,
                        Func:   f,
                }
+               f.Sym = &syms[i]
        }
        return funcs
 }
 
-// findFunc returns the func corresponding to the given program counter.
-func (t *LineTable) findFunc(pc uint64) []byte {
-       if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
-               return nil
-       }
-
-       // The function table is a list of 2*nfunctab+1 uintptrs,
-       // alternating program counters and offsets to func structures.
-       f := t.functab
-       nf := t.nfunctab
-       for nf > 0 {
-               m := nf / 2
-               fm := f[2*t.ptrsize*m:]
-               if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) {
-                       return t.funcdata[t.uintptr(fm[t.ptrsize:]):]
-               } else if pc < t.uintptr(fm) {
-                       nf = m
-               } else {
-                       f = f[(m+1)*2*t.ptrsize:]
-                       nf -= m + 1
-               }
+// findFunc returns the funcData corresponding to the given program counter.
+func (t *LineTable) findFunc(pc uint64) funcData {
+       ft := t.funcTab()
+       if pc < ft.pc(0) || pc >= ft.pc(ft.Count()) {
+               return funcData{}
        }
-       return nil
+       idx := sort.Search(int(t.nfunctab), func(i int) bool {
+               return ft.pc(i) > pc
+       })
+       idx--
+       return t.funcData(uint32(idx))
 }
 
 // readvarint reads, removes, and returns a varint from *pp.
@@ -355,6 +373,106 @@ func (t *LineTable) string(off uint32) string {
        return t.stringFrom(t.funcdata, off)
 }
 
+// functabFieldSize returns the size in bytes of a single functab field.
+func (t *LineTable) functabFieldSize() int {
+       if t.version >= ver118 {
+               return 4
+       }
+       return int(t.ptrsize)
+}
+
+// funcTab returns t's funcTab.
+func (t *LineTable) funcTab() funcTab {
+       return funcTab{LineTable: t, sz: t.functabFieldSize()}
+}
+
+// funcTab is memory corresponding to a slice of functab structs, followed by an invalid PC.
+// A functab struct is a PC and a func offset.
+type funcTab struct {
+       *LineTable
+       sz int // cached result of t.functabFieldSize
+}
+
+// Count returns the number of func entries in f.
+func (f funcTab) Count() int {
+       return int(f.nfunctab)
+}
+
+// pc returns the PC of the i'th func in f.
+func (f funcTab) pc(i int) uint64 {
+       u := f.uint(f.functab[2*i*f.sz:])
+       if f.version >= ver118 {
+               u += uint64(f.textStart)
+       }
+       return u
+}
+
+// funcOff returns the funcdata offset of the i'th func in f.
+func (f funcTab) funcOff(i int) uint64 {
+       return f.uint(f.functab[(2*i+1)*f.sz:])
+}
+
+// uint returns the uint stored at b.
+func (f funcTab) uint(b []byte) uint64 {
+       if f.sz == 4 {
+               return uint64(f.binary.Uint32(b))
+       }
+       return f.binary.Uint64(b)
+}
+
+// funcData is memory corresponding to an _func struct.
+type funcData struct {
+       t    *LineTable // LineTable this data is a part of
+       data []byte     // raw memory for the function
+}
+
+// funcData returns the ith funcData in t.functab.
+func (t *LineTable) funcData(i uint32) funcData {
+       data := t.funcdata[t.funcTab().funcOff(int(i)):]
+       return funcData{t: t, data: data}
+}
+
+// IsZero reports whether f is the zero value.
+func (f funcData) IsZero() bool {
+       return f.t == nil && f.data == nil
+}
+
+// entryPC returns the func's entry PC.
+func (f *funcData) entryPC() uint64 {
+       // In Go 1.18, the first field of _func changed
+       // from a uintptr entry PC to a uint32 entry offset.
+       if f.t.version >= ver118 {
+               // TODO: support multiple text sections.
+               // See runtime/symtab.go:(*moduledata).textAddr.
+               return uint64(f.t.binary.Uint32(f.data)) + uint64(f.t.textStart)
+       }
+       return f.t.uintptr(f.data)
+}
+
+func (f funcData) nameoff() uint32     { return f.field(1) }
+func (f funcData) deferreturn() uint32 { return f.field(3) }
+func (f funcData) pcfile() uint32      { return f.field(5) }
+func (f funcData) pcln() uint32        { return f.field(6) }
+func (f funcData) cuOffset() uint32    { return f.field(8) }
+
+// field returns the nth field of the _func struct.
+// It panics if n == 0 or n > 9; for n == 0, call f.entryPC.
+// Most callers should use a named field accessor (just above).
+func (f funcData) field(n uint32) uint32 {
+       if n == 0 || n > 9 {
+               panic("bad funcdata field")
+       }
+       // In Go 1.18, the first field of _func changed
+       // from a uintptr entry PC to a uint32 entry offset.
+       sz0 := f.t.ptrsize
+       if f.t.version >= ver118 {
+               sz0 = 4
+       }
+       off := sz0 + (n-1)*4 // subsequent fields are 4 bytes each
+       data := f.data[off:]
+       return f.t.binary.Uint32(data)
+}
+
 // step advances to the next pc, value pair in the encoded table.
 func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
        uvdelta := t.readvarint(p)
@@ -409,7 +527,7 @@ func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum,
        fileStartPC := filePC
        for t.step(&fp, &filePC, &fileVal, filePC == entry) {
                fileIndex := fileVal
-               if t.version == ver116 {
+               if t.version == ver116 || t.version == ver118 {
                        fileIndex = int32(t.binary.Uint32(cutab[fileVal*4:]))
                }
                if fileIndex == filenum && fileStartPC < filePC {
@@ -436,37 +554,37 @@ func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum,
        return 0
 }
 
-// go12PCToLine maps program counter to line number for the Go 1.2 pcln table.
+// go12PCToLine maps program counter to line number for the Go 1.2+ pcln table.
 func (t *LineTable) go12PCToLine(pc uint64) (line int) {
        defer func() {
-               if recover() != nil {
+               if !disableRecover && recover() != nil {
                        line = -1
                }
        }()
 
        f := t.findFunc(pc)
-       if f == nil {
+       if f.IsZero() {
                return -1
        }
-       entry := t.uintptr(f)
-       linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
+       entry := f.entryPC()
+       linetab := f.pcln()
        return int(t.pcvalue(linetab, entry, pc))
 }
 
-// go12PCToFile maps program counter to file name for the Go 1.2 pcln table.
+// go12PCToFile maps program counter to file name for the Go 1.2+ pcln table.
 func (t *LineTable) go12PCToFile(pc uint64) (file string) {
        defer func() {
-               if recover() != nil {
+               if !disableRecover && recover() != nil {
                        file = ""
                }
        }()
 
        f := t.findFunc(pc)
-       if f == nil {
+       if f.IsZero() {
                return ""
        }
-       entry := t.uintptr(f)
-       filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
+       entry := f.entryPC()
+       filetab := f.pcfile()
        fno := t.pcvalue(filetab, entry, pc)
        if t.version == ver12 {
                if fno <= 0 {
@@ -478,17 +596,17 @@ func (t *LineTable) go12PCToFile(pc uint64) (file string) {
        if fno < 0 { // 0 is valid for ≥ 1.16
                return ""
        }
-       cuoff := t.binary.Uint32(f[t.ptrsize+7*4:])
+       cuoff := f.cuOffset()
        if fnoff := t.binary.Uint32(t.cutab[(cuoff+uint32(fno))*4:]); fnoff != ^uint32(0) {
                return t.stringFrom(t.filetab, fnoff)
        }
        return ""
 }
 
-// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2/1.16 pcln table.
+// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2+ pcln table.
 func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
        defer func() {
-               if recover() != nil {
+               if !disableRecover && recover() != nil {
                        pc = 0
                }
        }()
@@ -504,13 +622,12 @@ func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
        // mapping file number to a list of functions with code from that file.
        var cutab []byte
        for i := uint32(0); i < t.nfunctab; i++ {
-               f := t.funcdata[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
-               entry := t.uintptr(f)
-               filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
-               linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
-               if t.version == ver116 {
-                       cuoff := t.binary.Uint32(f[t.ptrsize+7*4:]) * 4
-                       cutab = t.cutab[cuoff:]
+               f := t.funcData(i)
+               entry := f.entryPC()
+               filetab := f.pcfile()
+               linetab := f.pcln()
+               if t.version == ver116 || t.version == ver118 {
+                       cutab = t.cutab[f.cuOffset()*4:]
                }
                pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line), cutab)
                if pc != 0 {
@@ -550,12 +667,18 @@ func (t *LineTable) initFileMap() {
 // Every key maps to obj. That's not a very interesting map, but it provides
 // a way for callers to obtain the list of files in the program.
 func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) {
-       defer func() {
-               recover()
-       }()
+       if !disableRecover {
+               defer func() {
+                       recover()
+               }()
+       }
 
        t.initFileMap()
        for file := range t.fileMap {
                m[file] = obj
        }
 }
+
+// disableRecover causes this package not to swallow panics.
+// This is useful when making changes.
+const disableRecover = false
index 7347139b5df2bdc1da77f9b57011afe4259e7d47..d690a1e3f2de21a61ede6087ceff17d7dbdbb56d 100644 (file)
@@ -29,6 +29,10 @@ func dotest(t *testing.T) {
        if runtime.GOARCH != "amd64" {
                t.Skipf("skipping on non-AMD64 system %s", runtime.GOARCH)
        }
+       // This test builds a Linux/AMD64 binary. Skipping in short mode if cross compiling.
+       if runtime.GOOS != "linux" && testing.Short() {
+               t.Skipf("skipping in short mode on non-Linux system %s", runtime.GOARCH)
+       }
        var err error
        pclineTempDir, err = os.MkdirTemp("", "pclinetest")
        if err != nil {
@@ -198,9 +202,6 @@ func TestLineAline(t *testing.T) {
 }
 
 func TestPCLine(t *testing.T) {
-       if testing.Short() {
-               t.Skip("skipping in -short mode")
-       }
        dotest(t)
        defer endtest()
 
@@ -267,7 +268,8 @@ func TestPCLine(t *testing.T) {
        }
 }
 
-// Test that we can parse a pclntab from 1.15.
+// read115Executable returns a hello world executable compiled by Go 1.15.
+//
 // The file was compiled in /tmp/hello.go:
 // [BEGIN]
 // package main
@@ -276,25 +278,30 @@ func TestPCLine(t *testing.T) {
 //    println("hello")
 // }
 // [END]
-func Test115PclnParsing(t *testing.T) {
+func read115Executable(tb testing.TB) []byte {
        zippedDat, err := os.ReadFile("testdata/pcln115.gz")
        if err != nil {
-               t.Fatal(err)
+               tb.Fatal(err)
        }
        var gzReader *gzip.Reader
        gzReader, err = gzip.NewReader(bytes.NewBuffer(zippedDat))
        if err != nil {
-               t.Fatal(err)
+               tb.Fatal(err)
        }
        var dat []byte
        dat, err = io.ReadAll(gzReader)
        if err != nil {
-               t.Fatal(err)
+               tb.Fatal(err)
        }
+       return dat
+}
+
+// Test that we can parse a pclntab from 1.15.
+func Test115PclnParsing(t *testing.T) {
+       dat := read115Executable(t)
        const textStart = 0x1001000
        pcln := NewLineTable(dat, textStart)
-       var tab *Table
-       tab, err = NewTable(nil, pcln)
+       tab, err := NewTable(nil, pcln)
        if err != nil {
                t.Fatal(err)
        }
@@ -314,3 +321,74 @@ func Test115PclnParsing(t *testing.T) {
                t.Fatalf("expected to parse name as main.main, got %v", f.Name)
        }
 }
+
+var (
+       sinkLineTable *LineTable
+       sinkTable     *Table
+)
+
+func Benchmark115(b *testing.B) {
+       dat := read115Executable(b)
+       const textStart = 0x1001000
+
+       b.Run("NewLineTable", func(b *testing.B) {
+               b.ReportAllocs()
+               for i := 0; i < b.N; i++ {
+                       sinkLineTable = NewLineTable(dat, textStart)
+               }
+       })
+
+       pcln := NewLineTable(dat, textStart)
+       b.Run("NewTable", func(b *testing.B) {
+               b.ReportAllocs()
+               for i := 0; i < b.N; i++ {
+                       var err error
+                       sinkTable, err = NewTable(nil, pcln)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+               }
+       })
+
+       tab, err := NewTable(nil, pcln)
+       if err != nil {
+               b.Fatal(err)
+       }
+
+       b.Run("LineToPC", func(b *testing.B) {
+               b.ReportAllocs()
+               for i := 0; i < b.N; i++ {
+                       var f *Func
+                       var pc uint64
+                       pc, f, err = tab.LineToPC("/tmp/hello.go", 3)
+                       if err != nil {
+                               b.Fatal(err)
+                       }
+                       if pcln.version != ver12 {
+                               b.Fatalf("want version=%d, got %d", ver12, pcln.version)
+                       }
+                       if pc != 0x105c280 {
+                               b.Fatalf("want pc=0x105c280, got 0x%x", pc)
+                       }
+                       if f.Name != "main.main" {
+                               b.Fatalf("want name=main.main, got %q", f.Name)
+                       }
+               }
+       })
+
+       b.Run("PCToLine", func(b *testing.B) {
+               b.ReportAllocs()
+               for i := 0; i < b.N; i++ {
+                       file, line, fn := tab.PCToLine(0x105c280)
+                       if file != "/tmp/hello.go" {
+                               b.Fatalf("want name=/tmp/hello.go, got %q", file)
+                       }
+                       if line != 3 {
+                               b.Fatalf("want line=3, got %d", line)
+                       }
+                       if fn.Name != "main.main" {
+                               b.Fatalf("want name=main.main, got %q", fn.Name)
+                       }
+               }
+       })
+}
index 00701c2875aaace9dac055a40c93ef073556891c..72490dca8affefeacad906dbda21cd58eecdede3 100644 (file)
@@ -32,10 +32,28 @@ type Sym struct {
 // Static reports whether this symbol is static (not visible outside its file).
 func (s *Sym) Static() bool { return s.Type >= 'a' }
 
+// nameWithoutInst returns s.Name if s.Name has no brackets (does not reference an
+// instantiated type, function, or method). If s.Name contains brackets, then it
+// returns s.Name with all the contents between (and including) the outermost left
+// and right bracket removed. This is useful to ignore any extra slashes or dots
+// inside the brackets from the string searches below, where needed.
+func (s *Sym) nameWithoutInst() string {
+       start := strings.Index(s.Name, "[")
+       if start < 0 {
+               return s.Name
+       }
+       end := strings.LastIndex(s.Name, "]")
+       if end < 0 {
+               // Malformed name, should contain closing bracket too.
+               return s.Name
+       }
+       return s.Name[0:start] + s.Name[end+1:]
+}
+
 // PackageName returns the package part of the symbol name,
 // or the empty string if there is none.
 func (s *Sym) PackageName() string {
-       name := s.Name
+       name := s.nameWithoutInst()
 
        // A prefix of "type." and "go." is a compiler-generated symbol that doesn't belong to any package.
        // See variable reservedimports in cmd/compile/internal/gc/subr.go
@@ -55,23 +73,46 @@ func (s *Sym) PackageName() string {
 }
 
 // ReceiverName returns the receiver type name of this symbol,
-// or the empty string if there is none.
+// or the empty string if there is none.  A receiver name is only detected in
+// the case that s.Name is fully-specified with a package name.
 func (s *Sym) ReceiverName() string {
-       pathend := strings.LastIndex(s.Name, "/")
+       name := s.nameWithoutInst()
+       // If we find a slash in name, it should precede any bracketed expression
+       // that was removed, so pathend will apply correctly to name and s.Name.
+       pathend := strings.LastIndex(name, "/")
        if pathend < 0 {
                pathend = 0
        }
-       l := strings.Index(s.Name[pathend:], ".")
-       r := strings.LastIndex(s.Name[pathend:], ".")
+       // Find the first dot after pathend (or from the beginning, if there was
+       // no slash in name).
+       l := strings.Index(name[pathend:], ".")
+       // Find the last dot after pathend (or the beginnng).
+       r := strings.LastIndex(name[pathend:], ".")
        if l == -1 || r == -1 || l == r {
+               // There is no receiver if we didn't find two distinct dots after pathend.
                return ""
        }
+       // Given there is a trailing '.' that is in name, find it now in s.Name.
+       // pathend+l should apply to s.Name, because it should be the dot in the
+       // package name.
+       r = strings.LastIndex(s.Name[pathend:], ".")
        return s.Name[pathend+l+1 : pathend+r]
 }
 
 // BaseName returns the symbol name without the package or receiver name.
 func (s *Sym) BaseName() string {
-       if i := strings.LastIndex(s.Name, "."); i != -1 {
+       name := s.nameWithoutInst()
+       if i := strings.LastIndex(name, "."); i != -1 {
+               if s.Name != name {
+                       brack := strings.Index(s.Name, "[")
+                       if i > brack {
+                               // BaseName is a method name after the brackets, so
+                               // recalculate for s.Name. Otherwise, i applies
+                               // correctly to s.Name, since it is before the
+                               // brackets.
+                               i = strings.LastIndex(s.Name, ".")
+                       }
+               }
                return s.Name[i+1:]
        }
        return s.Name
index b6ed8f554c517d8773b6fd439365556e10844de1..da3c21209d68f11b2ca1fe0a4b2d3a697062fdd4 100644 (file)
@@ -33,6 +33,25 @@ func TestStandardLibPathPackage(t *testing.T) {
        assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
 }
 
+func TestGenericNames(t *testing.T) {
+       s1 := Sym{Name: "main.set[int]"}
+       s2 := Sym{Name: "main.(*value[int]).get"}
+       s3 := Sym{Name: "a/b.absDifference[c/d.orderedAbs[float64]]"}
+       s4 := Sym{Name: "main.testfunction[.shape.int]"}
+       assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "main")
+       assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "main")
+       assertString(t, fmt.Sprintf("package of %q", s3.Name), s3.PackageName(), "a/b")
+       assertString(t, fmt.Sprintf("package of %q", s4.Name), s4.PackageName(), "main")
+       assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "")
+       assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "(*value[int])")
+       assertString(t, fmt.Sprintf("receiver of %q", s3.Name), s3.ReceiverName(), "")
+       assertString(t, fmt.Sprintf("receiver of %q", s4.Name), s4.ReceiverName(), "")
+       assertString(t, fmt.Sprintf("base of %q", s1.Name), s1.BaseName(), "set[int]")
+       assertString(t, fmt.Sprintf("base of %q", s2.Name), s2.BaseName(), "get")
+       assertString(t, fmt.Sprintf("base of %q", s3.Name), s3.BaseName(), "absDifference[c/d.orderedAbs[float64]]")
+       assertString(t, fmt.Sprintf("base of %q", s4.Name), s4.BaseName(), "testfunction[.shape.int]")
+}
+
 func TestRemotePackage(t *testing.T) {
        s1 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.(*FlagSet).PrintDefaults"}
        s2 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.PrintDefaults"}
index 085b0c8219bad436e5438e3aae5190dc2510583b..73cfce3c7606e419c3ed3de7f7f9f3811d7eb7a2 100644 (file)
@@ -345,6 +345,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
                        if err := binary.Read(b, bo, &hdr); err != nil {
                                return nil, err
                        }
+                       if hdr.Iundefsym > uint32(len(f.Symtab.Syms)) {
+                               return nil, &FormatError{offset, fmt.Sprintf(
+                                       "undefined symbols index in dynamic symbol table command is greater than symbol table length (%d > %d)",
+                                       hdr.Iundefsym, len(f.Symtab.Syms)), nil}
+                       } else if hdr.Iundefsym+hdr.Nundefsym > uint32(len(f.Symtab.Syms)) {
+                               return nil, &FormatError{offset, fmt.Sprintf(
+                                       "number of undefined symbols after index in dynamic symbol table command is greater than symbol table length (%d > %d)",
+                                       hdr.Iundefsym+hdr.Nundefsym, len(f.Symtab.Syms)), nil}
+                       }
                        dat := make([]byte, hdr.Nindirectsyms*4)
                        if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
                                return nil, err
index 03915c86e23d9955b00d320be02f0a610140e508..9beeb80dd27c1f09e8af31e0ccb77d3a6e51defe 100644 (file)
@@ -416,3 +416,10 @@ func TestTypeString(t *testing.T) {
                t.Errorf("got %v, want %v", TypeExec.GoString(), "macho.Exec")
        }
 }
+
+func TestOpenBadDysymCmd(t *testing.T) {
+       _, err := openObscured("testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64")
+       if err == nil {
+               t.Fatal("openObscured did not fail when opening a file with an invalid dynamic symbol table command")
+       }
+}
diff --git a/src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64 b/src/debug/macho/testdata/gcc-amd64-darwin-exec-with-bad-dysym.base64
new file mode 100644 (file)
index 0000000..8e04366
--- /dev/null
@@ -0,0 +1 @@
+z/rt/gcAAAEDAACAAgAAAAsAAABoBQAAhQAAAAAAAAAZAAAASAAAAF9fUEFHRVpFUk8AAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAA2AEAAF9fVEVYVAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAcAAAAFAAAABQAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAABQPAAABAAAAbQAAAAAAAAAUDwAAAgAAAAAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAF9fc3ltYm9sX3N0dWIxAABfX1RFWFQAAAAAAAAAAAAAgQ8AAAEAAAAMAAAAAAAAAIEPAAAAAAAAAAAAAAAAAAAIBACAAAAAAAYAAAAAAAAAX19zdHViX2hlbHBlcgAAAF9fVEVYVAAAAAAAAAAAAACQDwAAAQAAABgAAAAAAAAAkA8AAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2NzdHJpbmcAAAAAAAAAX19URVhUAAAAAAAAAAAAAKgPAAABAAAADQAAAAAAAACoDwAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAF9fZWhfZnJhbWUAAAAAAABfX1RFWFQAAAAAAAAAAAAAuA8AAAEAAABIAAAAAAAAALgPAAADAAAAAAAAAAAAAAALAABgAAAAAAAAAAAAAAAAGQAAADgBAABfX0RBVEEAAAAAAAAAAAAAABAAAAEAAAAAEAAAAAAAAAAQAAAAAAAAABAAAAAAAAAHAAAAAwAAAAMAAAAAAAAAX19kYXRhAAAAAAAAAAAAAF9fREFUQQAAAAAAAAAAAAAAEAAAAQAAABwAAAAAAAAAABAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2R5bGQAAAAAAAAAAAAAX19EQVRBAAAAAAAAAAAAACAQAAABAAAAOAAAAAAAAAAgEAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9fbGFfc3ltYm9sX3B0cgBfX0RBVEEAAAAAAAAAAAAAWBAAAAEAAAAQAAAAAAAAAFgQAAACAAAAAAAAAAAAAAAHAAAAAgAAAAAAAAAAAAAAGQAAAEgAAABfX0xJTktFRElUAAAAAAAAACAAAAEAAAAAEAAAAAAAAAAgAAAAAAAAQAEAAAAAAAAHAAAAAQAAAAAAAAAAAAAAAgAAABgAAAAAIAAACwAAAMAgAACAAAAACwAAAFAAAAAAAAAAAgAAAAIAAAAHAAAACQAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwIAAABAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAIAAAAAwAAAAvdXNyL2xpYi9keWxkAAAAAAAAABsAAAAYAAAAOyS4cg5FdtQoqu6JsMEhXQUAAAC4AAAABAAAACoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQPAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAOAAAABgAAAACAAAAAAABAAAAAQAvdXNyL2xpYi9saWJnY2Nfcy4xLmR5bGliAAAAAAAAAAwAAAA4AAAAGAAAAAIAAAAEAW8AAAABAC91c3IvbGliL2xpYlN5c3RlbS5CLmR5bGliAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqAEiJ5UiD5PBIi30ISI11EIn6g8IBweIDSAHySInR6wRIg8EISIM5AHX2SIPBCOgiAAAAicfoMgAAAPRBU0yNHafw//9BU/8lvwAAAA8fAP8lvgAAAFVIieVIjT0zAAAA6A0AAAC4AAAAAMnD/yXRAAAA/yXTAAAAAAAATI0dwQAAAOm0////TI0dvQAAAOmo////aGVsbG8sIHdvcmxkAAAAABQAAAAAAAAAAXpSAAF4EAEQDAcIkAEAACwAAAAcAAAAkv////////8XAAAAAAAAAAAEAQAAAA4QhgIEAwAAAA0GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDAX/9/AAAIEMBf/38AAAAAAAABAAAAGBAAAAEAAAAQEAAAAQAAAAgQAAABAAAAABAAAAEAAACQDwAAAQAAAJwPAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAHgEAAFAPAAABAAAAGwAAAB4BAABkDwAAAQAAAC4AAAAPBgAAGBAAAAEAAAA2AAAADwYAABAQAAABAAAAPgAAAA8GAAAAEAAAAQAAAEoAAAADABAAAAAAAAEAAABeAAAADwYAAAgQAAABAAAAZwAAAA8BAABqDwAAAQAAAG0AAAAPAQAAFA8AAAEAAABzAAAAAQABAgAAAAAAAAAAeQAAAAEAAQIAAAAAAAAAAAkAAAAKAAAACQAAAAoAAAAgAGR5bGRfc3R1Yl9iaW5kaW5nX2hlbHBlcgBfX2R5bGRfZnVuY19sb29rdXAAX05YQXJnYwBfTlhBcmd2AF9fX3Byb2duYW1lAF9fbWhfZXhlY3V0ZV9oZWFkZXIAX2Vudmlyb24AX21haW4Ac3RhcnQAX2V4aXQAX3B1dHMAAA==
\ No newline at end of file
index 851cc216fca2eba28e5898486cc4488113df7967..f87cc5b963912fbdfcf3f5be3e227d3a8412c412 100644 (file)
@@ -83,8 +83,7 @@
 //
 // The //go:embed directive can be used with both exported and unexported variables,
 // depending on whether the package wants to make the data available to other packages.
-// It can only be used with global variables at package scope,
-// not with local variables.
+// It can only be used with variables at package scope, not with local variables.
 //
 // Patterns must not match files outside the package's module, such as ‘.git/*’ or symbolic links.
 // Matches for empty directories are ignored. After that, each pattern in a //go:embed line
@@ -292,6 +291,8 @@ func (f FS) readDir(dir string) []file {
 }
 
 // Open opens the named file for reading and returns it as an fs.File.
+//
+// The returned file implements io.Seeker when the file is not a directory.
 func (f FS) Open(name string) (fs.File, error) {
        file := f.lookup(name)
        if file == nil {
@@ -339,6 +340,10 @@ type openFile struct {
        offset int64 // current read offset
 }
 
+var (
+       _ io.Seeker = (*openFile)(nil)
+)
+
 func (f *openFile) Close() error               { return nil }
 func (f *openFile) Stat() (fs.FileInfo, error) { return f.f, nil }
 
diff --git a/src/embed/example_test.go b/src/embed/example_test.go
new file mode 100644 (file)
index 0000000..5498c27
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 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 embed_test
+
+import (
+       "embed"
+       "log"
+       "net/http"
+)
+
+//go:embed internal/embedtest/testdata/*.txt
+var content embed.FS
+
+func Example() {
+       mutex := http.NewServeMux()
+       mutex.Handle("/", http.FileServer(http.FS(content)))
+       err := http.ListenAndServe(":8080", mutex)
+       if err != nil {
+               log.Fatal(err)
+       }
+}
index 2d50f5e01f1fafe1975dad2fc43c0fa83720e696..bfd94af69d259b4acec395b1de65c0a3ad8439b7 100644 (file)
@@ -89,11 +89,13 @@ func TestDir(t *testing.T) {
        testDir(t, all, "testdata/i/j/k", "k8s.txt")
 }
 
-//go:embed testdata
-var testHiddenDir embed.FS
+var (
+       //go:embed testdata
+       testHiddenDir embed.FS
 
-//go:embed testdata/*
-var testHiddenStar embed.FS
+       //go:embed testdata/*
+       testHiddenStar embed.FS
+)
 
 func TestHidden(t *testing.T) {
        dir := testHiddenDir
@@ -129,3 +131,43 @@ func TestUninitialized(t *testing.T) {
                t.Errorf("in uninitialized embed.FS, . is not a directory")
        }
 }
+
+var (
+       //go:embed "testdata/hello.txt"
+       helloT []T
+       //go:embed "testdata/hello.txt"
+       helloUint8 []uint8
+       //go:embed "testdata/hello.txt"
+       helloEUint8 []EmbedUint8
+       //go:embed "testdata/hello.txt"
+       helloBytes EmbedBytes
+       //go:embed "testdata/hello.txt"
+       helloString EmbedString
+)
+
+type T byte
+type EmbedUint8 uint8
+type EmbedBytes []byte
+type EmbedString string
+
+// golang.org/issue/47735
+func TestAliases(t *testing.T) {
+       all := testDirAll
+       want, e := all.ReadFile("testdata/hello.txt")
+       if e != nil {
+               t.Fatal("ReadFile:", e)
+       }
+       check := func(g interface{}) {
+               got := reflect.ValueOf(g)
+               for i := 0; i < got.Len(); i++ {
+                       if byte(got.Index(i).Uint()) != want[i] {
+                               t.Fatalf("got %v want %v", got.Bytes(), want)
+                       }
+               }
+       }
+       check(helloT)
+       check(helloUint8)
+       check(helloEUint8)
+       check(helloBytes)
+       check(helloString)
+}
index d42eb0ab00a6f970ba2d166dc61ebeb9d9f70413..f1f7af863c33363ec45c17611c5a13252d77f540 100644 (file)
@@ -142,9 +142,7 @@ func (e *encoder) Write(p []byte) (n int, err error) {
        }
 
        // Trailing fringe.
-       for i := 0; i < len(p); i++ {
-               e.buf[i] = p[i]
-       }
+       copy(e.buf[:], p)
        e.nbuf = len(p)
        n += len(p)
        return
index cffc06dc9c8689f528203cbdb7251301322aa396..d0e1c6b176976a775c9d241827b60802ea84f00f 100644 (file)
@@ -1101,7 +1101,7 @@ func (e *invalidUnmarshalError) Error() string {
                return "asn1: Unmarshal recipient value is nil"
        }
 
-       if e.Type.Kind() != reflect.Ptr {
+       if e.Type.Kind() != reflect.Pointer {
                return "asn1: Unmarshal recipient value is non-pointer " + e.Type.String()
        }
        return "asn1: Unmarshal recipient value is nil " + e.Type.String()
@@ -1111,7 +1111,7 @@ func (e *invalidUnmarshalError) Error() string {
 // top-level element. The form of the params is the same as the field tags.
 func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err error) {
        v := reflect.ValueOf(val)
-       if v.Kind() != reflect.Ptr || v.IsNil() {
+       if v.Kind() != reflect.Pointer || v.IsNil() {
                return nil, &invalidUnmarshalError{reflect.TypeOf(val)}
        }
        offset, err := parseField(v.Elem(), b, 0, parseFieldParameters(params))
index 1c712e1eff4f05bffa72da895b698a58e3cd3f92..40115df8b4b6aae141b603a360e1af6fb1761179 100644 (file)
@@ -94,14 +94,7 @@ type fieldParameters struct {
 func parseFieldParameters(str string) (ret fieldParameters) {
        var part string
        for len(str) > 0 {
-               // This loop uses IndexByte and explicit slicing
-               // instead of strings.Split(str, ",") to reduce allocations.
-               i := strings.IndexByte(str, ',')
-               if i < 0 {
-                       part, str = str, ""
-               } else {
-                       part, str = str[:i], str[i+1:]
-               }
+               part, str, _ = strings.Cut(str, ",")
                switch {
                case part == "optional":
                        ret.optional = true
index 2f7d3637e5a85329e97474310e34c54f25053ead..3feea9ba473f7fd0d82e2e71af22a31767d5d7a7 100644 (file)
@@ -221,9 +221,7 @@ func (e *encoder) Write(p []byte) (n int, err error) {
        }
 
        // Trailing fringe.
-       for i := 0; i < len(p); i++ {
-               e.buf[i] = p[i]
-       }
+       copy(e.buf[:], p)
        e.nbuf = len(p)
        n += len(p)
        return
index 2a302d88da2b4eaea929daa6385f6f64c77da6d3..251624f0bd825438f83ffa600bf9f95e6cec617b 100644 (file)
@@ -20,6 +20,15 @@ func ExampleEncoding_EncodeToString() {
        // MFXHSIBLEBXWYZBAEYQGIYLUME======
 }
 
+func ExampleEncoding_Encode() {
+       data := []byte("Hello, world!")
+       dst := make([]byte, base32.StdEncoding.EncodedLen(len(data)))
+       base32.StdEncoding.Encode(dst, data)
+       fmt.Println(string(dst))
+       // Output:
+       // JBSWY3DPFQQHO33SNRSCC===
+}
+
 func ExampleEncoding_DecodeString() {
        str := "ONXW2ZJAMRQXIYJAO5UXI2BAAAQGC3TEEDX3XPY="
        data, err := base32.StdEncoding.DecodeString(str)
@@ -32,6 +41,20 @@ func ExampleEncoding_DecodeString() {
        // "some data with \x00 and \ufeff"
 }
 
+func ExampleEncoding_Decode() {
+       str := "JBSWY3DPFQQHO33SNRSCC==="
+       dst := make([]byte, base32.StdEncoding.DecodedLen(len(str)))
+       n, err := base32.StdEncoding.Decode(dst, []byte(str))
+       if err != nil {
+               fmt.Println("decode error:", err)
+               return
+       }
+       dst = dst[:n]
+       fmt.Printf("%q\n", dst)
+       // Output:
+       // "Hello, world!"
+}
+
 func ExampleNewEncoder() {
        input := []byte("foo\x00bar")
        encoder := base32.NewEncoder(base32.StdEncoding, os.Stdout)
index 0c33f8e5f844348c3ffe35f909de6da83be72ff6..4a3e590649ea95e62dadd92cea0006227f008a4b 100644 (file)
@@ -229,9 +229,7 @@ func (e *encoder) Write(p []byte) (n int, err error) {
        }
 
        // Trailing fringe.
-       for i := 0; i < len(p); i++ {
-               e.buf[i] = p[i]
-       }
+       copy(e.buf[:], p)
        e.nbuf = len(p)
        n += len(p)
        return
index 73f119ac5e549c945e97bfd0d5144bad22855b0a..61a3adc5adfae14026db29dbba460dc0a9e3eb9c 100644 (file)
@@ -35,6 +35,15 @@ func ExampleEncoding_EncodeToString() {
        // YW55ICsgb2xkICYgZGF0YQ==
 }
 
+func ExampleEncoding_Encode() {
+       data := []byte("Hello, world!")
+       dst := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
+       base64.StdEncoding.Encode(dst, data)
+       fmt.Println(string(dst))
+       // Output:
+       // SGVsbG8sIHdvcmxkIQ==
+}
+
 func ExampleEncoding_DecodeString() {
        str := "c29tZSBkYXRhIHdpdGggACBhbmQg77u/"
        data, err := base64.StdEncoding.DecodeString(str)
@@ -47,6 +56,20 @@ func ExampleEncoding_DecodeString() {
        // "some data with \x00 and \ufeff"
 }
 
+func ExampleEncoding_Decode() {
+       str := "SGVsbG8sIHdvcmxkIQ=="
+       dst := make([]byte, base64.StdEncoding.DecodedLen(len(str)))
+       n, err := base64.StdEncoding.Decode(dst, []byte(str))
+       if err != nil {
+               fmt.Println("decode error:", err)
+               return
+       }
+       dst = dst[:n]
+       fmt.Printf("%q\n", dst)
+       // Output:
+       // "Hello, world!"
+}
+
 func ExampleNewEncoder() {
        input := []byte("foo\x00bar")
        encoder := base64.NewEncoder(base64.StdEncoding, os.Stdout)
index a31149979da62951f254c871a1f5e411aec4029f..52417a793347390e580ca21e4109c53e5713aeb0 100644 (file)
@@ -243,7 +243,7 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
        v := reflect.ValueOf(data)
        size := -1
        switch v.Kind() {
-       case reflect.Ptr:
+       case reflect.Pointer:
                v = v.Elem()
                size = dataSize(v)
        case reflect.Slice:
index a03fa83d8ce3a7a7c2075369e95c0ea6e577b71d..5f5cdfcbf8187e4fe7d17c95bf772975b58e05ab 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gofuzz
-// +build gofuzz
 
 package csv
 
index 5965fea921f9d30bd098e3d414f48b79a07c91eb..5ceb2bfac7b4b1a3d2aea3f3280d12e22513de48 100644 (file)
@@ -4,7 +4,6 @@
 
 // Delete the next line to include in the gob package.
 //go:build ignore
-// +build ignore
 
 package gob
 
index 994be877d935b60be097398cf5d9538509cfffc2..e40816eb869ba92af55dac5da521bc5579f98a39 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // encgen writes the helper functions for encoding. Intended to be
 // used with go generate; see the invocation in encode.go.
index d2f6c749b1b6065693cb44940d89e91775f17805..34f302a5cf54d60e6e5cf9d163d4ad8f6f9c7a6b 100644 (file)
@@ -228,7 +228,7 @@ func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) {
 // The callers to the individual decoders are expected to have used decAlloc.
 // The individual decoders don't need to it.
 func decAlloc(v reflect.Value) reflect.Value {
-       for v.Kind() == reflect.Ptr {
+       for v.Kind() == reflect.Pointer {
                if v.IsNil() {
                        v.Set(reflect.New(v.Type().Elem()))
                }
@@ -376,7 +376,7 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
        if value.Cap() < n {
                value.Set(reflect.MakeSlice(value.Type(), n, n))
        } else {
-               value.Set(value.Slice(0, n))
+               value.SetLen(n)
        }
        if _, err := state.b.Read(value.Bytes()); err != nil {
                errorf("error decoding []byte: %s", err)
@@ -464,7 +464,7 @@ func (dec *Decoder) decodeStruct(engine *decEngine, value reflect.Value) {
                if instr.index != nil {
                        // Otherwise the field is unknown to us and instr.op is an ignore op.
                        field = value.FieldByIndex(instr.index)
-                       if field.Kind() == reflect.Ptr {
+                       if field.Kind() == reflect.Pointer {
                                field = decAlloc(field)
                        }
                }
@@ -518,7 +518,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value,
                return
        }
        instr := &decInstr{elemOp, 0, nil, ovfl}
-       isPtr := value.Type().Elem().Kind() == reflect.Ptr
+       isPtr := value.Type().Elem().Kind() == reflect.Pointer
        for i := 0; i < length; i++ {
                if state.b.Len() == 0 {
                        errorf("decoding array or slice: length exceeds input size (%d elements)", length)
@@ -561,8 +561,8 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value refl
        if value.IsNil() {
                value.Set(reflect.MakeMapWithSize(mtyp, n))
        }
-       keyIsPtr := mtyp.Key().Kind() == reflect.Ptr
-       elemIsPtr := mtyp.Elem().Kind() == reflect.Ptr
+       keyIsPtr := mtyp.Key().Kind() == reflect.Pointer
+       elemIsPtr := mtyp.Elem().Kind() == reflect.Pointer
        keyInstr := &decInstr{keyOp, 0, nil, ovfl}
        elemInstr := &decInstr{elemOp, 0, nil, ovfl}
        keyP := reflect.New(mtyp.Key())
@@ -625,7 +625,7 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp
        if value.Cap() < n {
                value.Set(reflect.MakeSlice(typ, n, n))
        } else {
-               value.Set(value.Slice(0, n))
+               value.SetLen(n)
        }
        dec.decodeArrayHelper(state, value, elemOp, n, ovfl, helper)
 }
@@ -945,7 +945,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp)
 func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) *decOp {
        rcvrType := ut.user
        if ut.decIndir == -1 {
-               rcvrType = reflect.PtrTo(rcvrType)
+               rcvrType = reflect.PointerTo(rcvrType)
        } else if ut.decIndir > 0 {
                for i := int8(0); i < ut.decIndir; i++ {
                        rcvrType = rcvrType.Elem()
@@ -954,7 +954,7 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) *decOp {
        var op decOp
        op = func(i *decInstr, state *decoderState, value reflect.Value) {
                // We now have the base type. We need its address if the receiver is a pointer.
-               if value.Kind() != reflect.Ptr && rcvrType.Kind() == reflect.Ptr {
+               if value.Kind() != reflect.Pointer && rcvrType.Kind() == reflect.Pointer {
                        value = value.Addr()
                }
                state.dec.decodeGobDecoder(ut, state, value)
index b476aaac93be537f24ef16c72c208bee6538078d..96e215eb8c16de0ecee6ae69995265a819468706 100644 (file)
@@ -138,9 +138,17 @@ func (dec *Decoder) nextUint() uint64 {
 // decoded. If this is an interface value, it can be ignored by
 // resetting that buffer.
 func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
+       firstMessage := true
        for dec.err == nil {
                if dec.buf.Len() == 0 {
                        if !dec.recvMessage() {
+                               // We can only return io.EOF if the input was empty.
+                               // If we read one or more type spec messages,
+                               // require a data item message to follow.
+                               // If we hit an EOF before that, then give ErrUnexpectedEOF.
+                               if !firstMessage && dec.err == io.EOF {
+                                       dec.err = io.ErrUnexpectedEOF
+                               }
                                break
                        }
                }
@@ -166,6 +174,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
                        }
                        dec.nextUint()
                }
+               firstMessage = false
        }
        return -1
 }
@@ -184,7 +193,7 @@ func (dec *Decoder) Decode(e interface{}) error {
        value := reflect.ValueOf(e)
        // If e represents a value as opposed to a pointer, the answer won't
        // get back to the caller. Make sure it's a pointer.
-       if value.Type().Kind() != reflect.Ptr {
+       if value.Type().Kind() != reflect.Pointer {
                dec.err = errors.New("gob: attempt to decode into a non-pointer")
                return dec.err
        }
@@ -199,7 +208,7 @@ func (dec *Decoder) Decode(e interface{}) error {
 // does not modify v.
 func (dec *Decoder) DecodeValue(v reflect.Value) error {
        if v.IsValid() {
-               if v.Kind() == reflect.Ptr && !v.IsNil() {
+               if v.Kind() == reflect.Pointer && !v.IsNil() {
                        // That's okay, we'll store through the pointer.
                } else if !v.CanSet() {
                        return errors.New("gob: DecodeValue of unassignable value")
index 8c0bbc4ff2e50bbc1f5a891f433b8ada36022f26..f4b1bebfba1dcc0a5506b95f2b449a92f377a09d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
index b562da177dbb34d0b4faf149ced9c1464706946c..e5f68786a0607f66fdaf8ab875ab71546eb7e826 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // encgen writes the helper functions for encoding. Intended to be
 // used with go generate; see the invocation in encode.go.
index 8f8f170c1643c14e84b91a2271599bf15c718c9a..e49b452f6c3724599182c07476bbd238bbed3da2 100644 (file)
@@ -279,7 +279,7 @@ func valid(v reflect.Value) bool {
        switch v.Kind() {
        case reflect.Invalid:
                return false
-       case reflect.Ptr:
+       case reflect.Pointer:
                return !v.IsNil()
        }
        return true
@@ -368,11 +368,11 @@ func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encO
        state := enc.newEncoderState(b)
        state.fieldnum = -1
        state.sendZero = true
-       keys := mv.MapKeys()
-       state.encodeUint(uint64(len(keys)))
-       for _, key := range keys {
-               encodeReflectValue(state, key, keyOp, keyIndir)
-               encodeReflectValue(state, mv.MapIndex(key), elemOp, elemIndir)
+       state.encodeUint(uint64(mv.Len()))
+       mi := mv.MapRange()
+       for mi.Next() {
+               encodeReflectValue(state, mi.Key(), keyOp, keyIndir)
+               encodeReflectValue(state, mi.Value(), elemOp, elemIndir)
        }
        enc.freeEncoderState(state)
 }
@@ -386,7 +386,7 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
        // Gobs can encode nil interface values but not typed interface
        // values holding nil pointers, since nil pointers point to no value.
        elem := iv.Elem()
-       if elem.Kind() == reflect.Ptr && elem.IsNil() {
+       if elem.Kind() == reflect.Pointer && elem.IsNil() {
                errorf("gob: cannot encode nil pointer of type %s inside interface", iv.Elem().Type())
        }
        state := enc.newEncoderState(b)
@@ -446,7 +446,7 @@ func isZero(val reflect.Value) bool {
                return !val.Bool()
        case reflect.Complex64, reflect.Complex128:
                return val.Complex() == 0
-       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
+       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Pointer:
                return val.IsNil()
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
                return val.Int() == 0
@@ -600,7 +600,7 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[
 func gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
        rt := ut.user
        if ut.encIndir == -1 {
-               rt = reflect.PtrTo(rt)
+               rt = reflect.PointerTo(rt)
        } else if ut.encIndir > 0 {
                for i := int8(0); i < ut.encIndir; i++ {
                        rt = rt.Elem()
index 53e2cace1667457a2ff11f1f5c6a1b3d66830d99..32865a7edee49b8e88c5b76da75950867d72d3e5 100644 (file)
@@ -219,7 +219,7 @@ func (enc *Encoder) EncodeValue(value reflect.Value) error {
        if value.Kind() == reflect.Invalid {
                return errors.New("gob: cannot encode nil value")
        }
-       if value.Kind() == reflect.Ptr && value.IsNil() {
+       if value.Kind() == reflect.Pointer && value.IsNil() {
                panic("gob: cannot encode nil pointer of type " + value.Type().String())
        }
 
index 6183646f60c8d39ddbf15896911e3d036848c474..a358d5bc3009d682528d50afb667294e2691218f 100644 (file)
@@ -9,7 +9,9 @@ import (
        "encoding/hex"
        "fmt"
        "io"
+       "math"
        "reflect"
+       "sort"
        "strings"
        "testing"
 )
@@ -1152,3 +1154,114 @@ func TestDecodeErrorMultipleTypes(t *testing.T) {
                t.Errorf("decode: expected duplicate type error, got %s", err.Error())
        }
 }
+
+// Issue 24075
+func TestMarshalFloatMap(t *testing.T) {
+       nan1 := math.NaN()
+       nan2 := math.Float64frombits(math.Float64bits(nan1) ^ 1) // A different NaN in the same class.
+
+       in := map[float64]string{
+               nan1: "a",
+               nan1: "b",
+               nan2: "c",
+       }
+
+       var b bytes.Buffer
+       enc := NewEncoder(&b)
+       if err := enc.Encode(in); err != nil {
+               t.Errorf("Encode : %v", err)
+       }
+
+       out := map[float64]string{}
+       dec := NewDecoder(&b)
+       if err := dec.Decode(&out); err != nil {
+               t.Fatalf("Decode : %v", err)
+       }
+
+       type mapEntry struct {
+               keyBits uint64
+               value   string
+       }
+       readMap := func(m map[float64]string) (entries []mapEntry) {
+               for k, v := range m {
+                       entries = append(entries, mapEntry{math.Float64bits(k), v})
+               }
+               sort.Slice(entries, func(i, j int) bool {
+                       ei, ej := entries[i], entries[j]
+                       if ei.keyBits != ej.keyBits {
+                               return ei.keyBits < ej.keyBits
+                       }
+                       return ei.value < ej.value
+               })
+               return entries
+       }
+
+       got := readMap(out)
+       want := readMap(in)
+       if !reflect.DeepEqual(got, want) {
+               t.Fatalf("\nEncode: %v\nDecode: %v", want, got)
+       }
+}
+
+func TestDecodePartial(t *testing.T) {
+       type T struct {
+               X []int
+               Y string
+       }
+
+       var buf bytes.Buffer
+       t1 := T{X: []int{1, 2, 3}, Y: "foo"}
+       t2 := T{X: []int{4, 5, 6}, Y: "bar"}
+       enc := NewEncoder(&buf)
+
+       t1start := 0
+       if err := enc.Encode(&t1); err != nil {
+               t.Fatal(err)
+       }
+
+       t2start := buf.Len()
+       if err := enc.Encode(&t2); err != nil {
+               t.Fatal(err)
+       }
+
+       data := buf.Bytes()
+       for i := 0; i <= len(data); i++ {
+               bufr := bytes.NewReader(data[:i])
+
+               // Decode both values, stopping at the first error.
+               var t1b, t2b T
+               dec := NewDecoder(bufr)
+               var err error
+               err = dec.Decode(&t1b)
+               if err == nil {
+                       err = dec.Decode(&t2b)
+               }
+
+               switch i {
+               case t1start, t2start:
+                       // Either the first or the second Decode calls had zero input.
+                       if err != io.EOF {
+                               t.Errorf("%d/%d: expected io.EOF: %v", i, len(data), err)
+                       }
+               case len(data):
+                       // We reached the end of the entire input.
+                       if err != nil {
+                               t.Errorf("%d/%d: unexpected error: %v", i, len(data), err)
+                       }
+                       if !reflect.DeepEqual(t1b, t1) {
+                               t.Fatalf("t1 value mismatch: got %v, want %v", t1b, t1)
+                       }
+                       if !reflect.DeepEqual(t2b, t2) {
+                               t.Fatalf("t2 value mismatch: got %v, want %v", t2b, t2)
+                       }
+               default:
+                       // In between, we must see io.ErrUnexpectedEOF.
+                       // The decoder used to erroneously return io.EOF in some cases here,
+                       // such as if the input was cut off right after some type specs,
+                       // but before any value was actually transmitted.
+                       if err != io.ErrUnexpectedEOF {
+                               t.Errorf("%d/%d: expected io.ErrUnexpectedEOF: %v", i, len(data), err)
+                       }
+               }
+       }
+}
index 3478bd247ed8562c0a0336ca73bd55edc97dd9ad..516aeea92c606f4eeef9dd2006bf874516737e2a 100644 (file)
@@ -279,6 +279,20 @@ func BenchmarkDecodeStringSlice(b *testing.B) {
        }
        benchmarkDecodeSlice(b, a)
 }
+func BenchmarkDecodeStringsSlice(b *testing.B) {
+       a := make([][]string, 1000)
+       for i := range a {
+               a[i] = []string{"now is the time"}
+       }
+       benchmarkDecodeSlice(b, a)
+}
+func BenchmarkDecodeBytesSlice(b *testing.B) {
+       a := make([][]byte, 1000)
+       for i := range a {
+               a[i] = []byte("now is the time")
+       }
+       benchmarkDecodeSlice(b, a)
+}
 
 func BenchmarkDecodeInterfaceSlice(b *testing.B) {
        a := make([]interface{}, 1000)
index 31c0ef7af1513f462f008a85c485d2549bbcc919..412a348137f80d728d90fc8ea07d013409f781ca 100644 (file)
@@ -61,7 +61,7 @@ func validUserType(rt reflect.Type) (*userTypeInfo, error) {
        slowpoke := ut.base // walks half as fast as ut.base
        for {
                pt := ut.base
-               if pt.Kind() != reflect.Ptr {
+               if pt.Kind() != reflect.Pointer {
                        break
                }
                ut.base = pt.Elem()
@@ -126,7 +126,7 @@ func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir i
                if rt.Implements(gobEncDecType) {
                        return true, indir
                }
-               if p := rt; p.Kind() == reflect.Ptr {
+               if p := rt; p.Kind() == reflect.Pointer {
                        indir++
                        if indir > 100 { // insane number of indirections
                                return false, 0
@@ -137,9 +137,9 @@ func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir i
                break
        }
        // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
-       if typ.Kind() != reflect.Ptr {
+       if typ.Kind() != reflect.Pointer {
                // Not a pointer, but does the pointer work?
-               if reflect.PtrTo(typ).Implements(gobEncDecType) {
+               if reflect.PointerTo(typ).Implements(gobEncDecType) {
                        return true, -1
                }
        }
@@ -569,7 +569,7 @@ func isSent(field *reflect.StructField) bool {
        // If the field is a chan or func or pointer thereto, don't send it.
        // That is, treat it like an unexported field.
        typ := field.Type
-       for typ.Kind() == reflect.Ptr {
+       for typ.Kind() == reflect.Pointer {
                typ = typ.Elem()
        }
        if typ.Kind() == reflect.Chan || typ.Kind() == reflect.Func {
@@ -842,7 +842,7 @@ func Register(value interface{}) {
        // Dereference one pointer looking for a named type.
        star := ""
        if rt.Name() == "" {
-               if pt := rt; pt.Kind() == reflect.Ptr {
+               if pt := rt; pt.Kind() == reflect.Pointer {
                        star = "*"
                        // NOTE: The following line should be rt = pt.Elem() to implement
                        // what the comment above claims, but fixing it would break compatibility
index 934270eedd8a547d5af9a2dc070de0c244d9c03b..fa3e802d4e1f0b7b25400194ba0d9c96aa2163b4 100644 (file)
@@ -184,7 +184,7 @@ func TestRegistrationNaming(t *testing.T) {
                        t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct)
                }
                // concreteTypeToName is keyed off the base type.
-               if tct.Kind() == reflect.Ptr {
+               if tct.Kind() == reflect.Pointer {
                        tct = tct.Elem()
                }
                if n, _ := concreteTypeToName.Load(tct); n != tc.name {
index a9917e72c761cd408021d37b712620d14ac2a84f..df4c5e1a1693a9194e42ac31cd7cd5db0e68536d 100644 (file)
@@ -161,7 +161,7 @@ func (e *InvalidUnmarshalError) Error() string {
                return "json: Unmarshal(nil)"
        }
 
-       if e.Type.Kind() != reflect.Ptr {
+       if e.Type.Kind() != reflect.Pointer {
                return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
        }
        return "json: Unmarshal(nil " + e.Type.String() + ")"
@@ -169,7 +169,7 @@ func (e *InvalidUnmarshalError) Error() string {
 
 func (d *decodeState) unmarshal(v interface{}) error {
        rv := reflect.ValueOf(v)
-       if rv.Kind() != reflect.Ptr || rv.IsNil() {
+       if rv.Kind() != reflect.Pointer || rv.IsNil() {
                return &InvalidUnmarshalError{reflect.TypeOf(v)}
        }
 
@@ -440,7 +440,7 @@ func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnm
        // If v is a named type and is addressable,
        // start with its address, so that if the type has pointer methods,
        // we find them.
-       if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
+       if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() {
                haveAddr = true
                v = v.Addr()
        }
@@ -449,14 +449,14 @@ func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnm
                // usefully addressable.
                if v.Kind() == reflect.Interface && !v.IsNil() {
                        e := v.Elem()
-                       if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
+                       if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) {
                                haveAddr = false
                                v = e
                                continue
                        }
                }
 
-               if v.Kind() != reflect.Ptr {
+               if v.Kind() != reflect.Pointer {
                        break
                }
 
@@ -641,7 +641,7 @@ func (d *decodeState) object(v reflect.Value) error {
                        reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
                        reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
                default:
-                       if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
+                       if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) {
                                d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)})
                                d.skip()
                                return nil
@@ -717,7 +717,7 @@ func (d *decodeState) object(v reflect.Value) error {
                                subv = v
                                destring = f.quoted
                                for _, i := range f.index {
-                                       if subv.Kind() == reflect.Ptr {
+                                       if subv.Kind() == reflect.Pointer {
                                                if subv.IsNil() {
                                                        // If a struct embeds a pointer to an unexported type,
                                                        // it is not possible to set a newly allocated value
@@ -782,7 +782,7 @@ func (d *decodeState) object(v reflect.Value) error {
                        kt := t.Key()
                        var kv reflect.Value
                        switch {
-                       case reflect.PtrTo(kt).Implements(textUnmarshalerType):
+                       case reflect.PointerTo(kt).Implements(textUnmarshalerType):
                                kv = reflect.New(kt)
                                if err := d.literalStore(item, kv, true); err != nil {
                                        return err
@@ -907,7 +907,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
                        break
                }
                switch v.Kind() {
-               case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
+               case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice:
                        v.Set(reflect.Zero(v.Type()))
                        // otherwise, ignore null for primitives/string
                }
index 219e845c7b0b2cf47d6ffc2ca006715edb10e56e..96bf9fb5ffdedfc45c4f25169b2077ee6c0a6b38 100644 (file)
@@ -1103,7 +1103,7 @@ func TestUnmarshal(t *testing.T) {
                }
 
                typ := reflect.TypeOf(tt.ptr)
-               if typ.Kind() != reflect.Ptr {
+               if typ.Kind() != reflect.Pointer {
                        t.Errorf("#%d: unmarshalTest.ptr %T is not a pointer type", i, tt.ptr)
                        continue
                }
index e473e615a9ed43f5f974853e86b220259c81c091..4f40197797e342b8b42eafb24ccf1992a5968050 100644 (file)
@@ -350,7 +350,7 @@ func isEmptyValue(v reflect.Value) bool {
                return v.Uint() == 0
        case reflect.Float32, reflect.Float64:
                return v.Float() == 0
-       case reflect.Interface, reflect.Ptr:
+       case reflect.Interface, reflect.Pointer:
                return v.IsNil()
        }
        return false
@@ -419,13 +419,13 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
        // Marshaler with a value receiver, then we're better off taking
        // the address of the value - otherwise we end up with an
        // allocation as we cast the value to an interface.
-       if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(marshalerType) {
+       if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(marshalerType) {
                return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
        }
        if t.Implements(marshalerType) {
                return marshalerEncoder
        }
-       if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(textMarshalerType) {
+       if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(textMarshalerType) {
                return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
        }
        if t.Implements(textMarshalerType) {
@@ -455,7 +455,7 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
                return newSliceEncoder(t)
        case reflect.Array:
                return newArrayEncoder(t)
-       case reflect.Ptr:
+       case reflect.Pointer:
                return newPtrEncoder(t)
        default:
                return unsupportedTypeEncoder
@@ -467,7 +467,7 @@ func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) {
 }
 
 func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
-       if v.Kind() == reflect.Ptr && v.IsNil() {
+       if v.Kind() == reflect.Pointer && v.IsNil() {
                e.WriteString("null")
                return
        }
@@ -504,7 +504,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 }
 
 func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
-       if v.Kind() == reflect.Ptr && v.IsNil() {
+       if v.Kind() == reflect.Pointer && v.IsNil() {
                e.WriteString("null")
                return
        }
@@ -738,7 +738,7 @@ FieldLoop:
                // Find the nested struct field by following f.index.
                fv := v
                for _, i := range f.index {
-                       if fv.Kind() == reflect.Ptr {
+                       if fv.Kind() == reflect.Pointer {
                                if fv.IsNil() {
                                        continue FieldLoop
                                }
@@ -893,7 +893,7 @@ func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 func newSliceEncoder(t reflect.Type) encoderFunc {
        // Byte slices get special treatment; arrays don't.
        if t.Elem().Kind() == reflect.Uint8 {
-               p := reflect.PtrTo(t.Elem())
+               p := reflect.PointerTo(t.Elem())
                if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {
                        return encodeByteSlice
                }
@@ -989,7 +989,7 @@ func isValidTag(s string) bool {
 
 func typeByIndex(t reflect.Type, index []int) reflect.Type {
        for _, i := range index {
-               if t.Kind() == reflect.Ptr {
+               if t.Kind() == reflect.Pointer {
                        t = t.Elem()
                }
                t = t.Field(i).Type
@@ -1009,7 +1009,7 @@ func (w *reflectWithString) resolve() error {
                return nil
        }
        if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok {
-               if w.k.Kind() == reflect.Ptr && w.k.IsNil() {
+               if w.k.Kind() == reflect.Pointer && w.k.IsNil() {
                        return nil
                }
                buf, err := tm.MarshalText()
@@ -1243,7 +1243,7 @@ func typeFields(t reflect.Type) structFields {
                                sf := f.typ.Field(i)
                                if sf.Anonymous {
                                        t := sf.Type
-                                       if t.Kind() == reflect.Ptr {
+                                       if t.Kind() == reflect.Pointer {
                                                t = t.Elem()
                                        }
                                        if !sf.IsExported() && t.Kind() != reflect.Struct {
@@ -1269,7 +1269,7 @@ func typeFields(t reflect.Type) structFields {
                                index[len(f.index)] = i
 
                                ft := sf.Type
-                               if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+                               if ft.Name() == "" && ft.Kind() == reflect.Pointer {
                                        // Follow pointer.
                                        ft = ft.Elem()
                                }
index d3fa2d111384152b18e9b804bea4bf429c1548ed..f00898a798d31793302e96641eb13a385e9a40f6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gofuzz
-// +build gofuzz
 
 package json
 
index c38fd5102f6302deb1e10639dbe4552ee255837e..b490328f4c46e70aa85413ac5a4ee5a0190592e9 100644 (file)
@@ -15,10 +15,8 @@ type tagOptions string
 // parseTag splits a struct field's json tag into its name and
 // comma-separated options.
 func parseTag(tag string) (string, tagOptions) {
-       if idx := strings.Index(tag, ","); idx != -1 {
-               return tag[:idx], tagOptions(tag[idx+1:])
-       }
-       return tag, tagOptions("")
+       tag, opt, _ := strings.Cut(tag, ",")
+       return tag, tagOptions(opt)
 }
 
 // Contains reports whether a comma-separated list of options
@@ -30,15 +28,11 @@ func (o tagOptions) Contains(optionName string) bool {
        }
        s := string(o)
        for s != "" {
-               var next string
-               i := strings.Index(s, ",")
-               if i >= 0 {
-                       s, next = s[:i], s[i+1:]
-               }
-               if s == optionName {
+               var name string
+               name, s, _ = strings.Cut(s, ",")
+               if name == optionName {
                        return true
                }
-               s = next
        }
        return false
 }
index a7272da5ad3a81575c3930fd405aafb824375004..e7adf88382320d4de57851430f0ea2211f139c5a 100644 (file)
@@ -78,6 +78,7 @@ func removeSpacesAndTabs(data []byte) []byte {
 var pemStart = []byte("\n-----BEGIN ")
 var pemEnd = []byte("\n-----END ")
 var pemEndOfLine = []byte("-----")
+var colon = []byte(":")
 
 // Decode will find the next PEM formatted block (certificate, private key
 // etc) in the input. It returns that block and the remainder of the input. If
@@ -89,8 +90,8 @@ func Decode(data []byte) (p *Block, rest []byte) {
        rest = data
        if bytes.HasPrefix(data, pemStart[1:]) {
                rest = rest[len(pemStart)-1 : len(data)]
-       } else if i := bytes.Index(data, pemStart); i >= 0 {
-               rest = rest[i+len(pemStart) : len(data)]
+       } else if _, after, ok := bytes.Cut(data, pemStart); ok {
+               rest = after
        } else {
                return nil, data
        }
@@ -114,13 +115,12 @@ func Decode(data []byte) (p *Block, rest []byte) {
                }
                line, next := getLine(rest)
 
-               i := bytes.IndexByte(line, ':')
-               if i == -1 {
+               key, val, ok := bytes.Cut(line, colon)
+               if !ok {
                        break
                }
 
                // TODO(agl): need to cope with values that spread across lines.
-               key, val := line[:i], line[i+1:]
                key = bytes.TrimSpace(key)
                val = bytes.TrimSpace(val)
                p.Headers[string(key)] = string(val)
index d8a04a95a2520fa39b8028dd97f43bef70804aba..1f0eb7634115e179422999c2e3cd4d55b3371193 100644 (file)
@@ -420,7 +420,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
        // Drill into interfaces and pointers.
        // This can turn into an infinite loop given a cyclic chain,
        // but it matches the Go 1 behavior.
-       for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
+       for val.Kind() == reflect.Interface || val.Kind() == reflect.Pointer {
                if val.IsNil() {
                        return nil
                }
@@ -494,6 +494,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
        }
        if start.Name.Local == "" {
                name := typ.Name()
+               if i := strings.IndexByte(name, '['); i >= 0 {
+                       // Truncate generic instantiation name. See issue 48318.
+                       name = name[:i]
+               }
                if name == "" {
                        return &UnsupportedTypeError{typ}
                }
@@ -599,7 +603,7 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
 
        // Dereference or skip nil pointer, interface values.
        switch val.Kind() {
-       case reflect.Ptr, reflect.Interface:
+       case reflect.Pointer, reflect.Interface:
                if val.IsNil() {
                        return nil
                }
@@ -793,7 +797,7 @@ var ddBytes = []byte("--")
 // This can turn into an infinite loop given a cyclic chain,
 // but it matches the Go 1 behavior.
 func indirect(vf reflect.Value) reflect.Value {
-       for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
+       for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Pointer {
                if vf.IsNil() {
                        return vf
                }
@@ -942,7 +946,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
                                return err
                        }
                        if len(finfo.parents) > len(s.stack) {
-                               if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
+                               if vf.Kind() != reflect.Pointer && vf.Kind() != reflect.Interface || !vf.IsNil() {
                                        if err := s.push(finfo.parents[len(s.stack):]); err != nil {
                                                return err
                                        }
@@ -1051,7 +1055,7 @@ func isEmptyValue(v reflect.Value) bool {
                return v.Uint() == 0
        case reflect.Float32, reflect.Float64:
                return v.Float() == 0
-       case reflect.Interface, reflect.Ptr:
+       case reflect.Interface, reflect.Pointer:
                return v.IsNil()
        }
        return false
index ef5df3f7f6aecca09302cb07050711d8b79b51da..48b0ec055c17fecd8a456c44313258f82ef114c3 100644 (file)
@@ -145,7 +145,7 @@ func (d *Decoder) Decode(v interface{}) error {
 // but also wants to defer to Unmarshal for some elements.
 func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
        val := reflect.ValueOf(v)
-       if val.Kind() != reflect.Ptr {
+       if val.Kind() != reflect.Pointer {
                return errors.New("non-pointer passed to Unmarshal")
        }
        return d.unmarshal(val.Elem(), start)
@@ -244,7 +244,7 @@ func (d *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
 
 // unmarshalAttr unmarshals a single XML attribute into val.
 func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
-       if val.Kind() == reflect.Ptr {
+       if val.Kind() == reflect.Pointer {
                if val.IsNil() {
                        val.Set(reflect.New(val.Type().Elem()))
                }
@@ -324,12 +324,12 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
        // usefully addressable.
        if val.Kind() == reflect.Interface && !val.IsNil() {
                e := val.Elem()
-               if e.Kind() == reflect.Ptr && !e.IsNil() {
+               if e.Kind() == reflect.Pointer && !e.IsNil() {
                        val = e
                }
        }
 
-       if val.Kind() == reflect.Ptr {
+       if val.Kind() == reflect.Pointer {
                if val.IsNil() {
                        val.Set(reflect.New(val.Type().Elem()))
                }
@@ -602,7 +602,7 @@ Loop:
 func copyValue(dst reflect.Value, src []byte) (err error) {
        dst0 := dst
 
-       if dst.Kind() == reflect.Ptr {
+       if dst.Kind() == reflect.Pointer {
                if dst.IsNil() {
                        dst.Set(reflect.New(dst.Type().Elem()))
                }
index 162724ef1a58b02d452a7783a11f523c65c3d6bf..6b399b9a0e67392de2e09b10bdd24806387db4da 100644 (file)
@@ -67,7 +67,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
                        // For embedded structs, embed its fields.
                        if f.Anonymous {
                                t := f.Type
-                               if t.Kind() == reflect.Ptr {
+                               if t.Kind() == reflect.Pointer {
                                        t = t.Elem()
                                }
                                if t.Kind() == reflect.Struct {
@@ -115,8 +115,8 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
 
        // Split the tag from the xml namespace if necessary.
        tag := f.Tag.Get("xml")
-       if i := strings.Index(tag, " "); i >= 0 {
-               finfo.xmlns, tag = tag[:i], tag[i+1:]
+       if ns, t, ok := strings.Cut(tag, " "); ok {
+               finfo.xmlns, tag = ns, t
        }
 
        // Parse flags.
@@ -229,7 +229,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
 // in case it exists and has a valid xml field tag, otherwise
 // it returns nil.
 func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) {
-       for typ.Kind() == reflect.Ptr {
+       for typ.Kind() == reflect.Pointer {
                typ = typ.Elem()
        }
        if typ.Kind() != reflect.Struct {
@@ -358,7 +358,7 @@ func (finfo *fieldInfo) value(v reflect.Value, shouldInitNilPointers bool) refle
        for i, x := range finfo.idx {
                if i > 0 {
                        t := v.Type()
-                       if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
+                       if t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Struct {
                                if v.IsNil() {
                                        if !shouldInitNilPointers {
                                                return reflect.Value{}
index c14954df155a64a0ff3ef1126f22376538f4f78a..33d0b417b91e11f619bdedc9de2a15bd64b9e71f 100644 (file)
@@ -1164,11 +1164,11 @@ func (d *Decoder) nsname() (name Name, ok bool) {
        }
        if strings.Count(s, ":") > 1 {
                name.Local = s
-       } else if i := strings.Index(s, ":"); i < 1 || i > len(s)-2 {
+       } else if space, local, ok := strings.Cut(s, ":"); !ok || space == "" || local == "" {
                name.Local = s
        } else {
-               name.Space = s[0:i]
-               name.Local = s[i+1:]
+               name.Space = space
+               name.Local = local
        }
        return name, true
 }
@@ -2012,25 +2012,26 @@ func emitCDATA(w io.Writer, s []byte) error {
        if _, err := w.Write(cdataStart); err != nil {
                return err
        }
+
        for {
-               i := bytes.Index(s, cdataEnd)
-               if i >= 0 && i+len(cdataEnd) <= len(s) {
-                       // Found a nested CDATA directive end.
-                       if _, err := w.Write(s[:i]); err != nil {
-                               return err
-                       }
-                       if _, err := w.Write(cdataEscape); err != nil {
-                               return err
-                       }
-                       i += len(cdataEnd)
-               } else {
-                       if _, err := w.Write(s); err != nil {
-                               return err
-                       }
+               before, after, ok := bytes.Cut(s, cdataEnd)
+               if !ok {
                        break
                }
-               s = s[i:]
+               // Found a nested CDATA directive end.
+               if _, err := w.Write(before); err != nil {
+                       return err
+               }
+               if _, err := w.Write(cdataEscape); err != nil {
+                       return err
+               }
+               s = after
+       }
+
+       if _, err := w.Write(s); err != nil {
+               return err
        }
+
        _, err := w.Write(cdataEnd)
        return err
 }
@@ -2041,20 +2042,16 @@ func procInst(param, s string) string {
        // TODO: this parsing is somewhat lame and not exact.
        // It works for all actual cases, though.
        param = param + "="
-       idx := strings.Index(s, param)
-       if idx == -1 {
-               return ""
-       }
-       v := s[idx+len(param):]
+       _, v, _ := strings.Cut(s, param)
        if v == "" {
                return ""
        }
        if v[0] != '\'' && v[0] != '"' {
                return ""
        }
-       idx = strings.IndexRune(v[1:], rune(v[0]))
-       if idx == -1 {
+       unquote, _, ok := strings.Cut(v[1:], v[:1])
+       if !ok {
                return ""
        }
-       return v[1 : idx+1]
+       return unquote
 }
index 4eb4f9ae378bdbb182d4403edfd725cebbd6dfa6..ab3cdb86d31f5ed8a812158f43227ed1b4c9347f 100644 (file)
@@ -35,7 +35,8 @@ func Unwrap(err error) error {
 //     func (m MyError) Is(target error) bool { return target == fs.ErrExist }
 //
 // then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for
-// an example in the standard library.
+// an example in the standard library. An Is method should only shallowly
+// compare err and the target and not call Unwrap on either.
 func Is(err, target error) bool {
        if target == nil {
                return err == target
@@ -58,7 +59,7 @@ func Is(err, target error) bool {
        }
 }
 
-// As finds the first error in err's chain that matches target, and if so, sets
+// As finds the first error in err's chain that matches target, and if one is found, sets
 // target to that error value and returns true. Otherwise, it returns false.
 //
 // The chain consists of err itself followed by the sequence of errors obtained by
index 885a4c8369663f99b9b492bb65d4e768b66d51f6..86e16e5a612f303b308d68183e616c4433ab4c6f 100644 (file)
@@ -456,7 +456,7 @@ func isZeroValue(flag *Flag, value string) bool {
        // This works unless the Value type is itself an interface type.
        typ := reflect.TypeOf(flag.Value)
        var z reflect.Value
-       if typ.Kind() == reflect.Ptr {
+       if typ.Kind() == reflect.Pointer {
                z = reflect.New(typ.Elem())
        } else {
                z = reflect.Zero(typ)
index 8bc225f5484ae4171e650d52cba6c93db13beadb..698ab557a4a3f91a4aa1bcb1a1dfe86a677265b7 100644 (file)
@@ -498,7 +498,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
 func (p *pp) fmtPointer(value reflect.Value, verb rune) {
        var u uintptr
        switch value.Kind() {
-       case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
+       case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Slice, reflect.UnsafePointer:
                u = value.Pointer()
        default:
                p.badVerb(verb)
@@ -538,7 +538,7 @@ func (p *pp) catchPanic(arg interface{}, verb rune, method string) {
                // If it's a nil pointer, just say "<nil>". The likeliest causes are a
                // Stringer that fails to guard against nil or a nil pointer for a
                // value receiver, and in either case, "<nil>" is a nice result.
-               if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
+               if v := reflect.ValueOf(arg); v.Kind() == reflect.Pointer && v.IsNil() {
                        p.buf.writeString(nilAngleString)
                        return
                }
@@ -866,7 +866,7 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) {
                        }
                        p.buf.writeByte(']')
                }
-       case reflect.Ptr:
+       case reflect.Pointer:
                // pointer to array or slice or struct? ok at top level
                // but not embedded (avoid loops)
                if depth == 0 && f.Pointer() != 0 {
index 381577049c0fc9343eaf4b3b29798e6a763d04e3..18cb608f43ba2e6189fc29176a07d920d6c13e9e 100644 (file)
@@ -1017,7 +1017,7 @@ func (s *ss) scanOne(verb rune, arg interface{}) {
        default:
                val := reflect.ValueOf(v)
                ptr := val
-               if ptr.Kind() != reflect.Ptr {
+               if ptr.Kind() != reflect.Pointer {
                        s.errorString("type not a pointer: " + val.Type().String())
                        return
                }
index 1cc469ce3610c1411003ac255fc8c51005157449..6b71b792ed1bb2e6705a29f5ae3dc2b61711bb47 100644 (file)
@@ -516,7 +516,7 @@ func testScan(t *testing.T, f func(string) io.Reader, scan func(r io.Reader, a .
                }
                // The incoming value may be a pointer
                v := reflect.ValueOf(test.in)
-               if p := v; p.Kind() == reflect.Ptr {
+               if p := v; p.Kind() == reflect.Pointer {
                        v = p.Elem()
                }
                val := v.Interface()
@@ -561,7 +561,7 @@ func TestScanf(t *testing.T) {
                }
                // The incoming value may be a pointer
                v := reflect.ValueOf(test.in)
-               if p := v; p.Kind() == reflect.Ptr {
+               if p := v; p.Kind() == reflect.Pointer {
                        v = p.Elem()
                }
                val := v.Interface()
index 1fb8cbfcbe07155891d25e5e60ccd8fbf5062dc4..7d982c75aa3a0721bdba1ce5def3a34d9fe03f53 100644 (file)
@@ -3,8 +3,11 @@ module std
 go 1.18
 
 require (
-       golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e
-       golang.org/x/net v0.0.0-20210510120150-4163338589ed
-       golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
-       golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f // indirect
+       golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
+       golang.org/x/net v0.0.0-20211005215030-d2e5035098b3
+)
+
+require (
+       golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
+       golang.org/x/text v0.3.7 // indirect
 )
index b3de6c526c98c72c2029a8c354706653dba751b5..ff1279697dcc3ef973973ed1658a9b352a1f4e41 100644 (file)
@@ -1,8 +1,8 @@
-golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
-golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
-golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI=
-golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20211005215030-d2e5035098b3 h1:G64nFNerDErBd2KdvHvIn3Ee6ccUQBTfhDZEO0DccfU=
+golang.org/x/net v0.0.0-20211005215030-d2e5035098b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
index b0f133056425652958430342ca433dce4b732656..bc140473d58d2fbc634a70197b34956d447a3e3a 100644 (file)
@@ -193,14 +193,10 @@ func isDirective(c string) bool {
 // in a signature.
 // Field.Names is nil for unnamed parameters (parameter lists which only contain types)
 // and embedded struct fields. In the latter case, the field name is the type name.
-// Field.Names contains a single name "type" for elements of interface type lists.
-// Types belonging to the same type list share the same "type" identifier which also
-// records the position of that keyword.
-//
 type Field struct {
        Doc     *CommentGroup // associated documentation; or nil
-       Names   []*Ident      // field/method/(type) parameter names, or type "type"; or nil
-       Type    Expr          // field/method/parameter type, type list type; or nil
+       Names   []*Ident      // field/method/(type) parameter names; or nil
+       Type    Expr          // field/method/parameter type; or nil
        Tag     *BasicLit     // field tag; or nil
        Comment *CommentGroup // line comments; or nil
 }
@@ -344,9 +340,9 @@ type (
                Rbrack token.Pos // position of "]"
        }
 
-       // A MultiIndexExpr node represents an expression followed by multiple
+       // An IndexListExpr node represents an expression followed by multiple
        // indices.
-       MultiIndexExpr struct {
+       IndexListExpr struct {
                X       Expr      // expression
                Lbrack  token.Pos // position of "["
                Indices []Expr    // index expressions
@@ -451,10 +447,10 @@ type (
 
        // A FuncType node represents a function type.
        FuncType struct {
-               Func    token.Pos  // position of "func" keyword (token.NoPos if there is no "func")
-               TParams *FieldList // type parameters; or nil
-               Params  *FieldList // (incoming) parameters; non-nil
-               Results *FieldList // (outgoing) results; or nil
+               Func       token.Pos  // position of "func" keyword (token.NoPos if there is no "func")
+               TypeParams *FieldList // type parameters; or nil
+               Params     *FieldList // (incoming) parameters; non-nil
+               Results    *FieldList // (outgoing) results; or nil
        }
 
        // An InterfaceType node represents an interface type.
@@ -496,7 +492,7 @@ func (x *CompositeLit) Pos() token.Pos {
 func (x *ParenExpr) Pos() token.Pos      { return x.Lparen }
 func (x *SelectorExpr) Pos() token.Pos   { return x.X.Pos() }
 func (x *IndexExpr) Pos() token.Pos      { return x.X.Pos() }
-func (x *MultiIndexExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *IndexListExpr) Pos() token.Pos  { return x.X.Pos() }
 func (x *SliceExpr) Pos() token.Pos      { return x.X.Pos() }
 func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() }
 func (x *CallExpr) Pos() token.Pos       { return x.Fun.Pos() }
@@ -530,7 +526,7 @@ func (x *CompositeLit) End() token.Pos   { return x.Rbrace + 1 }
 func (x *ParenExpr) End() token.Pos      { return x.Rparen + 1 }
 func (x *SelectorExpr) End() token.Pos   { return x.Sel.End() }
 func (x *IndexExpr) End() token.Pos      { return x.Rbrack + 1 }
-func (x *MultiIndexExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *IndexListExpr) End() token.Pos  { return x.Rbrack + 1 }
 func (x *SliceExpr) End() token.Pos      { return x.Rbrack + 1 }
 func (x *TypeAssertExpr) End() token.Pos { return x.Rparen + 1 }
 func (x *CallExpr) End() token.Pos       { return x.Rparen + 1 }
@@ -562,7 +558,7 @@ func (*CompositeLit) exprNode()   {}
 func (*ParenExpr) exprNode()      {}
 func (*SelectorExpr) exprNode()   {}
 func (*IndexExpr) exprNode()      {}
-func (*MultiIndexExpr) exprNode() {}
+func (*IndexListExpr) exprNode()  {}
 func (*SliceExpr) exprNode()      {}
 func (*TypeAssertExpr) exprNode() {}
 func (*CallExpr) exprNode()       {}
@@ -915,12 +911,12 @@ type (
 
        // A TypeSpec node represents a type declaration (TypeSpec production).
        TypeSpec struct {
-               Doc     *CommentGroup // associated documentation; or nil
-               Name    *Ident        // type name
-               TParams *FieldList    // type parameters; or nil
-               Assign  token.Pos     // position of '=', if any
-               Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
-               Comment *CommentGroup // line comments; or nil
+               Doc        *CommentGroup // associated documentation; or nil
+               Name       *Ident        // type name
+               TypeParams *FieldList    // type parameters; or nil
+               Assign     token.Pos     // position of '=', if any
+               Type       Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
+               Comment    *CommentGroup // line comments; or nil
        }
 )
 
@@ -998,8 +994,6 @@ type (
                Name *Ident        // function/method name
                Type *FuncType     // function signature: type and value parameters, results, and position of "func" keyword
                Body *BlockStmt    // function body; or nil for external (non-Go) function
-               // TODO(rFindley) consider storing TParams here, rather than FuncType, as
-               //                they are only valid for declared functions
        }
 )
 
index d86d9ba64b78168f42ff2fdef7e6b1f676e31e07..b58683075cbca26dc4b1dbec973a9ccb07a8defb 100644 (file)
@@ -21,7 +21,7 @@ type FieldFilter func(name string, value reflect.Value) bool
 // it returns false otherwise.
 func NotNilFilter(_ string, v reflect.Value) bool {
        switch v.Kind() {
-       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
                return !v.IsNil()
        }
        return true
@@ -165,7 +165,7 @@ func (p *printer) print(x reflect.Value) {
                }
                p.printf("}")
 
-       case reflect.Ptr:
+       case reflect.Pointer:
                p.printf("*")
                // type-checked ASTs may contain cycles - use ptrmap
                // to keep track of objects that have been printed
index c8abc40972842157dfaee016b5d669829ba51cf8..308662f633b50cec49ec14e355f98c4aa24bbded 100644 (file)
@@ -116,7 +116,7 @@ func Walk(v Visitor, node Node) {
                Walk(v, n.X)
                Walk(v, n.Index)
 
-       case *MultiIndexExpr:
+       case *IndexListExpr:
                Walk(v, n.X)
                for _, index := range n.Indices {
                        Walk(v, index)
@@ -169,8 +169,8 @@ func Walk(v Visitor, node Node) {
                Walk(v, n.Fields)
 
        case *FuncType:
-               if n.TParams != nil {
-                       Walk(v, n.TParams)
+               if n.TypeParams != nil {
+                       Walk(v, n.TypeParams)
                }
                if n.Params != nil {
                        Walk(v, n.Params)
@@ -326,8 +326,8 @@ func Walk(v Visitor, node Node) {
                        Walk(v, n.Doc)
                }
                Walk(v, n.Name)
-               if n.TParams != nil {
-                       Walk(v, n.TParams)
+               if n.TypeParams != nil {
+                       Walk(v, n.TypeParams)
                }
                Walk(v, n.Type)
                if n.Comment != nil {
index 6e8a89a39273c6756f4a92bf328ebae32feab961..b0decbba9f514db3fea79803040f7fba7f5bd4d7 100644 (file)
@@ -1258,19 +1258,14 @@ func findImportComment(data []byte) (s string, line int) {
        var comment []byte
        switch {
        case bytes.HasPrefix(data, slashSlash):
-               i := bytes.Index(data, newline)
-               if i < 0 {
-                       i = len(data)
-               }
-               comment = data[2:i]
+               comment, _, _ = bytes.Cut(data[2:], newline)
        case bytes.HasPrefix(data, slashStar):
-               data = data[2:]
-               i := bytes.Index(data, starSlash)
-               if i < 0 {
+               var ok bool
+               comment, _, ok = bytes.Cut(data[2:], starSlash)
+               if !ok {
                        // malformed comment
                        return "", 0
                }
-               comment = data[:i]
                if bytes.Contains(comment, newline) {
                        return "", 0
                }
@@ -1654,12 +1649,10 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
                }
 
                // Split at colon.
-               line = strings.TrimSpace(line[4:])
-               i := strings.Index(line, ":")
-               if i < 0 {
+               line, argstr, ok := strings.Cut(strings.TrimSpace(line[4:]), ":")
+               if !ok {
                        return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
                }
-               line, argstr := line[:i], line[i+1:]
 
                // Parse GOOS/GOARCH stuff.
                f := strings.Fields(line)
@@ -1685,7 +1678,6 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
                if err != nil {
                        return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
                }
-               var ok bool
                for i, arg := range args {
                        if arg, ok = expandSrcDir(arg, di.Dir); !ok {
                                return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
@@ -1949,9 +1941,7 @@ func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool {
 // if GOOS=illumos, then files with GOOS=solaris are also matched.
 // if GOOS=ios, then files with GOOS=darwin are also matched.
 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
-       if dot := strings.Index(name, "."); dot != -1 {
-               name = name[:dot]
-       }
+       name, _, _ = strings.Cut(name, ".")
 
        // Before Go 1.4, a file called "linux.go" would be equivalent to having a
        // build tag "linux" in that file. For Go 1.4 and beyond, we require this
index 80f930f3c23bef47516580717c8cb729273d93d1..cfe9c5e4bb286b82a944e41929adb72c080bfd2a 100644 (file)
@@ -712,7 +712,7 @@ func TestMissingImportErrorRepetition(t *testing.T) {
        // Also don't count instances in suggested "go get" or similar commands
        // (see https://golang.org/issue/41576). The suggested command typically
        // follows a semicolon.
-       errStr = strings.SplitN(errStr, ";", 2)[0]
+       errStr, _, _ = strings.Cut(errStr, ";")
 
        if n := strings.Count(errStr, pkgPath); n != 1 {
                t.Fatalf("package path %q appears in error %d times; should appear once\nerror: %v", pkgPath, n, err)
index 7e43445a0739664fc915c11abd183fc793657f25..9b5dabf6f144156d8f0e5be05058470bf876b9ae 100644 (file)
@@ -70,7 +70,7 @@ import (
 var depsRules = `
        # No dependencies allowed for any of these packages.
        NONE
-       < container/list, container/ring,
+       < constraints, container/list, container/ring,
          internal/cfg, internal/cpu, internal/goarch,
          internal/goexperiment, internal/goos,
          internal/goversion, internal/nettrace,
@@ -173,7 +173,7 @@ var depsRules = `
        io/fs
        < embed;
 
-       unicode, fmt !< os, os/signal;
+       unicode, fmt !< net, os, os/signal;
 
        os/signal, STR
        < path/filepath
@@ -187,6 +187,8 @@ var depsRules = `
        OS
        < golang.org/x/sys/cpu;
 
+       os < internal/godebug;
+
        # 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
@@ -214,7 +216,6 @@ var depsRules = `
          mime/quotedprintable,
          net/internal/socktest,
          net/url,
-         runtime/debug,
          runtime/trace,
          text/scanner,
          text/tabwriter;
@@ -271,8 +272,10 @@ var depsRules = `
 
        # executable parsing
        FMT, encoding/binary, compress/zlib
+       < runtime/debug
        < debug/dwarf
        < debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
+       < debug/buildinfo
        < DEBUG;
 
        # go parser and friends.
@@ -330,7 +333,7 @@ var depsRules = `
        < C
        < runtime/cgo
        < CGO
-       < runtime/race, runtime/msan;
+       < runtime/race, runtime/msan, runtime/asan;
 
        # Bulk of the standard library must not use cgo.
        # The prohibition stops at net and os/user.
@@ -351,6 +354,13 @@ var depsRules = `
          golang.org/x/net/lif,
          golang.org/x/net/route;
 
+       os, runtime, strconv, sync, unsafe,
+       internal/godebug
+       < internal/intern;
+
+       internal/bytealg, internal/intern, internal/itoa, math/bits, sort, strconv
+       < net/netip;
+
        # net is unavoidable when doing any networking,
        # so large dependencies must be kept out.
        # This is a long-looking list but most of these
@@ -359,10 +369,12 @@ var depsRules = `
        golang.org/x/net/dns/dnsmessage,
        golang.org/x/net/lif,
        golang.org/x/net/route,
+       internal/godebug,
        internal/nettrace,
        internal/poll,
        internal/singleflight,
        internal/race,
+       net/netip,
        os
        < net;
 
@@ -398,7 +410,8 @@ var depsRules = `
        < crypto/subtle
        < crypto/internal/subtle
        < crypto/elliptic/internal/fiat
-       < crypto/ed25519/internal/edwards25519/field
+       < crypto/elliptic/internal/nistec
+       < crypto/ed25519/internal/edwards25519/field, golang.org/x/crypto/curve25519/internal/field
        < crypto/ed25519/internal/edwards25519
        < crypto/cipher
        < encoding/asn1
@@ -514,10 +527,14 @@ var depsRules = `
        FMT, flag, math/rand
        < testing/quick;
 
-       FMT, flag, runtime/debug, runtime/trace, internal/sysinfo, math/rand
+       FMT, DEBUG, flag, runtime/trace, internal/sysinfo, math/rand
        < testing;
 
-       internal/testlog, runtime/pprof, regexp
+       FMT, crypto/sha256, encoding/json, go/ast, go/parser, go/token,
+       internal/godebug, math/rand, encoding/hex, crypto/sha256
+       < internal/fuzz;
+
+       internal/fuzz, internal/testlog, runtime/pprof, regexp
        < testing/internal/testdeps;
 
        OS, flag, testing, internal/cfg
@@ -621,7 +638,7 @@ func TestDependencies(t *testing.T) {
        }
 }
 
-var buildIgnore = []byte("\n// +build ignore")
+var buildIgnore = []byte("\n//go:build ignore")
 
 func findImports(pkg string) ([]string, error) {
        vpkg := pkg
@@ -658,6 +675,9 @@ func findImports(pkg string) ([]string, error) {
                if err != nil {
                        return nil, fmt.Errorf("reading %v: %v", name, err)
                }
+               if info.parsed.Name.Name == "main" {
+                       continue
+               }
                if bytes.Contains(info.header, buildIgnore) {
                        continue
                }
index e16e186e0df9662ee420c51d2ad41eaced1f6a31..434991f66ef80163b2a467a59939ab2f9dbed88a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gc
-// +build gc
 
 package build
 
index c8ec7041fb3653cd71ce0799925851303fd50868..f806729f7e0e283f3e75ca89e251ab03f29a28ab 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gccgo
-// +build gccgo
 
 package build
 
index b98c7938a855993454b5e374ff99d9b9ebd04b95..6115ef810c786713bdc8c6696eaeccf9448c1436 100644 (file)
@@ -516,12 +516,12 @@ func parseGoEmbed(args string, pos token.Position) ([]fileEmbed, error) {
                        trimBytes(i)
 
                case '`':
-                       i := strings.Index(args[1:], "`")
-                       if i < 0 {
+                       var ok bool
+                       path, _, ok = strings.Cut(args[1:], "`")
+                       if !ok {
                                return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
                        }
-                       path = args[1 : 1+i]
-                       trimBytes(1 + i + 1)
+                       trimBytes(1 + len(path) + 1)
 
                case '"':
                        i := 1
index 1e5e1c2de2e6d110b539058fe64711c97547ee89..6851e6b6d6003eec431616fdf20ddf2968d6bf18 100644 (file)
@@ -119,20 +119,15 @@ var readCommentsTests = []readTest{
 
 func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
        for i, tt := range tests {
-               var in, testOut string
-               j := strings.Index(tt.in, "ℙ")
-               if j < 0 {
-                       in = tt.in
-                       testOut = tt.in
-               } else {
-                       in = tt.in[:j] + tt.in[j+len("ℙ"):]
-                       testOut = tt.in[:j]
-               }
-               d := strings.Index(tt.in, "𝔻")
-               if d >= 0 {
-                       in = in[:d] + in[d+len("𝔻"):]
-                       testOut = testOut[d+len("𝔻"):]
+               beforeP, afterP, _ := strings.Cut(tt.in, "ℙ")
+               in := beforeP + afterP
+               testOut := beforeP
+
+               if beforeD, afterD, ok := strings.Cut(beforeP, "𝔻"); ok {
+                       in = beforeD + afterD + afterP
+                       testOut = afterD
                }
+
                r := strings.NewReader(in)
                buf, err := read(r)
                if err != nil {
index 60ac5511bda72f1cbd1cb47f764300f87450298a..0f6e3369253ff2a84e6f5607ee3d4ef50f46d94f 100644 (file)
@@ -8,4 +8,4 @@ package build
 // Do not remove from this list, as these are used for go/build filename matching.
 
 const goosList = "aix android darwin dragonfly freebsd hurd illumos ios js linux nacl netbsd openbsd plan9 solaris windows zos "
-const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le loong64 mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "
+const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be loong64 mips mipsle mips64 mips64le mips64p32 mips64p32le ppc ppc64 ppc64le riscv riscv64 s390 s390x sparc sparc64 wasm "
index 91ad0b0c2b9d998a2a28feb2827d8b118cb56124..ac179b3d8c21028bb726bac4ba8cc8c4b53bafc5 100644 (file)
@@ -143,9 +143,9 @@ func testNumbers(t *testing.T, kind token.Token, tests []string) {
                if a[1] == "?" {
                        y = MakeUnknown()
                } else {
-                       if i := strings.Index(a[1], "/"); i >= 0 && kind == token.FLOAT {
-                               n := MakeFromLiteral(a[1][:i], token.INT, 0)
-                               d := MakeFromLiteral(a[1][i+1:], token.INT, 0)
+                       if ns, ds, ok := strings.Cut(a[1], "/"); ok && kind == token.FLOAT {
+                               n := MakeFromLiteral(ns, token.INT, 0)
+                               d := MakeFromLiteral(ds, token.INT, 0)
                                y = BinaryOp(n, token.QUO, d)
                        } else {
                                y = MakeFromLiteral(a[1], kind, 0)
@@ -454,10 +454,10 @@ func val(lit string) Value {
                return MakeBool(false)
        }
 
-       if i := strings.IndexByte(lit, '/'); i >= 0 {
+       if as, bs, ok := strings.Cut(lit, "/"); ok {
                // assume fraction
-               a := MakeFromLiteral(lit[:i], token.INT, 0)
-               b := MakeFromLiteral(lit[i+1:], token.INT, 0)
+               a := MakeFromLiteral(as, token.INT, 0)
+               b := MakeFromLiteral(bs, token.INT, 0)
                return BinaryOp(a, token.QUO, b)
        }
 
index 92131a3b83f02700cb4b48d21d2ed3947056c082..a93c05fbb7e315494f229b7014bd270fd9e1b4b2 100644 (file)
@@ -236,26 +236,24 @@ func heading(line string) string {
 
        // allow "'" for possessive "'s" only
        for b := line; ; {
-               i := strings.IndexRune(b, '\'')
-               if i < 0 {
+               var ok bool
+               if _, b, ok = strings.Cut(b, "'"); !ok {
                        break
                }
-               if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') {
-                       return "" // not followed by "s "
+               if b != "s" && !strings.HasPrefix(b, "s ") {
+                       return "" // ' not followed by s and then end-of-word
                }
-               b = b[i+2:]
        }
 
        // allow "." when followed by non-space
        for b := line; ; {
-               i := strings.IndexRune(b, '.')
-               if i < 0 {
+               var ok bool
+               if _, b, ok = strings.Cut(b, "."); !ok {
                        break
                }
-               if i+1 >= len(b) || b[i+1] == ' ' {
+               if b == "" || strings.HasPrefix(b, " ") {
                        return "" // not followed by non-space
                }
-               b = b[i+1:]
        }
 
        return line
index 274000cecb7a4b194193cbe2f87e7a1d5753f867..fbbd846354608c80b9eb247bd3f5cfeb33e3474e 100644 (file)
@@ -44,13 +44,13 @@ type Example struct {
 //     identifiers from other packages (or predeclared identifiers, such as
 //     "int") and the test file does not include a dot import.
 //   - The entire test file is the example: the file contains exactly one
-//     example function, zero test or benchmark functions, and at least one
-//     top-level function, type, variable, or constant declaration other
-//     than the example function.
+//     example function, zero test, fuzz target, or benchmark function, and at
+//     least one top-level function, type, variable, or constant declaration
+//     other than the example function.
 func Examples(testFiles ...*ast.File) []*Example {
        var list []*Example
        for _, file := range testFiles {
-               hasTests := false // file contains tests or benchmarks
+               hasTests := false // file contains tests, fuzz targets, or benchmarks
                numDecl := 0      // number of non-import declarations in the file
                var flist []*Example
                for _, decl := range file.Decls {
@@ -64,7 +64,7 @@ func Examples(testFiles ...*ast.File) []*Example {
                        }
                        numDecl++
                        name := f.Name.Name
-                       if isTest(name, "Test") || isTest(name, "Benchmark") {
+                       if isTest(name, "Test") || isTest(name, "Benchmark") || isTest(name, "Fuzz") {
                                hasTests = true
                                continue
                        }
@@ -133,9 +133,9 @@ func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output strin
        return "", false, false // no suitable comment found
 }
 
-// isTest tells whether name looks like a test, example, or benchmark.
-// It is a Test (say) if there is a character after Test that is not a
-// lower-case letter. (We don't want Testiness.)
+// isTest tells whether name looks like a test, example, fuzz target, or
+// benchmark. It is a Test (say) if there is a character after Test that is not
+// lower-case letter. (We don't want Testiness.)
 func isTest(name, prefix string) bool {
        if !strings.HasPrefix(name, prefix) {
                return false
index cf1b702549e5242e57d60e4998873c558d5fed72..21b71290f7d4e64ed0e9c9423932ea3e2c3d6eb6 100644 (file)
@@ -307,6 +307,9 @@ func (X) TestBlah() {
 func (X) BenchmarkFoo() {
 }
 
+func (X) FuzzFoo() {
+}
+
 func Example() {
        fmt.Println("Hello, world!")
        // Output: Hello, world!
@@ -326,6 +329,9 @@ func (X) TestBlah() {
 func (X) BenchmarkFoo() {
 }
 
+func (X) FuzzFoo() {
+}
+
 func main() {
        fmt.Println("Hello, world!")
 }
index 819c030c9bf51c9f7f36f50a20688df98bd04c14..671c622205b2d4d96127421a2cf7bb7b17d9784e 100644 (file)
@@ -79,18 +79,15 @@ func hasExportedName(list []*ast.Ident) bool {
        return false
 }
 
-// removeErrorField removes anonymous fields named "error" from an interface.
-// This is called when "error" has been determined to be a local name,
-// not the predeclared type.
-//
-func removeErrorField(ityp *ast.InterfaceType) {
+// removeAnonymousField removes anonymous fields named name from an interface.
+func removeAnonymousField(name string, ityp *ast.InterfaceType) {
        list := ityp.Methods.List // we know that ityp.Methods != nil
        j := 0
        for _, field := range list {
                keepField := true
                if n := len(field.Names); n == 0 {
                        // anonymous field
-                       if fname, _ := baseTypeName(field.Type); fname == "error" {
+                       if fname, _ := baseTypeName(field.Type); fname == name {
                                keepField = false
                        }
                }
@@ -119,16 +116,25 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp
        for _, field := range list {
                keepField := false
                if n := len(field.Names); n == 0 {
-                       // anonymous field
+                       // anonymous field or embedded type or union element
                        fname := r.recordAnonymousField(parent, field.Type)
-                       if token.IsExported(fname) {
-                               keepField = true
-                       } else if ityp != nil && fname == "error" {
-                               // possibly the predeclared error interface; keep
-                               // it for now but remember this interface so that
-                               // it can be fixed if error is also defined locally
-                               keepField = true
-                               r.remember(ityp)
+                       if fname != "" {
+                               if token.IsExported(fname) {
+                                       keepField = true
+                               } else if ityp != nil && predeclaredTypes[fname] {
+                                       // possibly an embedded predeclared type; keep it for now but
+                                       // remember this interface so that it can be fixed if name is also
+                                       // defined locally
+                                       keepField = true
+                                       r.remember(fname, ityp)
+                               }
+                       } else {
+                               // If we're operating on an interface, assume that this is an embedded
+                               // type or union element.
+                               //
+                               // TODO(rfindley): consider traversing into approximation/unions
+                               // elements to see if they are entirely unexported.
+                               keepField = ityp != nil
                        }
                } else {
                        field.Names = filterIdentList(field.Names)
@@ -172,6 +178,17 @@ func (r *reader) filterType(parent *namedType, typ ast.Expr) {
                // nothing to do
        case *ast.ParenExpr:
                r.filterType(nil, t.X)
+       case *ast.StarExpr: // possibly an embedded type literal
+               r.filterType(nil, t.X)
+       case *ast.UnaryExpr:
+               if t.Op == token.TILDE { // approximation element
+                       r.filterType(nil, t.X)
+               }
+       case *ast.BinaryExpr:
+               if t.Op == token.OR { // union
+                       r.filterType(nil, t.X)
+                       r.filterType(nil, t.Y)
+               }
        case *ast.ArrayType:
                r.filterType(nil, t.Elt)
        case *ast.StructType:
@@ -179,6 +196,7 @@ func (r *reader) filterType(parent *namedType, typ ast.Expr) {
                        t.Incomplete = true
                }
        case *ast.FuncType:
+               r.filterParamList(t.TypeParams)
                r.filterParamList(t.Params)
                r.filterParamList(t.Results)
        case *ast.InterfaceType:
@@ -219,12 +237,16 @@ func (r *reader) filterSpec(spec ast.Spec) bool {
                        }
                }
        case *ast.TypeSpec:
+               // Don't filter type parameters here, by analogy with function parameters
+               // which are not filtered for top-level function declarations.
                if name := s.Name.Name; token.IsExported(name) {
                        r.filterType(r.lookupType(s.Name.Name), s.Type)
                        return true
-               } else if name == "error" {
-                       // special case: remember that error is declared locally
-                       r.errorDecl = true
+               } else if IsPredeclared(name) {
+                       if r.shadowedPredecl == nil {
+                               r.shadowedPredecl = make(map[string]bool)
+                       }
+                       r.shadowedPredecl[name] = true
                }
        }
        return false
index a6f243f33e5825e07f99cef220b185a7ae19ebf8..9904da150e96ac4052794fb6c16124633a9160dc 100644 (file)
@@ -34,6 +34,8 @@ func matchDecl(d *ast.GenDecl, f Filter) bool {
                        if f(v.Name.Name) {
                                return true
                        }
+                       // We don't match ordinary parameters in filterFuncs, so by analogy don't
+                       // match type parameters here.
                        switch t := v.Type.(type) {
                        case *ast.StructType:
                                if matchFields(t.Fields, f) {
index 28cb84f91da8f0436684072703ad84c5ce231210..320895e43a4c576797a2ac53f7b1ca7be69cf170 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
        The headscan command extracts comment headings from package files;
@@ -23,10 +22,10 @@ import (
        "go/doc"
        "go/parser"
        "go/token"
-       "internal/lazyregexp"
        "io/fs"
        "os"
        "path/filepath"
+       "regexp"
        "runtime"
        "strings"
 )
@@ -37,7 +36,7 @@ var (
 )
 
 // ToHTML in comment.go assigns a (possibly blank) ID to each heading
-var html_h = lazyregexp.New(`<h3 id="[^"]*">`)
+var html_h = regexp.MustCompile(`<h3 id="[^"]*">`)
 
 const html_endh = "</h3>\n"
 
@@ -49,19 +48,14 @@ func isGoFile(fi fs.FileInfo) bool {
 func appendHeadings(list []string, comment string) []string {
        var buf bytes.Buffer
        doc.ToHTML(&buf, comment, nil)
-       for s := buf.String(); ; {
+       for s := buf.String(); s != ""; {
                loc := html_h.FindStringIndex(s)
                if len(loc) == 0 {
                        break
                }
-               i := loc[1]
-               j := strings.Index(s, html_endh)
-               if j < 0 {
-                       list = append(list, s[i:]) // incorrect HTML
-                       break
-               }
-               list = append(list, s[i:j])
-               s = s[j+len(html_endh):]
+               var inner string
+               inner, s, _ = strings.Cut(s[loc[1]:], html_endh)
+               list = append(list, inner)
        }
        return list
 }
index c277b35e89420acfe14bd95ee5a6af7393e91ded..348b9b59a02dd1ac9d46f39bd00e59d10a311fb2 100644 (file)
@@ -101,6 +101,10 @@ func baseTypeName(x ast.Expr) (name string, imported bool) {
        switch t := x.(type) {
        case *ast.Ident:
                return t.Name, false
+       case *ast.IndexExpr:
+               return baseTypeName(t.X)
+       case *ast.IndexListExpr:
+               return baseTypeName(t.X)
        case *ast.SelectorExpr:
                if _, ok := t.X.(*ast.Ident); ok {
                        // only possible for qualified type names;
@@ -112,7 +116,7 @@ func baseTypeName(x ast.Expr) (name string, imported bool) {
        case *ast.StarExpr:
                return baseTypeName(t.X)
        }
-       return
+       return "", false
 }
 
 // An embeddedSet describes a set of embedded types.
@@ -163,9 +167,9 @@ type reader struct {
        types     map[string]*namedType
        funcs     methodSet
 
-       // support for package-local error type declarations
-       errorDecl bool                 // if set, type "error" was declared locally
-       fixlist   []*ast.InterfaceType // list of interfaces containing anonymous field "error"
+       // support for package-local shadowing of predeclared types
+       shadowedPredecl map[string]bool
+       fixmap          map[string][]*ast.InterfaceType
 }
 
 func (r *reader) isVisible(name string) bool {
@@ -224,8 +228,11 @@ func (r *reader) readDoc(comment *ast.CommentGroup) {
        r.doc += "\n" + text
 }
 
-func (r *reader) remember(typ *ast.InterfaceType) {
-       r.fixlist = append(r.fixlist, typ)
+func (r *reader) remember(predecl string, typ *ast.InterfaceType) {
+       if r.fixmap == nil {
+               r.fixmap = make(map[string][]*ast.InterfaceType)
+       }
+       r.fixmap[predecl] = append(r.fixmap[predecl], typ)
 }
 
 func specNames(specs []ast.Spec) []string {
@@ -679,10 +686,11 @@ func (r *reader) computeMethodSets() {
                }
        }
 
-       // if error was declared locally, don't treat it as exported field anymore
-       if r.errorDecl {
-               for _, ityp := range r.fixlist {
-                       removeErrorField(ityp)
+       // For any predeclared names that are declared locally, don't treat them as
+       // exported fields anymore.
+       for predecl := range r.shadowedPredecl {
+               for _, ityp := range r.fixmap[predecl] {
+                       removeAnonymousField(predecl, ityp)
                }
        }
 }
@@ -869,6 +877,7 @@ func IsPredeclared(s string) bool {
 }
 
 var predeclaredTypes = map[string]bool{
+       "any":        true,
        "bool":       true,
        "byte":       true,
        "complex64":  true,
diff --git a/src/go/doc/testdata/generics.0.golden b/src/go/doc/testdata/generics.0.golden
new file mode 100644 (file)
index 0000000..a6dbcf6
--- /dev/null
@@ -0,0 +1,70 @@
+// Package generics contains the new syntax supporting generic ...
+PACKAGE generics
+
+IMPORTPATH
+       testdata/generics
+
+FILENAMES
+       testdata/generics.go
+
+FUNCTIONS
+       // AnotherFunc has an implicit constraint interface.  Neither type ...
+       func AnotherFunc[T ~struct{ f int }](_ struct{ f int })
+
+       // Func has an instantiated constraint. 
+       func Func[T Constraint[string, Type[int]]]()
+
+
+TYPES
+       // AFuncType demonstrates filtering of parameters and type ...
+       type AFuncType[T ~struct{ f int }] func(_ struct {
+               // contains filtered or unexported fields
+       })
+
+       // Constraint is a constraint interface with two type parameters. 
+       type Constraint[P, Q interface{ string | ~int | Type[int] }] interface {
+               ~int | ~byte | Type[string]
+               M() P
+       }
+
+       // NewEmbeddings demonstrates how we filter the new embedded ...
+       type NewEmbeddings interface {
+               string  // should not be filtered
+       
+               struct {
+                       // contains filtered or unexported fields
+               }
+               ~struct {
+                       // contains filtered or unexported fields
+               }
+               *struct {
+                       // contains filtered or unexported fields
+               }
+               struct {
+                       // contains filtered or unexported fields
+               } | ~struct {
+                       // contains filtered or unexported fields
+               }
+               // contains filtered or unexported methods
+       }
+
+       // Parameterized types should be shown. 
+       type Type[P any] struct {
+               Field P
+       }
+
+       // Variables with an instantiated type should be shown. 
+       var X Type[int]
+
+       // Constructors for parameterized types should be shown. 
+       func Constructor[lowerCase any]() Type[lowerCase]
+
+       // MethodA uses a different name for its receiver type parameter. 
+       func (t Type[A]) MethodA(p A)
+
+       // MethodB has a blank receiver type parameter. 
+       func (t Type[_]) MethodB()
+
+       // MethodC has a lower-case receiver type parameter. 
+       func (t Type[c]) MethodC()
+
diff --git a/src/go/doc/testdata/generics.1.golden b/src/go/doc/testdata/generics.1.golden
new file mode 100644 (file)
index 0000000..c0548b5
--- /dev/null
@@ -0,0 +1,60 @@
+// Package generics contains the new syntax supporting generic ...
+PACKAGE generics
+
+IMPORTPATH
+       testdata/generics
+
+FILENAMES
+       testdata/generics.go
+
+FUNCTIONS
+       // AnotherFunc has an implicit constraint interface.  Neither type ...
+       func AnotherFunc[T ~struct{ f int }](_ struct{ f int })
+
+       // Func has an instantiated constraint. 
+       func Func[T Constraint[string, Type[int]]]()
+
+
+TYPES
+       // AFuncType demonstrates filtering of parameters and type ...
+       type AFuncType[T ~struct{ f int }] func(_ struct{ f int })
+
+       // Constraint is a constraint interface with two type parameters. 
+       type Constraint[P, Q interface{ string | ~int | Type[int] }] interface {
+               ~int | ~byte | Type[string]
+               M() P
+       }
+
+       // NewEmbeddings demonstrates how we filter the new embedded ...
+       type NewEmbeddings interface {
+               string  // should not be filtered
+               int16
+               struct{ f int }
+               ~struct{ f int }
+               *struct{ f int }
+               struct{ f int } | ~struct{ f int }
+       }
+
+       // Parameterized types should be shown. 
+       type Type[P any] struct {
+               Field P
+       }
+
+       // Variables with an instantiated type should be shown. 
+       var X Type[int]
+
+       // Constructors for parameterized types should be shown. 
+       func Constructor[lowerCase any]() Type[lowerCase]
+
+       // MethodA uses a different name for its receiver type parameter. 
+       func (t Type[A]) MethodA(p A)
+
+       // MethodB has a blank receiver type parameter. 
+       func (t Type[_]) MethodB()
+
+       // MethodC has a lower-case receiver type parameter. 
+       func (t Type[c]) MethodC()
+
+       // int16 shadows the predeclared type int16. 
+       type int16 int
+
diff --git a/src/go/doc/testdata/generics.2.golden b/src/go/doc/testdata/generics.2.golden
new file mode 100644 (file)
index 0000000..a6dbcf6
--- /dev/null
@@ -0,0 +1,70 @@
+// Package generics contains the new syntax supporting generic ...
+PACKAGE generics
+
+IMPORTPATH
+       testdata/generics
+
+FILENAMES
+       testdata/generics.go
+
+FUNCTIONS
+       // AnotherFunc has an implicit constraint interface.  Neither type ...
+       func AnotherFunc[T ~struct{ f int }](_ struct{ f int })
+
+       // Func has an instantiated constraint. 
+       func Func[T Constraint[string, Type[int]]]()
+
+
+TYPES
+       // AFuncType demonstrates filtering of parameters and type ...
+       type AFuncType[T ~struct{ f int }] func(_ struct {
+               // contains filtered or unexported fields
+       })
+
+       // Constraint is a constraint interface with two type parameters. 
+       type Constraint[P, Q interface{ string | ~int | Type[int] }] interface {
+               ~int | ~byte | Type[string]
+               M() P
+       }
+
+       // NewEmbeddings demonstrates how we filter the new embedded ...
+       type NewEmbeddings interface {
+               string  // should not be filtered
+       
+               struct {
+                       // contains filtered or unexported fields
+               }
+               ~struct {
+                       // contains filtered or unexported fields
+               }
+               *struct {
+                       // contains filtered or unexported fields
+               }
+               struct {
+                       // contains filtered or unexported fields
+               } | ~struct {
+                       // contains filtered or unexported fields
+               }
+               // contains filtered or unexported methods
+       }
+
+       // Parameterized types should be shown. 
+       type Type[P any] struct {
+               Field P
+       }
+
+       // Variables with an instantiated type should be shown. 
+       var X Type[int]
+
+       // Constructors for parameterized types should be shown. 
+       func Constructor[lowerCase any]() Type[lowerCase]
+
+       // MethodA uses a different name for its receiver type parameter. 
+       func (t Type[A]) MethodA(p A)
+
+       // MethodB has a blank receiver type parameter. 
+       func (t Type[_]) MethodB()
+
+       // MethodC has a lower-case receiver type parameter. 
+       func (t Type[c]) MethodC()
+
diff --git a/src/go/doc/testdata/generics.go b/src/go/doc/testdata/generics.go
new file mode 100644 (file)
index 0000000..b5debba
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2021 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 generics contains the new syntax supporting generic programming in
+// Go.
+package generics
+
+// Variables with an instantiated type should be shown.
+var X Type[int]
+
+// Parameterized types should be shown.
+type Type[P any] struct {
+       Field P
+}
+
+// Constructors for parameterized types should be shown.
+func Constructor[lowerCase any]() Type[lowerCase] {
+       return Type[lowerCase]{}
+}
+
+// MethodA uses a different name for its receiver type parameter.
+func (t Type[A]) MethodA(p A) {}
+
+// MethodB has a blank receiver type parameter.
+func (t Type[_]) MethodB() {}
+
+// MethodC has a lower-case receiver type parameter.
+func (t Type[c]) MethodC() {}
+
+// Constraint is a constraint interface with two type parameters.
+type Constraint[P, Q interface{ string | ~int | Type[int] }] interface {
+       ~int | ~byte | Type[string]
+       M() P
+}
+
+// int16 shadows the predeclared type int16.
+type int16 int
+
+// NewEmbeddings demonstrates how we filter the new embedded elements.
+type NewEmbeddings interface {
+       string // should not be filtered
+       int16
+       struct{ f int }
+       ~struct{ f int }
+       *struct{ f int }
+       struct{ f int } | ~struct{ f int }
+}
+
+// Func has an instantiated constraint.
+func Func[T Constraint[string, Type[int]]]() {}
+
+// AnotherFunc has an implicit constraint interface.
+//
+// Neither type parameters nor regular parameters should be filtered.
+func AnotherFunc[T ~struct{ f int }](_ struct{ f int }) {}
+
+// AFuncType demonstrates filtering of parameters and type parameters. Here we
+// don't filter type parameters (to be consistent with function declarations),
+// but DO filter the RHS.
+type AFuncType[T ~struct{ f int }] func(_ struct{ f int })
index 0f5121d80212bd57e9f18ad94f995a69a1cf733d..27c4aa787173d82e2027a812493a70a06d02e32c 100644 (file)
@@ -24,8 +24,7 @@ func TestForCompiler(t *testing.T) {
                t.Fatalf("go list %s: %v\n%s", thePackage, err, out)
        }
        target := strings.TrimSpace(string(out))
-       i := strings.Index(target, ":")
-       compiler, target := target[:i], target[i+1:]
+       compiler, target, _ := strings.Cut(target, ":")
        if !strings.HasSuffix(target, ".a") {
                t.Fatalf("unexpected package %s target %q (not *.a)", thePackage, target)
        }
index 1b1d07d3f6ed57da2ccbc9edd570064f5be7d101..267c9953e49a8a3132bdac85660dccc48f7d16c1 100644 (file)
@@ -599,7 +599,7 @@ func (p *parser) parseNamedType(nlist []interface{}) types.Type {
                        p.skipInlineBody()
                        p.expectEOL()
 
-                       sig := types.NewSignature(receiver, params, results, isVariadic)
+                       sig := types.NewSignatureType(receiver, nil, nil, params, results, isVariadic)
                        nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
                }
        }
@@ -766,7 +766,7 @@ func (p *parser) parseFunctionType(pkg *types.Package, nlist []interface{}) *typ
        params, isVariadic := p.parseParamList(pkg)
        results := p.parseResultList(pkg)
 
-       *t = *types.NewSignature(nil, params, results, isVariadic)
+       *t = *types.NewSignatureType(nil, nil, nil, params, results, isVariadic)
        return t
 }
 
index 1db81562c1d74a34f1739fd1bf1ac5dd269502d8..94ce0393fc0353bc2647ff1e3babc16c50d848cb 100644 (file)
Binary files a/src/go/internal/gccgoimporter/testdata/escapeinfo.gox and b/src/go/internal/gccgoimporter/testdata/escapeinfo.gox differ
index 80c2dbcb472813d114032c583c85134a8f340590..a6822ea19859bef114e34b24b05ddca7c8966833 100644 (file)
Binary files a/src/go/internal/gccgoimporter/testdata/time.gox and b/src/go/internal/gccgoimporter/testdata/time.gox differ
index e70e539655e9f00af598bffa62f987c77cd96009..ae1a6f758b4d807567569126b1fe2df57a3152cb 100644 (file)
Binary files a/src/go/internal/gccgoimporter/testdata/unicode.gox and b/src/go/internal/gccgoimporter/testdata/unicode.gox differ
index ea468414d9fa8ad66e978799a8ff5d2f90eb4961..d693fe631b53ee3ac530c76d6ce35782421db9a0 100644 (file)
Binary files a/src/go/internal/gccgoimporter/testdata/v1reflect.gox and b/src/go/internal/gccgoimporter/testdata/v1reflect.gox differ
index 286b8a63471e6851dd14d06dc8650e859adf881c..3a9ed79df6b454232d967d5cfebde0bb80a42902 100644 (file)
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gcimporter
+package gcimporter_test
 
 import (
        "bytes"
        "fmt"
+       "internal/goexperiment"
        "internal/testenv"
        "os"
        "os/exec"
@@ -16,8 +17,13 @@ import (
        "testing"
        "time"
 
+       "go/ast"
+       "go/importer"
+       "go/parser"
        "go/token"
        "go/types"
+
+       . "go/internal/gcimporter"
 )
 
 // skipSpecialPlatforms causes the test to be skipped for platforms where
@@ -63,6 +69,8 @@ func testPath(t *testing.T, path, srcDir string) *types.Package {
 
 const maxTime = 30 * time.Second
 
+var pkgExts = [...]string{".a", ".o"} // keep in sync with gcimporter.go
+
 func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
        dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
        list, err := os.ReadDir(dirname)
@@ -134,11 +142,130 @@ func TestImportTestdata(t *testing.T) {
        }
 }
 
+func TestImportTypeparamTests(t *testing.T) {
+       // This test doesn't yet work with the unified export format.
+       if goexperiment.Unified {
+               t.Skip("unified export data format is currently unsupported")
+       }
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       tmpdir := mktmpdir(t)
+       defer os.RemoveAll(tmpdir)
+
+       // Check go files in test/typeparam, except those that fail for a known
+       // reason.
+       rootDir := filepath.Join(runtime.GOROOT(), "test", "typeparam")
+       list, err := os.ReadDir(rootDir)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       skip := map[string]string{
+               "equal.go":  "inconsistent embedded sorting", // TODO(rfindley): investigate this.
+               "nested.go": "fails to compile",              // TODO(rfindley): investigate this.
+       }
+
+       for _, entry := range list {
+               if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
+                       // For now, only consider standalone go files.
+                       continue
+               }
+
+               t.Run(entry.Name(), func(t *testing.T) {
+                       if reason, ok := skip[entry.Name()]; ok {
+                               t.Skip(reason)
+                       }
+
+                       filename := filepath.Join(rootDir, entry.Name())
+                       src, err := os.ReadFile(filename)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) {
+                               // We're bypassing the logic of run.go here, so be conservative about
+                               // the files we consider in an attempt to make this test more robust to
+                               // changes in test/typeparams.
+                               t.Skipf("not detected as a run test")
+                       }
+
+                       // Compile and import, and compare the resulting package with the package
+                       // that was type-checked directly.
+                       compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"))
+                       pkgName := strings.TrimSuffix(entry.Name(), ".go")
+                       imported := importPkg(t, "./testdata/"+pkgName, tmpdir)
+                       checked := checkFile(t, filename, src)
+
+                       seen := make(map[string]bool)
+                       for _, name := range imported.Scope().Names() {
+                               if !token.IsExported(name) {
+                                       continue // ignore synthetic names like .inittask and .dict.*
+                               }
+                               seen[name] = true
+
+                               importedObj := imported.Scope().Lookup(name)
+                               got := types.ObjectString(importedObj, types.RelativeTo(imported))
+                               got = sanitizeObjectString(got)
+
+                               checkedObj := checked.Scope().Lookup(name)
+                               if checkedObj == nil {
+                                       t.Fatalf("imported object %q was not type-checked", name)
+                               }
+                               want := types.ObjectString(checkedObj, types.RelativeTo(checked))
+                               want = sanitizeObjectString(want)
+
+                               if got != want {
+                                       t.Errorf("imported %q as %q, want %q", name, got, want)
+                               }
+                       }
+
+                       for _, name := range checked.Scope().Names() {
+                               if !token.IsExported(name) || seen[name] {
+                                       continue
+                               }
+                               t.Errorf("did not import object %q", name)
+                       }
+               })
+       }
+}
+
+// sanitizeObjectString removes type parameter debugging markers from an object
+// string, to normalize it for comparison.
+// TODO(rfindley): this should not be necessary.
+func sanitizeObjectString(s string) string {
+       var runes []rune
+       for _, r := range s {
+               if '₀' <= r && r < '₀'+10 {
+                       continue // trim type parameter subscripts
+               }
+               runes = append(runes, r)
+       }
+       return string(runes)
+}
+
+func checkFile(t *testing.T, filename string, src []byte) *types.Package {
+       fset := token.NewFileSet()
+       f, err := parser.ParseFile(fset, filename, src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+       config := types.Config{
+               Importer: importer.Default(),
+       }
+       pkg, err := config.Check("", fset, []*ast.File{f}, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return pkg
+}
+
 func TestVersionHandling(t *testing.T) {
        skipSpecialPlatforms(t)
 
        // This package only handles gc export data.
-       // Disable test until we put in the new export version.
        if runtime.Compiler != "gc" {
                t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
        }
index dbc9b3a83e8ddeccec4a6c4687779536293b4a15..49ea64392a578de274eb1c249c625f3f8f74247f 100644 (file)
@@ -18,6 +18,7 @@ import (
        "io"
        "math/big"
        "sort"
+       "strings"
 )
 
 type intReader struct {
@@ -43,14 +44,19 @@ func (r *intReader) uint64() uint64 {
 
 // Keep this in sync with constants in iexport.go.
 const (
-       iexportVersionGo1_11 = 0
-       iexportVersionPosCol = 1
-       // TODO: before release, change this back to 2.
-       iexportVersionGenerics = iexportVersionPosCol
+       iexportVersionGo1_11   = 0
+       iexportVersionPosCol   = 1
+       iexportVersionGenerics = 1 // probably change to 2 before release
+       iexportVersionGo1_18   = 2
 
-       iexportVersionCurrent = iexportVersionGenerics
+       iexportVersionCurrent = 2
 )
 
+type ident struct {
+       pkg  string
+       name string
+}
+
 const predeclReserved = 32
 
 type itag uint64
@@ -67,7 +73,8 @@ const (
        structType
        interfaceType
        typeParamType
-       instType
+       instanceType
+       unionType
 )
 
 // iImportData imports a package from the serialized package data
@@ -91,13 +98,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea
 
        version = int64(r.uint64())
        switch version {
-       case /* iexportVersionGenerics, */ iexportVersionPosCol, iexportVersionGo1_11:
+       case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
        default:
-               if version > iexportVersionGenerics {
-                       errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
-               } else {
-                       errorf("unknown iexport format version %d", version)
-               }
+               errorf("unknown iexport format version %d", version)
        }
 
        sLen := int64(r.uint64())
@@ -122,12 +125,16 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea
                declData: declData,
                pkgIndex: make(map[*types.Package]map[string]uint64),
                typCache: make(map[uint64]types.Type),
+               // Separate map for typeparams, keyed by their package and unique
+               // name (name with subscript).
+               tparamIndex: make(map[ident]types.Type),
 
                fake: fakeFileSet{
                        fset:  fset,
-                       files: make(map[string]*token.File),
+                       files: make(map[string]*fileInfo),
                },
        }
+       defer p.fake.setLines() // set lines for files in fset
 
        for i, pt := range predeclared {
                p.typCache[uint64(i)] = pt
@@ -197,9 +204,10 @@ type iimporter struct {
        stringCache map[uint64]string
        pkgCache    map[uint64]*types.Package
 
-       declData []byte
-       pkgIndex map[*types.Package]map[string]uint64
-       typCache map[uint64]types.Type
+       declData    []byte
+       pkgIndex    map[*types.Package]map[string]uint64
+       typCache    map[uint64]types.Type
+       tparamIndex map[ident]types.Type
 
        fake          fakeFileSet
        interfaceList []*types.Interface
@@ -289,20 +297,26 @@ func (r *importReader) obj(name string) {
 
                r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
 
-       case 'F':
-               sig := r.signature(nil)
-
+       case 'F', 'G':
+               var tparams []*types.TypeParam
+               if tag == 'G' {
+                       tparams = r.tparamList()
+               }
+               sig := r.signature(nil, nil, tparams)
                r.declare(types.NewFunc(pos, r.currPkg, name, sig))
 
-       case 'G':
-               errorf("unexpected parameterized function/method")
-
-       case 'T':
+       case 'T', 'U':
                // Types can be recursive. We need to setup a stub
                // declaration before recursing.
                obj := types.NewTypeName(pos, r.currPkg, name, nil)
                named := types.NewNamed(obj, nil, nil)
+               // Declare obj before calling r.tparamList, so the new type name is recognized
+               // if used in the constraint of one of its own typeparams (see #48280).
                r.declare(obj)
+               if tag == 'U' {
+                       tparams := r.tparamList()
+                       named.SetTypeParams(tparams)
+               }
 
                underlying := r.p.typAt(r.uint64(), named).Underlying()
                named.SetUnderlying(underlying)
@@ -312,14 +326,56 @@ func (r *importReader) obj(name string) {
                                mpos := r.pos()
                                mname := r.ident()
                                recv := r.param()
-                               msig := r.signature(recv)
+
+                               // If the receiver has any targs, set those as the
+                               // rparams of the method (since those are the
+                               // typeparams being used in the method sig/body).
+                               targs := baseType(recv.Type()).TypeArgs()
+                               var rparams []*types.TypeParam
+                               if targs.Len() > 0 {
+                                       rparams = make([]*types.TypeParam, targs.Len())
+                                       for i := range rparams {
+                                               rparams[i], _ = targs.At(i).(*types.TypeParam)
+                                       }
+                               }
+                               msig := r.signature(recv, rparams, nil)
 
                                named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
                        }
                }
 
-       case 'U':
-               errorf("unexpected parameterized type")
+       case 'P':
+               // We need to "declare" a typeparam in order to have a name that
+               // can be referenced recursively (if needed) in the type param's
+               // bound.
+               if r.p.exportVersion < iexportVersionGenerics {
+                       errorf("unexpected type param type")
+               }
+               // Remove the "path" from the type param name that makes it unique
+               ix := strings.LastIndex(name, ".")
+               if ix < 0 {
+                       errorf("missing path for type param")
+               }
+               tn := types.NewTypeName(pos, r.currPkg, name[ix+1:], nil)
+               t := types.NewTypeParam(tn, nil)
+               // To handle recursive references to the typeparam within its
+               // bound, save the partial type in tparamIndex before reading the bounds.
+               id := ident{r.currPkg.Name(), name}
+               r.p.tparamIndex[id] = t
+
+               var implicit bool
+               if r.p.exportVersion >= iexportVersionGo1_18 {
+                       implicit = r.bool()
+               }
+               constraint := r.typ()
+               if implicit {
+                       iface, _ := constraint.(*types.Interface)
+                       if iface == nil {
+                               errorf("non-interface constraint marked implicit")
+                       }
+                       iface.MarkImplicit()
+               }
+               t.SetConstraint(constraint)
 
        case 'V':
                typ := r.typ()
@@ -337,6 +393,10 @@ func (r *importReader) declare(obj types.Object) {
 
 func (r *importReader) value() (typ types.Type, val constant.Value) {
        typ = r.typ()
+       if r.p.exportVersion >= iexportVersionGo1_18 {
+               // TODO: add support for using the kind
+               _ = constant.Kind(r.int64())
+       }
 
        switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
        case types.IsBoolean:
@@ -526,7 +586,7 @@ func (r *importReader) doType(base *types.Named) types.Type {
                return types.NewMap(r.typ(), r.typ())
        case signatureType:
                r.currPkg = r.pkg()
-               return r.signature(nil)
+               return r.signature(nil, nil, nil)
 
        case structType:
                r.currPkg = r.pkg()
@@ -566,7 +626,7 @@ func (r *importReader) doType(base *types.Named) types.Type {
                                recv = types.NewVar(token.NoPos, r.currPkg, "", base)
                        }
 
-                       msig := r.signature(recv)
+                       msig := r.signature(recv, nil, nil)
                        methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
                }
 
@@ -575,12 +635,47 @@ func (r *importReader) doType(base *types.Named) types.Type {
                return typ
 
        case typeParamType:
-               errorf("do not handle type param types yet")
-               return nil
+               if r.p.exportVersion < iexportVersionGenerics {
+                       errorf("unexpected type param type")
+               }
+               pkg, name := r.qualifiedIdent()
+               id := ident{pkg.Name(), name}
+               if t, ok := r.p.tparamIndex[id]; ok {
+                       // We're already in the process of importing this typeparam.
+                       return t
+               }
+               // Otherwise, import the definition of the typeparam now.
+               r.p.doDecl(pkg, name)
+               return r.p.tparamIndex[id]
 
-       case instType:
-               errorf("do not handle instantiated types yet")
-               return nil
+       case instanceType:
+               if r.p.exportVersion < iexportVersionGenerics {
+                       errorf("unexpected instantiation type")
+               }
+               // pos does not matter for instances: they are positioned on the original
+               // type.
+               _ = r.pos()
+               len := r.uint64()
+               targs := make([]types.Type, len)
+               for i := range targs {
+                       targs[i] = r.typ()
+               }
+               baseType := r.typ()
+               // The imported instantiated type doesn't include any methods, so
+               // we must always use the methods of the base (orig) type.
+               // TODO provide a non-nil *Context
+               t, _ := types.Instantiate(nil, baseType, targs, false)
+               return t
+
+       case unionType:
+               if r.p.exportVersion < iexportVersionGenerics {
+                       errorf("unexpected instantiation type")
+               }
+               terms := make([]*types.Term, r.uint64())
+               for i := range terms {
+                       terms[i] = types.NewTerm(r.bool(), r.typ())
+               }
+               return types.NewUnion(terms)
        }
 }
 
@@ -588,11 +683,23 @@ func (r *importReader) kind() itag {
        return itag(r.uint64())
 }
 
-func (r *importReader) signature(recv *types.Var) *types.Signature {
+func (r *importReader) signature(recv *types.Var, rparams, tparams []*types.TypeParam) *types.Signature {
        params := r.paramList()
        results := r.paramList()
        variadic := params.Len() > 0 && r.bool()
-       return types.NewSignature(recv, params, results, variadic)
+       return types.NewSignatureType(recv, rparams, tparams, params, results, variadic)
+}
+
+func (r *importReader) tparamList() []*types.TypeParam {
+       n := r.uint64()
+       if n == 0 {
+               return nil
+       }
+       xs := make([]*types.TypeParam, n)
+       for i := range xs {
+               xs[i], _ = r.typ().(*types.TypeParam)
+       }
+       return xs
 }
 
 func (r *importReader) paramList() *types.Tuple {
@@ -637,3 +744,13 @@ func (r *importReader) byte() byte {
        }
        return x
 }
+
+func baseType(typ types.Type) *types.Named {
+       // pointer receivers are never types.Named types
+       if p, _ := typ.(*types.Pointer); p != nil {
+               typ = p.Elem()
+       }
+       // receiver base types are always (possibly generic) types.Named types
+       n, _ := typ.(*types.Named)
+       return n
+}
index 09810dd85b8b5949550b729debdbc5e7f04690cf..5aef63ec1e4fc2b4227512492765f8ddda167370 100644 (file)
@@ -25,37 +25,50 @@ const deltaNewFile = -64
 // Synthesize a token.Pos
 type fakeFileSet struct {
        fset  *token.FileSet
-       files map[string]*token.File
+       files map[string]*fileInfo
 }
 
+type fileInfo struct {
+       file     *token.File
+       lastline int
+}
+
+const maxlines = 64 * 1024
+
 func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
        // TODO(mdempsky): Make use of column.
 
-       // Since we don't know the set of needed file positions, we
-       // reserve maxlines positions per file.
-       const maxlines = 64 * 1024
+       // Since we don't know the set of needed file positions, we reserve
+       // maxlines positions per file. We delay calling token.File.SetLines until
+       // all positions have been calculated (by way of fakeFileSet.setLines), so
+       // that we can avoid setting unnecessary lines. See also golang/go#46586.
        f := s.files[file]
        if f == nil {
-               f = s.fset.AddFile(file, -1, maxlines)
+               f = &fileInfo{file: s.fset.AddFile(file, -1, maxlines)}
                s.files[file] = f
-               // Allocate the fake linebreak indices on first use.
-               // TODO(adonovan): opt: save ~512KB using a more complex scheme?
-               fakeLinesOnce.Do(func() {
-                       fakeLines = make([]int, maxlines)
-                       for i := range fakeLines {
-                               fakeLines[i] = i
-                       }
-               })
-               f.SetLines(fakeLines)
        }
 
        if line > maxlines {
                line = 1
        }
+       if line > f.lastline {
+               f.lastline = line
+       }
 
-       // Treat the file as if it contained only newlines
-       // and column=1: use the line number as the offset.
-       return f.Pos(line - 1)
+       // Return a fake position assuming that f.file consists only of newlines.
+       return token.Pos(f.file.Base() + line - 1)
+}
+
+func (s *fakeFileSet) setLines() {
+       fakeLinesOnce.Do(func() {
+               fakeLines = make([]int, maxlines)
+               for i := range fakeLines {
+                       fakeLines[i] = i
+               }
+       })
+       for _, f := range s.files {
+               f.file.SetLines(fakeLines[:f.lastline])
+       }
 }
 
 var (
index 47b8f7cf02f30dc9d09f4d10bfab082ddd4f1b17..9b82e6061a5509e161ddde04ce0f2b969b6d2ba3 100644 (file)
@@ -7,7 +7,9 @@
 // constraint.
 package typeparams
 
-// DisallowParsing is the numeric value of a parsing mode that disallows type
-// parameters. This only matters if the typeparams experiment is active, and
-// may be used for running tests that disallow generics.
-const DisallowParsing = 1 << 30
+// 'Hidden' parser modes to control the parsing of type-parameter related
+// features.
+const (
+       DisallowTypeSets = 1 << 29 // Disallow eliding 'interface' in constraint type sets.
+       DisallowParsing  = 1 << 30 // Disallow type parameters entirely.
+)
index 3191654d4f8607ef48b5c7c682336ee6ac50137c..3f84f2f0d05afd28b9d10b8b146e09deee2ef505 100644 (file)
@@ -5,7 +5,6 @@
 package typeparams
 
 import (
-       "fmt"
        "go/ast"
        "go/token"
 )
@@ -22,7 +21,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.
                        Rbrack: rbrack,
                }
        default:
-               return &ast.MultiIndexExpr{
+               return &ast.IndexListExpr{
                        X:       x,
                        Lbrack:  lbrack,
                        Indices: exprs,
@@ -31,48 +30,25 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.
        }
 }
 
-// IndexExpr wraps an ast.IndexExpr or ast.MultiIndexExpr into the
-// MultiIndexExpr interface.
+// IndexExpr wraps an ast.IndexExpr or ast.IndexListExpr.
 //
 // Orig holds the original ast.Expr from which this IndexExpr was derived.
 type IndexExpr struct {
-       Orig ast.Expr // the wrapped expr, which may be distinct from MultiIndexExpr below.
-       *ast.MultiIndexExpr
+       Orig ast.Expr // the wrapped expr, which may be distinct from the IndexListExpr below.
+       *ast.IndexListExpr
 }
 
 func UnpackIndexExpr(n ast.Node) *IndexExpr {
        switch e := n.(type) {
        case *ast.IndexExpr:
-               return &IndexExpr{e, &ast.MultiIndexExpr{
+               return &IndexExpr{e, &ast.IndexListExpr{
                        X:       e.X,
                        Lbrack:  e.Lbrack,
                        Indices: []ast.Expr{e.Index},
                        Rbrack:  e.Rbrack,
                }}
-       case *ast.MultiIndexExpr:
+       case *ast.IndexListExpr:
                return &IndexExpr{e, e}
        }
        return nil
 }
-
-func Get(n ast.Node) *ast.FieldList {
-       switch n := n.(type) {
-       case *ast.TypeSpec:
-               return n.TParams
-       case *ast.FuncType:
-               return n.TParams
-       default:
-               panic(fmt.Sprintf("node type %T has no type parameters", n))
-       }
-}
-
-func Set(n ast.Node, params *ast.FieldList) {
-       switch n := n.(type) {
-       case *ast.TypeSpec:
-               n.TParams = params
-       case *ast.FuncType:
-               n.TParams = params
-       default:
-               panic(fmt.Sprintf("node type %T has no type parameters", n))
-       }
-}
index f35ba0b50173c9b8fcd8f2d8f7c52f20c503510e..a45c897da364045d57ca5741e5f3bf9031b4b609 100644 (file)
@@ -23,6 +23,7 @@
 package parser
 
 import (
+       "flag"
        "go/internal/typeparams"
        "go/scanner"
        "go/token"
@@ -33,6 +34,8 @@ import (
        "testing"
 )
 
+var traceErrs = flag.Bool("trace_errs", false, "whether to enable tracing for error tests")
+
 const testdata = "testdata"
 
 // getFile assumes that each filename occurs at most once
@@ -192,6 +195,9 @@ func TestErrors(t *testing.T) {
                                if !strings.HasSuffix(name, ".go2") {
                                        mode |= typeparams.DisallowParsing
                                }
+                               if *traceErrs {
+                                       mode |= Trace
+                               }
                                checkErrors(t, filepath.Join(testdata, name), nil, mode, true)
                        }
                })
index bdc2ad308c862084f43ed18c96a65f955d64978a..8952a2bc2972e270bd725e34456a3a1e2c76bb9e 100644 (file)
@@ -76,9 +76,8 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mod
        p.next()
 }
 
-func (p *parser) parseTypeParams() bool {
-       return p.mode&typeparams.DisallowParsing == 0
-}
+func (p *parser) allowGenerics() bool { return p.mode&typeparams.DisallowParsing == 0 }
+func (p *parser) allowTypeSets() bool { return p.mode&typeparams.DisallowTypeSets == 0 }
 
 // ----------------------------------------------------------------------------
 // Parsing support
@@ -499,7 +498,7 @@ func (p *parser) parseQualifiedIdent(ident *ast.Ident) ast.Expr {
        }
 
        typ := p.parseTypeName(ident)
-       if p.tok == token.LBRACK && p.parseTypeParams() {
+       if p.tok == token.LBRACK && p.allowGenerics() {
                typ = p.parseTypeInstance(typ)
        }
 
@@ -526,23 +525,27 @@ func (p *parser) parseTypeName(ident *ast.Ident) ast.Expr {
        return ident
 }
 
-func (p *parser) parseArrayLen() ast.Expr {
+// "[" has already been consumed, and lbrack is its position.
+// If len != nil it is the already consumed array length.
+func (p *parser) parseArrayType(lbrack token.Pos, len ast.Expr) *ast.ArrayType {
        if p.trace {
-               defer un(trace(p, "ArrayLen"))
+               defer un(trace(p, "ArrayType"))
        }
 
-       p.exprLev++
-       var len ast.Expr
-       // always permit ellipsis for more fault-tolerant parsing
-       if p.tok == token.ELLIPSIS {
-               len = &ast.Ellipsis{Ellipsis: p.pos}
-               p.next()
-       } else if p.tok != token.RBRACK {
-               len = p.parseRhs()
+       if len == nil {
+               p.exprLev++
+               // always permit ellipsis for more fault-tolerant parsing
+               if p.tok == token.ELLIPSIS {
+                       len = &ast.Ellipsis{Ellipsis: p.pos}
+                       p.next()
+               } else if p.tok != token.RBRACK {
+                       len = p.parseRhs()
+               }
+               p.exprLev--
        }
-       p.exprLev--
-
-       return len
+       p.expect(token.RBRACK)
+       elt := p.parseType()
+       return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}
 }
 
 func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Expr) {
@@ -558,7 +561,7 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
        // TODO(rfindley): consider changing parseRhsOrType so that this function variable
        // is not needed.
        argparser := p.parseRhsOrType
-       if !p.parseTypeParams() {
+       if !p.allowGenerics() {
                argparser = p.parseRhs
        }
        if p.tok != token.RBRACK {
@@ -588,13 +591,13 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
                        // x [P]E
                        return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt}
                }
-               if !p.parseTypeParams() {
+               if !p.allowGenerics() {
                        p.error(rbrack, "missing element type in array type expression")
                        return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()}
                }
        }
 
-       if !p.parseTypeParams() {
+       if !p.allowGenerics() {
                p.error(firstComma, "expected ']', found ','")
                return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
        }
@@ -711,8 +714,9 @@ type field struct {
        typ  ast.Expr
 }
 
-func (p *parser) parseParamDecl(name *ast.Ident) (f field) {
-       // TODO(rFindley) compare with parser.paramDeclOrNil in the syntax package
+func (p *parser) parseParamDecl(name *ast.Ident, typeSetsOK bool) (f field) {
+       // TODO(rFindley) refactor to be more similar to paramDeclOrNil in the syntax
+       // package
        if p.trace {
                defer un(trace(p, "ParamDeclOrNil"))
        }
@@ -720,10 +724,14 @@ func (p *parser) parseParamDecl(name *ast.Ident) (f field) {
        ptok := p.tok
        if name != nil {
                p.tok = token.IDENT // force token.IDENT case in switch below
+       } else if typeSetsOK && p.tok == token.TILDE {
+               // "~" ...
+               return field{nil, p.embeddedElem(nil)}
        }
 
        switch p.tok {
        case token.IDENT:
+               // name
                if name != nil {
                        f.name = name
                        p.tok = ptok
@@ -736,17 +744,32 @@ func (p *parser) parseParamDecl(name *ast.Ident) (f field) {
                        f.typ = p.parseType()
 
                case token.LBRACK:
-                       // name[type1, type2, ...] or name []type or name [len]type
+                       // name "[" type1, ..., typeN "]" or name "[" n "]" type
                        f.name, f.typ = p.parseArrayFieldOrTypeInstance(f.name)
 
                case token.ELLIPSIS:
-                       // name ...type
+                       // name "..." type
                        f.typ = p.parseDotsType()
+                       return // don't allow ...type "|" ...
 
                case token.PERIOD:
-                       // qualified.typename
+                       // name "." ...
                        f.typ = p.parseQualifiedIdent(f.name)
                        f.name = nil
+
+               case token.TILDE:
+                       if typeSetsOK {
+                               f.typ = p.embeddedElem(nil)
+                               return
+                       }
+
+               case token.OR:
+                       if typeSetsOK {
+                               // name "|" typeset
+                               f.typ = p.embeddedElem(f.name)
+                               f.name = nil
+                               return
+                       }
                }
 
        case token.MUL, token.ARROW, token.FUNC, token.LBRACK, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN:
@@ -754,23 +777,36 @@ func (p *parser) parseParamDecl(name *ast.Ident) (f field) {
                f.typ = p.parseType()
 
        case token.ELLIPSIS:
-               // ...type
+               // "..." type
                // (always accepted)
                f.typ = p.parseDotsType()
+               return // don't allow ...type "|" ...
 
        default:
+               // TODO(rfindley): this looks incorrect in the case of type parameter
+               // lists.
                p.errorExpected(p.pos, ")")
                p.advance(exprEnd)
        }
 
+       // [name] type "|"
+       if typeSetsOK && p.tok == token.OR && f.typ != nil {
+               f.typ = p.embeddedElem(f.typ)
+       }
+
        return
 }
 
-func (p *parser) parseParameterList(name0 *ast.Ident, closing token.Token, parseParamDecl func(*ast.Ident) field, tparams bool) (params []*ast.Field) {
+func (p *parser) parseParameterList(name0 *ast.Ident, closing token.Token) (params []*ast.Field) {
        if p.trace {
                defer un(trace(p, "ParameterList"))
        }
 
+       // Type parameters are the only parameter list closed by ']'.
+       tparams := closing == token.RBRACK
+       // Type set notation is ok in type parameter lists.
+       typeSetsOK := tparams && p.allowTypeSets()
+
        pos := p.pos
        if name0 != nil {
                pos = name0.Pos()
@@ -780,7 +816,7 @@ func (p *parser) parseParameterList(name0 *ast.Ident, closing token.Token, parse
        var named int // number of parameters that have an explicit name and type
 
        for name0 != nil || p.tok != closing && p.tok != token.EOF {
-               par := parseParamDecl(name0)
+               par := p.parseParamDecl(name0, typeSetsOK)
                name0 = nil // 1st name was consumed if present
                if par.name != nil || par.typ != nil {
                        list = append(list, par)
@@ -818,11 +854,13 @@ func (p *parser) parseParameterList(name0 *ast.Ident, closing token.Token, parse
                // some named => all must be named
                ok := true
                var typ ast.Expr
+               missingName := pos
                for i := len(list) - 1; i >= 0; i-- {
                        if par := &list[i]; par.typ != nil {
                                typ = par.typ
                                if par.name == nil {
                                        ok = false
+                                       missingName = par.typ.Pos()
                                        n := ast.NewIdent("_")
                                        n.NamePos = typ.Pos() // correct position
                                        par.name = n
@@ -832,12 +870,13 @@ func (p *parser) parseParameterList(name0 *ast.Ident, closing token.Token, parse
                        } else {
                                // par.typ == nil && typ == nil => we only have a par.name
                                ok = false
+                               missingName = par.name.Pos()
                                par.typ = &ast.BadExpr{From: par.name.Pos(), To: p.pos}
                        }
                }
                if !ok {
                        if tparams {
-                               p.error(pos, "all type parameters must be named")
+                               p.error(missingName, "all type parameters must be named")
                        } else {
                                p.error(pos, "mixed named and unnamed parameters")
                        }
@@ -883,11 +922,11 @@ func (p *parser) parseParameters(acceptTParams bool) (tparams, params *ast.Field
                defer un(trace(p, "Parameters"))
        }
 
-       if p.parseTypeParams() && acceptTParams && p.tok == token.LBRACK {
+       if p.allowGenerics() && acceptTParams && p.tok == token.LBRACK {
                opening := p.pos
                p.next()
                // [T any](params) syntax
-               list := p.parseParameterList(nil, token.RBRACK, p.parseParamDecl, true)
+               list := p.parseParameterList(nil, token.RBRACK)
                rbrack := p.expect(token.RBRACK)
                tparams = &ast.FieldList{Opening: opening, List: list, Closing: rbrack}
                // Type parameter lists must not be empty.
@@ -901,7 +940,7 @@ func (p *parser) parseParameters(acceptTParams bool) (tparams, params *ast.Field
 
        var fields []*ast.Field
        if p.tok != token.RPAREN {
-               fields = p.parseParameterList(nil, token.RPAREN, p.parseParamDecl, false)
+               fields = p.parseParameterList(nil, token.RPAREN)
        }
 
        rparen := p.expect(token.RPAREN)
@@ -956,7 +995,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
        x := p.parseTypeName(nil)
        if ident, _ := x.(*ast.Ident); ident != nil {
                switch {
-               case p.tok == token.LBRACK && p.parseTypeParams():
+               case p.tok == token.LBRACK && p.allowGenerics():
                        // generic method or embedded instantiated type
                        lbrack := p.pos
                        p.next()
@@ -965,15 +1004,19 @@ func (p *parser) parseMethodSpec() *ast.Field {
                        p.exprLev--
                        if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.COMMA && p.tok != token.RBRACK {
                                // generic method m[T any]
-                               list := p.parseParameterList(name0, token.RBRACK, p.parseParamDecl, true)
+                               list := p.parseParameterList(name0, token.RBRACK)
                                rbrack := p.expect(token.RBRACK)
                                tparams := &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack}
                                // TODO(rfindley) refactor to share code with parseFuncType.
                                _, params := p.parseParameters(false)
                                results := p.parseResult()
                                idents = []*ast.Ident{ident}
-                               typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
-                               typeparams.Set(typ, tparams)
+                               typ = &ast.FuncType{
+                                       Func:       token.NoPos,
+                                       TypeParams: tparams,
+                                       Params:     params,
+                                       Results:    results,
+                               }
                        } else {
                                // embedded instantiated type
                                // TODO(rfindley) should resolve all identifiers in x.
@@ -1007,7 +1050,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
        } else {
                // embedded, possibly instantiated type
                typ = x
-               if p.tok == token.LBRACK && p.parseTypeParams() {
+               if p.tok == token.LBRACK && p.allowGenerics() {
                        // embedded instantiated interface
                        typ = p.parseTypeInstance(typ)
                }
@@ -1020,24 +1063,23 @@ func (p *parser) parseMethodSpec() *ast.Field {
        return &ast.Field{Doc: doc, Names: idents, Type: typ}
 }
 
-func (p *parser) embeddedElem(f *ast.Field) *ast.Field {
+func (p *parser) embeddedElem(x ast.Expr) ast.Expr {
        if p.trace {
                defer un(trace(p, "EmbeddedElem"))
        }
-       if f == nil {
-               f = new(ast.Field)
-               f.Type = p.embeddedTerm()
+       if x == nil {
+               x = p.embeddedTerm()
        }
        for p.tok == token.OR {
                t := new(ast.BinaryExpr)
                t.OpPos = p.pos
                t.Op = token.OR
                p.next()
-               t.X = f.Type
+               t.X = x
                t.Y = p.embeddedTerm()
-               f.Type = t
+               x = t
        }
-       return f
+       return x
 }
 
 func (p *parser) embeddedTerm() ast.Expr {
@@ -1079,37 +1121,23 @@ parseElements:
                switch {
                case p.tok == token.IDENT:
                        f := p.parseMethodSpec()
-                       if f.Names == nil && p.parseTypeParams() {
-                               f = p.embeddedElem(f)
+                       if f.Names == nil && p.allowGenerics() {
+                               f.Type = p.embeddedElem(f.Type)
                        }
                        p.expectSemi()
                        f.Comment = p.lineComment
                        list = append(list, f)
-               case p.tok == token.TILDE && p.parseTypeParams():
-                       f := p.embeddedElem(nil)
+               case p.tok == token.TILDE && p.allowGenerics():
+                       typ := p.embeddedElem(nil)
                        p.expectSemi()
-                       f.Comment = p.lineComment
-                       list = append(list, f)
-               case p.tok == token.TYPE && p.parseTypeParams():
-                       // TODO(rfindley): remove TypeList syntax and refactor the clauses above.
-
-                       // all types in a type list share the same field name "type"
-                       // (since type is a keyword, a Go program cannot have that field name)
-                       name := []*ast.Ident{{NamePos: p.pos, Name: "type"}}
-                       p.next()
-                       // add each type as a field named "type"
-                       for _, typ := range p.parseTypeList() {
-                               list = append(list, &ast.Field{Names: name, Type: typ})
-                       }
-                       p.expectSemi()
-               case p.parseTypeParams():
+                       comment := p.lineComment
+                       list = append(list, &ast.Field{Type: typ, Comment: comment})
+               case p.allowGenerics():
                        if t := p.tryIdentOrType(); t != nil {
-                               f := new(ast.Field)
-                               f.Type = t
-                               f = p.embeddedElem(f)
+                               typ := p.embeddedElem(t)
                                p.expectSemi()
-                               f.Comment = p.lineComment
-                               list = append(list, f)
+                               comment := p.lineComment
+                               list = append(list, &ast.Field{Type: typ, Comment: comment})
                        } else {
                                break parseElements
                        }
@@ -1172,7 +1200,7 @@ func (p *parser) parseChanType() *ast.ChanType {
 }
 
 func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
-       assert(p.parseTypeParams(), "parseTypeInstance while not parsing type params")
+       assert(p.allowGenerics(), "parseTypeInstance while not parsing type params")
        if p.trace {
                defer un(trace(p, "TypeInstance"))
        }
@@ -1208,16 +1236,13 @@ func (p *parser) tryIdentOrType() ast.Expr {
        switch p.tok {
        case token.IDENT:
                typ := p.parseTypeName(nil)
-               if p.tok == token.LBRACK && p.parseTypeParams() {
+               if p.tok == token.LBRACK && p.allowGenerics() {
                        typ = p.parseTypeInstance(typ)
                }
                return typ
        case token.LBRACK:
                lbrack := p.expect(token.LBRACK)
-               alen := p.parseArrayLen()
-               p.expect(token.RBRACK)
-               elt := p.parseType()
-               return &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
+               return p.parseArrayType(lbrack, nil)
        case token.STRUCT:
                return p.parseStructType()
        case token.MUL:
@@ -1458,7 +1483,7 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr {
                return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
        }
 
-       if !p.parseTypeParams() {
+       if !p.allowGenerics() {
                p.error(firstComma, "expected ']' or ':', found ','")
                return &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
        }
@@ -1566,7 +1591,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
                panic("unreachable")
        case *ast.SelectorExpr:
        case *ast.IndexExpr:
-       case *ast.MultiIndexExpr:
+       case *ast.IndexListExpr:
        case *ast.SliceExpr:
        case *ast.TypeAssertExpr:
                // If t.Type == nil we have a type assertion of the form
@@ -1612,12 +1637,14 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
        return x
 }
 
-func (p *parser) parsePrimaryExpr() (x ast.Expr) {
+func (p *parser) parsePrimaryExpr(x ast.Expr) ast.Expr {
        if p.trace {
                defer un(trace(p, "PrimaryExpr"))
        }
 
-       x = p.parseOperand()
+       if x == nil {
+               x = p.parseOperand()
+       }
        for {
                switch p.tok {
                case token.PERIOD:
@@ -1653,18 +1680,18 @@ func (p *parser) parsePrimaryExpr() (x ast.Expr) {
                        switch t.(type) {
                        case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr:
                                if p.exprLev < 0 {
-                                       return
+                                       return x
                                }
                                // x is possibly a composite literal type
-                       case *ast.IndexExpr, *ast.MultiIndexExpr:
+                       case *ast.IndexExpr, *ast.IndexListExpr:
                                if p.exprLev < 0 {
-                                       return
+                                       return x
                                }
                                // x is possibly a composite literal type
                        case *ast.ArrayType, *ast.StructType, *ast.MapType:
                                // x is a composite literal type
                        default:
-                               return
+                               return x
                        }
                        if t != x {
                                p.error(t.Pos(), "cannot parenthesize type in composite literal")
@@ -1672,7 +1699,7 @@ func (p *parser) parsePrimaryExpr() (x ast.Expr) {
                        }
                        x = p.parseLiteralValue(x)
                default:
-                       return
+                       return x
                }
        }
 }
@@ -1743,7 +1770,7 @@ func (p *parser) parseUnaryExpr() ast.Expr {
                return &ast.StarExpr{Star: pos, X: p.checkExprOrType(x)}
        }
 
-       return p.parsePrimaryExpr()
+       return p.parsePrimaryExpr(nil)
 }
 
 func (p *parser) tokPrec() (token.Token, int) {
@@ -1754,19 +1781,21 @@ func (p *parser) tokPrec() (token.Token, int) {
        return tok, tok.Precedence()
 }
 
-func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+func (p *parser) parseBinaryExpr(x ast.Expr, prec1 int) ast.Expr {
        if p.trace {
                defer un(trace(p, "BinaryExpr"))
        }
 
-       x := p.parseUnaryExpr()
+       if x == nil {
+               x = p.parseUnaryExpr()
+       }
        for {
                op, oprec := p.tokPrec()
                if oprec < prec1 {
                        return x
                }
                pos := p.expect(op)
-               y := p.parseBinaryExpr(oprec + 1)
+               y := p.parseBinaryExpr(nil, oprec+1)
                x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
        }
 }
@@ -1779,7 +1808,7 @@ func (p *parser) parseExpr() ast.Expr {
                defer un(trace(p, "Expression"))
        }
 
-       return p.parseBinaryExpr(token.LowestPrec + 1)
+       return p.parseBinaryExpr(nil, token.LowestPrec+1)
 }
 
 func (p *parser) parseRhs() ast.Expr {
@@ -2502,10 +2531,14 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, _ token.Pos, keyword toke
        return spec
 }
 
-func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *ast.Ident, closeTok token.Token) {
-       list := p.parseParameterList(name0, closeTok, p.parseParamDecl, true)
-       closePos := p.expect(closeTok)
-       typeparams.Set(spec, &ast.FieldList{Opening: openPos, List: list, Closing: closePos})
+func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *ast.Ident) {
+       if p.trace {
+               defer un(trace(p, "parseGenericType"))
+       }
+
+       list := p.parseParameterList(name0, token.RBRACK)
+       closePos := p.expect(token.RBRACK)
+       spec.TypeParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos}
        // Type alias cannot have type parameters. Accept them for robustness but complain.
        if p.tok == token.ASSIGN {
                p.error(p.pos, "generic type cannot be alias")
@@ -2522,34 +2555,42 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
        ident := p.parseIdent()
        spec := &ast.TypeSpec{Doc: doc, Name: ident}
 
-       switch p.tok {
-       case token.LBRACK:
+       if p.tok == token.LBRACK && p.allowGenerics() {
                lbrack := p.pos
                p.next()
                if p.tok == token.IDENT {
-                       // array type or generic type [T any]
-                       p.exprLev++
-                       x := p.parseExpr()
-                       p.exprLev--
-                       if name0, _ := x.(*ast.Ident); p.parseTypeParams() && name0 != nil && p.tok != token.RBRACK {
+                       // array type or generic type: [name0...
+                       name0 := p.parseIdent()
+
+                       // Index or slice expressions are never constant and thus invalid
+                       // array length expressions. Thus, if we see a "[" following name
+                       // we can safely assume that "[" name starts a type parameter list.
+                       var x ast.Expr // x != nil means x is the array length expression
+                       if p.tok != token.LBRACK {
+                               // We may still have either an array type or generic type -- check if
+                               // name0 is the entire expr.
+                               p.exprLev++
+                               lhs := p.parsePrimaryExpr(name0)
+                               x = p.parseBinaryExpr(lhs, token.LowestPrec+1)
+                               p.exprLev--
+                               if x == name0 && p.tok != token.RBRACK {
+                                       x = nil
+                               }
+                       }
+
+                       if x == nil {
                                // generic type [T any];
-                               p.parseGenericType(spec, lbrack, name0, token.RBRACK)
+                               p.parseGenericType(spec, lbrack, name0)
                        } else {
                                // array type
                                // TODO(rfindley) should resolve all identifiers in x.
-                               p.expect(token.RBRACK)
-                               elt := p.parseType()
-                               spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
+                               spec.Type = p.parseArrayType(lbrack, x)
                        }
                } else {
                        // array type
-                       alen := p.parseArrayLen()
-                       p.expect(token.RBRACK)
-                       elt := p.parseType()
-                       spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
+                       spec.Type = p.parseArrayType(lbrack, nil)
                }
-
-       default:
+       } else {
                // no type parameters
                if p.tok == token.ASSIGN {
                        // type alias
@@ -2615,10 +2656,11 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
        results := p.parseResult()
 
        var body *ast.BlockStmt
-       if p.tok == token.LBRACE {
+       switch p.tok {
+       case token.LBRACE:
                body = p.parseBody()
                p.expectSemi()
-       } else if p.tok == token.SEMICOLON {
+       case token.SEMICOLON:
                p.next()
                if p.tok == token.LBRACE {
                        // opening { of function declaration on next line
@@ -2626,7 +2668,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
                        body = p.parseBody()
                        p.expectSemi()
                }
-       } else {
+       default:
                p.expectSemi()
        }
 
@@ -2635,13 +2677,13 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
                Recv: recv,
                Name: ident,
                Type: &ast.FuncType{
-                       Func:    pos,
-                       Params:  params,
-                       Results: results,
+                       Func:       pos,
+                       TypeParams: tparams,
+                       Params:     params,
+                       Results:    results,
                },
                Body: body,
        }
-       typeparams.Set(decl.Type, tparams)
        return decl
 }
 
index cf92c7e4f571ef089e4992a29af0805281a61e41..54732a7fd6f15eb8e0f39cb1f4acb8d00be7e5e9 100644 (file)
@@ -7,7 +7,6 @@ package parser
 import (
        "fmt"
        "go/ast"
-       "go/internal/typeparams"
        "go/token"
 )
 
@@ -118,12 +117,6 @@ func (r *resolver) closeLabelScope() {
 
 func (r *resolver) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
        for _, ident := range idents {
-               // "type" is used for type lists in interfaces, and is otherwise an invalid
-               // identifier. The 'type' identifier is also artificially duplicated in the
-               // type list, so could cause panics below if we were to proceed.
-               if ident.Name == "type" {
-                       continue
-               }
                assert(ident.Obj == nil, "identifier already declared or resolved")
                obj := ast.NewObj(kind, ident.Name)
                // remember the corresponding declaration for redeclaration
@@ -189,10 +182,9 @@ func (r *resolver) resolve(ident *ast.Ident, collectUnresolved bool) {
        if ident.Obj != nil {
                panic(fmt.Sprintf("%s: identifier %s already declared or resolved", r.handle.Position(ident.Pos()), ident.Name))
        }
-       // '_' and 'type' should never refer to existing declarations: '_' because it
-       // has special handling in the spec, and 'type' because it is a keyword, and
-       // only valid in an interface type list.
-       if ident.Name == "_" || ident.Name == "type" {
+       // '_' should never refer to existing declarations, because it has special
+       // handling in the spec.
+       if ident.Name == "_" {
                return
        }
        for s := r.topScope; s != nil; s = s.Outer {
@@ -455,10 +447,10 @@ func (r *resolver) Visit(node ast.Node) ast.Visitor {
                                // at the identifier in the TypeSpec and ends at the end of the innermost
                                // containing block.
                                r.declare(spec, nil, r.topScope, ast.Typ, spec.Name)
-                               if tparams := typeparams.Get(spec); tparams != nil {
+                               if spec.TypeParams != nil {
                                        r.openScope(spec.Pos())
                                        defer r.closeScope()
-                                       r.walkTParams(tparams)
+                                       r.walkTParams(spec.TypeParams)
                                }
                                ast.Walk(r, spec.Type)
                        }
@@ -474,8 +466,8 @@ func (r *resolver) Visit(node ast.Node) ast.Visitor {
 
                // Type parameters are walked normally: they can reference each other, and
                // can be referenced by normal parameters.
-               if tparams := typeparams.Get(n.Type); tparams != nil {
-                       r.walkTParams(tparams)
+               if n.Type.TypeParams != nil {
+                       r.walkTParams(n.Type.TypeParams)
                        // TODO(rFindley): need to address receiver type parameters.
                }
 
@@ -500,7 +492,7 @@ func (r *resolver) Visit(node ast.Node) ast.Visitor {
 }
 
 func (r *resolver) walkFuncType(typ *ast.FuncType) {
-       // typ.TParams must be walked separately for FuncDecls.
+       // typ.TypeParams must be walked separately for FuncDecls.
        r.resolveList(typ.Params)
        r.resolveList(typ.Results)
        r.declareList(typ.Params, ast.Var)
@@ -539,9 +531,6 @@ func (r *resolver) walkFieldList(list *ast.FieldList, kind ast.ObjKind) {
 // that they may be resolved in the constraint expressions held in the field
 // Type.
 func (r *resolver) walkTParams(list *ast.FieldList) {
-       if list == nil {
-               return
-       }
        r.declareList(list, ast.Typ)
        r.resolveList(list)
 }
index bfc6f6714b9f59f0bb31079709f620a184aba0b4..20450bfe8ed362b88d5d12646cc81490ad4cc31f 100644 (file)
@@ -119,8 +119,7 @@ var validWithTParamsOnly = []string{
        `package p; func _(T[P] /* ERROR "missing element type" */ ) T[P]`,
        `package p; type _ struct{ T[P] /* ERROR "missing element type" */ }`,
        `package p; type _ struct{ T[struct /* ERROR "expected expression" */ {a, b, c int}] }`,
-       `package p; type _ interface{type /* ERROR "expected '}', found 'type'" */ int}`,
-       `package p; type _ interface{type /* ERROR "expected '}', found 'type'" */ int, float32; type bool; m(); type string;}`,
+       `package p; type _ interface{int| /* ERROR "expected ';'" */ float32; bool; m(); string;}`,
        `package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2 interface{ I1[int] }`,
        `package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2[T any] interface{ I1[T] }`,
        `package p; type _ interface { f[ /* ERROR "expected ';', found '\['" */ T any]() }`,
index b399d7514889f39c5e8889088dd2c4ada0d2c857..2ed9339c5204d6525b57bf9961bef8ae954c2d99 100644 (file)
@@ -4,16 +4,13 @@
 
 // This file contains test cases for interfaces containing
 // constraint elements.
-//
-// For now, we accept both ordinary type lists and the
-// more complex constraint elements.
 
 package p
 
 type _ interface {
        m()
-       type int
-       type int, string
+       ~int
+       ~int|string
        E
 }
 
@@ -31,7 +28,6 @@ type _ interface {
        T[int, string] | string
        int | ~T[string, struct{}]
        ~int | ~string
-       type bool, int, float64
 }
 
 type _ interface {
diff --git a/src/go/parser/testdata/issue49174.go2 b/src/go/parser/testdata/issue49174.go2
new file mode 100644 (file)
index 0000000..77c1950
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2021 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 _[_ []int | int]() {}
+func _[_ int | []int]() {}
diff --git a/src/go/parser/testdata/issue49175.go2 b/src/go/parser/testdata/issue49175.go2
new file mode 100644 (file)
index 0000000..a5ad30f
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2021 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]t
+type _[_ [1]t]t
+
+func _[_ []t]() {}
+func _[_ [1]t]() {}
+
+type t [t /* ERROR "all type parameters must be named" */ [0]]t
index fba0d02eb2fe045370515aaed3b35e0cf8709594..7ccb19c08d3f1ff9dfde94113b618a6c3c627197 100644 (file)
@@ -9,10 +9,10 @@ import "math"
 // Numeric is type bound that matches any numeric type.
 // It would likely be in a constraints package in the standard library.
 type Numeric interface {
-       type int, int8, int16, int32, int64,
-               uint, uint8, uint16, uint32, uint64, uintptr,
-               float32, float64,
-               complex64, complex128
+       ~int|~int8|~int16|~int32|~int64|
+               ~uint|~uint8|~uint16|~uint32|~uint64|~uintptr|
+               ~float32|~float64|
+               ~complex64|~complex128
 }
 
 func DotProduct[T Numeric](s1, s2 []T) T {
@@ -42,14 +42,14 @@ func AbsDifference[T NumericAbs](a, b T) T {
 
 // OrderedNumeric is a type bound that matches numeric types that support the < operator.
 type OrderedNumeric interface {
-       type int, int8, int16, int32, int64,
-               uint, uint8, uint16, uint32, uint64, uintptr,
-               float32, float64
+       ~int|~int8|~int16|~int32|~int64|
+               ~uint|~uint8|~uint16|~uint32|~uint64|~uintptr|
+               ~float32|~float64
 }
 
 // Complex is a type bound that matches the two complex types, which do not have a < operator.
 type Complex interface {
-       type complex64, complex128
+       ~complex64|~complex128
 }
 
 // OrderedAbs is a helper type that defines an Abs method for
index 0ffecd69b5b8a49985b57de39b340d335e865201..8c243afda7eb396dca137458f74a44ce7f2d66ab 100644 (file)
@@ -15,7 +15,7 @@ type Pair /* =@Pair */ [L /* =@L */, R /* =@R */ any] struct {
 var _ = Pair /* @Pair */ [int, string]{}
 
 type Addable /* =@Addable */ interface {
-       type int64, float64
+       ~int64|~float64
 }
 
 func Add /* =@AddDecl */[T /* =@T */ Addable /* @Addable */](l /* =@l */, r /* =@r */ T /* @T */) T /* @T */ {
@@ -30,7 +30,7 @@ type Receiver /* =@Receiver */[P /* =@P */ any] struct {}
 // parameter below.
 func (r /* =@recv */ Receiver /* @Receiver */ [P]) m() P {}
 
-func f /* =@f */[T1 /* =@T1 */ interface{type []T2 /* @T2 */}, T2 /* =@T2 */ any](
+func f /* =@f */[T1 /* =@T1 */ interface{~[]T2 /* @T2 */}, T2 /* =@T2 */ any](
   x /* =@x */ T1 /* @T1 */, T1 /* =@T1_duplicate */ y,  // Note that this is a bug:
                                                         // the duplicate T1 should
                                                        // not be allowed.
diff --git a/src/go/parser/testdata/typeset.go2 b/src/go/parser/testdata/typeset.go2
new file mode 100644 (file)
index 0000000..aa18e8c
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains test cases for typeset-only constraint elements.
+// TODO(gri) gofmt once/if gofmt supports this notation.
+
+package p
+
+type (
+        _[_ t] t
+        _[_ ~t] t
+        _[_ t|t] t
+        _[_ ~t|t] t
+        _[_ t|~t] t
+        _[_ ~t|~t] t
+
+        _[_ t, _, _ t|t] t
+        _[_ t, _, _ ~t|t] t
+        _[_ t, _, _ t|~t] t
+        _[_ t, _, _ ~t|~t] t
+
+        _[_ t.t] t
+        _[_ ~t.t] t
+        _[_ t.t|t.t] t
+        _[_ ~t.t|t.t] t
+        _[_ t.t|~t.t] t
+        _[_ ~t.t|~t.t] t
+
+        _[_ t, _, _ t.t|t.t] t
+        _[_ t, _, _ ~t.t|t.t] t
+        _[_ t, _, _ t.t|~t.t] t
+        _[_ t, _, _ ~t.t|~t.t] t
+
+        _[_ struct{}] t
+        _[_ ~struct{}] t
+
+        _[_ struct{}|t] t
+        _[_ ~struct{}|t] t
+        _[_ struct{}|~t] t
+        _[_ ~struct{}|~t] t
+
+        _[_ t|struct{}] t
+        _[_ ~t|struct{}] t
+        _[_ t|~struct{}] t
+        _[_ ~t|~struct{}] t
+)
+
+// Single-expression type parameter lists and those that don't start
+// with a (type parameter) name are considered array sizes.
+// The term must be a valid expression (it could be a type - and then
+// a type-checker will complain - but we don't allow ~ in the expr).
+// TODO(rfindley): Improve error recover here. In these cases go/parser error
+// recovery is worse than cmd/compile/internal/syntax, and unnecessary type
+// declarations had to be inserted to force synchronization.
+type _[t] t
+type _[~ /* ERROR "expected operand" */ t] t
+type /* ERROR "expected ']'" */ Sync int  // placeholder to synchronize the parser
+type _[t|t] t
+type _[~ /* ERROR "expected operand" */ t|t] t
+type /* ERROR "expected ']'" */ Sync int  // placeholder to synchronize the parser
+type _[t| ~ /* ERROR "expected operand" */ t] t
+type /* ERROR "expected ']'" */ Sync int  // placeholder to synchronize the parser
+type _[~ /* ERROR "expected operand" */ t|~t] t
+type /* ERROR "expected ']'" */ Sync int  // placeholder to synchronize the parser
+
+type _[_ t, t /* ERROR "type parameters must be named" */ ] t
+type _[_ ~t, t /* ERROR "type parameters must be named" */ ] t
+type _[_ t, ~ /* ERROR "type parameters must be named" */ t] t
+type _[_ ~t, ~ /* ERROR "type parameters must be named" */ t] t
+
+type _[_ t|t, t /* ERROR "type parameters must be named" */ |t] t
+type _[_ ~t|t, t /* ERROR "type parameters must be named" */ |t] t
+type _[_ t|t, ~ /* ERROR "type parameters must be named" */ t|t] t
+type _[_ ~t|t, ~ /* ERROR "type parameters must be named" */ t|t] t
index 239fcbde1c8b4cc3d6b8a5b4082d8f8a996b03b4..19d4ab6663d3d0f067a33cef99a375995d2dcfe9 100644 (file)
@@ -11,7 +11,6 @@ package printer
 import (
        "bytes"
        "go/ast"
-       "go/internal/typeparams"
        "go/token"
        "math"
        "strconv"
@@ -383,8 +382,8 @@ func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
 }
 
 func (p *printer) signature(sig *ast.FuncType) {
-       if tparams := typeparams.Get(sig); tparams != nil {
-               p.parameters(tparams, true)
+       if sig.TypeParams != nil {
+               p.parameters(sig.TypeParams, true)
        }
        if sig.Params != nil {
                p.parameters(sig.Params, false)
@@ -472,17 +471,9 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
                                p.expr(f.Type)
                        } else { // interface
                                if len(f.Names) > 0 {
-                                       // type list type or method
-                                       name := f.Names[0] // "type" or method name
+                                       name := f.Names[0] // method name
                                        p.expr(name)
-                                       if name.Name == "type" {
-                                               // type list type
-                                               p.print(blank)
-                                               p.expr(f.Type)
-                                       } else {
-                                               // method
-                                               p.signature(f.Type.(*ast.FuncType)) // don't print "func"
-                                       }
+                                       p.signature(f.Type.(*ast.FuncType)) // don't print "func"
                                } else {
                                        // embedded interface
                                        p.expr(f.Type)
@@ -569,24 +560,10 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
                        p.setComment(f.Doc)
                        p.recordLine(&line)
                        if name != nil {
-                               // type list type or method
-                               if name.Name == "type" {
-                                       // type list type
-                                       if name == prev {
-                                               // type is part of a list of types
-                                               p.print(token.COMMA, blank)
-                                       } else {
-                                               // type starts a new list of types
-                                               p.print(name, blank)
-                                       }
-                                       p.expr(f.Type)
-                                       prev = name
-                               } else {
-                                       // method
-                                       p.expr(name)
-                                       p.signature(f.Type.(*ast.FuncType)) // don't print "func"
-                                       prev = nil
-                               }
+                               // method
+                               p.expr(name)
+                               p.signature(f.Type.(*ast.FuncType)) // don't print "func"
+                               prev = nil
                        } else {
                                // embedded interface
                                p.expr(f.Type)
@@ -874,7 +851,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                p.expr0(x.Index, depth+1)
                p.print(x.Rbrack, token.RBRACK)
 
-       case *ast.MultiIndexExpr:
+       case *ast.IndexListExpr:
                // TODO(gri): as for IndexExpr, should treat [] like parentheses and undo
                // one level of depth
                p.expr1(x.X, token.HighestPrec, 1)
@@ -1050,7 +1027,7 @@ func normalizedNumber(lit *ast.BasicLit) *ast.BasicLit {
                        break
                }
                // remove leading 0's from integer (but not floating-point) imaginary literals
-               if x[len(x)-1] == 'i' && strings.IndexByte(x, '.') < 0 && strings.IndexByte(x, 'e') < 0 {
+               if x[len(x)-1] == 'i' && !strings.ContainsAny(x, ".e") {
                        x = strings.TrimLeft(x, "0_")
                        if x == "i" {
                                x = "0i"
@@ -1633,8 +1610,8 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
        case *ast.TypeSpec:
                p.setComment(s.Doc)
                p.expr(s.Name)
-               if tparams := typeparams.Get(s); tparams != nil {
-                       p.parameters(tparams, true)
+               if s.TypeParams != nil {
+                       p.parameters(s.TypeParams, true)
                }
                if n == 1 {
                        p.print(blank)
index ba61f782267ad8ed27ab5b2252f06bdf70cc5252..2f41e7bf72f6b97b8f53eac68b9a304e490f25e6 100644 (file)
@@ -559,12 +559,9 @@ func stripCommonPrefix(lines []string) {
         * Check for vertical "line of stars" and correct prefix accordingly.
         */
        lineOfStars := false
-       if i := strings.Index(prefix, "*"); i >= 0 {
-               // Line of stars present.
-               if i > 0 && prefix[i-1] == ' ' {
-                       i-- // remove trailing blank from prefix so stars remain aligned
-               }
-               prefix = prefix[0:i]
+       if p, _, ok := strings.Cut(prefix, "*"); ok {
+               // remove trailing blank from prefix so stars remain aligned
+               prefix = strings.TrimSuffix(p, " ")
                lineOfStars = true
        } else {
                // No line of stars present.
@@ -616,8 +613,8 @@ func stripCommonPrefix(lines []string) {
        // lines.
        last := lines[len(lines)-1]
        closing := "*/"
-       i := strings.Index(last, closing) // i >= 0 (closing is always present)
-       if isBlank(last[0:i]) {
+       before, _, _ := strings.Cut(last, closing) // closing always present
+       if isBlank(before) {
                // last line only contains closing */
                if lineOfStars {
                        closing = " */" // add blank to align final star
index cc7fbbe1d8360403db9181d0303e7df12a18780b..3d95eda5b2ac4a56ce79d7837f0766e42d3fe6e0 100644 (file)
@@ -22,7 +22,7 @@ func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
 func f[P interface{}](x P)
 func f[P1, P2, P3 interface {
        m1(P1)
-       type P2, P3
+       ~P2 | ~P3
 }](x1 P1, x2 P2, x3 P3) struct{}
 func f[P any](T1[P], T2[P]) T3[P]
 
@@ -35,9 +35,6 @@ func _() {
        _ = []T[P]{}
 }
 
-// properly format one-line type lists
-type _ interface{ type a }
-
-type _ interface {
-       type a, b, c
-}
+// type constraint literals with elided interfaces
+func _[P ~int, Q int | string]()       {}
+func _[P struct{ f int }, Q *P]()      {}
index f4571ad33693cb260dd3c0afb4420eba1ac11cf4..746dfdd2358ba987efc0847035ad6f759151e07f 100644 (file)
@@ -20,7 +20,7 @@ func f[P any](x P)
 func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
 
 func f[P interface{}](x P)
-func f[P1, P2, P3 interface{ m1(P1); type P2, P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P1, P2, P3 interface{ m1(P1); ~P2|~P3 }](x1 P1, x2 P2, x3 P3) struct{}
 func f[P any](T1[P], T2[P]) T3[P]
 
 func (x T[P]) m()
@@ -32,7 +32,6 @@ func _() {
        _ = []T[P]{}
 }
 
-// properly format one-line type lists
-type _ interface { type a }
-
-type _ interface { type a,b,c }
+// type constraint literals with elided interfaces
+func _[P ~int, Q int | string]() {}
+func _[P struct{f int}, Q *P]() {}
index 0d7982c67059374be2c291fd3bd312b7a3e950d8..ce4af039237ce6f3cb12005e8f34fe8430ad04a5 100644 (file)
@@ -540,7 +540,7 @@ func searchInts(a []int, x int) int {
        // TODO(gri): Remove this when compilers have caught up.
        i, j := 0, len(a)
        for i < j {
-               h := i + (j-i)>>1 // avoid overflow when computing h
+               h := int(uint(i+j) >> 1) // avoid overflow when computing h
                // i ≤ h < j
                if a[h] <= x {
                        i = h + 1
index 315f77f362ae096880b1b75da48148c036840484..c115d07b4182d080df7d7b59263d6cf2c34edca3 100644 (file)
@@ -62,6 +62,15 @@ func (err Error) Error() string {
        return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
 }
 
+// An ArgumentError holds an error associated with an argument index.
+type ArgumentError struct {
+       Index int
+       Err   error
+}
+
+func (e *ArgumentError) Error() string { return e.Err.Error() }
+func (e *ArgumentError) Unwrap() error { return e.Err }
+
 // An Importer resolves import paths to Packages.
 //
 // CAUTION: This interface does not support the import of locally
@@ -103,6 +112,10 @@ type ImporterFrom interface {
 // A Config specifies the configuration for type checking.
 // The zero value for Config is a ready-to-use default configuration.
 type Config struct {
+       // Context is the context used for resolving global identifiers. If nil, the
+       // type checker will initialize this field with a newly created context.
+       Context *Context
+
        // GoVersion describes the accepted Go language version. The string
        // must follow the format "go%d.%d" (e.g. "go1.12") or it must be
        // empty; an empty string indicates the latest language version.
@@ -186,11 +199,19 @@ type Info struct {
        // qualified identifiers are collected in the Uses map.
        Types map[ast.Expr]TypeAndValue
 
-       // Inferred maps calls of parameterized functions that use
-       // type inference to the inferred type arguments and signature
-       // of the function called. The recorded "call" expression may be
-       // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
-       Inferred map[ast.Expr]Inferred
+       // Instances maps identifiers denoting parameterized types or functions to
+       // their type arguments and instantiated type.
+       //
+       // For example, Instances will map the identifier for 'T' in the type
+       // instantiation T[int, string] to the type arguments [int, string] and
+       // resulting instantiated *Named type. Given a parameterized function
+       // func F[A any](A), Instances will map the identifier for 'F' in the call
+       // expression F(int(1)) to the inferred type arguments [int], and resulting
+       // instantiated *Signature.
+       //
+       // Invariant: Instantiating Uses[id].Type() with Instances[id].TypeArgs
+       // results in an equivalent of Instances[id].Type.
+       Instances map[*ast.Ident]Instance
 
        // Defs maps identifiers to the objects they define (including
        // package names, dots "." of dot-imports, and blank "_" identifiers).
@@ -348,11 +369,13 @@ func (tv TypeAndValue) HasOk() bool {
        return tv.mode == commaok || tv.mode == mapindex
 }
 
-// Inferred reports the Inferred type arguments and signature
-// for a parameterized function call that uses type inference.
-type Inferred struct {
-       TArgs []Type
-       Sig   *Signature
+// Instance reports the type arguments and instantiated type for type and
+// function instantiations. For type instantiations, Type will be of dynamic
+// type *Named. For function instantiations, Type will be of dynamic type
+// *Signature.
+type Instance struct {
+       TypeArgs *TypeList
+       Type     Type
 }
 
 // An Initializer describes a package-level variable, or a list of variables in case
index f138af5fbf55fabdb581b743012dd7669905f3d4..807bffbff6569256a29b806a6813c0bcaa9fb5c0 100644 (file)
@@ -6,6 +6,7 @@ package types_test
 
 import (
        "bytes"
+       "errors"
        "fmt"
        "go/ast"
        "go/importer"
@@ -152,6 +153,7 @@ func TestValuesInfo(t *testing.T) {
                {`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
 
                {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // issue #22341
+               {`package g1; var(j int32; s int; n = 1.0<<s == j)`, `1.0`, `int32`, `1`},        // issue #48422
        }
 
        for _, test := range tests {
@@ -343,16 +345,18 @@ func TestTypesInfo(t *testing.T) {
                {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
 
                // parameterized functions
-               {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[generic_p0.T₁ interface{}](generic_p0.T₁)`},
-               {genericPkg + `p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
-               {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[generic_p2.T₁ interface{}](generic_p2.T₁)`},
-               {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
+               {genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[T interface{}](T)`},
+               {genericPkg + `p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`},
+               {genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func(int)`},
+               {genericPkg + `p3; func f[T any](T) {}; func _() { f[int](42) }`, `f[int]`, `func(int)`},
+               {genericPkg + `p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[T interface{}](T)`},
+               {genericPkg + `p5; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
 
                // type parameters
                {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
-               {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[generic_t1.P₁ interface{}]`},
-               {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[generic_t2.P₁ interface{}]`},
-               {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[generic_t3.P₁, generic_t3.Q₂ interface{}]`},
+               {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P interface{}]`},
+               {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P interface{}]`},
+               {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P, Q interface{}]`},
 
                // TODO (rFindley): compare with types2, which resolves the type broken_t4.t[P₁, Q₂ interface{m()}] here
                {broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t`},
@@ -361,7 +365,10 @@ func TestTypesInfo(t *testing.T) {
                {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
 
                // issue 45096
-               {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32  }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`},
+               {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32  }](x T) { _ = x < 0 }`, `0`, `T`},
+
+               // issue 47895
+               {`package p; import "unsafe"; type S struct { f int }; var s S; var _ = unsafe.Offsetof(s.f)`, `s.f`, `int`},
        }
 
        for _, test := range tests {
@@ -398,125 +405,189 @@ func TestTypesInfo(t *testing.T) {
        }
 }
 
-func TestInferredInfo(t *testing.T) {
+func TestInstanceInfo(t *testing.T) {
        var tests = []struct {
                src   string
-               fun   string
+               name  string
                targs []string
-               sig   string
+               typ   string
        }{
-               {genericPkg + `p0; func f[T any](T); func _() { f(42) }`,
+               {`package p0; func f[T any](T) {}; func _() { f(42) }`,
                        `f`,
                        []string{`int`},
                        `func(int)`,
                },
-               {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`,
+               {`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
                        `f`,
                        []string{`rune`},
                        `func(rune) rune`,
                },
-               {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`,
+               {`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
                        `f`,
                        []string{`complex128`},
                        `func(...complex128) complex128`,
                },
-               {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
+               {`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
                        `f`,
                        []string{`float64`, `string`, `byte`},
                        `func(float64, *string, []byte)`,
                },
-               {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
+               {`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
                        `f`,
                        []string{`float64`, `byte`},
                        `func(float64, *byte, ...[]byte)`,
                },
 
-               {genericPkg + `s1; func f[T any, P interface{~*T}](x T); func _(x string) { f(x) }`,
+               {`package s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`,
                        `f`,
                        []string{`string`, `*string`},
                        `func(x string)`,
                },
-               {genericPkg + `s2; func f[T any, P interface{~*T}](x []T); func _(x []int) { f(x) }`,
+               {`package s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`,
                        `f`,
                        []string{`int`, `*int`},
                        `func(x []int)`,
                },
-               {genericPkg + `s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
+               {`package s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
                        `f`,
                        []string{`int`, `chan<- int`},
                        `func(x []int)`,
                },
-               {genericPkg + `s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`,
+               {`package s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
                        `f`,
                        []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
                        `func(x []int)`,
                },
 
-               {genericPkg + `t1; func f[T any, P interface{~*T}]() T; func _() { _ = f[string] }`,
+               {`package t1; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = f[string] }`,
+                       `f`,
+                       []string{`string`, `*string`},
+                       `func() string`,
+               },
+               {`package t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
                        `f`,
                        []string{`string`, `*string`},
                        `func() string`,
                },
-               {genericPkg + `t2; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
+               {`package t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T { return nil }; func _() { _ = f[int] }`,
                        `f`,
                        []string{`int`, `chan<- int`},
                        `func() []int`,
                },
-               {genericPkg + `t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
+               {`package t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
                        `f`,
                        []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
                        `func() []int`,
                },
+               {`package i0; import "lib"; func _() { lib.F(42) }`,
+                       `F`,
+                       []string{`int`},
+                       `func(int)`,
+               },
+               {`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
+                       `T`,
+                       []string{`int`},
+                       `struct{x int}`,
+               },
+               {`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
+                       `T`,
+                       []string{`[]int`, `int`},
+                       `struct{x []int; y int}`,
+               },
+               {`package type4; import "lib"; var _ lib.T[int]`,
+                       `T`,
+                       []string{`int`},
+                       `[]int`,
+               },
        }
 
        for _, test := range tests {
-               info := Info{}
-               info.Inferred = make(map[ast.Expr]Inferred)
-               name, err := mayTypecheck(t, "InferredInfo", test.src, &info)
-               if err != nil {
-                       t.Errorf("package %s: %v", name, err)
-                       continue
+               const lib = `package lib
+
+func F[P any](P) {}
+
+type T[P any] []P
+`
+
+               imports := make(testImporter)
+               conf := Config{Importer: imports}
+               instances := make(map[*ast.Ident]Instance)
+               uses := make(map[*ast.Ident]Object)
+               makePkg := func(src string) *Package {
+                       f, err := parser.ParseFile(fset, "p.go", src, 0)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       pkg, err := conf.Check("", fset, []*ast.File{f}, &Info{Instances: instances, Uses: uses})
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       imports[pkg.Name()] = pkg
+                       return pkg
                }
+               makePkg(lib)
+               pkg := makePkg(test.src)
 
-               // look for inferred type arguments and signature
+               // look for instance information
                var targs []Type
-               var sig *Signature
-               for call, inf := range info.Inferred {
-                       var fun ast.Expr
-                       switch x := call.(type) {
-                       case *ast.CallExpr:
-                               fun = x.Fun
-                       case *ast.IndexExpr:
-                               fun = x.X
-                       default:
-                               panic(fmt.Sprintf("unexpected call expression type %T", call))
-                       }
-                       if ExprString(fun) == test.fun {
-                               targs = inf.TArgs
-                               sig = inf.Sig
+               var typ Type
+               for ident, inst := range instances {
+                       if ExprString(ident) == test.name {
+                               for i := 0; i < inst.TypeArgs.Len(); i++ {
+                                       targs = append(targs, inst.TypeArgs.At(i))
+                               }
+                               typ = inst.Type
+
+                               // Check that we can find the corresponding parameterized type.
+                               ptype := uses[ident].Type()
+                               lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
+                               if lister == nil || lister.TypeParams().Len() == 0 {
+                                       t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
+                                       continue
+                               }
+
+                               // Verify the invariant that re-instantiating the generic type with
+                               // TypeArgs results in an equivalent type.
+                               inst2, err := Instantiate(nil, ptype, targs, true)
+                               if err != nil {
+                                       t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
+                               }
+                               if !Identical(inst.Type, inst2) {
+                                       t.Errorf("%v and %v are not identical", inst.Type, inst2)
+                               }
                                break
                        }
                }
                if targs == nil {
-                       t.Errorf("package %s: no inferred information found for %s", name, test.fun)
+                       t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
                        continue
                }
 
                // check that type arguments are correct
                if len(targs) != len(test.targs) {
-                       t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs))
+                       t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
                        continue
                }
                for i, targ := range targs {
                        if got := targ.String(); got != test.targs[i] {
-                               t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i])
+                               t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
                                continue
                        }
                }
 
-               // check that signature is correct
-               if got := sig.String(); got != test.sig {
-                       t.Errorf("package %s: got %s; want %s", name, got, test.sig)
+               // check that the types match
+               if got := typ.Underlying().String(); got != test.typ {
+                       t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
                }
        }
 }
@@ -533,13 +604,6 @@ func TestDefsInfo(t *testing.T) {
                {`package p3; type x int`, `x`, `type p3.x int`},
                {`package p4; func f()`, `f`, `func p4.f()`},
                {`package p5; func f() int { x, _ := 1, 2; return x }`, `_`, `var _ int`},
-
-               // generic types must be sanitized
-               // (need to use sufficiently nested types to provoke unexpanded types)
-               {genericPkg + `g0; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
-               {genericPkg + `g1; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
-               {genericPkg + `g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
-               {genericPkg + `g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var generic_g3.g func(x struct{f generic_g3.t[string]})`},
        }
 
        for _, test := range tests {
@@ -578,13 +642,6 @@ func TestUsesInfo(t *testing.T) {
                {`package p2; func _() { _ = x }; var x int`, `x`, `var p2.x int`},
                {`package p3; func _() { type _ x }; type x int`, `x`, `type p3.x int`},
                {`package p4; func _() { _ = f }; func f()`, `f`, `func p4.f()`},
-
-               // generic types must be sanitized
-               // (need to use sufficiently nested types to provoke unexpanded types)
-               {genericPkg + `g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
-               {genericPkg + `g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
-               {genericPkg + `g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
-               {genericPkg + `g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func generic_g3.f(x struct{f generic_g3.t[string]})`},
        }
 
        for _, test := range tests {
@@ -1546,6 +1603,13 @@ func F(){
        }
 }
 
+// newDefined creates a new defined type named T with the given underlying type.
+// Helper function for use with TestIncompleteInterfaces only.
+func newDefined(underlying Type) *Named {
+       tname := NewTypeName(token.NoPos, nil, "T", nil)
+       return NewNamed(tname, underlying, nil)
+}
+
 func TestConvertibleTo(t *testing.T) {
        for _, test := range []struct {
                v, t Type
@@ -1553,6 +1617,7 @@ func TestConvertibleTo(t *testing.T) {
        }{
                {Typ[Int], Typ[Int], true},
                {Typ[Int], Typ[Float32], true},
+               {Typ[Int], Typ[String], true},
                {newDefined(Typ[Int]), Typ[Int], true},
                {newDefined(new(Struct)), new(Struct), true},
                {newDefined(Typ[Int]), new(Struct), false},
@@ -1560,8 +1625,7 @@ func TestConvertibleTo(t *testing.T) {
                {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
                {NewSlice(Typ[Int]), NewArray(Typ[Int], 10), false},
                {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
-               // Untyped string values are not permitted by the spec, so the below
-               // behavior is undefined.
+               // Untyped string values are not permitted by the spec, so the behavior below is undefined.
                {Typ[UntypedString], Typ[String], true},
        } {
                if got := ConvertibleTo(test.v, test.t); got != test.want {
@@ -1610,6 +1674,48 @@ func TestIdentical_issue15173(t *testing.T) {
        }
 }
 
+func TestIdenticalUnions(t *testing.T) {
+       tname := NewTypeName(token.NoPos, nil, "myInt", nil)
+       myInt := NewNamed(tname, Typ[Int], nil)
+       tmap := map[string]*Term{
+               "int":     NewTerm(false, Typ[Int]),
+               "~int":    NewTerm(true, Typ[Int]),
+               "string":  NewTerm(false, Typ[String]),
+               "~string": NewTerm(true, Typ[String]),
+               "myInt":   NewTerm(false, myInt),
+       }
+       makeUnion := func(s string) *Union {
+               parts := strings.Split(s, "|")
+               var terms []*Term
+               for _, p := range parts {
+                       term := tmap[p]
+                       if term == nil {
+                               t.Fatalf("missing term %q", p)
+                       }
+                       terms = append(terms, term)
+               }
+               return NewUnion(terms)
+       }
+       for _, test := range []struct {
+               x, y string
+               want bool
+       }{
+               // These tests are just sanity checks. The tests for type sets and
+               // interfaces provide much more test coverage.
+               {"int|~int", "~int", true},
+               {"myInt|~int", "~int", true},
+               {"int|string", "string|int", true},
+               {"int|int|string", "string|int", true},
+               {"myInt|string", "int|string", false},
+       } {
+               x := makeUnion(test.x)
+               y := makeUnion(test.y)
+               if got := Identical(x, y); got != test.want {
+                       t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
+               }
+       }
+}
+
 func TestIssue15305(t *testing.T) {
        const src = "package p; func f() int16; var _ = f(undef)"
        fset := token.NewFileSet()
@@ -1840,17 +1946,96 @@ func TestInstantiate(t *testing.T) {
 
        // type T should have one type parameter
        T := pkg.Scope().Lookup("T").Type().(*Named)
-       if n := T.TParams().Len(); n != 1 {
+       if n := T.TypeParams().Len(); n != 1 {
                t.Fatalf("expected 1 type parameter; found %d", n)
        }
 
        // instantiation should succeed (no endless recursion)
        // even with a nil *Checker
-       var check *Checker
-       res := check.Instantiate(token.NoPos, T, []Type{Typ[Int]}, nil, false)
+       res, err := Instantiate(nil, T, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
 
        // instantiated type should point to itself
-       if res.Underlying().(*Pointer).Elem() != res {
-               t.Fatalf("unexpected result type: %s", res)
+       if p := res.Underlying().(*Pointer).Elem(); p != res {
+               t.Fatalf("unexpected result type: %s points to %s", res, p)
+       }
+}
+
+func TestInstantiateErrors(t *testing.T) {
+       tests := []struct {
+               src    string // by convention, T must be the type being instantiated
+               targs  []Type
+               wantAt int // -1 indicates no error
+       }{
+               {"type T[P interface{~string}] int", []Type{Typ[Int]}, 0},
+               {"type T[P1 interface{int}, P2 interface{~string}] int", []Type{Typ[Int], Typ[Int]}, 1},
+               {"type T[P1 any, P2 interface{~[]P1}] int", []Type{Typ[Int], NewSlice(Typ[String])}, 1},
+               {"type T[P1 interface{~[]P2}, P2 any] int", []Type{NewSlice(Typ[String]), Typ[Int]}, 0},
+       }
+
+       for _, test := range tests {
+               src := genericPkg + "p; " + test.src
+               pkg, err := pkgFor(".", src, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               T := pkg.Scope().Lookup("T").Type().(*Named)
+
+               _, err = Instantiate(nil, T, test.targs, true)
+               if err == nil {
+                       t.Fatalf("Instantiate(%v, %v) returned nil error, want non-nil", T, test.targs)
+               }
+
+               var argErr *ArgumentError
+               if !errors.As(err, &argErr) {
+                       t.Fatalf("Instantiate(%v, %v): error is not an *ArgumentError", T, test.targs)
+               }
+
+               if argErr.Index != test.wantAt {
+                       t.Errorf("Instantate(%v, %v): error at index %d, want index %d", T, test.targs, argErr.Index, test.wantAt)
+               }
+       }
+}
+
+func TestArgumentErrorUnwrapping(t *testing.T) {
+       var err error = &ArgumentError{
+               Index: 1,
+               Err:   Error{Msg: "test"},
+       }
+       var e Error
+       if !errors.As(err, &e) {
+               t.Fatalf("error %v does not wrap types.Error", err)
+       }
+       if e.Msg != "test" {
+               t.Errorf("e.Msg = %q, want %q", e.Msg, "test")
+       }
+}
+
+func TestInstanceIdentity(t *testing.T) {
+       imports := make(testImporter)
+       conf := Config{Importer: imports}
+       makePkg := func(src string) {
+               fset := token.NewFileSet()
+               f, err := parser.ParseFile(fset, "", src, 0)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               name := f.Name.Name
+               pkg, err := conf.Check(name, fset, []*ast.File{f}, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               imports[name] = pkg
+       }
+       makePkg(genericPkg + `lib; type T[P any] struct{}`)
+       makePkg(genericPkg + `a; import "generic_lib"; var A generic_lib.T[int]`)
+       makePkg(genericPkg + `b; import "generic_lib"; var B generic_lib.T[int]`)
+       a := imports["generic_a"].Scope().Lookup("A")
+       b := imports["generic_b"].Scope().Lookup("B")
+       if !Identical(a.Type(), b.Type()) {
+               t.Errorf("mismatching types: a.A: %s, b.B: %s", a.Type(), b.Type())
        }
 }
index 595f426e1090a209c589edb80f305bd0ab146a68..2810133a1f93bcc53b7641069b30ab4206eac548 100644 (file)
@@ -71,7 +71,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
        }
 
        // A generic (non-instantiated) function value cannot be assigned to a variable.
-       if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
+       if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
                check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context)
        }
 
@@ -237,6 +237,7 @@ func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnPos token.P
        if len(lhs) != len(rhs) {
                // invalidate lhs
                for _, obj := range lhs {
+                       obj.used = true // avoid declared but not used errors
                        if obj.typ == nil {
                                obj.typ = Typ[Invalid]
                        }
index c73d94658ab263678920d902e47c48faefdb42e2..aefac786cafd96d8c8549e1a9b78e15887662c22 100644 (file)
@@ -47,7 +47,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
        default:
                // make argument getter
                xlist, _ := check.exprList(call.Args, false)
-               arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) }
+               arg = func(x *operand, i int) { *x = *xlist[i] }
                nargs = len(xlist)
                // evaluate first argument, if present
                if nargs > 0 {
@@ -83,7 +83,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                // of S and the respective parameter passing rules apply."
                S := x.typ
                var T Type
-               if s := asSlice(S); s != nil {
+               if s, _ := structure(S).(*Slice); s != nil {
                        T = s.elem
                } else {
                        check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
@@ -145,7 +145,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                mode := invalid
                var typ Type
                var val constant.Value
-               switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) {
+               switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) {
                case *Basic:
                        if isString(t) && id == _Len {
                                if x.mode == constant_ {
@@ -179,9 +179,9 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                                mode = value
                        }
 
-               case *Union:
+               case *TypeParam:
                        if t.underIs(func(t Type) bool {
-                               switch t := t.(type) {
+                               switch t := arrayPtrDeref(t).(type) {
                                case *Basic:
                                        if isString(t) && id == _Len {
                                                return true
@@ -296,8 +296,10 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                }
 
                // the argument types must be of floating-point type
-               f := func(x Type) Type {
-                       if t := asBasic(x); t != nil {
+               // (applyTypeFunc never calls f with a type parameter)
+               f := func(typ Type) Type {
+                       assert(asTypeParam(typ) == nil)
+                       if t := asBasic(typ); t != nil {
                                switch t.kind {
                                case Float32:
                                        return Typ[Complex64]
@@ -330,35 +332,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
 
        case _Copy:
                // copy(x, y []T) int
-               var dst Type
-               if t := asSlice(x.typ); t != nil {
-                       dst = t.elem
-               }
+               dst, _ := structure(x.typ).(*Slice)
 
                var y operand
                arg(&y, 1)
                if y.mode == invalid {
                        return
                }
-               var src Type
-               switch t := under(y.typ).(type) {
-               case *Basic:
-                       if isString(y.typ) {
-                               src = universeByte
-                       }
-               case *Slice:
-                       src = t.elem
-               case *TypeParam:
-                       check.error(x, _Todo, "copy on generic operands not yet implemented")
-               }
+               src, _ := structureString(y.typ).(*Slice)
 
                if dst == nil || src == nil {
                        check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
                        return
                }
 
-               if !Identical(dst, src) {
-                       check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+               if !Identical(dst.elem, src.elem) {
+                       check.errorf(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)
                        return
                }
 
@@ -431,8 +420,10 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                }
 
                // the argument must be of complex type
-               f := func(x Type) Type {
-                       if t := asBasic(x); t != nil {
+               // (applyTypeFunc never calls f with a type parameter)
+               f := func(typ Type) Type {
+                       assert(asTypeParam(typ) == nil)
+                       if t := asBasic(typ); t != nil {
                                switch t.kind {
                                case Complex64:
                                        return Typ[Float32]
@@ -481,39 +472,21 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        return
                }
 
-               min, max := -1, 10
-               var valid func(t Type) bool
-               valid = func(t Type) bool {
-                       var m int
-                       switch t := under(t).(type) {
-                       case *Slice:
-                               m = 2
-                       case *Map, *Chan:
-                               m = 1
-                       case *TypeParam:
-                               return t.underIs(valid)
-                       default:
-                               return false
-                       }
-                       if m > min {
-                               min = m
-                       }
-                       if m+1 < max {
-                               max = m + 1
-                       }
-                       return true
-               }
-
-               if !valid(T) {
+               var min int // minimum number of arguments
+               switch structure(T).(type) {
+               case *Slice:
+                       min = 2
+               case *Map, *Chan:
+                       min = 1
+               case nil:
+                       check.errorf(arg0, _InvalidMake, "cannot make %s; type set has no single underlying type", arg0)
+                       return
+               default:
                        check.invalidArg(arg0, _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
                        return
                }
-               if nargs < min || max < nargs {
-                       if min == max {
-                               check.errorf(call, _WrongArgCount, "%v expects %d arguments; found %d", call, min, nargs)
-                       } else {
-                               check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, max, nargs)
-                       }
+               if nargs < min || min+1 < nargs {
+                       check.invalidOp(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
                        return
                }
 
@@ -689,6 +662,15 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)?
                check.recordSelection(selx, FieldVal, base, obj, index, false)
 
+               // record the selector expression (was bug - issue #47895)
+               {
+                       mode := value
+                       if x.mode == variable || indirect {
+                               mode = variable
+                       }
+                       check.record(&operand{mode, selx, obj.Type(), nil, 0})
+               }
+
                // The field offset is considered a variable even if the field is declared before
                // the part of the struct which is variable-sized. This makes both the rules
                // simpler and also permits (or at least doesn't prevent) a compiler from re-
@@ -781,7 +763,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                var t operand
                x1 := x
                for _, arg := range call.Args {
-                       check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+                       check.rawExpr(x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T))
                        check.dump("%v: %s", x1.Pos(), x1)
                        x1 = &t // use incoming x only for first argument
                }
@@ -794,6 +776,46 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
        return true
 }
 
+// If typ is a type parameter, structure returns the single underlying
+// type of all types in the corresponding type constraint if it exists,
+// or nil otherwise. If typ is not a type parameter, structure returns
+// the underlying type.
+func structure(typ Type) Type {
+       var su Type
+       if underIs(typ, func(u Type) bool {
+               if su != nil && !Identical(su, u) {
+                       return false
+               }
+               // su == nil || Identical(su, u)
+               su = u
+               return true
+       }) {
+               return su
+       }
+       return nil
+}
+
+// structureString is like structure but also considers []byte and
+// string as "identical". In this case, if successful, the result
+// is always []byte.
+func structureString(typ Type) Type {
+       var su Type
+       if underIs(typ, func(u Type) bool {
+               if isString(u) {
+                       u = NewSlice(universeByte)
+               }
+               if su != nil && !Identical(su, u) {
+                       return false
+               }
+               // su == nil || Identical(su, u)
+               su = u
+               return true
+       }) {
+               return su
+       }
+       return nil
+}
+
 // hasVarSize reports if the size of type t is variable due to type parameters.
 func hasVarSize(t Type) bool {
        switch t := under(t).(type) {
@@ -807,7 +829,7 @@ func hasVarSize(t Type) bool {
                }
        case *TypeParam:
                return true
-       case *Named, *Union, *top:
+       case *Named, *Union:
                unreachable()
        }
        return false
@@ -824,12 +846,13 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
        if tp := asTypeParam(x); tp != nil {
                // Test if t satisfies the requirements for the argument
                // type and collect possible result types at the same time.
-               var rtypes []Type
-               var tildes []bool
-               if !tp.iface().is(func(typ Type, tilde bool) bool {
-                       if r := f(typ); r != nil {
-                               rtypes = append(rtypes, r)
-                               tildes = append(tildes, tilde)
+               var terms []*Term
+               if !tp.is(func(t *term) bool {
+                       if t == nil {
+                               return false
+                       }
+                       if r := f(t.typ); r != nil {
+                               terms = append(terms, NewTerm(t.tilde, r))
                                return true
                        }
                        return false
@@ -837,14 +860,12 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
                        return nil
                }
 
-               // Construct a suitable new type parameter for the sum type. The
-               // type param is placed in the current package so export/import
+               // Construct a suitable new type parameter for the result type.
+               // The type parameter is placed in the current package so export/import
                // works as expected.
                tpar := NewTypeName(token.NoPos, check.pkg, "<type parameter>", nil)
-               ptyp := check.NewTypeParam(tpar, &emptyInterface) // assigns type to tpar as a side-effect
+               ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
                ptyp.index = tp.index
-               tsum := newUnion(rtypes, tildes)
-               ptyp.bound = &Interface{complete: true, tset: &_TypeSet{types: tsum}}
 
                return ptyp
        }
@@ -868,10 +889,9 @@ func makeSig(res Type, args ...Type) *Signature {
        return &Signature{params: params, results: result}
 }
 
-// implicitArrayDeref returns A if typ is of the form *A and A is an array;
+// arrayPtrDeref returns A if typ is of the form *A and A is an array;
 // otherwise it returns typ.
-//
-func implicitArrayDeref(typ Type) Type {
+func arrayPtrDeref(typ Type) Type {
        if p, ok := typ.(*Pointer); ok {
                if a := asArray(p.base); a != nil {
                        return a
index cee3d315e592f621b3ce2dbc5d87fa90ee439515..edcd7e7724a1aaf12802594ed6a8b29985eef771 100644 (file)
@@ -113,15 +113,15 @@ var builtinCalls = []struct {
 
        {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
        {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
-       {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(p.P₁) uintptr`},
+       {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(P) uintptr`},
 
        {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
        {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
-       {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(p.P₁) uintptr`},
+       {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(P) uintptr`},
 
        {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
        {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
-       {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(p.P₁) uintptr`},
+       {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(P) uintptr`},
 
        {"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
        {"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
index da2f319a4a718975a92ca79261781064b0328d8e..a7024f5f9c5c6baa3dfb311f89fdb0b4b693f233 100644 (file)
@@ -17,6 +17,10 @@ import (
 // funcInst type-checks a function instantiation inst and returns the result in x.
 // The operand x must be the evaluation of inst.X and its type must be a signature.
 func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
+       if !check.allowVersion(check.pkg, 1, 18) {
+               check.softErrorf(inNode(ix.Orig, ix.Lbrack), _Todo, "function instantiation requires go1.18 or later")
+       }
+
        targs := check.typeList(ix.Indices)
        if targs == nil {
                x.mode = invalid
@@ -27,7 +31,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
 
        // check number of type arguments (got) vs number of type parameters (want)
        sig := x.typ.(*Signature)
-       got, want := len(targs), sig.TParams().Len()
+       got, want := len(targs), sig.TypeParams().Len()
        if got > want {
                check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want)
                x.mode = invalid
@@ -35,11 +39,8 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
                return
        }
 
-       // if we don't have enough type arguments, try type inference
-       inferred := false
-
        if got < want {
-               targs = check.infer(ix.Orig, sig.TParams().list(), targs, nil, nil, true)
+               targs = check.infer(ix.Orig, sig.TypeParams().list(), targs, nil, nil)
                if targs == nil {
                        // error was already reported
                        x.mode = invalid
@@ -47,7 +48,6 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
                        return
                }
                got = len(targs)
-               inferred = true
        }
        assert(got == want)
 
@@ -60,16 +60,44 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
        }
 
        // instantiate function signature
-       res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature)
-       assert(res.TParams().Len() == 0) // signature is not generic anymore
-       if inferred {
-               check.recordInferred(ix.Orig, targs, res)
-       }
+       res := check.instantiateSignature(x.Pos(), sig, targs, poslist)
+       assert(res.TypeParams().Len() == 0) // signature is not generic anymore
+       check.recordInstance(ix.Orig, targs, res)
        x.typ = res
        x.mode = value
        x.expr = ix.Orig
 }
 
+func (check *Checker) instantiateSignature(pos token.Pos, typ *Signature, targs []Type, posList []token.Pos) (res *Signature) {
+       assert(check != nil)
+       assert(len(targs) == typ.TypeParams().Len())
+
+       if trace {
+               check.trace(pos, "-- instantiating %s with %s", typ, targs)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(pos, "=> %s (under = %s)", res, res.Underlying())
+               }()
+       }
+
+       inst := check.instance(pos, typ, targs, check.conf.Context).(*Signature)
+       assert(len(posList) <= len(targs))
+       tparams := typ.TypeParams().list()
+       if i, err := check.verify(pos, tparams, targs); err != nil {
+               // best position for error reporting
+               pos := pos
+               if i < len(posList) {
+                       pos = posList[i]
+               }
+               check.softErrorf(atPos(pos), _Todo, err.Error())
+       } else {
+               check.mono.recordInstance(check.pkg, pos, tparams, targs, posList)
+       }
+
+       return inst
+}
+
 func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
        ix := typeparams.UnpackIndexExpr(call.Fun)
        if ix != nil {
@@ -85,8 +113,9 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
                check.record(x)
 
        } else {
-               check.exprOrType(x, call.Fun)
+               check.exprOrType(x, call.Fun, true)
        }
+       // x.typ may be generic
 
        switch x.mode {
        case invalid:
@@ -96,6 +125,10 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
 
        case typexpr:
                // conversion
+               check.nonGeneric(x)
+               if x.mode == invalid {
+                       return conversion
+               }
                T := x.typ
                x.mode = invalid
                switch n := len(call.Args); n {
@@ -109,8 +142,8 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
                                        break
                                }
                                if t := asInterface(T); t != nil {
-                                       if t.IsConstraint() {
-                                               check.errorf(call, _Todo, "cannot use interface %s in conversion (contains type list or is comparable)", T)
+                                       if !t.IsMethodSet() {
+                                               check.errorf(call, _Todo, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
                                                break
                                        }
                                }
@@ -124,6 +157,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
                return conversion
 
        case builtin:
+               // no need to check for non-genericity here
                id := x.id
                if !check.builtin(x, call, id) {
                        x.mode = invalid
@@ -137,9 +171,11 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
        }
 
        // ordinary function/method call
+       // signature may be generic
        cgocall := x.mode == cgofunc
 
-       sig := asSignature(x.typ)
+       // a type parameter may be "called" if all types have the same signature
+       sig, _ := structure(x.typ).(*Signature)
        if sig == nil {
                check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
                x.mode = invalid
@@ -160,7 +196,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
                assert(len(targs) == len(ix.Indices))
 
                // check number of type arguments (got) vs number of type parameters (want)
-               got, want := len(targs), sig.TParams().Len()
+               got, want := len(targs), sig.TypeParams().Len()
                if got > want {
                        check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want)
                        check.use(call.Args...)
@@ -172,8 +208,14 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
 
        // evaluate arguments
        args, _ := check.exprList(call.Args, false)
+       isGeneric := sig.TypeParams().Len() > 0
        sig = check.arguments(call, sig, targs, args)
 
+       if isGeneric && sig.TypeParams().Len() == 0 {
+               // Update the recorded type of call.Fun to its instantiated type.
+               check.recordTypeAndValue(call.Fun, value, sig, nil)
+       }
+
        // determine result
        switch sig.results.Len() {
        case 0:
@@ -194,7 +236,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
 
        // if type inference failed, a parametrized result must be invalidated
        // (operands cannot have a parametrized type)
-       if x.mode == value && sig.TParams().Len() > 0 && isParameterized(sig.TParams().list(), x.typ) {
+       if x.mode == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ) {
                x.mode = invalid
        }
 
@@ -223,7 +265,6 @@ func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*op
                // exactly one (possibly invalid or comma-ok) value
                xlist = []*operand{&x}
                if allowCommaOk && (x.mode == mapindex || x.mode == commaok || x.mode == commaerr) {
-                       x.mode = value
                        x2 := &operand{mode: value, expr: e, typ: Typ[UntypedBool]}
                        if x.mode == commaerr {
                                x2.typ = universeError
@@ -324,32 +365,44 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
        }
 
        // infer type arguments and instantiate signature if necessary
-       if sig.TParams().Len() > 0 {
+       if sig.TypeParams().Len() > 0 {
+               if !check.allowVersion(check.pkg, 1, 18) {
+                       switch call.Fun.(type) {
+                       case *ast.IndexExpr, *ast.IndexListExpr:
+                               ix := typeparams.UnpackIndexExpr(call.Fun)
+                               check.softErrorf(inNode(call.Fun, ix.Lbrack), _Todo, "function instantiation requires go1.18 or later")
+                       default:
+                               check.softErrorf(inNode(call, call.Lparen), _Todo, "implicit function instantiation requires go1.18 or later")
+                       }
+               }
                // TODO(gri) provide position information for targs so we can feed
                //           it to the instantiate call for better error reporting
-               targs := check.infer(call, sig.TParams().list(), targs, sigParams, args, true)
+               targs := check.infer(call, sig.TypeParams().list(), targs, sigParams, args)
                if targs == nil {
                        return // error already reported
                }
 
                // compute result signature
-               rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature)
-               assert(rsig.TParams().Len() == 0) // signature is not generic anymore
-               check.recordInferred(call, targs, rsig)
+               rsig = check.instantiateSignature(call.Pos(), sig, targs, nil)
+               assert(rsig.TypeParams().Len() == 0) // signature is not generic anymore
+               check.recordInstance(call.Fun, targs, rsig)
 
                // Optimization: Only if the parameter list was adjusted do we
                // need to compute it from the adjusted list; otherwise we can
                // simply use the result signature's parameter list.
                if adjusted {
-                       sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs)).(*Tuple)
+                       sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TypeParams().list(), targs), nil).(*Tuple)
                } else {
                        sigParams = rsig.params
                }
        }
 
        // check arguments
-       for i, a := range args {
-               check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun))
+       if len(args) > 0 {
+               context := check.sprintf("argument to %s", call.Fun)
+               for i, a := range args {
+                       check.assignment(a, sigParams.vars[i].typ, context)
+               }
        }
 
        return
@@ -463,13 +516,11 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
                }
        }
 
-       check.exprOrType(x, e.X)
+       check.exprOrType(x, e.X, false)
        if x.mode == invalid {
                goto Error
        }
 
-       check.instantiatedOperand(x)
-
        obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
        if obj == nil {
                switch {
@@ -512,54 +563,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
        // methods may not have a fully set up signature yet
        if m, _ := obj.(*Func); m != nil {
                check.objDecl(m, nil)
-               // If m has a parameterized receiver type, infer the type arguments from
-               // the actual receiver provided and then substitute the type parameters in
-               // the signature accordingly.
-               // TODO(gri) factor this code out
-               sig := m.typ.(*Signature)
-               if sig.RParams().Len() > 0 {
-                       // For inference to work, we must use the receiver type
-                       // matching the receiver in the actual method declaration.
-                       // If the method is embedded, the matching receiver is the
-                       // embedded struct or interface that declared the method.
-                       // Traverse the embedding to find that type (issue #44688).
-                       recv := x.typ
-                       for i := 0; i < len(index)-1; i++ {
-                               // The embedded type is either a struct or a pointer to
-                               // a struct except for the last one (which we don't need).
-                               recv = asStruct(derefStructPtr(recv)).Field(index[i]).typ
-                       }
-
-                       // The method may have a pointer receiver, but the actually provided receiver
-                       // may be a (hopefully addressable) non-pointer value, or vice versa. Here we
-                       // only care about inferring receiver type parameters; to make the inference
-                       // work, match up pointer-ness of receiver and argument.
-                       if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(recv) {
-                               if ptrRecv {
-                                       recv = NewPointer(recv)
-                               } else {
-                                       recv = recv.(*Pointer).base
-                               }
-                       }
-                       // Disable reporting of errors during inference below. If we're unable to infer
-                       // the receiver type arguments here, the receiver must be be otherwise invalid
-                       // and an error has been reported elsewhere.
-                       arg := operand{mode: variable, expr: x.expr, typ: recv}
-                       targs := check.infer(m, sig.RParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */)
-                       if targs == nil {
-                               // We may reach here if there were other errors (see issue #40056).
-                               goto Error
-                       }
-                       // Don't modify m. Instead - for now - make a copy of m and use that instead.
-                       // (If we modify m, some tests will fail; possibly because the m is in use.)
-                       // TODO(gri) investigate and provide a correct explanation here
-                       copy := *m
-                       copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs))
-                       obj = &copy
-               }
-               // TODO(gri) we also need to do substitution for parameterized interface methods
-               //           (this breaks code in testdata/linalg.go2 at the moment)
-               //           12/20/2019: Is this TODO still correct?
        }
 
        if x.mode == typexpr {
@@ -705,7 +708,7 @@ func (check *Checker) use(arg ...ast.Expr) {
                // The nil check below is necessary since certain AST fields
                // may legally be nil (e.g., the ast.SliceExpr.High field).
                if e != nil {
-                       check.rawExpr(&x, e, nil)
+                       check.rawExpr(&x, e, nil, false)
                }
        }
 }
@@ -737,17 +740,9 @@ func (check *Checker) useLHS(arg ...ast.Expr) {
                                }
                        }
                }
-               check.rawExpr(&x, e, nil)
+               check.rawExpr(&x, e, nil, false)
                if v != nil {
                        v.used = v_used // restore v.used
                }
        }
 }
-
-// instantiatedOperand reports an error of x is an uninstantiated (generic) type and sets x.typ to Typ[Invalid].
-func (check *Checker) instantiatedOperand(x *operand) {
-       if x.mode == typexpr && isGeneric(x.typ) {
-               check.errorf(x, _Todo, "cannot use generic type %s without instantiation", x.typ)
-               x.typ = Typ[Invalid]
-       }
-}
index b2d076dc680fc7456e8aff21c62d4c3ba01c6287..3a0e4a6a234ee564e9ff1af1b0fa4686391836d0 100644 (file)
@@ -76,6 +76,28 @@ type dotImportKey struct {
        name  string
 }
 
+// An action describes a (delayed) action.
+type action struct {
+       f    func()      // action to be executed
+       desc *actionDesc // action description; may be nil, requires debug to be set
+}
+
+// If debug is set, describef sets a printf-formatted description for action a.
+// Otherwise, it is a no-op.
+func (a *action) describef(pos positioner, format string, args ...interface{}) {
+       if debug {
+               a.desc = &actionDesc{pos, format, args}
+       }
+}
+
+// An actionDesc provides information on an action.
+// For debugging only.
+type actionDesc struct {
+       pos    positioner
+       format string
+       args   []interface{}
+}
+
 // A Checker maintains the state of the type checker.
 // It must be created with NewChecker.
 type Checker struct {
@@ -89,7 +111,6 @@ type Checker struct {
        nextID  uint64                 // unique Id for type parameters (first valid Id is 1)
        objMap  map[Object]*declInfo   // maps package-level objects and (non-interface) methods to declaration info
        impMap  map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
-       typMap  map[string]*Named      // maps an instantiated named type hash to a *Named type
 
        // pkgPathMap maps package names to the set of distinct import paths we've
        // seen for that name, anywhere in the import graph. It is used for
@@ -104,15 +125,18 @@ type Checker struct {
        // information collected during type-checking of a set of package files
        // (initialized by Files, valid only for the duration of check.Files;
        // maps and lists are allocated on demand)
-       files        []*ast.File               // package files
-       imports      []*PkgName                // list of imported packages
-       dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
+       files         []*ast.File               // package files
+       imports       []*PkgName                // list of imported packages
+       dotImportMap  map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
+       recvTParamMap map[*ast.Ident]*TypeParam // maps blank receiver type parameters to their type
+       mono          monoGraph                 // graph for detecting non-monomorphizable instantiation loops
 
        firstErr error                 // first error encountered
        methods  map[*TypeName][]*Func // maps package scope type names to associated non-blank (non-interface) methods
        untyped  map[ast.Expr]exprInfo // map of expressions without final type
-       delayed  []func()              // stack of delayed action segments; segments are processed in FIFO order
+       delayed  []action              // stack of delayed action segments; segments are processed in FIFO order
        objPath  []Object              // path of object dependencies during type inference (for cycle reporting)
+       defTypes []*Named              // defined types created during type checking, for final validation.
 
        // context within which the current object is type-checked
        // (valid only for the duration of type-checking a specific object)
@@ -147,8 +171,12 @@ func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, ty
 // either at the end of the current statement, or in case of a local constant
 // or variable declaration, before the constant or variable is in scope
 // (so that f still sees the scope before any new declarations).
-func (check *Checker) later(f func()) {
-       check.delayed = append(check.delayed, f)
+// later returns the pushed action so one can provide a description
+// via action.describef for debugging, if desired.
+func (check *Checker) later(f func()) *action {
+       i := len(check.delayed)
+       check.delayed = append(check.delayed, action{f: f})
+       return &check.delayed[i]
 }
 
 // push pushes obj onto the object path and returns its index in the path.
@@ -174,6 +202,11 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
                conf = new(Config)
        }
 
+       // make sure we have a context
+       if conf.Context == nil {
+               conf.Context = NewContext()
+       }
+
        // make sure we have an info struct
        if info == nil {
                info = new(Info)
@@ -192,7 +225,6 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
                version: version,
                objMap:  make(map[Object]*declInfo),
                impMap:  make(map[importKey]*Package),
-               typMap:  make(map[string]*Named),
        }
 }
 
@@ -265,6 +297,8 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
 
        check.processDelayed(0) // incl. all functions
 
+       check.expandDefTypes()
+
        check.initOrder()
 
        if !check.conf.DisableUnusedImportCheck {
@@ -273,6 +307,11 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
 
        check.recordUntyped()
 
+       if check.firstErr == nil {
+               // TODO(mdempsky): Ensure monomorph is safe when errors exist.
+               check.monomorph()
+       }
+
        check.pkg.complete = true
 
        // no longer needed - release memory
@@ -280,6 +319,8 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
        check.dotImportMap = nil
        check.pkgPathMap = nil
        check.seenPkgMap = nil
+       check.recvTParamMap = nil
+       check.defTypes = nil
 
        // TODO(rFindley) There's more memory we should release at this point.
 
@@ -295,12 +336,40 @@ func (check *Checker) processDelayed(top int) {
        // add more actions (such as nested functions), so
        // this is a sufficiently bounded process.
        for i := top; i < len(check.delayed); i++ {
-               check.delayed[i]() // may append to check.delayed
+               a := &check.delayed[i]
+               if trace && a.desc != nil {
+                       fmt.Println()
+                       check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
+               }
+               a.f() // may append to check.delayed
        }
        assert(top <= len(check.delayed)) // stack must not have shrunk
        check.delayed = check.delayed[:top]
 }
 
+func (check *Checker) expandDefTypes() {
+       // Ensure that every defined type created in the course of type-checking has
+       // either non-*Named underlying, or is unresolved.
+       //
+       // This guarantees that we don't leak any types whose underlying is *Named,
+       // because any unresolved instances will lazily compute their underlying by
+       // substituting in the underlying of their origin. The origin must have
+       // either been imported or type-checked and expanded here, and in either case
+       // its underlying will be fully expanded.
+       for i := 0; i < len(check.defTypes); i++ {
+               n := check.defTypes[i]
+               switch n.underlying.(type) {
+               case nil:
+                       if n.resolver == nil {
+                               panic("nil underlying")
+                       }
+               case *Named:
+                       n.under() // n.under may add entries to check.defTypes
+               }
+               n.check = nil
+       }
+}
+
 func (check *Checker) record(x *operand) {
        // convert x into a user-friendly set of values
        // TODO(gri) this code can be simplified
@@ -403,12 +472,38 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
        }
 }
 
-func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) {
-       assert(call != nil)
-       assert(sig != nil)
-       if m := check.Info.Inferred; m != nil {
-               m[call] = Inferred{targs, sig}
+// recordInstance records instantiation information into check.Info, if the
+// Instances map is non-nil. The given expr must be an ident, selector, or
+// index (list) expr with ident or selector operand.
+//
+// TODO(rfindley): the expr parameter is fragile. See if we can access the
+// instantiated identifier in some other way.
+func (check *Checker) recordInstance(expr ast.Expr, targs []Type, typ Type) {
+       ident := instantiatedIdent(expr)
+       assert(ident != nil)
+       assert(typ != nil)
+       if m := check.Instances; m != nil {
+               m[ident] = Instance{NewTypeList(targs), typ}
+       }
+}
+
+func instantiatedIdent(expr ast.Expr) *ast.Ident {
+       var selOrIdent ast.Expr
+       switch e := expr.(type) {
+       case *ast.IndexExpr:
+               selOrIdent = e.X
+       case *ast.IndexListExpr:
+               selOrIdent = e.X
+       case *ast.SelectorExpr, *ast.Ident:
+               selOrIdent = e
+       }
+       switch x := selOrIdent.(type) {
+       case *ast.Ident:
+               return x
+       case *ast.SelectorExpr:
+               return x.Sel
        }
+       panic("instantiated ident not found")
 }
 
 func (check *Checker) recordDef(id *ast.Ident, obj Object) {
index 8c8452c9c683d26c478fcef3b6808560c87f978e..75b26e34bd266c203d0be58456ddcbd420a89e45 100644 (file)
@@ -20,9 +20,6 @@
 //             _ = x /* ERROR "not declared" */ + 1
 //     }
 
-// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
-//           and test against strict mode.
-
 package types_test
 
 import (
@@ -213,7 +210,7 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man
        }
 
        mode := parser.AllErrors
-       if !strings.HasSuffix(filenames[0], ".go2") {
+       if !strings.HasSuffix(filenames[0], ".go2") && !manual {
                mode |= typeparams.DisallowParsing
        }
 
@@ -362,6 +359,7 @@ func TestIssue47243_TypedRHS(t *testing.T) {
 }
 
 func TestCheck(t *testing.T)     { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", false) }
+func TestSpec(t *testing.T)      { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/spec", false) }
 func TestExamples(t *testing.T)  { testDirFiles(t, "testdata/examples", false) }
 func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", false) }
 
diff --git a/src/go/types/context.go b/src/go/types/context.go
new file mode 100644 (file)
index 0000000..99baad8
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2021 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 types
+
+import (
+       "bytes"
+       "strings"
+       "sync"
+)
+
+// An Context is an opaque type checking context. It may be used to share
+// identical type instances across type-checked packages or calls to
+// Instantiate.
+//
+// It is safe for concurrent use.
+type Context struct {
+       mu      sync.Mutex
+       typeMap map[string]*Named // type hash -> instance
+       nextID  int               // next unique ID
+       seen    map[*Named]int    // assigned unique IDs
+}
+
+// NewContext creates a new Context.
+func NewContext() *Context {
+       return &Context{
+               typeMap: make(map[string]*Named),
+               seen:    make(map[*Named]int),
+       }
+}
+
+// typeHash returns a string representation of typ, which can be used as an exact
+// type hash: types that are identical produce identical string representations.
+// If typ is a *Named type and targs is not empty, typ is printed as if it were
+// instantiated with targs. The result is guaranteed to not contain blanks (" ").
+func (ctxt *Context) typeHash(typ Type, targs []Type) string {
+       assert(ctxt != nil)
+       assert(typ != nil)
+       var buf bytes.Buffer
+
+       h := newTypeHasher(&buf, ctxt)
+       if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
+               // Don't use WriteType because we need to use the provided targs
+               // and not any targs that might already be with the *Named type.
+               h.typePrefix(named)
+               h.typeName(named.obj)
+               h.typeList(targs)
+       } else {
+               assert(targs == nil)
+               h.typ(typ)
+       }
+
+       return strings.Replace(buf.String(), " ", "#", -1) // ReplaceAll is not available in Go1.4
+}
+
+// typeForHash returns the recorded type for the type hash h, if it exists.
+// If no type exists for h and n is non-nil, n is recorded for h.
+func (ctxt *Context) typeForHash(h string, n *Named) *Named {
+       ctxt.mu.Lock()
+       defer ctxt.mu.Unlock()
+       if existing := ctxt.typeMap[h]; existing != nil {
+               return existing
+       }
+       if n != nil {
+               ctxt.typeMap[h] = n
+       }
+       return n
+}
+
+// idForType returns a unique ID for the pointer n.
+func (ctxt *Context) idForType(n *Named) int {
+       ctxt.mu.Lock()
+       defer ctxt.mu.Unlock()
+       id, ok := ctxt.seen[n]
+       if !ok {
+               id = ctxt.nextID
+               ctxt.seen[n] = id
+               ctxt.nextID++
+       }
+       return id
+}
index a1fcdd4fd8dfd5ddb8bc22c6e08d04f2ed4c8aeb..a6f0714ba034205bedc14afd9d3c6e7c5478d3e5 100644 (file)
@@ -16,31 +16,60 @@ import (
 func (check *Checker) conversion(x *operand, T Type) {
        constArg := x.mode == constant_
 
-       var ok bool
-       var reason string
-       switch {
-       case constArg && isConstType(T):
-               // constant conversion
+       constConvertibleTo := func(T Type, val *constant.Value) bool {
                switch t := asBasic(T); {
-               case representableConst(x.val, check, t, &x.val):
-                       ok = true
+               case t == nil:
+                       // nothing to do
+               case representableConst(x.val, check, t, val):
+                       return true
                case isInteger(x.typ) && isString(t):
                        codepoint := unicode.ReplacementChar
                        if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
                                codepoint = rune(i)
                        }
-                       x.val = constant.MakeString(string(codepoint))
-                       ok = true
+                       if val != nil {
+                               *val = constant.MakeString(string(codepoint))
+                       }
+                       return true
                }
-       case x.convertibleTo(check, T, &reason):
+               return false
+       }
+
+       var ok bool
+       var cause string
+       switch {
+       case constArg && isConstType(T):
+               // constant conversion
+               ok = constConvertibleTo(T, &x.val)
+       case constArg && isTypeParam(T):
+               // x is convertible to T if it is convertible
+               // to each specific type in the type set of T.
+               // If T's type set is empty, or if it doesn't
+               // have specific types, constant x cannot be
+               // converted.
+               ok = under(T).(*TypeParam).underIs(func(u Type) bool {
+                       // t is nil if there are no specific type terms
+                       if u == nil {
+                               cause = check.sprintf("%s does not contain specific types", T)
+                               return false
+                       }
+                       if !constConvertibleTo(u, nil) {
+                               cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
+                               return false
+                       }
+                       return true
+               })
+               x.mode = value // type parameters are not constants
+       case x.convertibleTo(check, T, &cause):
                // non-constant conversion
-               x.mode = value
                ok = true
+               x.mode = value
        }
 
        if !ok {
-               if reason != "" {
-                       check.errorf(x, _InvalidConversion, "cannot convert %s to %s (%s)", x, T, reason)
+               // TODO(rfindley): use types2-style error reporting here.
+               if cause != "" {
+                       check.errorf(x, _InvalidConversion, "cannot convert %s to %s (%s)", x, T, cause)
                } else {
                        check.errorf(x, _InvalidConversion, "cannot convert %s to %s", x, T)
                }
@@ -81,24 +110,81 @@ func (check *Checker) conversion(x *operand, T Type) {
 // is tricky because we'd have to run updateExprType on the argument first.
 // (Issue #21982.)
 
-// convertibleTo reports whether T(x) is valid.
+// convertibleTo reports whether T(x) is valid. In the failure case, *cause
+// may be set to the cause for the failure.
 // The check parameter may be nil if convertibleTo is invoked through an
 // exported API call, i.e., when all methods have been type-checked.
-func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
+func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
        // "x is assignable to T"
-       if ok, _ := x.assignableTo(check, T, nil); ok {
+       if ok, _ := x.assignableTo(check, T, cause); ok {
                return true
        }
 
-       // "x's type and T have identical underlying types if tags are ignored"
-       V := x.typ
+       // determine type parameter operands with specific type terms
+       Vp, _ := under(x.typ).(*TypeParam)
+       Tp, _ := under(T).(*TypeParam)
+       if Vp != nil && !Vp.hasTerms() {
+               Vp = nil
+       }
+       if Tp != nil && !Tp.hasTerms() {
+               Tp = nil
+       }
+
+       errorf := func(format string, args ...interface{}) {
+               if check != nil && cause != nil {
+                       msg := check.sprintf(format, args...)
+                       if *cause != "" {
+                               msg += "\n\t" + *cause
+                       }
+                       *cause = msg
+               }
+       }
+
+       // generic cases with specific type terms
+       // (generic operands cannot be constants, so we can ignore x.val)
+       switch {
+       case Vp != nil && Tp != nil:
+               return Vp.is(func(V *term) bool {
+                       return Tp.is(func(T *term) bool {
+                               if !convertibleToImpl(check, V.typ, T.typ, cause) {
+                                       errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
+                                       return false
+                               }
+                               return true
+                       })
+               })
+       case Vp != nil:
+               return Vp.is(func(V *term) bool {
+                       if !convertibleToImpl(check, V.typ, T, cause) {
+                               errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
+                               return false
+                       }
+                       return true
+               })
+       case Tp != nil:
+               return Tp.is(func(T *term) bool {
+                       if !convertibleToImpl(check, x.typ, T.typ, cause) {
+                               errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
+                               return false
+                       }
+                       return true
+               })
+       }
+
+       // non-generic case
+       return convertibleToImpl(check, x.typ, T, cause)
+}
+
+// convertibleToImpl should only be called by convertibleTo
+func convertibleToImpl(check *Checker, V, T Type, cause *string) bool {
+       // "V and T have identical underlying types if tags are ignored"
        Vu := under(V)
        Tu := under(T)
        if IdenticalIgnoreTags(Vu, Tu) {
                return true
        }
 
-       // "x's type and T are unnamed pointer types and their pointer base types
+       // "V and T are unnamed pointer types and their pointer base types
        // have identical underlying types if tags are ignored"
        if V, ok := V.(*Pointer); ok {
                if T, ok := T.(*Pointer); ok {
@@ -108,22 +194,22 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
                }
        }
 
-       // "x's type and T are both integer or floating point types"
+       // "V and T are both integer or floating point types"
        if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
                return true
        }
 
-       // "x's type and T are both complex types"
+       // "V and T are both complex types"
        if isComplex(V) && isComplex(T) {
                return true
        }
 
-       // "x is an integer or a slice of bytes or runes and T is a string type"
+       // "V is an integer or a slice of bytes or runes and T is a string type"
        if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
                return true
        }
 
-       // "x is a string and T is a slice of bytes or runes"
+       // "V is a string and T is a slice of bytes or runes"
        if isString(V) && isBytesOrRunes(Tu) {
                return true
        }
@@ -138,7 +224,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
                return true
        }
 
-       // "x is a slice, T is a pointer-to-array type,
+       // "V is a slice, T is a pointer-to-array type,
        // and the slice and array types have identical element types."
        if s := asSlice(V); s != nil {
                if p := asPointer(T); p != nil {
@@ -147,8 +233,8 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
                                        if check == nil || check.allowVersion(check.pkg, 1, 17) {
                                                return true
                                        }
-                                       if reason != nil {
-                                               *reason = "conversion of slices to array pointers requires go1.17 or later"
+                                       if cause != nil {
+                                               *cause = "conversion of slices to array pointers requires go1.17 or later"
                                        }
                                }
                        }
@@ -158,6 +244,10 @@ func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
        return false
 }
 
+// Helper predicates for convertibleToImpl. The types provided to convertibleToImpl
+// may be type parameters but they won't have specific type terms. Thus it is ok to
+// use the toT convenience converters in the predicates below.
+
 func isUintptr(typ Type) bool {
        t := asBasic(typ)
        return t != nil && t.kind == Uintptr
index 831b1da5896841bcc8d64ddeaa583c68650b0d2b..8d255dcf3d12bfc78e6b136a9c608a837b1032af 100644 (file)
@@ -8,7 +8,6 @@ import (
        "fmt"
        "go/ast"
        "go/constant"
-       "go/internal/typeparams"
        "go/token"
 )
 
@@ -66,6 +65,12 @@ func (check *Checker) objDecl(obj Object, def *Named) {
                }()
        }
 
+       // Funcs with m.instRecv set have not yet be completed. Complete them now
+       // so that they have a type when objDecl exits.
+       if m, _ := obj.(*Func); m != nil && m.instRecv != nil {
+               check.completeMethod(check.conf.Context, m)
+       }
+
        // Checking the declaration of obj means inferring its type
        // (and possibly its value, for constants).
        // An object's type (and thus the object) may be in one of
@@ -309,6 +314,13 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                        }
                }
 
+       case *Union:
+               for _, t := range t.terms {
+                       if check.validType(t.typ, path) == invalid {
+                               return invalid
+                       }
+               }
+
        case *Interface:
                for _, etyp := range t.embeddeds {
                        if check.validType(etyp, path) == invalid {
@@ -317,7 +329,17 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                }
 
        case *Named:
-               t.expand()
+               // If t is parameterized, we should be considering the instantiated (expanded)
+               // form of t, but in general we can't with this algorithm: if t is an invalid
+               // type it may be so because it infinitely expands through a type parameter.
+               // Instantiating such a type would lead to an infinite sequence of instantiations.
+               // In general, we need "type flow analysis" to recognize those cases.
+               // Example: type A[T any] struct{ x A[*T] } (issue #48951)
+               // In this algorithm we always only consider the orginal, uninstantiated type.
+               // This won't recognize some invalid cases with parameterized types, but it
+               // will terminate.
+               t = t.orig
+
                // don't touch the type if it is from a different package or the Universe scope
                // (doing so would lead to a race condition - was issue #35049)
                if t.obj.pkg != check.pkg {
@@ -339,15 +361,16 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                        // cycle detected
                        for i, tn := range path {
                                if t.obj.pkg != check.pkg {
-                                       panic("internal error: type cycle via package-external type")
+                                       panic("type cycle via package-external type")
                                }
                                if tn == t.obj {
                                        check.cycleError(path[i:])
                                        t.info = invalid
-                                       return t.info
+                                       t.underlying = Typ[Invalid]
+                                       return invalid
                                }
                        }
-                       panic("internal error: cycle start not found")
+                       panic("cycle start not found")
                }
                return t.info
        }
@@ -567,15 +590,30 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
        check.initVars(lhs, []ast.Expr{init}, token.NoPos)
 }
 
+// isImportedConstraint reports whether typ is an imported type constraint.
+func (check *Checker) isImportedConstraint(typ Type) bool {
+       named, _ := typ.(*Named)
+       if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
+               return false
+       }
+       u, _ := named.under().(*Interface)
+       return u != nil && !u.IsMethodSet()
+}
+
 func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
        assert(obj.typ == nil)
 
+       var rhs Type
        check.later(func() {
                check.validType(obj.typ, nil)
-       })
+               // If typ is local, an error was already reported where typ is specified/defined.
+               if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
+                       check.errorf(tdecl.Type, _Todo, "using type constraint %s requires go1.18 or later", rhs)
+               }
+       }).describef(obj, "validType(%s)", obj.Name())
 
        alias := tdecl.Assign.IsValid()
-       if alias && typeparams.Get(tdecl) != nil {
+       if alias && tdecl.TypeParams.NumFields() != 0 {
                // The parser will ensure this but we may still get an invalid AST.
                // Complain and continue as regular type definition.
                check.error(atPos(tdecl.Assign), 0, "generic type cannot be alias")
@@ -589,7 +627,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
                }
 
                obj.typ = Typ[Invalid]
-               obj.typ = check.anyType(tdecl.Type)
+               rhs = check.varType(tdecl.Type)
+               obj.typ = rhs
                return
        }
 
@@ -597,42 +636,35 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
        named := check.newNamed(obj, nil, nil, nil, nil)
        def.setUnderlying(named)
 
-       if tparams := typeparams.Get(tdecl); tparams != nil {
+       if tdecl.TypeParams != nil {
                check.openScope(tdecl, "type parameters")
                defer check.closeScope()
-               named.tparams = check.collectTypeParams(tparams)
+               check.collectTypeParams(&named.tparams, tdecl.TypeParams)
        }
 
        // determine underlying type of named
-       named.fromRHS = check.definedType(tdecl.Type, named)
-       assert(named.fromRHS != nil)
+       rhs = check.definedType(tdecl.Type, named)
+       assert(rhs != nil)
+       named.fromRHS = rhs
 
-       // The underlying type of named may be itself a named type that is
-       // incomplete:
-       //
-       //      type (
-       //              A B
-       //              B *C
-       //              C A
-       //      )
-       //
-       // The type of C is the (named) type of A which is incomplete,
-       // and which has as its underlying type the named type B.
-       // Determine the (final, unnamed) underlying type by resolving
-       // any forward chain.
-       // TODO(gri) Investigate if we can just use named.fromRHS here
-       //           and rely on lazy computation of the underlying type.
-       named.underlying = under(named)
-
-       // If the RHS is a type parameter, it must be from this type declaration.
-       if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TParams().list(), tpar) < 0 {
-               check.errorf(tdecl.Type, _Todo, "cannot use function type parameter %s as RHS in type declaration", tpar)
+       // If the underlying was not set while type-checking the right-hand side, it
+       // is invalid and an error should have been reported elsewhere.
+       if named.underlying == nil {
+               named.underlying = Typ[Invalid]
+       }
+
+       // Disallow a lone type parameter as the RHS of a type declaration (issue #45639).
+       // We can look directly at named.underlying because even if it is still a *Named
+       // type (underlying not fully resolved yet) it cannot become a type parameter due
+       // to this very restriction.
+       if tpar, _ := named.underlying.(*TypeParam); tpar != nil {
+               check.error(tdecl.Type, _Todo, "cannot use a type parameter as RHS in type declaration")
                named.underlying = Typ[Invalid]
        }
 }
 
-func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParams {
-       var tparams []*TypeName
+func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList) {
+       var tparams []*TypeParam
        // Declare type parameters up-front, with empty interface as type bound.
        // The scope of type parameters starts at the beginning of the type parameter
        // list (so we can have mutually recursive parameterized interfaces).
@@ -640,29 +672,73 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) *TypeParams {
                tparams = check.declareTypeParams(tparams, f.Names)
        }
 
+       // Set the type parameters before collecting the type constraints because
+       // the parameterized type may be used by the constraints (issue #47887).
+       // Example: type T[P T[P]] interface{}
+       *dst = bindTParams(tparams)
+
        index := 0
-       var bound Type
+       var bounds []Type
+       var posns []positioner // bound positions
        for _, f := range list.List {
-               if f.Type == nil {
-                       goto next
-               }
-               bound = check.boundType(f.Type)
-               for i := range f.Names {
-                       tparams[index+i].typ.(*TypeParam).bound = bound
+               // TODO(rfindley) we should be able to rely on f.Type != nil at this point
+               if f.Type != nil {
+                       bound := check.bound(f.Type)
+                       bounds = append(bounds, bound)
+                       posns = append(posns, f.Type)
+                       for i := range f.Names {
+                               tparams[index+i].bound = bound
+                       }
                }
-
-       next:
                index += len(f.Names)
        }
 
-       return bindTParams(tparams)
+       check.later(func() {
+               for i, bound := range bounds {
+                       if _, ok := under(bound).(*TypeParam); ok {
+                               check.error(posns[i], _Todo, "cannot use a type parameter as constraint")
+                       }
+               }
+               for _, tpar := range tparams {
+                       tpar.iface() // compute type set
+               }
+       })
+}
+
+func (check *Checker) bound(x ast.Expr) Type {
+       // A type set literal of the form ~T and A|B may only appear as constraint;
+       // embed it in an implicit interface so that only interface type-checking
+       // needs to take care of such type expressions.
+       wrap := false
+       switch op := x.(type) {
+       case *ast.UnaryExpr:
+               wrap = op.Op == token.TILDE
+       case *ast.BinaryExpr:
+               wrap = op.Op == token.OR
+       }
+       if wrap {
+               x = &ast.InterfaceType{Methods: &ast.FieldList{List: []*ast.Field{{Type: x}}}}
+               t := check.typ(x)
+               // mark t as implicit interface if all went well
+               if t, _ := t.(*Interface); t != nil {
+                       t.implicit = true
+               }
+               return t
+       }
+       return check.typ(x)
 }
 
-func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
+func (check *Checker) declareTypeParams(tparams []*TypeParam, names []*ast.Ident) []*TypeParam {
+       // Use Typ[Invalid] for the type constraint to ensure that a type
+       // is present even if the actual constraint has not been assigned
+       // yet.
+       // TODO(gri) Need to systematically review all uses of type parameter
+       //           constraints to make sure we don't rely on them if they
+       //           are not properly set yet.
        for _, name := range names {
-               tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
-               check.NewTypeParam(tpar, &emptyInterface)               // assigns type to tpar as a side-effect
-               check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
+               tname := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
+               tpar := check.newTypeParam(tname, Typ[Invalid])          // assigns type to tpar as a side-effect
+               check.declare(check.scope, name, tname, check.scope.pos) // TODO(gri) check scope position
                tparams = append(tparams, tpar)
        }
 
@@ -673,25 +749,6 @@ func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident)
        return tparams
 }
 
-// boundType type-checks the type expression e and returns its type, or Typ[Invalid].
-// The type must be an interface, including the predeclared type "any".
-func (check *Checker) boundType(e ast.Expr) Type {
-       // The predeclared identifier "any" is visible only as a type bound in a type parameter list.
-       // If we allow "any" for general use, this if-statement can be removed (issue #33232).
-       if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == universeAny {
-               return universeAny.Type()
-       }
-
-       bound := check.typ(e)
-       check.later(func() {
-               u := under(bound)
-               if _, ok := u.(*Interface); !ok && u != Typ[Invalid] {
-                       check.errorf(e, _Todo, "%s is not an interface", bound)
-               }
-       })
-       return bound
-}
-
 func (check *Checker) collectMethods(obj *TypeName) {
        // get associated methods
        // (Checker.collectObjects only collects methods with non-blank names;
@@ -711,7 +768,8 @@ func (check *Checker) collectMethods(obj *TypeName) {
        // and field names must be distinct."
        base := asNamed(obj.typ) // shouldn't fail but be conservative
        if base != nil {
-               if t, _ := base.Underlying().(*Struct); t != nil {
+               u := base.under()
+               if t, _ := u.(*Struct); t != nil {
                        for _, fld := range t.fields {
                                if fld.name != "_" {
                                        assert(mset.insert(fld) == nil)
@@ -747,7 +805,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
                }
 
                if base != nil {
-                       base.load() // TODO(mdempsky): Probably unnecessary.
+                       base.resolve(nil) // TODO(mdempsky): Probably unnecessary.
                        base.methods = append(base.methods, m)
                }
        }
@@ -774,6 +832,10 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
        check.funcType(sig, fdecl.Recv, fdecl.Type)
        obj.color_ = saved
 
+       if fdecl.Type.TypeParams.NumFields() > 0 && fdecl.Body == nil {
+               check.softErrorf(fdecl.Name, _Todo, "parameterized function is missing function body")
+       }
+
        // function body must be type-checked after global declarations
        // (functions implemented elsewhere have no body)
        if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
index bcc850f75381f32bd6ca3f7c88b708195c5d8e04..88dd0fda2f8aefbd03f42729592aeac3bdb1204c 100644 (file)
@@ -875,7 +875,7 @@ const (
        // context in which it is used.
        //
        // Example:
-       //  var _ = 1 + nil
+       //  var _ = 1 + new(int)
        _InvalidUntypedConversion
 
        // _BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument
@@ -1301,6 +1301,13 @@ const (
        //  var _ = unsafe.Slice(&x, uint64(1) << 63)
        _InvalidUnsafeSlice
 
+       // _InvalidInstanceCycle occurs when an invalid cycle is detected
+       // within the instantiation graph.
+       //
+       // Example:
+       //  func f[T any]() { f[*T]() }
+       _InvalidInstanceCycle
+
        // _Todo is a placeholder for error codes that have not been decided.
        // TODO(rFindley) remove this error code after deciding on errors for generics code.
        _Todo
index 226310641733ae833e91e63064ec6a8db71ea469..92002add13cc4957fc446753868237b7cc8aefe9 100644 (file)
@@ -63,22 +63,28 @@ func (check *Checker) markImports(pkg *Package) {
 }
 
 func (check *Checker) sprintf(format string, args ...interface{}) string {
+       return sprintf(check.fset, check.qualifier, false, format, args...)
+}
+
+func sprintf(fset *token.FileSet, qf Qualifier, debug bool, format string, args ...interface{}) string {
        for i, arg := range args {
                switch a := arg.(type) {
                case nil:
                        arg = "<nil>"
                case operand:
-                       panic("internal error: should always pass *operand")
+                       panic("got operand instead of *operand")
                case *operand:
-                       arg = operandString(a, check.qualifier)
+                       arg = operandString(a, qf)
                case token.Pos:
-                       arg = check.fset.Position(a).String()
+                       if fset != nil {
+                               arg = fset.Position(a).String()
+                       }
                case ast.Expr:
                        arg = ExprString(a)
                case Object:
-                       arg = ObjectString(a, check.qualifier)
+                       arg = ObjectString(a, qf)
                case Type:
-                       arg = TypeString(a, check.qualifier)
+                       arg = typeString(a, qf, debug)
                }
                args[i] = arg
        }
@@ -89,13 +95,13 @@ func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
        fmt.Printf("%s:\t%s%s\n",
                check.fset.Position(pos),
                strings.Repeat(".  ", check.indent),
-               check.sprintf(format, args...),
+               sprintf(check.fset, check.qualifier, true, format, args...),
        )
 }
 
 // dump is only needed for debugging
 func (check *Checker) dump(format string, args ...interface{}) {
-       fmt.Println(check.sprintf(format, args...))
+       fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...))
 }
 
 func (check *Checker) err(err error) {
@@ -236,7 +242,7 @@ func (s atPos) Pos() token.Pos {
 func spanOf(at positioner) posSpan {
        switch x := at.(type) {
        case nil:
-               panic("internal error: nil")
+               panic("nil positioner")
        case posSpan:
                return x
        case ast.Node:
@@ -259,7 +265,7 @@ func stripAnnotations(s string) string {
        var b strings.Builder
        for _, r := range s {
                // strip #'s and subscript digits
-               if r != instanceMarker && !('₀' <= r && r < '₀'+10) { // '₀' == U+2080
+               if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
                        b.WriteRune(r)
                }
        }
index fdbe07cae0b4892387fce5287adb71e964a1efd9..942a9fdd4c2579fe7d2572e5cf900671dfdeb1df 100644 (file)
@@ -15,7 +15,6 @@ func TestStripAnnotations(t *testing.T) {
                {"foo", "foo"},
                {"foo₀", "foo"},
                {"foo(T₀)", "foo(T)"},
-               {"#foo(T₀)", "foo(T)"},
        } {
                got := stripAnnotations(test.in)
                if got != test.want {
index 51259604c984c5d6d74274e9341de8349ba866b5..c8bb005eb6d4a13d638a8aa2e8b32176411c38d1 100644 (file)
@@ -35,9 +35,10 @@ func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (_ Type
        return info.Types[node], err
 }
 
-// CheckExpr type checks the expression expr as if it had appeared at
-// position pos of package pkg. Type information about the expression
-// is recorded in info.
+// CheckExpr type checks the expression expr as if it had appeared at position
+// pos of package pkg. Type information about the expression is recorded in
+// info. The expression may be an uninstantiated parameterized function or
+// type.
 //
 // If pkg == nil, the Universe scope is used and the provided
 // position pos is ignored. If pkg != nil, and pos is invalid,
@@ -91,8 +92,8 @@ func CheckExpr(fset *token.FileSet, pkg *Package, pos token.Pos, expr ast.Expr,
 
        // evaluate node
        var x operand
-       check.rawExpr(&x, expr, nil)
-       check.processDelayed(0) // incl. all functions
+       check.rawExpr(&x, expr, nil, true) // allow generic expressions
+       check.processDelayed(0)            // incl. all functions
        check.recordUntyped()
 
        return nil
index 41d3a61b89528ed7e8c4445585982f8efc593bd0..345bd143059350e16ddf8ab3da995500acdddf12 100644 (file)
@@ -195,10 +195,10 @@ func TestEvalPos(t *testing.T) {
        }
 }
 
-// split splits string s at the first occurrence of s.
+// split splits string s at the first occurrence of s, trimming spaces.
 func split(s, sep string) (string, string) {
-       i := strings.Index(s, sep)
-       return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+       before, after, _ := strings.Cut(s, sep)
+       return strings.TrimSpace(before), strings.TrimSpace(after)
 }
 
 func TestCheckExpr(t *testing.T) {
index 32a25a41176159264c28ab7943aceb200b56712f..270256748645a9d7d6380df4d17cbb2d45f08dc0 100644 (file)
@@ -6,7 +6,6 @@
 // access to compiled packages for import.
 //
 //go:build !arm && !arm64
-// +build !arm,!arm64
 
 package types_test
 
index c9a55aa871e2c8131066913f93f3d4d61d24def9..d4de212e068c17da71f953e1307ccfaa52fdc215 100644 (file)
@@ -100,6 +100,8 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
 
        // Typed constants must be representable in
        // their type after each constant operation.
+       // x.typ cannot be a type parameter (type
+       // parameters cannot be constant types).
        if isTyped(x.typ) {
                check.representable(x, asBasic(x.typ))
                return
@@ -114,9 +116,7 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
 }
 
 // opName returns the name of an operation, or the empty string.
-// For now, only operations that might overflow are handled.
-// TODO(gri) Expand this to a general mechanism giving names to
-//           nodes?
+// Only operations that might overflow are handled.
 func opName(e ast.Expr) string {
        switch e := e.(type) {
        case *ast.BinaryExpr:
@@ -144,6 +144,8 @@ var op2str2 = [...]string{
        token.SHL: "shift",
 }
 
+// If typ is a type parameter, underIs returns the result of typ.underIs(f).
+// Otherwise, underIs returns the result of f(under(typ)).
 func underIs(typ Type, f func(Type) bool) bool {
        u := under(typ)
        if tpar, _ := u.(*TypeParam); tpar != nil {
@@ -600,7 +602,7 @@ func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) {
 func (check *Checker) convertUntyped(x *operand, target Type) {
        newType, val, code := check.implicitTypeAndValue(x, target)
        if code != 0 {
-               check.invalidConversion(code, x, target.Underlying())
+               check.invalidConversion(code, x, safeUnderlying(target))
                x.mode = invalid
                return
        }
@@ -621,7 +623,6 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
 // If x is a constant operand, the returned constant.Value will be the
 // representation of x in this context.
 func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, errorCode) {
-       target = expand(target)
        if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
                return x.typ, nil, 0
        }
@@ -680,6 +681,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
                        return nil, nil, _InvalidUntypedConversion
                }
        case *TypeParam:
+               // TODO(gri) review this code - doesn't look quite right
                ok := t.underIs(func(t Type) bool {
                        target, _, _ := check.implicitTypeAndValue(x, t)
                        return target != nil
@@ -970,6 +972,12 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token
                if isString(x.typ) != isString(y.typ) {
                        return false
                }
+               if x.isNil() && !hasNil(y.typ) {
+                       return false
+               }
+               if y.isNil() && !hasNil(x.typ) {
+                       return false
+               }
                return true
        }
        if canMix(x, &y) {
@@ -997,7 +1005,11 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token
                        if e != nil {
                                posn = e
                        }
-                       check.invalidOp(posn, _MismatchedTypes, "mismatched types %s and %s", x.typ, y.typ)
+                       if e != nil {
+                               check.invalidOp(posn, _MismatchedTypes, "%s (mismatched types %s and %s)", e, x.typ, y.typ)
+                       } else {
+                               check.invalidOp(posn, _MismatchedTypes, "%s %s= %s (mismatched types %s and %s)", lhs, op, rhs, x.typ, y.typ)
+                       }
                }
                x.mode = invalid
                return
@@ -1062,8 +1074,10 @@ const (
 // rawExpr typechecks expression e and initializes x with the expression
 // value or type. If an error occurred, x.mode is set to invalid.
 // If hint != nil, it is the type of a composite literal element.
+// If allowGeneric is set, the operand type may be an uninstantiated
+// parameterized type or function value.
 //
-func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
+func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type, allowGeneric bool) exprKind {
        if trace {
                check.trace(e.Pos(), "expr %s", e)
                check.indent++
@@ -1074,11 +1088,40 @@ func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
        }
 
        kind := check.exprInternal(x, e, hint)
+
+       if !allowGeneric {
+               check.nonGeneric(x)
+       }
+
        check.record(x)
 
        return kind
 }
 
+// If x is a generic function or type, nonGeneric reports an error and invalidates x.mode and x.typ.
+// Otherwise it leaves x alone.
+func (check *Checker) nonGeneric(x *operand) {
+       if x.mode == invalid || x.mode == novalue {
+               return
+       }
+       var what string
+       switch t := x.typ.(type) {
+       case *Named:
+               if isGeneric(t) {
+                       what = "type"
+               }
+       case *Signature:
+               if t.tparams != nil {
+                       what = "function"
+               }
+       }
+       if what != "" {
+               check.errorf(x.expr, _Todo, "cannot use generic %s %s without instantiation", what, x.expr)
+               x.mode = invalid
+               x.typ = Typ[Invalid]
+       }
+}
+
 // exprInternal contains the core of type checking of expressions.
 // Must only be called by rawExpr.
 //
@@ -1185,7 +1228,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                        goto Error
                }
 
-               switch utyp := under(base).(type) {
+               switch utyp := structure(base).(type) {
                case *Struct:
                        if len(e.Elts) == 0 {
                                break
@@ -1357,14 +1400,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                x.typ = typ
 
        case *ast.ParenExpr:
-               kind := check.rawExpr(x, e.X, nil)
+               kind := check.rawExpr(x, e.X, nil, false)
                x.expr = e
                return kind
 
        case *ast.SelectorExpr:
                check.selector(x, e)
 
-       case *ast.IndexExpr, *ast.MultiIndexExpr:
+       case *ast.IndexExpr, *ast.IndexListExpr:
                ix := typeparams.UnpackIndexExpr(e)
                if check.indexExpr(x, ix) {
                        check.funcInst(x, ix)
@@ -1389,7 +1432,6 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                        check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
                        goto Error
                }
-               check.ordinaryType(x, xtyp)
                // x.(type) expressions are handled explicitly in type switches
                if e.Type == nil {
                        // Don't use invalidAST because this can occur in the AST produced by
@@ -1409,7 +1451,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                return check.callExpr(x, e)
 
        case *ast.StarExpr:
-               check.exprOrType(x, e.X)
+               check.exprOrType(x, e.X, false)
                switch x.mode {
                case invalid:
                        goto Error
@@ -1529,14 +1571,14 @@ func (check *Checker) typeAssertion(at positioner, x *operand, xtyp *Interface,
 // If an error occurred, x.mode is set to invalid.
 //
 func (check *Checker) expr(x *operand, e ast.Expr) {
-       check.rawExpr(x, e, nil)
+       check.rawExpr(x, e, nil, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
 }
 
 // multiExpr is like expr but the result may also be a multi-value.
 func (check *Checker) multiExpr(x *operand, e ast.Expr) {
-       check.rawExpr(x, e, nil)
+       check.rawExpr(x, e, nil, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
 }
 
@@ -1546,16 +1588,18 @@ func (check *Checker) multiExpr(x *operand, e ast.Expr) {
 //
 func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
        assert(hint != nil)
-       check.rawExpr(x, e, hint)
+       check.rawExpr(x, e, hint, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
 }
 
 // exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If allowGeneric is set, the operand type may be an uninstantiated parameterized type or function
+// value.
 // If an error occurred, x.mode is set to invalid.
 //
-func (check *Checker) exprOrType(x *operand, e ast.Expr) {
-       check.rawExpr(x, e, nil)
+func (check *Checker) exprOrType(x *operand, e ast.Expr, allowGeneric bool) {
+       check.rawExpr(x, e, nil, allowGeneric)
        check.exclude(x, 1<<novalue)
        check.singleValue(x)
 }
index aee8a5ba5f74d2826d76ddbbf41ade0992cdeebd..aa4f403c1f1e8019ea444d14498469ced4746ce5 100644 (file)
@@ -67,7 +67,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
                buf.WriteByte('.')
                buf.WriteString(x.Sel.Name)
 
-       case *ast.IndexExpr, *ast.MultiIndexExpr:
+       case *ast.IndexExpr, *ast.IndexListExpr:
                ix := typeparams.UnpackIndexExpr(x)
                WriteExpr(buf, ix.X)
                buf.WriteByte('[')
@@ -145,29 +145,8 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
                writeSigExpr(buf, x)
 
        case *ast.InterfaceType:
-               // separate type list types from method list
-               // TODO(gri) we can get rid of this extra code if writeExprList does the separation
-               var types []ast.Expr
-               var methods []*ast.Field
-               for _, f := range x.Methods.List {
-                       if len(f.Names) > 1 && f.Names[0].Name == "type" {
-                               // type list type
-                               types = append(types, f.Type)
-                       } else {
-                               // method or embedded interface
-                               methods = append(methods, f)
-                       }
-               }
-
                buf.WriteString("interface{")
-               writeFieldList(buf, methods, "; ", true)
-               if len(types) > 0 {
-                       if len(methods) > 0 {
-                               buf.WriteString("; ")
-                       }
-                       buf.WriteString("type ")
-                       writeExprList(buf, types)
-               }
+               writeFieldList(buf, x.Methods.List, "; ", true)
                buf.WriteByte('}')
 
        case *ast.MapType:
index a67f6a978a9509ce8f251041f0e2e92d82a91876..27cd532c97c2715a3de8941774e37f15a36cfefe 100644 (file)
@@ -36,15 +36,8 @@ var testExprs = []testEntry{
        dup("func(int, float32) string"),
        dup("interface{m()}"),
        dup("interface{m() string; n(x int)}"),
-       dup("interface{type int}"),
-
-       // The following exprs do not get formatted correctly: each element in the
-       // type list is printed on a separate line. This is left as a placeholder
-       // until type lists are removed.
-       // TODO(rfindley): remove this once type lists are gone.
-       // dup("interface{type int, float64, string}"),
-       // dup("interface{type int; m()}"),
-       // dup("interface{type int, float64, string; m() string; n(x int)}"),
+       dup("interface{~int}"),
+
        dup("map[string]int"),
        dup("chan E"),
        dup("<-chan E"),
index ca1d42c14d5aec3d543529ace321d4f9fd54ca17..1126b73810cf3b4afd1bcbfb92ed5b161803a587 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Build this command explicitly: go build gotype.go
 
index a49bc5519cf3e9a5f29fdaf45d2595af2d1342ae..a85d314efa641011d9a448407cd13b98a4c10532 100644 (file)
@@ -16,7 +16,8 @@ import (
 // In that case x represents the uninstantiated function value and
 // it is the caller's responsibility to instantiate the function.
 func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst bool) {
-       check.exprOrType(x, e.X)
+       check.exprOrType(x, e.X, true)
+       // x may be generic
 
        switch x.mode {
        case invalid:
@@ -26,6 +27,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
        case typexpr:
                // type instantiation
                x.mode = invalid
+               // TODO(gri) here we re-evaluate e.X - try to avoid this
                x.typ = check.varType(e.Orig)
                if x.typ != Typ[Invalid] {
                        x.mode = typexpr
@@ -33,12 +35,18 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
                return false
 
        case value:
-               if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
+               if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
                        // function instantiation
                        return true
                }
        }
 
+       // x should not be generic at this point, but be safe and check
+       check.nonGeneric(x)
+       if x.mode == invalid {
+               return false
+       }
+
        valid := false
        length := int64(-1) // valid if >= 0
        switch typ := under(x.typ).(type) {
@@ -93,77 +101,80 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
 
        case *TypeParam:
                // TODO(gri) report detailed failure cause for better error messages
-               var tkey, telem Type // tkey != nil if we have maps
+               var key, elem Type // key != nil: we must have all maps
+               mode := variable   // non-maps result mode
+               // TODO(gri) factor out closure and use it for non-typeparam cases as well
                if typ.underIs(func(u Type) bool {
-                       var key, elem Type
-                       alen := int64(-1) // valid if >= 0
+                       l := int64(-1) // valid if >= 0
+                       var k, e Type  // k is only set for maps
                        switch t := u.(type) {
                        case *Basic:
-                               if !isString(t) {
-                                       return false
+                               if isString(t) {
+                                       e = universeByte
+                                       mode = value
                                }
-                               elem = universeByte
                        case *Array:
-                               elem = t.elem
-                               alen = t.len
+                               l = t.len
+                               e = t.elem
+                               if x.mode != variable {
+                                       mode = value
+                               }
                        case *Pointer:
-                               a, _ := under(t.base).(*Array)
-                               if a == nil {
-                                       return false
+                               if t := asArray(t.base); t != nil {
+                                       l = t.len
+                                       e = t.elem
                                }
-                               elem = a.elem
-                               alen = a.len
                        case *Slice:
-                               elem = t.elem
+                               e = t.elem
                        case *Map:
-                               key = t.key
-                               elem = t.elem
-                       default:
+                               k = t.key
+                               e = t.elem
+                       }
+                       if e == nil {
                                return false
                        }
-                       assert(elem != nil)
-                       if telem == nil {
+                       if elem == nil {
                                // first type
-                               tkey, telem = key, elem
-                               length = alen
-                       } else {
-                               // all map keys must be identical (incl. all nil)
-                               if !Identical(key, tkey) {
-                                       return false
-                               }
-                               // all element types must be identical
-                               if !Identical(elem, telem) {
-                                       return false
-                               }
-                               tkey, telem = key, elem
-                               // track the minimal length for arrays
-                               if alen >= 0 && alen < length {
-                                       length = alen
-                               }
+                               length = l
+                               key, elem = k, e
+                               return true
+                       }
+                       // all map keys must be identical (incl. all nil)
+                       // (that is, we cannot mix maps with other types)
+                       if !Identical(key, k) {
+                               return false
+                       }
+                       // all element types must be identical
+                       if !Identical(elem, e) {
+                               return false
+                       }
+                       // track the minimal length for arrays, if any
+                       if l >= 0 && l < length {
+                               length = l
                        }
                        return true
                }) {
                        // For maps, the index expression must be assignable to the map key type.
-                       if tkey != nil {
+                       if key != nil {
                                index := check.singleIndex(e)
                                if index == nil {
                                        x.mode = invalid
                                        return false
                                }
-                               var key operand
-                               check.expr(&key, index)
-                               check.assignment(&key, tkey, "map index")
+                               var k operand
+                               check.expr(&k, index)
+                               check.assignment(&kkey, "map index")
                                // ok to continue even if indexing failed - map element type is known
                                x.mode = mapindex
-                               x.typ = telem
+                               x.typ = elem
                                x.expr = e
                                return false
                        }
 
                        // no maps
                        valid = true
-                       x.mode = variable
-                       x.typ = telem
+                       x.mode = mode
+                       x.typ = elem
                }
        }
 
@@ -199,9 +210,14 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
 
        valid := false
        length := int64(-1) // valid if >= 0
-       switch typ := under(x.typ).(type) {
+       switch u := structure(x.typ).(type) {
+       case nil:
+               check.errorf(x, _NonSliceableOperand, "cannot slice %s: type set has no single underlying type", x)
+               x.mode = invalid
+               return
+
        case *Basic:
-               if isString(typ) {
+               if isString(u) {
                        if e.Slice3 {
                                check.invalidOp(x, _InvalidSliceExpr, "3-index slice of string")
                                x.mode = invalid
@@ -213,36 +229,31 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
                        }
                        // spec: "For untyped string operands the result
                        // is a non-constant value of type string."
-                       if typ.kind == UntypedString {
+                       if u.kind == UntypedString {
                                x.typ = Typ[String]
                        }
                }
 
        case *Array:
                valid = true
-               length = typ.len
+               length = u.len
                if x.mode != variable {
                        check.invalidOp(x, _NonSliceableOperand, "cannot slice %s (value not addressable)", x)
                        x.mode = invalid
                        return
                }
-               x.typ = &Slice{elem: typ.elem}
+               x.typ = &Slice{elem: u.elem}
 
        case *Pointer:
-               if typ := asArray(typ.base); typ != nil {
+               if u := asArray(u.base); u != nil {
                        valid = true
-                       length = typ.len
-                       x.typ = &Slice{elem: typ.elem}
+                       length = u.len
+                       x.typ = &Slice{elem: u.elem}
                }
 
        case *Slice:
                valid = true
                // x.typ doesn't change
-
-       case *TypeParam:
-               check.errorf(x, _Todo, "generic slice expressions not yet implemented")
-               x.mode = invalid
-               return
        }
 
        if !valid {
index 6e70a103e72856dbe0c30f4cdbbc93a0ce32e325..41326a1be8bd3574ab632d63331418f7424f7416 100644 (file)
@@ -8,6 +8,7 @@
 package types
 
 import (
+       "fmt"
        "go/token"
        "strings"
 )
@@ -26,8 +27,7 @@ import (
 //   3) Infer type arguments from untyped function arguments.
 //
 // Constraint type inference is used after each step to expand the set of type arguments.
-//
-func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type, params *Tuple, args []*operand, report bool) (result []Type) {
+func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (result []Type) {
        if debug {
                defer func() {
                        assert(result == nil || len(result) == len(tparams))
@@ -59,7 +59,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
        // If we have type arguments, see how far we get with constraint type inference.
        if len(targs) > 0 {
                var index int
-               targs, index = check.inferB(tparams, targs, report)
+               targs, index = check.inferB(tparams, targs)
                if targs == nil || index < 0 {
                        return targs
                }
@@ -82,11 +82,11 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
 
        // Substitute type arguments for their respective type parameters in params,
        // if any. Note that nil targs entries are ignored by check.subst.
-       // TODO(gri) Can we avoid this (we're setting known type argumemts below,
+       // TODO(gri) Can we avoid this (we're setting known type arguments below,
        //           but that doesn't impact the isParameterized check for now).
        if params.Len() > 0 {
                smap := makeSubstMap(tparams, targs)
-               params = check.subst(token.NoPos, params, smap).(*Tuple)
+               params = check.subst(token.NoPos, params, smap, nil).(*Tuple)
        }
 
        // --- 2 ---
@@ -104,9 +104,6 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
        }
 
        errorf := func(kind string, tpar, targ Type, arg *operand) {
-               if !report {
-                       return
-               }
                // provide a better error message if we can
                targs, index := u.x.types()
                if index == 0 {
@@ -121,17 +118,17 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
                                }
                        }
                        if allFailed {
-                               check.errorf(arg, _Todo, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
+                               check.errorf(arg, _Todo, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeParamsString(tparams))
                                return
                        }
                }
                smap := makeSubstMap(tparams, targs)
                // TODO(rFindley): pass a positioner here, rather than arg.Pos().
-               inferred := check.subst(arg.Pos(), tpar, smap)
+               inferred := check.subst(arg.Pos(), tpar, smap, nil)
                if inferred != tpar {
                        check.errorf(arg, _Todo, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
                } else {
-                       check.errorf(arg, 0, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+                       check.errorf(arg, _Todo, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
                }
        }
 
@@ -173,7 +170,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
        // See how far we get with constraint type inference.
        // Note that even if we don't have any type arguments, constraint type inference
        // may produce results for constraints that explicitly specify a type.
-       targs, index = check.inferB(tparams, targs, report)
+       targs, index = check.inferB(tparams, targs)
        if targs == nil || index < 0 {
                return targs
        }
@@ -209,7 +206,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
        }
 
        // Again, follow up with constraint type inference.
-       targs, index = check.inferB(tparams, targs, report)
+       targs, index = check.inferB(tparams, targs)
        if targs == nil || index < 0 {
                return targs
        }
@@ -217,24 +214,22 @@ func (check *Checker) infer(posn positioner, tparams []*TypeName, targs []Type,
        // At least one type argument couldn't be inferred.
        assert(index >= 0 && targs[index] == nil)
        tpar := tparams[index]
-       if report {
-               check.errorf(posn, _Todo, "cannot infer %s (%v) (%v)", tpar.name, tpar.pos, targs)
-       }
+       check.errorf(posn, _Todo, "cannot infer %s (%v)", tpar.obj.name, tpar.obj.pos)
        return nil
 }
 
-// typeNamesString produces a string containing all the
-// type names in list suitable for human consumption.
-func typeNamesString(list []*TypeName) string {
+// typeParamsString produces a string containing all the type parameter names
+// in list suitable for human consumption.
+func typeParamsString(list []*TypeParam) string {
        // common cases
        n := len(list)
        switch n {
        case 0:
                return ""
        case 1:
-               return list[0].name
+               return list[0].obj.name
        case 2:
-               return list[0].name + " and " + list[1].name
+               return list[0].obj.name + " and " + list[1].obj.name
        }
 
        // general case (n > 2)
@@ -243,15 +238,15 @@ func typeNamesString(list []*TypeName) string {
                if i > 0 {
                        b.WriteString(", ")
                }
-               b.WriteString(tname.name)
+               b.WriteString(tname.obj.name)
        }
        b.WriteString(", and ")
-       b.WriteString(list[n-1].name)
+       b.WriteString(list[n-1].obj.name)
        return b.String()
 }
 
 // IsParameterized reports whether typ contains any of the type parameters of tparams.
-func isParameterized(tparams []*TypeName, typ Type) bool {
+func isParameterized(tparams []*TypeParam, typ Type) bool {
        w := tpWalker{
                seen:    make(map[Type]bool),
                tparams: tparams,
@@ -261,7 +256,7 @@ func isParameterized(tparams []*TypeName, typ Type) bool {
 
 type tpWalker struct {
        seen    map[Type]bool
-       tparams []*TypeName
+       tparams []*TypeParam
 }
 
 func (w *tpWalker) isParameterized(typ Type) (res bool) {
@@ -302,9 +297,6 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
                        }
                }
 
-       case *Union:
-               return w.isParameterizedTermList(t.terms)
-
        case *Signature:
                // t.tparams may not be nil if we are looking at a signature
                // of a generic function type (or an interface method) that is
@@ -322,7 +314,9 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
                                return true
                        }
                }
-               return w.isParameterized(tset.types)
+               return tset.is(func(t *term) bool {
+                       return t != nil && w.isParameterized(t.typ)
+               })
 
        case *Map:
                return w.isParameterized(t.key) || w.isParameterized(t.elem)
@@ -331,11 +325,11 @@ func (w *tpWalker) isParameterized(typ Type) (res bool) {
                return w.isParameterized(t.elem)
 
        case *Named:
-               return w.isParameterizedTypeList(t.targs)
+               return w.isParameterizedTypeList(t.targs.list())
 
        case *TypeParam:
                // t must be one of w.tparams
-               return t.index < len(w.tparams) && w.tparams[t.index].typ == t
+               return tparamIndex(w.tparams, t) >= 0
 
        default:
                unreachable()
@@ -353,15 +347,6 @@ func (w *tpWalker) isParameterizedTypeList(list []Type) bool {
        return false
 }
 
-func (w *tpWalker) isParameterizedTermList(list []*term) bool {
-       for _, t := range list {
-               if w.isParameterized(t.typ) {
-                       return true
-               }
-       }
-       return false
-}
-
 // inferB returns the list of actual type arguments inferred from the type parameters'
 // bounds and an initial set of type arguments. If type inference is impossible because
 // unification fails, an error is reported if report is set to true, the resulting types
@@ -370,10 +355,10 @@ func (w *tpWalker) isParameterizedTermList(list []*term) bool {
 // first type argument in that list that couldn't be inferred (and thus is nil). If all
 // type arguments were inferred successfully, index is < 0. The number of type arguments
 // provided may be less than the number of type parameters, but there must be at least one.
-func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (types []Type, index int) {
+func (check *Checker) inferB(tparams []*TypeParam, targs []Type) (types []Type, index int) {
        assert(len(tparams) >= len(targs) && len(targs) > 0)
 
-       // Setup bidirectional unification between those structural bounds
+       // Setup bidirectional unification between constraints
        // and the corresponding type arguments (which may be nil!).
        u := newUnifier(false)
        u.x.init(tparams)
@@ -386,22 +371,26 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
                }
        }
 
-       // Unify type parameters with their structural constraints, if any.
+       // If a constraint has a structural type, unify the corresponding type parameter with it.
        for _, tpar := range tparams {
-               typ := tpar.typ.(*TypeParam)
-               sbound := check.structuralType(typ.bound)
+               sbound := structure(tpar)
                if sbound != nil {
-                       if !u.unify(typ, sbound) {
-                               if report {
-                                       check.errorf(tpar, _Todo, "%s does not match %s", tpar, sbound)
-                               }
+                       // If the structural type is the underlying type of a single
+                       // defined type in the constraint, use that defined type instead.
+                       if named, _ := tpar.singleType().(*Named); named != nil {
+                               sbound = named
+                       }
+                       if !u.unify(tpar, sbound) {
+                               // TODO(gri) improve error message by providing the type arguments
+                               //           which we know already
+                               check.errorf(tpar.obj, _Todo, "%s does not match %s", tpar, sbound)
                                return nil, 0
                        }
                }
        }
 
        // u.x.types() now contains the incoming type arguments plus any additional type
-       // arguments for which there were structural constraints. The newly inferred non-
+       // arguments which were inferred from structural types. The newly inferred non-
        // nil entries may still contain references to other type parameters.
        // For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
        // was given, unification produced the type list [int, []C, *A]. We eliminate the
@@ -414,6 +403,34 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
                }
        }
 
+       // The data structure of each (provided or inferred) type represents a graph, where
+       // each node corresponds to a type and each (directed) vertice points to a component
+       // type. The substitution process described above repeatedly replaces type parameter
+       // nodes in these graphs with the graphs of the types the type parameters stand for,
+       // which creates a new (possibly bigger) graph for each type.
+       // The substitution process will not stop if the replacement graph for a type parameter
+       // also contains that type parameter.
+       // For instance, for [A interface{ *A }], without any type argument provided for A,
+       // unification produces the type list [*A]. Substituting A in *A with the value for
+       // A will lead to infinite expansion by producing [**A], [****A], [********A], etc.,
+       // because the graph A -> *A has a cycle through A.
+       // Generally, cycles may occur across multiple type parameters and inferred types
+       // (for instance, consider [P interface{ *Q }, Q interface{ func(P) }]).
+       // We eliminate cycles by walking the graphs for all type parameters. If a cycle
+       // through a type parameter is detected, cycleFinder nils out the respectice type
+       // which kills the cycle; this also means that the respective type could not be
+       // inferred.
+       //
+       // TODO(gri) If useful, we could report the respective cycle as an error. We don't
+       //           do this now because type inference will fail anyway, and furthermore,
+       //           constraints with cycles of this kind cannot currently be satisfied by
+       //           any user-suplied type. But should that change, reporting an error
+       //           would be wrong.
+       w := cycleFinder{tparams, types, make(map[Type]bool)}
+       for _, t := range tparams {
+               w.typ(t) // t != nil
+       }
+
        // dirty tracks the indices of all types that may still contain type parameters.
        // We know that nil type entries and entries corresponding to provided (non-nil)
        // type arguments are clean, so exclude them from the start.
@@ -432,7 +449,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
                n := 0
                for _, index := range dirty {
                        t0 := types[index]
-                       if t1 := check.subst(token.NoPos, t0, smap); t1 != t0 {
+                       if t1 := check.subst(token.NoPos, t0, smap, nil); t1 != t0 {
                                types[index] = t1
                                dirty[n] = index
                                n++
@@ -463,19 +480,97 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type, report bool) (ty
        return
 }
 
-// structuralType returns the structural type of a constraint, if any.
-func (check *Checker) structuralType(constraint Type) Type {
-       if iface, _ := under(constraint).(*Interface); iface != nil {
-               types := iface.typeSet().types
-               if u, _ := types.(*Union); u != nil {
-                       if u.NumTerms() == 1 {
-                               // TODO(gri) do we need to respect tilde?
-                               t, _ := u.Term(0)
-                               return t
+type cycleFinder struct {
+       tparams []*TypeParam
+       types   []Type
+       seen    map[Type]bool
+}
+
+func (w *cycleFinder) typ(typ Type) {
+       if w.seen[typ] {
+               // We have seen typ before. If it is one of the type parameters
+               // in tparams, iterative substitution will lead to infinite expansion.
+               // Nil out the corresponding type which effectively kills the cycle.
+               if tpar, _ := typ.(*TypeParam); tpar != nil {
+                       if i := tparamIndex(w.tparams, tpar); i >= 0 {
+                               // cycle through tpar
+                               w.types[i] = nil
                        }
-                       return nil
                }
-               return types
+               // If we don't have one of our type parameters, the cycle is due
+               // to an ordinary recursive type and we can just stop walking it.
+               return
+       }
+       w.seen[typ] = true
+       defer delete(w.seen, typ)
+
+       switch t := typ.(type) {
+       case *Basic:
+               // nothing to do
+
+       case *Array:
+               w.typ(t.elem)
+
+       case *Slice:
+               w.typ(t.elem)
+
+       case *Struct:
+               w.varList(t.fields)
+
+       case *Pointer:
+               w.typ(t.base)
+
+       // case *Tuple:
+       //      This case should not occur because tuples only appear
+       //      in signatures where they are handled explicitly.
+
+       case *Signature:
+               // There are no "method types" so we should never see a recv.
+               assert(t.recv == nil)
+               if t.params != nil {
+                       w.varList(t.params.vars)
+               }
+               if t.results != nil {
+                       w.varList(t.results.vars)
+               }
+
+       case *Union:
+               for _, t := range t.terms {
+                       w.typ(t.typ)
+               }
+
+       case *Interface:
+               for _, m := range t.methods {
+                       w.typ(m.typ)
+               }
+               for _, t := range t.embeddeds {
+                       w.typ(t)
+               }
+
+       case *Map:
+               w.typ(t.key)
+               w.typ(t.elem)
+
+       case *Chan:
+               w.typ(t.elem)
+
+       case *Named:
+               for _, tpar := range t.TypeArgs().list() {
+                       w.typ(tpar)
+               }
+
+       case *TypeParam:
+               if i := tparamIndex(w.tparams, t); i >= 0 && w.types[i] != nil {
+                       w.typ(w.types[i])
+               }
+
+       default:
+               panic(fmt.Sprintf("unexpected %T", typ))
+       }
+}
+
+func (w *cycleFinder) varList(list []*Var) {
+       for _, v := range list {
+               w.typ(v.typ)
        }
-       return nil
 }
index 6d56eb7ea211d496bcaa583c1860d79ea4a70d2e..8d8d2818429ecf322b4b441f208d049227445ffb 100644 (file)
 package types
 
 import (
+       "errors"
        "fmt"
        "go/token"
 )
 
-// Instantiate instantiates the type typ with the given type arguments
-// targs. To check type constraint satisfaction, verify must be set.
-// pos and posList correspond to the instantiation and type argument
-// positions respectively; posList may be nil or shorter than the number
-// of type arguments provided.
-// typ must be a *Named or a *Signature type, and its number of type
-// parameters must match the number of provided type arguments.
-// The receiver (check) may be nil if and only if verify is not set.
-// The result is a new, instantiated (not generic) type of the same kind
-// (either a *Named or a *Signature).
-// Any methods attached to a *Named are simply copied; they are not
-// instantiated.
-func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) (res Type) {
-       var tparams []*TypeName
-       switch t := typ.(type) {
-       case *Named:
-               tparams = t.TParams().list()
-       case *Signature:
-               tparams = t.TParams().list()
-               defer func() {
-                       // If we had an unexpected failure somewhere don't panic below when
-                       // asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
-                       // is returned.
-                       if _, ok := res.(*Signature); !ok {
-                               return
-                       }
-                       // If the signature doesn't use its type parameters, subst
-                       // will not make a copy. In that case, make a copy now (so
-                       // we can set tparams to nil w/o causing side-effects).
-                       if t == res {
-                               copy := *t
-                               res = &copy
-                       }
-                       // After instantiating a generic signature, it is not generic
-                       // anymore; we need to set tparams to nil.
-                       res.(*Signature).tparams = nil
-               }()
-       default:
-               // only types and functions can be generic
-               panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
+// Instantiate instantiates the type typ with the given type arguments targs.
+// typ must be a *Named or a *Signature type, and its number of type parameters
+// must match the number of provided type arguments. The result is a new,
+// instantiated (not parameterized) type of the same kind (either a *Named or a
+// *Signature). Any methods attached to a *Named are simply copied; they are
+// not instantiated.
+//
+// If ctxt is non-nil, it may be used to de-dupe the instance against previous
+// instances with the same identity.
+//
+// If verify is set and constraint satisfaction fails, the returned error may
+// wrap an *ArgumentError indicating which type argument did not satisfy its
+// corresponding type parameter constraint, and why.
+//
+// TODO(rfindley): change this function to also return an error if lengths of
+// tparams and targs do not match.
+func Instantiate(ctxt *Context, typ Type, targs []Type, validate bool) (Type, error) {
+       inst := (*Checker)(nil).instance(token.NoPos, typ, targs, ctxt)
+
+       var err error
+       if validate {
+               var tparams []*TypeParam
+               switch t := typ.(type) {
+               case *Named:
+                       tparams = t.TypeParams().list()
+               case *Signature:
+                       tparams = t.TypeParams().list()
+               }
+               if i, err := (*Checker)(nil).verify(token.NoPos, tparams, targs); err != nil {
+                       return inst, &ArgumentError{i, err}
+               }
        }
 
-       inst := check.instantiate(pos, typ, tparams, targs, posList)
-       if verify && len(tparams) == len(targs) {
-               check.verify(pos, tparams, targs, posList)
-       }
-       return inst
+       return inst, err
 }
 
-func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, posList []token.Pos) (res Type) {
-       // the number of supplied types must match the number of type parameters
-       if len(targs) != len(tparams) {
-               // TODO(gri) provide better error message
-               if check != nil {
-                       check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams))
-                       return Typ[Invalid]
-               }
-               panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
-       }
-
-       if check != nil && trace {
-               check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
-               check.indent++
-               defer func() {
-                       check.indent--
-                       var under Type
-                       if res != nil {
-                               // Calling under() here may lead to endless instantiations.
-                               // Test case: type T[P any] T[P]
-                               // TODO(gri) investigate if that's a bug or to be expected.
-                               under = res.Underlying()
+// instance creates a type or function instance using the given original type
+// typ and arguments targs. For Named types the resulting instance will be
+// unexpanded.
+func (check *Checker) instance(pos token.Pos, typ Type, targs []Type, ctxt *Context) Type {
+       switch t := typ.(type) {
+       case *Named:
+               var h string
+               if ctxt != nil {
+                       h = ctxt.typeHash(t, targs)
+                       // typ may already have been instantiated with identical type arguments. In
+                       // that case, re-use the existing instance.
+                       if named := ctxt.typeForHash(h, nil); named != nil {
+                               return named
                        }
-                       check.trace(pos, "=> %s (under = %s)", res, under)
-               }()
-       }
-
-       assert(len(posList) <= len(targs))
-
-       // TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
+               }
+               tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
+               named := check.newNamed(tname, t, nil, nil, nil) // underlying, tparams, and methods are set when named is resolved
+               named.targs = NewTypeList(targs)
+               named.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, []*Func) {
+                       return expandNamed(ctxt, n, pos)
+               }
+               if ctxt != nil {
+                       // It's possible that we've lost a race to add named to the context.
+                       // In this case, use whichever instance is recorded in the context.
+                       named = ctxt.typeForHash(h, named)
+               }
+               return named
 
-       if len(tparams) == 0 {
-               return typ // nothing to do (minor optimization)
+       case *Signature:
+               tparams := t.TypeParams()
+               if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
+                       return Typ[Invalid]
+               }
+               if tparams.Len() == 0 {
+                       return typ // nothing to do (minor optimization)
+               }
+               sig := check.subst(pos, typ, makeSubstMap(tparams.list(), targs), ctxt).(*Signature)
+               // If the signature doesn't use its type parameters, subst
+               // will not make a copy. In that case, make a copy now (so
+               // we can set tparams to nil w/o causing side-effects).
+               if sig == t {
+                       copy := *sig
+                       sig = &copy
+               }
+               // After instantiating a generic signature, it is not generic
+               // anymore; we need to set tparams to nil.
+               sig.tparams = nil
+               return sig
        }
-
-       smap := makeSubstMap(tparams, targs)
-
-       return check.subst(pos, typ, smap)
+       // only types and functions can be generic
+       panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
 }
 
-// InstantiateLazy is like Instantiate, but avoids actually
-// instantiating the type until needed. typ must be a *Named
-// type.
-func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) Type {
-       // Don't use asNamed here: we don't want to expand the base during lazy
-       // instantiation.
-       base := typ.(*Named)
-       if base == nil {
-               panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
-       }
-       if verify && base.TParams().Len() == len(targs) {
-               check.later(func() {
-                       check.verify(pos, base.tparams.list(), targs, posList)
-               })
-       }
-       h := instantiatedHash(base, targs)
-       if check != nil {
-               // typ may already have been instantiated with identical type arguments. In
-               // that case, re-use the existing instance.
-               if named := check.typMap[h]; named != nil {
-                       return named
+// validateTArgLen verifies that the length of targs and tparams matches,
+// reporting an error if not. If validation fails and check is nil,
+// validateTArgLen panics.
+func (check *Checker) validateTArgLen(pos token.Pos, ntparams, ntargs int) bool {
+       if ntargs != ntparams {
+               // TODO(gri) provide better error message
+               if check != nil {
+                       check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", ntargs, ntparams)
+                       return false
                }
+               panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
        }
-
-       tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil)
-       named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded.
-       named.targs = targs
-       named.instance = &instance{pos, posList}
-
-       if check != nil {
-               check.typMap[h] = named
-       }
-
-       return named
+       return true
 }
 
-func (check *Checker) verify(pos token.Pos, tparams []*TypeName, targs []Type, posList []token.Pos) {
-       if check == nil {
-               panic("cannot have nil Checker if verifying constraints")
-       }
-
+func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type) (int, error) {
        smap := makeSubstMap(tparams, targs)
-       for i, tname := range tparams {
-               // best position for error reporting
-               pos := pos
-               if i < len(posList) {
-                       pos = posList[i]
-               }
-
+       for i, tpar := range tparams {
                // stop checking bounds after the first failure
-               if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) {
-                       break
+               if err := check.satisfies(pos, targs[i], tpar, smap); err != nil {
+                       return i, err
                }
        }
+       return -1, nil
 }
 
 // satisfies reports whether the type argument targ satisfies the constraint of type parameter
 // parameter tpar (after any of its type parameters have been substituted through smap).
 // A suitable error is reported if the result is false.
 // TODO(gri) This should be a method of interfaces or type sets.
-func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap *substMap) bool {
+func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap substMap) error {
        iface := tpar.iface()
+
+       // Every type argument satisfies interface{}.
        if iface.Empty() {
-               return true // no type bound
+               return nil
+       }
+
+       // A type argument that is a type parameter with an empty type set satisfies any constraint.
+       // (The empty set is a subset of any set.)
+       if targ := asTypeParam(targ); targ != nil && targ.iface().typeSet().IsEmpty() {
+               return nil
+       }
+
+       // TODO(rfindley): it would be great if users could pass in a qualifier here,
+       // rather than falling back to verbose qualification. Maybe this can be part
+       // of the shared context.
+       var qf Qualifier
+       if check != nil {
+               qf = check.qualifier
+       }
+       errorf := func(format string, args ...interface{}) error {
+               return errors.New(sprintf(nil, qf, false, format, args...))
+       }
+
+       // No type argument with non-empty type set satisfies the empty type set.
+       if iface.typeSet().IsEmpty() {
+               return errorf("%s does not satisfy %s (constraint type set is empty)", targ, tpar.bound)
        }
 
        // The type parameter bound is parameterized with the same type parameters
        // as the instantiated type; before we can use it for bounds checking we
        // need to instantiate it with the type arguments with which we instantiate
        // the parameterized type.
-       iface = check.subst(pos, iface, smap).(*Interface)
+       iface = check.subst(pos, iface, smap, nil).(*Interface)
 
        // if iface is comparable, targ must be comparable
        // TODO(gri) the error messages needs to be better, here
        if iface.IsComparable() && !Comparable(targ) {
-               if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsTop() {
-                       check.softErrorf(atPos(pos), _Todo, "%s has no constraints", targ)
-                       return false
+               if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsAll() {
+                       return errorf("%s has no constraints", targ)
                }
-               check.softErrorf(atPos(pos), _Todo, "%s does not satisfy comparable", targ)
-               return false
+               return errorf("%s does not satisfy comparable", targ)
        }
 
        // targ must implement iface (methods)
@@ -191,8 +184,7 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap
                // method set is empty.
                // TODO(gri) is this what we want? (spec question)
                if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
-                       check.errorf(atPos(pos), 0, "%s has no methods", targ)
-                       return false
+                       return errorf("%s has no methods", targ)
                }
                if m, wrong := check.missingMethod(targ, iface, true); m != nil {
                        // TODO(gri) needs to print updated name to avoid major confusion in error message!
@@ -203,46 +195,37 @@ func (check *Checker) satisfies(pos token.Pos, targ Type, tpar *TypeParam, smap
                                // TODO(gri) This can still report uninstantiated types which makes the error message
                                //           more difficult to read then necessary.
                                // TODO(rFindley) should this use parentheses rather than ':' for qualification?
-                               check.softErrorf(atPos(pos), _Todo,
-                                       "%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
+                               return errorf("%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
                                        targ, tpar.bound, wrong, m,
                                )
-                       } else {
-                               check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
                        }
-                       return false
+                       return errorf("%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
                }
        }
 
-       // targ's underlying type must also be one of the interface types listed, if any
-       if iface.typeSet().types == nil {
-               return true // nothing to do
+       // targ must also be in the set of types of iface, if any.
+       // Constraints with empty type sets were already excluded above.
+       if !iface.typeSet().hasTerms() {
+               return nil // nothing to do
        }
 
-       // If targ is itself a type parameter, each of its possible types, but at least one, must be in the
-       // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
+       // If targ is itself a type parameter, each of its possible types must be in the set
+       // of iface types (i.e., the targ type set must be a subset of the iface type set).
+       // Type arguments with empty type sets were already excluded above.
        if targ := asTypeParam(targ); targ != nil {
                targBound := targ.iface()
-               if targBound.typeSet().types == nil {
-                       check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
-                       return false
+               if !targBound.typeSet().subsetOf(iface.typeSet()) {
+                       // TODO(gri) report which type is missing
+                       return errorf("%s does not satisfy %s", targ, tpar.bound)
                }
-               return iface.is(func(typ Type, tilde bool) bool {
-                       // TODO(gri) incorporate tilde information!
-                       if !iface.isSatisfiedBy(typ) {
-                               // TODO(gri) match this error message with the one below (or vice versa)
-                               check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, typ, iface.typeSet().types)
-                               return false
-                       }
-                       return true
-               })
+               return nil
        }
 
-       // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
-       if !iface.isSatisfiedBy(targ) {
-               check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ, iface.typeSet().types)
-               return false
+       // Otherwise, targ's type must be included in the iface type set.
+       if !iface.typeSet().includes(targ) {
+               // TODO(gri) report which type is missing
+               return errorf("%s does not satisfy %s", targ, tpar.bound)
        }
 
-       return true
+       return nil
 }
diff --git a/src/go/types/instantiate_test.go b/src/go/types/instantiate_test.go
new file mode 100644 (file)
index 0000000..832c822
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2021 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 types_test
+
+import (
+       . "go/types"
+       "strings"
+       "testing"
+)
+
+func TestInstantiateEquality(t *testing.T) {
+       const src = genericPkg + "p; type T[P any] int"
+
+       pkg, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       T := pkg.Scope().Lookup("T").Type().(*Named)
+
+       // Instantiating the same type twice should result in pointer-equivalent
+       // instances.
+       ctxt := NewContext()
+       res1, err := Instantiate(ctxt, T, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res2, err := Instantiate(ctxt, T, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if res1 != res2 {
+               t.Errorf("first instance (%s) not pointer-equivalent to second instance (%s)", res1, res2)
+       }
+}
+
+func TestInstantiateNonEquality(t *testing.T) {
+       const src = genericPkg + "p; type T[P any] int"
+
+       pkg1, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       pkg2, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // We consider T1 and T2 to be distinct types, so their instances should not
+       // be deduplicated by the context.
+       T1 := pkg1.Scope().Lookup("T").Type().(*Named)
+       T2 := pkg2.Scope().Lookup("T").Type().(*Named)
+
+       ctxt := NewContext()
+       res1, err := Instantiate(ctxt, T1, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+       res2, err := Instantiate(ctxt, T2, []Type{Typ[Int]}, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if res1 == res2 {
+               t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
+       }
+       if Identical(res1, res2) {
+               t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
+       }
+}
+
+func TestMethodInstantiation(t *testing.T) {
+       const prefix = genericPkg + `p
+
+type T[P any] struct{}
+
+var X T[int]
+
+`
+       tests := []struct {
+               decl string
+               want string
+       }{
+               {"func (r T[P]) m() P", "func (T[int]).m() int"},
+               {"func (r T[P]) m(P)", "func (T[int]).m(int)"},
+               {"func (r *T[P]) m(P)", "func (*T[int]).m(int)"},
+               {"func (r T[P]) m() T[P]", "func (T[int]).m() T[int]"},
+               {"func (r T[P]) m(T[P])", "func (T[int]).m(T[int])"},
+               {"func (r T[P]) m(T[P], P, string)", "func (T[int]).m(T[int], int, string)"},
+               {"func (r T[P]) m(T[P], T[string], T[int])", "func (T[int]).m(T[int], T[string], T[int])"},
+       }
+
+       for _, test := range tests {
+               src := prefix + test.decl
+               pkg, err := pkgFor(".", src, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               typ := NewPointer(pkg.Scope().Lookup("X").Type())
+               obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
+               m, _ := obj.(*Func)
+               if m == nil {
+                       t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
+               }
+               if got := ObjectString(m, RelativeTo(pkg)); got != test.want {
+                       t.Errorf("instantiated %q, want %q", got, test.want)
+               }
+       }
+}
+
+func TestImmutableSignatures(t *testing.T) {
+       const src = genericPkg + `p
+
+type T[P any] struct{}
+
+func (T[P]) m() {}
+
+var _ T[int]
+`
+       pkg, err := pkgFor(".", src, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       typ := pkg.Scope().Lookup("T").Type().(*Named)
+       obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
+       if obj == nil {
+               t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
+       }
+
+       // Verify that the original method is not mutated by instantiating T (this
+       // bug manifested when subst did not return a new signature).
+       want := "func (T[P]).m()"
+       if got := stripAnnotations(ObjectString(obj, RelativeTo(pkg))); got != want {
+               t.Errorf("instantiated %q, want %q", got, want)
+       }
+}
+
+// Copied from errors.go.
+func stripAnnotations(s string) string {
+       var b strings.Builder
+       for _, r := range s {
+               // strip #'s and subscript digits
+               if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
+                       b.WriteRune(r)
+               }
+       }
+       if b.Len() < len(s) {
+               return b.String()
+       }
+       return s
+}
index d8f967185713295e005faadc83d520384c08ed05..78813e665bf1b605986eb202f8c73f320eaeb75b 100644 (file)
@@ -6,7 +6,6 @@ package types
 
 import (
        "go/ast"
-       "go/internal/typeparams"
        "go/token"
 )
 
@@ -15,30 +14,19 @@ import (
 
 // An Interface represents an interface type.
 type Interface struct {
+       check     *Checker     // for error reporting; nil once type set is computed
        obj       *TypeName    // type name object defining this interface; or nil (for better error messages)
        methods   []*Func      // ordered list of explicitly declared methods
        embeddeds []Type       // ordered list of explicitly embedded elements
        embedPos  *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space
+       implicit  bool         // interface is wrapper for type set literal (non-interface T, ~T, or A|B)
        complete  bool         // indicates that obj, methods, and embeddeds are set and type set can be computed
 
        tset *_TypeSet // type set described by this interface, computed lazily
 }
 
 // typeSet returns the type set for interface t.
-func (t *Interface) typeSet() *_TypeSet { return computeTypeSet(nil, token.NoPos, t) }
-
-// is reports whether interface t represents types that all satisfy f.
-func (t *Interface) is(f func(Type, bool) bool) bool {
-       switch t := t.typeSet().types.(type) {
-       case nil, *top:
-               // TODO(gri) should settle on top or nil to represent this case
-               return false // we must have at least one type! (was bug)
-       case *Union:
-               return t.is(func(t *term) bool { return f(t.typ, t.tilde) })
-       default:
-               return f(t, false)
-       }
-}
+func (t *Interface) typeSet() *_TypeSet { return computeInterfaceTypeSet(t.check, token.NoPos, t) }
 
 // emptyInterface represents the empty (completed) interface
 var emptyInterface = Interface{complete: true, tset: &topTypeSet}
@@ -56,9 +44,12 @@ func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
        return NewInterfaceType(methods, tnames)
 }
 
-// NewInterfaceType returns a new interface for the given methods and embedded types.
-// NewInterfaceType takes ownership of the provided methods and may modify their types
-// by setting missing receivers.
+// NewInterfaceType returns a new interface for the given methods and embedded
+// types. NewInterfaceType takes ownership of the provided methods and may
+// modify their types by setting missing receivers.
+//
+// To avoid race conditions, the interface's type set should be computed before
+// concurrent use of the interface, by explicitly calling Complete.
 func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        if len(methods) == 0 && len(embeddeds) == 0 {
                return &emptyInterface
@@ -82,6 +73,14 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        return typ
 }
 
+// MarkImplicit marks the interface t as implicit, meaning this interface
+// corresponds to a constraint literal such as ~T or A|B without explicit
+// interface embedding. MarkImplicit should be called before any concurrent use
+// of implicit interfaces.
+func (t *Interface) MarkImplicit() {
+       t.implicit = true
+}
+
 // NumExplicitMethods returns the number of explicitly declared methods of interface t.
 func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
 
@@ -109,30 +108,17 @@ func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() }
 func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) }
 
 // Empty reports whether t is the empty interface.
-func (t *Interface) Empty() bool { return t.typeSet().IsTop() }
+func (t *Interface) Empty() bool { return t.typeSet().IsAll() }
 
 // IsComparable reports whether each type in interface t's type set is comparable.
 func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() }
 
-// IsConstraint reports whether interface t is not just a method set.
-func (t *Interface) IsConstraint() bool { return !t.typeSet().IsMethodSet() }
-
-// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ.
-// If the type list is empty (absent), typ trivially satisfies the interface.
-// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive
-//           "implements" predicate.
-func (t *Interface) isSatisfiedBy(typ Type) bool {
-       t.Complete()
-       switch t := t.typeSet().types.(type) {
-       case nil:
-               return true // no type restrictions
-       case *Union:
-               r, _ := t.intersect(typ, false)
-               return r != nil
-       default:
-               return Identical(t, typ)
-       }
-}
+// IsMethodSet reports whether the interface t is fully described by its method
+// set.
+func (t *Interface) IsMethodSet() bool { return t.typeSet().IsMethodSet() }
+
+// IsImplicit reports whether the interface t is a wrapper for a type set literal.
+func (t *Interface) IsImplicit() bool { return t.implicit }
 
 // Complete computes the interface's type set. It must be called by users of
 // NewInterfaceType and NewInterface after the interface's embedded types are
@@ -140,16 +126,12 @@ func (t *Interface) isSatisfiedBy(typ Type) bool {
 // form other types. The interface must not contain duplicate methods or a
 // panic occurs. Complete returns the receiver.
 //
-// Deprecated: Type sets are now computed lazily, on demand; this function
-//             is only here for backward-compatibility. It does not have to
-//             be called explicitly anymore.
+// Interface types that have been completed are safe for concurrent use.
 func (t *Interface) Complete() *Interface {
-       // Some tests are still depending on the state change
-       // (string representation of an Interface not containing an
-       // /* incomplete */ marker) caused by the explicit Complete
-       // call, so we compute the type set eagerly here.
-       t.complete = true
-       t.typeSet()
+       if !t.complete {
+               t.complete = true
+       }
+       t.typeSet() // checks if t.tset is already set
        return t
 }
 
@@ -160,9 +142,6 @@ func (t *Interface) String() string   { return TypeString(t, nil) }
 // Implementation
 
 func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
-       var tlist []ast.Expr
-       var tname *ast.Ident // "type" name of first entry in a type list declaration
-
        addEmbedded := func(pos token.Pos, typ Type) {
                ityp.embeddeds = append(ityp.embeddeds, typ)
                if ityp.embedPos == nil {
@@ -173,45 +152,18 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
 
        for _, f := range iface.Methods.List {
                if len(f.Names) == 0 {
-                       // We have an embedded type; possibly a union of types.
                        addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type)))
                        continue
                }
+               // f.Name != nil
 
-               // We have a method with name f.Names[0], or a type
-               // of a type list (name.Name == "type").
-               // (The parser ensures that there's only one method
-               // and we don't care if a constructed AST has more.)
+               // We have a method with name f.Names[0].
                name := f.Names[0]
                if name.Name == "_" {
                        check.errorf(name, _BlankIfaceMethod, "invalid method name _")
                        continue // ignore
                }
 
-               // TODO(rfindley) Remove type list handling once the parser doesn't accept type lists anymore.
-               if name.Name == "type" {
-                       // Report an error for the first type list per interface
-                       // if we don't allow type lists, but continue.
-                       if !allowTypeLists && tlist == nil {
-                               check.softErrorf(name, _Todo, "use generalized embedding syntax instead of a type list")
-                       }
-                       // For now, collect all type list entries as if it
-                       // were a single union, where each union element is
-                       // of the form ~T.
-                       // TODO(rfindley) remove once we disallow type lists
-                       op := new(ast.UnaryExpr)
-                       op.Op = token.TILDE
-                       op.X = f.Type
-                       tlist = append(tlist, op)
-                       // Report an error if we have multiple type lists in an
-                       // interface, but only if they are permitted in the first place.
-                       if allowTypeLists && tname != nil && tname != name {
-                               check.errorf(name, _Todo, "cannot have multiple type lists in an interface")
-                       }
-                       tname = name
-                       continue
-               }
-
                typ := check.typ(f.Type)
                sig, _ := typ.(*Signature)
                if sig == nil {
@@ -226,8 +178,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
                // a receiver specification.)
                if sig.tparams != nil {
                        var at positioner = f.Type
-                       if tparams := typeparams.Get(f.Type); tparams != nil {
-                               at = tparams
+                       if ftyp, _ := f.Type.(*ast.FuncType); ftyp != nil && ftyp.TypeParams != nil {
+                               at = ftyp.TypeParams
                        }
                        check.errorf(at, _Todo, "methods cannot have type parameters")
                }
@@ -244,15 +196,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
                ityp.methods = append(ityp.methods, m)
        }
 
-       // type constraints
-       if tlist != nil {
-               // TODO(rfindley): this differs from types2 due to the use of Pos() below,
-               // which should actually be on the ~. Confirm that this position is correct.
-               addEmbedded(tlist[0].Pos(), parseUnion(check, tlist))
-       }
-
        // All methods and embedded elements for this interface are collected;
-       // i.e., this interface is may be used in a type set computation.
+       // i.e., this interface may be used in a type set computation.
        ityp.complete = true
 
        if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
@@ -268,7 +213,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
        // Compute type set with a non-nil *Checker as soon as possible
        // to report any errors. Subsequent uses of type sets will use
        // this computed type set and won't need to pass in a *Checker.
-       check.later(func() { computeTypeSet(check, iface.Pos(), ityp) })
+       //
+       // Pin the checker to the interface type in the interim, in case the type set
+       // must be used before delayed funcs are processed (see issue #48234).
+       // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
+       ityp.check = check
+       check.later(func() {
+               computeInterfaceTypeSet(check, iface.Pos(), ityp)
+               ityp.check = nil
+       }).describef(iface, "compute type set for %s", ityp)
 }
 
 func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr {
index 7cab336dbe2e8632d1551afbe0b6fec02e555d7b..afb1215af28639359e692ce5d475ac2b342f413c 100644 (file)
@@ -6,8 +6,6 @@
 
 package types
 
-import "go/token"
-
 // Internal use of LookupFieldOrMethod: If the obj result is a method
 // associated with a concrete (non-interface) type, the method's signature
 // may not be fully set up. Call Checker.objDecl(obj, nil) before accessing
@@ -48,7 +46,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
        // pointer type but discard the result if it is a method since we would
        // not have found it for T (see also issue 8590).
        if t := asNamed(T); t != nil {
-               if p, _ := t.Underlying().(*Pointer); p != nil {
+               if p, _ := safeUnderlying(t).(*Pointer); p != nil {
                        obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
                        if _, ok := obj.(*Func); ok {
                                return nil, nil, false
@@ -76,9 +74,12 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
        typ, isPtr := deref(T)
 
        // *typ where typ is an interface or type parameter has no methods.
-       switch under(typ).(type) {
-       case *Interface, *TypeParam:
-               if isPtr {
+       if isPtr {
+               // don't look at under(typ) here - was bug (issue #47747)
+               if _, ok := typ.(*TypeParam); ok {
+                       return
+               }
+               if _, ok := under(typ).(*Interface); ok {
                        return
                }
        }
@@ -121,7 +122,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                                seen[named] = true
 
                                // look for a matching attached method
-                               named.load()
+                               named.resolve(nil)
                                if i, m := lookupMethod(named.methods, pkg, name); m != nil {
                                        // potential match
                                        // caution: method may not have a proper signature yet
@@ -211,7 +212,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
                        //        is shorthand for (&x).m()".
                        if f, _ := obj.(*Func); f != nil {
                                // determine if method has a pointer receiver
-                               hasPtrRecv := tpar == nil && ptrRecv(f)
+                               hasPtrRecv := tpar == nil && f.hasPtrRecv()
                                if hasPtrRecv && !indirect && !addressable {
                                        return nil, nil, true // pointer/addressable receiver required
                                }
@@ -316,11 +317,11 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // both methods must have the same number of type parameters
                        ftyp := f.typ.(*Signature)
                        mtyp := m.typ.(*Signature)
-                       if ftyp.TParams().Len() != mtyp.TParams().Len() {
+                       if ftyp.TypeParams().Len() != mtyp.TypeParams().Len() {
                                return m, f
                        }
-                       if ftyp.TParams().Len() > 0 {
-                               panic("internal error: method with type parameters")
+                       if ftyp.TypeParams().Len() > 0 {
+                               panic("method with type parameters")
                        }
 
                        // If the methods have type parameters we don't care whether they
@@ -329,7 +330,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        // TODO(gri) is this always correct? what about type bounds?
                        // (Alternative is to rename/subst type parameters and compare.)
                        u := newUnifier(true)
-                       u.x.init(ftyp.TParams().list())
+                       u.x.init(ftyp.TypeParams().list())
                        if !u.unify(ftyp, mtyp) {
                                return m, f
                        }
@@ -339,8 +340,6 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
        }
 
        // A concrete type implements T if it implements all methods of T.
-       Vd, _ := deref(V)
-       Vn := asNamed(Vd)
        for _, m := range T.typeSet().methods {
                // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
                obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
@@ -368,31 +367,11 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // both methods must have the same number of type parameters
                ftyp := f.typ.(*Signature)
                mtyp := m.typ.(*Signature)
-               if ftyp.TParams().Len() != mtyp.TParams().Len() {
+               if ftyp.TypeParams().Len() != mtyp.TypeParams().Len() {
                        return m, f
                }
-               if ftyp.TParams().Len() > 0 {
-                       panic("internal error: method with type parameters")
-               }
-
-               // If V is a (instantiated) generic type, its methods are still
-               // parameterized using the original (declaration) receiver type
-               // parameters (subst simply copies the existing method list, it
-               // does not instantiate the methods).
-               // In order to compare the signatures, substitute the receiver
-               // type parameters of ftyp with V's instantiation type arguments.
-               // This lazily instantiates the signature of method f.
-               if Vn != nil && Vn.TParams().Len() > 0 {
-                       // Be careful: The number of type arguments may not match
-                       // the number of receiver parameters. If so, an error was
-                       // reported earlier but the length discrepancy is still
-                       // here. Exit early in this case to prevent an assertion
-                       // failure in makeSubstMap.
-                       // TODO(gri) Can we avoid this check by fixing the lengths?
-                       if len(ftyp.RParams().list()) != len(Vn.targs) {
-                               return
-                       }
-                       ftyp = check.subst(token.NoPos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs)).(*Signature)
+               if ftyp.TypeParams().Len() > 0 {
+                       panic("method with type parameters")
                }
 
                // If the methods have type parameters we don't care whether they
@@ -401,7 +380,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // TODO(gri) is this always correct? what about type bounds?
                // (Alternative is to rename/subst type parameters and compare.)
                u := newUnifier(true)
-               u.x.init(ftyp.RParams().list())
+               u.x.init(ftyp.RecvTypeParams().list())
                if !u.unify(ftyp, mtyp) {
                        return m, f
                }
index 1462601d5869e4a135bf8be616bd4028c49c090e..89e4b57627f9e337f77e7a9eff0832cd03130e1d 100644 (file)
@@ -232,10 +232,10 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
                // if f is not in the set, add it
                if !multiples {
                        // TODO(gri) A found method may not be added because it's not in the method set
-                       // (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
+                       // (!indirect && f.hasPtrRecv()). A 2nd method on the same level may be in the method
                        // set and may not collide with the first one, thus leading to a false positive.
                        // Is that possible? Investigate.
-                       if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
+                       if _, found := s[key]; !found && (indirect || !f.hasPtrRecv()) {
                                s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
                                continue
                        }
@@ -244,22 +244,3 @@ func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool)
        }
        return s
 }
-
-// ptrRecv reports whether the receiver is of the form *T.
-func ptrRecv(f *Func) bool {
-       // If a method's receiver type is set, use that as the source of truth for the receiver.
-       // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
-       // signature. We may reach here before the signature is fully set up: we must explicitly
-       // check if the receiver is set (we cannot just look for non-nil f.typ).
-       if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
-               _, isPtr := deref(sig.recv.typ)
-               return isPtr
-       }
-
-       // If a method's type is not set it may be a method/function that is:
-       // 1) client-supplied (via NewFunc with no signature), or
-       // 2) internally created but not yet type-checked.
-       // For case 1) we can't do anything; the client must know what they are doing.
-       // For case 2) we can use the information gathered by the resolver.
-       return f.hasPtrRecv
-}
diff --git a/src/go/types/mono.go b/src/go/types/mono.go
new file mode 100644 (file)
index 0000000..d4d8843
--- /dev/null
@@ -0,0 +1,335 @@
+// Copyright 2021 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 types
+
+import (
+       "go/token"
+)
+
+// This file implements a check to validate that a Go package doesn't
+// have unbounded recursive instantiation, which is not compatible
+// with compilers using static instantiation (such as
+// monomorphization).
+//
+// It implements a sort of "type flow" analysis by detecting which
+// type parameters are instantiated with other type parameters (or
+// types derived thereof). A package cannot be statically instantiated
+// if the graph has any cycles involving at least one derived type.
+//
+// Concretely, we construct a directed, weighted graph. Vertices are
+// used to represent type parameters as well as some defined
+// types. Edges are used to represent how types depend on each other:
+//
+// * Everywhere a type-parameterized function or type is instantiated,
+//   we add edges to each type parameter from the vertices (if any)
+//   representing each type parameter or defined type referenced by
+//   the type argument. If the type argument is just the referenced
+//   type itself, then the edge has weight 0, otherwise 1.
+//
+// * For every defined type declared within a type-parameterized
+//   function or method, we add an edge of weight 1 to the defined
+//   type from each ambient type parameter.
+//
+// For example, given:
+//
+//     func f[A, B any]() {
+//             type T int
+//             f[T, map[A]B]()
+//     }
+//
+// we construct vertices representing types A, B, and T. Because of
+// declaration "type T int", we construct edges T<-A and T<-B with
+// weight 1; and because of instantiation "f[T, map[A]B]" we construct
+// edges A<-T with weight 0, and B<-A and B<-B with weight 1.
+//
+// Finally, we look for any positive-weight cycles. Zero-weight cycles
+// are allowed because static instantiation will reach a fixed point.
+
+type monoGraph struct {
+       vertices []monoVertex
+       edges    []monoEdge
+
+       // canon maps method receiver type parameters to their respective
+       // receiver type's type parameters.
+       canon map[*TypeParam]*TypeParam
+
+       // nameIdx maps a defined type or (canonical) type parameter to its
+       // vertex index.
+       nameIdx map[*TypeName]int
+}
+
+type monoVertex struct {
+       weight int // weight of heaviest known path to this vertex
+       pre    int // previous edge (if any) in the above path
+       len    int // length of the above path
+
+       // obj is the defined type or type parameter represented by this
+       // vertex.
+       obj *TypeName
+}
+
+type monoEdge struct {
+       dst, src int
+       weight   int
+
+       pos token.Pos
+       typ Type
+}
+
+func (check *Checker) monomorph() {
+       // We detect unbounded instantiation cycles using a variant of
+       // Bellman-Ford's algorithm. Namely, instead of always running |V|
+       // iterations, we run until we either reach a fixed point or we've
+       // found a path of length |V|. This allows us to terminate earlier
+       // when there are no cycles, which should be the common case.
+
+       again := true
+       for again {
+               again = false
+
+               for i, edge := range check.mono.edges {
+                       src := &check.mono.vertices[edge.src]
+                       dst := &check.mono.vertices[edge.dst]
+
+                       // N.B., we're looking for the greatest weight paths, unlike
+                       // typical Bellman-Ford.
+                       w := src.weight + edge.weight
+                       if w <= dst.weight {
+                               continue
+                       }
+
+                       dst.pre = i
+                       dst.len = src.len + 1
+                       if dst.len == len(check.mono.vertices) {
+                               check.reportInstanceLoop(edge.dst)
+                               return
+                       }
+
+                       dst.weight = w
+                       again = true
+               }
+       }
+}
+
+func (check *Checker) reportInstanceLoop(v int) {
+       var stack []int
+       seen := make([]bool, len(check.mono.vertices))
+
+       // We have a path that contains a cycle and ends at v, but v may
+       // only be reachable from the cycle, not on the cycle itself. We
+       // start by walking backwards along the path until we find a vertex
+       // that appears twice.
+       for !seen[v] {
+               stack = append(stack, v)
+               seen[v] = true
+               v = check.mono.edges[check.mono.vertices[v].pre].src
+       }
+
+       // Trim any vertices we visited before visiting v the first
+       // time. Since v is the first vertex we found within the cycle, any
+       // vertices we visited earlier cannot be part of the cycle.
+       for stack[0] != v {
+               stack = stack[1:]
+       }
+
+       // TODO(mdempsky): Pivot stack so we report the cycle from the top?
+
+       obj0 := check.mono.vertices[v].obj
+       check.errorf(obj0, _InvalidInstanceCycle, "instantiation cycle:")
+
+       qf := RelativeTo(check.pkg)
+       for _, v := range stack {
+               edge := check.mono.edges[check.mono.vertices[v].pre]
+               obj := check.mono.vertices[edge.dst].obj
+
+               switch obj.Type().(type) {
+               default:
+                       panic("unexpected type")
+               case *Named:
+                       check.errorf(atPos(edge.pos), _InvalidInstanceCycle, "\t%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
+               case *TypeParam:
+                       check.errorf(atPos(edge.pos), _InvalidInstanceCycle, "\t%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
+               }
+       }
+}
+
+// recordCanon records that tpar is the canonical type parameter
+// corresponding to method type parameter mpar.
+func (w *monoGraph) recordCanon(mpar, tpar *TypeParam) {
+       if w.canon == nil {
+               w.canon = make(map[*TypeParam]*TypeParam)
+       }
+       w.canon[mpar] = tpar
+}
+
+// recordInstance records that the given type parameters were
+// instantiated with the corresponding type arguments.
+func (w *monoGraph) recordInstance(pkg *Package, pos token.Pos, tparams []*TypeParam, targs []Type, posList []token.Pos) {
+       for i, tpar := range tparams {
+               pos := pos
+               if i < len(posList) {
+                       pos = posList[i]
+               }
+               w.assign(pkg, pos, tpar, targs[i])
+       }
+}
+
+// assign records that tpar was instantiated as targ at pos.
+func (w *monoGraph) assign(pkg *Package, pos token.Pos, tpar *TypeParam, targ Type) {
+       // Go generics do not have an analog to C++`s template-templates,
+       // where a template parameter can itself be an instantiable
+       // template. So any instantiation cycles must occur within a single
+       // package. Accordingly, we can ignore instantiations of imported
+       // type parameters.
+       //
+       // TODO(mdempsky): Push this check up into recordInstance? All type
+       // parameters in a list will appear in the same package.
+       if tpar.Obj().Pkg() != pkg {
+               return
+       }
+
+       // flow adds an edge from vertex src representing that typ flows to tpar.
+       flow := func(src int, typ Type) {
+               weight := 1
+               if typ == targ {
+                       weight = 0
+               }
+
+               w.addEdge(w.typeParamVertex(tpar), src, weight, pos, targ)
+       }
+
+       // Recursively walk the type argument to find any defined types or
+       // type parameters.
+       var do func(typ Type)
+       do = func(typ Type) {
+               switch typ := typ.(type) {
+               default:
+                       panic("unexpected type")
+
+               case *TypeParam:
+                       assert(typ.Obj().Pkg() == pkg)
+                       flow(w.typeParamVertex(typ), typ)
+
+               case *Named:
+                       if src := w.localNamedVertex(pkg, typ.Origin()); src >= 0 {
+                               flow(src, typ)
+                       }
+
+                       targs := typ.TypeArgs()
+                       for i := 0; i < targs.Len(); i++ {
+                               do(targs.At(i))
+                       }
+
+               case *Array:
+                       do(typ.Elem())
+               case *Basic:
+                       // ok
+               case *Chan:
+                       do(typ.Elem())
+               case *Map:
+                       do(typ.Key())
+                       do(typ.Elem())
+               case *Pointer:
+                       do(typ.Elem())
+               case *Slice:
+                       do(typ.Elem())
+
+               case *Interface:
+                       for i := 0; i < typ.NumMethods(); i++ {
+                               do(typ.Method(i).Type())
+                       }
+               case *Signature:
+                       tuple := func(tup *Tuple) {
+                               for i := 0; i < tup.Len(); i++ {
+                                       do(tup.At(i).Type())
+                               }
+                       }
+                       tuple(typ.Params())
+                       tuple(typ.Results())
+               case *Struct:
+                       for i := 0; i < typ.NumFields(); i++ {
+                               do(typ.Field(i).Type())
+                       }
+               }
+       }
+       do(targ)
+}
+
+// localNamedVertex returns the index of the vertex representing
+// named, or -1 if named doesn't need representation.
+func (w *monoGraph) localNamedVertex(pkg *Package, named *Named) int {
+       obj := named.Obj()
+       if obj.Pkg() != pkg {
+               return -1 // imported type
+       }
+
+       root := pkg.Scope()
+       if obj.Parent() == root {
+               return -1 // package scope, no ambient type parameters
+       }
+
+       if idx, ok := w.nameIdx[obj]; ok {
+               return idx
+       }
+
+       idx := -1
+
+       // Walk the type definition's scope to find any ambient type
+       // parameters that it's implicitly parameterized by.
+       for scope := obj.Parent(); scope != root; scope = scope.Parent() {
+               for _, elem := range scope.elems {
+                       if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && elem.Pos() < obj.Pos() {
+                               if tpar, ok := elem.Type().(*TypeParam); ok {
+                                       if idx < 0 {
+                                               idx = len(w.vertices)
+                                               w.vertices = append(w.vertices, monoVertex{obj: obj})
+                                       }
+
+                                       w.addEdge(idx, w.typeParamVertex(tpar), 1, obj.Pos(), tpar)
+                               }
+                       }
+               }
+       }
+
+       if w.nameIdx == nil {
+               w.nameIdx = make(map[*TypeName]int)
+       }
+       w.nameIdx[obj] = idx
+       return idx
+}
+
+// typeParamVertex returns the index of the vertex representing tpar.
+func (w *monoGraph) typeParamVertex(tpar *TypeParam) int {
+       if x, ok := w.canon[tpar]; ok {
+               tpar = x
+       }
+
+       obj := tpar.Obj()
+
+       if idx, ok := w.nameIdx[obj]; ok {
+               return idx
+       }
+
+       if w.nameIdx == nil {
+               w.nameIdx = make(map[*TypeName]int)
+       }
+
+       idx := len(w.vertices)
+       w.vertices = append(w.vertices, monoVertex{obj: obj})
+       w.nameIdx[obj] = idx
+       return idx
+}
+
+func (w *monoGraph) addEdge(dst, src, weight int, pos token.Pos, typ Type) {
+       // TODO(mdempsky): Deduplicate redundant edges?
+       w.edges = append(w.edges, monoEdge{
+               dst:    dst,
+               src:    src,
+               weight: weight,
+
+               pos: pos,
+               typ: typ,
+       })
+}
diff --git a/src/go/types/mono_test.go b/src/go/types/mono_test.go
new file mode 100644 (file)
index 0000000..5df3d49
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2021 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 types_test
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+       "go/ast"
+       "go/importer"
+       "go/parser"
+       "go/token"
+       "go/types"
+       "strings"
+       "testing"
+)
+
+func checkMono(t *testing.T, body string) error {
+       fset := token.NewFileSet()
+       file, err := parser.ParseFile(fset, "x.go", "package x; import `unsafe`; var _ unsafe.Pointer;\n"+body, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+       files := []*ast.File{file}
+
+       var buf bytes.Buffer
+       conf := types.Config{
+               Error:    func(err error) { fmt.Fprintln(&buf, err) },
+               Importer: importer.Default(),
+       }
+       conf.Check("x", fset, files, nil)
+       if buf.Len() == 0 {
+               return nil
+       }
+       return errors.New(strings.TrimRight(buf.String(), "\n"))
+}
+
+func TestMonoGood(t *testing.T) {
+       for i, good := range goods {
+               if err := checkMono(t, good); err != nil {
+                       t.Errorf("%d: unexpected failure: %v", i, err)
+               }
+       }
+}
+
+func TestMonoBad(t *testing.T) {
+       for i, bad := range bads {
+               if err := checkMono(t, bad); err == nil {
+                       t.Errorf("%d: unexpected success", i)
+               } else {
+                       t.Log(err)
+               }
+       }
+}
+
+var goods = []string{
+       "func F[T any](x T) { F(x) }",
+       "func F[T, U, V any]() { F[U, V, T](); F[V, T, U]() }",
+       "type Ring[A, B, C any] struct { L *Ring[B, C, A]; R *Ring[C, A, B] }",
+       "func F[T any]() { type U[T any] [unsafe.Sizeof(F[*T])]byte }",
+       "func F[T any]() { type U[T any] [unsafe.Sizeof(F[*T])]byte; var _ U[int] }",
+       "type U[T any] [unsafe.Sizeof(F[*T])]byte; func F[T any]() { var _ U[U[int]] }",
+       "func F[T any]() { type A = int; F[A]() }",
+}
+
+// TODO(mdempsky): Validate specific error messages and positioning.
+
+var bads = []string{
+       "func F[T any](x T) { F(&x) }",
+       "func F[T any]() { F[*T]() }",
+       "func F[T any]() { F[[]T]() }",
+       "func F[T any]() { F[[1]T]() }",
+       "func F[T any]() { F[chan T]() }",
+       "func F[T any]() { F[map[*T]int]() }",
+       "func F[T any]() { F[map[error]T]() }",
+       "func F[T any]() { F[func(T)]() }",
+       "func F[T any]() { F[func() T]() }",
+       "func F[T any]() { F[struct{ t T }]() }",
+       "func F[T any]() { F[interface{ t() T }]() }",
+       "type U[_ any] int; func F[T any]() { F[U[T]]() }",
+       "func F[T any]() { type U int; F[U]() }",
+       "func F[T any]() { type U int; F[*U]() }",
+       "type U[T any] int; func (U[T]) m() { var _ U[*T] }",
+       "type U[T any] int; func (*U[T]) m() { var _ U[*T] }",
+       "type U[T1 any] [unsafe.Sizeof(F[*T1])]byte; func F[T2 any]() { var _ U[T2] }",
+       "func F[A, B, C, D, E any]() { F[B, C, D, E, *A]() }",
+       "type U[_ any] int; const X = unsafe.Sizeof(func() { type A[T any] U[A[*T]] })",
+       "func F[T any]() { type A = *T; F[A]() }",
+       "type A[T any] struct { _ A[*T] }",
+}
index f26b50aa81177fb449c90b886f4f66c10a2fc486..393d40b127cb27a7dcb45e748978105913969876 100644 (file)
@@ -9,23 +9,21 @@ import (
        "sync"
 )
 
-// TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?).
-
 // A Named represents a named (defined) type.
 type Named struct {
        check      *Checker
-       info       typeInfo    // for cycle detection
-       obj        *TypeName   // corresponding declared object
-       orig       *Named      // original, uninstantiated type
-       fromRHS    Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
-       underlying Type        // possibly a *Named during setup; never a *Named once set up completely
-       instance   *instance   // syntactic information for lazy instantiation
-       tparams    *TypeParams // type parameters, or nil
-       targs      []Type      // type arguments (after instantiation), or nil
-       methods    []*Func     // methods declared for this type (not the method set of this type); signatures are type-checked lazily
-
-       resolve func(*Named) ([]*TypeName, Type, []*Func)
-       once    sync.Once
+       info       typeInfo       // for cycle detection
+       obj        *TypeName      // corresponding declared object for declared types; placeholder for instantiated types
+       orig       *Named         // original, uninstantiated type
+       fromRHS    Type           // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
+       underlying Type           // possibly a *Named during setup; never a *Named once set up completely
+       tparams    *TypeParamList // type parameters, or nil
+       targs      *TypeList      // type arguments (after instantiation), or nil
+       methods    []*Func        // methods declared for this type (not the method set of this type); signatures are type-checked lazily
+
+       // resolver may be provided to lazily resolve type parameters, underlying, and methods.
+       resolver func(*Context, *Named) (tparams *TypeParamList, underlying Type, methods []*Func)
+       once     sync.Once // ensures that tparams, underlying, and methods are resolved before accessing
 }
 
 // NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@ -33,54 +31,33 @@ type Named struct {
 // The underlying type must not be a *Named.
 func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
        if _, ok := underlying.(*Named); ok {
-               panic("types.NewNamed: underlying type must not be *Named")
+               panic("underlying type must not be *Named")
        }
        return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
 }
 
-func (t *Named) load() *Named {
-       // If t is an instantiated type, it derives its methods and tparams from its
-       // base type. Since we expect type parameters and methods to be set after a
-       // call to load, we must load the base and copy here.
-       //
-       // underlying is set when t is expanded.
-       //
-       // By convention, a type instance is loaded iff its tparams are set.
-       if len(t.targs) > 0 && t.tparams == nil {
-               t.orig.load()
-               t.tparams = t.orig.tparams
-               t.methods = t.orig.methods
-       }
-       if t.resolve == nil {
+func (t *Named) resolve(ctxt *Context) *Named {
+       if t.resolver == nil {
                return t
        }
 
        t.once.Do(func() {
-               // TODO(mdempsky): Since we're passing t to resolve anyway
+               // TODO(mdempsky): Since we're passing t to the resolver anyway
                // (necessary because types2 expects the receiver type for methods
                // on defined interface types to be the Named rather than the
                // underlying Interface), maybe it should just handle calling
-               // SetTParams, SetUnderlying, and AddMethod instead?  Those
-               // methods would need to support reentrant calls though.  It would
+               // SetTypeParams, SetUnderlying, and AddMethod instead?  Those
+               // methods would need to support reentrant calls though. It would
                // also make the API more future-proof towards further extensions
-               // (like SetTParams).
-
-               tparams, underlying, methods := t.resolve(t)
-
-               switch underlying.(type) {
-               case nil, *Named:
-                       panic("invalid underlying type")
-               }
-
-               t.tparams = bindTParams(tparams)
-               t.underlying = underlying
-               t.methods = methods
+               // (like SetTypeParams).
+               t.tparams, t.underlying, t.methods = t.resolver(ctxt, t)
+               t.fromRHS = t.underlying // for cycle detection
        })
        return t
 }
 
 // newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
-func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParams, methods []*Func) *Named {
+func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParamList, methods []*Func) *Named {
        typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
        if typ.orig == nil {
                typ.orig = typ
@@ -88,79 +65,62 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
        if obj.typ == nil {
                obj.typ = typ
        }
-       // Ensure that typ is always expanded, at which point the check field can be
-       // nilled out.
-       //
-       // Note that currently we cannot nil out check inside typ.under(), because
-       // it's possible that typ is expanded multiple times.
-       //
-       // TODO(rFindley): clean this up so that under is the only function mutating
-       //                 named types.
+       // Ensure that typ is always expanded and sanity-checked.
        if check != nil {
-               check.later(func() {
-                       switch typ.under().(type) {
-                       case *Named:
-                               panic("internal error: unexpanded underlying type")
-                       }
-                       typ.check = nil
-               })
+               check.defTypes = append(check.defTypes, typ)
        }
        return typ
 }
 
-// Obj returns the type name for the named type t.
-func (t *Named) Obj() *TypeName { return t.obj }
+// Obj returns the type name for the declaration defining the named type t. For
+// instantiated types, this is the type name of the base type.
+func (t *Named) Obj() *TypeName {
+       return t.orig.obj // for non-instances this is the same as t.obj
+}
 
-// _Orig returns the original generic type an instantiated type is derived from.
-// If t is not an instantiated type, the result is t.
-func (t *Named) _Orig() *Named { return t.orig }
+// Origin returns the parameterized type from which the named type t is
+// instantiated. If t is not an instantiated type, the result is t.
+func (t *Named) Origin() *Named { return t.orig }
 
 // TODO(gri) Come up with a better representation and API to distinguish
 //           between parameterized instantiated and non-instantiated types.
 
-// TParams returns the type parameters of the named type t, or nil.
+// TypeParams returns the type parameters of the named type t, or nil.
 // The result is non-nil for an (originally) parameterized type even if it is instantiated.
-func (t *Named) TParams() *TypeParams { return t.load().tparams }
+func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
 
-// SetTParams sets the type parameters of the named type t.
-func (t *Named) SetTParams(tparams []*TypeName) { t.load().tparams = bindTParams(tparams) }
+// SetTypeParams sets the type parameters of the named type t.
+func (t *Named) SetTypeParams(tparams []*TypeParam) { t.resolve(nil).tparams = bindTParams(tparams) }
 
-// NumTArgs returns the number of type arguments used to instantiate the named
-// type t, or 0 if t is not an instantiated type.
-func (t *Named) NumTArgs() int { return len(t.targs) }
-
-// TArgs returns the i'th type argument of the named type t for 0 <= i < t.NumTArgs().
-func (t *Named) TArg(i int) Type { return t.targs[i] }
-
-// SetTArgs sets the type arguments of the named type t.
-func (t *Named) SetTArgs(args []Type) { t.targs = args }
+// TypeArgs returns the type arguments used to instantiate the named type t.
+func (t *Named) TypeArgs() *TypeList { return t.targs }
 
 // NumMethods returns the number of explicit methods whose receiver is named type t.
-func (t *Named) NumMethods() int { return len(t.load().methods) }
+func (t *Named) NumMethods() int { return len(t.resolve(nil).methods) }
 
 // Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
-func (t *Named) Method(i int) *Func { return t.load().methods[i] }
+func (t *Named) Method(i int) *Func { return t.resolve(nil).methods[i] }
 
 // SetUnderlying sets the underlying type and marks t as complete.
 func (t *Named) SetUnderlying(underlying Type) {
        if underlying == nil {
-               panic("types.Named.SetUnderlying: underlying type must not be nil")
+               panic("underlying type must not be nil")
        }
        if _, ok := underlying.(*Named); ok {
-               panic("types.Named.SetUnderlying: underlying type must not be *Named")
+               panic("underlying type must not be *Named")
        }
-       t.load().underlying = underlying
+       t.resolve(nil).underlying = underlying
 }
 
 // AddMethod adds method m unless it is already in the method list.
 func (t *Named) AddMethod(m *Func) {
-       t.load()
+       t.resolve(nil)
        if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
                t.methods = append(t.methods, m)
        }
 }
 
-func (t *Named) Underlying() Type { return t.load().underlying }
+func (t *Named) Underlying() Type { return t.resolve(nil).underlying }
 func (t *Named) String() string   { return TypeString(t, nil) }
 
 // ----------------------------------------------------------------------------
@@ -172,72 +132,72 @@ func (t *Named) String() string   { return TypeString(t, nil) }
 // chain before returning it. If no underlying type is found or a cycle
 // is detected, the result is Typ[Invalid]. If a cycle is detected and
 // n0.check != nil, the cycle is reported.
+//
+// This is necessary because the underlying type of named may be itself a
+// named type that is incomplete:
+//
+//     type (
+//             A B
+//             B *C
+//             C A
+//     )
+//
+// The type of C is the (named) type of A which is incomplete,
+// and which has as its underlying type the named type B.
 func (n0 *Named) under() Type {
-       n0.expand()
-
        u := n0.Underlying()
 
-       if u == Typ[Invalid] {
-               return u
-       }
-
        // If the underlying type of a defined type is not a defined
        // (incl. instance) type, then that is the desired underlying
        // type.
-       switch u.(type) {
+       var n1 *Named
+       switch u1 := u.(type) {
        case nil:
-               return Typ[Invalid]
+               // After expansion via Underlying(), we should never encounter a nil
+               // underlying.
+               panic("nil underlying")
        default:
                // common case
                return u
        case *Named:
                // handled below
+               n1 = u1
        }
 
        if n0.check == nil {
-               panic("internal error: Named.check == nil but type is incomplete")
+               panic("Named.check == nil but type is incomplete")
        }
 
        // Invariant: after this point n0 as well as any named types in its
        // underlying chain should be set up when this function exits.
        check := n0.check
+       n := n0
 
-       // If we can't expand u at this point, it is invalid.
-       n := asNamed(u)
-       if n == nil {
-               n0.underlying = Typ[Invalid]
-               return n0.underlying
-       }
+       seen := make(map[*Named]int) // types that need their underlying resolved
+       var path []Object            // objects encountered, for cycle reporting
 
-       // Otherwise, follow the forward chain.
-       seen := map[*Named]int{n0: 0}
-       path := []Object{n0.obj}
+loop:
        for {
-               u = n.Underlying()
-               if u == nil {
-                       u = Typ[Invalid]
-                       break
-               }
-               var n1 *Named
-               switch u1 := u.(type) {
-               case *Named:
-                       u1.expand()
-                       n1 = u1
-               }
-               if n1 == nil {
-                       break // end of chain
-               }
-
                seen[n] = len(seen)
                path = append(path, n.obj)
                n = n1
-
                if i, ok := seen[n]; ok {
                        // cycle
                        check.cycleError(path[i:])
                        u = Typ[Invalid]
                        break
                }
+               u = n.Underlying()
+               switch u1 := u.(type) {
+               case nil:
+                       u = Typ[Invalid]
+                       break loop
+               default:
+                       break loop
+               case *Named:
+                       // Continue collecting *Named types in the chain.
+                       n1 = u1
+               }
        }
 
        for n := range seen {
@@ -246,7 +206,7 @@ func (n0 *Named) under() Type {
                // Also, doing so would lead to a race condition (was issue #31749).
                // Do this check always, not just in debug mode (it's cheap).
                if n.obj.pkg != check.pkg {
-                       panic("internal error: imported type with unresolved underlying type")
+                       panic("imported type with unresolved underlying type")
                }
                n.underlying = u
        }
@@ -260,37 +220,128 @@ func (n *Named) setUnderlying(typ Type) {
        }
 }
 
-// instance holds position information for use in lazy instantiation.
-//
-// TODO(rfindley): come up with a better name for this type, now that its usage
-// has changed.
-type instance struct {
-       pos     token.Pos   // position of type instantiation; for error reporting only
-       posList []token.Pos // position of each targ; for error reporting only
+// bestContext returns the best available context. In order of preference:
+// - the given ctxt, if non-nil
+// - check.Config.Context, if check is non-nil
+// - a new Context
+func (check *Checker) bestContext(ctxt *Context) *Context {
+       if ctxt != nil {
+               return ctxt
+       }
+       if check != nil {
+               assert(check.conf.Context != nil)
+               return check.conf.Context
+       }
+       return NewContext()
 }
 
-// expand ensures that the underlying type of n is instantiated.
+// expandNamed ensures that the underlying type of n is instantiated.
 // The underlying type will be Typ[Invalid] if there was an error.
-// TODO(rfindley): expand would be a better name for this method, but conflicts
-// with the existing concept of lazy expansion. Need to reconcile this.
-func (n *Named) expand() {
-       if n.instance != nil {
-               // n must be loaded before instantiation, in order to have accurate
-               // tparams. This is done implicitly by the call to n.TParams, but making it
-               // explicit is harmless: load is idempotent.
-               n.load()
-               inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList)
-               n.underlying = inst
-               n.fromRHS = inst
-               n.instance = nil
+func expandNamed(ctxt *Context, n *Named, instPos token.Pos) (tparams *TypeParamList, underlying Type, methods []*Func) {
+       n.orig.resolve(ctxt)
+       assert(n.orig.underlying != nil)
+
+       check := n.check
+
+       if _, unexpanded := n.orig.underlying.(*Named); unexpanded {
+               // We should only get an unexpanded underlying here during type checking
+               // (for example, in recursive type declarations).
+               assert(check != nil)
+       }
+
+       // Mismatching arg and tparam length may be checked elsewhere.
+       if n.orig.tparams.Len() == n.targs.Len() {
+               // We must always have a context, to avoid infinite recursion.
+               ctxt = check.bestContext(ctxt)
+               h := ctxt.typeHash(n.orig, n.targs.list())
+               // ensure that an instance is recorded for h to avoid infinite recursion.
+               ctxt.typeForHash(h, n)
+
+               smap := makeSubstMap(n.orig.tparams.list(), n.targs.list())
+               underlying = n.check.subst(instPos, n.orig.underlying, smap, ctxt)
+
+               for i := 0; i < n.orig.NumMethods(); i++ {
+                       origm := n.orig.Method(i)
+
+                       // During type checking origm may not have a fully set up type, so defer
+                       // instantiation of its signature until later.
+                       m := NewFunc(origm.pos, origm.pkg, origm.name, nil)
+                       m.hasPtrRecv_ = origm.hasPtrRecv()
+                       // Setting instRecv here allows us to complete later (we need the
+                       // instRecv to get targs and the original method).
+                       m.instRecv = n
+
+                       methods = append(methods, m)
+               }
+       } else {
+               underlying = Typ[Invalid]
+       }
+
+       // Methods should not escape the type checker API without being completed. If
+       // we're in the context of a type checking pass, we need to defer this until
+       // later (not all methods may have types).
+       completeMethods := func() {
+               for _, m := range methods {
+                       if m.instRecv != nil {
+                               check.completeMethod(ctxt, m)
+                       }
+               }
        }
+       if check != nil {
+               check.later(completeMethods)
+       } else {
+               completeMethods()
+       }
+
+       return n.orig.tparams, underlying, methods
+}
+
+func (check *Checker) completeMethod(ctxt *Context, m *Func) {
+       assert(m.instRecv != nil)
+       rbase := m.instRecv
+       m.instRecv = nil
+       m.setColor(black)
+
+       assert(rbase.TypeArgs().Len() > 0)
+
+       // Look up the original method.
+       _, orig := lookupMethod(rbase.orig.methods, rbase.obj.pkg, m.name)
+       assert(orig != nil)
+       if check != nil {
+               check.objDecl(orig, nil)
+       }
+       origSig := orig.typ.(*Signature)
+       if origSig.RecvTypeParams().Len() != rbase.targs.Len() {
+               m.typ = origSig // or new(Signature), but we can't use Typ[Invalid]: Funcs must have Signature type
+               return          // error reported elsewhere
+       }
+
+       smap := makeSubstMap(origSig.RecvTypeParams().list(), rbase.targs.list())
+       sig := check.subst(orig.pos, origSig, smap, ctxt).(*Signature)
+       if sig == origSig {
+               // No substitution occurred, but we still need to create a new signature to
+               // hold the instantiated receiver.
+               copy := *origSig
+               sig = &copy
+       }
+       var rtyp Type
+       if m.hasPtrRecv() {
+               rtyp = NewPointer(rbase)
+       } else {
+               rtyp = rbase
+       }
+       sig.recv = NewParam(origSig.recv.pos, origSig.recv.pkg, origSig.recv.name, rtyp)
+
+       m.typ = sig
 }
 
-// expand expands uninstantiated named types and leaves all other types alone.
-// expand does not recurse.
-func expand(typ Type) Type {
+// safeUnderlying returns the underlying of typ without expanding instances, to
+// avoid infinite recursion.
+//
+// TODO(rfindley): eliminate this function or give it a better name.
+func safeUnderlying(typ Type) Type {
        if t, _ := typ.(*Named); t != nil {
-               t.expand()
+               return t.underlying
        }
-       return typ
+       return typ.Underlying()
 }
index 7266623fbe99693ffc108e91e339ead3d896b256..a8bd62a04ef9f5736caeb1391cb7ea5b529e8eef 100644 (file)
@@ -232,9 +232,21 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
 
 // _NewTypeNameLazy returns a new defined type like NewTypeName, but it
 // lazily calls resolve to finish constructing the Named object.
-func _NewTypeNameLazy(pos token.Pos, pkg *Package, name string, resolve func(named *Named) (tparams []*TypeName, underlying Type, methods []*Func)) *TypeName {
+func _NewTypeNameLazy(pos token.Pos, pkg *Package, name string, load func(named *Named) (tparams []*TypeParam, underlying Type, methods []*Func)) *TypeName {
        obj := NewTypeName(pos, pkg, name, nil)
-       NewNamed(obj, nil, nil).resolve = resolve
+
+       resolve := func(_ *Context, t *Named) (*TypeParamList, Type, []*Func) {
+               tparams, underlying, methods := load(t)
+
+               switch underlying.(type) {
+               case nil, *Named:
+                       panic(fmt.Sprintf("invalid underlying type %T", t.underlying))
+               }
+
+               return bindTParams(tparams), underlying, methods
+       }
+
+       NewNamed(obj, nil, nil).resolver = resolve
        return obj
 }
 
@@ -257,6 +269,8 @@ func (obj *TypeName) IsAlias() bool {
                return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
        case *Named:
                return obj != t.obj
+       case *TypeParam:
+               return obj != t.obj
        default:
                return true
        }
@@ -305,7 +319,8 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
 // An abstract method may belong to many interfaces due to embedding.
 type Func struct {
        object
-       hasPtrRecv bool // only valid for methods that don't have a type yet
+       instRecv    *Named // if non-nil, the receiver type for an incomplete instance method
+       hasPtrRecv_ bool   // only valid for methods that don't have a type yet; use hasPtrRecv() to read
 }
 
 // NewFunc returns a new function with the given signature, representing
@@ -316,7 +331,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
        if sig != nil {
                typ = sig
        }
-       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false}
+       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, nil, false}
 }
 
 // FullName returns the package- or receiver-type-qualified name of
@@ -330,6 +345,25 @@ func (obj *Func) FullName() string {
 // Scope returns the scope of the function's body block.
 func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
 
+// hasPtrRecv reports whether the receiver is of the form *T for the given method obj.
+func (obj *Func) hasPtrRecv() bool {
+       // If a method's receiver type is set, use that as the source of truth for the receiver.
+       // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
+       // signature. We may reach here before the signature is fully set up: we must explicitly
+       // check if the receiver is set (we cannot just look for non-nil obj.typ).
+       if sig, _ := obj.typ.(*Signature); sig != nil && sig.recv != nil {
+               _, isPtr := deref(sig.recv.typ)
+               return isPtr
+       }
+
+       // If a method's type is not set it may be a method/function that is:
+       // 1) client-supplied (via NewFunc with no signature), or
+       // 2) internally created but not yet type-checked.
+       // For case 1) we can't do anything; the client must know what they are doing.
+       // For case 2) we can use the information gathered by the resolver.
+       return obj.hasPtrRecv_
+}
+
 func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
 
 // A Label represents a declared label.
@@ -429,8 +463,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                if _, ok := typ.(*Basic); ok {
                        return
                }
-               if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
-                       writeTParamList(buf, named.TParams().list(), qf, nil)
+               if named, _ := typ.(*Named); named != nil && named.TypeParams().Len() > 0 {
+                       newTypeWriter(buf, qf).tParamList(named.TypeParams().list())
                }
                if tname.IsAlias() {
                        buf.WriteString(" =")
index 0ff8fdd6fa69bad43ca3a603d6f3d7fe6770d89a..c12af64df7fb359534ee73b321a0c9ee891c5a9f 100644 (file)
@@ -30,6 +30,8 @@ func TestIsAlias(t *testing.T) {
        pkg := NewPackage("p", "p")
        t1 := NewTypeName(0, pkg, "t1", nil)
        n1 := NewNamed(t1, new(Struct), nil)
+       t5 := NewTypeName(0, pkg, "t5", nil)
+       NewTypeParam(t5, nil)
        for _, test := range []struct {
                name  *TypeName
                alias bool
@@ -43,6 +45,7 @@ func TestIsAlias(t *testing.T) {
                {NewTypeName(0, nil, "int32", Typ[Int32]), false},  // type name refers to basic type with same name
                {NewTypeName(0, pkg, "int32", Typ[Int32]), true},   // type name is declared in user-defined package (outside Universe)
                {NewTypeName(0, nil, "rune", Typ[Rune]), true},     // type name refers to basic type rune which is an alias already
+               {t5, false}, // type name refers to type parameter and vice versa
        } {
                check(test.name, test.alias)
        }
index aea8bf5e7ad11b9a378503d5bb42f14cd47712a2..8b76e939b6773c3b1bba6dc6a73158047dd88fa8 100644 (file)
@@ -159,17 +159,14 @@ func operandString(x *operand, qf Qualifier) string {
        if hasType {
                if x.typ != Typ[Invalid] {
                        var intro string
-                       var tpar *TypeParam
                        if isGeneric(x.typ) {
                                intro = " of parameterized type "
-                       } else if tpar = asTypeParam(x.typ); tpar != nil {
-                               intro = " of type parameter "
                        } else {
                                intro = " of type "
                        }
                        buf.WriteString(intro)
                        WriteType(&buf, x.typ, qf)
-                       if tpar != nil {
+                       if tpar := asTypeParam(x.typ); tpar != nil {
                                buf.WriteString(" constrained by ")
                                WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
                        }
@@ -237,53 +234,49 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
 
        V := x.typ
 
-       const debugAssignableTo = false
-       if debugAssignableTo && check != nil {
-               check.dump("V = %s", V)
-               check.dump("T = %s", T)
-       }
-
        // x's type is identical to T
        if Identical(V, T) {
                return true, 0
        }
 
-       Vu := optype(V)
-       Tu := optype(T)
-
-       if debugAssignableTo && check != nil {
-               check.dump("Vu = %s", Vu)
-               check.dump("Tu = %s", Tu)
-       }
+       Vu := under(V)
+       Tu := under(T)
+       Vp, _ := Vu.(*TypeParam)
+       Tp, _ := Tu.(*TypeParam)
 
        // x is an untyped value representable by a value of type T.
        if isUntyped(Vu) {
-               if t, ok := Tu.(*Union); ok {
-                       return t.is(func(t *term) bool {
-                               // TODO(gri) this could probably be more efficient
-                               if t.tilde {
-                                       // TODO(gri) We need to check assignability
-                                       //           for the underlying type of x.
+               assert(Vp == nil)
+               if Tp != nil {
+                       // T is a type parameter: x is assignable to T if it is
+                       // representable by each specific type in the type set of T.
+                       return Tp.is(func(t *term) bool {
+                               if t == nil {
+                                       return false
                                }
-                               ok, _ := x.assignableTo(check, t.typ, reason)
-                               return ok
+                               // A term may be a tilde term but the underlying
+                               // type of an untyped value doesn't change so we
+                               // don't need to do anything special.
+                               newType, _, _ := check.implicitTypeAndValue(x, t.typ)
+                               return newType != nil
                        }), _IncompatibleAssign
                }
-               newType, _, _ := check.implicitTypeAndValue(x, Tu)
+               newType, _, _ := check.implicitTypeAndValue(x, T)
                return newType != nil, _IncompatibleAssign
        }
        // Vu is typed
 
        // x's type V and T have identical underlying types
-       // and at least one of V or T is not a named type
-       if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+       // and at least one of V or T is not a named type.
+       if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) {
                return true, 0
        }
 
-       // T is an interface type and x implements T
+       // T is an interface type and x implements T and T is not a type parameter
        if Ti, ok := Tu.(*Interface); ok {
                if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
                        if reason != nil {
+                               // TODO(gri) the error messages here should follow the style in Checker.typeAssertion (factor!)
                                if wrongType != nil {
                                        if Identical(m.typ, wrongType.typ) {
                                                *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
@@ -302,12 +295,68 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
 
        // x is a bidirectional channel value, T is a channel
        // type, x's type V and T have identical element types,
-       // and at least one of V or T is not a named type
+       // and at least one of V or T is not a named type.
        if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
                if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
-                       return !isNamed(V) || !isNamed(T), _InvalidChanAssign
+                       return !hasName(V) || !hasName(T), _InvalidChanAssign
+               }
+       }
+
+       // optimization: if we don't have type parameters, we're done
+       if Vp == nil && Tp == nil {
+               return false, _IncompatibleAssign
+       }
+
+       errorf := func(format string, args ...interface{}) {
+               if check != nil && reason != nil {
+                       msg := check.sprintf(format, args...)
+                       if *reason != "" {
+                               msg += "\n\t" + *reason
+                       }
+                       *reason = msg
                }
        }
 
+       // x's type V is not a named type and T is a type parameter, and
+       // x is assignable to each specific type in T's type set.
+       if !hasName(V) && Tp != nil {
+               ok := false
+               code := _IncompatibleAssign
+               Tp.is(func(T *term) bool {
+                       if T == nil {
+                               return false // no specific types
+                       }
+                       ok, code = x.assignableTo(check, T.typ, reason)
+                       if !ok {
+                               errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
+                               return false
+                       }
+                       return true
+               })
+               return ok, code
+       }
+
+       // x's type V is a type parameter and T is not a named type,
+       // and values x' of each specific type in V's type set are
+       // assignable to T.
+       if Vp != nil && !hasName(T) {
+               x := *x // don't clobber outer x
+               ok := false
+               code := _IncompatibleAssign
+               Vp.is(func(V *term) bool {
+                       if V == nil {
+                               return false // no specific types
+                       }
+                       x.typ = V.typ
+                       ok, code = x.assignableTo(check, T, reason)
+                       if !ok {
+                               errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T)
+                               return false
+                       }
+                       return true
+               })
+               return ok, code
+       }
+
        return false, _IncompatibleAssign
 }
index 23924693fd2987b5caa665dfa9542fedf1cdaf45..3c76d15c79c6c311339887bd1cddc29832ec69d3 100644 (file)
@@ -6,9 +6,12 @@
 
 package types
 
-// isNamed reports whether typ has a name.
-// isNamed may be called with types that are not fully set up.
-func isNamed(typ Type) bool {
+import "go/token"
+
+// hasName reports whether typ has a name. This includes
+// predeclared types, defined types, and type parameters.
+// hasName may be called with types that are not fully set up.
+func hasName(typ Type) bool {
        switch typ.(type) {
        case *Basic, *Named, *TypeParam:
                return true
@@ -21,7 +24,7 @@ func isNamed(typ Type) bool {
 func isGeneric(typ Type) bool {
        // A parameterized type is only instantiated if it doesn't have an instantiation already.
        named, _ := typ.(*Named)
-       return named != nil && named.obj != nil && named.targs == nil && named.TParams() != nil
+       return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
 }
 
 func is(typ Type, what BasicInfo) bool {
@@ -43,7 +46,7 @@ func isNumeric(typ Type) bool  { return is(typ, IsNumeric) }
 func isString(typ Type) bool   { return is(typ, IsString) }
 
 // Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
-// produce the expected result because a type list that contains both an integer
+// produce the expected result because a type set that contains both an integer
 // and a floating-point type is neither (all) integers, nor (all) floats.
 // Use isIntegerOrFloat instead.
 func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
@@ -70,7 +73,7 @@ func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
 
 func isConstType(typ Type) bool {
        // Type parameters are never const types.
-       t, _ := under(typ).(*Basic)
+       t := asBasic(typ)
        return t != nil && t.info&IsConstType != 0
 }
 
@@ -79,6 +82,12 @@ func IsInterface(typ Type) bool {
        return asInterface(typ) != nil
 }
 
+// isTypeParam reports whether typ is a type parameter.
+func isTypeParam(typ Type) bool {
+       _, ok := under(typ).(*TypeParam)
+       return ok
+}
+
 // Comparable reports whether values of type T are comparable.
 func Comparable(T Type) bool {
        return comparable(T, nil)
@@ -140,10 +149,6 @@ func (p *ifacePair) identical(q *ifacePair) bool {
 
 // For changes to this code the corresponding changes should be made to unifier.nify.
 func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
-       // types must be expanded for comparison
-       x = expand(x)
-       y = expand(y)
-
        if x == y {
                return true
        }
@@ -224,19 +229,16 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                // parameter names.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
-                               identicalTParams(x.TParams().list(), y.TParams().list(), cmpTags, p) &&
+                               identicalTParams(x.TypeParams().list(), y.TypeParams().list(), cmpTags, p) &&
                                identical(x.params, y.params, cmpTags, p) &&
                                identical(x.results, y.results, cmpTags, p)
                }
 
        case *Union:
-               // Two union types are identical if they contain the same terms.
-               // The set (list) of types in a union type consists of unique
-               // types - each type appears exactly once. Thus, two union types
-               // must contain the same number of types to have chance of
-               // being equal.
-               if y, ok := y.(*Union); ok {
-                       return identicalTerms(x.terms, y.terms)
+               if y, _ := y.(*Union); y != nil {
+                       xset := computeUnionTypeSet(nil, token.NoPos, x)
+                       yset := computeUnionTypeSet(nil, token.NoPos, y)
+                       return xset.terms.equal(yset.terms)
                }
 
        case *Interface:
@@ -250,7 +252,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                if y, ok := y.(*Interface); ok {
                        xset := x.typeSet()
                        yset := y.typeSet()
-                       if !Identical(xset.types, yset.types) {
+                       if !xset.terms.equal(yset.terms) {
                                return false
                        }
                        a := xset.methods
@@ -316,6 +318,27 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                // Two named types are identical if their type names originate
                // in the same type declaration.
                if y, ok := y.(*Named); ok {
+                       xargs := x.TypeArgs().list()
+                       yargs := y.TypeArgs().list()
+
+                       if len(xargs) != len(yargs) {
+                               return false
+                       }
+
+                       if len(xargs) > 0 {
+                               // Instances are identical if their original type and type arguments
+                               // are identical.
+                               if !Identical(x.orig, y.orig) {
+                                       return false
+                               }
+                               for i, xa := range xargs {
+                                       if !Identical(xa, yargs[i]) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+
                        // TODO(gri) Why is x == y not sufficient? And if it is,
                        //           we can just return false here because x == y
                        //           is caught in the very beginning of this function.
@@ -325,10 +348,6 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
        case *TypeParam:
                // nothing to do (x and y being equal is caught in the very beginning of this function)
 
-       case *top:
-               // Either both types are theTop in which case the initial x == y check
-               // will have caught them. Otherwise they are not identical.
-
        case nil:
                // avoid a crash in case of nil type
 
@@ -339,13 +358,13 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
        return false
 }
 
-func identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
+func identicalTParams(x, y []*TypeParam, cmpTags bool, p *ifacePair) bool {
        if len(x) != len(y) {
                return false
        }
        for i, x := range x {
                y := y[i]
-               if !identical(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
+               if !identical(x.bound, y.bound, cmpTags, p) {
                        return false
                }
        }
index 5e58c3dcfd568839df2d82264b992298a5622464..5a82b4fd9ca496f966a9b6ef5113ba53ab46ae70 100644 (file)
@@ -381,12 +381,15 @@ func (check *Checker) collectObjects() {
                                        check.declarePkgObj(name, obj, di)
                                }
                        case typeDecl:
+                               if d.spec.TypeParams.NumFields() != 0 && !check.allowVersion(pkg, 1, 18) {
+                                       check.softErrorf(d.spec.TypeParams.List[0], _Todo, "type parameters require go1.18 or later")
+                               }
                                obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
                                check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec})
                        case funcDecl:
-                               info := &declInfo{file: fileScope, fdecl: d.decl}
                                name := d.decl.Name.Name
                                obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil)
+                               hasTParamError := false // avoid duplicate type parameter errors
                                if d.decl.Recv.NumFields() == 0 {
                                        // regular function
                                        if d.decl.Recv != nil {
@@ -398,8 +401,9 @@ func (check *Checker) collectObjects() {
                                                if name == "main" {
                                                        code = _InvalidMainDecl
                                                }
-                                               if tparams := typeparams.Get(d.decl.Type); tparams != nil {
-                                                       check.softErrorf(tparams, code, "func %s must have no type parameters", name)
+                                               if d.decl.Type.TypeParams.NumFields() != 0 {
+                                                       check.softErrorf(d.decl.Type.TypeParams.List[0], code, "func %s must have no type parameters", name)
+                                                       hasTParamError = true
                                                }
                                                if t := d.decl.Type; t.Params.NumFields() != 0 || t.Results != nil {
                                                        // TODO(rFindley) Should this be a hard error?
@@ -435,6 +439,10 @@ func (check *Checker) collectObjects() {
                                        }
                                        check.recordDef(d.decl.Name, obj)
                                }
+                               if d.decl.Type.TypeParams.NumFields() != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
+                                       check.softErrorf(d.decl.Type.TypeParams.List[0], _Todo, "type parameters require go1.18 or later")
+                               }
+                               info := &declInfo{file: fileScope, fdecl: d.decl}
                                // Methods are not package-level objects but we still track them in the
                                // object map so that we can handle them like regular functions (if the
                                // receiver is invalid); also we need their fdecl info when associating
@@ -475,7 +483,7 @@ func (check *Checker) collectObjects() {
                // Determine the receiver base type and associate m with it.
                ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
                if base != nil {
-                       m.obj.hasPtrRecv = ptr
+                       m.obj.hasPtrRecv_ = ptr
                        check.methods[base] = append(check.methods[base], m.obj)
                }
        }
@@ -505,7 +513,7 @@ L: // unpack receiver type
 
        // unpack type parameters, if any
        switch rtyp.(type) {
-       case *ast.IndexExpr, *ast.MultiIndexExpr:
+       case *ast.IndexExpr, *ast.IndexListExpr:
                ix := typeparams.UnpackIndexExpr(rtyp)
                rtyp = ix.X
                if unpackParams {
index 262dc7b97abe931c49dc916681ed98b62befd745..55436d3b6225a0e709a82ed43dc5f155e3afeaa5 100644 (file)
@@ -27,12 +27,7 @@ func TestSelf(t *testing.T) {
        conf := Config{Importer: importer.Default()}
        _, err = conf.Check("go/types", fset, files, nil)
        if err != nil {
-               // Importing go/constant doesn't work in the
-               // build dashboard environment. Don't report an error
-               // for now so that the build remains green.
-               // TODO(gri) fix this
-               t.Log(err) // replace w/ t.Fatal eventually
-               return
+               t.Fatal(err)
        }
 }
 
index 5a69bb17b5724ffca0f4a889e033adeaa377a95c..ad69c95d1288fd88ab104fc369bd9de827da69c8 100644 (file)
@@ -5,9 +5,7 @@
 package types
 
 import (
-       "fmt"
        "go/ast"
-       "go/internal/typeparams"
        "go/token"
 )
 
@@ -21,30 +19,54 @@ type Signature struct {
        // and store it in the Func Object) because when type-checking a function
        // literal we call the general type checker which returns a general Type.
        // We then unpack the *Signature and use the scope for the literal body.
-       rparams  *TypeParams // receiver type parameters from left to right, or nil
-       tparams  *TypeParams // type parameters from left to right, or nil
-       scope    *Scope      // function scope, present for package-local signatures
-       recv     *Var        // nil if not a method
-       params   *Tuple      // (incoming) parameters from left to right; or nil
-       results  *Tuple      // (outgoing) results from left to right; or nil
-       variadic bool        // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+       rparams  *TypeParamList // receiver type parameters from left to right, or nil
+       tparams  *TypeParamList // type parameters from left to right, or nil
+       scope    *Scope         // function scope, present for package-local signatures
+       recv     *Var           // nil if not a method
+       params   *Tuple         // (incoming) parameters from left to right; or nil
+       results  *Tuple         // (outgoing) results from left to right; or nil
+       variadic bool           // true if the last parameter's type is of the form ...T (or string, for append built-in only)
 }
 
 // NewSignature returns a new function type for the given receiver, parameters,
 // and results, either of which may be nil. If variadic is set, the function
 // is variadic, it must have at least one parameter, and the last parameter
 // must be of unnamed slice type.
+//
+// Deprecated: Use NewSignatureType instead which allows for type parameters.
 func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
+       return NewSignatureType(recv, nil, nil, params, results, variadic)
+}
+
+// NewSignatureType creates a new function type for the given receiver,
+// receiver type parameters, type parameters, parameters, and results. If
+// variadic is set, params must hold at least one parameter and the last
+// parameter must be of unnamed slice type. If recv is non-nil, typeParams must
+// be empty. If recvTypeParams is non-empty, recv must be non-nil.
+func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature {
        if variadic {
                n := params.Len()
                if n == 0 {
-                       panic("types.NewSignature: variadic function must have at least one parameter")
+                       panic("variadic function must have at least one parameter")
                }
                if _, ok := params.At(n - 1).typ.(*Slice); !ok {
-                       panic("types.NewSignature: variadic parameter must be of unnamed slice type")
+                       panic("variadic parameter must be of unnamed slice type")
+               }
+       }
+       sig := &Signature{recv: recv, params: params, results: results, variadic: variadic}
+       if len(recvTypeParams) != 0 {
+               if recv == nil {
+                       panic("function with receiver type parameters must have a receiver")
+               }
+               sig.rparams = bindTParams(recvTypeParams)
+       }
+       if len(typeParams) != 0 {
+               if recv != nil {
+                       panic("function with type parameters cannot have a receiver")
                }
+               sig.tparams = bindTParams(typeParams)
        }
-       return &Signature{recv: recv, params: params, results: results, variadic: variadic}
+       return sig
 }
 
 // Recv returns the receiver of signature s (if a method), or nil if a
@@ -55,17 +77,11 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
 // contain methods whose receiver type is a different interface.
 func (s *Signature) Recv() *Var { return s.recv }
 
-// TParams returns the type parameters of signature s, or nil.
-func (s *Signature) TParams() *TypeParams { return s.tparams }
-
-// SetTParams sets the type parameters of signature s.
-func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) }
-
-// RParams returns the receiver type parameters of signature s, or nil.
-func (s *Signature) RParams() *TypeParams { return s.rparams }
+// TypeParams returns the type parameters of signature s, or nil.
+func (s *Signature) TypeParams() *TypeParamList { return s.tparams }
 
-// SetRParams sets the receiver type params of signature s.
-func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) }
+// RecvTypeParams returns the receiver type parameters of signature s, or nil.
+func (s *Signature) RecvTypeParams() *TypeParamList { return s.rparams }
 
 // Params returns the parameters of signature s, or nil.
 func (s *Signature) Params() *Tuple { return s.params }
@@ -90,79 +106,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
        sig.scope = check.scope
        defer check.closeScope()
 
-       var recvTyp ast.Expr // rewritten receiver type; valid if != nil
        if recvPar != nil && len(recvPar.List) > 0 {
                // collect generic receiver type parameters, if any
                // - a receiver type parameter is like any other type parameter, except that it is declared implicitly
                // - the receiver specification acts as local declaration for its type parameters, which may be blank
                _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
                if len(rparams) > 0 {
-                       // Blank identifiers don't get declared and regular type-checking of the instantiated
-                       // parameterized receiver type expression fails in Checker.collectParams of receiver.
-                       // Identify blank type parameters and substitute each with a unique new identifier named
-                       // "n_" (where n is the parameter index) and which cannot conflict with any user-defined
-                       // name.
-                       var smap map[*ast.Ident]*ast.Ident // substitution map from "_" to "n_" identifiers
+                       sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
+                       // Blank identifiers don't get declared, so naive type-checking of the
+                       // receiver type expression would fail in Checker.collectParams below,
+                       // when Checker.ident cannot resolve the _ to a type.
+                       //
+                       // Checker.recvTParamMap maps these blank identifiers to their type parameter
+                       // types, so that they may be resolved in Checker.ident when they fail
+                       // lookup in the scope.
                        for i, p := range rparams {
                                if p.Name == "_" {
-                                       new := *p
-                                       new.Name = fmt.Sprintf("%d_", i)
-                                       rparams[i] = &new // use n_ identifier instead of _ so it can be looked up
-                                       if smap == nil {
-                                               smap = make(map[*ast.Ident]*ast.Ident)
+                                       tpar := sig.rparams.At(i)
+                                       if check.recvTParamMap == nil {
+                                               check.recvTParamMap = make(map[*ast.Ident]*TypeParam)
                                        }
-                                       smap[p] = &new
+                                       check.recvTParamMap[p] = tpar
                                }
                        }
-                       if smap != nil {
-                               // blank identifiers were found => use rewritten receiver type
-                               recvTyp = isubst(recvPar.List[0].Type, smap)
-                       }
-                       sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
                        // determine receiver type to get its type parameters
                        // and the respective type parameter bounds
-                       var recvTParams []*TypeName
+                       var recvTParams []*TypeParam
                        if rname != nil {
                                // recv should be a Named type (otherwise an error is reported elsewhere)
                                // Also: Don't report an error via genericType since it will be reported
                                //       again when we type-check the signature.
                                // TODO(gri) maybe the receiver should be marked as invalid instead?
-                               if recv := asNamed(check.genericType(rname, false)); recv != nil {
-                                       recvTParams = recv.TParams().list()
+                               if recv, _ := check.genericType(rname, false).(*Named); recv != nil {
+                                       recvTParams = recv.TypeParams().list()
                                }
                        }
                        // provide type parameter bounds
                        // - only do this if we have the right number (otherwise an error is reported elsewhere)
-                       if sig.RParams().Len() == len(recvTParams) {
+                       if sig.RecvTypeParams().Len() == len(recvTParams) {
                                // We have a list of *TypeNames but we need a list of Types.
-                               list := make([]Type, sig.RParams().Len())
-                               for i, t := range sig.RParams().list() {
-                                       list[i] = t.typ
+                               list := make([]Type, sig.RecvTypeParams().Len())
+                               for i, t := range sig.RecvTypeParams().list() {
+                                       list[i] = t
+                                       check.mono.recordCanon(t, recvTParams[i])
                                }
                                smap := makeSubstMap(recvTParams, list)
-                               for i, tname := range sig.RParams().list() {
-                                       bound := recvTParams[i].typ.(*TypeParam).bound
+                               for i, tpar := range sig.RecvTypeParams().list() {
+                                       bound := recvTParams[i].bound
                                        // bound is (possibly) parameterized in the context of the
                                        // receiver type declaration. Substitute parameters for the
                                        // current context.
-                                       // TODO(gri) should we assume now that bounds always exist?
-                                       //           (no bound == empty interface)
-                                       if bound != nil {
-                                               bound = check.subst(tname.pos, bound, smap)
-                                               tname.typ.(*TypeParam).bound = bound
-                                       }
+                                       tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
                                }
                        }
                }
        }
 
-       if tparams := typeparams.Get(ftyp); tparams != nil {
-               sig.tparams = check.collectTypeParams(tparams)
+       if ftyp.TypeParams != nil {
+               check.collectTypeParams(&sig.tparams, ftyp.TypeParams)
                // Always type-check method type parameters but complain that they are not allowed.
                // (A separate check is needed when type-checking interface method signatures because
                // they don't have a receiver specification.)
                if recvPar != nil {
-                       check.errorf(tparams, _Todo, "methods cannot have type parameters")
+                       check.errorf(ftyp.TypeParams, _Todo, "methods cannot have type parameters")
                }
        }
 
@@ -170,9 +176,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
        // declarations and then squash that scope into the parent scope (and report any redeclarations at
        // that time).
        scope := NewScope(check.scope, token.NoPos, token.NoPos, "function body (temp. scope)")
-       recvList, _ := check.collectParams(scope, recvPar, recvTyp, false) // use rewritten receiver type, if any
-       params, variadic := check.collectParams(scope, ftyp.Params, nil, true)
-       results, _ := check.collectParams(scope, ftyp.Results, nil, false)
+       recvList, _ := check.collectParams(scope, recvPar, false)
+       params, variadic := check.collectParams(scope, ftyp.Params, true)
+       results, _ := check.collectParams(scope, ftyp.Results, false)
        scope.squash(func(obj, alt Object) {
                check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name())
                check.reportAltDecl(alt)
@@ -198,7 +204,6 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                // TODO(gri) We should delay rtyp expansion to when we actually need the
                //           receiver; thus all checks here should be delayed to later.
                rtyp, _ := deref(recv.typ)
-               rtyp = expand(rtyp)
 
                // spec: "The receiver type must be of the form T or *T where T is a type name."
                // (ignore invalid types - error was reported before)
@@ -206,6 +211,13 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                        var err string
                        switch T := rtyp.(type) {
                        case *Named:
+                               T.resolve(check.conf.Context)
+                               // The receiver type may be an instantiated type referred to
+                               // by an alias (which cannot have receiver parameters for now).
+                               if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
+                                       check.errorf(atPos(recv.pos), _Todo, "cannot define methods on instantiated type %s", recv.typ)
+                                       break
+                               }
                                // spec: "The type denoted by T is called the receiver base type; it must not
                                // be a pointer or interface type and it must be declared in the same package
                                // as the method."
@@ -248,8 +260,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
 }
 
 // collectParams declares the parameters of list in scope and returns the corresponding
-// variable list. If type0 != nil, it is used instead of the first type in list.
-func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast.Expr, variadicOk bool) (params []*Var, variadic bool) {
+// variable list.
+func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
        if list == nil {
                return
        }
@@ -257,9 +269,6 @@ func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast
        var named, anonymous bool
        for i, field := range list.List {
                ftype := field.Type
-               if i == 0 && type0 != nil {
-                       ftype = type0
-               }
                if t, _ := ftype.(*ast.Ellipsis); t != nil {
                        ftype = t.Elt
                        if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 {
@@ -309,44 +318,3 @@ func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast
 
        return
 }
-
-// isubst returns an x with identifiers substituted per the substitution map smap.
-// isubst only handles the case of (valid) method receiver type expressions correctly.
-func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr {
-       switch n := x.(type) {
-       case *ast.Ident:
-               if alt := smap[n]; alt != nil {
-                       return alt
-               }
-       case *ast.StarExpr:
-               X := isubst(n.X, smap)
-               if X != n.X {
-                       new := *n
-                       new.X = X
-                       return &new
-               }
-       case *ast.IndexExpr, *ast.MultiIndexExpr:
-               ix := typeparams.UnpackIndexExpr(x)
-               var newIndexes []ast.Expr
-               for i, index := range ix.Indices {
-                       new := isubst(index, smap)
-                       if new != index {
-                               if newIndexes == nil {
-                                       newIndexes = make([]ast.Expr, len(ix.Indices))
-                                       copy(newIndexes, ix.Indices)
-                               }
-                               newIndexes[i] = new
-                       }
-               }
-               if newIndexes != nil {
-                       return typeparams.PackIndexExpr(ix.X, ix.Lbrack, newIndexes, ix.Rbrack)
-               }
-       case *ast.ParenExpr:
-               return isubst(n.X, smap) // no need to keep parentheses
-       default:
-               // Other receiver type expressions are invalid.
-               // It's fine to ignore those here as they will
-               // be checked elsewhere.
-       }
-       return x
-}
index 67a9b39558e8da5b99736ff1ab6c825ec37b0770..5b7ee8bb7883da571516038a8107de46e90cd568 100644 (file)
@@ -26,21 +26,20 @@ func TestSizeof(t *testing.T) {
                {Pointer{}, 8, 16},
                {Tuple{}, 12, 24},
                {Signature{}, 28, 56},
-               {Union{}, 12, 24},
-               {Interface{}, 40, 80},
+               {Union{}, 16, 32},
+               {Interface{}, 44, 88},
                {Map{}, 16, 32},
                {Chan{}, 12, 24},
-               {Named{}, 80, 152},
+               {Named{}, 68, 128},
                {TypeParam{}, 28, 48},
                {term{}, 12, 24},
-               {top{}, 0, 0},
 
                // Objects
                {PkgName{}, 48, 88},
                {Const{}, 48, 88},
                {TypeName{}, 40, 72},
                {Var{}, 44, 80},
-               {Func{}, 44, 80},
+               {Func{}, 48, 88},
                {Label{}, 44, 80},
                {Builtin{}, 44, 80},
                {Nil{}, 40, 72},
@@ -48,7 +47,7 @@ func TestSizeof(t *testing.T) {
                // Misc
                {Scope{}, 44, 88},
                {Package{}, 40, 80},
-               {_TypeSet{}, 24, 48},
+               {_TypeSet{}, 28, 56},
        }
        for _, test := range tests {
                got := reflect.TypeOf(test.val).Size()
index 3eb7519a91af06d2d27f8c19fdb1b4bb358e0ea9..b0d7fdd3d9c55cce7689e918d32a1b83ef839d86 100644 (file)
@@ -194,6 +194,8 @@ func TestStdFixed(t *testing.T) {
                "bug251.go",      // issue #34333 which was exposed with fix for #34151
                "issue42058a.go", // go/types does not have constraints on channel element size
                "issue42058b.go", // go/types does not have constraints on channel element size
+               "issue48097.go",  // go/types doesn't check validity of //go:xxx directives, and non-init bodyless function
+               "issue48230.go",  // go/types doesn't check validity of //go:xxx directives
        )
 }
 
index 0f0a2e4d9fd754a15049d569562c6da66f3d0d92..cc4eceae5d7faf2ddafcdcb558ccd54a5905b3a2 100644 (file)
@@ -15,7 +15,7 @@ import (
 
 func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt, iota constant.Value) {
        if check.conf.IgnoreFuncBodies {
-               panic("internal error: function body not ignored")
+               panic("function body not ignored")
        }
 
        if trace {
@@ -53,11 +53,6 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
                check.error(atPos(body.Rbrace), _MissingReturn, "missing return")
        }
 
-       // TODO(gri) Should we make it an error to declare generic functions
-       //           where the type parameters are not used?
-       // 12/19/2018: Probably not - it can make sense to have an API with
-       //           all functions uniformly sharing the same type parameters.
-
        // spec: "Implementation restriction: A compiler may make it illegal to
        // declare a variable inside a function body if the variable is never used."
        check.usage(sig.scope)
@@ -179,7 +174,7 @@ func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
        var x operand
        var msg string
        var code errorCode
-       switch check.rawExpr(&x, call, nil) {
+       switch check.rawExpr(&x, call, nil, false) {
        case conversion:
                msg = "requires function call, not conversion"
                code = _InvalidDefer
@@ -276,15 +271,29 @@ L:
        }
 }
 
+// isNil reports whether the expression e denotes the predeclared value nil.
+func (check *Checker) isNil(e ast.Expr) bool {
+       // The only way to express the nil value is by literally writing nil (possibly in parentheses).
+       if name, _ := unparen(e).(*ast.Ident); name != nil {
+               _, ok := check.lookup(name.Name).(*Nil)
+               return ok
+       }
+       return false
+}
+
 func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]ast.Expr) (T Type) {
+       var dummy operand
 L:
        for _, e := range types {
-               T = check.typeOrNil(e)
-               if T == Typ[Invalid] {
-                       continue L
-               }
-               if T != nil {
-                       check.ordinaryType(e, T)
+               // The spec allows the value nil instead of a type.
+               if check.isNil(e) {
+                       T = nil
+                       check.expr(&dummy, e) // run e through expr so we get the usual Info recordings
+               } else {
+                       T = check.varType(e)
+                       if T == Typ[Invalid] {
+                               continue L
+                       }
                }
                // look for duplicate types
                // (quadratic algorithm, but type switches tend to be reasonably small)
@@ -293,7 +302,7 @@ L:
                                // talk about "case" rather than "type" because of nil case
                                Ts := "nil"
                                if T != nil {
-                                       Ts = T.String()
+                                       Ts = TypeString(T, check.qualifier)
                                }
                                check.errorf(e, _DuplicateCase, "duplicate case %s in type switch", Ts)
                                check.error(other, _DuplicateCase, "\tprevious case") // secondary error, \t indented
@@ -308,6 +317,47 @@ L:
        return
 }
 
+// TODO(gri) Once we are certain that typeHash is correct in all situations, use this version of caseTypes instead.
+//           (Currently it may be possible that different types have identical names and import paths due to ImporterFrom.)
+//
+// func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[string]ast.Expr) (T Type) {
+//     var dummy operand
+// L:
+//     for _, e := range types {
+//             // The spec allows the value nil instead of a type.
+//             var hash string
+//             if check.isNil(e) {
+//                     check.expr(&dummy, e) // run e through expr so we get the usual Info recordings
+//                     T = nil
+//                     hash = "<nil>" // avoid collision with a type named nil
+//             } else {
+//                     T = check.varType(e)
+//                     if T == Typ[Invalid] {
+//                             continue L
+//                     }
+//                     hash = typeHash(T, nil)
+//             }
+//             // look for duplicate types
+//             if other := seen[hash]; other != nil {
+//                     // talk about "case" rather than "type" because of nil case
+//                     Ts := "nil"
+//                     if T != nil {
+//                             Ts = TypeString(T, check.qualifier)
+//                     }
+//                     var err error_
+//                     err.errorf(e, "duplicate case %s in type switch", Ts)
+//                     err.errorf(other, "previous case")
+//                     check.report(&err)
+//                     continue L
+//             }
+//             seen[hash] = e
+//             if T != nil {
+//                     check.typeAssertion(e.Pos(), x, xtyp, T)
+//             }
+//     }
+//     return
+// }
+
 // stmt typechecks statement s.
 func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
        // statements must end with the same top scope as they started with
@@ -341,7 +391,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                // function and method calls and receive operations can appear
                // in statement context. Such statements may be parenthesized."
                var x operand
-               kind := check.rawExpr(&x, s.X, nil)
+               kind := check.rawExpr(&x, s.X, nil, false)
                var msg string
                var code errorCode
                switch x.mode {
@@ -646,7 +696,6 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                        check.errorf(&x, _InvalidTypeSwitch, "%s is not an interface", &x)
                        return
                }
-               check.ordinaryType(&x, xtyp)
 
                check.multipleDefaults(s.Body.List)
 
@@ -783,20 +832,28 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                // determine key/value types
                var key, val Type
                if x.mode != invalid {
-                       typ := optype(x.typ)
-                       if _, ok := typ.(*Chan); ok && s.Value != nil {
-                               // TODO(gri) this also needs to happen for channels in generic variables
-                               check.softErrorf(atPos(s.Value.Pos()), _InvalidIterVar, "range over %s permits only one iteration variable", &x)
-                               // ok to continue
+                       // Ranging over a type parameter is permitted if it has a single underlying type.
+                       var cause string
+                       u := structure(x.typ)
+                       switch t := u.(type) {
+                       case nil:
+                               cause = "type set has no single underlying type"
+                       case *Chan:
+                               if s.Value != nil {
+                                       check.softErrorf(s.Value, _InvalidIterVar, "range over %s permits only one iteration variable", &x)
+                                       // ok to continue
+                               }
+                               if t.dir == SendOnly {
+                                       cause = "receive from send-only channel"
+                               }
                        }
-                       var msg string
-                       key, val, msg = rangeKeyVal(typ, isVarName(s.Key), isVarName(s.Value))
-                       if key == nil || msg != "" {
-                               if msg != "" {
-                                       // TODO(rFindley) should this be parenthesized, to be consistent with other qualifiers?
-                                       msg = ": " + msg
+                       key, val = rangeKeyVal(u)
+                       if key == nil || cause != "" {
+                               if cause == "" {
+                                       check.softErrorf(&x, _InvalidRangeExpr, "cannot range over %s", &x)
+                               } else {
+                                       check.softErrorf(&x, _InvalidRangeExpr, "cannot range over %s (%s)", &x, cause)
                                }
-                               check.softErrorf(&x, _InvalidRangeExpr, "cannot range over %s%s", &x, msg)
                                // ok to continue
                        }
                }
@@ -881,71 +938,23 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
        }
 }
 
-// isVarName reports whether x is a non-nil, non-blank (_) expression.
-func isVarName(x ast.Expr) bool {
-       if x == nil {
-               return false
-       }
-       ident, _ := unparen(x).(*ast.Ident)
-       return ident == nil || ident.Name != "_"
-}
-
 // rangeKeyVal returns the key and value type produced by a range clause
-// over an expression of type typ, and possibly an error message. If the
-// range clause is not permitted the returned key is nil or msg is not
-// empty (in that case we still may have a non-nil key type which can be
-// used to reduce the chance for follow-on errors).
-// The wantKey, wantVal, and hasVal flags indicate which of the iteration
-// variables are used or present; this matters if we range over a generic
-// type where not all keys or values are of the same type.
-func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
-       switch typ := typ.(type) {
+// over an expression of type typ. If the range clause is not permitted
+// the results are nil.
+func rangeKeyVal(typ Type) (key, val Type) {
+       switch typ := arrayPtrDeref(typ).(type) {
        case *Basic:
                if isString(typ) {
-                       return Typ[Int], universeRune, "" // use 'rune' name
+                       return Typ[Int], universeRune // use 'rune' name
                }
        case *Array:
-               return Typ[Int], typ.elem, ""
+               return Typ[Int], typ.elem
        case *Slice:
-               return Typ[Int], typ.elem, ""
-       case *Pointer:
-               if typ := asArray(typ.base); typ != nil {
-                       return Typ[Int], typ.elem, ""
-               }
+               return Typ[Int], typ.elem
        case *Map:
-               return typ.key, typ.elem, ""
+               return typ.key, typ.elem
        case *Chan:
-               var msg string
-               if typ.dir == SendOnly {
-                       msg = "send-only channel"
-               }
-               return typ.elem, Typ[Invalid], msg
-       case *Union:
-               first := true
-               var key, val Type
-               var msg string
-               typ.underIs(func(t Type) bool {
-                       k, v, m := rangeKeyVal(t, wantKey, wantVal)
-                       if k == nil || m != "" {
-                               key, val, msg = k, v, m
-                               return false
-                       }
-                       if first {
-                               key, val, msg = k, v, m
-                               first = false
-                               return true
-                       }
-                       if wantKey && !Identical(key, k) {
-                               key, val, msg = nil, nil, "all possible values must have the same key type"
-                               return false
-                       }
-                       if wantVal && !Identical(val, v) {
-                               key, val, msg = nil, nil, "all possible values must have the same element type"
-                               return false
-                       }
-                       return true
-               })
-               return key, val, msg
+               return typ.elem, Typ[Invalid]
        }
-       return nil, nil, ""
+       return
 }
index 48b07346dc30cc7c3ba3038ca7b1a780bd41829d..442c7a66e329daa5acd7e9148b815f8764381998 100644 (file)
@@ -155,7 +155,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
                                                check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
                                        }
                                }
-                       })
+                       }).describef(embeddedPos, "check embedded type %s", embeddedTyp)
                }
        }
 
@@ -176,6 +176,8 @@ func embeddedFieldIdent(e ast.Expr) *ast.Ident {
                return e.Sel
        case *ast.IndexExpr:
                return embeddedFieldIdent(e.X)
+       case *ast.IndexListExpr:
+               return embeddedFieldIdent(e.X)
        }
        return nil // invalid embedded field
 }
index 322e30d357771711fbaee2eb2b18d6193280b6b5..f0b79f60c6f7133709c98317ea3227f0a1dfa958 100644 (file)
@@ -6,55 +6,39 @@
 
 package types
 
-import (
-       "bytes"
-       "fmt"
-       "go/token"
-)
-
-// TODO(rFindley) decide error codes for the errors in this file, and check
-//                if error spans can be improved
-
-type substMap struct {
-       // The targs field is currently needed for *Named type substitution.
-       // TODO(gri) rewrite that code, get rid of this field, and make this
-       //           struct just the map (proj)
-       targs []Type
-       proj  map[*TypeParam]Type
-}
+import "go/token"
+
+type substMap map[*TypeParam]Type
 
 // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
 // If targs[i] is nil, tpars[i] is not substituted.
-func makeSubstMap(tpars []*TypeName, targs []Type) *substMap {
+func makeSubstMap(tpars []*TypeParam, targs []Type) substMap {
        assert(len(tpars) == len(targs))
-       proj := make(map[*TypeParam]Type, len(tpars))
+       proj := make(substMap, len(tpars))
        for i, tpar := range tpars {
-               proj[tpar.typ.(*TypeParam)] = targs[i]
+               proj[tpar] = targs[i]
        }
-       return &substMap{targs, proj}
+       return proj
 }
 
-func (m *substMap) String() string {
-       return fmt.Sprintf("%s", m.proj)
+func (m substMap) empty() bool {
+       return len(m) == 0
 }
 
-func (m *substMap) empty() bool {
-       return len(m.proj) == 0
-}
-
-func (m *substMap) lookup(tpar *TypeParam) Type {
-       if t := m.proj[tpar]; t != nil {
+func (m substMap) lookup(tpar *TypeParam) Type {
+       if t := m[tpar]; t != nil {
                return t
        }
        return tpar
 }
 
-// subst returns the type typ with its type parameters tpars replaced by
-// the corresponding type arguments targs, recursively.
-// subst is functional in the sense that it doesn't modify the incoming
-// type. If a substitution took place, the result type is different from
-// from the incoming type.
-func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type {
+// subst returns the type typ with its type parameters tpars replaced by the
+// corresponding type arguments targs, recursively. subst is pure in the sense
+// that it doesn't modify the incoming type. If a substitution took place, the
+// result type is different from the incoming type.
+//
+// If the given context is non-nil, it is used in lieu of check.Config.Context
+func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, ctxt *Context) Type {
        if smap.empty() {
                return typ
        }
@@ -68,28 +52,20 @@ func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type {
        }
 
        // general case
-       var subst subster
-       subst.pos = pos
-       subst.smap = smap
-       if check != nil {
-               subst.check = check
-               subst.typMap = check.typMap
-       } else {
-               // If we don't have a *Checker and its global type map,
-               // use a local version. Besides avoiding duplicate work,
-               // the type map prevents infinite recursive substitution
-               // for recursive types (example: type T[P any] *T[P]).
-               subst.typMap = make(map[string]*Named)
+       subst := subster{
+               pos:   pos,
+               smap:  smap,
+               check: check,
+               ctxt:  check.bestContext(ctxt),
        }
-
        return subst.typ(typ)
 }
 
 type subster struct {
-       pos    token.Pos
-       smap   *substMap
-       check  *Checker // nil if called via Instantiate
-       typMap map[string]*Named
+       pos   token.Pos
+       smap  substMap
+       check *Checker // nil if called via Instantiate
+       ctxt  *Context
 }
 
 func (subst *subster) typ(typ Type) Type {
@@ -98,7 +74,7 @@ func (subst *subster) typ(typ Type) Type {
                // Call typOrNil if it's possible that typ is nil.
                panic("nil typ")
 
-       case *Basic, *top:
+       case *Basic:
                // nothing to do
 
        case *Array:
@@ -136,8 +112,7 @@ func (subst *subster) typ(typ Type) Type {
                if recv != t.recv || params != t.params || results != t.results {
                        return &Signature{
                                rparams: t.rparams,
-                               // TODO(rFindley) why can't we nil out tparams here, rather than in
-                               //                instantiate above?
+                               // TODO(rFindley) why can't we nil out tparams here, rather than in instantiate?
                                tparams:  t.tparams,
                                scope:    t.scope,
                                recv:     recv,
@@ -148,12 +123,12 @@ func (subst *subster) typ(typ Type) Type {
                }
 
        case *Union:
-               terms, copied := subst.termList(t.terms)
+               terms, copied := subst.termlist(t.terms)
                if copied {
-                       // TODO(gri) Remove duplicates that may have crept in after substitution
-                       //           (unlikely but possible). This matters for the Identical
-                       //           predicate on unions.
-                       return &Union{terms}
+                       // term list substitution may introduce duplicate terms (unlikely but possible).
+                       // This is ok; lazy type set computation will determine the actual type set
+                       // in normal form.
+                       return &Union{terms, nil}
                }
 
        case *Interface:
@@ -161,9 +136,6 @@ func (subst *subster) typ(typ Type) Type {
                embeddeds, ecopied := subst.typeList(t.embeddeds)
                if mcopied || ecopied {
                        iface := &Interface{methods: methods, embeddeds: embeddeds, complete: t.complete}
-                       if subst.check == nil {
-                               panic("internal error: cannot instantiate interfaces yet")
-                       }
                        return iface
                }
 
@@ -193,67 +165,65 @@ func (subst *subster) typ(typ Type) Type {
                        }
                }
 
-               if t.TParams().Len() == 0 {
+               // subst is called by expandNamed, so in this function we need to be
+               // careful not to call any methods that would cause t to be expanded: doing
+               // so would result in deadlock.
+               //
+               // So we call t.orig.TypeParams() rather than t.TypeParams() here and
+               // below.
+               if t.orig.TypeParams().Len() == 0 {
                        dump(">>> %s is not parameterized", t)
                        return t // type is not parameterized
                }
 
-               var newTargs []Type
-
-               if len(t.targs) > 0 {
-                       // already instantiated
-                       dump(">>> %s already instantiated", t)
-                       assert(len(t.targs) == t.TParams().Len())
-                       // For each (existing) type argument targ, determine if it needs
-                       // to be substituted; i.e., if it is or contains a type parameter
-                       // that has a type argument for it.
-                       for i, targ := range t.targs {
-                               dump(">>> %d targ = %s", i, targ)
-                               newTarg := subst.typ(targ)
-                               if newTarg != targ {
-                                       dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
-                                       if newTargs == nil {
-                                               newTargs = make([]Type, t.TParams().Len())
-                                               copy(newTargs, t.targs)
-                                       }
-                                       newTargs[i] = newTarg
+               var newTArgs []Type
+               if t.targs.Len() != t.orig.TypeParams().Len() {
+                       return Typ[Invalid] // error reported elsewhere
+               }
+
+               // already instantiated
+               dump(">>> %s already instantiated", t)
+               // For each (existing) type argument targ, determine if it needs
+               // to be substituted; i.e., if it is or contains a type parameter
+               // that has a type argument for it.
+               for i, targ := range t.targs.list() {
+                       dump(">>> %d targ = %s", i, targ)
+                       new_targ := subst.typ(targ)
+                       if new_targ != targ {
+                               dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
+                               if newTArgs == nil {
+                                       newTArgs = make([]Type, t.orig.TypeParams().Len())
+                                       copy(newTArgs, t.targs.list())
                                }
+                               newTArgs[i] = new_targ
                        }
+               }
 
-                       if newTargs == nil {
-                               dump(">>> nothing to substitute in %s", t)
-                               return t // nothing to substitute
-                       }
-               } else {
-                       // not yet instantiated
-                       dump(">>> first instantiation of %s", t)
-                       // TODO(rFindley) can we instead subst the tparam types here?
-                       newTargs = subst.smap.targs
+               if newTArgs == nil {
+                       dump(">>> nothing to substitute in %s", t)
+                       return t // nothing to substitute
                }
 
                // before creating a new named type, check if we have this one already
-               h := instantiatedHash(t, newTargs)
+               h := subst.ctxt.typeHash(t.orig, newTArgs)
                dump(">>> new type hash: %s", h)
-               if named, found := subst.typMap[h]; found {
+               if named := subst.ctxt.typeForHash(h, nil); named != nil {
                        dump(">>> found %s", named)
                        return named
                }
 
-               // create a new named type and populate typMap to avoid endless recursion
-               tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
-               named := subst.check.newNamed(tname, t, t.Underlying(), t.TParams(), t.methods) // method signatures are updated lazily
-               named.targs = newTargs
-               subst.typMap[h] = named
-               t.expand() // must happen after typMap update to avoid infinite recursion
-
-               // do the substitution
-               dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs)
-               named.underlying = subst.typOrNil(t.Underlying())
-               dump(">>> underlying: %v", named.underlying)
-               assert(named.underlying != nil)
-               named.fromRHS = named.underlying // for cycle detection (Checker.validType)
+               // Create a new instance and populate the context to avoid endless
+               // recursion. The position used here is irrelevant because validation only
+               // occurs on t (we don't call validType on named), but we use subst.pos to
+               // help with debugging.
+               t.orig.resolve(subst.ctxt)
+               return subst.check.instance(subst.pos, t.orig, newTArgs, subst.ctxt)
 
-               return named
+               // Note that if we were to expose substitution more generally (not just in
+               // the context of a declaration), we'd have to substitute in
+               // named.underlying as well.
+               //
+               // But this is unnecessary for now.
 
        case *TypeParam:
                return subst.smap.lookup(t)
@@ -265,40 +235,6 @@ func (subst *subster) typ(typ Type) Type {
        return typ
 }
 
-var instanceHashing = 0
-
-func instantiatedHash(typ *Named, targs []Type) string {
-       assert(instanceHashing == 0)
-       instanceHashing++
-       var buf bytes.Buffer
-       writeTypeName(&buf, typ.obj, nil)
-       buf.WriteByte('[')
-       writeTypeList(&buf, targs, nil, nil)
-       buf.WriteByte(']')
-       instanceHashing--
-
-       // With respect to the represented type, whether a
-       // type is fully expanded or stored as instance
-       // does not matter - they are the same types.
-       // Remove the instanceMarkers printed for instances.
-       res := buf.Bytes()
-       i := 0
-       for _, b := range res {
-               if b != instanceMarker {
-                       res[i] = b
-                       i++
-               }
-       }
-
-       return string(res[:i])
-}
-
-func typeListString(list []Type) string {
-       var buf bytes.Buffer
-       writeTypeList(&buf, list, nil, nil)
-       return buf.String()
-}
-
 // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
 // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
 // where an array/slice element is accessed before it is set up.
@@ -394,19 +330,19 @@ func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
        return
 }
 
-func (subst *subster) termList(in []*term) (out []*term, copied bool) {
+func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
        out = in
        for i, t := range in {
                if u := subst.typ(t.typ); u != t.typ {
                        if !copied {
                                // first function that got substituted => allocate new out slice
                                // and copy all functions
-                               new := make([]*term, len(in))
+                               new := make([]*Term, len(in))
                                copy(new, out)
                                out = new
                                copied = true
                        }
-                       out[i] = &term{t.tilde, u}
+                       out[i] = NewTerm(t.tilde, u)
                }
        }
        return
diff --git a/src/go/types/termlist.go b/src/go/types/termlist.go
new file mode 100644 (file)
index 0000000..c4ab0e0
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2021 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 types
+
+import "bytes"
+
+// A termlist represents the type set represented by the union
+// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn.
+// A termlist is in normal form if all terms are disjoint.
+// termlist operations don't require the operands to be in
+// normal form.
+type termlist []*term
+
+// allTermlist represents the set of all types.
+// It is in normal form.
+var allTermlist = termlist{new(term)}
+
+// String prints the termlist exactly (without normalization).
+func (xl termlist) String() string {
+       if len(xl) == 0 {
+               return "∅"
+       }
+       var buf bytes.Buffer
+       for i, x := range xl {
+               if i > 0 {
+                       buf.WriteString(" ∪ ")
+               }
+               buf.WriteString(x.String())
+       }
+       return buf.String()
+}
+
+// isEmpty reports whether the termlist xl represents the empty set of types.
+func (xl termlist) isEmpty() bool {
+       // If there's a non-nil term, the entire list is not empty.
+       // If the termlist is in normal form, this requires at most
+       // one iteration.
+       for _, x := range xl {
+               if x != nil {
+                       return false
+               }
+       }
+       return true
+}
+
+// isAll reports whether the termlist xl represents the set of all types.
+func (xl termlist) isAll() bool {
+       // If there's a 𝓤 term, the entire list is 𝓤.
+       // If the termlist is in normal form, this requires at most
+       // one iteration.
+       for _, x := range xl {
+               if x != nil && x.typ == nil {
+                       return true
+               }
+       }
+       return false
+}
+
+// norm returns the normal form of xl.
+func (xl termlist) norm() termlist {
+       // Quadratic algorithm, but good enough for now.
+       // TODO(gri) fix asymptotic performance
+       used := make([]bool, len(xl))
+       var rl termlist
+       for i, xi := range xl {
+               if xi == nil || used[i] {
+                       continue
+               }
+               for j := i + 1; j < len(xl); j++ {
+                       xj := xl[j]
+                       if xj == nil || used[j] {
+                               continue
+                       }
+                       if u1, u2 := xi.union(xj); u2 == nil {
+                               // If we encounter a 𝓤 term, the entire list is 𝓤.
+                               // Exit early.
+                               // (Note that this is not just an optimization;
+                               // if we continue, we may end up with a 𝓤 term
+                               // and other terms and the result would not be
+                               // in normal form.)
+                               if u1.typ == nil {
+                                       return allTermlist
+                               }
+                               xi = u1
+                               used[j] = true // xj is now unioned into xi - ignore it in future iterations
+                       }
+               }
+               rl = append(rl, xi)
+       }
+       return rl
+}
+
+// If the type set represented by xl is specified by a single (non-𝓤) term,
+// singleType returns that type. Otherwise it returns nil.
+func (xl termlist) singleType() Type {
+       if nl := xl.norm(); len(nl) == 1 {
+               return nl[0].typ // if nl.isAll() then typ is nil, which is ok
+       }
+       return nil
+}
+
+// union returns the union xl ∪ yl.
+func (xl termlist) union(yl termlist) termlist {
+       return append(xl, yl...).norm()
+}
+
+// intersect returns the intersection xl ∩ yl.
+func (xl termlist) intersect(yl termlist) termlist {
+       if xl.isEmpty() || yl.isEmpty() {
+               return nil
+       }
+
+       // Quadratic algorithm, but good enough for now.
+       // TODO(gri) fix asymptotic performance
+       var rl termlist
+       for _, x := range xl {
+               for _, y := range yl {
+                       if r := x.intersect(y); r != nil {
+                               rl = append(rl, r)
+                       }
+               }
+       }
+       return rl.norm()
+}
+
+// equal reports whether xl and yl represent the same type set.
+func (xl termlist) equal(yl termlist) bool {
+       // TODO(gri) this should be more efficient
+       return xl.subsetOf(yl) && yl.subsetOf(xl)
+}
+
+// includes reports whether t ∈ xl.
+func (xl termlist) includes(t Type) bool {
+       for _, x := range xl {
+               if x.includes(t) {
+                       return true
+               }
+       }
+       return false
+}
+
+// supersetOf reports whether y ⊆ xl.
+func (xl termlist) supersetOf(y *term) bool {
+       for _, x := range xl {
+               if y.subsetOf(x) {
+                       return true
+               }
+       }
+       return false
+}
+
+// subsetOf reports whether xl ⊆ yl.
+func (xl termlist) subsetOf(yl termlist) bool {
+       if yl.isEmpty() {
+               return xl.isEmpty()
+       }
+
+       // each term x of xl must be a subset of yl
+       for _, x := range xl {
+               if !yl.supersetOf(x) {
+                       return false // x is not a subset yl
+               }
+       }
+       return true
+}
diff --git a/src/go/types/termlist_test.go b/src/go/types/termlist_test.go
new file mode 100644 (file)
index 0000000..dddca7a
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright 2021 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 types
+
+import (
+       "strings"
+       "testing"
+)
+
+// maketl makes a term list from a string of the term list.
+func maketl(s string) termlist {
+       s = strings.ReplaceAll(s, " ", "")
+       names := strings.Split(s, "∪")
+       r := make(termlist, len(names))
+       for i, n := range names {
+               r[i] = testTerm(n)
+       }
+       return r
+}
+
+func TestTermlistAll(t *testing.T) {
+       if !allTermlist.isAll() {
+               t.Errorf("allTermlist is not the set of all types")
+       }
+}
+
+func TestTermlistString(t *testing.T) {
+       for _, want := range []string{
+               "∅",
+               "𝓤",
+               "int",
+               "~int",
+               "myInt",
+               "∅ ∪ ∅",
+               "𝓤 ∪ 𝓤",
+               "∅ ∪ 𝓤 ∪ int",
+               "∅ ∪ 𝓤 ∪ int ∪ myInt",
+       } {
+               if got := maketl(want).String(); got != want {
+                       t.Errorf("(%v).String() == %v", want, got)
+               }
+       }
+}
+
+func TestTermlistIsEmpty(t *testing.T) {
+       for test, want := range map[string]bool{
+               "∅":             true,
+               "∅ ∪ ∅":         true,
+               "∅ ∪ ∅ ∪ 𝓤":     false,
+               "∅ ∪ ∅ ∪ myInt": false,
+               "𝓤":             false,
+               "𝓤 ∪ int":       false,
+               "𝓤 ∪ myInt ∪ ∅": false,
+       } {
+               xl := maketl(test)
+               got := xl.isEmpty()
+               if got != want {
+                       t.Errorf("(%v).isEmpty() == %v; want %v", test, got, want)
+               }
+       }
+}
+
+func TestTermlistIsAll(t *testing.T) {
+       for test, want := range map[string]bool{
+               "∅":             false,
+               "∅ ∪ ∅":         false,
+               "int ∪ ~string": false,
+               "~int ∪ myInt":  false,
+               "∅ ∪ ∅ ∪ 𝓤":     true,
+               "𝓤":             true,
+               "𝓤 ∪ int":       true,
+               "myInt ∪ 𝓤":     true,
+       } {
+               xl := maketl(test)
+               got := xl.isAll()
+               if got != want {
+                       t.Errorf("(%v).isAll() == %v; want %v", test, got, want)
+               }
+       }
+}
+
+func TestTermlistNorm(t *testing.T) {
+       for _, test := range []struct {
+               xl, want string
+       }{
+               {"∅", "∅"},
+               {"∅ ∪ ∅", "∅"},
+               {"∅ ∪ int", "int"},
+               {"∅ ∪ myInt", "myInt"},
+               {"𝓤 ∪ int", "𝓤"},
+               {"𝓤 ∪ myInt", "𝓤"},
+               {"int ∪ myInt", "int ∪ myInt"},
+               {"~int ∪ int", "~int"},
+               {"~int ∪ myInt", "~int"},
+               {"int ∪ ~string ∪ int", "int ∪ ~string"},
+               {"~int ∪ string ∪ 𝓤 ∪ ~string ∪ int", "𝓤"},
+               {"~int ∪ string ∪ myInt ∪ ~string ∪ int", "~int ∪ ~string"},
+       } {
+               xl := maketl(test.xl)
+               got := maketl(test.xl).norm()
+               if got.String() != test.want {
+                       t.Errorf("(%v).norm() = %v; want %v", xl, got, test.want)
+               }
+       }
+}
+
+func TestTermlistSingleType(t *testing.T) {
+       // helper to deal with nil types
+       tstring := func(typ Type) string {
+               if typ == nil {
+                       return "nil"
+               }
+               return typ.String()
+       }
+
+       for test, want := range map[string]string{
+               "∅":                 "nil",
+               "𝓤":                 "nil",
+               "int":               "int",
+               "myInt":             "myInt",
+               "~int":              "int",
+               "~int ∪ string":     "nil",
+               "~int ∪ myInt":      "int",
+               "∅ ∪ int":           "int",
+               "∅ ∪ ~int":          "int",
+               "∅ ∪ ~int ∪ string": "nil",
+       } {
+               xl := maketl(test)
+               got := tstring(xl.singleType())
+               if got != want {
+                       t.Errorf("(%v).singleType() == %v; want %v", test, got, want)
+               }
+       }
+}
+
+func TestTermlistUnion(t *testing.T) {
+       for _, test := range []struct {
+               xl, yl, want string
+       }{
+
+               {"∅", "∅", "∅"},
+               {"∅", "𝓤", "𝓤"},
+               {"∅", "int", "int"},
+               {"𝓤", "~int", "𝓤"},
+               {"int", "~int", "~int"},
+               {"int", "string", "int ∪ string"},
+               {"int", "myInt", "int ∪ myInt"},
+               {"~int", "myInt", "~int"},
+               {"int ∪ string", "~string", "int ∪ ~string"},
+               {"~int ∪ string", "~string ∪ int", "~int ∪ ~string"},
+               {"~int ∪ string ∪ ∅", "~string ∪ int", "~int ∪ ~string"},
+               {"~int ∪ myInt ∪ ∅", "~string ∪ int", "~int ∪ ~string"},
+               {"~int ∪ string ∪ 𝓤", "~string ∪ int", "𝓤"},
+               {"~int ∪ string ∪ myInt", "~string ∪ int", "~int ∪ ~string"},
+       } {
+               xl := maketl(test.xl)
+               yl := maketl(test.yl)
+               got := xl.union(yl).String()
+               if got != test.want {
+                       t.Errorf("(%v).union(%v) = %v; want %v", test.xl, test.yl, got, test.want)
+               }
+       }
+}
+
+func TestTermlistIntersect(t *testing.T) {
+       for _, test := range []struct {
+               xl, yl, want string
+       }{
+
+               {"∅", "∅", "∅"},
+               {"∅", "𝓤", "∅"},
+               {"∅", "int", "∅"},
+               {"∅", "myInt", "∅"},
+               {"𝓤", "~int", "~int"},
+               {"𝓤", "myInt", "myInt"},
+               {"int", "~int", "int"},
+               {"int", "string", "∅"},
+               {"int", "myInt", "∅"},
+               {"~int", "myInt", "myInt"},
+               {"int ∪ string", "~string", "string"},
+               {"~int ∪ string", "~string ∪ int", "int ∪ string"},
+               {"~int ∪ string ∪ ∅", "~string ∪ int", "int ∪ string"},
+               {"~int ∪ myInt ∪ ∅", "~string ∪ int", "int"},
+               {"~int ∪ string ∪ 𝓤", "~string ∪ int", "int ∪ ~string"},
+               {"~int ∪ string ∪ myInt", "~string ∪ int", "int ∪ string"},
+       } {
+               xl := maketl(test.xl)
+               yl := maketl(test.yl)
+               got := xl.intersect(yl).String()
+               if got != test.want {
+                       t.Errorf("(%v).intersect(%v) = %v; want %v", test.xl, test.yl, got, test.want)
+               }
+       }
+}
+
+func TestTermlistEqual(t *testing.T) {
+       for _, test := range []struct {
+               xl, yl string
+               want   bool
+       }{
+               {"∅", "∅", true},
+               {"∅", "𝓤", false},
+               {"𝓤", "𝓤", true},
+               {"𝓤 ∪ int", "𝓤", true},
+               {"𝓤 ∪ int", "string ∪ 𝓤", true},
+               {"𝓤 ∪ myInt", "string ∪ 𝓤", true},
+               {"int ∪ ~string", "string ∪ int", false},
+               {"~int ∪ string", "string ∪ myInt", false},
+               {"int ∪ ~string ∪ ∅", "string ∪ int ∪ ~string", true},
+       } {
+               xl := maketl(test.xl)
+               yl := maketl(test.yl)
+               got := xl.equal(yl)
+               if got != test.want {
+                       t.Errorf("(%v).equal(%v) = %v; want %v", test.xl, test.yl, got, test.want)
+               }
+       }
+}
+
+func TestTermlistIncludes(t *testing.T) {
+       for _, test := range []struct {
+               xl, typ string
+               want    bool
+       }{
+               {"∅", "int", false},
+               {"𝓤", "int", true},
+               {"~int", "int", true},
+               {"int", "string", false},
+               {"~int", "string", false},
+               {"~int", "myInt", true},
+               {"int ∪ string", "string", true},
+               {"~int ∪ string", "int", true},
+               {"~int ∪ string", "myInt", true},
+               {"~int ∪ myInt ∪ ∅", "myInt", true},
+               {"myInt ∪ ∅ ∪ 𝓤", "int", true},
+       } {
+               xl := maketl(test.xl)
+               yl := testTerm(test.typ).typ
+               got := xl.includes(yl)
+               if got != test.want {
+                       t.Errorf("(%v).includes(%v) = %v; want %v", test.xl, yl, got, test.want)
+               }
+       }
+}
+
+func TestTermlistSupersetOf(t *testing.T) {
+       for _, test := range []struct {
+               xl, typ string
+               want    bool
+       }{
+               {"∅", "∅", true},
+               {"∅", "𝓤", false},
+               {"∅", "int", false},
+               {"𝓤", "∅", true},
+               {"𝓤", "𝓤", true},
+               {"𝓤", "int", true},
+               {"𝓤", "~int", true},
+               {"𝓤", "myInt", true},
+               {"~int", "int", true},
+               {"~int", "~int", true},
+               {"~int", "myInt", true},
+               {"int", "~int", false},
+               {"myInt", "~int", false},
+               {"int", "string", false},
+               {"~int", "string", false},
+               {"int ∪ string", "string", true},
+               {"int ∪ string", "~string", false},
+               {"~int ∪ string", "int", true},
+               {"~int ∪ string", "myInt", true},
+               {"~int ∪ string ∪ ∅", "string", true},
+               {"~string ∪ ∅ ∪ 𝓤", "myInt", true},
+       } {
+               xl := maketl(test.xl)
+               y := testTerm(test.typ)
+               got := xl.supersetOf(y)
+               if got != test.want {
+                       t.Errorf("(%v).supersetOf(%v) = %v; want %v", test.xl, y, got, test.want)
+               }
+       }
+}
+
+func TestTermlistSubsetOf(t *testing.T) {
+       for _, test := range []struct {
+               xl, yl string
+               want   bool
+       }{
+               {"∅", "∅", true},
+               {"∅", "𝓤", true},
+               {"𝓤", "∅", false},
+               {"𝓤", "𝓤", true},
+               {"int", "int ∪ string", true},
+               {"~int", "int ∪ string", false},
+               {"~int", "myInt ∪ string", false},
+               {"myInt", "~int ∪ string", true},
+               {"~int", "string ∪ string ∪ int ∪ ~int", true},
+               {"myInt", "string ∪ string ∪ ~int", true},
+               {"int ∪ string", "string", false},
+               {"int ∪ string", "string ∪ int", true},
+               {"int ∪ ~string", "string ∪ int", false},
+               {"myInt ∪ ~string", "string ∪ int ∪ 𝓤", true},
+               {"int ∪ ~string", "string ∪ int ∪ ∅ ∪ string", false},
+               {"int ∪ myInt", "string ∪ ~int ∪ ∅ ∪ string", true},
+       } {
+               xl := maketl(test.xl)
+               yl := maketl(test.yl)
+               got := xl.subsetOf(yl)
+               if got != test.want {
+                       t.Errorf("(%v).subsetOf(%v) = %v; want %v", test.xl, test.yl, got, test.want)
+               }
+       }
+}
index 3881090603ebcc0831bef61756bd6e836aa88ab5..7cca6fd7142d2b0bbc5675bba269f2e84e62d33d 100644 (file)
@@ -45,6 +45,49 @@ func _[T C5[X], X any](ch T) {
        close(ch)
 }
 
+// copy
+
+func _[T any](x, y T) {
+       copy(x /* ERROR copy expects slice arguments */ , y)
+}
+
+func _[T ~[]byte](x, y T) {
+       copy(x, y)
+       copy(x, "foo")
+       copy("foo" /* ERROR expects slice arguments */ , y)
+
+       var x2 []byte
+       copy(x2, y) // element types are identical
+       copy(y, x2) // element types are identical
+
+       type myByte byte
+       var x3 []myByte
+       copy(x3 /* ERROR different element types */ , y)
+       copy(y /* ERROR different element types */ , x3)
+}
+
+func _[T ~[]E, E any](x T, y []E) {
+       copy(x, y)
+       copy(x /* ERROR different element types */ , "foo")
+}
+
+func _[T ~string](x []byte, y T) {
+       copy(x, y)
+       copy(y /* ERROR expects slice arguments */ , x)
+}
+
+func _[T ~[]byte|~string](x T, y []byte) {
+       copy(x /* ERROR expects slice arguments */ , y)
+       copy(y, x)
+}
+
+type L0 []int
+type L1 []int
+
+func _[T L0 | L1](x, y T) {
+       copy(x, y)
+}
+
 // delete
 
 type M0 interface{ int }
@@ -84,50 +127,45 @@ func _[T M4[K, V], K comparable, V any](m T) {
 
 // make
 
-type Bmc interface {
-       ~map[rune]string | ~chan int
-}
-
-type Bms interface {
-       ~map[string]int | ~[]int
-}
-
-type Bcs interface {
-       ~chan bool | ~[]float64
-}
-
-type Bss interface {
-       ~[]int | ~[]string
-}
-
-func _[T any]() {
-       _ = make(T /* ERROR invalid argument */)
-       _ = make(T /* ERROR invalid argument */, 10)
-       _ = make(T /* ERROR invalid argument */, 10, 20)
-}
-
-func _[T Bmc]() {
-       _ = make(T)
-       _ = make(T, 10)
-       _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20)
-}
-
-func _[T Bms]() {
-       _ = make /* ERROR expects 2 arguments */ (T)
-       _ = make(T, 10)
-       _ = make /* ERROR expects 2 arguments */ (T, 10, 20)
-}
-
-func _[T Bcs]() {
-       _ = make /* ERROR expects 2 arguments */ (T)
-       _ = make(T, 10)
-       _ = make /* ERROR expects 2 arguments */ (T, 10, 20)
-}
-
-func _[T Bss]() {
-       _ = make /* ERROR expects 2 or 3 arguments */ (T)
-       _ = make(T, 10)
-       _ = make(T, 10, 20)
+type myChan chan int
+
+func _[
+       S1 ~[]int,
+       S2 ~[]int | ~chan int,
+
+       M1 ~map[string]int,
+       M2 ~map[string]int | ~chan int,
+
+       C1 ~chan int,
+       C2 ~chan int | ~chan string,
+       C3 chan int | myChan, // single underlying type
+]() {
+       type S0 []int
+       _ = make([]int, 10)
+       _ = make(S0, 10)
+       _ = make(S1, 10)
+       _ = make() /* ERROR not enough arguments */
+       _ = make /* ERROR expects 2 or 3 arguments */ (S1)
+       _ = make(S1, 10, 20)
+       _ = make /* ERROR expects 2 or 3 arguments */ (S1, 10, 20, 30)
+       _ = make(S2 /* ERROR cannot make .* no single underlying type */ , 10)
+
+       type M0 map[string]int
+       _ = make(map[string]int)
+       _ = make(M0)
+       _ = make(M1)
+       _ = make(M1, 10)
+       _ = make/* ERROR expects 1 or 2 arguments */(M1, 10, 20)
+       _ = make(M2 /* ERROR cannot make .* no single underlying type */ )
+
+       type C0 chan int
+       _ = make(chan int)
+       _ = make(C0)
+       _ = make(C1)
+       _ = make(C1, 10)
+       _ = make/* ERROR expects 1 or 2 arguments */(C1, 10, 20)
+       _ = make(C2 /* ERROR cannot make .* no single underlying type */ )
+       _ = make(C3)
 }
 
 // unsafe.Alignof
diff --git a/src/go/types/testdata/check/compliterals.go2 b/src/go/types/testdata/check/compliterals.go2
new file mode 100644 (file)
index 0000000..60eac97
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+// Composite literals with parameterized types
+
+package comp_literals
+
+type myStruct struct {
+       f int
+}
+
+type slice[E any] []E
+
+func struct_literals[S struct{f int}|myStruct]() {
+       _ = S{}
+       _ = S{0}
+       _ = S{f: 0}
+
+        _ = slice[int]{1, 2, 3}
+        _ = slice[S]{{}, {0}, {f:0}}
+}
index 1224e46377ab45f1bb32965ffd86f53a3431bb31..18f0d32e1b4a5a878c65a5e8253b12cd8a54a8a5 100644 (file)
@@ -146,7 +146,7 @@ type (
                m1(I5)
        }
        I6 interface {
-               S0 /* ERROR "not an interface" */
+               S0 /* ERROR "non-interface type S0" */
        }
        I7 interface {
                I1
index f9726b5de53202c301757e36ea5bde812cd3db24..8757fd9e487f3c7d1aac003b87cc04beb9dba87f 100644 (file)
@@ -29,7 +29,7 @@ func arrays() {
        _ = a == b
        _ = a != b
        _ = a /* ERROR < not defined */ < b
-       _ = a == nil /* ERROR cannot convert */
+       _ = a /* ERROR cannot compare.*mismatched types */ == nil
 
        type C [10]int
        var c C
@@ -53,7 +53,7 @@ func structs() {
        _ = s == t
        _ = s != t
        _ = s /* ERROR < not defined */ < t
-       _ = s == nil /* ERROR cannot convert */
+       _ = s /* ERROR cannot compare.*mismatched types */ == nil
 
        type S struct {
                x int
similarity index 63%
rename from src/go/types/testdata/check/tinference.go2
rename to src/go/types/testdata/check/funcinference.go2
index 44e8dc00595f66a3c7f8390c647537b0e24a8408..f04b76ca1a9812edf2237fc1aef2c647b960e9f2 100644 (file)
@@ -2,31 +2,27 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package tinferenceB
+package funcInference
 
 import "strconv"
 
 type any interface{}
 
-// TODO(rFindley) the below partially applied function types should probably
-//                not be permitted (spec question).
+func f0[A any, B interface{~*C}, C interface{~*D}, D interface{~*A}](A, B, C, D) {}
+func _() {
+       f := f0[string]
+       f("a", nil, nil, nil)
+       f0("a", nil, nil, nil)
+}
 
-// Embedding stand-alone type parameters is not permitted for now. Disabled.
-// func f0[A any, B interface{~C}, C interface{~D}, D interface{~A}](A, B, C, D)
-// func _() {
-//     f := f0[string]
-//     f("a", "b", "c", "d")
-//     f0("a", "b", "c", "d")
-// }
-//
-// func f1[A any, B interface{~A}](A, B)
-// func _() {
-//     f := f1[int]
-//     f(int(0), int(0))
-//     f1(int(0), int(0))
-// }
+func f1[A any, B interface{~*A}](A, B) {}
+func _() {
+       f := f1[int]
+       f(int(0), new(int))
+       f1(int(0), new(int))
+}
 
-func f2[A any, B interface{~[]A}](A, B)
+func f2[A any, B interface{~[]A}](A, B) {}
 func _() {
        f := f2[byte]
        f(byte(0), []byte{})
@@ -42,7 +38,7 @@ func _() {
 //     f3(x, &x, &x)
 // }
 
-func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C)
+func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) {}
 func _() {
        f := f4[int]
        var x int
@@ -50,22 +46,20 @@ func _() {
        f4(x, []*int{}, &x)
 }
 
-func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A
+func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A { panic(0) }
 func _() {
        x := f5(1.2)
        var _ float64 = x.b
        var _ float64 = *x.c
 }
 
-func f6[A any, B interface{~struct{f []A}}](B) A
+func f6[A any, B interface{~struct{f []A}}](B) A { panic(0) }
 func _() {
        x := f6(struct{f []string}{})
        var _ string = x
 }
 
-// TODO(gri) Need to flag invalid recursive constraints. At the
-// moment these cause infinite recursions and stack overflow.
-// func f7[A interface{type B}, B interface{~A}]()
+func f7[A interface{*B}, B interface{~*A}]() {}
 
 // More realistic examples
 
@@ -92,7 +86,7 @@ func FromStrings[T interface{}, PT Setter[T]](s []string) []T {
        result := make([]T, len(s))
        for i, v := range s {
                // The type of &result[i] is *T which is in the type list
-               // of Setter2, so we can convert it to PT.
+               // of Setter, so we can convert it to PT.
                p := PT(&result[i])
                // PT has a Set method.
                p.Set(v)
index 6a1a10ad49b935e039c881b4edf851938a214c1c..b7bba5d3b1dd8f88f56b9477ebd9afaa173a8965 100644 (file)
@@ -40,13 +40,7 @@ func _[T interface{ m() }](x *T) {
        x.m  /* ERROR x\.m undefined */ ()
 }
 
-// In a generic function body all method calls will be pointer method calls.
-// If necessary, the function body will insert temporary variables, not seen
-// by the user, in order to get an addressable variable to use to call the method.
-// Thus, assume an argument type for a generic function to be the type of addressable
-// values in the generic function when checking if the argument type satisfies the
-// generic function's type bound.
-func f2[_ interface{ m1(); m2() }]()
+func f2[_ interface{ m1(); m2() }]() {}
 
 type T struct{}
 func (T) m1()
@@ -59,8 +53,8 @@ func _() {
 }
 
 // When a type parameter is used as an argument to instantiate a parameterized
-// type with a type list constraint, all of the type argument's types in its
-// bound, but at least one (!), must be in the type list of the bound of the
+// type with a type set constraint, all of the type argument's types in its
+// bound, but at least one (!), must be in the type set of the bound of the
 // corresponding parameterized type's type parameter.
 type T1[P interface{~uint}] struct{}
 
@@ -152,13 +146,13 @@ type List3[TElem any] struct {
 }
 
 // Infinite generic type declarations must lead to an error.
-type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] }
-type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] }
+type inf1 /* ERROR illegal cycle */ [T any] struct{ _ inf1[T] }
+type inf2 /* ERROR illegal cycle */ [T any] struct{ inf2[T] }
 
 // The implementation of conversions T(x) between integers and floating-point
 // numbers checks that both T and x have either integer or floating-point
 // type. When the type of T or x is a type parameter, the respective simple
-// predicate disjunction in the implementation was wrong because if a type list
+// predicate disjunction in the implementation was wrong because if a term list
 // contains both an integer and a floating-point type, the type parameter is
 // neither an integer or a floating-point number.
 func convert[T1, T2 interface{~int | ~uint | ~float32}](v T1) T2 {
@@ -191,13 +185,13 @@ func _[T interface{}, PT interface{~*T}] (x T) PT {
     return &x
 }
 
-// Indexing of generic types containing type parameters in their type list:
+// Indexing of generic types containing type parameters in their term list:
 func at[T interface{ ~[]E }, E interface{}](x T, i int) E {
         return x[i]
 }
 
 // A generic type inside a function acts like a named type. Its underlying
-// type is itself, its "operational type" is defined by the type list in
+// type is itself, its "operational type" is defined by the term list in
 // the tybe bound, if any.
 func _[T interface{~int}](x T) {
        type myint int
@@ -230,16 +224,23 @@ func _[T interface{ ~func() }](f T) {
        go f()
 }
 
-// We must compare against the underlying type of type list entries
+type F1 func()
+type F2 func()
+func _[T interface{ func()|F1|F2 }](f T) {
+       f()
+       go f()
+}
+
+// We must compare against the underlying type of term list entries
 // when checking if a constraint is satisfied by a type. The under-
-// lying type of each type list entry must be computed after the
+// lying type of each term list entry must be computed after the
 // interface has been instantiated as its typelist may contain a
 // type parameter that was substituted with a defined type.
 // Test case from an (originally) failing example.
 
 type sliceOf[E any] interface{ ~[]E }
 
-func append[T interface{}, S sliceOf[T], T2 interface{}](s S, t ...T2) S
+func append[T interface{}, S sliceOf[T], T2 interface{}](s S, t ...T2) S { panic(0) }
 
 var f           func()
 var cancelSlice []context.CancelFunc
@@ -247,7 +248,7 @@ var _ = append[context.CancelFunc, []context.CancelFunc, context.CancelFunc](can
 
 // A generic function must be instantiated with a type, not a value.
 
-func g[T any](T) T
+func g[T any](T) T { panic(0) }
 
 var _ = g[int]
 var _ = g[nil /* ERROR is not a type */ ]
index ef1737331d7eeaac110fe8bfde549ac5a8181796..88ce452959845dd77e2ba9ccfac917dcfcf8df26 100644 (file)
@@ -79,11 +79,11 @@ func issue9473(a []int, b ...int) {
 // Check that embedding a non-interface type in an interface results in a good error message.
 func issue10979() {
        type _ interface {
-               int /* ERROR int is not an interface */
+               int /* ERROR non-interface type int */
        }
        type T struct{}
        type _ interface {
-               T /* ERROR T is not an interface */
+               T /* ERROR non-interface type T */
        }
        type _ interface {
                nosuchtype /* ERROR undeclared name: nosuchtype */
@@ -280,7 +280,7 @@ type issue25301b /* ERROR cycle */ = interface {
 }
 
 type issue25301c interface {
-       notE // ERROR struct\{\} is not an interface
+       notE // ERROR non-interface type struct\{\}
 }
 
 type notE = struct{}
index efc090a1d1f0b788dd8977cf551ed2d77a40a108..f02e773dbeeeebbafde08ab38ac4cef93f11897a 100644 (file)
@@ -4,8 +4,6 @@
 
 package linalg
 
-import "math"
-
 // Numeric is type bound that matches any numeric type.
 // It would likely be in a constraints package in the standard library.
 type Numeric interface {
@@ -52,32 +50,33 @@ type Complex interface {
        ~complex64 | ~complex128
 }
 
-// OrderedAbs is a helper type that defines an Abs method for
-// ordered numeric types.
-type OrderedAbs[T OrderedNumeric] T
-
-func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
-       if a < 0 {
-               return -a
-       }
-       return a
-}
-
-// ComplexAbs is a helper type that defines an Abs method for
-// complex types.
-type ComplexAbs[T Complex] T
-
-func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
-       r := float64(real(a))
-       i := float64(imag(a))
-       d := math.Sqrt(r * r + i * i)
-       return ComplexAbs[T](complex(d, 0))
-}
-
-func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
-       return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
-}
-
-func ComplexAbsDifference[T Complex](a, b T) T {
-       return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // OrderedAbs is a helper type that defines an Abs method for
+// // ordered numeric types.
+// type OrderedAbs[T OrderedNumeric] T
+// 
+// func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+//     if a < 0 {
+//             return -a
+//     }
+//     return a
+// }
+// 
+// // ComplexAbs is a helper type that defines an Abs method for
+// // complex types.
+// type ComplexAbs[T Complex] T
+// 
+// func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+//     r := float64(real(a))
+//     i := float64(imag(a))
+//     d := math.Sqrt(r * r + i * i)
+//     return ComplexAbs[T](complex(d, 0))
+// }
+// 
+// func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+//     return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+// }
+// 
+// func ComplexAbsDifference[T Complex](a, b T) T {
+//     return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+// }
index 65e9aa29629faefa5b78c5a4eaaab98239b9e304..fb567a07d085a32493b7126995a13b1a0a39962f 100644 (file)
@@ -4,4 +4,4 @@
 
 package main
 
-func main[ /* ERROR "func main must have no type parameters" */ T any]() {}
+func main[T /* ERROR "func main must have no type parameters" */ any]() {}
index 2833445662de813d6d3eeed95978c8342316b29f..e13bf33feda9edb1f87910f9bda04d4f7908bd9e 100644 (file)
@@ -114,7 +114,7 @@ func (it *Iterator[K, V]) Next() (K, V, bool) {
 
 // chans
 
-func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T])
+func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T]) { panic(0) }
 
 // A sender is used to send values to a Receiver.
 type chans_Sender[T any] struct {
@@ -143,4 +143,4 @@ type chans_Receiver[T any] struct {
 func (r *chans_Receiver[T]) Next() (T, bool) {
        v, ok := <-r.values
        return v, ok
-}
\ No newline at end of file
+}
diff --git a/src/go/types/testdata/check/typeinference.go2 b/src/go/types/testdata/check/typeinference.go2
new file mode 100644 (file)
index 0000000..8876cca
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2021 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 typeInference
+
+// basic inference
+type Tb[P ~*Q, Q any] int
+func _() {
+       var x Tb[*int]
+       var y Tb[*int, int]
+       x = y
+       _ = x
+}
+
+// recursive inference
+type Tr[A any, B ~*C, C ~*D, D ~*A] int
+func _() {
+       var x Tr[string]
+       var y Tr[string, ***string, **string, *string]
+       var z Tr[int, ***int, **int, *int]
+       x = y
+       x = z // ERROR cannot use z .* as Tr
+       _ = x
+}
+
+// other patterns of inference
+type To0[A any, B ~[]A] int
+type To1[A any, B ~struct{a A}] int
+type To2[A any, B ~[][]A] int
+type To3[A any, B ~[3]*A] int
+type To4[A any, B any, C ~struct{a A; b B}] int
+func _() {
+       var _ To0[int]
+       var _ To1[int]
+       var _ To2[int]
+       var _ To3[int]
+       var _ To4[int, string]
+}
+
+// failed inference
+type Tf0[A, B any] int
+type Tf1[A any, B ~struct{a A; c C}, C any] int
+func _() {
+       var _ Tf0 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int]
+       var _ Tf1 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 3 type parameters */ [int]
+}
index 069bd3bc1695fe8539f2ea9454ff28f2132b893d..65481202e4c4e8ccdff904a66c5d7ef48b5da1f9 100644 (file)
@@ -8,7 +8,8 @@ type myInt int
 
 // Parameterized type declarations
 
-type T1[P any] P
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+type T1[P any] P // ERROR cannot use a type parameter as RHS in type declaration
 
 type T2[P any] struct {
         f P
@@ -17,13 +18,15 @@ type T2[P any] struct {
 
 type List[P any] []P
 
-// Alias type declarations cannot have type parameters. Syntax error.
-type A1[P any] = /* ERROR cannot be alias */ P
+// Alias type declarations cannot have type parameters.
+// Issue #46477 proposses to change that.
+type A1[P any] = /* ERROR cannot be alias */ struct{}
 
-// But an alias may refer to a generic, uninstantiated type.
-type A2 = List
+// Pending clarification of #46477 we disallow aliases
+// of generic types.
+type A2 = List // ERROR cannot use generic type
 var _ A2[int]
-var _ A2 /* ERROR without instantiation */
+var _ A2
 
 type A3 = List[int]
 var _ A3
@@ -55,5 +58,5 @@ var _ T3[int] = T3[int](List[int]{1, 2, 3})
 
 // Self-recursive generic types are not permitted
 
-type self1[P any] self1 /* ERROR illegal cycle */ [P]
+type self1 /* ERROR illegal cycle */ [P any] self1[P]
 type self2[P any] *self2[P] // this is ok
index ab56ccafc91e755aaa4136fba8d472ea755b8b7a..f07c42a1da2b1d0b431479fc30c15e1deca67d23 100644 (file)
@@ -85,27 +85,29 @@ type NumericAbs[T any] interface {
        Abs() T
 }
 
-func AbsDifference[T NumericAbs[T]](x T)
+func AbsDifference[T NumericAbs[T]](x T) { panic(0) }
 
-type OrderedAbs[T any] T
-
-func (a OrderedAbs[T]) Abs() OrderedAbs[T]
-
-func OrderedAbsDifference[T any](x T) {
-       AbsDifference(OrderedAbs[T](x))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type OrderedAbs[T any] T
+// 
+// func (a OrderedAbs[T]) Abs() OrderedAbs[T]
+// 
+// func OrderedAbsDifference[T any](x T) {
+//     AbsDifference(OrderedAbs[T](x))
+// }
 
 // same code, reduced to essence
 
-func g[P interface{ m() P }](x P)
+func g[P interface{ m() P }](x P) { panic(0) }
 
-type T4[P any] P
-
-func (_ T4[P]) m() T4[P]
-
-func _[Q any](x Q) {
-       g(T4[Q](x))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type T4[P any] P
+// 
+// func (_ T4[P]) m() T4[P]
+// 
+// func _[Q any](x Q) {
+//     g(T4[Q](x))
+// }
 
 // Another test case that caused  problems in the past
 
@@ -159,21 +161,18 @@ type _ interface {
        ~rune
 }
 
-// Interface type lists may contain each type at most once.
-// (If there are multiple lists, we assume the author intended
-// for them to be all in a single list, and we report the error
-// as well.)
+// Type sets may contain each type at most once.
 type _ interface {
-       ~int|~ /* ERROR duplicate term int */ int
-       ~int|int /* ERROR duplicate term int */
-       int|int /* ERROR duplicate term int */
+       ~int|~ /* ERROR overlapping terms ~int */ int
+       ~int|int /* ERROR overlapping terms int */
+       int|int /* ERROR overlapping terms int */
 }
 
 type _ interface {
-       ~struct{f int} | ~struct{g int} | ~ /* ERROR duplicate term */ struct{f int}
+       ~struct{f int} | ~struct{g int} | ~ /* ERROR overlapping terms */ struct {f int}
 }
 
-// Interface type lists can contain any type, incl. *Named types.
+// Interface term lists can contain any type, incl. *Named types.
 // Verify that we use the underlying type to compute the operational type.
 type MyInt int
 func add1[T interface{MyInt}](x T) T {
@@ -185,9 +184,9 @@ func double[T interface{MyInt|MyString}](x T) T {
        return x + x
 }
 
-// Embedding of interfaces with type lists leads to interfaces
-// with type lists that are the intersection of the embedded
-// type lists.
+// Embedding of interfaces with term lists leads to interfaces
+// with term lists that are the intersection of the embedded
+// term lists.
 
 type E0 interface {
        ~int | ~bool | ~string
@@ -205,7 +204,7 @@ type I0 interface {
        E0
 }
 
-func f0[T I0]()
+func f0[T I0]() {}
 var _ = f0[int]
 var _ = f0[bool]
 var _ = f0[string]
@@ -216,7 +215,7 @@ type I01 interface {
        E1
 }
 
-func f01[T I01]()
+func f01[T I01]() {}
 var _ = f01[int]
 var _ = f01[bool /* ERROR does not satisfy I0 */ ]
 var _ = f01[string]
@@ -228,18 +227,18 @@ type I012 interface {
        E2
 }
 
-func f012[T I012]()
-var _ = f012[int /* ERROR does not satisfy I012 */ ]
-var _ = f012[bool /* ERROR does not satisfy I012 */ ]
-var _ = f012[string /* ERROR does not satisfy I012 */ ]
-var _ = f012[float64 /* ERROR does not satisfy I012 */ ]
+func f012[T I012]() {}
+var _ = f012[int /* ERROR does not satisfy I012.*type set is empty */ ]
+var _ = f012[bool /* ERROR does not satisfy I012.*type set is empty */ ]
+var _ = f012[string /* ERROR does not satisfy I012.*type set is empty */ ]
+var _ = f012[float64 /* ERROR does not satisfy I012.*type set is empty */ ]
 
 type I12 interface {
        E1
        E2
 }
 
-func f12[T I12]()
+func f12[T I12]() {}
 var _ = f12[int /* ERROR does not satisfy I12 */ ]
 var _ = f12[bool /* ERROR does not satisfy I12 */ ]
 var _ = f12[string /* ERROR does not satisfy I12 */ ]
@@ -250,8 +249,32 @@ type I0_ interface {
        ~int
 }
 
-func f0_[T I0_]()
+func f0_[T I0_]() {}
 var _ = f0_[int]
 var _ = f0_[bool /* ERROR does not satisfy I0_ */ ]
 var _ = f0_[string /* ERROR does not satisfy I0_ */ ]
 var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ]
+
+// Using a function instance as a type is an error.
+var _ f0 // ERROR not a type
+var _ f0 /* ERROR not a type */ [int]
+
+// Empty type sets can only be satisfied by empty type sets.
+type none interface {
+       // force an empty type set
+        int
+        string
+}
+
+func ff[T none]() {}
+func gg[T any]() {}
+func hh[T ~int]() {}
+
+func _[T none]() {
+        _ = ff[int /* ERROR int does not satisfy none \(constraint type set is empty\) */ ]
+        _ = ff[T]  // pathological but ok because T's type set is empty, too
+        _ = gg[int]
+        _ = gg[T]
+       _ = hh[int]
+       _ = hh[T]
+}
diff --git a/src/go/types/testdata/check/typeinstcycles.go2 b/src/go/types/testdata/check/typeinstcycles.go2
new file mode 100644 (file)
index 0000000..74fe191
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "unsafe"
+
+func F1[T any](_ [unsafe.Sizeof(F1[int])]T) (res T)      { return }
+func F2[T any](_ T) (res [unsafe.Sizeof(F2[string])]int) { return }
+func F3[T any](_ [unsafe.Sizeof(F1[string])]int)         {}
index 77cd65d19a8b57b141fccfbd1bbf954d79133747..09d478c4d75a046e65a2cc8db62b306c70e4848f 100644 (file)
@@ -6,18 +6,16 @@ package p
 
 // import "io" // for type assertion tests
 
-// The predeclared identifier "any" can only be used as a constraint
-// in a type parameter list.
-var _ any // ERROR cannot use any outside constraint position
-func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) {
-        var _ any /* ERROR constraint */
+var _ any // ok to use any anywhere
+func _[_ any, _ interface{any}](any) {
+        var _ any
 }
 
 func identity[T any](x T) T { return x }
 
-func _[_ any](x int) int
-func _[T any](T /* ERROR redeclared */ T)()
-func _[T, T /* ERROR redeclared */ any]()
+func _[_ any](x int) int { panic(0) }
+func _[T any](T /* ERROR redeclared */ T)() {}
+func _[T, T /* ERROR redeclared */ any]() {}
 
 // Constraints (incl. any) may be parenthesized.
 func _[_ (any)]() {}
@@ -77,18 +75,18 @@ func new[T any]() *T {
 var _ = new /* ERROR cannot use generic function new */
 var _ *int = new[int]()
 
-func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
+func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) {} // w/o constraint we don't know if T is comparable
 
-func f1[T1 any](struct{T1 /* ERROR cannot be a .* type parameter */ }) int
+func f1[T1 any](struct{T1 /* ERROR cannot be a .* type parameter */ }) int { panic(0) }
 var _ = f1[int](struct{T1}{})
 type T1 = int
 
-func f2[t1 any](struct{t1 /* ERROR cannot be a .* type parameter */ ; x float32}) int
+func f2[t1 any](struct{t1 /* ERROR cannot be a .* type parameter */ ; x float32}) int { panic(0) }
 var _ = f2[t1](struct{t1; x float32}{})
 type t1 = int
 
 
-func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int
+func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int { panic(0) }
 
 var _ = f3[int, rune, bool](1, struct{x rune}{}, nil)
 
@@ -116,10 +114,27 @@ func _[T interface{ [10]int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERR
 func _[T interface{ [10]byte | string }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
 func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
 
+// indexing with strings and non-variable arrays (assignment not permitted)
+func _[T string](x T) { _ = x[0]; x /* ERROR cannot assign */ [0] = 0 }
+func _[T []byte | string](x T) { x /* ERROR cannot assign */ [0] = 0 }
+func _[T [10]byte]() { f := func() (x T) { return }; f /* ERROR cannot assign */ ()[0] = 0 }
+func _[T [10]byte]() { f := func() (x *T) { return }; f /* ERROR cannot index */ ()[0] = 0 }
+func _[T [10]byte]() { f := func() (x *T) { return }; (*f())[0] = 0 }
+func _[T *[10]byte]() { f := func() (x T) { return }; f()[0] = 0 }
+
 // slicing
-// TODO(gri) implement this
 
-func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR generic slice expressions not yet implemented */ [i:j:k] }
+func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j] }
+func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j:k] }
+func _[T interface{ ~[]byte }] (x T, i, j, k int) { var _ T = x[i:j] }
+func _[T interface{ ~[]byte }] (x T, i, j, k int) { var _ T = x[i:j:k] }
+func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x[i:j] }
+func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x /* ERROR 3-index slice of string */ [i:j:k] }
+
+type myByte1 []byte
+type myByte2 []byte
+func _[T interface{ []byte | myByte1 | myByte2 }] (x T, i, j, k int) { var _ T = x[i:j:k] }
+func _[T interface{ []byte | myByte1 | []int }] (x T, i, j, k int) { var _ T = x /* ERROR no single underlying type */ [i:j:k] }
 
 // len/cap built-ins
 
@@ -149,64 +164,136 @@ func _[T interface{}](x T) {
         for range x /* ERROR cannot range */ {}
 }
 
-func _[T interface{ ~string | ~[]string }](x T) {
-        for range x {}
-        for i := range x { _ = i }
-        for i, _ := range x { _ = i }
-        for i, e := range x /* ERROR must have the same element type */ { _ = i }
-        for _, e := range x /* ERROR must have the same element type */ {}
-        var e rune
-        _ = e
-        for _, (e) = range x /* ERROR must have the same element type */ {}
-}
+type myString string
 
+func _[
+        B1 interface{ string },
+        B2 interface{ string | myString },
 
-func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) {
-        for _, e := range x { _ = e }
-        for i, e := range x { _ = i; _ = e }
-}
+        C1 interface{ chan int },
+        C2 interface{ chan int | <-chan int },
+        C3 interface{ chan<- int },
 
-func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) {
-        for _, e := range x { _ = e }
-        for i, e := range x /* ERROR must have the same key type */ { _ = e }
-}
+        S1 interface{ []int },
+        S2 interface{ []int | [10]int },
 
-func _[T interface{ ~string | ~chan int }](x T) {
-        for range x {}
-        for i := range x { _ = i }
-        for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
-}
+        A1 interface{ [10]int },
+        A2 interface{ [10]int | []int },
+
+        P1 interface{ *[10]int },
+        P2 interface{ *[10]int | *[]int },
+
+        M1 interface{ map[string]int },
+        M2 interface{ map[string]int | map[string]string },
+]() {
+        var b0 string
+        for range b0 {}
+        for _ = range b0 {}
+        for _, _ = range b0 {}
+
+        var b1 B1
+        for range b1 {}
+        for _ = range b1 {}
+        for _, _ = range b1 {}
+
+        var b2 B2
+        for range b2 {}
+
+        var c0 chan int
+        for range c0 {}
+        for _ = range c0 {}
+        for _, _ /* ERROR permits only one iteration variable */ = range c0 {}
+
+        var c1 C1
+        for range c1 {}
+        for _ = range c1 {}
+        for _, _ /* ERROR permits only one iteration variable */ = range c1 {}
+
+        var c2 C2
+        for range c2 /* ERROR cannot range over c2.*no single underlying type */ {}
+
+        var c3 C3
+        for range c3 /* ERROR receive from send-only channel */ {}
+
+        var s0 []int
+        for range s0 {}
+        for _ = range s0 {}
+        for _, _ = range s0 {}
+
+        var s1 S1
+        for range s1 {}
+        for _ = range s1 {}
+        for _, _ = range s1 {}
+
+        var s2 S2
+        for range s2 /* ERROR cannot range over s2.*no single underlying type */ {}
 
-func _[T interface{ ~string | ~chan<-int }](x T) {
-        for i := range x /* ERROR send-only channel */ { _ = i }
+        var a0 []int
+        for range a0 {}
+        for _ = range a0 {}
+        for _, _ = range a0 {}
+
+        var a1 A1
+        for range a1 {}
+        for _ = range a1 {}
+        for _, _ = range a1 {}
+
+        var a2 A2
+        for range a2 /* ERROR cannot range over a2.*no single underlying type */ {}
+
+        var p0 *[10]int
+        for range p0 {}
+        for _ = range p0 {}
+        for _, _ = range p0 {}
+
+        var p1 P1
+        for range p1 {}
+        for _ = range p1 {}
+        for _, _ = range p1 {}
+
+        var p2 P2
+        for range p2 /* ERROR cannot range over p2.*no single underlying type */ {}
+
+        var m0 map[string]int
+        for range m0 {}
+        for _ = range m0 {}
+        for _, _ = range m0 {}
+
+        var m1 M1
+        for range m1 {}
+        for _ = range m1 {}
+        for _, _ = range m1 {}
+
+        var m2 M2
+        for range m2 /* ERROR cannot range over m2.*no single underlying type */ {}
 }
 
 // type inference checks
 
 var _ = new /* ERROR cannot infer T */ ()
 
-func f4[A, B, C any](A, B) C
+func f4[A, B, C any](A, B) C { panic(0) }
 
 var _ = f4 /* ERROR cannot infer C */ (1, 2)
 var _ = f4[int, float32, complex128](1, 2)
 
-func f5[A, B, C any](A, []*B, struct{f []C}) int
+func f5[A, B, C any](A, []*B, struct{f []C}) int { panic(0) }
 
 var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{})
 var _ = f5 /* ERROR cannot infer */ (0, nil, struct{f []complex128}{})
 var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{})
 
-func f6[A any](A, []A) int
+func f6[A any](A, []A) int { panic(0) }
 
 var _ = f6(0, nil)
 
-func f6nil[A any](A) int
+func f6nil[A any](A) int { panic(0) }
 
 var _ = f6nil /* ERROR cannot infer */ (nil)
 
 // type inference with variadic functions
 
-func f7[T any](...T) T
+func f7[T any](...T) T { panic(0) }
 
 var _ int = f7 /* ERROR cannot infer T */ ()
 var _ int = f7(1)
@@ -219,7 +306,7 @@ var _ = f7(float64(1), 2.3)
 var _ = f7(1, 2.3 /* ERROR does not match */ )
 var _ = f7(1.2, 3 /* ERROR does not match */ )
 
-func f8[A, B any](A, B, ...B) int
+func f8[A, B any](A, B, ...B) int { panic(0) }
 
 var _ = f8(1) /* ERROR not enough arguments */
 var _ = f8(1, 2.3)
@@ -232,8 +319,8 @@ var _ = f8[int, float64](0, 0, nil...) // test case for #18268
 // init functions cannot have type parameters
 
 func init() {}
-func init[/* ERROR func init must have no type parameters */ _ any]() {}
-func init[/* ERROR func init must have no type parameters */ P any]() {}
+func init[_ /* ERROR func init must have no type parameters */ any]() {}
+func init[P /* ERROR func init must have no type parameters */ any]() {}
 
 type T struct {}
 
@@ -245,7 +332,7 @@ func (T) m3[ /* ERROR methods cannot have type parameters */ P any]() {}
 
 type S1[P any] struct { f P }
 
-func f9[P any](x S1[P])
+func f9[P any](x S1[P]) {}
 
 func _() {
         f9[int](S1[int]{42})
@@ -254,7 +341,7 @@ func _() {
 
 type S2[A, B, C any] struct{}
 
-func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool])
+func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool]) {}
 
 func _[P any]() {
         f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{})
@@ -265,7 +352,7 @@ func _[P any]() {
 // corner case for type inference
 // (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic)
 
-func f11[T any]()
+func f11[T any]() {}
 
 func _() {
        f11[int]()
@@ -273,15 +360,16 @@ func _() {
 
 // the previous example was extracted from
 
-func f12[T interface{m() T}]()
-
-type A[T any] T
-
-func (a A[T]) m() A[T]
-
-func _[T any]() {
-       f12[A[T]]()
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// func f12[T interface{m() T}]() {}
+// 
+// type A[T any] T
+// 
+// func (a A[T]) m() A[T]
+// 
+// func _[T any]() {
+//     f12[A[T]]()
+// }
 
 // method expressions
 
@@ -301,15 +389,15 @@ func _[T any] (x T) {
 
 type R0 struct{}
 
-func (R0) _[ /* ERROR methods cannot have type parameters */ T any](x T)
-func (R0 /* ERROR invalid receiver */ ) _[ /* ERROR methods cannot have type parameters */ R0 any]() // scope of type parameters starts at "func"
+func (R0) _[ /* ERROR methods cannot have type parameters */ T any](x T) {}
+func (R0 /* ERROR invalid receiver */ ) _[ /* ERROR methods cannot have type parameters */ R0 any]() {} // scope of type parameters starts at "func"
 
 type R1[A, B any] struct{}
 
 func (_ R1[A, B]) m0(A, B)
-func (_ R1[A, B]) m1[ /* ERROR methods cannot have type parameters */ T any](A, B, T) T
+func (_ R1[A, B]) m1[ /* ERROR methods cannot have type parameters */ T any](A, B, T) T  { panic(0) }
 func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
-func (_ R1[A, B]) _[ /* ERROR methods cannot have type parameters */ A /* ERROR redeclared */ any](B)
+func (_ R1[A, B]) _[ /* ERROR methods cannot have type parameters */ A /* ERROR redeclared */ any](B) {}
 
 func _() {
         var r R1[int, string]
diff --git a/src/go/types/testdata/check/unions.go2 b/src/go/types/testdata/check/unions.go2
new file mode 100644 (file)
index 0000000..bcd7de6
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2021 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 that overlong unions don't bog down type checking.
+// Disallow them for now.
+
+package p
+
+type t int
+
+type (
+       t00 t; t01 t; t02 t; t03 t; t04 t; t05 t; t06 t; t07 t; t08 t; t09 t
+       t10 t; t11 t; t12 t; t13 t; t14 t; t15 t; t16 t; t17 t; t18 t; t19 t
+       t20 t; t21 t; t22 t; t23 t; t24 t; t25 t; t26 t; t27 t; t28 t; t29 t
+       t30 t; t31 t; t32 t; t33 t; t34 t; t35 t; t36 t; t37 t; t38 t; t39 t
+       t40 t; t41 t; t42 t; t43 t; t44 t; t45 t; t46 t; t47 t; t48 t; t49 t
+       t50 t; t51 t; t52 t; t53 t; t54 t; t55 t; t56 t; t57 t; t58 t; t59 t
+       t60 t; t61 t; t62 t; t63 t; t64 t; t65 t; t66 t; t67 t; t68 t; t69 t
+       t70 t; t71 t; t72 t; t73 t; t74 t; t75 t; t76 t; t77 t; t78 t; t79 t
+       t80 t; t81 t; t82 t; t83 t; t84 t; t85 t; t86 t; t87 t; t88 t; t89 t
+       t90 t; t91 t; t92 t; t93 t; t94 t; t95 t; t96 t; t97 t; t98 t; t99 t
+)
+
+type u99 interface {
+       t00|t01|t02|t03|t04|t05|t06|t07|t08|t09|
+       t10|t11|t12|t13|t14|t15|t16|t17|t18|t19|
+       t20|t21|t22|t23|t24|t25|t26|t27|t28|t29|
+       t30|t31|t32|t33|t34|t35|t36|t37|t38|t39|
+       t40|t41|t42|t43|t44|t45|t46|t47|t48|t49|
+       t50|t51|t52|t53|t54|t55|t56|t57|t58|t59|
+       t60|t61|t62|t63|t64|t65|t66|t67|t68|t69|
+       t70|t71|t72|t73|t74|t75|t76|t77|t78|t79|
+       t80|t81|t82|t83|t84|t85|t86|t87|t88|t89|
+       t90|t91|t92|t93|t94|t95|t96|t97|t98
+}
+
+type u100a interface {
+       u99|float32
+}
+
+type u100b interface {
+       u99|float64
+}
+
+type u101 interface {
+       t00|t01|t02|t03|t04|t05|t06|t07|t08|t09|
+       t10|t11|t12|t13|t14|t15|t16|t17|t18|t19|
+       t20|t21|t22|t23|t24|t25|t26|t27|t28|t29|
+       t30|t31|t32|t33|t34|t35|t36|t37|t38|t39|
+       t40|t41|t42|t43|t44|t45|t46|t47|t48|t49|
+       t50|t51|t52|t53|t54|t55|t56|t57|t58|t59|
+       t60|t61|t62|t63|t64|t65|t66|t67|t68|t69|
+       t70|t71|t72|t73|t74|t75|t76|t77|t78|t79|
+       t80|t81|t82|t83|t84|t85|t86|t87|t88|t89|
+       t90|t91|t92|t93|t94|t95|t96|t97|t98|t99|
+        int // ERROR cannot handle more than 100 union terms
+}
+
+type u102 interface {
+        int /* ERROR cannot handle more than 100 union terms */ |string|u100a
+}
+
+type u200 interface {
+        u100a /* ERROR cannot handle more than 100 union terms */ |u100b
+}
index 28aa19bb12c7c1e93e1d574f604c28a9af304505..4d7f70313a20ae48cf0afea39d9efe88c4f1f4dc 100644 (file)
@@ -6,17 +6,7 @@
 
 package p
 
-type (
-       // Type lists are processed as unions but an error is reported.
-       // TODO(gri) remove this once the parser doesn't accept type lists anymore.
-       _ interface{
-               type /* ERROR use generalized embedding syntax instead of a type list */ int
-       }
-       _ interface{
-               type /* ERROR use generalized embedding syntax instead of a type list */ int
-               type float32
-       }
-)
+type MyInt int
 
 type (
        // Arbitrary types may be embedded like interfaces.
@@ -24,27 +14,41 @@ type (
        _ interface{~int}
 
        // Types may be combined into a union.
-       _ interface{int|~string}
+       union interface{int|~string}
 
-       // Union terms must be unique independent of whether they are ~ or not.
-       _ interface{int|int /* ERROR duplicate term int */ }
-       _ interface{int|~ /* ERROR duplicate term int */ int }
-       _ interface{~int|~ /* ERROR duplicate term int */ int }
+       // Union terms must describe disjoint (non-overlapping) type sets.
+       _ interface{int|int /* ERROR overlapping terms int */ }
+       _ interface{int|~ /* ERROR overlapping terms ~int */ int }
+       _ interface{~int|~ /* ERROR overlapping terms ~int */ int }
+       _ interface{~int|MyInt /* ERROR overlapping terms p.MyInt and ~int */ }
+       _ interface{int|any}
+       _ interface{int|~string|union}
+       _ interface{int|~string|interface{int}}
+       _ interface{union|union /* ERROR overlapping terms p.union and p.union */ }
 
        // For now we do not permit interfaces with methods in unions.
-       _ interface{~ /* ERROR invalid use of ~ */ interface{}}
+       _ interface{~ /* ERROR invalid use of ~ */ any}
        _ interface{int|interface /* ERROR cannot use .* in union */ { m() }}
 )
 
 type (
        // Tilde is not permitted on defined types or interfaces.
        foo int
-       bar interface{}
+       bar any
        _ interface{foo}
        _ interface{~ /* ERROR invalid use of ~ */ foo }
        _ interface{~ /* ERROR invalid use of ~ */ bar }
 )
 
+// Stand-alone type parameters are not permitted as elements or terms in unions.
+type (
+       _[T interface{ *T } ] struct{}        // ok
+       _[T interface{ int | *T } ] struct{}  // ok
+       _[T interface{ T /* ERROR cannot embed a type parameter */ } ] struct{}
+       _[T interface{ ~T /* ERROR cannot embed a type parameter */ } ] struct{}
+       _[T interface{ int|T /* ERROR cannot embed a type parameter */ }] struct{}
+)
+
 // Multiple embedded union elements are intersected. The order in which they
 // appear in the interface doesn't matter since intersection is a symmetric
 // operation.
@@ -58,3 +62,18 @@ func _[T interface{ ~int; myInt1|myInt2 }]() T { return T(0) }
 // Here the intersections are empty - there's no type that's in the type set of T.
 func _[T interface{ myInt1|myInt2; int }]() T { return T(0 /* ERROR cannot convert */ ) }
 func _[T interface{ int; myInt1|myInt2 }]() T { return T(0 /* ERROR cannot convert */ ) }
+
+// Union elements may be interfaces as long as they don't define
+// any methods or embed comparable.
+
+type (
+       Integer interface{ ~int|~int8|~int16|~int32|~int64 }
+       Unsigned interface{ ~uint|~uint8|~uint16|~uint32|~uint64 }
+       Floats interface{ ~float32|~float64 }
+       Complex interface{ ~complex64|~complex128 }
+       Number interface{ Integer|Unsigned|Floats|Complex }
+       Ordered interface{ Integer|Unsigned|Floats|~string }
+
+       _ interface{ Number | error /* ERROR cannot use error in union */ }
+       _ interface{ Ordered | comparable /* ERROR cannot use comparable in union */ }
+)
index 81b9d3456c829edf2671e260be4062c6f2cdc0af..0af77267c5f56f9db551ac9fc838f5958dbe6fcb 100644 (file)
@@ -66,7 +66,7 @@ var _ float64 = foo(42, []float64{1.0}, &s)
 
 // Type inference works in a straight-forward manner even
 // for variadic functions.
-func variadic[A, B any](A, B, ...B) int
+func variadic[A, B any](A, B, ...B) int { panic(0) }
 
 // var _ = variadic(1) // ERROR not enough arguments
 var _ = variadic(1, 2.3)
@@ -118,9 +118,9 @@ func max[T interface{ ~int }](x ...T) T {
 // Thus even if a type can be inferred successfully, the function
 // call may not be valid.
 
-func fboth[T any](chan T)
-func frecv[T any](<-chan T)
-func fsend[T any](chan<- T)
+func fboth[T any](chan T) {}
+func frecv[T any](<-chan T) {}
+func fsend[T any](chan<- T) {}
 
 func _() {
        var both chan int
@@ -140,9 +140,9 @@ func _() {
        fsend(send)
 }
 
-func ffboth[T any](func(chan T))
-func ffrecv[T any](func(<-chan T))
-func ffsend[T any](func(chan<- T))
+func ffboth[T any](func(chan T)) {}
+func ffrecv[T any](func(<-chan T)) {}
+func ffsend[T any](func(chan<- T)) {}
 
 func _() {
        var both func(chan int)
@@ -169,9 +169,9 @@ func _() {
 // assignment is permitted, parameter passing is permitted as well,
 // so type inference should be able to handle these cases well.
 
-func g1[T any]([]T)
-func g2[T any]([]T, T)
-func g3[T any](*T, ...T)
+func g1[T any]([]T) {}
+func g2[T any]([]T, T) {}
+func g3[T any](*T, ...T) {}
 
 func _() {
        type intSlize []int
@@ -194,7 +194,7 @@ func _() {
 
 // Here's a realistic example.
 
-func append[T any](s []T, t ...T) []T
+func append[T any](s []T, t ...T) []T { panic(0) }
 
 func _() {
        var f func()
@@ -207,8 +207,12 @@ func _() {
 // (that would indicate a slice type). Thus, generic functions cannot
 // have empty type parameter lists, either. This is a syntax error.
 
-func h[] /* ERROR empty type parameter list */ ()
+func h[] /* ERROR empty type parameter list */ () {}
 
 func _() {
        h /* ERROR cannot index */ [] /* ERROR operand */ ()
 }
+
+// Parameterized functions must have a function body.
+
+func _ /* ERROR missing function body */ [P any]()
index 1142e569b47c099e57195a973b90a352531dcd80..73246b0137a64fdcdf79d8a729f042b328f39f81 100644 (file)
@@ -10,7 +10,7 @@ type Ordered interface {
        ~int|~float64|~string
 }
 
-func min[T Ordered](x, y T) T
+func min[T Ordered](x, y T) T { panic(0) }
 
 func _() {
        // min can be called with explicit instantiation.
@@ -37,7 +37,7 @@ func _() {
        _ = min("foo", "bar")
 }
 
-func mixed[T1, T2, T3 any](T1, T2, T3)
+func mixed[T1, T2, T3 any](T1, T2, T3) {}
 
 func _() {
        // mixed can be called with explicit instantiation.
@@ -54,7 +54,7 @@ func _() {
        mixed[int, string](1.1 /* ERROR cannot use 1.1 */ , "", false)
 }
 
-func related1[Slice interface{~[]Elem}, Elem any](s Slice, e Elem)
+func related1[Slice interface{~[]Elem}, Elem any](s Slice, e Elem) {}
 
 func _() {
        // related1 can be called with explicit instantiation.
@@ -78,7 +78,7 @@ func _() {
        related1(si, "foo" /* ERROR cannot use "foo" */ )
 }
 
-func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice)
+func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) {}
 
 func _() {
        // related2 can be called with explicit instantiation.
@@ -99,3 +99,26 @@ func _() {
        related2(1.0, []int{})
        related2 /* ERROR does not satisfy */ (float64(1.0), []int{})
 }
+
+type List[P any] []P
+
+func related3[Elem any, Slice []Elem | List[Elem]]() Slice { return nil }
+
+func _() {
+       // related3 can be instantiated explicitly
+       related3[int, []int]()
+       related3[byte, List[byte]]()
+
+       // Alternatively, the 2nd type argument can be inferred
+       // from the first one through constraint type inference.
+       related3[int]()
+
+       // The inferred type is the structural type of the Slice
+       // type parameter.
+       var _ []int = related3[int]()
+
+       // It is not the defined parameterized type List.
+       type anotherList []float32
+       var _ anotherList = related3[float32]() // valid
+       var _ anotherList = related3 /* ERROR cannot use .* \(value of type List\[float32\]\) as anotherList */ [float32, List[float32]]()
+}
index 4e87041e54771391056937e8b8e5424df025f5c5..1d76d553dcc44a1b57f2f983edefa404c39ab534 100644 (file)
@@ -6,8 +6,6 @@
 
 package p
 
-import "unsafe"
-
 // Parameterized types may have methods.
 type T1[A any] struct{ a A }
 
@@ -97,17 +95,18 @@ type T0 struct{}
 func (T0) _() {}
 func (T1[A]) _() {}
 
-// A generic receiver type may constrain its type parameter such
-// that it must be a pointer type. Such receiver types are not
-// permitted.
-type T3a[P interface{ ~int | ~string | ~float64 }] P
-
-func (T3a[_]) m() {} // this is ok
-
-type T3b[P interface{ ~unsafe.Pointer }] P
-
-func (T3b /* ERROR invalid receiver */ [_]) m() {}
-
-type T3c[P interface{ *int | *string }] P
-
-func (T3c /* ERROR invalid receiver */ [_]) m() {}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // A generic receiver type may constrain its type parameter such
+// // that it must be a pointer type. Such receiver types are not
+// // permitted.
+// type T3a[P interface{ ~int | ~string | ~float64 }] P
+// 
+// func (T3a[_]) m() {} // this is ok
+// 
+// type T3b[P interface{ ~unsafe.Pointer }] P
+// 
+// func (T3b /* ERROR invalid receiver */ [_]) m() {}
+// 
+// type T3c[P interface{ *int | *string }] P
+// 
+// func (T3c /* ERROR invalid receiver */ [_]) m() {}
index a7544f79ea0b005a39b6b16c5671ba0ffb65b78f..33642fa42fd071cf8a181b0d308423e11bf4fec9 100644 (file)
@@ -102,6 +102,7 @@ func _() {
 
 // Generic types cannot be used without instantiation.
 var _ T // ERROR cannot use generic type T
+var _ = T /* ERROR cannot use generic type T */ (0)
 
 // In type context, generic (parameterized) types cannot be parenthesized before
 // being instantiated. See also NOTES entry from 12/4/2019.
@@ -113,7 +114,7 @@ type I1[T any] interface{
 }
 
 // There is no such thing as a variadic generic type.
-type _[T ... /* ERROR invalid use of ... */ interface{}] struct{}
+type _[T ... /* ERROR invalid use of ... */ any] struct{}
 
 // Generic interfaces may be embedded as one would expect.
 type I2 interface {
@@ -190,12 +191,13 @@ type _ struct {
 //     _ = y < 0
 //}
 
-// It is not permitted to declare a local type whose underlying
-// type is a type parameters not declared by that type declaration.
-func _[T any]() {
-       type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
-       type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // It is not permitted to declare a local type whose underlying
+// // type is a type parameter not declared by that type declaration.
+// func _[T any]() {
+//     type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
+//     type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
+// }
 
 // As a special case, an explicit type argument may be omitted
 // from a type parameter bound if the type bound expects exactly
@@ -218,19 +220,19 @@ func Sum[T Adder[T]](list []T) T {
 }
 
 // Valid and invalid variations.
-type B0 interface {}
-type B1[_ any] interface{}
-type B2[_, _ any] interface{}
+type B0 any
+type B1[_ any] any
+type B2[_, _ any] any
 
-func _[T1 B0]()
-func _[T1 B1[T1]]()
-func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
+func _[T1 B0]() {}
+func _[T1 B1[T1]]() {}
+func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() {}
 
-func _[T1, T2 B0]()
-func _[T1 B1[T1], T2 B1[T2]]()
-func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
+func _[T1, T2 B0]() {}
+func _[T1 B1[T1], T2 B1[T2]]() {}
+func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() {}
 
-func _[T1 B0, T2 B1[T2]]() // here B1 applies to T2
+func _[T1 B0, T2 B1[T2]]() {} // here B1 applies to T2
 
 // When the type argument is left away, the type bound is
 // instantiated for each type parameter with that type
@@ -280,8 +282,8 @@ func _() {
 
 // Type parameters are never const types, i.e., it's
 // not possible to declare a constant of type parameter type.
-// (If a type list contains just a single const type, we could
-// allow it, but such type lists don't make much sense in the
+// (If a type set contains just a single const type, we could
+// allow it, but such type sets don't make much sense in the
 // first place.)
 func _[T interface {~int|~float64}]() {
        // not valid
@@ -294,3 +296,26 @@ func _[T interface {~int|~float64}]() {
        _ = T(0)
 }
 
+// It is possible to create composite literals of type parameter
+// type as long as it's possible to create a composite literal
+// of the structural type of the type parameter's constraint.
+func _[P interface{ ~[]int }]() P {
+       return P{}
+       return P{1, 2, 3}
+}
+
+func _[P interface{ ~[]E }, E interface{ map[string]P } ]() P {
+       x := P{}
+       return P{{}}
+       return P{E{}}
+       return P{E{"foo": x}}
+       return P{{"foo": x}, {}}
+}
+
+// This is a degenerate case with a singleton type set, but we can create
+// composite literals even if the structural type is a defined type.
+type MyInts []int
+
+func _[P MyInts]() P {
+       return P{}
+}
diff --git a/src/go/types/testdata/examples/typesets.go2 b/src/go/types/testdata/examples/typesets.go2
new file mode 100644 (file)
index 0000000..cf01072
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file shows some examples of constraint literals with elided interfaces.
+// These examples are permitted if proposal issue #48424 is accepted.
+
+package p
+
+// Constraint type sets of the form T, ~T, or A|B may omit the interface.
+type (
+       _[T int] struct{}
+       _[T ~int] struct{}
+       _[T int|string] struct{}
+       _[T ~int|~string] struct{}
+)
+
+func min[T int|string](x, y T) T {
+       if x < y {
+               return x
+       }
+       return y
+}
+
+func lookup[M ~map[K]V, K comparable, V any](m M, k K) V {
+       return m[k]
+}
+
+func deref[P ~*E, E any](p P) E {
+       return *p
+}
+
+func _() int {
+       p := new(int)
+       return deref(p)
+}
+
+func addrOfCopy[V any, P ~*V](v V) P {
+       return &v
+}
+
+func _() *int {
+       return addrOfCopy(0)
+}
+
+// A type parameter may not be embedded in an interface;
+// so it can also not be used as a constraint.
+func _[A any, B A /* ERROR cannot use a type parameter as constraint */ ]() {}
+
+// Error messages refer to the type constraint as it appears in the source.
+// (No implicit interface should be exposed.)
+func _[T string](x T) T {
+       return x /* ERROR constrained by string */ * x
+}
+
+func _[T int|string](x T) T {
+       return x /* ERROR constrained by int|string */ * x
+}
index aec404e294be3bb1bfc28675b9dece84497f3f32..2de2f4378aac0a8206b0ec2d99fd8eab719bbc26 100644 (file)
@@ -37,8 +37,8 @@ func main7() { var _ foo7 = x7[int]{} }
 // func main8() {}
 
 // crash 9
-type foo9[A any] interface { foo9 /* ERROR illegal cycle */ [A] }
-func _() { var _ = new(foo9 /* ERROR illegal cycle */ [int]) }
+type foo9 /* ERROR illegal cycle */ [A any] interface { foo9[A] }
+func _() { var _ = new(foo9[int]) }
 
 // crash 12
 var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len /* ERROR must be called */ /* ERROR must be called */ )]c /* ERROR undeclared */ /* ERROR undeclared */
@@ -50,7 +50,7 @@ func (G15 /* ERROR generic type .* without instantiation */ ) p()
 
 // crash 16
 type Foo16[T any] r16 /* ERROR not a type */
-func r16[T any]() Foo16[Foo16[T]]
+func r16[T any]() Foo16[Foo16[T]] { panic(0) }
 
 // crash 17
 type Y17 interface{ c() }
@@ -58,7 +58,7 @@ type Z17 interface {
        c() Y17
        Y17 /* ERROR duplicate method */
 }
-func F17[T Z17](T)
+func F17[T Z17](T) {}
 
 // crash 18
 type o18[T any] []func(_ o18[[]_ /* ERROR cannot use _ */ ])
@@ -74,9 +74,10 @@ func F20[t Z20]() { F20(t /* ERROR invalid composite literal type */ {}) }
 type Z21 /* ERROR illegal cycle */ interface{ Z21 }
 func F21[T Z21]() { ( /* ERROR not used */ F21[Z21]) }
 
-// crash 24
-type T24[P any] P
-func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // crash 24
+// type T24[P any] P
+// func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }
 
 // crash 25
 type T25[A any] int
@@ -85,8 +86,11 @@ var x T25 /* ERROR without instantiation */ .m1
 
 // crash 26
 type T26 = interface{ F26[ /* ERROR methods cannot have type parameters */ Z any]() }
+// The error messages on the line below differ from types2 because for backward
+// compatibility go/parser must produce an IndexExpr with BadExpr index for the
+// expression F26[].
 func F26[Z any]() T26 { return F26[] /* ERROR operand */ }
 
 // crash 27
-func e27[T any]() interface{ x27 /* ERROR not a type */ }
+func e27[T any]() interface{ x27 /* ERROR not a type */ } { panic(0) }
 func x27() { e27 /* ERROR cannot infer T */ () }
index cf1f90545f6e8026fa53529db85ff47334117277..d85fa03fc433bc77d34c4e16f4fbb923cfee8d32 100644 (file)
@@ -4,10 +4,10 @@
 
 package p
 
-// Do not report a duplicate type error for this type list.
+// Do not report a duplicate type error for this term list.
 // (Check types after interfaces have been completed.)
 type _ interface {
        // TODO(rfindley) Once we have full type sets we can enable this again.
-       // Fow now we don't permit interfaces in type lists.
+       // Fow now we don't permit interfaces in term lists.
        // type interface{ Error() string }, interface{ String() string }
 }
index 367b3f1360f3cfdb82736edd00a7ac1cd7f27025..00885238e69c9a26ce5ef6f44539c0cba86152b1 100644 (file)
@@ -6,4 +6,4 @@ package p
 
 // A constraint must be an interface; it cannot
 // be a type parameter, for instance.
-func _[A interface{ ~int }, B A /* ERROR not an interface */ ]()
+func _[A interface{ ~int }, B A /* ERROR cannot use a type parameter as constraint */ ]() {}
index e19b6770bfe4bd21462434f97ace29659a02c4ed..62dc45a59601eecc43e0b23fd09123cf00fbf57d 100644 (file)
@@ -4,13 +4,13 @@
 
 package p
 
-func f1[T1, T2 any](T1, T2, struct{a T1; b T2})
+func f1[T1, T2 any](T1, T2, struct{a T1; b T2}) {}
 func _() {
        f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{})
 }
 
 // simplified test case from issue
-func f2[T any](_ []T, _ func(T))
+func f2[T any](_ []T, _ func(T)) {}
 func _() {
        f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {})
 }
index abac141d7f08dd359a26ba18c36b696d7970d40a..696d9d9beef9d2f9961456e1ddf3ed6f31c51889 100644 (file)
@@ -4,17 +4,18 @@
 
 package p
 
-type T[P any] P
-type A = T
-var x A[int]
-var _ A /* ERROR cannot use generic type */
-
-type B = T[int]
-var y B = x
-var _ B /* ERROR not a generic type */ [int]
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type T[P any] P
+// type A = T  // ERROR cannot use generic type
+// var x A[int]
+// var _ A
+//
+// type B = T[int]
+// var y B = x
+// var _ B /* ERROR not a generic type */ [int]
 
 // test case from issue
 
 type Vector[T any] []T
-type VectorAlias = Vector
+type VectorAlias = Vector // ERROR cannot use generic type
 var v Vector[int]
index 0da6e103fd1139b48d6d26e6d9b9ec9cee7ac5db..114646786d5b74324413b74cbbca0c211f3c6cb2 100644 (file)
@@ -3,19 +3,21 @@
 // license that can be found in the LICENSE file.
 
 // Check "infinite expansion" cycle errors across instantiated types.
+// We can't detect these errors anymore at the moment. See #48962 for
+// details.
 
 package p
 
-type E0[P any] P
+type E0[P any] []P
 type E1[P any] *P
 type E2[P any] struct{ _ P }
 type E3[P any] struct{ _ *P }
 
-type T0 /* ERROR illegal cycle */ struct {
+type T0 /* illegal cycle */ struct {
         _ E0[T0]
 }
 
-type T0_ /* ERROR illegal cycle */ struct {
+type T0_ /* illegal cycle */ struct {
         E0[T0_]
 }
 
@@ -23,7 +25,7 @@ type T1 struct {
         _ E1[T1]
 }
 
-type T2 /* ERROR illegal cycle */ struct {
+type T2 /* illegal cycle */ struct {
         _ E2[T2]
 }
 
@@ -33,7 +35,7 @@ type T3 struct {
 
 // some more complex cases
 
-type T4 /* ERROR illegal cycle */ struct {
+type T4 /* illegal cycle */ struct {
        _ E0[E2[T4]]
 }
 
@@ -41,7 +43,7 @@ type T5 struct {
        _ E0[E2[E0[E1[E2[[10]T5]]]]]
 }
 
-type T6 /* ERROR illegal cycle */ struct {
+type T6 /* illegal cycle */ struct {
        _ E0[[10]E2[E0[E2[E2[T6]]]]]
 }
 
index 3db4eae0123930db81b5ff193e58ff802678878a..d703da90a2176a3e975f5a62cad5cf5b3f665faf 100644 (file)
@@ -7,7 +7,7 @@ package p
 type policy[K, V any] interface{}
 type LRU[K, V any] struct{}
 
-func NewCache[K, V any](p policy[K, V])
+func NewCache[K, V any](p policy[K, V]) {}
 
 func _() {
        var lru LRU[int, string]
index 8948d61caa477fff40ac7f773946d0377df734e4..5f81fcbfaa7236bfcdd58114ac74847f9e709555 100644 (file)
@@ -8,8 +8,8 @@ type A[T any] int
 
 func (A[T]) m(A[T])
 
-func f[P interface{m(P)}]()
+func f[P interface{m(P)}]() {}
 
 func _() {
        _ = f[A[int]]
-}
\ No newline at end of file
+}
index f587691e3d746a58bc22a2bfd6d9382230859d3c..66130c0a558ebaef7ec875d3072a818a65b16ff3 100644 (file)
@@ -10,6 +10,6 @@ func _() {
 
 type S struct {}
 
-func NewS[T any]() *S
+func NewS[T any]() *S { panic(0) }
 
 func (_ *S /* ERROR S is not a generic type */ [T]) M()
index 0269c3a62ce6d0d10d92f0f2cb4e0ce8e82129cf..63a058d039d93448f745ec2ecc1d091dae93da13 100644 (file)
@@ -6,10 +6,10 @@ package p
 
 type T[_ any] int
 
-func f[_ any]()
-func g[_, _ any]()
+func f[_ any]() {}
+func g[_, _ any]() {}
 
 func _() {
        _ = f[T /* ERROR without instantiation */ ]
        _ = g[T /* ERROR without instantiation */ , T /* ERROR without instantiation */ ]
-}
\ No newline at end of file
+}
index ab535049dd7e58485e118e62a7ffbe336b6d8318..7f55ba85a6b42d4580a030337e5bba3e1da71713 100644 (file)
@@ -6,13 +6,13 @@ package p
 
 // Test case from issue.
 
-type Nat interface {
+type Nat /* ERROR cycle */ interface {
        Zero|Succ
 }
 
 type Zero struct{}
 type Succ struct{
-       Nat // ERROR interface contains type constraints
+       Nat // Nat contains type constraints but is invalid, so no error
 }
 
 // Struct tests.
@@ -47,7 +47,7 @@ type _ struct{
 }
 
 type _ struct{
-       I3 // ERROR interface contains type constraints
+       I3 // ERROR interface is .* comparable
 }
 
 // General composite types.
@@ -59,19 +59,19 @@ type (
        _ []I1 // ERROR interface is .* comparable
        _ []I2 // ERROR interface contains type constraints
 
-       _ *I3 // ERROR interface contains type constraints
+       _ *I3 // ERROR interface is .* comparable
        _ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints
-       _ chan I3 // ERROR interface contains type constraints
+       _ chan I3 // ERROR interface is .* comparable
        _ func(I1 /* ERROR interface is .* comparable */ )
        _ func() I2 // ERROR interface contains type constraints
 )
 
 // Other cases.
 
-var _ = [...]I3 /* ERROR interface contains type constraints */ {}
+var _ = [...]I3 /* ERROR interface is .* comparable */ {}
 
 func _(x interface{}) {
-       _ = x.(I3 /* ERROR interface contains type constraints */ )
+       _ = x.(I3 /* ERROR interface is .* comparable */ )
 }
 
 type T1[_ any] struct{}
@@ -79,9 +79,9 @@ type T3[_, _, _ any] struct{}
 var _ T1[I2 /* ERROR interface contains type constraints */ ]
 var _ T3[int, I2 /* ERROR interface contains type constraints */ , float32]
 
-func f1[_ any]() int
+func f1[_ any]() int { panic(0) }
 var _ = f1[I2 /* ERROR interface contains type constraints */ ]()
-func f3[_, _, _ any]() int
+func f3[_, _, _ any]() int { panic(0) }
 var _ = f3[int, I2 /* ERROR interface contains type constraints */ , float32]()
 
 func _(x interface{}) {
index bf0031f5d244305720afb8c8d2f2710c5b8bbaf9..dd66e9648b56326f364b4ade15b459a506a5bb9d 100644 (file)
@@ -28,6 +28,6 @@ func _[T constraint](x interface{}){
 }
 
 func _(x constraint /* ERROR contains type constraints */ ) {
-       switch x /* ERROR contains type constraints */ .(type) {
+       switch x.(type) { // no need to report another error
        }
 }
diff --git a/src/go/types/testdata/fixedbugs/issue43527.go2 b/src/go/types/testdata/fixedbugs/issue43527.go2
new file mode 100644 (file)
index 0000000..e4bcee5
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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
+
+const L = 10
+
+type (
+       _        [L]struct{}
+       _        [A /* ERROR undeclared name A for array length */ ]struct{}
+       _        [B /* ERROR not an expression */ ]struct{}
+       _[A any] struct{}
+
+       B int
+)
diff --git a/src/go/types/testdata/fixedbugs/issue45550.go2 b/src/go/types/testdata/fixedbugs/issue45550.go2
new file mode 100644 (file)
index 0000000..c3e9e34
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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 Builder[T interface{ struct{ Builder[T] } }] struct{}
+type myBuilder struct {
+       Builder[myBuilder /* ERROR myBuilder does not satisfy */]
+}
index 441fb4cb346211c684e0a9e51247102b89ed7048..80148fe4819862f4761eb439da062e735204aa20 100644 (file)
@@ -4,9 +4,10 @@
 
 package P
 
-// It is not permitted to declare a local type whose underlying
-// type is a type parameters not declared by that type declaration.
-func _[T any]() {
-       type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
-       type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // It is not permitted to declare a local type whose underlying
+// // type is a type parameters not declared by that type declaration.
+// func _[T any]() {
+//     type _ T         // ERROR cannot use function type parameter T as RHS in type declaration
+//     type _ [_ any] T // ERROR cannot use function type parameter T as RHS in type declaration
+// }
index 6e42dbb633969bf92e3df7e0ce084c4de103b7b3..637e2cad5e05e0f42513b790c7f150329c934191 100644 (file)
@@ -5,7 +5,7 @@
 package issue45985
 
 // TODO(rFindley): this error should be on app[int] below.
-func app[S /* ERROR "type S = S does not match" */ interface{ ~[]T }, T any](s S, e T) S {
+func app[S /* ERROR "S does not match" */ interface{ ~[]T }, T any](s S, e T) S {
     return append(s, e)
 }
 
diff --git a/src/go/types/testdata/fixedbugs/issue46461.go2 b/src/go/types/testdata/fixedbugs/issue46461.go2
new file mode 100644 (file)
index 0000000..8bf3109
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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
+
+// test case 1
+type T[U interface{ M() T[U] }] int
+
+type X int
+
+func (X) M() T[X] { return 0 }
+
+// test case 2
+type A[T interface{ A[T] }] interface{}
+
+// test case 3
+type A2[U interface{ A2[U] }] interface{ M() A2[U] }
+
+type I interface{ A2[I]; M() A2[I] }
index 387c946957cd0436f5c9a39b6f4fe9d64d0c5355..108d600a38a6c9ce9075ca792ab7abf4077f1d8e 100644 (file)
@@ -30,8 +30,8 @@ func _[P any]() {
         )
 }
 
-func _[P any, Q interface{ *P | []P | chan P | map[string]P }]()
-func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]()
-func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]()
-func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]()
-func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]()
+func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() {}
+func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() {}
+func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() {}
+func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() {}
+func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() {}
index 7326205863ffb3787094d119457efb79dbdf65d1..fde704bb416d45fa1293d3d8efbc0e75fb64079c 100644 (file)
@@ -4,8 +4,8 @@
 
 package p
 
-func f[_ comparable]()
-func g[_ interface{interface{comparable; ~int|~string}}]()
+func f[_ comparable]() {}
+func g[_ interface{interface{comparable; ~int|~string}}]() {}
 
 func _[P comparable,
         Q interface{ comparable; ~int|~string },
@@ -19,7 +19,7 @@ func _[P comparable,
         _ = f[R /* ERROR R has no constraints */ ]
 
         _ = g[int]
-        _ = g[P /* ERROR P has no type constraints */ ]
+       _ = g[P /* ERROR P does not satisfy interface{interface{comparable; ~int\|~string} */ ]
         _ = g[Q]
         _ = g[func /* ERROR does not satisfy comparable */()]
         _ = g[R /* ERROR R has no constraints */ ]
diff --git a/src/go/types/testdata/fixedbugs/issue47747.go2 b/src/go/types/testdata/fixedbugs/issue47747.go2
new file mode 100644 (file)
index 0000000..6a2e787
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2021 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
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type T1[P any] P
+// 
+// func (T1[_]) m() {}
+// 
+// func _[P any](x *T1[P]) {
+//         // x.m exists because x is of type *T1 where T1 is a defined type
+//         // (even though under(T1) is a type parameter)
+//         x.m()
+// }
+
+
+func _[P interface{ m() }](x P) {
+        x.m()
+        // (&x).m doesn't exist because &x is of type *P
+        // and pointers to type parameters don't have methods
+        (&x).m /* ERROR \*P has no field or method m */ ()
+}
+
+
+type T2 interface{ m() }
+
+func _(x *T2) {
+        // x.m doesn't exists because x is of type *T2
+        // and pointers to interfaces don't have methods
+        x.m /* ERROR \*T2 has no field or method m */()
+}
+
+// Test case 1 from issue
+
+type Fooer1[t any] interface {
+       Foo(Barer[t])
+}
+type Barer[t any] interface {
+       Bar(t)
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Foo1[t any] t
+// type Bar[t any] t
+// 
+// func (l Foo1[t]) Foo(v Barer[t]) { v.Bar(t(l)) }
+// func (b *Bar[t]) Bar(l t)        { *b = Bar[t](l) }
+// 
+// func _[t any](f Fooer1[t]) t {
+//     var b Bar[t]
+//     f.Foo(&b)
+//     return t(b)
+// }
+
+// Test case 2 from issue
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Fooer2[t any] interface {
+//     Foo()
+// }
+// 
+// type Foo2[t any] t
+// 
+// func (f *Foo2[t]) Foo() {}
+// 
+// func _[t any](v t) {
+//     var f = Foo2[t](v)
+//     _ = Fooer2[t](&f)
+// }
diff --git a/src/go/types/testdata/fixedbugs/issue47796.go2 b/src/go/types/testdata/fixedbugs/issue47796.go2
new file mode 100644 (file)
index 0000000..9c10683
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2021 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
+
+// parameterized types with self-recursive constraints
+type (
+       T1[P T1[P]]                            interface{}
+       T2[P, Q T2[P, Q]]                      interface{}
+       T3[P T2[P, Q], Q interface{ ~string }] interface{}
+
+       T4a[P T4a[P]]                                                        interface{ ~int }
+       T4b[P T4b[int]]                                                      interface{ ~int }
+       T4c[P T4c[string /* ERROR string does not satisfy T4c\[string\] */]] interface{ ~int }
+
+       // mutually recursive constraints
+       T5[P T6[P]] interface{ int }
+       T6[P T5[P]] interface{ int }
+)
+
+// verify that constraints are checked as expected
+var (
+       _ T1[int]
+       _ T2[int, string]
+       _ T3[int, string]
+)
+
+// test case from issue
+
+type Eq[a Eq[a]] interface {
+       Equal(that a) bool
+}
diff --git a/src/go/types/testdata/fixedbugs/issue47818.go2 b/src/go/types/testdata/fixedbugs/issue47818.go2
new file mode 100644 (file)
index 0000000..e3e5a99
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2021 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.
+
+// Parser accepts type parameters but the type checker
+// needs to report any operations that are not permitted
+// before Go 1.18.
+
+package go1_17
+
+type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}
+
+// for init (and main, but we're not in package main) we should only get one error
+func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]()   {}
+func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
+
+func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
+       var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
+       var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
+       _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
+       _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int](struct{}{})
+}
+
+func (T[ /* ERROR type instantiation requires go1\.18 or later */ P]) g(x int) {
+       f[ /* ERROR function instantiation requires go1\.18 or later */ int](0)     // explicit instantiation
+       (f[ /* ERROR function instantiation requires go1\.18 or later */ int])(0)   // parentheses (different code path)
+       f( /* ERROR implicit function instantiation requires go1\.18 or later */ x) // implicit instantiation
+}
+
+type C1 interface {
+       comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+}
+
+type C2 interface {
+       comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+       int        // ERROR embedding non-interface type int requires go1\.18 or later
+       ~ /* ERROR embedding interface element ~int requires go1\.18 or later */ int
+       int /* ERROR embedding interface element int\|~string requires go1\.18 or later */ | ~string
+}
+
+type _ interface {
+       // errors for these were reported with their declaration
+       C1
+       C2
+}
+
+type (
+       _ comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+       // errors for these were reported with their declaration
+       _ C1
+       _ C2
+
+       _ = comparable // ERROR undeclared name: comparable \(requires version go1\.18 or later\)
+       // errors for these were reported with their declaration
+       _ = C1
+       _ = C2
+)
+
+// TODO(gri) need test cases for imported constraint types (see also issue #47967)
diff --git a/src/go/types/testdata/fixedbugs/issue47887.go2 b/src/go/types/testdata/fixedbugs/issue47887.go2
new file mode 100644 (file)
index 0000000..4c4fc2f
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2021 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 Fooer[t any] interface {
+       foo(Barer[t])
+}
+type Barer[t any] interface {
+       bar(Bazer[t])
+}
+type Bazer[t any] interface {
+       Fooer[t]
+       baz(t)
+}
+
+type Int int
+
+func (n Int) baz(int) {}
+func (n Int) foo(b Barer[int]) { b.bar(n) }
+
+type F[t any] interface { f(G[t]) }
+type G[t any] interface { g(H[t]) }
+type H[t any] interface { F[t] }
+
+type T struct{}
+func (n T) f(b G[T]) { b.g(n) }
diff --git a/src/go/types/testdata/fixedbugs/issue47968.go2 b/src/go/types/testdata/fixedbugs/issue47968.go2
new file mode 100644 (file)
index 0000000..711e50a
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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[P any] struct{}
+
+func (T[P]) m1()
+
+type A1 = T // ERROR cannot use generic type
+
+func (A1[P]) m2() {}
+
+type A2 = T[int]
+
+func (A2 /* ERROR cannot define methods on instantiated type T\[int\] */) m3()   {}
+func (_ /* ERROR cannot define methods on instantiated type T\[int\] */ A2) m4() {}
+
+func (T[int]) m5()                                     {} // int is the type parameter name, not an instantiation
+func (T[* /* ERROR must be an identifier */ int]) m6() {} // syntax error
diff --git a/src/go/types/testdata/fixedbugs/issue48008.go2 b/src/go/types/testdata/fixedbugs/issue48008.go2
new file mode 100644 (file)
index 0000000..5c97268
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2021 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[P any] struct{}
+
+func _(x interface{}) {
+       switch x.(type) {
+       case nil:
+       case int:
+
+       case T[int]:
+       case []T[int]:
+       case [10]T[int]:
+       case struct{T[int]}:
+       case *T[int]:
+       case func(T[int]):
+       case interface{m(T[int])}:
+       case map[T[int]] string:
+       case chan T[int]:
+
+       case T /* ERROR cannot use generic type T\[P interface{}\] without instantiation */ :
+       case []T /* ERROR cannot use generic type */ :
+       case [10]T /* ERROR cannot use generic type */ :
+       case struct{T /* ERROR cannot use generic type */ }:
+       case *T /* ERROR cannot use generic type */ :
+       case func(T /* ERROR cannot use generic type */ ):
+       case interface{m(T /* ERROR cannot use generic type */ )}:
+       case map[T /* ERROR cannot use generic type */ ] string:
+       case chan T /* ERROR cannot use generic type */ :
+
+       case T /* ERROR cannot use generic type */ , *T /* ERROR cannot use generic type */ :
+       }
+}
+
+// Make sure a parenthesized nil is ok.
+
+func _(x interface{}) {
+       switch x.(type) {
+       case ((nil)), int:
+       }
+}
+
+// Make sure we look for the predeclared nil.
+
+func _(x interface{}) {
+       type nil int
+       switch x.(type) {
+       case nil: // ok - this is the type nil
+       }
+}
+
+func _(x interface{}) {
+       var nil int
+       switch x.(type) {
+       case nil /* ERROR not a type */ : // not ok - this is the variable nil
+       }
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48018.go2 b/src/go/types/testdata/fixedbugs/issue48018.go2
new file mode 100644 (file)
index 0000000..e6ccc6b
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Box[A any] struct {
+       value A
+}
+
+func Nest[A /* ERROR instantiation cycle */ any](b Box[A], n int) interface{} {
+       if n == 0 {
+               return b
+       }
+       return Nest(Box[Box[A]]{b}, n-1)
+}
+
+func main() {
+       Nest(Box[int]{0}, 10)
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48048.go2 b/src/go/types/testdata/fixedbugs/issue48048.go2
new file mode 100644 (file)
index 0000000..f401330
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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[P any] struct{}
+
+func (T[_]) A() {}
+
+var _ = (T[int]).A
+var _ = (*T[int]).A
+
+var _ = (T /* ERROR cannot use generic type */).A
+var _ = (*T /* ERROR cannot use generic type */).A
diff --git a/src/go/types/testdata/fixedbugs/issue48082.src b/src/go/types/testdata/fixedbugs/issue48082.src
new file mode 100644 (file)
index 0000000..5395154
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2021 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 issue48082
+
+import "init" /* ERROR init must be a func */ /* ERROR could not import init */
diff --git a/src/go/types/testdata/fixedbugs/issue48083.go2 b/src/go/types/testdata/fixedbugs/issue48083.go2
new file mode 100644 (file)
index 0000000..3dae514
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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[P any] struct{}
+
+type _ interface{ int | T /* ERROR cannot use generic type */ }
\ No newline at end of file
diff --git a/src/go/types/testdata/fixedbugs/issue48136.go2 b/src/go/types/testdata/fixedbugs/issue48136.go2
new file mode 100644 (file)
index 0000000..b87f84a
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2021 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 f1[P interface{ *P }]() {}
+func f2[P interface{ func(P) }]() {}
+func f3[P, Q interface{ func(Q) P }]() {}
+func f4[P interface{ *Q }, Q interface{ func(P) }]() {}
+func f5[P interface{ func(P) }]() {}
+func f6[P interface { *Tree[P] }, Q any ]() {}
+
+func _() {
+        f1 /* ERROR cannot infer P */ ()
+        f2 /* ERROR cannot infer P */ ()
+        f3 /* ERROR cannot infer P */ ()
+        f4 /* ERROR cannot infer P */ ()
+        f5 /* ERROR cannot infer P */ ()
+        f6 /* ERROR cannot infer P */ ()
+}
+
+type Tree[P any] struct {
+        left, right *Tree[P]
+        data P
+}
+
+// test case from issue
+
+func foo[Src interface { func() Src }]() Src {
+        return foo[Src]
+}
+
+func _() {
+        foo /* ERROR cannot infer Src */ ()
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48234.go2 b/src/go/types/testdata/fixedbugs/issue48234.go2
new file mode 100644 (file)
index 0000000..e069930
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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
+
+var _ = interface{
+       m()
+       m /* ERROR "duplicate method" */ ()
+}(nil)
diff --git a/src/go/types/testdata/fixedbugs/issue48472.go2 b/src/go/types/testdata/fixedbugs/issue48472.go2
new file mode 100644 (file)
index 0000000..2d908f4
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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 g() {
+       var s string
+       var i int
+       _ = s /* ERROR invalid operation: s \+ i \(mismatched types string and int\) */ + i
+}
+
+func f(i int) int {
+        i /* ERROR invalid operation: i \+= "1" \(mismatched types int and untyped string\) */ += "1"
+        return i
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48529.go2 b/src/go/types/testdata/fixedbugs/issue48529.go2
new file mode 100644 (file)
index 0000000..4f92dec
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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[U interface{ M() T /* ERROR "got 2 arguments but 1 type parameters" */ [U, int] }] int
+
+type X int
+
+func (X) M() T[X] { return 0 }
diff --git a/src/go/types/testdata/fixedbugs/issue48582.go2 b/src/go/types/testdata/fixedbugs/issue48582.go2
new file mode 100644 (file)
index 0000000..c12091b
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 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 N /* ERROR cycle */ interface {
+       int | N
+}
+
+type A /* ERROR cycle */ interface {
+       int | B
+}
+
+type B interface {
+       int | A
+}
+
+type S /* ERROR cycle */ struct {
+       I // ERROR interface contains type constraints
+}
+
+type I interface {
+       int | S
+}
+
+type P interface {
+       *P // ERROR interface contains type constraints
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48619.go2 b/src/go/types/testdata/fixedbugs/issue48619.go2
new file mode 100644 (file)
index 0000000..870bacd
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This issue has been re-opened.
+
+package p
+
+func f[P any](a, _ P) {
+       // var x int
+       // f(a, x /* ERROR type int of x does not match P */)
+       // f(x, a /* ERROR type P of a does not match inferred type int for P */)
+}
+
+func g[P any](a, b P) {
+       // g(a, b)
+       // g(&a, &b)
+       // g([]P{}, []P{})
+}
+
+func h[P any](a, b P) {
+       // h(&a, &b)
+       // h([]P{a}, []P{b})
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48656.go2 b/src/go/types/testdata/fixedbugs/issue48656.go2
new file mode 100644 (file)
index 0000000..52863d4
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This issue is still open.
+
+package p
+
+func f[P interface{*Q}, Q any](p P, q Q) {
+       // _ = f[P]
+        // _ = f[/* ERROR cannot infer P */ *P]
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48695.go2 b/src/go/types/testdata/fixedbugs/issue48695.go2
new file mode 100644 (file)
index 0000000..2d9e6a5
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2021 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 g[P interface{~func(T) P}, T any](P) {}
+
+func _() {
+       type F func(int) F
+       var f F
+       g(f)
+       _ = g[F]
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48703.go2 b/src/go/types/testdata/fixedbugs/issue48703.go2
new file mode 100644 (file)
index 0000000..8a32c1e
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2021 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 "unsafe"
+
+// The actual example from the issue.
+type List[P any] struct{}
+
+func (_ List[P]) m() (_ List[List[P]]) { return }
+
+// Other types of recursion through methods.
+type R[P any] int
+
+func (*R[R /* ERROR must be an identifier */ [int]]) m0() {}
+func (R[P]) m1(R[R[P]])                                   {}
+func (R[P]) m2(R[*P])                                     {}
+func (R[P]) m3([unsafe.Sizeof(new(R[P]))]int)             {}
+func (R[P]) m4([unsafe.Sizeof(new(R[R[P]]))]int)          {}
+
+// Mutual recursion
+type M[P any] int
+
+func (R[P]) m5(M[M[P]]) {}
+func (M[P]) m(R[R[P]])  {}
diff --git a/src/go/types/testdata/fixedbugs/issue48819.src b/src/go/types/testdata/fixedbugs/issue48819.src
new file mode 100644 (file)
index 0000000..9262110
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 "unsafe"
+
+type T /* ERROR illegal cycle in declaration of T */ struct {
+       T
+}
+
+func _(t T) {
+       _ = unsafe.Sizeof(t) // should not go into infinite recursion here
+}
diff --git a/src/go/types/testdata/fixedbugs/issue48951.go2 b/src/go/types/testdata/fixedbugs/issue48951.go2
new file mode 100644 (file)
index 0000000..cf02cc1
--- /dev/null
@@ -0,0 +1,21 @@
+// 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 (
+        A1 /* ERROR illegal cycle */ [P any] [10]A1[P]
+        A2 /* ERROR illegal cycle */ [P any] [10]A2[*P]
+        A3[P any] [10]*A3[P]
+
+        L1[P any] []L1[P]
+
+        S1 /* ERROR illegal cycle */ [P any] struct{ f S1[P] }
+        S2 /* ERROR illegal cycle */ [P any] struct{ f S2[*P] } // like example in issue
+        S3[P any] struct{ f *S3[P] }
+
+        I1 /* ERROR illegal cycle */ [P any] interface{ I1[P] }
+        I2 /* ERROR illegal cycle */ [P any] interface{ I2[*P] }
+        I3[P any] interface{ *I3 /* ERROR interface contains type constraints */ [P] }
+)
diff --git a/src/go/types/testdata/fixedbugs/issue48974.go2 b/src/go/types/testdata/fixedbugs/issue48974.go2
new file mode 100644 (file)
index 0000000..d8ff7c8
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 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 Fooer interface {
+       Foo()
+}
+
+type Fooable[F /* ERROR instantiation cycle */ Fooer] struct {
+       ptr F
+}
+
+func (f *Fooable[F]) Adapter() *Fooable[*FooerImpl[F]] {
+       return &Fooable[*FooerImpl[F]]{&FooerImpl[F]{}}
+}
+
+type FooerImpl[F Fooer] struct {
+}
+
+func (fi *FooerImpl[F]) Foo() {}
diff --git a/src/go/types/testdata/fixedbugs/issue49003.go b/src/go/types/testdata/fixedbugs/issue49003.go
new file mode 100644 (file)
index 0000000..ece1a27
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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(s string) int {
+       for range s {
+       }
+} // ERROR missing return
diff --git a/src/go/types/testdata/fixedbugs/issue49043.go2 b/src/go/types/testdata/fixedbugs/issue49043.go2
new file mode 100644 (file)
index 0000000..c37b0f1
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2021 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
+
+// The example from the issue.
+type (
+       N /* ERROR illegal cycle */ [P any] M[P]
+       M[P any] N[P]
+)
+
+// A slightly more complicated case.
+type (
+       A /* ERROR illegal cycle */ [P any] B[P]
+       B[P any] C[P]
+       C[P any] A[P]
+)
+
+// Confusing but valid (note that `type T *T` is valid).
+type (
+       N1[P any] *M1[P]
+       M1[P any] *N1[P]
+)
diff --git a/src/go/types/testdata/fixedbugs/issue49242.go2 b/src/go/types/testdata/fixedbugs/issue49242.go2
new file mode 100644 (file)
index 0000000..524a0cb
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2021 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 _[P int](x P) int {
+       return x // ERROR cannot use x .* as int value in return statement
+}
+
+func _[P int]() int {
+       return P /* ERROR cannot use P\(1\) .* as int value in return statement */ (1)
+}
+
+func _[P int](x int) P {
+        return x // ERROR cannot use x .* as P value in return statement
+}
+
+func _[P, Q any](x P) Q {
+        return x // ERROR cannot use x .* as Q value in return statement
+}
+
+// test case from issue
+func F[G interface{ uint }]() int {
+       f := func(uint) int { return 0 }
+       return f(G /* ERROR cannot use G\(1\) .* as uint value in argument to f */ (1))
+}
diff --git a/src/go/types/testdata/fixedbugs/issue49247.go2 b/src/go/types/testdata/fixedbugs/issue49247.go2
new file mode 100644 (file)
index 0000000..3f25e0e
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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 integer interface {
+       ~int | ~int8 | ~int16 | ~int32 | ~int64 |
+               ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+func Add1024[T integer](s []T) {
+       for i, v := range s {
+               s[i] = v + 1024 // ERROR cannot convert 1024 \(untyped int constant\) to T
+       }
+}
+
+func f[T interface{ int8 }]() {
+       println(T(1024 /* ERROR cannot convert 1024 \(untyped int value\) to T */))
+}
diff --git a/src/go/types/testdata/fixedbugs/issue49296.go2 b/src/go/types/testdata/fixedbugs/issue49296.go2
new file mode 100644 (file)
index 0000000..8c6d0b6
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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 _[
+        T0 any,
+        T1 []int,
+        T2 ~float64 | ~complex128 | chan int,
+]() {
+       // TODO(rfindley): the types2 error here is clearer.
+        _ = T0(nil /* ERROR cannot convert nil \(untyped nil value\) to T0 */ )
+        _ = T1(1 /* ERROR cannot convert 1 .* to T1 */ )
+        _ = T2(2 /* ERROR cannot convert 2 .* to T2 */ )
+}
+
+// test case from issue
+func f[T interface{[]int}]() {
+       _ = T(1 /* ERROR cannot convert */ )
+}
diff --git a/src/go/types/testdata/spec/assignability.go2 b/src/go/types/testdata/spec/assignability.go2
new file mode 100644 (file)
index 0000000..a6e71aa
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2021 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 assignability
+
+// See the end of this package for the declarations
+// of the types and variables used in these tests.
+
+// "x's type is identical to T"
+func _[TP any](X TP) {
+       b = b
+       a = a
+       l = l
+       s = s
+       p = p
+       f = f
+       i = i
+       m = m
+       c = c
+       d = d
+
+       B = B
+       A = A
+       L = L
+       S = S
+       P = P
+       F = F
+       I = I
+       M = M
+       C = C
+       D = D
+       X = X
+}
+
+// "x's type V and T have identical underlying types
+// and at least one of V or T is not a named type."
+// (here a named type is a type with a name)
+func _[TP1, TP2 Interface](X1 TP1, X2 TP2) {
+       b = B // ERROR cannot use B .* as int value
+       a = A
+       l = L
+       s = S
+       p = P
+       f = F
+       i = I
+       m = M
+       c = C
+       d = D
+
+       B = b // ERROR cannot use b .* as Basic value
+       A = a
+       L = l
+       S = s
+       P = p
+       F = f
+       I = i
+       M = m
+       C = c
+       D = d
+       X1 = i  // ERROR cannot use i .* as TP1 value
+       X1 = X2 // ERROR cannot use X2 .* as TP1 value
+}
+
+// "T is an interface type and x implements T and T is not a type parameter"
+func _[TP Interface](X TP) {
+       i = d // ERROR missing method m
+       i = D
+       i = X
+       X = i // ERROR cannot use i .* as TP value
+}
+
+// "x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type"
+// (here a named type is a type with a name)
+type (
+       _SendChan = chan<- int
+       _RecvChan = <-chan int
+
+       SendChan _SendChan
+       RecvChan _RecvChan
+)
+
+func _[
+       _CC ~_Chan,
+       _SC ~_SendChan,
+       _RC ~_RecvChan,
+
+       CC Chan,
+       SC SendChan,
+       RC RecvChan,
+]() {
+       var (
+               _ _SendChan = c
+               _ _RecvChan = c
+               _ _Chan = c
+
+               _ _SendChan = C
+               _ _RecvChan = C
+               _ _Chan = C
+
+               _ SendChan = c
+               _ RecvChan = c
+               _ Chan = c
+
+               _ SendChan = C // ERROR cannot use C .* as SendChan value
+               _ RecvChan = C // ERROR cannot use C .* as RecvChan value
+               _ Chan = C
+               _ Chan = make /* ERROR cannot use make\(chan Basic\) .* as Chan value */ (chan Basic)
+       )
+
+       var (
+               _ _CC = C // ERROR cannot use C .* as _CC value
+               _ _SC = C // ERROR cannot use C .* as _SC value
+               _ _RC = C // ERROR cannot use C .* as _RC value
+
+               _ CC = _CC /* ERROR cannot use _CC\(nil\) .* as CC value */ (nil)
+               _ SC = _CC /* ERROR cannot use _CC\(nil\) .* as SC value */ (nil)
+               _ RC = _CC /* ERROR cannot use _CC\(nil\) .* as RC value */ (nil)
+
+               _ CC = C // ERROR cannot use C .* as CC value
+               _ SC = C // ERROR cannot use C .* as SC value
+               _ RC = C // ERROR cannot use C .* as RC value
+       )
+}
+
+// "x's type V is not a named type and T is a type parameter, and x is assignable to each specific type in T's type set."
+func _[
+       TP0 any,
+       TP1 ~_Chan,
+       TP2 ~chan int | ~chan byte,
+]() {
+       var (
+               _ TP0 = c // ERROR cannot use c .* as TP0 value
+               _ TP0 = C // ERROR cannot use C .* as TP0 value
+               _ TP1 = c
+               _ TP1 = C // ERROR cannot use C .* as TP1 value
+               _ TP2 = c // ERROR .* cannot assign chan int to chan byte
+       )
+}
+
+// "x's type V is a type parameter and T is not a named type, and values x' of each specific type in V's type set are assignable to T."
+func _[
+       TP0 Interface,
+       TP1 ~_Chan,
+       TP2 ~chan int | ~chan byte,
+](X0 TP0, X1 TP1, X2 TP2) {
+       i = X0
+       I = X0
+       c = X1
+       C = X1 // ERROR cannot use X1 .* as Chan value
+       c = X2 // ERROR .* cannot assign chan byte \(in TP2\) to chan int
+}
+
+// "x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type"
+// TODO(rfindley) error messages about untyped nil diverge from types2 here.
+// Consider aligning them.
+func _[TP Interface](X TP) {
+       b = nil // ERROR cannot use.*untyped nil
+       a = nil // ERROR cannot use.*untyped nil
+       l = nil
+       s = nil // ERROR cannot use.*untyped nil
+       p = nil
+       f = nil
+       i = nil
+       m = nil
+       c = nil
+       d = nil // ERROR cannot use.*untyped nil
+
+       B = nil // ERROR cannot use.*untyped nil
+       A = nil // ERROR cannot use.*untyped nil
+       L = nil
+       S = nil // ERROR cannot use.*untyped nil
+       P = nil
+       F = nil
+       I = nil
+       M = nil
+       C = nil
+       D = nil // ERROR cannot use.*untyped nil
+       X = nil // ERROR cannot use.*untyped nil
+}
+
+// "x is an untyped constant representable by a value of type T"
+func _[
+       Int8 ~int8,
+       Int16 ~int16,
+       Int32 ~int32,
+       Int64 ~int64,
+        Int8_16 ~int8 | ~int16,
+](
+       i8 Int8,
+       i16 Int16,
+       i32 Int32,
+       i64 Int64,
+        i8_16 Int8_16,
+) {
+       b = 42
+       b = 42.0
+       // etc.
+
+       i8 = -1 << 7
+       i8 = 1<<7 - 1
+       i16 = -1 << 15
+       i16 = 1<<15 - 1
+       i32 = -1 << 31
+       i32 = 1<<31 - 1
+       i64 = -1 << 63
+       i64 = 1<<63 - 1
+
+       i8_16 = -1 << 7
+       i8_16 = 1<<7 - 1
+       i8_16 = - /* ERROR cannot use .* as Int8_16 */ 1 << 15
+       i8_16 = 1 /* ERROR cannot use .* as Int8_16 */ <<15 - 1
+}
+
+// proto-types for tests
+
+type (
+       _Basic     = int
+       _Array     = [10]int
+       _Slice     = []int
+       _Struct    = struct{ f int }
+       _Pointer   = *int
+       _Func      = func(x int) string
+       _Interface = interface{ m() int }
+       _Map       = map[string]int
+       _Chan      = chan int
+
+       Basic     _Basic
+       Array     _Array
+       Slice     _Slice
+       Struct    _Struct
+       Pointer   _Pointer
+       Func      _Func
+       Interface _Interface
+       Map       _Map
+       Chan      _Chan
+       Defined   _Struct
+)
+
+func (Defined) m() int
+
+// proto-variables for tests
+
+var (
+       b _Basic
+       a _Array
+       l _Slice
+       s _Struct
+       p _Pointer
+       f _Func
+       i _Interface
+       m _Map
+       c _Chan
+       d _Struct
+
+       B Basic
+       A Array
+       L Slice
+       S Struct
+       P Pointer
+       F Func
+       I Interface
+       M Map
+       C Chan
+       D Defined
+)
diff --git a/src/go/types/testdata/spec/conversions.go2 b/src/go/types/testdata/spec/conversions.go2
new file mode 100644 (file)
index 0000000..e54403c
--- /dev/null
@@ -0,0 +1,179 @@
+// Copyright 2021 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 conversions
+
+import "unsafe"
+
+// constant conversions
+
+func _[T ~byte]() T { return 255 }
+func _[T ~byte]() T { return 256 /* ERROR cannot use 256 .* as T value */ }
+
+func _[T ~byte]() {
+       const _ = T /* ERROR T\(0\) .* is not constant */ (0)
+       var _ T = 255
+       var _ T = 256 // ERROR cannot use 256 .* as T value
+}
+
+func _[T ~string]() T { return T('a') }
+func _[T ~int | ~string]() T { return T('a') }
+func _[T ~byte | ~int | ~string]() T { return T(256 /* ERROR cannot convert 256 .* to T */ ) }
+
+// implicit conversions never convert to string
+func _[T ~string]() {
+       var _ string = 0 // ERROR cannot use .* as string value
+       var _ T = 0 // ERROR cannot use .* as T value
+}
+
+// failing const conversions of constants to type parameters report a cause
+func _[
+       T1 any,
+       T2 interface{ m() },
+       T3 ~int | ~float64 | ~bool,
+       T4 ~int | ~string,
+]() {
+       // TODO(rfindley): align the error formatting here with types2.
+       _ = T1(0 /* ERROR cannot convert 0 .* to T1.*T1 does not contain specific types */ )
+       _ = T2(1 /* ERROR cannot convert 1 .* to T2.*T2 does not contain specific types */ )
+       _ = T3(2 /* ERROR cannot convert 2 .* to T3.*cannot convert 2 .* to bool \(in T3\) */ )
+       _ = T4(3.14 /* ERROR cannot convert 3.14 .* to T4.*cannot convert 3.14 .* to int \(in T4\) */ )
+}
+
+// "x is assignable to T"
+// - tested via assignability tests
+
+// "x's type and T have identical underlying types if tags are ignored"
+
+func _[X ~int, T ~int](x X) T { return T(x) }
+func _[X struct{f int "foo"}, T struct{f int "bar"}](x X) T { return T(x) }
+
+type Foo struct{f int "foo"}
+type Bar struct{f int "bar"}
+type Far struct{f float64 }
+
+func _[X Foo, T Bar](x X) T { return T(x) }
+func _[X Foo|Bar, T Bar](x X) T { return T(x) }
+func _[X Foo, T Foo|Bar](x X) T { return T(x) }
+func _[X Foo, T Far](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Foo\) to T.*cannot convert Foo \(in X\) to Far \(in T\) */ ) }
+
+// "x's type and T are unnamed pointer types and their pointer base types
+// have identical underlying types if tags are ignored"
+
+func _[X ~*Foo, T ~*Bar](x X) T { return T(x) }
+func _[X ~*Foo|~*Bar, T ~*Bar](x X) T { return T(x) }
+func _[X ~*Foo, T ~*Foo|~*Bar](x X) T { return T(x) }
+func _[X ~*Foo, T ~*Far](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\*Foo\) to T.*cannot convert \*Foo \(in X\) to \*Far \(in T\) */ ) }
+
+// Verify that the defined types in constraints are considered for the rule above.
+
+type (
+       B int
+       C int
+       X0 *B
+       T0 *C
+)
+
+func _(x X0) T0 { return T0(x /* ERROR cannot convert */ ) } // non-generic reference
+func _[X X0, T T0](x X) T { return T(x /* ERROR cannot convert */ ) }
+func _[T T0](x X0) T { return T(x /* ERROR cannot convert */ ) }
+func _[X X0](x X) T0 { return T0(x /* ERROR cannot convert */ ) }
+
+// "x's type and T are both integer or floating point types"
+
+func _[X Integer, T Integer](x X) T { return T(x) }
+func _[X Unsigned, T Integer](x X) T { return T(x) }
+func _[X Float, T Integer](x X) T { return T(x) }
+
+func _[X Integer, T Unsigned](x X) T { return T(x) }
+func _[X Unsigned, T Unsigned](x X) T { return T(x) }
+func _[X Float, T Unsigned](x X) T { return T(x) }
+
+func _[X Integer, T Float](x X) T { return T(x) }
+func _[X Unsigned, T Float](x X) T { return T(x) }
+func _[X Float, T Float](x X) T { return T(x) }
+
+func _[X, T Integer|Unsigned|Float](x X) T { return T(x) }
+func _[X, T Integer|~string](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Integer\|~string\) to T.*cannot convert string \(in X\) to int \(in T\) */ ) }
+
+// "x's type and T are both complex types"
+
+func _[X, T Complex](x X) T { return T(x) }
+func _[X, T Float|Complex](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Float\|Complex\) to T.*cannot convert float32 \(in X\) to complex64 \(in T\) */ ) }
+
+// "x is an integer or a slice of bytes or runes and T is a string type"
+
+type myInt int
+type myString string
+
+func _[T ~string](x int) T { return T(x) }
+func _[T ~string](x myInt) T { return T(x) }
+func _[X Integer](x X) string { return string(x) }
+func _[X Integer](x X) myString { return myString(x) }
+func _[X Integer](x X) *string { return (*string)(x /* ERROR cannot convert x \(variable of type X constrained by Integer\) to \*string.*cannot convert int \(in X\) to \*string */ ) }
+
+func _[T ~string](x []byte) T { return T(x) }
+func _[T ~string](x []rune) T { return T(x) }
+func _[X ~[]byte, T ~string](x X) T { return T(x) }
+func _[X ~[]rune, T ~string](x X) T { return T(x) }
+func _[X Integer|~[]byte|~[]rune, T ~string](x X) T { return T(x) }
+func _[X Integer|~[]byte|~[]rune, T ~*string](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by Integer\|~\[\]byte\|~\[\]rune\) to T.*cannot convert int \(in X\) to \*string \(in T\) */ ) }
+
+// "x is a string and T is a slice of bytes or runes"
+
+func _[T ~[]byte](x string) T { return T(x) }
+func _[T ~[]rune](x string) T { return T(x) }
+func _[T ~[]rune](x *string) T { return T(x /* ERROR cannot convert x \(variable of type \*string\) to T.*cannot convert \*string to \[\]rune \(in T\) */ ) }
+
+func _[X ~string, T ~[]byte](x X) T { return T(x) }
+func _[X ~string, T ~[]rune](x X) T { return T(x) }
+func _[X ~string, T ~[]byte|~[]rune](x X) T { return T(x) }
+func _[X ~*string, T ~[]byte|~[]rune](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\*string\) to T.*cannot convert \*string \(in X\) to \[\]byte \(in T\) */ ) }
+
+// package unsafe:
+// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+
+type myUintptr uintptr
+
+func _[X ~uintptr](x X) unsafe.Pointer { return unsafe.Pointer(x) }
+func _[T unsafe.Pointer](x myUintptr) T { return T(x) }
+func _[T unsafe.Pointer](x int64) T { return T(x /* ERROR cannot convert x \(variable of type int64\) to T.*cannot convert int64 to unsafe\.Pointer \(in T\) */ ) }
+
+// "and vice versa"
+
+func _[T ~uintptr](x unsafe.Pointer) T { return T(x) }
+func _[X unsafe.Pointer](x X) uintptr { return uintptr(x) }
+func _[X unsafe.Pointer](x X) myUintptr { return myUintptr(x) }
+func _[X unsafe.Pointer](x X) int64 { return int64(x /* ERROR cannot convert x \(variable of type X constrained by unsafe\.Pointer\) to int64.*cannot convert unsafe\.Pointer \(in X\) to int64 */ ) }
+
+// "x is a slice, T is a pointer-to-array type,
+// and the slice and array types have identical element types."
+
+func _[X ~[]E, T ~*[10]E, E any](x X) T { return T(x) }
+func _[X ~[]E, T ~[10]E, E any](x X) T { return T(x /* ERROR cannot convert x \(variable of type X constrained by ~\[\]E\) to T.*cannot convert \[\]E \(in X\) to \[10\]E \(in T\) */ ) }
+
+// ----------------------------------------------------------------------------
+// The following declarations can be replaced by the exported types of the
+// constraints package once all builders support importing interfaces with
+// type constraints.
+
+type Signed interface {
+       ~int | ~int8 | ~int16 | ~int32 | ~int64
+}
+
+type Unsigned interface {
+       ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+type Integer interface {
+       Signed | Unsigned
+}
+
+type Float interface {
+       ~float32 | ~float64
+}
+
+type Complex interface {
+       ~complex64 | ~complex128
+}
index 16d28bc9a6fc222a4dee0a1de842b318df81cc9d..e85c5aa81bef566c2af58fbb0d1b144dce537147 100644 (file)
@@ -16,8 +16,6 @@ func NewTuple(x ...*Var) *Tuple {
        if len(x) > 0 {
                return &Tuple{vars: x}
        }
-       // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
-       //           it's too subtle and causes problems.
        return nil
 }
 
index 5819dd290ca6f5e1bf4bbb68a8f3917f464f096f..4247f52c31f3bbbb78b5d9e48d0c67c155e6e0f5 100644 (file)
@@ -9,118 +9,70 @@ package types
 type Type interface {
        // Underlying returns the underlying type of a type
        // w/o following forwarding chains. Only used by
-       // client packages (here for backward-compatibility).
+       // client packages.
        Underlying() Type
 
        // String returns a string representation of a type.
        String() string
 }
 
-// top represents the top of the type lattice.
-// It is the underlying type of a type parameter that
-// can be satisfied by any type (ignoring methods),
-// because its type constraint contains no restrictions
-// besides methods.
-type top struct{}
-
-// theTop is the singleton top type.
-var theTop = &top{}
-
-func (t *top) Underlying() Type { return t }
-func (t *top) String() string   { return TypeString(t, nil) }
-
 // under returns the true expanded underlying type.
 // If it doesn't exist, the result is Typ[Invalid].
 // under must only be called when a type is known
 // to be fully set up.
 func under(t Type) Type {
-       // TODO(gri) is this correct for *Union?
        if n := asNamed(t); n != nil {
                return n.under()
        }
        return t
 }
 
-// optype returns a type's operational type. Except for
-// type parameters, the operational type is the same
-// as the underlying type (as returned by under). For
-// Type parameters, the operational type is determined
-// by the corresponding type bound's type list. The
-// result may be the bottom or top type, but it is never
-// the incoming type parameter.
-func optype(typ Type) Type {
-       if t := asTypeParam(typ); t != nil {
-               // If the optype is typ, return the top type as we have
-               // no information. It also prevents infinite recursion
-               // via the asTypeParam converter function. This can happen
-               // for a type parameter list of the form:
-               // (type T interface { type T }).
-               // See also issue #39680.
-               if a := t.iface().typeSet().types; a != nil && a != typ {
-                       // If we have a union with a single entry, ignore
-                       // any tilde because under(~t) == under(t).
-                       if u, _ := a.(*Union); u != nil && u.NumTerms() == 1 {
-                               a, _ = u.Term(0)
-                       }
-                       if a != typ {
-                               // a != typ and a is a type parameter => under(a) != typ, so this is ok
-                               return under(a)
-                       }
-               }
-               return theTop
-       }
-       return under(typ)
-}
-
-// Converters
-//
-// A converter must only be called when a type is
-// known to be fully set up. A converter returns
-// a type's operational type (see comment for optype)
-// or nil if the type argument is not of the
-// respective type.
+// Convenience converters
 
 func asBasic(t Type) *Basic {
-       op, _ := optype(t).(*Basic)
+       op, _ := under(t).(*Basic)
        return op
 }
 
 func asArray(t Type) *Array {
-       op, _ := optype(t).(*Array)
+       op, _ := under(t).(*Array)
        return op
 }
 
 func asSlice(t Type) *Slice {
-       op, _ := optype(t).(*Slice)
+       op, _ := under(t).(*Slice)
        return op
 }
 
 func asStruct(t Type) *Struct {
-       op, _ := optype(t).(*Struct)
+       op, _ := under(t).(*Struct)
        return op
 }
 
 func asPointer(t Type) *Pointer {
-       op, _ := optype(t).(*Pointer)
+       op, _ := under(t).(*Pointer)
        return op
 }
 
 func asSignature(t Type) *Signature {
-       op, _ := optype(t).(*Signature)
+       op, _ := under(t).(*Signature)
        return op
 }
 
-// If the argument to asInterface, asNamed, or asTypeParam is of the respective type
-// (possibly after expanding an instance type), these methods return that type.
-// Otherwise the result is nil.
-
 func asInterface(t Type) *Interface {
-       op, _ := optype(t).(*Interface)
+       op, _ := under(t).(*Interface)
        return op
 }
 
+// If the argument to asNamed, or asTypeParam is of the respective type
+// (possibly after expanding resolving a *Named type), these methods return that type.
+// Otherwise the result is nil.
+
 func asNamed(t Type) *Named {
-       e, _ := expand(t).(*Named)
+       e, _ := t.(*Named)
+       if e != nil {
+               e.resolve(nil)
+       }
        return e
 }
 
diff --git a/src/go/types/typelists.go b/src/go/types/typelists.go
new file mode 100644 (file)
index 0000000..ba74b8d
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2021 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 types
+
+import "bytes"
+
+// TypeParamList holds a list of type parameters.
+type TypeParamList struct{ tparams []*TypeParam }
+
+// Len returns the number of type parameters in the list.
+// It is safe to call on a nil receiver.
+func (l *TypeParamList) Len() int { return len(l.list()) }
+
+// At returns the i'th type parameter in the list.
+func (l *TypeParamList) At(i int) *TypeParam { return l.tparams[i] }
+
+// list is for internal use where we expect a []*TypeParam.
+// TODO(rfindley): list should probably be eliminated: we can pass around a
+// TypeParamList instead.
+func (l *TypeParamList) list() []*TypeParam {
+       if l == nil {
+               return nil
+       }
+       return l.tparams
+}
+
+// TypeList holds a list of types.
+type TypeList struct{ types []Type }
+
+// NewTypeList returns a new TypeList with the types in list.
+func NewTypeList(list []Type) *TypeList {
+       if len(list) == 0 {
+               return nil
+       }
+       return &TypeList{list}
+}
+
+// Len returns the number of types in the list.
+// It is safe to call on a nil receiver.
+func (l *TypeList) Len() int { return len(l.list()) }
+
+// At returns the i'th type in the list.
+func (l *TypeList) At(i int) Type { return l.types[i] }
+
+// list is for internal use where we expect a []Type.
+// TODO(rfindley): list should probably be eliminated: we can pass around a
+// TypeList instead.
+func (l *TypeList) list() []Type {
+       if l == nil {
+               return nil
+       }
+       return l.types
+}
+
+func (l *TypeList) String() string {
+       if l == nil || len(l.types) == 0 {
+               return "[]"
+       }
+       var buf bytes.Buffer
+       newTypeWriter(&buf, nil).typeList(l.types)
+       return buf.String()
+}
+
+// ----------------------------------------------------------------------------
+// Implementation
+
+func bindTParams(list []*TypeParam) *TypeParamList {
+       if len(list) == 0 {
+               return nil
+       }
+       for i, typ := range list {
+               if typ.index >= 0 {
+                       panic("type parameter bound more than once")
+               }
+               typ.index = i
+       }
+       return &TypeParamList{tparams: list}
+}
index 33a516c209734f117dc55582c91002c5ba40ed20..731b746d05f288c159a079bca1ecb4b1b8034d9f 100644 (file)
@@ -24,113 +24,120 @@ type TypeParam struct {
        id    uint64    // unique id, for debugging only
        obj   *TypeName // corresponding type name
        index int       // type parameter index in source order, starting at 0
-       // TODO(rfindley): this could also be Typ[Invalid]. Verify that this is handled correctly.
-       bound Type // *Named or *Interface; underlying type is always *Interface
+       bound Type      // any type, but eventually an *Interface for correct programs (see TypeParam.iface)
 }
 
 // NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
-// or Signature type by calling SetTParams. Setting a type parameter on more
+// or Signature type by calling SetTypeParams. Setting a type parameter on more
 // than one type will result in a panic.
 //
-// The bound argument can be nil, and set later via SetBound.
-func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam {
+// The constraint argument can be nil, and set later via SetConstraint.
+func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
+       return (*Checker)(nil).newTypeParam(obj, constraint)
+}
+
+func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
        // Always increment lastID, even if it is not used.
        id := nextID()
        if check != nil {
                check.nextID++
                id = check.nextID
        }
-       typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound}
+       typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: constraint}
        if obj.typ == nil {
                obj.typ = typ
        }
        return typ
 }
 
-// TODO(rfindley): remove or export these placeholder APIs.
-
-// Index returns the index of the type param within its param list.
-func (t *TypeParam) _Index() int {
+// Index returns the index of the type param within its param list, or -1 if
+// the type parameter has not yet been bound to a type.
+func (t *TypeParam) Index() int {
        return t.index
 }
 
-// SetId sets the unique id of a type param. Should only be used for type params
-// in imported generic types.
-func (t *TypeParam) _SetId(id uint64) {
-       t.id = id
-}
+// Obj returns the type name for t.
+func (t *TypeParam) Obj() *TypeName { return t.obj }
 
 // Constraint returns the type constraint specified for t.
 func (t *TypeParam) Constraint() Type {
-       // compute the type set if possible (we may not have an interface)
-       if iface, _ := under(t.bound).(*Interface); iface != nil {
-               // use the type bound position if we have one
-               pos := token.NoPos
-               if n, _ := t.bound.(*Named); n != nil {
-                       pos = n.obj.pos
-               }
-               computeTypeSet(t.check, pos, iface)
-       }
        return t.bound
 }
 
 // SetConstraint sets the type constraint for t.
 func (t *TypeParam) SetConstraint(bound Type) {
        if bound == nil {
-               panic("types2.TypeParam.SetConstraint: bound must not be nil")
+               panic("nil constraint")
        }
        t.bound = bound
 }
 
+func (t *TypeParam) Underlying() Type { return t }
+func (t *TypeParam) String() string   { return TypeString(t, nil) }
+
+// ----------------------------------------------------------------------------
+// Implementation
+
 // iface returns the constraint interface of t.
 func (t *TypeParam) iface() *Interface {
-       if iface, _ := under(t.Constraint()).(*Interface); iface != nil {
-               return iface
+       bound := t.bound
+
+       // determine constraint interface
+       var ityp *Interface
+       switch u := under(bound).(type) {
+       case *Basic:
+               if u == Typ[Invalid] {
+                       // error is reported elsewhere
+                       return &emptyInterface
+               }
+       case *Interface:
+               ityp = u
+       case *TypeParam:
+               // error is reported in Checker.collectTypeParams
+               return &emptyInterface
        }
-       return &emptyInterface
-}
 
-func (t *TypeParam) Underlying() Type { return t }
-func (t *TypeParam) String() string   { return TypeString(t, nil) }
+       // If we don't have an interface, wrap constraint into an implicit interface.
+       // TODO(gri) mark it as implicit - see comment in Checker.bound
+       if ityp == nil {
+               ityp = NewInterfaceType(nil, []Type{bound})
+               ityp.implicit = true
+               t.bound = ityp // update t.bound for next time (optimization)
+       }
 
-// TypeParams holds a list of type parameters bound to a type.
-type TypeParams struct{ tparams []*TypeName }
+       // compute type set if necessary
+       if ityp.tset == nil {
+               // use the (original) type bound position if we have one
+               pos := token.NoPos
+               if n, _ := bound.(*Named); n != nil {
+                       pos = n.obj.pos
+               }
+               computeInterfaceTypeSet(t.check, pos, ityp)
+       }
 
-// Len returns the number of type parameters in the list.
-// It is safe to call on a nil receiver.
-func (tps *TypeParams) Len() int {
-       return len(tps.list())
+       return ityp
 }
 
-// At returns the i'th type parameter in the list.
-func (tps *TypeParams) At(i int) *TypeName {
-       return tps.list()[i]
+// singleType returns the single type of the type parameter constraint; or nil.
+func (t *TypeParam) singleType() Type {
+       return t.iface().typeSet().singleType()
 }
 
-func (tps *TypeParams) list() []*TypeName {
-       if tps == nil {
-               return nil
-       }
-       return tps.tparams
+// hasTerms reports whether the type parameter constraint has specific type terms.
+func (t *TypeParam) hasTerms() bool {
+       return t.iface().typeSet().hasTerms()
 }
 
-func bindTParams(list []*TypeName) *TypeParams {
-       if len(list) == 0 {
-               return nil
-       }
-       for i, tp := range list {
-               typ := tp.Type().(*TypeParam)
-               if typ.index >= 0 {
-                       panic("internal error: type parameter bound more than once")
-               }
-               typ.index = i
-       }
-       return &TypeParams{tparams: list}
+// is calls f with the specific type terms of t's constraint and reports whether
+// all calls to f returned true. If there are no specific terms, is
+// returns the result of f(nil).
+func (t *TypeParam) is(f func(*term) bool) bool {
+       return t.iface().typeSet().is(f)
 }
 
-// ----------------------------------------------------------------------------
-// Implementation
-
+// underIs calls f with the underlying types of the specific type terms
+// of t's constraint and reports whether all calls to f returned true.
+// If there are no specific terms, underIs returns the result of f(nil).
 func (t *TypeParam) underIs(f func(Type) bool) bool {
        return t.iface().typeSet().underIs(f)
 }
index 836f93047a237d5cad0adaccbb53b964da4b145d..f8e76ed400f17587a0e6a96d55616d5533268d0f 100644 (file)
@@ -18,32 +18,30 @@ import (
 type _TypeSet struct {
        comparable bool // if set, the interface is or embeds comparable
        // TODO(gri) consider using a set for the methods for faster lookup
-       methods []*Func // all methods of the interface; sorted by unique ID
-       types   Type    // typically a *Union; nil means no type restrictions
+       methods []*Func  // all methods of the interface; sorted by unique ID
+       terms   termlist // type terms of the type set
 }
 
-// IsTop reports whether type set s is the top type set (corresponding to the empty interface).
-func (s *_TypeSet) IsTop() bool { return !s.comparable && len(s.methods) == 0 && s.types == nil }
+// IsEmpty reports whether type set s is the empty set.
+func (s *_TypeSet) IsEmpty() bool { return s.terms.isEmpty() }
 
-// IsMethodSet reports whether the type set s is described by a single set of methods.
-func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.types == nil }
+// IsAll reports whether type set s is the set of all types (corresponding to the empty interface).
+func (s *_TypeSet) IsAll() bool { return !s.comparable && len(s.methods) == 0 && s.terms.isAll() }
+
+// IsMethodSet reports whether the interface t is fully described by its method set.
+func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() }
 
 // IsComparable reports whether each type in the set is comparable.
-// TODO(gri) this is not correct - there may be s.types values containing non-comparable types
 func (s *_TypeSet) IsComparable() bool {
-       if s.types == nil {
+       if s.terms.isAll() {
                return s.comparable
        }
-       tcomparable := s.underIs(func(u Type) bool {
-               return Comparable(u)
+       return s.is(func(t *term) bool {
+               return t != nil && Comparable(t.typ)
        })
-       if !s.comparable {
-               return tcomparable
-       }
-       return s.comparable && tcomparable
 }
 
-// TODO(gri) IsTypeSet is not a great name. Find a better one.
+// TODO(gri) IsTypeSet is not a great name for this predicate. Find a better one.
 
 // IsTypeSet reports whether the type set s is represented by a finite set of underlying types.
 func (s *_TypeSet) IsTypeSet() bool {
@@ -64,60 +62,102 @@ func (s *_TypeSet) LookupMethod(pkg *Package, name string) (int, *Func) {
 }
 
 func (s *_TypeSet) String() string {
-       if s.IsTop() {
-               return "⊤"
+       switch {
+       case s.IsEmpty():
+               return "∅"
+       case s.IsAll():
+               return "𝓤"
        }
 
+       hasMethods := len(s.methods) > 0
+       hasTerms := s.hasTerms()
+
        var buf bytes.Buffer
        buf.WriteByte('{')
        if s.comparable {
-               buf.WriteString(" comparable")
-               if len(s.methods) > 0 || s.types != nil {
-                       buf.WriteByte(';')
+               buf.WriteString("comparable")
+               if hasMethods || hasTerms {
+                       buf.WriteString("; ")
                }
        }
        for i, m := range s.methods {
                if i > 0 {
-                       buf.WriteByte(';')
+                       buf.WriteString("; ")
                }
-               buf.WriteByte(' ')
                buf.WriteString(m.String())
        }
-       if len(s.methods) > 0 && s.types != nil {
-               buf.WriteByte(';')
+       if hasMethods && hasTerms {
+               buf.WriteString("; ")
        }
-       if s.types != nil {
-               buf.WriteByte(' ')
-               writeType(&buf, s.types, nil, nil)
+       if hasTerms {
+               buf.WriteString(s.terms.String())
        }
-
-       buf.WriteString(" }") // there was a least one method or type
+       buf.WriteString("}")
        return buf.String()
 }
 
 // ----------------------------------------------------------------------------
 // Implementation
 
-// underIs reports whether f returned true for the underlying types of the
-// enumerable types in the type set s. If the type set comprises all types
-// f is called once with the top type; if the type set is empty, the result
-// is false.
+// hasTerms reports whether the type set has specific type terms.
+func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
+
+// singleType returns the single type in s if there is exactly one; otherwise the result is nil.
+func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
+
+// includes reports whether t ∈ s.
+func (s *_TypeSet) includes(t Type) bool { return s.terms.includes(t) }
+
+// subsetOf reports whether s1 ⊆ s2.
+func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
+
+// TODO(gri) TypeSet.is and TypeSet.underIs should probably also go into termlist.go
+
+// is calls f with the specific type terms of s and reports whether
+// all calls to f returned true. If there are no specific terms, is
+// returns the result of f(nil).
+func (s *_TypeSet) is(f func(*term) bool) bool {
+       if !s.hasTerms() {
+               return f(nil)
+       }
+       for _, t := range s.terms {
+               assert(t.typ != nil)
+               if !f(t) {
+                       return false
+               }
+       }
+       return true
+}
+
+// underIs calls f with the underlying types of the specific type terms
+// of s and reports whether all calls to f returned true. If there are
+// no specific terms, is returns the result of f(nil).
 func (s *_TypeSet) underIs(f func(Type) bool) bool {
-       switch t := s.types.(type) {
-       case nil:
-               return f(theTop)
-       default:
-               return f(t)
-       case *Union:
-               return t.underIs(f)
+       if !s.hasTerms() {
+               return f(nil)
+       }
+       for _, t := range s.terms {
+               assert(t.typ != nil)
+               // x == under(x) for ~x terms
+               u := t.typ
+               if !t.tilde {
+                       u = under(u)
+               }
+               if debug {
+                       assert(Identical(u, under(u)))
+               }
+               if !f(u) {
+                       return false
+               }
        }
+       return true
 }
 
 // topTypeSet may be used as type set for the empty interface.
-var topTypeSet _TypeSet
+var topTypeSet = _TypeSet{terms: allTermlist}
 
-// computeTypeSet may be called with check == nil.
-func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
+// computeInterfaceTypeSet may be called with check == nil.
+func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
        if ityp.tset != nil {
                return ityp.tset
        }
@@ -157,7 +197,7 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
        // have valid interfaces. Mark the interface as complete to avoid
        // infinite recursion if the validType check occurs later for some
        // reason.
-       ityp.tset = new(_TypeSet) // TODO(gri) is this sufficient?
+       ityp.tset = &_TypeSet{terms: allTermlist} // TODO(gri) is this sufficient?
 
        // Methods of embedded interfaces are collected unchanged; i.e., the identity
        // of a method I.m's Func Object of an interface I is the same as that of
@@ -214,7 +254,7 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
        }
 
        // collect embedded elements
-       var allTypes Type
+       var allTerms = allTermlist
        for i, typ := range ityp.embeddeds {
                // The embedding position is nil for imported interfaces
                // and also for interface copies after substitution (but
@@ -223,39 +263,51 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
                if ityp.embedPos != nil {
                        pos = (*ityp.embedPos)[i]
                }
-               var types Type
-               switch t := under(typ).(type) {
+               var terms termlist
+               switch u := under(typ).(type) {
                case *Interface:
-                       tset := computeTypeSet(check, pos, t)
+                       tset := computeInterfaceTypeSet(check, pos, u)
+                       // If typ is local, an error was already reported where typ is specified/defined.
+                       if check != nil && check.isImportedConstraint(typ) && !check.allowVersion(check.pkg, 1, 18) {
+                               check.errorf(atPos(pos), _Todo, "embedding constraint interface %s requires go1.18 or later", typ)
+                               continue
+                       }
                        if tset.comparable {
                                ityp.tset.comparable = true
                        }
                        for _, m := range tset.methods {
                                addMethod(pos, m, false) // use embedding position pos rather than m.pos
-
                        }
-                       types = tset.types
+                       terms = tset.terms
                case *Union:
-                       // TODO(gri) combine with default case once we have
-                       //           converted all tests to new notation and we
-                       //           can report an error when we don't have an
-                       //           interface before go1.18.
-                       types = typ
+                       if check != nil && !check.allowVersion(check.pkg, 1, 18) {
+                               check.errorf(atPos(pos), _Todo, "embedding interface element %s requires go1.18 or later", u)
+                               continue
+                       }
+                       tset := computeUnionTypeSet(check, pos, u)
+                       if tset == &invalidTypeSet {
+                               continue // ignore invalid unions
+                       }
+                       terms = tset.terms
                case *TypeParam:
-                       // Embedding stand-alone type parameters is not permitted for now.
-                       // This case is handled during union parsing.
-                       unreachable()
+                       // Embedding stand-alone type parameters is not permitted.
+                       // Union parsing reports a (delayed) error, so we can ignore this entry.
+                       continue
                default:
-                       if typ == Typ[Invalid] {
+                       if u == Typ[Invalid] {
                                continue
                        }
                        if check != nil && !check.allowVersion(check.pkg, 1, 18) {
-                               check.errorf(atPos(pos), _InvalidIfaceEmbed, "%s is not an interface", typ)
+                               check.errorf(atPos(pos), _InvalidIfaceEmbed, "embedding non-interface type %s requires go1.18 or later", typ)
                                continue
                        }
-                       types = typ
+                       terms = termlist{{false, typ}}
                }
-               allTypes = intersect(allTypes, types)
+               // The type set of an interface is the intersection
+               // of the type sets of all its elements.
+               // Intersection cannot produce longer termlists and
+               // thus cannot overflow.
+               allTerms = allTerms.intersect(terms)
        }
        ityp.embedPos = nil // not needed anymore (errors have been reported)
 
@@ -272,7 +324,7 @@ func computeTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_TypeSet {
                sort.Sort(byUniqueMethodName(methods))
                ityp.tset.methods = methods
        }
-       ityp.tset.types = allTypes
+       ityp.tset.terms = allTerms
 
        return ityp.tset
 }
@@ -283,10 +335,10 @@ func sortMethods(list []*Func) {
 
 func assertSortedMethods(list []*Func) {
        if !debug {
-               panic("internal error: assertSortedMethods called outside debug mode")
+               panic("assertSortedMethods called outside debug mode")
        }
        if !sort.IsSorted(byUniqueMethodName(list)) {
-               panic("internal error: methods not sorted")
+               panic("methods not sorted")
        }
 }
 
@@ -296,3 +348,50 @@ type byUniqueMethodName []*Func
 func (a byUniqueMethodName) Len() int           { return len(a) }
 func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
 func (a byUniqueMethodName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+// invalidTypeSet is a singleton type set to signal an invalid type set
+// due to an error. It's also a valid empty type set, so consumers of
+// type sets may choose to ignore it.
+var invalidTypeSet _TypeSet
+
+// computeUnionTypeSet may be called with check == nil.
+// The result is &invalidTypeSet if the union overflows.
+func computeUnionTypeSet(check *Checker, pos token.Pos, utyp *Union) *_TypeSet {
+       if utyp.tset != nil {
+               return utyp.tset
+       }
+
+       // avoid infinite recursion (see also computeInterfaceTypeSet)
+       utyp.tset = new(_TypeSet)
+
+       var allTerms termlist
+       for _, t := range utyp.terms {
+               var terms termlist
+               switch u := under(t.typ).(type) {
+               case *Interface:
+                       terms = computeInterfaceTypeSet(check, pos, u).terms
+               case *TypeParam:
+                       // A stand-alone type parameters is not permitted as union term.
+                       // Union parsing reports a (delayed) error, so we can ignore this entry.
+                       continue
+               default:
+                       if t.typ == Typ[Invalid] {
+                               continue
+                       }
+                       terms = termlist{(*term)(t)}
+               }
+               // The type set of a union expression is the union
+               // of the type sets of each term.
+               allTerms = allTerms.union(terms)
+               if len(allTerms) > maxTermCount {
+                       if check != nil {
+                               check.errorf(atPos(pos), _Todo, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
+                       }
+                       utyp.tset = &invalidTypeSet
+                       return utyp.tset
+               }
+       }
+       utyp.tset.terms = allTerms
+
+       return utyp.tset
+}
diff --git a/src/go/types/typeset_test.go b/src/go/types/typeset_test.go
new file mode 100644 (file)
index 0000000..1c0eece
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2021 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 types
+
+import (
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "testing"
+)
+
+func TestInvalidTypeSet(t *testing.T) {
+       if !invalidTypeSet.IsEmpty() {
+               t.Error("invalidTypeSet is not empty")
+       }
+}
+
+func TestTypeSetString(t *testing.T) {
+       for body, want := range map[string]string{
+               "{}":            "𝓤",
+               "{int}":         "{int}",
+               "{~int}":        "{~int}",
+               "{int|string}":  "{int ∪ string}",
+               "{int; string}": "∅",
+
+               "{comparable}":              "{comparable}",
+               "{comparable; int}":         "{comparable; int}",
+               "{~int; comparable}":        "{comparable; ~int}",
+               "{int|string; comparable}":  "{comparable; int ∪ string}",
+               "{comparable; int; string}": "∅",
+
+               "{m()}":                         "{func (p.T).m()}",
+               "{m1(); m2() int }":             "{func (p.T).m1(); func (p.T).m2() int}",
+               "{error}":                       "{func (error).Error() string}",
+               "{m(); comparable}":             "{comparable; func (p.T).m()}",
+               "{m1(); comparable; m2() int }": "{comparable; func (p.T).m1(); func (p.T).m2() int}",
+               "{comparable; error}":           "{comparable; func (error).Error() string}",
+
+               "{m(); comparable; int|float32|string}": "{comparable; func (p.T).m(); int ∪ float32 ∪ string}",
+               "{m1(); int; m2(); comparable }":        "{comparable; func (p.T).m1(); func (p.T).m2(); int}",
+
+               "{E}; type E interface{}":           "𝓤",
+               "{E}; type E interface{int;string}": "∅",
+               "{E}; type E interface{comparable}": "{comparable}",
+       } {
+               // parse
+               src := "package p; type T interface" + body
+               fset := token.NewFileSet()
+               file, err := parser.ParseFile(fset, "p.go", src, parser.AllErrors)
+               if file == nil {
+                       t.Fatalf("%s: %v (invalid test case)", body, err)
+               }
+
+               // type check
+               var conf Config
+               pkg, err := conf.Check(file.Name.Name, fset, []*ast.File{file}, nil)
+               if err != nil {
+                       t.Fatalf("%s: %v (invalid test case)", body, err)
+               }
+
+               // lookup T
+               obj := pkg.scope.Lookup("T")
+               if obj == nil {
+                       t.Fatalf("%s: T not found (invalid test case)", body)
+               }
+               T, ok := under(obj.Type()).(*Interface)
+               if !ok {
+                       t.Fatalf("%s: %v is not an interface (invalid test case)", body, obj)
+               }
+
+               // verify test case
+               got := T.typeSet().String()
+               if got != want {
+                       t.Errorf("%s: got %s; want %s", body, got, want)
+               }
+       }
+}
+
+// TODO(gri) add more tests
index c0c69624ec703a4aea7f48e126118bd80920301f..e138af64880f58ac70d7d3bdc158b0f52f578e09 100644 (file)
@@ -8,8 +8,8 @@ package types
 
 import (
        "bytes"
-       "fmt"
        "go/token"
+       "strconv"
        "unicode/utf8"
 )
 
@@ -40,33 +40,18 @@ func RelativeTo(pkg *Package) Qualifier {
        }
 }
 
-// If gcCompatibilityMode is set, printing of types is modified
-// to match the representation of some types in the gc compiler:
-//
-//     - byte and rune lose their alias name and simply stand for
-//       uint8 and int32 respectively
-//     - embedded interfaces get flattened (the embedding info is lost,
-//       and certain recursive interface types cannot be printed anymore)
-//
-// This makes it easier to compare packages computed with the type-
-// checker vs packages imported from gc export data.
-//
-// Caution: This flag affects all uses of WriteType, globally.
-// It is only provided for testing in conjunction with
-// gc-generated data.
-//
-// This flag is exported in the x/tools/go/types package. We don't
-// need it at the moment in the std repo and so we don't export it
-// anymore. We should eventually try to remove it altogether.
-// TODO(gri) remove this
-var gcCompatibilityMode bool
-
 // TypeString returns the string representation of typ.
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 func TypeString(typ Type, qf Qualifier) string {
+       return typeString(typ, qf, false)
+}
+
+func typeString(typ Type, qf Qualifier, debug bool) string {
        var buf bytes.Buffer
-       WriteType(&buf, typ, qf)
+       w := newTypeWriter(&buf, qf)
+       w.debug = debug
+       w.typ(typ)
        return buf.String()
 }
 
@@ -74,174 +59,178 @@ func TypeString(typ Type, qf Qualifier) string {
 // The Qualifier controls the printing of
 // package-level objects, and may be nil.
 func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
-       writeType(buf, typ, qf, make([]Type, 0, 8))
+       newTypeWriter(buf, qf).typ(typ)
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
+       newTypeWriter(buf, qf).signature(sig)
+}
+
+type typeWriter struct {
+       buf   *bytes.Buffer
+       seen  map[Type]bool
+       qf    Qualifier
+       ctxt  *Context // if non-nil, we are type hashing
+       debug bool     // if true, write debug annotations
+}
+
+func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
+       return &typeWriter{buf, make(map[Type]bool), qf, nil, false}
+}
+
+func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
+       assert(ctxt != nil)
+       return &typeWriter{buf, make(map[Type]bool), nil, ctxt, false}
 }
 
-// instanceMarker is the prefix for an instantiated type
-// in "non-evaluated" instance form.
-const instanceMarker = '#'
-
-func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
-       // Theoretically, this is a quadratic lookup algorithm, but in
-       // practice deeply nested composite types with unnamed component
-       // types are uncommon. This code is likely more efficient than
-       // using a map.
-       for _, t := range visited {
-               if t == typ {
-                       fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
-                       return
+func (w *typeWriter) byte(b byte) {
+       if w.ctxt != nil {
+               if b == ' ' {
+                       b = '#'
                }
+               w.buf.WriteByte(b)
+               return
+       }
+       w.buf.WriteByte(b)
+       if b == ',' || b == ';' {
+               w.buf.WriteByte(' ')
        }
-       visited = append(visited, typ)
+}
+
+func (w *typeWriter) string(s string) {
+       w.buf.WriteString(s)
+}
+
+func (w *typeWriter) error(msg string) {
+       if w.ctxt != nil {
+               panic(msg)
+       }
+       w.buf.WriteString("<" + msg + ">")
+}
+
+func (w *typeWriter) typ(typ Type) {
+       if w.seen[typ] {
+               w.error("cycle to " + goTypeName(typ))
+               return
+       }
+       w.seen[typ] = true
+       defer delete(w.seen, typ)
 
        switch t := typ.(type) {
        case nil:
-               buf.WriteString("<nil>")
+               w.error("nil")
 
        case *Basic:
                // exported basic types go into package unsafe
                // (currently this is just unsafe.Pointer)
                if token.IsExported(t.name) {
                        if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil {
-                               writeTypeName(buf, obj, qf)
+                               w.typeName(obj)
                                break
                        }
                }
-
-               if gcCompatibilityMode {
-                       // forget the alias names
-                       switch t.kind {
-                       case Byte:
-                               t = Typ[Uint8]
-                       case Rune:
-                               t = Typ[Int32]
-                       }
-               }
-               buf.WriteString(t.name)
+               w.string(t.name)
 
        case *Array:
-               fmt.Fprintf(buf, "[%d]", t.len)
-               writeType(buf, t.elem, qf, visited)
+               w.byte('[')
+               w.string(strconv.FormatInt(t.len, 10))
+               w.byte(']')
+               w.typ(t.elem)
 
        case *Slice:
-               buf.WriteString("[]")
-               writeType(buf, t.elem, qf, visited)
+               w.string("[]")
+               w.typ(t.elem)
 
        case *Struct:
-               buf.WriteString("struct{")
+               w.string("struct{")
                for i, f := range t.fields {
                        if i > 0 {
-                               buf.WriteString("; ")
+                               w.byte(';')
                        }
                        // This doesn't do the right thing for embedded type
                        // aliases where we should print the alias name, not
                        // the aliased type (see issue #44410).
                        if !f.embedded {
-                               buf.WriteString(f.name)
-                               buf.WriteByte(' ')
+                               w.string(f.name)
+                               w.byte(' ')
                        }
-                       writeType(buf, f.typ, qf, visited)
+                       w.typ(f.typ)
                        if tag := t.Tag(i); tag != "" {
-                               fmt.Fprintf(buf, " %q", tag)
+                               w.byte(' ')
+                               // TODO(rfindley) If tag contains blanks, replacing them with '#'
+                               //                in Context.TypeHash may produce another tag
+                               //                accidentally.
+                               w.string(strconv.Quote(tag))
                        }
                }
-               buf.WriteByte('}')
+               w.byte('}')
 
        case *Pointer:
-               buf.WriteByte('*')
-               writeType(buf, t.base, qf, visited)
+               w.byte('*')
+               w.typ(t.base)
 
        case *Tuple:
-               writeTuple(buf, t, false, qf, visited)
+               w.tuple(t, false)
 
        case *Signature:
-               buf.WriteString("func")
-               writeSignature(buf, t, qf, visited)
+               w.string("func")
+               w.signature(t)
 
        case *Union:
-               if t.IsEmpty() {
-                       buf.WriteString("⊥")
+               // Unions only appear as (syntactic) embedded elements
+               // in interfaces and syntactically cannot be empty.
+               if t.Len() == 0 {
+                       w.error("empty union")
                        break
                }
                for i, t := range t.terms {
                        if i > 0 {
-                               buf.WriteByte('|')
+                               w.byte('|')
                        }
                        if t.tilde {
-                               buf.WriteByte('~')
+                               w.byte('~')
                        }
-                       writeType(buf, t.typ, qf, visited)
+                       w.typ(t.typ)
                }
 
        case *Interface:
-               // We write the source-level methods and embedded types rather
-               // than the actual method set since resolved method signatures
-               // may have non-printable cycles if parameters have embedded
-               // interface types that (directly or indirectly) embed the
-               // current interface. For instance, consider the result type
-               // of m:
-               //
-               //     type T interface{
-               //         m() interface{ T }
-               //     }
-               //
-               buf.WriteString("interface{")
-               empty := true
-               if gcCompatibilityMode {
-                       // print flattened interface
-                       // (useful to compare against gc-generated interfaces)
-                       tset := t.typeSet()
-                       for i, m := range tset.methods {
-                               if i > 0 {
-                                       buf.WriteString("; ")
-                               }
-                               buf.WriteString(m.name)
-                               writeSignature(buf, m.typ.(*Signature), qf, visited)
-                               empty = false
-                       }
-                       if !empty && tset.types != nil {
-                               buf.WriteString("; ")
-                       }
-                       if tset.types != nil {
-                               buf.WriteString("type ")
-                               writeType(buf, tset.types, qf, visited)
-                       }
-               } else {
-                       // print explicit interface methods and embedded types
-                       for i, m := range t.methods {
-                               if i > 0 {
-                                       buf.WriteString("; ")
-                               }
-                               buf.WriteString(m.name)
-                               writeSignature(buf, m.typ.(*Signature), qf, visited)
-                               empty = false
-                       }
-                       if !empty && len(t.embeddeds) > 0 {
-                               buf.WriteString("; ")
+               if t.implicit {
+                       if len(t.methods) == 0 && len(t.embeddeds) == 1 {
+                               w.typ(t.embeddeds[0])
+                               break
                        }
-                       for i, typ := range t.embeddeds {
-                               if i > 0 {
-                                       buf.WriteString("; ")
-                               }
-                               writeType(buf, typ, qf, visited)
-                               empty = false
+                       // Something's wrong with the implicit interface.
+                       // Print it as such and continue.
+                       w.string("/* implicit */ ")
+               }
+               w.string("interface{")
+               first := true
+               for _, m := range t.methods {
+                       if !first {
+                               w.byte(';')
                        }
+                       first = false
+                       w.string(m.name)
+                       w.signature(m.typ.(*Signature))
                }
-               // print /* incomplete */ if needed to satisfy existing tests
-               // TODO(gri) get rid of this eventually
-               if debug && t.tset == nil {
-                       if !empty {
-                               buf.WriteByte(' ')
+               for _, typ := range t.embeddeds {
+                       if !first {
+                               w.byte(';')
                        }
-                       buf.WriteString("/* incomplete */")
+                       first = false
+                       w.typ(typ)
                }
-               buf.WriteByte('}')
+               w.byte('}')
 
        case *Map:
-               buf.WriteString("map[")
-               writeType(buf, t.key, qf, visited)
-               buf.WriteByte(']')
-               writeType(buf, t.elem, qf, visited)
+               w.string("map[")
+               w.typ(t.key)
+               w.byte(']')
+               w.typ(t.elem)
 
        case *Chan:
                var s string
@@ -258,180 +247,142 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                case RecvOnly:
                        s = "<-chan "
                default:
-                       panic("unreachable")
+                       w.error("unknown channel direction")
                }
-               buf.WriteString(s)
+               w.string(s)
                if parens {
-                       buf.WriteByte('(')
+                       w.byte('(')
                }
-               writeType(buf, t.elem, qf, visited)
+               w.typ(t.elem)
                if parens {
-                       buf.WriteByte(')')
+                       w.byte(')')
                }
 
        case *Named:
-               if t.instance != nil {
-                       buf.WriteByte(instanceMarker)
-               }
-               writeTypeName(buf, t.obj, qf)
+               w.typePrefix(t)
+               w.typeName(t.obj)
                if t.targs != nil {
                        // instantiated type
-                       buf.WriteByte('[')
-                       writeTypeList(buf, t.targs, qf, visited)
-                       buf.WriteByte(']')
-               } else if t.TParams().Len() != 0 {
+                       w.typeList(t.targs.list())
+               } else if w.ctxt == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TypeParams
                        // parameterized type
-                       writeTParamList(buf, t.TParams().list(), qf, visited)
+                       w.tParamList(t.TypeParams().list())
                }
 
        case *TypeParam:
-               s := "?"
-               if t.obj != nil {
-                       // Optionally write out package for typeparams (like Named).
-                       // TODO(rfindley): this is required for import/export, so
-                       // we maybe need a separate function that won't be changed
-                       // for debugging purposes.
-                       if t.obj.pkg != nil {
-                               writePackage(buf, t.obj.pkg, qf)
-                       }
-                       s = t.obj.name
+               if t.obj == nil {
+                       w.error("unnamed type parameter")
+                       break
+               }
+               w.string(t.obj.name)
+               if w.debug || w.ctxt != nil {
+                       w.string(subscript(t.id))
                }
-               buf.WriteString(s + subscript(t.id))
-
-       case *top:
-               buf.WriteString("⊤")
 
        default:
                // For externally defined implementations of Type.
                // Note: In this case cycles won't be caught.
-               buf.WriteString(t.String())
+               w.string(t.String())
+       }
+}
+
+// If w.ctxt is non-nil, typePrefix writes a unique prefix for the named type t
+// based on the types already observed by w.ctxt. If w.ctxt is nil, it does
+// nothing.
+func (w *typeWriter) typePrefix(t *Named) {
+       if w.ctxt != nil {
+               w.string(strconv.Itoa(w.ctxt.idForType(t)))
        }
 }
 
-func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
+func (w *typeWriter) typeList(list []Type) {
+       w.byte('[')
        for i, typ := range list {
                if i > 0 {
-                       buf.WriteString(", ")
+                       w.byte(',')
                }
-               writeType(buf, typ, qf, visited)
+               w.typ(typ)
        }
+       w.byte(']')
 }
 
-func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
-       // TODO(rFindley) compare this with the corresponding implementation in types2
-       buf.WriteString("[")
+func (w *typeWriter) tParamList(list []*TypeParam) {
+       w.byte('[')
        var prev Type
-       for i, p := range list {
-               // TODO(rFindley) support 'any' sugar here.
-               var b Type = &emptyInterface
-               if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
-                       b = t.bound
+       for i, tpar := range list {
+               // Determine the type parameter and its constraint.
+               // list is expected to hold type parameter names,
+               // but don't crash if that's not the case.
+               if tpar == nil {
+                       w.error("nil type parameter")
+                       continue
                }
                if i > 0 {
-                       if b != prev {
-                               // type bound changed - write previous one before advancing
-                               buf.WriteByte(' ')
-                               writeType(buf, prev, qf, visited)
+                       if tpar.bound != prev {
+                               // bound changed - write previous one before advancing
+                               w.byte(' ')
+                               w.typ(prev)
                        }
-                       buf.WriteString(", ")
-               }
-               prev = b
-
-               if t, _ := p.typ.(*TypeParam); t != nil {
-                       writeType(buf, t, qf, visited)
-               } else {
-                       buf.WriteString(p.name)
+                       w.byte(',')
                }
+               prev = tpar.bound
+               w.typ(tpar)
        }
        if prev != nil {
-               buf.WriteByte(' ')
-               writeType(buf, prev, qf, visited)
+               w.byte(' ')
+               w.typ(prev)
        }
-       buf.WriteByte(']')
+       w.byte(']')
 }
 
-func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
-       if obj == nil {
-               buf.WriteString("<Named w/o object>")
-               return
-       }
+func (w *typeWriter) typeName(obj *TypeName) {
        if obj.pkg != nil {
-               writePackage(buf, obj.pkg, qf)
-       }
-       buf.WriteString(obj.name)
-
-       if instanceHashing != 0 {
-               // For local defined types, use the (original!) TypeName's scope
-               // numbers to disambiguate.
-               typ := obj.typ.(*Named)
-               // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
-               //           and whether the loop can iterate more than twice.
-               //           (It seems somehow connected to instance types.)
-               for typ.orig != typ {
-                       typ = typ.orig
-               }
-               writeScopeNumbers(buf, typ.obj.parent)
-       }
-}
-
-// writeScopeNumbers writes the number sequence for this scope to buf
-// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
-// If a scope is nil or has no parent (such as a package scope), nothing
-// is written.
-func writeScopeNumbers(buf *bytes.Buffer, s *Scope) {
-       if s != nil && s.number > 0 {
-               writeScopeNumbers(buf, s.parent)
-               fmt.Fprintf(buf, ".%d", s.number)
+               writePackage(w.buf, obj.pkg, w.qf)
        }
+       w.string(obj.name)
 }
 
-func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
-       buf.WriteByte('(')
+func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
+       w.byte('(')
        if tup != nil {
                for i, v := range tup.vars {
                        if i > 0 {
-                               buf.WriteString(", ")
+                               w.byte(',')
                        }
-                       if v.name != "" {
-                               buf.WriteString(v.name)
-                               buf.WriteByte(' ')
+                       // parameter names are ignored for type identity and thus type hashes
+                       if w.ctxt == nil && v.name != "" {
+                               w.string(v.name)
+                               w.byte(' ')
                        }
                        typ := v.typ
                        if variadic && i == len(tup.vars)-1 {
                                if s, ok := typ.(*Slice); ok {
-                                       buf.WriteString("...")
+                                       w.string("...")
                                        typ = s.elem
                                } else {
                                        // special case:
                                        // append(s, "foo"...) leads to signature func([]byte, string...)
                                        if t := asBasic(typ); t == nil || t.kind != String {
-                                               panic("internal error: string type expected")
+                                               w.error("expected string type")
+                                               continue
                                        }
-                                       writeType(buf, typ, qf, visited)
-                                       buf.WriteString("...")
+                                       w.typ(typ)
+                                       w.string("...")
                                        continue
                                }
                        }
-                       writeType(buf, typ, qf, visited)
+                       w.typ(typ)
                }
        }
-       buf.WriteByte(')')
-}
-
-// WriteSignature writes the representation of the signature sig to buf,
-// without a leading "func" keyword.
-// The Qualifier controls the printing of
-// package-level objects, and may be nil.
-func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
-       writeSignature(buf, sig, qf, make([]Type, 0, 8))
+       w.byte(')')
 }
 
-func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
-       if sig.TParams().Len() != 0 {
-               writeTParamList(buf, sig.TParams().list(), qf, visited)
+func (w *typeWriter) signature(sig *Signature) {
+       if sig.TypeParams().Len() != 0 {
+               w.tParamList(sig.TypeParams().list())
        }
 
-       writeTuple(buf, sig.params, sig.variadic, qf, visited)
+       w.tuple(sig.params, sig.variadic)
 
        n := sig.results.Len()
        if n == 0 {
@@ -439,15 +390,15 @@ func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []T
                return
        }
 
-       buf.WriteByte(' ')
-       if n == 1 && sig.results.vars[0].name == "" {
-               // single unnamed result
-               writeType(buf, sig.results.vars[0].typ, qf, visited)
+       w.byte(' ')
+       if n == 1 && (w.ctxt != nil || sig.results.vars[0].name == "") {
+               // single unnamed result (if type hashing, name must be ignored)
+               w.typ(sig.results.vars[0].typ)
                return
        }
 
        // multiple or named result(s)
-       writeTuple(buf, sig.results, false, qf, visited)
+       w.tuple(sig.results, false)
 }
 
 // subscript returns the decimal (utf8) representation of x using subscript digits.
index f02c0d9c18db8aba78693058341612fe25ad6b04..5718ffcc6c182ca923f48f7e262df3ed9deecbfc 100644 (file)
@@ -98,10 +98,6 @@ var independentTestTypes = []testEntry{
        dup("interface{int|float32|complex128}"),
        dup("interface{int|~float32|~complex128}"),
 
-       // TODO(rFindley) uncomment this once this AST is accepted, and add more test
-       // cases.
-       // dup(`interface{type int, float32, complex128}`),
-
        // maps
        dup("map[string]int"),
        {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
@@ -144,62 +140,6 @@ func TestTypeString(t *testing.T) {
        }
 }
 
-func TestIncompleteInterfaces(t *testing.T) {
-       if !Debug {
-               t.Skip("requires type checker to be compiled with debug = true")
-       }
-
-       sig := NewSignature(nil, nil, nil, false)
-       m := NewFunc(token.NoPos, nil, "m", sig)
-       for _, test := range []struct {
-               typ  *Interface
-               want string
-       }{
-               {new(Interface), "interface{/* incomplete */}"},
-               {new(Interface).Complete(), "interface{}"},
-
-               {NewInterface(nil, nil), "interface{}"},
-               {NewInterface(nil, nil).Complete(), "interface{}"},
-               {NewInterface([]*Func{}, nil), "interface{}"},
-               {NewInterface([]*Func{}, nil).Complete(), "interface{}"},
-               {NewInterface(nil, []*Named{}), "interface{}"},
-               {NewInterface(nil, []*Named{}).Complete(), "interface{}"},
-               {NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"},
-               {NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"},
-               {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"},
-               {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"},
-               {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"},
-               {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"},
-               {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"},
-
-               {NewInterfaceType(nil, nil), "interface{}"},
-               {NewInterfaceType(nil, nil).Complete(), "interface{}"},
-               {NewInterfaceType([]*Func{}, nil), "interface{}"},
-               {NewInterfaceType([]*Func{}, nil).Complete(), "interface{}"},
-               {NewInterfaceType(nil, []Type{}), "interface{}"},
-               {NewInterfaceType(nil, []Type{}).Complete(), "interface{}"},
-               {NewInterfaceType([]*Func{m}, nil), "interface{m() /* incomplete */}"},
-               {NewInterfaceType([]*Func{m}, nil).Complete(), "interface{m()}"},
-               {NewInterfaceType(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"},
-               {NewInterfaceType(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"},
-               {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"},
-               {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"},
-               {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"},
-       } {
-               got := test.typ.String()
-               if got != test.want {
-                       t.Errorf("got: %s, want: %s", got, test.want)
-               }
-       }
-}
-
-// newDefined creates a new defined type named T with the given underlying type.
-// Helper function for use with TestIncompleteInterfaces only.
-func newDefined(underlying Type) *Named {
-       tname := NewTypeName(token.NoPos, nil, "T", nil)
-       return NewNamed(tname, underlying, nil)
-}
-
 func TestQualifiedTypeString(t *testing.T) {
        p, _ := pkgFor("p.go", "package p; type T int", nil)
        q, _ := pkgFor("q.go", "package q", nil)
index dbd055a580c59388b23f6157d74445f426008e15..6b6782100084f66aa1ea9add9c35e2910b05d17c 100644 (file)
@@ -4,13 +4,10 @@
 
 package types
 
-// TODO(gri) use a different symbol instead of ⊤ for the set of all types
-//           (⊤ is hard to distinguish from T in some fonts)
-
 // A term describes elementary type sets:
 //
 //   ∅:  (*term)(nil)     == ∅                      // set of no types (empty set)
-//   ⊤:  &term{}          == ⊤                      // set of all types
+//   𝓤:  &term{}          == 𝓤                      // set of all types (𝓤niverse)
 //   T:  &term{false, T}  == {T}                    // set of type T
 //  ~t:  &term{true, t}   == {t' | under(t') == t}  // set of types with underlying type t
 //
@@ -24,7 +21,7 @@ func (x *term) String() string {
        case x == nil:
                return "∅"
        case x.typ == nil:
-               return "â\8a¤"
+               return "ð\9d\93¤"
        case x.tilde:
                return "~" + x.typ.String()
        default:
@@ -41,7 +38,7 @@ func (x *term) equal(y *term) bool {
        case x.typ == nil || y.typ == nil:
                return x.typ == y.typ
        }
-       // ∅ ⊂ x, y ⊂ â\8a¤
+       // ∅ ⊂ x, y ⊂ ð\9d\93¤
 
        return x.tilde == y.tilde && Identical(x.typ, y.typ)
 }
@@ -57,11 +54,11 @@ func (x *term) union(y *term) (_, _ *term) {
        case y == nil:
                return x, nil // x ∪ ∅ == x
        case x.typ == nil:
-               return x, nil // â\8a¤ â\88ª y == â\8a¤
+               return x, nil // ð\9d\93¤ â\88ª y == ð\9d\93¤
        case y.typ == nil:
-               return y, nil // x ∪ â\8a¤ == â\8a¤
+               return y, nil // x ∪ ð\9d\93¤ == ð\9d\93¤
        }
-       // ∅ ⊂ x, y ⊂ â\8a¤
+       // ∅ ⊂ x, y ⊂ ð\9d\93¤
 
        if x.disjoint(y) {
                return x, y // x ∪ y == (x, y) if x ∩ y == ∅
@@ -85,11 +82,11 @@ func (x *term) intersect(y *term) *term {
        case x == nil || y == nil:
                return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅
        case x.typ == nil:
-               return y // â\8a¤ â\88© y == y
+               return y // ð\9d\93¤ â\88© y == y
        case y.typ == nil:
-               return x // x ∩ â\8a¤ == x
+               return x // x ∩ ð\9d\93¤ == x
        }
-       // ∅ ⊂ x, y ⊂ â\8a¤
+       // ∅ ⊂ x, y ⊂ ð\9d\93¤
 
        if x.disjoint(y) {
                return nil // x ∩ y == ∅ if x ∩ y == ∅
@@ -113,9 +110,9 @@ func (x *term) includes(t Type) bool {
        case x == nil:
                return false // t ∈ ∅ == false
        case x.typ == nil:
-               return true // t ∈ â\8a¤ == true
+               return true // t ∈ ð\9d\93¤ == true
        }
-       // ∅ ⊂ x ⊂ â\8a¤
+       // ∅ ⊂ x ⊂ ð\9d\93¤
 
        u := t
        if x.tilde {
@@ -133,11 +130,11 @@ func (x *term) subsetOf(y *term) bool {
        case y == nil:
                return false // x ⊆ ∅ == false since x != ∅
        case y.typ == nil:
-               return true // x ⊆ â\8a¤ == true
+               return true // x ⊆ ð\9d\93¤ == true
        case x.typ == nil:
-               return false // â\8a¤ â\8a\86 y == false since y != â\8a¤
+               return false // ð\9d\93¤ â\8a\86 y == false since y != ð\9d\93¤
        }
-       // ∅ ⊂ x, y ⊂ â\8a¤
+       // ∅ ⊂ x, y ⊂ ð\9d\93¤
 
        if x.disjoint(y) {
                return false // x ⊆ y == false if x ∩ y == ∅
@@ -154,6 +151,9 @@ func (x *term) subsetOf(y *term) bool {
 // disjoint reports whether x ∩ y == ∅.
 // x.typ and y.typ must not be nil.
 func (x *term) disjoint(y *term) bool {
+       if debug && (x.typ == nil || y.typ == nil) {
+               panic("invalid argument(s)")
+       }
        ux := x.typ
        if y.tilde {
                ux = under(ux)
index 391ff3e05f8b66f97a2ca5b77e4259f90863df1c..27f132a1d249a2df23599acbd51123680399d2fa 100644 (file)
@@ -5,18 +5,24 @@
 package types
 
 import (
+       "go/token"
        "strings"
        "testing"
 )
 
+var myInt = func() Type {
+       tname := NewTypeName(token.NoPos, nil, "myInt", nil)
+       return NewNamed(tname, Typ[Int], nil)
+}()
+
 var testTerms = map[string]*term{
        "∅":       nil,
-       "â\8a¤":       {},
+       "ð\9d\93¤":       {},
        "int":     {false, Typ[Int]},
        "~int":    {true, Typ[Int]},
        "string":  {false, Typ[String]},
        "~string": {true, Typ[String]},
-       // TODO(gri) add a defined type
+       "myInt":   {false, myInt},
 }
 
 func TestTermString(t *testing.T) {
@@ -46,15 +52,19 @@ func testTerm(name string) *term {
 func TestTermEqual(t *testing.T) {
        for _, test := range []string{
                "∅ ∅ T",
-               "â\8a¤ â\8a¤ T",
+               "ð\9d\93¤ ð\9d\93¤ T",
                "int int T",
                "~int ~int T",
-               "∅ ⊤ F",
+               "myInt myInt T",
+               "∅ 𝓤 F",
                "∅ int F",
                "∅ ~int F",
-               "⊤ int F",
-               "⊤ ~int F",
+               "𝓤 int F",
+               "𝓤 ~int F",
+               "𝓤 myInt F",
                "int ~int F",
+               "int myInt F",
+               "~int myInt F",
        } {
                args := split(test, 3)
                x := testTerm(args[0])
@@ -74,28 +84,36 @@ func TestTermEqual(t *testing.T) {
 func TestTermUnion(t *testing.T) {
        for _, test := range []string{
                "∅ ∅ ∅ ∅",
-               "∅ â\8a¤ â\8a¤ â\88\85",
+               "∅ ð\9d\93¤ ð\9d\93¤ â\88\85",
                "∅ int int ∅",
                "∅ ~int ~int ∅",
-               "⊤ ⊤ ⊤ ∅",
-               "⊤ int ⊤ ∅",
-               "⊤ ~int ⊤ ∅",
+               "∅ myInt myInt ∅",
+               "𝓤 𝓤 𝓤 ∅",
+               "𝓤 int 𝓤 ∅",
+               "𝓤 ~int 𝓤 ∅",
+               "𝓤 myInt 𝓤 ∅",
                "int int int ∅",
                "int ~int ~int ∅",
                "int string int string",
                "int ~string int ~string",
+               "int myInt int myInt",
                "~int ~string ~int ~string",
+               "~int myInt ~int ∅",
 
                // union is symmetric, but the result order isn't - repeat symmetric cases explictly
-               "â\8a¤ â\88\85 â\8a¤ â\88\85",
+               "ð\9d\93¤ â\88\85 ð\9d\93¤ â\88\85",
                "int ∅ int ∅",
                "~int ∅ ~int ∅",
-               "int ⊤ ⊤ ∅",
-               "~int ⊤ ⊤ ∅",
+               "myInt ∅ myInt ∅",
+               "int 𝓤 𝓤 ∅",
+               "~int 𝓤 𝓤 ∅",
+               "myInt 𝓤 𝓤 ∅",
                "~int int ~int ∅",
                "string int string int",
                "~string int ~string int",
+               "myInt int myInt int",
                "~string ~int ~string ~int",
+               "myInt ~int ~int ∅",
        } {
                args := split(test, 4)
                x := testTerm(args[0])
@@ -111,17 +129,21 @@ func TestTermUnion(t *testing.T) {
 func TestTermIntersection(t *testing.T) {
        for _, test := range []string{
                "∅ ∅ ∅",
-               "∅ â\8a¤ â\88\85",
+               "∅ ð\9d\93¤ â\88\85",
                "∅ int ∅",
                "∅ ~int ∅",
-               "⊤ ⊤ ⊤",
-               "⊤ int int",
-               "⊤ ~int ~int",
+               "∅ myInt ∅",
+               "𝓤 𝓤 𝓤",
+               "𝓤 int int",
+               "𝓤 ~int ~int",
+               "𝓤 myInt myInt",
                "int int int",
                "int ~int int",
                "int string ∅",
                "int ~string ∅",
+               "int string ∅",
                "~int ~string ∅",
+               "~int myInt myInt",
        } {
                args := split(test, 3)
                x := testTerm(args[0])
@@ -141,11 +163,13 @@ func TestTermIntersection(t *testing.T) {
 func TestTermIncludes(t *testing.T) {
        for _, test := range []string{
                "∅ int F",
-               "â\8a¤ int T",
+               "ð\9d\93¤ int T",
                "int int T",
                "~int int T",
+               "~int myInt T",
                "string int F",
                "~string int F",
+               "myInt int F",
        } {
                args := split(test, 3)
                x := testTerm(args[0])
@@ -160,15 +184,22 @@ func TestTermIncludes(t *testing.T) {
 func TestTermSubsetOf(t *testing.T) {
        for _, test := range []string{
                "∅ ∅ T",
-               "â\8a¤ â\8a¤ T",
+               "ð\9d\93¤ ð\9d\93¤ T",
                "int int T",
                "~int ~int T",
-               "∅ ⊤ T",
+               "myInt myInt T",
+               "∅ 𝓤 T",
                "∅ int T",
                "∅ ~int T",
-               "⊤ int F",
-               "⊤ ~int F",
+               "∅ myInt T",
+               "𝓤 int F",
+               "𝓤 ~int F",
+               "𝓤 myInt F",
                "int ~int T",
+               "int myInt F",
+               "~int myInt F",
+               "myInt int F",
+               "myInt ~int T",
        } {
                args := split(test, 3)
                x := testTerm(args[0])
@@ -187,7 +218,11 @@ func TestTermDisjoint(t *testing.T) {
                "int ~int F",
                "int string T",
                "int ~string T",
+               "int myInt T",
                "~int ~string T",
+               "~int myInt F",
+               "string myInt T",
+               "~string myInt T",
        } {
                args := split(test, 3)
                x := testTerm(args[0])
index a812ba6519ae4b7dded1af4031dd20f6058713d0..e1d942a5c6f2562554f9b2be6d1e5b8d23c4d73f 100644 (file)
@@ -30,7 +30,15 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
        switch obj {
        case nil:
                if e.Name == "_" {
-                       check.error(e, _InvalidBlank, "cannot use _ as value or type")
+                       // Blank identifiers are never declared, but the current identifier may
+                       // be a placeholder for a receiver type parameter. In this case we can
+                       // resolve its type and object from Checker.recvTParamMap.
+                       if tpar := check.recvTParamMap[e]; tpar != nil {
+                               x.mode = typexpr
+                               x.typ = tpar
+                       } else {
+                               check.error(e, _InvalidBlank, "cannot use _ as value or type")
+                       }
                } else {
                        check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name)
                }
@@ -38,12 +46,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
        case universeAny, universeComparable:
                if !check.allowVersion(check.pkg, 1, 18) {
                        check.errorf(e, _UndeclaredName, "undeclared name: %s (requires version go1.18 or later)", e.Name)
-                       return
-               }
-               // If we allow "any" for general use, this if-statement can be removed (issue #33232).
-               if obj == universeAny {
-                       check.error(e, _Todo, "cannot use any outside constraint position")
-                       return
+                       return // avoid follow-on errors
                }
        }
        check.recordUse(e, obj)
@@ -134,41 +137,26 @@ func (check *Checker) typ(e ast.Expr) Type {
 }
 
 // varType type-checks the type expression e and returns its type, or Typ[Invalid].
-// The type must not be an (uninstantiated) generic type and it must be ordinary
-// (see ordinaryType).
+// The type must not be an (uninstantiated) generic type and it must not be a
+// constraint interface.
 func (check *Checker) varType(e ast.Expr) Type {
        typ := check.definedType(e, nil)
-       check.ordinaryType(e, typ)
-       return typ
-}
-
-// ordinaryType reports an error if typ is an interface type containing
-// type lists or is (or embeds) the predeclared type comparable.
-func (check *Checker) ordinaryType(pos positioner, typ Type) {
-       // We don't want to call under() (via asInterface) or complete interfaces
-       // while we are in the middle of type-checking parameter declarations that
-       // might belong to interface methods. Delay this check to the end of
-       // type-checking.
+       // We don't want to call under() (via toInterface) or complete interfaces while we
+       // are in the middle of type-checking parameter declarations that might belong to
+       // interface methods. Delay this check to the end of type-checking.
        check.later(func() {
                if t := asInterface(typ); t != nil {
-                       tset := computeTypeSet(check, pos.Pos(), t) // TODO(gri) is this the correct position?
-                       if tset.types != nil {
-                               check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", tset.types)
-                               return
-                       }
-                       if tset.IsComparable() {
-                               check.softErrorf(pos, _Todo, "interface is (or embeds) comparable")
+                       tset := computeInterfaceTypeSet(check, e.Pos(), t) // TODO(gri) is this the correct position?
+                       if !tset.IsMethodSet() {
+                               if tset.comparable {
+                                       check.softErrorf(e, _Todo, "interface is (or embeds) comparable")
+                               } else {
+                                       check.softErrorf(e, _Todo, "interface contains type constraints")
+                               }
                        }
                }
        })
-}
 
-// anyType type-checks the type expression e and returns its type, or Typ[Invalid].
-// The type may be generic or instantiated.
-func (check *Checker) anyType(e ast.Expr) Type {
-       typ := check.typInternal(e, nil)
-       assert(isTyped(typ))
-       check.recordTypeAndValue(e, typexpr, typ, nil)
        return typ
 }
 
@@ -222,9 +210,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
                        if T != nil {
                                // Calling under() here may lead to endless instantiations.
                                // Test case: type T[P any] *T[P]
-                               // TODO(gri) investigate if that's a bug or to be expected
-                               // (see also analogous comment in Checker.instantiate).
-                               under = T.Underlying()
+                               under = safeUnderlying(T)
                        }
                        if T == under {
                                check.trace(e0.Pos(), "=> %s // %s", T, goTypeName(T))
@@ -272,9 +258,11 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
                        check.errorf(&x, _NotAType, "%s is not a type", &x)
                }
 
-       case *ast.IndexExpr, *ast.MultiIndexExpr:
+       case *ast.IndexExpr, *ast.IndexListExpr:
                ix := typeparams.UnpackIndexExpr(e)
-               // TODO(rfindley): type instantiation should require go1.18
+               if !check.allowVersion(check.pkg, 1, 18) {
+                       check.softErrorf(inNode(e, ix.Lbrack), _Todo, "type instantiation requires go1.18 or later")
+               }
                return check.instantiatedType(ix.X, ix.Indices, def)
 
        case *ast.ParenExpr:
@@ -384,37 +372,25 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
        return typ
 }
 
-// typeOrNil type-checks the type expression (or nil value) e
-// and returns the type of e, or nil. If e is a type, it must
-// not be an (uninstantiated) generic type.
-// If e is neither a type nor nil, typeOrNil returns Typ[Invalid].
-// TODO(gri) should we also disallow non-var types?
-func (check *Checker) typeOrNil(e ast.Expr) Type {
-       var x operand
-       check.rawExpr(&x, e, nil)
-       switch x.mode {
-       case invalid:
-               // ignore - error reported before
-       case novalue:
-               check.errorf(&x, _NotAType, "%s used as type", &x)
-       case typexpr:
-               check.instantiatedOperand(&x)
-               return x.typ
-       case value:
-               if x.isNil() {
-                       return nil
-               }
-               fallthrough
-       default:
-               check.errorf(&x, _NotAType, "%s is not a type", &x)
+func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named) (res Type) {
+       if trace {
+               check.trace(x.Pos(), "-- instantiating %s with %s", x, targsx)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       // Don't format the underlying here. It will always be nil.
+                       check.trace(x.Pos(), "=> %s", res)
+               }()
+       }
+
+       gtyp := check.genericType(x, true)
+       if gtyp == Typ[Invalid] {
+               return gtyp // error already reported
        }
-       return Typ[Invalid]
-}
 
-func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named) Type {
-       base := check.genericType(x, true)
-       if base == Typ[Invalid] {
-               return base // error already reported
+       origin, _ := gtyp.(*Named)
+       if origin == nil {
+               panic(fmt.Sprintf("%v: cannot instantiate %v", x.Pos(), gtyp))
        }
 
        // evaluate arguments
@@ -430,23 +406,80 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
                posList[i] = arg.Pos()
        }
 
-       typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true)
-       def.setUnderlying(typ)
+       // create the instance
+       h := check.conf.Context.typeHash(origin, targs)
+       // targs may be incomplete, and require inference. In any case we should de-duplicate.
+       inst := check.conf.Context.typeForHash(h, nil)
+       // If inst is non-nil, we can't just return here. Inst may have been
+       // constructed via recursive substitution, in which case we wouldn't do the
+       // validation below. Ensure that the validation (and resulting errors) runs
+       // for each instantiated type in the source.
+       if inst == nil {
+               tname := NewTypeName(x.Pos(), origin.obj.pkg, origin.obj.name, nil)
+               inst = check.newNamed(tname, origin, nil, nil, nil) // underlying, methods and tparams are set when named is resolved
+               inst.targs = NewTypeList(targs)
+               inst = check.conf.Context.typeForHash(h, inst)
+       }
+       def.setUnderlying(inst)
+
+       inst.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, []*Func) {
+               tparams := origin.TypeParams().list()
+
+               inferred := targs
+               if len(targs) < len(tparams) {
+                       // If inference fails, len(inferred) will be 0, and inst.underlying will
+                       // be set to Typ[Invalid] in expandNamed.
+                       inferred = check.infer(x, tparams, targs, nil, nil)
+                       if len(inferred) > len(targs) {
+                               inst.targs = NewTypeList(inferred)
+                       }
+               }
+
+               check.recordInstance(x, inferred, inst)
+               return expandNamed(ctxt, n, x.Pos())
+       }
 
-       // make sure we check instantiation works at least once
-       // and that the resulting type is valid
+       // origin.tparams may not be set up, so we need to do expansion later.
        check.later(func() {
-               t := expand(typ)
-               check.validType(t, nil)
+               // This is an instance from the source, not from recursive substitution,
+               // and so it must be resolved during type-checking so that we can report
+               // errors.
+               inst.resolve(check.conf.Context)
+               // Since check is non-nil, we can still mutate inst. Unpinning the resolver
+               // frees some memory.
+               inst.resolver = nil
+
+               if check.validateTArgLen(x.Pos(), inst.tparams.Len(), inst.targs.Len()) {
+                       if i, err := check.verify(x.Pos(), inst.tparams.list(), inst.targs.list()); err != nil {
+                               // best position for error reporting
+                               pos := x.Pos()
+                               if i < len(posList) {
+                                       pos = posList[i]
+                               }
+                               check.softErrorf(atPos(pos), _Todo, err.Error())
+                       } else {
+                               check.mono.recordInstance(check.pkg, x.Pos(), inst.tparams.list(), inst.targs.list(), posList)
+                       }
+               }
+
+               check.validType(inst, nil)
        })
 
-       return typ
+       return inst
 }
 
 // arrayLength type-checks the array length expression e
 // and returns the constant length >= 0, or a value < 0
 // to indicate an error (and thus an unknown length).
 func (check *Checker) arrayLength(e ast.Expr) int64 {
+       // If e is an undeclared identifier, the array declaration might be an
+       // attempt at a parameterized type declaration with missing constraint.
+       // Provide a better error message than just "undeclared name: X".
+       if name, _ := e.(*ast.Ident); name != nil && check.lookup(name.Name) == nil {
+               check.errorf(name, _InvalidArrayLen, "undeclared name %s for array length", name.Name)
+               return -1
+       }
+
        var x operand
        check.expr(&x, e)
        if x.mode != constant_ {
@@ -455,6 +488,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
                }
                return -1
        }
+
        if isUntyped(x.typ) || isInteger(x.typ) {
                if val := constant.ToInt(x.val); val.Kind() == constant.Int {
                        if representableConst(val, check, Typ[Int], nil) {
@@ -466,6 +500,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
                        }
                }
        }
+
        check.errorf(&x, _InvalidArrayLen, "array length %s must be integer", &x)
        return -1
 }
index 90a5cf7c728f85101a9991104372d5666ec64797..d3b86008ef246a3c00d32fea18fcfff22efb93a2 100644 (file)
@@ -9,7 +9,6 @@ package types
 import (
        "bytes"
        "fmt"
-       "sort"
 )
 
 // The unifier maintains two separate sets of type parameters x and y
@@ -63,7 +62,7 @@ func (u *unifier) unify(x, y Type) bool {
 // A tparamsList describes a list of type parameters and the types inferred for them.
 type tparamsList struct {
        unifier *unifier
-       tparams []*TypeName
+       tparams []*TypeParam
        // For each tparams element, there is a corresponding type slot index in indices.
        // index  < 0: unifier.types[-index-1] == nil
        // index == 0: no type slot allocated yet
@@ -77,29 +76,30 @@ type tparamsList struct {
 // String returns a string representation for a tparamsList. For debugging.
 func (d *tparamsList) String() string {
        var buf bytes.Buffer
-       buf.WriteByte('[')
-       for i, tname := range d.tparams {
+       w := newTypeWriter(&buf, nil)
+       w.byte('[')
+       for i, tpar := range d.tparams {
                if i > 0 {
-                       buf.WriteString(", ")
+                       w.string(", ")
                }
-               writeType(&buf, tname.typ, nil, nil)
-               buf.WriteString(": ")
-               writeType(&buf, d.at(i), nil, nil)
+               w.typ(tpar)
+               w.string(": ")
+               w.typ(d.at(i))
        }
-       buf.WriteByte(']')
+       w.byte(']')
        return buf.String()
 }
 
 // init initializes d with the given type parameters.
 // The type parameters must be in the order in which they appear in their declaration
 // (this ensures that the tparams indices match the respective type parameter index).
-func (d *tparamsList) init(tparams []*TypeName) {
+func (d *tparamsList) init(tparams []*TypeParam) {
        if len(tparams) == 0 {
                return
        }
        if debug {
                for i, tpar := range tparams {
-                       assert(i == tpar.typ.(*TypeParam).index)
+                       assert(i == tpar.index)
                }
        }
        d.tparams = tparams
@@ -108,7 +108,7 @@ func (d *tparamsList) init(tparams []*TypeName) {
 
 // join unifies the i'th type parameter of x with the j'th type parameter of y.
 // If both type parameters already have a type associated with them and they are
-// not joined, join fails and return false.
+// not joined, join fails and returns false.
 func (u *unifier) join(i, j int) bool {
        ti := u.x.indices[i]
        tj := u.y.indices[j]
@@ -132,13 +132,18 @@ func (u *unifier) join(i, j int) bool {
                break
        case ti > 0 && tj > 0:
                // Both type parameters have (possibly different) inferred types. Cannot join.
+               // TODO(gri) Should we check if types are identical? Investigate.
                return false
        case ti > 0:
                // Only the type parameter for x has an inferred type. Use x slot for y.
                u.y.setIndex(j, ti)
+       // This case is handled like the default case.
+       // case tj > 0:
+       //      // Only the type parameter for y has an inferred type. Use y slot for x.
+       //      u.x.setIndex(i, tj)
        default:
-               // Either the type parameter for y has an inferred type, or neither type
-               // parameter has an inferred type. In either case, use y slot for x.
+               // Neither type parameter has an inferred type. Use y slot for x
+               // (or x slot for y, it doesn't matter).
                u.x.setIndex(i, tj)
        }
        return true
@@ -155,8 +160,8 @@ func (d *tparamsList) index(typ Type) int {
 
 // If tpar is a type parameter in list, tparamIndex returns the type parameter index.
 // Otherwise, the result is < 0. tpar must not be nil.
-func tparamIndex(list []*TypeName, tpar *TypeParam) int {
-       if i := tpar.index; i < len(list) && list[i].typ == tpar {
+func tparamIndex(list []*TypeParam, tpar *TypeParam) int {
+       if i := tpar.index; i < len(list) && list[i] == tpar {
                return i
        }
        return -1
@@ -222,25 +227,21 @@ func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
 }
 
 // nify implements the core unification algorithm which is an
-// adapted version of Checker.identical0. For changes to that
+// adapted version of Checker.identical. For changes to that
 // code the corresponding changes should be made here.
 // Must not be called directly from outside the unifier.
 func (u *unifier) nify(x, y Type, p *ifacePair) bool {
-       // types must be expanded for comparison
-       x = expand(x)
-       y = expand(y)
-
        if !u.exact {
                // If exact unification is known to fail because we attempt to
                // match a type name against an unnamed type literal, consider
                // the underlying type of the named type.
-               // (Subtle: We use isNamed to include any type with a name (incl.
-               // basic types and type parameters. We use asNamed() because we only
+               // (Subtle: We use hasName to include any type with a name (incl.
+               // basic types and type parameters. We use asNamed because we only
                // want *Named types.)
                switch {
-               case !isNamed(x) && y != nil && asNamed(y) != nil:
+               case !hasName(x) && y != nil && asNamed(y) != nil:
                        return u.nify(x, under(y), p)
-               case x != nil && asNamed(x) != nil && !isNamed(y):
+               case x != nil && asNamed(x) != nil && !hasName(y):
                        return u.nify(under(x), y, p)
                }
        }
@@ -358,9 +359,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                                u.nify(x.results, y.results, p)
                }
 
-       case *Union:
-               panic("unimplemented: unification with type sets described by types")
-
        case *Interface:
                // Two interface types are identical if they have the same set of methods with
                // the same names and identical function types. Lower-case method names from
@@ -368,7 +366,7 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                if y, ok := y.(*Interface); ok {
                        xset := x.typeSet()
                        yset := y.typeSet()
-                       if !Identical(xset.types, yset.types) {
+                       if !xset.terms.equal(yset.terms) {
                                return false
                        }
                        a := xset.methods
@@ -404,8 +402,8 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                                        p = p.prev
                                }
                                if debug {
-                                       assert(sort.IsSorted(byUniqueMethodName(a)))
-                                       assert(sort.IsSorted(byUniqueMethodName(b)))
+                                       assertSortedMethods(a)
+                                       assertSortedMethods(b)
                                }
                                for i, f := range a {
                                        g := b[i]
@@ -430,19 +428,18 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
                }
 
        case *Named:
-               // Two named types are identical if their type names originate
-               // in the same type declaration.
-               // if y, ok := y.(*Named); ok {
-               //      return x.obj == y.obj
-               // }
+               // TODO(gri) This code differs now from the parallel code in Checker.identical. Investigate.
                if y, ok := y.(*Named); ok {
+                       xargs := x.targs.list()
+                       yargs := y.targs.list()
+
                        // TODO(gri) This is not always correct: two types may have the same names
                        //           in the same package if one of them is nested in a function.
                        //           Extremely unlikely but we need an always correct solution.
                        if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
-                               assert(len(x.targs) == len(y.targs))
-                               for i, x := range x.targs {
-                                       if !u.nify(x, y.targs[i], p) {
+                               assert(len(xargs) == len(yargs))
+                               for i, x := range xargs {
+                                       if !u.nify(x, yargs[i], p) {
                                                return false
                                        }
                                }
index a56f9d29f341959b09335a1fc9ce6ad53c00a844..c715839315cd1e4402972019e3b6348908a5a3aa 100644 (file)
@@ -12,112 +12,82 @@ import (
 // ----------------------------------------------------------------------------
 // API
 
-// A Union represents a union of terms.
+// A Union represents a union of terms embedded in an interface.
 type Union struct {
-       terms []*term
+       terms []*Term   // list of syntactical terms (not a canonicalized termlist)
+       tset  *_TypeSet // type set described by this union, computed lazily
 }
 
-// NewUnion returns a new Union type with the given terms (types[i], tilde[i]).
-// The lengths of both arguments must match. An empty union represents the set
-// of no types.
-func NewUnion(types []Type, tilde []bool) *Union { return newUnion(types, tilde) }
+// NewUnion returns a new Union type with the given terms.
+// It is an error to create an empty union; they are syntactically not possible.
+func NewUnion(terms []*Term) *Union {
+       if len(terms) == 0 {
+               panic("empty union")
+       }
+       return &Union{terms, nil}
+}
 
-func (u *Union) IsEmpty() bool           { return len(u.terms) == 0 }
-func (u *Union) NumTerms() int           { return len(u.terms) }
-func (u *Union) Term(i int) (Type, bool) { t := u.terms[i]; return t.typ, t.tilde }
+func (u *Union) Len() int         { return len(u.terms) }
+func (u *Union) Term(i int) *Term { return u.terms[i] }
 
 func (u *Union) Underlying() Type { return u }
 func (u *Union) String() string   { return TypeString(u, nil) }
 
-// ----------------------------------------------------------------------------
-// Implementation
+// A Term represents a term in a Union.
+type Term term
 
-var emptyUnion = new(Union)
+// NewTerm returns a new union term.
+func NewTerm(tilde bool, typ Type) *Term { return &Term{tilde, typ} }
 
-func newUnion(types []Type, tilde []bool) *Union {
-       assert(len(types) == len(tilde))
-       if len(types) == 0 {
-               return emptyUnion
-       }
-       t := new(Union)
-       t.terms = make([]*term, len(types))
-       for i, typ := range types {
-               t.terms[i] = &term{tilde[i], typ}
-       }
-       return t
-}
+func (t *Term) Tilde() bool    { return t.tilde }
+func (t *Term) Type() Type     { return t.typ }
+func (t *Term) String() string { return (*term)(t).String() }
 
-// is reports whether f returns true for all terms of u.
-func (u *Union) is(f func(*term) bool) bool {
-       if u.IsEmpty() {
-               return false
-       }
-       for _, t := range u.terms {
-               if !f(t) {
-                       return false
-               }
-       }
-       return true
-}
+// ----------------------------------------------------------------------------
+// Implementation
 
-// underIs reports whether f returned true for the underlying types of all terms of u.
-func (u *Union) underIs(f func(Type) bool) bool {
-       if u.IsEmpty() {
-               return false
-       }
-       for _, t := range u.terms {
-               if !f(under(t.typ)) {
-                       return false
-               }
-       }
-       return true
-}
+// Avoid excessive type-checking times due to quadratic termlist operations.
+const maxTermCount = 100
 
+// parseUnion parses the given list of type expressions tlist as a union of
+// those expressions. The result is a Union type, or Typ[Invalid] for some
+// errors.
 func parseUnion(check *Checker, tlist []ast.Expr) Type {
-       var types []Type
-       var tilde []bool
+       var terms []*Term
        for _, x := range tlist {
-               t, d := parseTilde(check, x)
-               if len(tlist) == 1 && !d {
-                       return t // single type
+               tilde, typ := parseTilde(check, x)
+               if len(tlist) == 1 && !tilde {
+                       // Single type. Ok to return early because all relevant
+                       // checks have been performed in parseTilde (no need to
+                       // run through term validity check below).
+                       return typ
+               }
+               if len(terms) >= maxTermCount {
+                       check.errorf(x, _Todo, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
+                       return Typ[Invalid]
                }
-               types = append(types, t)
-               tilde = append(tilde, d)
+               terms = append(terms, NewTerm(tilde, typ))
        }
 
-       // Ensure that each type is only present once in the type list.
-       // It's ok to do this check later because it's not a requirement
-       // for correctness of the code.
+       // Check validity of terms.
+       // Do this check later because it requires types to be set up.
        // Note: This is a quadratic algorithm, but unions tend to be short.
        check.later(func() {
-               for i, t := range types {
-                       t := expand(t)
-                       if t == Typ[Invalid] {
+               for i, t := range terms {
+                       if t.typ == Typ[Invalid] {
                                continue
                        }
 
-                       x := tlist[i]
-                       pos := x.Pos()
-                       // We may not know the position of x if it was a typechecker-
-                       // introduced ~T term for a type list entry T. Use the position
-                       // of T instead.
-                       // TODO(rfindley) remove this test once we don't support type lists anymore
-                       if !pos.IsValid() {
-                               if op, _ := x.(*ast.UnaryExpr); op != nil {
-                                       pos = op.X.Pos()
-                               }
-                       }
-
-                       u := under(t)
+                       u := under(t.typ)
                        f, _ := u.(*Interface)
-                       if tilde[i] {
+                       if t.tilde {
                                if f != nil {
-                                       check.errorf(x, _Todo, "invalid use of ~ (%s is an interface)", t)
+                                       check.errorf(tlist[i], _Todo, "invalid use of ~ (%s is an interface)", t.typ)
                                        continue // don't report another error for t
                                }
 
-                               if !Identical(u, t) {
-                                       check.errorf(x, _Todo, "invalid use of ~ (underlying type of %s is %s)", t, u)
+                               if !Identical(u, t.typ) {
+                                       check.errorf(tlist[i], _Todo, "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
                                        continue // don't report another error for t
                                }
                        }
@@ -126,146 +96,54 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type {
                        // in the beginning. Embedded interfaces with tilde are excluded above. If we reach
                        // here, we must have at least two terms in the union.
                        if f != nil && !f.typeSet().IsTypeSet() {
-                               check.errorf(atPos(pos), _Todo, "cannot use %s in union (interface contains methods)", t)
+                               check.errorf(tlist[i], _Todo, "cannot use %s in union (interface contains methods)", t)
                                continue // don't report another error for t
                        }
 
-                       // Complain about duplicate entries a|a, but also a|~a, and ~a|~a.
-                       // TODO(gri) We should also exclude myint|~int since myint is included in ~int.
-                       if includes(types[:i], t) {
-                               // TODO(rfindley) this currently doesn't print the ~ if present
-                               check.softErrorf(atPos(pos), _Todo, "duplicate term %s in union element", t)
+                       // Report overlapping (non-disjoint) terms such as
+                       // a|a, a|~a, ~a|~a, and ~a|A (where under(A) == a).
+                       if j := overlappingTerm(terms[:i], t); j >= 0 {
+                               check.softErrorf(tlist[i], _Todo, "overlapping terms %s and %s", t, terms[j])
                        }
                }
        })
 
-       return newUnion(types, tilde)
+       return &Union{terms, nil}
 }
 
-func parseTilde(check *Checker, x ast.Expr) (typ Type, tilde bool) {
+func parseTilde(check *Checker, x ast.Expr) (tilde bool, typ Type) {
        if op, _ := x.(*ast.UnaryExpr); op != nil && op.Op == token.TILDE {
                x = op.X
                tilde = true
        }
-       typ = check.anyType(x)
-       // embedding stand-alone type parameters is not permitted (issue #47127).
-       if _, ok := under(typ).(*TypeParam); ok {
-               check.error(x, _Todo, "cannot embed a type parameter")
-               typ = Typ[Invalid]
-       }
-       return
-}
-
-// intersect computes the intersection of the types x and y,
-// A nil type stands for the set of all types; an empty union
-// stands for the set of no types.
-func intersect(x, y Type) (r Type) {
-       // If one of the types is nil (no restrictions)
-       // the result is the other type.
-       switch {
-       case x == nil:
-               return y
-       case y == nil:
-               return x
-       }
-
-       // Compute the terms which are in both x and y.
-       // TODO(gri) This is not correct as it may not always compute
-       //           the "largest" intersection. For instance, for
-       //           x = myInt|~int, y = ~int
-       //           we get the result myInt but we should get ~int.
-       xu, _ := x.(*Union)
-       yu, _ := y.(*Union)
-       switch {
-       case xu != nil && yu != nil:
-               return &Union{intersectTerms(xu.terms, yu.terms)}
-
-       case xu != nil:
-               if r, _ := xu.intersect(y, false); r != nil {
-                       return y
-               }
-
-       case yu != nil:
-               if r, _ := yu.intersect(x, false); r != nil {
-                       return x
-               }
-
-       default: // xu == nil && yu == nil
-               if Identical(x, y) {
-                       return x
-               }
-       }
-
-       return emptyUnion
-}
-
-// includes reports whether typ is in list.
-func includes(list []Type, typ Type) bool {
-       for _, e := range list {
-               if Identical(typ, e) {
-                       return true
-               }
-       }
-       return false
-}
-
-// intersect computes the intersection of the union u and term (y, yt)
-// and returns the intersection term, if any. Otherwise the result is
-// (nil, false).
-// TODO(gri) this needs to cleaned up/removed once we switch to lazy
-//           union type set computation.
-func (u *Union) intersect(y Type, yt bool) (Type, bool) {
-       under_y := under(y)
-       for _, x := range u.terms {
-               xt := x.tilde
-               // determine which types xx, yy to compare
-               xx := x.typ
-               if yt {
-                       xx = under(xx)
-               }
-               yy := y
-               if xt {
-                       yy = under_y
-               }
-               if Identical(xx, yy) {
-                       //  T ∩  T =  T
-                       //  T ∩ ~t =  T
-                       // ~t ∩  T =  T
-                       // ~t ∩ ~t = ~t
-                       return xx, xt && yt
+       typ = check.typ(x)
+       // Embedding stand-alone type parameters is not permitted (issue #47127).
+       // Do this check later because it requires computation of the underlying type (see also issue #46461).
+       // Note: If an underlying type cannot be a type parameter, the call to
+       //       under() will not be needed and then we don't need to delay this
+       //       check to later and could return Typ[Invalid] instead.
+       check.later(func() {
+               if _, ok := under(typ).(*TypeParam); ok {
+                       check.error(x, _Todo, "cannot embed a type parameter")
                }
-       }
-       return nil, false
+       })
+       return
 }
 
-func identicalTerms(list1, list2 []*term) bool {
-       if len(list1) != len(list2) {
-               return false
-       }
-       // Every term in list1 must be in list2.
-       // Quadratic algorithm, but probably good enough for now.
-       // TODO(gri) we need a fast quick type ID/hash for all types.
-L:
-       for _, x := range list1 {
-               for _, y := range list2 {
-                       if x.equal(y) {
-                               continue L // x is in list2
+// overlappingTerm reports the index of the term x in terms which is
+// overlapping (not disjoint) from y. The result is < 0 if there is no
+// such term.
+func overlappingTerm(terms []*Term, y *Term) int {
+       for i, x := range terms {
+               // disjoint requires non-nil, non-top arguments
+               if debug {
+                       if x == nil || x.typ == nil || y == nil || y.typ == nil {
+                               panic("empty or top union term")
                        }
                }
-               return false
-       }
-       return true
-}
-
-func intersectTerms(list1, list2 []*term) (list []*term) {
-       // Quadratic algorithm, but good enough for now.
-       // TODO(gri) fix asymptotic performance
-       for _, x := range list1 {
-               for _, y := range list2 {
-                       if r := x.intersect(y); r != nil {
-                               list = append(list, r)
-                       }
+               if !(*term)(x).disjoint((*term)(y)) {
+                       return i
                }
        }
-       return
+       return -1
 }
index 83c54c8cd33577c04f2172e99a117add241fd043..519cf0b7078705900a30890bd0ce0eba2599b5e0 100644 (file)
@@ -87,10 +87,10 @@ func defPredeclaredTypes() {
                obj := NewTypeName(token.NoPos, nil, "error", nil)
                obj.setColor(black)
                res := NewVar(token.NoPos, nil, "", Typ[String])
-               sig := NewSignature(nil, nil, NewTuple(res), false)
+               sig := NewSignatureType(nil, nil, nil, nil, NewTuple(res), false)
                err := NewFunc(token.NoPos, nil, "Error", sig)
-               ityp := &Interface{obj, []*Func{err}, nil, nil, true, nil}
-               computeTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset
+               ityp := &Interface{nil, obj, []*Func{err}, nil, nil, false, true, nil}
+               computeInterfaceTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset
                typ := NewNamed(obj, ityp, nil)
                sig.recv = NewVar(token.NoPos, nil, "", typ)
                def(obj)
@@ -100,7 +100,7 @@ func defPredeclaredTypes() {
        {
                obj := NewTypeName(token.NoPos, nil, "comparable", nil)
                obj.setColor(black)
-               ityp := &Interface{obj, nil, nil, nil, true, &_TypeSet{true, nil, nil}}
+               ityp := &Interface{nil, obj, nil, nil, nil, false, true, &_TypeSet{true, nil, allTermlist}}
                NewNamed(obj, ityp, nil)
                def(obj)
        }
@@ -259,6 +259,6 @@ func def(obj Object) {
                }
        }
        if scope.Insert(obj) != nil {
-               panic("internal error: double declaration")
+               panic("double declaration of predeclared identifier")
        }
 }
index 936e5bf3e0c8dea18d52dda4505a32002edf3d17..762515257da3849a1da490399a711127fefa1495 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !s390x && !ppc64le && !arm64
-// +build !amd64,!s390x,!ppc64le,!arm64
 
 package crc32
 
index 10d5dd61dbcb7791cb32377249c0bfaed77cc9fd..763d3270f30d264894acc9aa44c3c6b429cd33c9 100644 (file)
@@ -112,19 +112,17 @@ loop:
        ANDCC   $7,R6,R8        // any leftover bytes
        BEQ     done            // none --> done
        MOVD    R8,CTR          // byte count
-
+        PCALIGN $16             // align short loop
 short:
        MOVBZ   0(R5),R8        // get v
        MOVBZ   R7,R9           // byte(crc) -> R8 BE vs LE?
-       MOVWZ   R7,R14
-       SRD     $8,R14,R14      // crc>>8
+        SRD     $8,R7,R14       // crc>>8
        XOR     R8,R9,R8        // byte(crc)^v -> R8
        ADD     $1,R5           // ptr to next v
        SLD     $2,R8           // convert index-> bytes
        ADD     R8,R4,R9        // &tab[byte(crc)^v]
        MOVWZ   0(R9),R10       // tab[byte(crc)^v]
        XOR     R10,R14,R7       // loop crc in R7
-       MOVWZ   R7,R7           // 32 bits
        BC      16,0,short
 done:
        NOR     R7,R7,R7        // ^crc
index c98454c6850cf84290ee92233c5f911b525b2d61..2f15a60b50e3bed04f131ac7d48ed1201d63ffcb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Generate the constant table associated with the poly used by the
 // vpmsumd crc32 algorithm.
index ecaf4f9069416b14c27f28c49618a70e1315c110..cd70f97106d990f123addd6dd4b3124d7137c725 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gofuzz
-// +build gofuzz
 
 package html
 
index 22922e6038b651196896976cfaccd56fe33fe34f..6c52211fede1d096f955a6bae656297bd5db8694 100644 (file)
@@ -143,12 +143,12 @@ func attrType(name string) contentType {
                // widely applied.
                // Treat data-action as URL below.
                name = name[5:]
-       } else if colon := strings.IndexRune(name, ':'); colon != -1 {
-               if name[:colon] == "xmlns" {
+       } else if prefix, short, ok := strings.Cut(name, ":"); ok {
+               if prefix == "xmlns" {
                        return contentTypeURL
                }
                // Treat svg:href and xlink:href as href below.
-               name = name[colon+1:]
+               name = short
        }
        if t, ok := attrTypeMap[name]; ok {
                return t
index 6ba87a955035abc49eb3136bdc2eee7537f5aba6..232ba199f35967622353241a0bc51e9061551518 100644 (file)
@@ -116,12 +116,12 @@ func indirect(a interface{}) interface{} {
        if a == nil {
                return nil
        }
-       if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
+       if t := reflect.TypeOf(a); t.Kind() != reflect.Pointer {
                // Avoid creating a reflect.Value if it's not a pointer.
                return a
        }
        v := reflect.ValueOf(a)
-       for v.Kind() == reflect.Ptr && !v.IsNil() {
+       for v.Kind() == reflect.Pointer && !v.IsNil() {
                v = v.Elem()
        }
        return v.Interface()
@@ -140,7 +140,7 @@ func indirectToStringerOrError(a interface{}) interface{} {
                return nil
        }
        v := reflect.ValueOf(a)
-       for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+       for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Pointer && !v.IsNil() {
                v = v.Elem()
        }
        return v.Interface()
index f7d4849928d98603a1db9162496362ef45378a26..aaa7d08359397c8fcb3b115561332553384f05b2 100644 (file)
@@ -6,6 +6,7 @@ package template
 
 import (
        "fmt"
+       "text/template/parse"
 )
 
 // context describes the state an HTML parser must be in when it reaches the
@@ -22,6 +23,7 @@ type context struct {
        jsCtx   jsCtx
        attr    attr
        element element
+       n       parse.Node // for range break/continue
        err     *Error
 }
 
@@ -141,6 +143,8 @@ const (
        // stateError is an infectious error state outside any valid
        // HTML/CSS/JS construct.
        stateError
+       // stateDead marks unreachable code after a {{break}} or {{continue}}.
+       stateDead
 )
 
 // isComment is true for any state that contains content meant for template
index 8739735cb7bc0cdfe6fa4507cd28df47b73919f9..6dea79c7b55fa676cd83673ceffa0d2047c4f88b 100644 (file)
@@ -97,6 +97,15 @@ type escaper struct {
        actionNodeEdits   map[*parse.ActionNode][]string
        templateNodeEdits map[*parse.TemplateNode]string
        textNodeEdits     map[*parse.TextNode][]byte
+       // rangeContext holds context about the current range loop.
+       rangeContext *rangeContext
+}
+
+// rangeContext holds information about the current range loop.
+type rangeContext struct {
+       outer     *rangeContext // outer loop
+       breaks    []context     // context at each break action
+       continues []context     // context at each continue action
 }
 
 // makeEscaper creates a blank escaper for the given set.
@@ -109,6 +118,7 @@ func makeEscaper(n *nameSpace) escaper {
                map[*parse.ActionNode][]string{},
                map[*parse.TemplateNode]string{},
                map[*parse.TextNode][]byte{},
+               nil,
        }
 }
 
@@ -124,8 +134,16 @@ func (e *escaper) escape(c context, n parse.Node) context {
        switch n := n.(type) {
        case *parse.ActionNode:
                return e.escapeAction(c, n)
+       case *parse.BreakNode:
+               c.n = n
+               e.rangeContext.breaks = append(e.rangeContext.breaks, c)
+               return context{state: stateDead}
        case *parse.CommentNode:
                return c
+       case *parse.ContinueNode:
+               c.n = n
+               e.rangeContext.continues = append(e.rangeContext.breaks, c)
+               return context{state: stateDead}
        case *parse.IfNode:
                return e.escapeBranch(c, &n.BranchNode, "if")
        case *parse.ListNode:
@@ -427,6 +445,12 @@ func join(a, b context, node parse.Node, nodeName string) context {
        if b.state == stateError {
                return b
        }
+       if a.state == stateDead {
+               return b
+       }
+       if b.state == stateDead {
+               return a
+       }
        if a.eq(b) {
                return a
        }
@@ -466,14 +490,27 @@ func join(a, b context, node parse.Node, nodeName string) context {
 
 // escapeBranch escapes a branch template node: "if", "range" and "with".
 func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context {
+       if nodeName == "range" {
+               e.rangeContext = &rangeContext{outer: e.rangeContext}
+       }
        c0 := e.escapeList(c, n.List)
-       if nodeName == "range" && c0.state != stateError {
+       if nodeName == "range" {
+               if c0.state != stateError {
+                       c0 = joinRange(c0, e.rangeContext)
+               }
+               e.rangeContext = e.rangeContext.outer
+               if c0.state == stateError {
+                       return c0
+               }
+
                // The "true" branch of a "range" node can execute multiple times.
                // We check that executing n.List once results in the same context
                // as executing n.List twice.
+               e.rangeContext = &rangeContext{outer: e.rangeContext}
                c1, _ := e.escapeListConditionally(c0, n.List, nil)
                c0 = join(c0, c1, n, nodeName)
                if c0.state == stateError {
+                       e.rangeContext = e.rangeContext.outer
                        // Make clear that this is a problem on loop re-entry
                        // since developers tend to overlook that branch when
                        // debugging templates.
@@ -481,11 +518,39 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string)
                        c0.err.Description = "on range loop re-entry: " + c0.err.Description
                        return c0
                }
+               c0 = joinRange(c0, e.rangeContext)
+               e.rangeContext = e.rangeContext.outer
+               if c0.state == stateError {
+                       return c0
+               }
        }
        c1 := e.escapeList(c, n.ElseList)
        return join(c0, c1, n, nodeName)
 }
 
+func joinRange(c0 context, rc *rangeContext) context {
+       // Merge contexts at break and continue statements into overall body context.
+       // In theory we could treat breaks differently from continues, but for now it is
+       // enough to treat them both as going back to the start of the loop (which may then stop).
+       for _, c := range rc.breaks {
+               c0 = join(c0, c, c.n, "range")
+               if c0.state == stateError {
+                       c0.err.Line = c.n.(*parse.BreakNode).Line
+                       c0.err.Description = "at range loop break: " + c0.err.Description
+                       return c0
+               }
+       }
+       for _, c := range rc.continues {
+               c0 = join(c0, c, c.n, "range")
+               if c0.state == stateError {
+                       c0.err.Line = c.n.(*parse.ContinueNode).Line
+                       c0.err.Description = "at range loop continue: " + c0.err.Description
+                       return c0
+               }
+       }
+       return c0
+}
+
 // escapeList escapes a list template node.
 func (e *escaper) escapeList(c context, n *parse.ListNode) context {
        if n == nil {
@@ -493,6 +558,9 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context {
        }
        for _, m := range n.Nodes {
                c = e.escape(c, m)
+               if c.state == stateDead {
+                       break
+               }
        }
        return c
 }
@@ -503,6 +571,7 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context {
 // which is the same as whether e was updated.
 func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) {
        e1 := makeEscaper(e.ns)
+       e1.rangeContext = e.rangeContext
        // Make type inferences available to f.
        for k, v := range e.output {
                e1.output[k] = v
index fbc84a75928b23077a2925598f472839c23b0fdd..3b0aa8c8466065bcc2972ed6ebe1aa516d7e5cd7 100644 (file)
@@ -920,6 +920,22 @@ func TestErrors(t *testing.T) {
                        "<a href='/foo?{{range .Items}}&{{.K}}={{.V}}{{end}}'>",
                        "",
                },
+               {
+                       "{{range .Items}}<a{{if .X}}{{end}}>{{end}}",
+                       "",
+               },
+               {
+                       "{{range .Items}}<a{{if .X}}{{end}}>{{continue}}{{end}}",
+                       "",
+               },
+               {
+                       "{{range .Items}}<a{{if .X}}{{end}}>{{break}}{{end}}",
+                       "",
+               },
+               {
+                       "{{range .Items}}<a{{if .X}}{{end}}>{{if .X}}{{break}}{{end}}{{end}}",
+                       "",
+               },
                // Error cases.
                {
                        "{{if .Cond}}<a{{end}}",
@@ -955,6 +971,14 @@ func TestErrors(t *testing.T) {
                        "\n{{range .Items}} x='<a{{end}}",
                        "z:2:8: on range loop re-entry: {{range}} branches",
                },
+               {
+                       "{{range .Items}}<a{{if .X}}{{break}}{{end}}>{{end}}",
+                       "z:1:29: at range loop break: {{range}} branches end in different contexts",
+               },
+               {
+                       "{{range .Items}}<a{{if .X}}{{continue}}{{end}}>{{end}}",
+                       "z:1:29: at range loop continue: {{range}} branches end in different contexts",
+               },
                {
                        "<a b=1 c={{.H}}",
                        "z: ends in a non-text context: {stateAttr delimSpaceOrTagEnd",
index 888587335de112cd5637f0bfe4e94d3213126c43..523340bac959151871943fb8091f6edeeca87efb 100644 (file)
@@ -567,6 +567,8 @@ var execTests = []execTest{
        {"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
        {"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
        {"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+       {"range []int break else", "{{range .SI}}-{{.}}-{{break}}NOTREACHED{{else}}EMPTY{{end}}", "-3-", tVal, true},
+       {"range []int continue else", "{{range .SI}}-{{.}}-{{continue}}NOTREACHED{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
        {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
        {"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
        {"range map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", tVal, true},
index ea9c18346ba2632b6e04db61e565492b96975156..7e919c48e6f67524ef18878c0d49d7ea670510cc 100644 (file)
@@ -132,7 +132,7 @@ func indirectToJSONMarshaler(a interface{}) interface{} {
        }
 
        v := reflect.ValueOf(a)
-       for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+       for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Pointer && !v.IsNil() {
                v = v.Elem()
        }
        return v.Interface()
@@ -398,9 +398,7 @@ func isJSType(mimeType string) bool {
        //   https://tools.ietf.org/html/rfc4329#section-3
        //   https://www.ietf.org/rfc/rfc4627.txt
        // discard parameters
-       if i := strings.Index(mimeType, ";"); i >= 0 {
-               mimeType = mimeType[:i]
-       }
+       mimeType, _, _ = strings.Cut(mimeType, ";")
        mimeType = strings.ToLower(mimeType)
        mimeType = strings.TrimSpace(mimeType)
        switch mimeType {
index 6f8185a4e90e69a0833c31b8aa4bffdc6ef5bc30..4b39fddf07df41e805ca0059c71c575d6a48a6bb 100644 (file)
@@ -46,9 +46,7 @@ func urlFilter(args ...interface{}) string {
 // isSafeURL is true if s is a relative URL or if URL has a protocol in
 // (http, https, mailto).
 func isSafeURL(s string) bool {
-       if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
-
-               protocol := s[:i]
+       if protocol, _, ok := strings.Cut(s, ":"); ok && !strings.Contains(protocol, "/") {
                if !strings.EqualFold(protocol, "http") && !strings.EqualFold(protocol, "https") && !strings.EqualFold(protocol, "mailto") {
                        return false
                }
index 7bb257d865ffa6bfa6ea15240efe916c41fc3695..be46c57020c58e1ac69f02e08ae85ea435e8094f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
index 831fd958ba3ed3efb292c12ef09aea4f6bd58607..55d25b85963f422794923b6c10450372d4918aba 100644 (file)
@@ -232,6 +232,18 @@ func BenchmarkGlyphOver(b *testing.B) {
        bench(b, color.RGBAModel, nil, color.AlphaModel, Over)
 }
 
+func BenchmarkRGBAMaskOver(b *testing.B) {
+       bench(b, color.RGBAModel, color.RGBAModel, color.AlphaModel, Over)
+}
+
+func BenchmarkGrayMaskOver(b *testing.B) {
+       bench(b, color.RGBAModel, color.GrayModel, color.AlphaModel, Over)
+}
+
+func BenchmarkRGBA64ImageMaskOver(b *testing.B) {
+       bench(b, color.RGBAModel, color.RGBA64Model, color.AlphaModel, Over)
+}
+
 func BenchmarkRGBA(b *testing.B) {
        bench(b, color.RGBAModel, color.RGBA64Model, nil, Src)
 }
index 13f6668293814e7b0c4d8e3271164c94d72eeb30..7dd18dfdb59a1b11ece550a1d2f3da58c4078022 100644 (file)
@@ -119,7 +119,8 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
                return
        }
 
-       // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
+       // Fast paths for special cases. If none of them apply, then we fall back
+       // to general but slower implementations.
        switch dst0 := dst.(type) {
        case *image.RGBA:
                if op == Over {
@@ -159,6 +160,17 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
                                case *image.Uniform:
                                        drawGlyphOver(dst0, r, src0, mask0, mp)
                                        return
+                               case *image.RGBA:
+                                       drawRGBAMaskOver(dst0, r, src0, sp, mask0, mp)
+                                       return
+                               case *image.Gray:
+                                       drawGrayMaskOver(dst0, r, src0, sp, mask0, mp)
+                                       return
+                               // Case order matters. The next case (image.RGBA64Image) is an
+                               // interface type that the concrete types above also implement.
+                               case image.RGBA64Image:
+                                       drawRGBA64ImageMaskOver(dst0, r, src0, sp, mask0, mp)
+                                       return
                                }
                        }
                } else {
@@ -219,6 +231,88 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
                y0, y1, dy = y1-1, y0-1, -1
        }
 
+       // FALLBACK1.17
+       //
+       // Try the draw.RGBA64Image and image.RGBA64Image interfaces, part of the
+       // standard library since Go 1.17. These are like the draw.Image and
+       // image.Image interfaces but they can avoid allocations from converting
+       // concrete color types to the color.Color interface type.
+
+       if dst0, _ := dst.(RGBA64Image); dst0 != nil {
+               if src0, _ := src.(image.RGBA64Image); src0 != nil {
+                       if mask == nil {
+                               sy := sp.Y + y0 - r.Min.Y
+                               my := mp.Y + y0 - r.Min.Y
+                               for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+                                       sx := sp.X + x0 - r.Min.X
+                                       mx := mp.X + x0 - r.Min.X
+                                       for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+                                               if op == Src {
+                                                       dst0.SetRGBA64(x, y, src0.RGBA64At(sx, sy))
+                                               } else {
+                                                       srgba := src0.RGBA64At(sx, sy)
+                                                       a := m - uint32(srgba.A)
+                                                       drgba := dst0.RGBA64At(x, y)
+                                                       dst0.SetRGBA64(x, y, color.RGBA64{
+                                                               R: uint16((uint32(drgba.R)*a)/m) + srgba.R,
+                                                               G: uint16((uint32(drgba.G)*a)/m) + srgba.G,
+                                                               B: uint16((uint32(drgba.B)*a)/m) + srgba.B,
+                                                               A: uint16((uint32(drgba.A)*a)/m) + srgba.A,
+                                                       })
+                                               }
+                                       }
+                               }
+                               return
+
+                       } else if mask0, _ := mask.(image.RGBA64Image); mask0 != nil {
+                               sy := sp.Y + y0 - r.Min.Y
+                               my := mp.Y + y0 - r.Min.Y
+                               for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+                                       sx := sp.X + x0 - r.Min.X
+                                       mx := mp.X + x0 - r.Min.X
+                                       for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+                                               ma := uint32(mask0.RGBA64At(mx, my).A)
+                                               switch {
+                                               case ma == 0:
+                                                       if op == Over {
+                                                               // No-op.
+                                                       } else {
+                                                               dst0.SetRGBA64(x, y, color.RGBA64{})
+                                                       }
+                                               case ma == m && op == Src:
+                                                       dst0.SetRGBA64(x, y, src0.RGBA64At(sx, sy))
+                                               default:
+                                                       srgba := src0.RGBA64At(sx, sy)
+                                                       if op == Over {
+                                                               drgba := dst0.RGBA64At(x, y)
+                                                               a := m - (uint32(srgba.A) * ma / m)
+                                                               dst0.SetRGBA64(x, y, color.RGBA64{
+                                                                       R: uint16((uint32(drgba.R)*a + uint32(srgba.R)*ma) / m),
+                                                                       G: uint16((uint32(drgba.G)*a + uint32(srgba.G)*ma) / m),
+                                                                       B: uint16((uint32(drgba.B)*a + uint32(srgba.B)*ma) / m),
+                                                                       A: uint16((uint32(drgba.A)*a + uint32(srgba.A)*ma) / m),
+                                                               })
+                                                       } else {
+                                                               dst0.SetRGBA64(x, y, color.RGBA64{
+                                                                       R: uint16(uint32(srgba.R) * ma / m),
+                                                                       G: uint16(uint32(srgba.G) * ma / m),
+                                                                       B: uint16(uint32(srgba.B) * ma / m),
+                                                                       A: uint16(uint32(srgba.A) * ma / m),
+                                                               })
+                                                       }
+                                               }
+                                       }
+                               }
+                               return
+                       }
+               }
+       }
+
+       // FALLBACK1.0
+       //
+       // If none of the faster code paths above apply, use the draw.Image and
+       // image.Image interfaces, part of the standard library since Go 1.0.
+
        var out color.RGBA64
        sy := sp.Y + y0 - r.Min.Y
        my := mp.Y + y0 - r.Min.Y
@@ -519,6 +613,156 @@ func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask
        }
 }
 
+func drawGrayMaskOver(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point, mask *image.Alpha, mp image.Point) {
+       x0, x1, dx := r.Min.X, r.Max.X, 1
+       y0, y1, dy := r.Min.Y, r.Max.Y, 1
+       if r.Overlaps(r.Add(sp.Sub(r.Min))) {
+               if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+                       x0, x1, dx = x1-1, x0-1, -1
+                       y0, y1, dy = y1-1, y0-1, -1
+               }
+       }
+
+       sy := sp.Y + y0 - r.Min.Y
+       my := mp.Y + y0 - r.Min.Y
+       sx0 := sp.X + x0 - r.Min.X
+       mx0 := mp.X + x0 - r.Min.X
+       sx1 := sx0 + (x1 - x0)
+       i0 := dst.PixOffset(x0, y0)
+       di := dx * 4
+       for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+               for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                       mi := mask.PixOffset(mx, my)
+                       ma := uint32(mask.Pix[mi])
+                       ma |= ma << 8
+                       si := src.PixOffset(sx, sy)
+                       sy := uint32(src.Pix[si])
+                       sy |= sy << 8
+                       sa := uint32(0xffff)
+
+                       d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+                       dr := uint32(d[0])
+                       dg := uint32(d[1])
+                       db := uint32(d[2])
+                       da := uint32(d[3])
+
+                       // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+                       // We work in 16-bit color, and so would normally do:
+                       // dr |= dr << 8
+                       // and similarly for dg, db and da, but instead we multiply a
+                       // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+                       // This yields the same result, but is fewer arithmetic operations.
+                       a := (m - (sa * ma / m)) * 0x101
+
+                       d[0] = uint8((dr*a + sy*ma) / m >> 8)
+                       d[1] = uint8((dg*a + sy*ma) / m >> 8)
+                       d[2] = uint8((db*a + sy*ma) / m >> 8)
+                       d[3] = uint8((da*a + sa*ma) / m >> 8)
+               }
+               i0 += dy * dst.Stride
+       }
+}
+
+func drawRGBAMaskOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point, mask *image.Alpha, mp image.Point) {
+       x0, x1, dx := r.Min.X, r.Max.X, 1
+       y0, y1, dy := r.Min.Y, r.Max.Y, 1
+       if dst == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+               if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+                       x0, x1, dx = x1-1, x0-1, -1
+                       y0, y1, dy = y1-1, y0-1, -1
+               }
+       }
+
+       sy := sp.Y + y0 - r.Min.Y
+       my := mp.Y + y0 - r.Min.Y
+       sx0 := sp.X + x0 - r.Min.X
+       mx0 := mp.X + x0 - r.Min.X
+       sx1 := sx0 + (x1 - x0)
+       i0 := dst.PixOffset(x0, y0)
+       di := dx * 4
+       for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+               for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                       mi := mask.PixOffset(mx, my)
+                       ma := uint32(mask.Pix[mi])
+                       ma |= ma << 8
+                       si := src.PixOffset(sx, sy)
+                       sr := uint32(src.Pix[si+0])
+                       sg := uint32(src.Pix[si+1])
+                       sb := uint32(src.Pix[si+2])
+                       sa := uint32(src.Pix[si+3])
+                       sr |= sr << 8
+                       sg |= sg << 8
+                       sb |= sb << 8
+                       sa |= sa << 8
+                       d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+                       dr := uint32(d[0])
+                       dg := uint32(d[1])
+                       db := uint32(d[2])
+                       da := uint32(d[3])
+
+                       // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+                       // We work in 16-bit color, and so would normally do:
+                       // dr |= dr << 8
+                       // and similarly for dg, db and da, but instead we multiply a
+                       // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+                       // This yields the same result, but is fewer arithmetic operations.
+                       a := (m - (sa * ma / m)) * 0x101
+
+                       d[0] = uint8((dr*a + sr*ma) / m >> 8)
+                       d[1] = uint8((dg*a + sg*ma) / m >> 8)
+                       d[2] = uint8((db*a + sb*ma) / m >> 8)
+                       d[3] = uint8((da*a + sa*ma) / m >> 8)
+               }
+               i0 += dy * dst.Stride
+       }
+}
+
+func drawRGBA64ImageMaskOver(dst *image.RGBA, r image.Rectangle, src image.RGBA64Image, sp image.Point, mask *image.Alpha, mp image.Point) {
+       x0, x1, dx := r.Min.X, r.Max.X, 1
+       y0, y1, dy := r.Min.Y, r.Max.Y, 1
+       if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+               if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+                       x0, x1, dx = x1-1, x0-1, -1
+                       y0, y1, dy = y1-1, y0-1, -1
+               }
+       }
+
+       sy := sp.Y + y0 - r.Min.Y
+       my := mp.Y + y0 - r.Min.Y
+       sx0 := sp.X + x0 - r.Min.X
+       mx0 := mp.X + x0 - r.Min.X
+       sx1 := sx0 + (x1 - x0)
+       i0 := dst.PixOffset(x0, y0)
+       di := dx * 4
+       for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+               for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                       mi := mask.PixOffset(mx, my)
+                       ma := uint32(mask.Pix[mi])
+                       ma |= ma << 8
+                       srgba := src.RGBA64At(sx, sy)
+                       d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+                       dr := uint32(d[0])
+                       dg := uint32(d[1])
+                       db := uint32(d[2])
+                       da := uint32(d[3])
+
+                       // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+                       // We work in 16-bit color, and so would normally do:
+                       // dr |= dr << 8
+                       // and similarly for dg, db and da, but instead we multiply a
+                       // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+                       // This yields the same result, but is fewer arithmetic operations.
+                       a := (m - (uint32(srgba.A) * ma / m)) * 0x101
+
+                       d[0] = uint8((dr*a + uint32(srgba.R)*ma) / m >> 8)
+                       d[1] = uint8((dg*a + uint32(srgba.G)*ma) / m >> 8)
+                       d[2] = uint8((db*a + uint32(srgba.B)*ma) / m >> 8)
+                       d[3] = uint8((da*a + uint32(srgba.A)*ma) / m >> 8)
+               }
+               i0 += dy * dst.Stride
+       }
+}
+
 func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
        x0, x1, dx := r.Min.X, r.Max.X, 1
        y0, y1, dy := r.Min.Y, r.Max.Y, 1
@@ -536,6 +780,89 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
        sx1 := sx0 + (x1 - x0)
        i0 := dst.PixOffset(x0, y0)
        di := dx * 4
+
+       // Try the image.RGBA64Image interface, part of the standard library since
+       // Go 1.17.
+       //
+       // This optimization is similar to how FALLBACK1.17 optimizes FALLBACK1.0
+       // in DrawMask, except here the concrete type of dst is known to be
+       // *image.RGBA.
+       if src0, _ := src.(image.RGBA64Image); src0 != nil {
+               if mask == nil {
+                       if op == Over {
+                               for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+                                       for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                                               srgba := src0.RGBA64At(sx, sy)
+                                               d := dst.Pix[i : i+4 : i+4]
+                                               dr := uint32(d[0])
+                                               dg := uint32(d[1])
+                                               db := uint32(d[2])
+                                               da := uint32(d[3])
+                                               a := (m - uint32(srgba.A)) * 0x101
+                                               d[0] = uint8((dr*a/m + uint32(srgba.R)) >> 8)
+                                               d[1] = uint8((dg*a/m + uint32(srgba.G)) >> 8)
+                                               d[2] = uint8((db*a/m + uint32(srgba.B)) >> 8)
+                                               d[3] = uint8((da*a/m + uint32(srgba.A)) >> 8)
+                                       }
+                                       i0 += dy * dst.Stride
+                               }
+                       } else {
+                               for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+                                       for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                                               srgba := src0.RGBA64At(sx, sy)
+                                               d := dst.Pix[i : i+4 : i+4]
+                                               d[0] = uint8(srgba.R >> 8)
+                                               d[1] = uint8(srgba.G >> 8)
+                                               d[2] = uint8(srgba.B >> 8)
+                                               d[3] = uint8(srgba.A >> 8)
+                                       }
+                                       i0 += dy * dst.Stride
+                               }
+                       }
+                       return
+
+               } else if mask0, _ := mask.(image.RGBA64Image); mask0 != nil {
+                       if op == Over {
+                               for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+                                       for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                                               ma := uint32(mask0.RGBA64At(mx, my).A)
+                                               srgba := src0.RGBA64At(sx, sy)
+                                               d := dst.Pix[i : i+4 : i+4]
+                                               dr := uint32(d[0])
+                                               dg := uint32(d[1])
+                                               db := uint32(d[2])
+                                               da := uint32(d[3])
+                                               a := (m - (uint32(srgba.A) * ma / m)) * 0x101
+                                               d[0] = uint8((dr*a + uint32(srgba.R)*ma) / m >> 8)
+                                               d[1] = uint8((dg*a + uint32(srgba.G)*ma) / m >> 8)
+                                               d[2] = uint8((db*a + uint32(srgba.B)*ma) / m >> 8)
+                                               d[3] = uint8((da*a + uint32(srgba.A)*ma) / m >> 8)
+                                       }
+                                       i0 += dy * dst.Stride
+                               }
+                       } else {
+                               for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+                                       for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
+                                               ma := uint32(mask0.RGBA64At(mx, my).A)
+                                               srgba := src0.RGBA64At(sx, sy)
+                                               d := dst.Pix[i : i+4 : i+4]
+                                               d[0] = uint8(uint32(srgba.R) * ma / m >> 8)
+                                               d[1] = uint8(uint32(srgba.G) * ma / m >> 8)
+                                               d[2] = uint8(uint32(srgba.B) * ma / m >> 8)
+                                               d[3] = uint8(uint32(srgba.A) * ma / m >> 8)
+                                       }
+                                       i0 += dy * dst.Stride
+                               }
+                       }
+                       return
+               }
+       }
+
+       // Use the image.Image interface, part of the standard library since Go
+       // 1.0.
+       //
+       // This is similar to FALLBACK1.0 in DrawMask, except here the concrete
+       // type of dst is known to be *image.RGBA.
        for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
                for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
                        ma := uint32(m)
index 9c5a118400e095ebc3681a479e4e0c1448352a3e..77f1c5c2c2cfbc0f2730fa32b468390c7b79e017 100644 (file)
@@ -13,6 +13,172 @@ import (
        "testing/quick"
 )
 
+// slowestRGBA is a draw.Image like image.RGBA but it is a different type and
+// therefore does not trigger the draw.go fastest code paths.
+//
+// Unlike slowerRGBA, it does not implement the draw.RGBA64Image interface.
+type slowestRGBA struct {
+       Pix    []uint8
+       Stride int
+       Rect   image.Rectangle
+}
+
+func (p *slowestRGBA) ColorModel() color.Model { return color.RGBAModel }
+
+func (p *slowestRGBA) Bounds() image.Rectangle { return p.Rect }
+
+func (p *slowestRGBA) At(x, y int) color.Color {
+       return p.RGBA64At(x, y)
+}
+
+func (p *slowestRGBA) RGBA64At(x, y int) color.RGBA64 {
+       if !(image.Point{x, y}.In(p.Rect)) {
+               return color.RGBA64{}
+       }
+       i := p.PixOffset(x, y)
+       s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+       r := uint16(s[0])
+       g := uint16(s[1])
+       b := uint16(s[2])
+       a := uint16(s[3])
+       return color.RGBA64{
+               (r << 8) | r,
+               (g << 8) | g,
+               (b << 8) | b,
+               (a << 8) | a,
+       }
+}
+
+func (p *slowestRGBA) Set(x, y int, c color.Color) {
+       if !(image.Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       c1 := color.RGBAModel.Convert(c).(color.RGBA)
+       s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+       s[0] = c1.R
+       s[1] = c1.G
+       s[2] = c1.B
+       s[3] = c1.A
+}
+
+func (p *slowestRGBA) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
+func convertToSlowestRGBA(m image.Image) *slowestRGBA {
+       if rgba, ok := m.(*image.RGBA); ok {
+               return &slowestRGBA{
+                       Pix:    append([]byte(nil), rgba.Pix...),
+                       Stride: rgba.Stride,
+                       Rect:   rgba.Rect,
+               }
+       }
+       rgba := image.NewRGBA(m.Bounds())
+       Draw(rgba, rgba.Bounds(), m, m.Bounds().Min, Src)
+       return &slowestRGBA{
+               Pix:    rgba.Pix,
+               Stride: rgba.Stride,
+               Rect:   rgba.Rect,
+       }
+}
+
+func init() {
+       var p interface{} = (*slowestRGBA)(nil)
+       if _, ok := p.(RGBA64Image); ok {
+               panic("slowestRGBA should not be an RGBA64Image")
+       }
+}
+
+// slowerRGBA is a draw.Image like image.RGBA but it is a different type and
+// therefore does not trigger the draw.go fastest code paths.
+//
+// Unlike slowestRGBA, it still implements the draw.RGBA64Image interface.
+type slowerRGBA struct {
+       Pix    []uint8
+       Stride int
+       Rect   image.Rectangle
+}
+
+func (p *slowerRGBA) ColorModel() color.Model { return color.RGBAModel }
+
+func (p *slowerRGBA) Bounds() image.Rectangle { return p.Rect }
+
+func (p *slowerRGBA) At(x, y int) color.Color {
+       return p.RGBA64At(x, y)
+}
+
+func (p *slowerRGBA) RGBA64At(x, y int) color.RGBA64 {
+       if !(image.Point{x, y}.In(p.Rect)) {
+               return color.RGBA64{}
+       }
+       i := p.PixOffset(x, y)
+       s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+       r := uint16(s[0])
+       g := uint16(s[1])
+       b := uint16(s[2])
+       a := uint16(s[3])
+       return color.RGBA64{
+               (r << 8) | r,
+               (g << 8) | g,
+               (b << 8) | b,
+               (a << 8) | a,
+       }
+}
+
+func (p *slowerRGBA) Set(x, y int, c color.Color) {
+       if !(image.Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       c1 := color.RGBAModel.Convert(c).(color.RGBA)
+       s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+       s[0] = c1.R
+       s[1] = c1.G
+       s[2] = c1.B
+       s[3] = c1.A
+}
+
+func (p *slowerRGBA) SetRGBA64(x, y int, c color.RGBA64) {
+       if !(image.Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
+       s[0] = uint8(c.R >> 8)
+       s[1] = uint8(c.G >> 8)
+       s[2] = uint8(c.B >> 8)
+       s[3] = uint8(c.A >> 8)
+}
+
+func (p *slowerRGBA) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
+func convertToSlowerRGBA(m image.Image) *slowerRGBA {
+       if rgba, ok := m.(*image.RGBA); ok {
+               return &slowerRGBA{
+                       Pix:    append([]byte(nil), rgba.Pix...),
+                       Stride: rgba.Stride,
+                       Rect:   rgba.Rect,
+               }
+       }
+       rgba := image.NewRGBA(m.Bounds())
+       Draw(rgba, rgba.Bounds(), m, m.Bounds().Min, Src)
+       return &slowerRGBA{
+               Pix:    rgba.Pix,
+               Stride: rgba.Stride,
+               Rect:   rgba.Rect,
+       }
+}
+
+func init() {
+       var p interface{} = (*slowerRGBA)(nil)
+       if _, ok := p.(RGBA64Image); !ok {
+               panic("slowerRGBA should be an RGBA64Image")
+       }
+}
+
 func eq(c0, c1 color.Color) bool {
        r0, g0, b0, a0 := c0.RGBA()
        r1, g1, b1, a1 := c1.RGBA()
@@ -178,6 +344,32 @@ var drawTests = []drawTest{
        {"grayAlphaSrc", vgradGray(), fillAlpha(192), Src, color.RGBA{102, 102, 102, 192}},
        {"grayNil", vgradGray(), nil, Over, color.RGBA{136, 136, 136, 255}},
        {"grayNilSrc", vgradGray(), nil, Src, color.RGBA{136, 136, 136, 255}},
+       // Same again, but with a slowerRGBA source.
+       {"graySlower", convertToSlowerRGBA(vgradGray()), fillAlpha(255),
+               Over, color.RGBA{136, 136, 136, 255}},
+       {"graySrcSlower", convertToSlowerRGBA(vgradGray()), fillAlpha(255),
+               Src, color.RGBA{136, 136, 136, 255}},
+       {"grayAlphaSlower", convertToSlowerRGBA(vgradGray()), fillAlpha(192),
+               Over, color.RGBA{136, 102, 102, 255}},
+       {"grayAlphaSrcSlower", convertToSlowerRGBA(vgradGray()), fillAlpha(192),
+               Src, color.RGBA{102, 102, 102, 192}},
+       {"grayNilSlower", convertToSlowerRGBA(vgradGray()), nil,
+               Over, color.RGBA{136, 136, 136, 255}},
+       {"grayNilSrcSlower", convertToSlowerRGBA(vgradGray()), nil,
+               Src, color.RGBA{136, 136, 136, 255}},
+       // Same again, but with a slowestRGBA source.
+       {"graySlowest", convertToSlowestRGBA(vgradGray()), fillAlpha(255),
+               Over, color.RGBA{136, 136, 136, 255}},
+       {"graySrcSlowest", convertToSlowestRGBA(vgradGray()), fillAlpha(255),
+               Src, color.RGBA{136, 136, 136, 255}},
+       {"grayAlphaSlowest", convertToSlowestRGBA(vgradGray()), fillAlpha(192),
+               Over, color.RGBA{136, 102, 102, 255}},
+       {"grayAlphaSrcSlowest", convertToSlowestRGBA(vgradGray()), fillAlpha(192),
+               Src, color.RGBA{102, 102, 102, 192}},
+       {"grayNilSlowest", convertToSlowestRGBA(vgradGray()), nil,
+               Over, color.RGBA{136, 136, 136, 255}},
+       {"grayNilSrcSlowest", convertToSlowestRGBA(vgradGray()), nil,
+               Src, color.RGBA{136, 136, 136, 255}},
        // Uniform mask (100%, 75%, nil) and variable CMYK source.
        // At (x, y) == (8, 8):
        // The destination pixel is {136, 0, 0, 255}.
@@ -188,13 +380,32 @@ var drawTests = []drawTest{
        {"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}},
        {"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}},
        {"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}},
-       // Variable mask and variable source.
+       // Variable mask and uniform source.
        // At (x, y) == (8, 8):
        // The destination pixel is {136, 0, 0, 255}.
        // The source pixel is {0, 0, 255, 255}.
        // The mask pixel's alpha is 102, or 40%.
        {"generic", fillBlue(255), vgradAlpha(192), Over, color.RGBA{81, 0, 102, 255}},
        {"genericSrc", fillBlue(255), vgradAlpha(192), Src, color.RGBA{0, 0, 102, 102}},
+       // Same again, but with a slowerRGBA mask.
+       {"genericSlower", fillBlue(255), convertToSlowerRGBA(vgradAlpha(192)),
+               Over, color.RGBA{81, 0, 102, 255}},
+       {"genericSrcSlower", fillBlue(255), convertToSlowerRGBA(vgradAlpha(192)),
+               Src, color.RGBA{0, 0, 102, 102}},
+       // Same again, but with a slowestRGBA mask.
+       {"genericSlowest", fillBlue(255), convertToSlowestRGBA(vgradAlpha(192)),
+               Over, color.RGBA{81, 0, 102, 255}},
+       {"genericSrcSlowest", fillBlue(255), convertToSlowestRGBA(vgradAlpha(192)),
+               Src, color.RGBA{0, 0, 102, 102}},
+       // Variable mask and variable source.
+       // At (x, y) == (8, 8):
+       // The destination pixel is {136, 0, 0, 255}.
+       // The source pixel is:
+       //   - {0, 48, 0, 90}.
+       //   - {136} in Gray-space, which is {136, 136, 136, 255} in RGBA-space.
+       // The mask pixel's alpha is 102, or 40%.
+       {"rgbaVariableMaskOver", vgradGreen(90), vgradAlpha(192), Over, color.RGBA{117, 19, 0, 255}},
+       {"grayVariableMaskOver", vgradGray(), vgradAlpha(192), Over, color.RGBA{136, 54, 54, 255}},
 }
 
 func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) image.Image {
@@ -260,30 +471,45 @@ func TestDraw(t *testing.T) {
        for _, r := range rr {
        loop:
                for _, test := range drawTests {
-                       dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
-                       // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
-                       golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
-                       b := dst.Bounds()
-                       if !b.Eq(golden.Bounds()) {
-                               t.Errorf("draw %v %s: bounds %v versus %v", r, test.desc, dst.Bounds(), golden.Bounds())
-                               continue
-                       }
-                       // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
-                       DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
-                       if image.Pt(8, 8).In(r) {
-                               // Check that the resultant pixel at (8, 8) matches what we expect
-                               // (the expected value can be verified by hand).
-                               if !eq(dst.At(8, 8), test.expected) {
-                                       t.Errorf("draw %v %s: at (8, 8) %v versus %v", r, test.desc, dst.At(8, 8), test.expected)
+                       for i := 0; i < 3; i++ {
+                               dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
+                               // For i != 0, substitute a different-typed dst that will take
+                               // us off the fastest code paths. We should still get the same
+                               // result, in terms of final pixel RGBA values.
+                               switch i {
+                               case 1:
+                                       dst = convertToSlowerRGBA(dst)
+                               case 2:
+                                       dst = convertToSlowestRGBA(dst)
+                               }
+
+                               // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+                               golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+                               b := dst.Bounds()
+                               if !b.Eq(golden.Bounds()) {
+                                       t.Errorf("draw %v %s on %T: bounds %v versus %v",
+                                               r, test.desc, dst, dst.Bounds(), golden.Bounds())
                                        continue
                                }
-                       }
-                       // Check that the resultant dst image matches the golden output.
-                       for y := b.Min.Y; y < b.Max.Y; y++ {
-                               for x := b.Min.X; x < b.Max.X; x++ {
-                                       if !eq(dst.At(x, y), golden.At(x, y)) {
-                                               t.Errorf("draw %v %s: at (%d, %d), %v versus golden %v", r, test.desc, x, y, dst.At(x, y), golden.At(x, y))
-                                               continue loop
+                               // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+                               DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+                               if image.Pt(8, 8).In(r) {
+                                       // Check that the resultant pixel at (8, 8) matches what we expect
+                                       // (the expected value can be verified by hand).
+                                       if !eq(dst.At(8, 8), test.expected) {
+                                               t.Errorf("draw %v %s on %T: at (8, 8) %v versus %v",
+                                                       r, test.desc, dst, dst.At(8, 8), test.expected)
+                                               continue
+                                       }
+                               }
+                               // Check that the resultant dst image matches the golden output.
+                               for y := b.Min.Y; y < b.Max.Y; y++ {
+                                       for x := b.Min.X; x < b.Max.X; x++ {
+                                               if !eq(dst.At(x, y), golden.At(x, y)) {
+                                                       t.Errorf("draw %v %s on %T: at (%d, %d), %v versus golden %v",
+                                                               r, test.desc, dst, x, y, dst.At(x, y), golden.At(x, y))
+                                                       continue loop
+                                               }
                                        }
                                }
                        }
index 38f41303fa747fa23b67f2306bc761eecde9ee28..65e1e30b64f700694b4276ef00fdfdec53ecace7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
index 6508533f4440b3f2816c43593e4beee387a30030..688b6c99361339b07d95ad931d9aac9f0c307331 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gofuzz
-// +build gofuzz
 
 package png
 
index 910520bd4b343037a2941494626cd00420f6533d..4c65038cb5bd534d147b212fefca158b5e4b1b92 100644 (file)
@@ -821,9 +821,17 @@ func (d *decoder) mergePassInto(dst image.Image, src image.Image, pass int) {
                dstPix, stride, rect = target.Pix, target.Stride, target.Rect
                bytesPerPixel = 8
        case *image.Paletted:
-               srcPix = src.(*image.Paletted).Pix
+               source := src.(*image.Paletted)
+               srcPix = source.Pix
                dstPix, stride, rect = target.Pix, target.Stride, target.Rect
                bytesPerPixel = 1
+               if len(target.Palette) < len(source.Palette) {
+                       // readImagePass can return a paletted image whose implicit palette
+                       // length (one more than the maximum Pix value) is larger than the
+                       // explicit palette length (what's in the PLTE chunk). Make the
+                       // same adjustment here.
+                       target.Palette = source.Palette
+               }
        case *image.RGBA:
                srcPix = src.(*image.RGBA).Pix
                dstPix, stride, rect = target.Pix, target.Stride, target.Rect
index 3bc9b1e2aea4328551f95aa8da19c5f3ab83ac44..d6eb32e2aeefa318724befe041c973d7edfd50fc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Gen generates sais2.go by duplicating functions in sais.go
 // using different input types.
index eadff248d99ff3a81f95b6b1643bcd8123625474..46dc593bd7e8f40ac5298ba3fcab2a38d661d4d3 100644 (file)
@@ -19,6 +19,14 @@ import (
 // when it may not be safe to keep them only in the integer
 // register space otherwise.
 type RegArgs struct {
+       // Values in these slots should be precisely the bit-by-bit
+       // representation of how they would appear in a register.
+       //
+       // This means that on big endian arches, integer values should
+       // be in the top bits of the slot. Floats are usually just
+       // directly represented, but some architectures treat narrow
+       // width floating point values specially (e.g. they're promoted
+       // first, or they need to be NaN-boxed).
        Ints   [IntArgRegs]uintptr  // untyped integer registers
        Floats [FloatArgRegs]uint64 // untyped float registers
 
@@ -56,26 +64,6 @@ func (r *RegArgs) IntRegArgAddr(reg int, argSize uintptr) unsafe.Pointer {
        return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Ints[reg])) + offset)
 }
 
-// FloatRegArgAddr returns a pointer inside of r.Floats[reg] that is appropriately
-// offset for an argument of size argSize.
-//
-// argSize must be non-zero, fit in a register, and a power-of-two.
-//
-// This method is a helper for dealing with the endianness of different CPU
-// architectures, since sub-word-sized arguments in big endian architectures
-// need to be "aligned" to the upper edge of the register to be interpreted
-// by the CPU correctly.
-func (r *RegArgs) FloatRegArgAddr(reg int, argSize uintptr) unsafe.Pointer {
-       if argSize > EffectiveFloatRegSize || argSize == 0 || argSize&(argSize-1) != 0 {
-               panic("invalid argSize")
-       }
-       offset := uintptr(0)
-       if goarch.BigEndian {
-               offset = EffectiveFloatRegSize - argSize
-       }
-       return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Floats[reg])) + offset)
-}
-
 // IntArgRegBitmap is a bitmap large enough to hold one bit per
 // integer argument/return register.
 type IntArgRegBitmap [(IntArgRegs + 7) / 8]uint8
index 7544d7506edb03d93be1ba4bbd626960d9c49528..5c3dd6cbe2815ae73be8ea286490056ccba333b1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build goexperiment.regabireflect
-// +build goexperiment.regabireflect
 
 package abi
 
index e8f94f805f57e8198c295acf97a6272b3884f3af..a36745f402c414cb01dc8b63921c3303777c7c09 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !goexperiment.regabireflect && !amd64
-// +build !goexperiment.regabireflect,!amd64
 
 package abi
 
diff --git a/src/internal/abi/abi_ppc64x.go b/src/internal/abi/abi_ppc64x.go
new file mode 100644 (file)
index 0000000..d47271d
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2021 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:build goexperiment.regabireflect && (ppc64 || ppc64le)
+
+package abi
+
+const (
+       // See abi_generic.go.
+
+       // R3 - R10, R14 - R17.
+       IntArgRegs = 12
+
+       // F1 - F12.
+       FloatArgRegs = 12
+
+       EffectiveFloatRegSize = 8
+)
index 9fe7f211fb3024951e24ce2f0f6f66f9572f2fb0..68c10a282465887f1b3b5aa2fb3f436888e8cf40 100644 (file)
@@ -25,6 +25,7 @@ var (
        GOARCH   = envOr("GOARCH", defaultGOARCH)
        GOOS     = envOr("GOOS", defaultGOOS)
        GO386    = envOr("GO386", defaultGO386)
+       GOAMD64  = goamd64()
        GOARM    = goarm()
        GOMIPS   = gomips()
        GOMIPS64 = gomips64()
@@ -52,6 +53,21 @@ func envOr(key, value string) string {
        return value
 }
 
+func goamd64() int {
+       switch v := envOr("GOAMD64", defaultGOAMD64); v {
+       case "v1":
+               return 1
+       case "v2":
+               return 2
+       case "v3":
+               return 3
+       case "v4":
+               return 4
+       }
+       Error = fmt.Errorf("invalid GOAMD64: must be v1, v2, v3, v4")
+       return int(defaultGOAMD64[len("v")] - '0')
+}
+
 func goarm() int {
        def := defaultGOARM
        if GOOS == "android" && GOARCH == "arm" {
diff --git a/src/internal/buildcfg/cfg_test.go b/src/internal/buildcfg/cfg_test.go
new file mode 100644 (file)
index 0000000..0123593
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2021 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 buildcfg
+
+import (
+       "os"
+       "testing"
+)
+
+func TestConfigFlags(t *testing.T) {
+       os.Setenv("GOAMD64", "v1")
+       if goamd64() != 1 {
+               t.Errorf("Wrong parsing of GOAMD64=v1")
+       }
+       os.Setenv("GOAMD64", "v4")
+       if goamd64() != 4 {
+               t.Errorf("Wrong parsing of GOAMD64=v4")
+       }
+       Error = nil
+       os.Setenv("GOAMD64", "1")
+       if goamd64(); Error == nil {
+               t.Errorf("Wrong parsing of GOAMD64=1")
+       }
+}
index 384f2f96af1a89b9e202bb04a0e980b17f401587..a9b29d6718c5cf08220127a6dbf11057a84899d7 100644 (file)
@@ -46,12 +46,17 @@ var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64"
 //
 // TODO(mdempsky): Move to internal/goexperiment.
 func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment.Flags, err error) {
-       regabiSupported := goarch == "amd64" || goarch == "arm64"
+       regabiSupported := false
+       switch goarch {
+       case "amd64", "arm64", "ppc64le", "ppc64":
+               regabiSupported = true
+       }
 
        baseline = goexperiment.Flags{
                RegabiWrappers: regabiSupported,
                RegabiReflect:  regabiSupported,
                RegabiArgs:     regabiSupported,
+               PacerRedesign:  true,
        }
 
        // Start with the statically enabled set of experiments.
@@ -111,8 +116,8 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (flags, baseline goexperiment
                flags.RegabiReflect = true
                flags.RegabiArgs = true
        }
-       // regabi is only supported on amd64 and arm64.
-       if goarch != "amd64" && goarch != "arm64" {
+       // regabi is only supported on amd64, arm64, ppc64 and ppc64le.
+       if !regabiSupported {
                flags.RegabiReflect = false
                flags.RegabiArgs = false
        }
@@ -158,7 +163,11 @@ func expList(exp, base *goexperiment.Flags, all bool) []string {
 // GOEXPERIMENT is exactly what a user would set on the command line
 // to get the set of enabled experiments.
 func GOEXPERIMENT() string {
-       return strings.Join(expList(&Experiment, &experimentBaseline, false), ",")
+       goexp := strings.Join(expList(&Experiment, &experimentBaseline, false), ",")
+       if goexp == "" && DefaultGOEXPERIMENT != "" {
+               goexp = "," // non-empty to override DefaultGOEXPERIMENT
+       }
+       return goexp
 }
 
 // EnabledExperiments returns a list of enabled experiments, as
index 6b2b540acc8846ce1707641930e3d185690ab295..ebebce75fe484a0317be60a053c473726b944f72 100644 (file)
@@ -11,7 +11,6 @@ import (
 
 // Offsets into internal/cpu records for use in assembly.
 const (
-       offsetX86HasSSE2   = unsafe.Offsetof(cpu.X86.HasSSE2)
        offsetX86HasSSE42  = unsafe.Offsetof(cpu.X86.HasSSE42)
        offsetX86HasAVX2   = unsafe.Offsetof(cpu.X86.HasAVX2)
        offsetX86HasPOPCNT = unsafe.Offsetof(cpu.X86.HasPOPCNT)
index 0981983d20f313bd5fd2f750afe89b6aab61f8fc..27b660ccf7c526ac70be5f016695cb19238aa19c 100644 (file)
@@ -36,8 +36,9 @@ TEXT cmpbody<>(SB),NOSPLIT,$0-0
        JEQ     allsame
        CMPL    BP, $4
        JB      small
-       CMPB    internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE     mediumloop
+#ifdef GO386_softfloat
+       JMP     mediumloop
+#endif
 largeloop:
        CMPL    BP, $16
        JB      mediumloop
index 0690d0cf31c51e1a4d908af72fb1a783e03f6eb5..eaea168f2de738ef38a2cf4b1bd6bd26be995650 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386 && !amd64 && !s390x && !arm && !arm64 && !ppc64 && !ppc64le && !mips && !mipsle && !wasm && !mips64 && !mips64le
-// +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!wasm,!mips64,!mips64le
 
 package bytealg
 
index baa188ff7af553ffbcbbf66de34347f3b4134b7f..21ff8fe786d9bf54c5b81dc8cf2a6606be20b571 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64 || s390x || arm || arm64 || ppc64 || ppc64le || mips || mipsle || wasm || mips64 || mips64le
-// +build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle wasm mips64 mips64le
 
 package bytealg
 
index 83444fa826008b1ed0de2fa053f05bd59935f6e5..390a72688b73bec52efb9510da69c3ab8583aa3c 100644 (file)
@@ -8,64 +8,99 @@
 #include "go_asm.h"
 #include "textflag.h"
 
-TEXT ·Compare(SB),NOSPLIT|NOFRAME,$0-56
+TEXT ·Compare<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-56
+#ifdef GOEXPERIMENT_regabiargs
+// incoming:
+// R3 a addr -> R5
+// R4 a len  -> R3
+// R5 a cap unused
+// R6 b addr -> R6
+// R7 b len  -> R4
+// R8 b cap unused
+       MOVD    R3, R5
+       MOVD    R4, R3
+       MOVD    R7, R4
+#else
        MOVD    a_base+0(FP), R5
        MOVD    b_base+24(FP), R6
        MOVD    a_len+8(FP), R3
-       CMP     R5,R6,CR7
        MOVD    b_len+32(FP), R4
        MOVD    $ret+48(FP), R7
+#endif
+       CMP     R5,R6,CR7
        CMP     R3,R4,CR6
        BEQ     CR7,equal
-
 #ifdef GOARCH_ppc64le
        BR      cmpbodyLE<>(SB)
 #else
        BR      cmpbodyBE<>(SB)
 #endif
-
 equal:
        BEQ     CR6,done
        MOVD    $1, R8
        BGT     CR6,greater
        NEG     R8
-
 greater:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R8, R3
+#else
        MOVD    R8, (R7)
+#endif
        RET
-
 done:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    $0, R3
+#else
        MOVD    $0, (R7)
+#endif
        RET
 
-TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40
+TEXT runtime·cmpstring<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
+#ifdef GOEXPERIMENT_regabiargs
+// incoming:
+// R3 a addr -> R5
+// R4 a len  -> R3
+// R5 b addr -> R6
+// R6 b len  -> R4
+       MOVD    R6, R7
+       MOVD    R5, R6
+       MOVD    R3, R5
+       MOVD    R4, R3
+       MOVD    R7, R4
+#else
        MOVD    a_base+0(FP), R5
        MOVD    b_base+16(FP), R6
        MOVD    a_len+8(FP), R3
-       CMP     R5,R6,CR7
        MOVD    b_len+24(FP), R4
        MOVD    $ret+32(FP), R7
+#endif
+       CMP     R5,R6,CR7
        CMP     R3,R4,CR6
        BEQ     CR7,equal
-
 #ifdef GOARCH_ppc64le
        BR      cmpbodyLE<>(SB)
 #else
        BR      cmpbodyBE<>(SB)
 #endif
-
 equal:
        BEQ     CR6,done
        MOVD    $1, R8
        BGT     CR6,greater
        NEG     R8
-
 greater:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R8, R3
+#else
        MOVD    R8, (R7)
+#endif
        RET
 
 done:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    $0, R3
+#else
        MOVD    $0, (R7)
+#endif
        RET
 
 // Do an efficient memcmp for ppc64le
@@ -73,7 +108,7 @@ done:
 // R4 = b len
 // R5 = a addr
 // R6 = b addr
-// R7 = addr of return value
+// R7 = addr of return value if not regabi
 TEXT cmpbodyLE<>(SB),NOSPLIT|NOFRAME,$0-0
        MOVD    R3,R8           // set up length
        CMP     R3,R4,CR2       // unequal?
@@ -168,14 +203,22 @@ cmpne:                            // only here is not equal
        BGT     greater         // here only if NE
 less:
        MOVD    $-1,R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3,(R7)         // return value if A < B
+#endif
        RET
 equal:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    $0, R3
+#else
        MOVD    $0,(R7)         // return value if A == B
+#endif
        RET
 greater:
        MOVD    $1,R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3,(R7)         // return value if A > B
+#endif
        RET
 
 // Do an efficient memcmp for ppc64 (BE)
@@ -267,12 +310,20 @@ simple:
        BC      12,9,greater    // 2nd len > 1st len
 less:
        MOVD    $-1,R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3,(R7)         // return value if A < B
+#endif
        RET
 equal:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    $0, R3
+#else
        MOVD    $0,(R7)         // return value if A == B
+#endif
        RET
 greater:
        MOVD    $1,R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3,(R7)         // return value if A > B
+#endif
        RET
index 1891d29b24cb4a6646e4e85fb5263d44e0e2a655..932a7c584c1ae60517465e615feafd815c2e3e83 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !arm && !arm64 && !ppc64le && !ppc64 && !riscv64 && !s390x
-// +build !amd64,!arm,!arm64,!ppc64le,!ppc64,!riscv64,!s390x
 
 package bytealg
 
index a19a6f8223fe9e495cda45dd9d775dc969e532ec..90189c9fe051bd12fd25b20993282ebf83e59744 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm || arm64 || ppc64le || ppc64 || riscv64 || s390x
-// +build amd64 arm arm64 ppc64le ppc64 riscv64 s390x
 
 package bytealg
 
index 94163cbd8a398d837d10a147a9c2b7d68e9ff26d..dbafd06edc595c517a78c9b544fd5777e0985871 100644 (file)
@@ -8,24 +8,37 @@
 #include "go_asm.h"
 #include "textflag.h"
 
-TEXT ·Count(SB), NOSPLIT|NOFRAME, $0-40
+TEXT ·Count<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
+#ifdef GOEXPERIMENT_regabiargs
+// R3 = byte array pointer 
+// R4 = length
+        MOVBZ R6,R5               // R5 = byte
+#else
+
        MOVD  b_base+0(FP), R3    // R3 = byte array pointer
        MOVD  b_len+8(FP), R4     // R4 = length
        MOVBZ c+24(FP), R5        // R5 = byte
        MOVD  $ret+32(FP), R14    // R14 = &ret
+#endif
        BR    countbytebody<>(SB)
 
-TEXT ·CountString(SB), NOSPLIT|NOFRAME, $0-32
+TEXT ·CountString<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-32
+#ifdef GOEXPERIMENT_regabiargs
+// R3 = byte array pointer
+// R4 = length
+        MOVBZ R5,R5               // R5 = byte
+#else
        MOVD  s_base+0(FP), R3    // R3 = string
        MOVD  s_len+8(FP), R4     // R4 = length
        MOVBZ c+16(FP), R5        // R5 = byte
        MOVD  $ret+24(FP), R14    // R14 = &ret
+#endif
        BR    countbytebody<>(SB)
 
 // R3: addr of string
 // R4: len of string
 // R5: byte to count
-// R14: addr for return value
+// R14: addr for return value when not regabi
 // endianness shouldn't matter since we are just counting and order
 // is irrelevant
 TEXT countbytebody<>(SB), NOSPLIT|NOFRAME, $0-0
@@ -94,5 +107,10 @@ next2:
        BR  small
 
 done:
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD R18, R3    // return count
+#else
        MOVD R18, (R14) // return count
+#endif
+
        RET
index 87233635a927d35cd6018fa692f3081317575eca..58b3cbe3d07194b5eddd4a3ef2f0b5425d8cb485 100644 (file)
@@ -43,8 +43,9 @@ TEXT memeqbody<>(SB),NOSPLIT,$0-0
 hugeloop:
        CMPL    BX, $64
        JB      bigloop
-       CMPB    internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE     bigloop
+#ifdef GO386_softfloat
+       JMP     bigloop
+#endif
        MOVOU   (SI), X0
        MOVOU   (DI), X1
        MOVOU   16(SI), X2
index 5f0fea521b24a74687bb9cf3a42db3dd517049f5..d59154101ac649eb577e5761da31dc7cee252fc2 100644 (file)
@@ -9,33 +9,38 @@
 #include "textflag.h"
 
 // memequal(a, b unsafe.Pointer, size uintptr) bool
-TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
+TEXT runtime·memequal<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-25
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    a+0(FP), R3
        MOVD    b+8(FP), R4
        MOVD    size+16(FP), R5
        MOVD    $ret+24(FP), R10
-
+#endif
        BR      memeqbody<>(SB)
 
 // memequal_varlen(a, b unsafe.Pointer) bool
-TEXT runtime·memequal_varlen(SB),NOSPLIT|NOFRAME,$0-17
+TEXT runtime·memequal_varlen<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-17
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    a+0(FP), R3
        MOVD    b+8(FP), R4
+       MOVD    $ret+16(FP), R10
+#endif
        CMP     R3, R4
        BEQ     eq
        MOVD    8(R11), R5    // compiler stores size at offset 8 in the closure
-       MOVD    $ret+16(FP), R10
        BR      memeqbody<>(SB)
 eq:
        MOVD    $1, R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVB    R3, ret+16(FP)
+#endif
        RET
 
 // Do an efficient memequal for ppc64
 // R3 = s1
 // R4 = s2
 // R5 = len
-// R10 = addr of return value (byte)
+// R10 = addr of return value (byte) when not regabi
 TEXT memeqbody<>(SB),NOSPLIT|NOFRAME,$0-0
        MOVD    R5,CTR
        CMP     R5,$8           // only optimize >=8
@@ -94,10 +99,16 @@ simple:
        BNE     noteq
        BR      equal
 noteq:
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    $0, R3
+#else
        MOVB    $0, (R10)
+#endif
        RET
 equal:
        MOVD    $1, R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVB    R3, (R10)
+#endif
        RET
 
index 0a6eb90d2d9297fbcffd1195c9ea3f515d5b73c2..a59e32938e76ec2dc1a7b5e6e4b9f958e284a9df 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !arm64 && !s390x && !ppc64le && !ppc64
-// +build !amd64,!arm64,!s390x,!ppc64le,!ppc64
 
 package bytealg
 
index 9547a5d8e2aa39e4ea7a543c09f8a555b099d313..6e4a2f39e4317fc4e7b7fe836bd8912cf141d093 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64 || s390x || ppc64le || ppc64
-// +build amd64 arm64 s390x ppc64le ppc64
 
 package bytealg
 
index c9b2b5a59f836dd1f45ede0766b04edbbc141377..ab3cbe5e96e6ba86e4e64ab8bb1ab069ed677411 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (aix || linux) && (ppc64 || ppc64le)
-// +build aix linux
-// +build ppc64 ppc64le
 
 package bytealg
 
index 3ed94421256115bef15079f524ff3672a7330f31..ab47495427dbae9ab3fcd44ea49bbf66b93e7114 100644 (file)
@@ -46,12 +46,20 @@ DATA byteswap<>+8(SB)/8, $0x0f0e0d0c0b0a0908
 
 GLOBL byteswap<>+0(SB), RODATA, $16
 
-TEXT ·Index(SB), NOSPLIT|NOFRAME, $0-56
+TEXT ·Index<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-56
+#ifdef GOEXPERIMENT_regabiargs 
+// R3 = byte array pointer 
+// R4 = length 
+        MOVD R6,R5             // R5 = separator pointer
+        MOVD R7,R6             // R6 = separator length 
+#else
        MOVD a_base+0(FP), R3  // R3 = byte array pointer
        MOVD a_len+8(FP), R4   // R4 = length
        MOVD b_base+24(FP), R5 // R5 = separator pointer
        MOVD b_len+32(FP), R6  // R6 = separator length
        MOVD $ret+48(FP), R14  // R14 = &ret
+#endif
+
 
 #ifdef GOARCH_ppc64le
        MOVBZ internal∕cpu·PPC64+const_offsetPPC64HasPOWER9(SB), R7
@@ -63,18 +71,21 @@ TEXT ·Index(SB), NOSPLIT|NOFRAME, $0-56
 power8:
        BR indexbody<>(SB)
 
-TEXT ·IndexString(SB), NOSPLIT|NOFRAME, $0-40
+TEXT ·IndexString<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
+#ifndef GOEXPERIMENT_regabiargs
        MOVD a_base+0(FP), R3  // R3 = string
        MOVD a_len+8(FP), R4   // R4 = length
        MOVD b_base+16(FP), R5 // R5 = separator pointer
        MOVD b_len+24(FP), R6  // R6 = separator length
        MOVD $ret+32(FP), R14  // R14 = &ret
+#endif
+
 
 #ifdef GOARCH_ppc64le
        MOVBZ internal∕cpu·PPC64+const_offsetPPC64HasPOWER9(SB), R7
        CMP   R7, $1
        BNE   power8
-       BR    indexbody<>(SB)
+       BR    indexbodyp9<>(SB)
 
 #endif
 power8:
@@ -141,7 +152,7 @@ loadge16:
        ANDCC $15, R5, R9 // Find byte offset of sep
        ADD   R9, R6, R10 // Add sep len
        CMP   R10, $16    // Check if sep len+offset > 16
-       BGE   sepcross16  // Sep crosses 16 byte boundary
+       BGT   sepcross16  // Sep crosses 16 byte boundary
 
        RLDICR $0, R5, $59, R8 // Adjust addr to 16 byte container
        VLOADSWAP(R8, R0, V0, V0_)// Load 16 bytes @R8 into V0
@@ -420,8 +431,12 @@ next17:
        BR         index17to32loop // Continue
 
 notfound:
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD $-1, R3   // Return -1 if not found
+#else
        MOVD $-1, R8   // Return -1 if not found
        MOVD R8, (R14)
+#endif
        RET
 
 index33plus:
@@ -432,12 +447,20 @@ foundR25:
        SRD  $3, R25   // Convert from bits to bytes
        ADD  R25, R7   // Add to current string address
        SUB  R3, R7    // Subtract from start of string
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD R7, R3    // Return byte where found
+#else
        MOVD R7, (R14) // Return byte where found
+#endif
        RET
 
 found:
        SUB  R3, R7    // Return byte where found
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD R7, R3
+#else
        MOVD R7, (R14)
+#endif
        RET
 
 TEXT indexbodyp9<>(SB), NOSPLIT|NOFRAME, $0
@@ -467,7 +490,7 @@ loadge16:
        ANDCC $15, R5, R9 // Find byte offset of sep
        ADD   R9, R6, R10 // Add sep len
        CMP   R10, $16    // Check if sep len+offset > 16
-       BGE   sepcross16  // Sep crosses 16 byte boundary
+       BGT   sepcross16  // Sep crosses 16 byte boundary
 
        RLDICR  $0, R5, $59, R8 // Adjust addr to 16 byte container
        LXVB16X (R8)(R0), V0_   // Load 16 bytes @R8 into V0
@@ -746,8 +769,12 @@ next17:
        BR         index17to32loop // Continue
 
 notfound:
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD $-1, R3   // Return -1 if not found
+#else
        MOVD $-1, R8   // Return -1 if not found
        MOVD R8, (R14)
+#endif
        RET
 
 index33plus:
@@ -758,11 +785,19 @@ foundR25:
        SRD  $3, R25   // Convert from bits to bytes
        ADD  R25, R7   // Add to current string address
        SUB  R3, R7    // Subtract from start of string
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD R7, R3    // Return byte where found
+#else
        MOVD R7, (R14) // Return byte where found
+#endif
        RET
 
 found:
        SUB  R3, R7    // Return byte where found
+#ifdef GOEXPERIMENT_regabiargs
+        MOVD R7, R3
+#else
        MOVD R7, (R14)
+#endif
        RET
 
index 6ef639fafdc992dd24023267efda30dca57947ef..0a45f903843edd8ae28d3ed07a63de5e7db35995 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386 && !amd64 && !s390x && !arm && !arm64 && !ppc64 && !ppc64le && !mips && !mipsle && !mips64 && !mips64le && !riscv64 && !wasm
-// +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!mips64,!mips64le,!riscv64,!wasm
 
 package bytealg
 
index 965f38fe52761cb34643ecbc6af03df92a94b91c..2101021e2d0254bcdc5b66b6a3633f01816cc38f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64 || s390x || arm || arm64 || ppc64 || ppc64le || mips || mipsle || mips64 || mips64le || riscv64 || wasm
-// +build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le riscv64 wasm
 
 package bytealg
 
index 8e13c5a56e348674dc6c232534b043a95d74c9b5..27e1ad7e0dd07fe48579f0b6c60e4ccfc9e0beb5 100644 (file)
@@ -8,20 +8,29 @@
 #include "go_asm.h"
 #include "textflag.h"
 
-TEXT ·IndexByte(SB),NOSPLIT|NOFRAME,$0-40
+TEXT ·IndexByte<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    b_base+0(FP), R3        // R3 = byte array pointer
        MOVD    b_len+8(FP), R4         // R4 = length
        MOVBZ   c+24(FP), R5            // R5 = byte
        MOVD    $ret+32(FP), R14        // R14 = &ret
+#else
+       MOVD    R6, R5
+#endif
        BR      indexbytebody<>(SB)
 
-TEXT ·IndexByteString(SB),NOSPLIT|NOFRAME,$0-32
+TEXT ·IndexByteString<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-32
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    s_base+0(FP), R3  // R3 = string
        MOVD    s_len+8(FP), R4   // R4 = length
        MOVBZ   c+16(FP), R5      // R5 = byte
        MOVD    $ret+24(FP), R14  // R14 = &ret
+#endif
        BR      indexbytebody<>(SB)
-
+// R3 = addr of string
+// R4 = len of string
+// R5 = byte to find
+// R14 = addr of return value when not regabi
 TEXT indexbytebody<>(SB),NOSPLIT|NOFRAME,$0-0
        MOVD    R3,R17          // Save base address for calculating the index later.
        RLDICR  $0,R3,$60,R8    // Align address to doubleword boundary in R8.
@@ -186,7 +195,9 @@ tail:
 
 notfound:
        MOVD    $-1,R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3,(R14)
+#endif
        RET
 
 found:
@@ -229,7 +240,9 @@ found:
 
 return:
        SUB     R17,R3
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3,(R14)
+#endif
        RET
 
 found_qw_align:
index 815994b679ac3c70658822a155d9981e4576da54..4cb3fbd4f342a4615a8483f352b45974b3a4ec79 100644 (file)
@@ -33,6 +33,7 @@ const KnownEnv = `
        GCCGO
        GO111MODULE
        GO386
+       GOAMD64
        GOARCH
        GOARM
        GOBIN
index dab5d068ef36e4ef5bf1d028bced35fc7cd5fa94..30745344e1c816e5986f386c0c112ebb981f98b2 100644 (file)
@@ -36,7 +36,7 @@ var X86 struct {
        HasOSXSAVE   bool
        HasPCLMULQDQ bool
        HasPOPCNT    bool
-       HasSSE2      bool
+       HasRDTSCP    bool
        HasSSE3      bool
        HasSSSE3     bool
        HasSSE41     bool
@@ -136,7 +136,6 @@ type option struct {
        Feature   *bool
        Specified bool // whether feature value was specified in GODEBUG
        Enable    bool // whether feature should be enabled
-       Required  bool // whether feature is mandatory and can not be disabled
 }
 
 // processOptions enables or disables CPU feature values based on the parsed env string.
@@ -179,7 +178,7 @@ field:
                if key == "all" {
                        for i := range options {
                                options[i].Specified = true
-                               options[i].Enable = enable || options[i].Required
+                               options[i].Enable = enable
                        }
                        continue field
                }
@@ -205,11 +204,6 @@ field:
                        continue
                }
 
-               if !o.Enable && o.Required {
-                       print("GODEBUG: can not disable \"", o.Name, "\", required CPU feature\n")
-                       continue
-               }
-
                *o.Feature = o.Enable
        }
 }
index ac6eee54b211389b095a5bc3acdaf30e46535fb5..fbdf7baca2f14d598ff002c4dea74b954780f84b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64
-// +build arm64
 
 package cpu
 
index ce1b250a18913792c2733007b3e0259fb64950f4..730e14caff09a9ac4e437127ff381cbafa21c337 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 && darwin && !ios
-// +build arm64,darwin,!ios
 
 package cpu
 
index 8c481370da65778478a7dbdbff65bc2b990c6193..c25e021c68f1c168cdd1be7d2df147585115fef5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64
-// +build arm64
 
 package cpu
 
index 8ac04fd8f975b8d5b18967b47c085c432948d360..0baa39f9cf79b0b98f6f92ecb5287578f790ec77 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 && linux
-// +build arm64,linux
 
 package cpu
 
index c3a3f9a8e9d64d97d3dc40546be5845503feda33..d746bdb063ed96cb2917bdb062fb9b2c510aedad 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 && linux && !android
-// +build arm64,linux,!android
 
 package cpu
 
index e8b5d529a4bbd6517b563bb6ece707c5ef54a9c4..d313648cb7c4544f6c1d3a0ab66cdd488124f674 100644 (file)
@@ -3,11 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 && !linux && !freebsd && !android && (!darwin || ios)
-// +build arm64
-// +build !linux
-// +build !freebsd
-// +build !android
-// +build !darwin ios
 
 package cpu
 
index d2f9d4499ba375f258cc163d328ef361e64441e2..c452ffd8b30216641232ad2f5c0713652c9488f5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips64 || mips64le
-// +build mips64 mips64le
 
 package cpu
 
index 8d563b536c3364ddcbe54e2fe6e0bbcf9c15cd2b..37de951ba6d783cd5e66b9a5f6e33496e132429e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386 && !amd64
-// +build !386,!amd64
 
 package cpu
 
index 2e7fd3ebb9f75fecb31ee0b2f2bc247a4bef6940..83687d6ed3438f8f933bc7b58b6b9122d761262b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package cpu
 
index 3d17a9c7304a565d926d91ff2462cc9098a8cd61..d518edcf490b7e23f09eb583715d845ca85a068b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package cpu
 
index b7c73451118b5a238e8c51f66a977e7db6b44ba0..7999656f01fc655d3eba347576d29c6160cd319c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package cpu
 
index 2de7365732d7482242648068aa78bdd77453ab25..8c21256b34825e4972c97814cc5740dee034f8b3 100644 (file)
@@ -6,31 +6,14 @@ package cpu_test
 
 import (
        . "internal/cpu"
+       "internal/godebug"
        "internal/testenv"
        "os"
        "os/exec"
-       "runtime"
        "strings"
        "testing"
 )
 
-func TestMinimalFeatures(t *testing.T) {
-       // TODO: maybe do MustSupportFeatureDectection(t) ?
-       if runtime.GOARCH == "arm64" {
-               switch runtime.GOOS {
-               case "linux", "android", "darwin":
-               default:
-                       t.Skipf("%s/%s is not supported", runtime.GOOS, runtime.GOARCH)
-               }
-       }
-
-       for _, o := range Options {
-               if o.Required && !*o.Feature {
-                       t.Errorf("%v expected true, got false", o.Name)
-               }
-       }
-}
-
 func MustHaveDebugOptionsSupport(t *testing.T) {
        if !DebugOptions {
                t.Skipf("skipping test: cpu feature options not supported by OS")
@@ -70,12 +53,12 @@ func TestDisableAllCapabilities(t *testing.T) {
 func TestAllCapabilitiesDisabled(t *testing.T) {
        MustHaveDebugOptionsSupport(t)
 
-       if os.Getenv("GODEBUG") != "cpu.all=off" {
+       if godebug.Get("cpu.all") != "off" {
                t.Skipf("skipping test: GODEBUG=cpu.all=off not set")
        }
 
        for _, o := range Options {
-               want := o.Required
+               want := false
                if got := *o.Feature; got != want {
                        t.Errorf("%v: expected %v, got %v", o.Name, want, got)
                }
index fd1217a05d7cab12bf2b7c0acd38553cafd47c03..81d5ceed61a1608698e581e936588c1899318a6a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64
-// +build 386 amd64
 
 package cpu
 
@@ -37,6 +36,9 @@ const (
        cpuid_BMI2 = 1 << 8
        cpuid_ERMS = 1 << 9
        cpuid_ADX  = 1 << 19
+
+       // edx bits for CPUID 0x80000001
+       cpuid_RDTSCP = 1 << 27
 )
 
 var maxExtendedFunctionInformation uint32
@@ -53,13 +55,11 @@ func doinit() {
                {Name: "fma", Feature: &X86.HasFMA},
                {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
                {Name: "popcnt", Feature: &X86.HasPOPCNT},
+               {Name: "rdtscp", Feature: &X86.HasRDTSCP},
                {Name: "sse3", Feature: &X86.HasSSE3},
                {Name: "sse41", Feature: &X86.HasSSE41},
                {Name: "sse42", Feature: &X86.HasSSE42},
                {Name: "ssse3", Feature: &X86.HasSSSE3},
-
-               // These capabilities should always be enabled on amd64:
-               {Name: "sse2", Feature: &X86.HasSSE2, Required: GOARCH == "amd64"},
        }
 
        maxID, _, _, _ := cpuid(0, 0)
@@ -70,8 +70,7 @@ func doinit() {
 
        maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0)
 
-       _, _, ecx1, edx1 := cpuid(1, 0)
-       X86.HasSSE2 = isSet(edx1, cpuid_SSE2)
+       _, _, ecx1, _ := cpuid(1, 0)
 
        X86.HasSSE3 = isSet(ecx1, cpuid_SSE3)
        X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ)
@@ -112,6 +111,16 @@ func doinit() {
        X86.HasBMI2 = isSet(ebx7, cpuid_BMI2)
        X86.HasERMS = isSet(ebx7, cpuid_ERMS)
        X86.HasADX = isSet(ebx7, cpuid_ADX)
+
+       var maxExtendedInformation uint32
+       maxExtendedInformation, _, _, _ = cpuid(0x80000000, 0)
+
+       if maxExtendedInformation < 0x80000001 {
+               return
+       }
+
+       _, _, _, edxExt1 := cpuid(0x80000001, 0)
+       X86.HasRDTSCP = isSet(edxExt1, cpuid_RDTSCP)
 }
 
 func isSet(hwc uint32, value uint32) bool {
index e3e16cc1612e05955295a965204ca0dc66e497aa..c8be210055c6e2ad3c3ad3ece9e358e9f40626b2 100644 (file)
@@ -3,14 +3,12 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64
-// +build 386 amd64
 
 package cpu_test
 
 import (
        . "internal/cpu"
-       "os"
-       "runtime"
+       "internal/godebug"
        "testing"
 )
 
@@ -20,23 +18,6 @@ func TestX86ifAVX2hasAVX(t *testing.T) {
        }
 }
 
-func TestDisableSSE2(t *testing.T) {
-       runDebugOptionsTest(t, "TestSSE2DebugOption", "cpu.sse2=off")
-}
-
-func TestSSE2DebugOption(t *testing.T) {
-       MustHaveDebugOptionsSupport(t)
-
-       if os.Getenv("GODEBUG") != "cpu.sse2=off" {
-               t.Skipf("skipping test: GODEBUG=cpu.sse2=off not set")
-       }
-
-       want := runtime.GOARCH != "386" // SSE2 can only be disabled on 386.
-       if got := X86.HasSSE2; got != want {
-               t.Errorf("X86.HasSSE2 on %s expected %v, got %v", runtime.GOARCH, want, got)
-       }
-}
-
 func TestDisableSSE3(t *testing.T) {
        runDebugOptionsTest(t, "TestSSE3DebugOption", "cpu.sse3=off")
 }
@@ -44,7 +25,7 @@ func TestDisableSSE3(t *testing.T) {
 func TestSSE3DebugOption(t *testing.T) {
        MustHaveDebugOptionsSupport(t)
 
-       if os.Getenv("GODEBUG") != "cpu.sse3=off" {
+       if godebug.Get("cpu.sse3") != "off" {
                t.Skipf("skipping test: GODEBUG=cpu.sse3=off not set")
        }
 
index 7127ba6ac3d970379f1aa29629418992c94c082d..34c1f477f0e31438209c5c96b4a1b20d2cf58511 100644 (file)
@@ -130,7 +130,7 @@ func compare(aVal, bVal reflect.Value) int {
                default:
                        return -1
                }
-       case reflect.Ptr, reflect.UnsafePointer:
+       case reflect.Pointer, reflect.UnsafePointer:
                a, b := aVal.Pointer(), bVal.Pointer()
                switch {
                case a < b:
diff --git a/src/internal/fuzz/counters_supported.go b/src/internal/fuzz/counters_supported.go
new file mode 100644 (file)
index 0000000..7ef553a
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 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:build (darwin || linux || windows || freebsd) && (amd64 || arm64)
+
+package fuzz
+
+import (
+       "internal/unsafeheader"
+       "unsafe"
+)
+
+// coverage returns a []byte containing unique 8-bit counters for each edge of
+// the instrumented source code. This coverage data will only be generated if
+// `-d=libfuzzer` is set at build time. This can be used to understand the code
+// coverage of a test execution.
+func coverage() []byte {
+       addr := unsafe.Pointer(&_counters)
+       size := uintptr(unsafe.Pointer(&_ecounters)) - uintptr(addr)
+
+       var res []byte
+       *(*unsafeheader.Slice)(unsafe.Pointer(&res)) = unsafeheader.Slice{
+               Data: addr,
+               Len:  int(size),
+               Cap:  int(size),
+       }
+       return res
+}
diff --git a/src/internal/fuzz/counters_unsupported.go b/src/internal/fuzz/counters_unsupported.go
new file mode 100644 (file)
index 0000000..bf28157
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: expand the set of supported platforms, with testing. Nothing about
+// the instrumentation is OS specific, but only amd64 and arm64 are
+// supported in the runtime. See src/runtime/libfuzzer*.
+//
+// If you update this constraint, also update cmd/internal/sys.FuzzInstrumeted.
+//
+//go:build !((darwin || linux || windows || freebsd) && (amd64 || arm64))
+
+package fuzz
+
+// TODO(#48504): re-enable on platforms where instrumentation works.
+// In theory, we shouldn't need this file at all: if the binary was built
+// without coverage, then _counters and _ecounters should have the same address.
+// However, this caused an init failure on aix/ppc64, so it's disabled here.
+
+// coverage returns a []byte containing unique 8-bit counters for each edge of
+// the instrumented source code. This coverage data will only be generated if
+// `-d=libfuzzer` is set at build time. This can be used to understand the code
+// coverage of a test execution.
+func coverage() []byte { return nil }
diff --git a/src/internal/fuzz/coverage.go b/src/internal/fuzz/coverage.go
new file mode 100644 (file)
index 0000000..3dee73b
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "fmt"
+       "math/bits"
+)
+
+// ResetCovereage sets all of the counters for each edge of the instrumented
+// source code to 0.
+func ResetCoverage() {
+       cov := coverage()
+       for i := range cov {
+               cov[i] = 0
+       }
+}
+
+// SnapshotCoverage copies the current counter values into coverageSnapshot,
+// preserving them for later inspection. SnapshotCoverage also rounds each
+// counter down to the nearest power of two. This lets the coordinator store
+// multiple values for each counter by OR'ing them together.
+func SnapshotCoverage() {
+       cov := coverage()
+       for i, b := range cov {
+               b |= b >> 1
+               b |= b >> 2
+               b |= b >> 4
+               b -= b >> 1
+               coverageSnapshot[i] = b
+       }
+}
+
+// diffCoverage returns a set of bits set in snapshot but not in base.
+// If there are no new bits set, diffCoverage returns nil.
+func diffCoverage(base, snapshot []byte) []byte {
+       if len(base) != len(snapshot) {
+               panic(fmt.Sprintf("the number of coverage bits changed: before=%d, after=%d", len(base), len(snapshot)))
+       }
+       found := false
+       for i := range snapshot {
+               if snapshot[i]&^base[i] != 0 {
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               return nil
+       }
+       diff := make([]byte, len(snapshot))
+       for i := range diff {
+               diff[i] = snapshot[i] &^ base[i]
+       }
+       return diff
+}
+
+// countNewCoverageBits returns the number of bits set in snapshot that are not
+// set in base.
+func countNewCoverageBits(base, snapshot []byte) int {
+       n := 0
+       for i := range snapshot {
+               n += bits.OnesCount8(snapshot[i] &^ base[i])
+       }
+       return n
+}
+
+// hasCoverageBit returns true if snapshot has at least one bit set that is
+// also set in base.
+func hasCoverageBit(base, snapshot []byte) bool {
+       for i := range snapshot {
+               if snapshot[i]&base[i] != 0 {
+                       return true
+               }
+       }
+       return false
+}
+
+func countBits(cov []byte) int {
+       n := 0
+       for _, c := range cov {
+               n += bits.OnesCount8(c)
+       }
+       return n
+}
+
+var (
+       coverageEnabled  = len(coverage()) > 0
+       coverageSnapshot = make([]byte, len(coverage()))
+
+       // _counters and _ecounters mark the start and end, respectively, of where
+       // the 8-bit coverage counters reside in memory. They're known to cmd/link,
+       // which specially assigns their addresses for this purpose.
+       _counters, _ecounters [0]byte
+)
diff --git a/src/internal/fuzz/encoding.go b/src/internal/fuzz/encoding.go
new file mode 100644 (file)
index 0000000..d3f24c3
--- /dev/null
@@ -0,0 +1,240 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "strconv"
+)
+
+// encVersion1 will be the first line of a file with version 1 encoding.
+var encVersion1 = "go test fuzz v1"
+
+// marshalCorpusFile encodes an arbitrary number of arguments into the file format for the
+// corpus.
+func marshalCorpusFile(vals ...interface{}) []byte {
+       if len(vals) == 0 {
+               panic("must have at least one value to marshal")
+       }
+       b := bytes.NewBuffer([]byte(encVersion1 + "\n"))
+       // TODO(katiehockman): keep uint8 and int32 encoding where applicable,
+       // instead of changing to byte and rune respectively.
+       for _, val := range vals {
+               switch t := val.(type) {
+               case int, int8, int16, int64, uint, uint16, uint32, uint64, float32, float64, bool:
+                       fmt.Fprintf(b, "%T(%v)\n", t, t)
+               case string:
+                       fmt.Fprintf(b, "string(%q)\n", t)
+               case rune: // int32
+                       fmt.Fprintf(b, "rune(%q)\n", t)
+               case byte: // uint8
+                       fmt.Fprintf(b, "byte(%q)\n", t)
+               case []byte: // []uint8
+                       fmt.Fprintf(b, "[]byte(%q)\n", t)
+               default:
+                       panic(fmt.Sprintf("unsupported type: %T", t))
+               }
+       }
+       return b.Bytes()
+}
+
+// unmarshalCorpusFile decodes corpus bytes into their respective values.
+func unmarshalCorpusFile(b []byte) ([]interface{}, error) {
+       if len(b) == 0 {
+               return nil, fmt.Errorf("cannot unmarshal empty string")
+       }
+       lines := bytes.Split(b, []byte("\n"))
+       if len(lines) < 2 {
+               return nil, fmt.Errorf("must include version and at least one value")
+       }
+       if string(lines[0]) != encVersion1 {
+               return nil, fmt.Errorf("unknown encoding version: %s", lines[0])
+       }
+       var vals []interface{}
+       for _, line := range lines[1:] {
+               line = bytes.TrimSpace(line)
+               if len(line) == 0 {
+                       continue
+               }
+               v, err := parseCorpusValue(line)
+               if err != nil {
+                       return nil, fmt.Errorf("malformed line %q: %v", line, err)
+               }
+               vals = append(vals, v)
+       }
+       return vals, nil
+}
+
+func parseCorpusValue(line []byte) (interface{}, error) {
+       fs := token.NewFileSet()
+       expr, err := parser.ParseExprFrom(fs, "(test)", line, 0)
+       if err != nil {
+               return nil, err
+       }
+       call, ok := expr.(*ast.CallExpr)
+       if !ok {
+               return nil, fmt.Errorf("expected call expression")
+       }
+       if len(call.Args) != 1 {
+               return nil, fmt.Errorf("expected call expression with 1 argument; got %d", len(call.Args))
+       }
+       arg := call.Args[0]
+
+       if arrayType, ok := call.Fun.(*ast.ArrayType); ok {
+               if arrayType.Len != nil {
+                       return nil, fmt.Errorf("expected []byte or primitive type")
+               }
+               elt, ok := arrayType.Elt.(*ast.Ident)
+               if !ok || elt.Name != "byte" {
+                       return nil, fmt.Errorf("expected []byte")
+               }
+               lit, ok := arg.(*ast.BasicLit)
+               if !ok || lit.Kind != token.STRING {
+                       return nil, fmt.Errorf("string literal required for type []byte")
+               }
+               s, err := strconv.Unquote(lit.Value)
+               if err != nil {
+                       return nil, err
+               }
+               return []byte(s), nil
+       }
+
+       idType, ok := call.Fun.(*ast.Ident)
+       if !ok {
+               return nil, fmt.Errorf("expected []byte or primitive type")
+       }
+       if idType.Name == "bool" {
+               id, ok := arg.(*ast.Ident)
+               if !ok {
+                       return nil, fmt.Errorf("malformed bool")
+               }
+               if id.Name == "true" {
+                       return true, nil
+               } else if id.Name == "false" {
+                       return false, nil
+               } else {
+                       return nil, fmt.Errorf("true or false required for type bool")
+               }
+       }
+       var (
+               val  string
+               kind token.Token
+       )
+       if op, ok := arg.(*ast.UnaryExpr); ok {
+               // Special case for negative numbers.
+               lit, ok := op.X.(*ast.BasicLit)
+               if !ok || (lit.Kind != token.INT && lit.Kind != token.FLOAT) {
+                       return nil, fmt.Errorf("expected operation on int or float type")
+               }
+               if op.Op != token.SUB {
+                       return nil, fmt.Errorf("unsupported operation on int: %v", op.Op)
+               }
+               val = op.Op.String() + lit.Value // e.g. "-" + "124"
+               kind = lit.Kind
+       } else {
+               lit, ok := arg.(*ast.BasicLit)
+               if !ok {
+                       return nil, fmt.Errorf("literal value required for primitive type")
+               }
+               val, kind = lit.Value, lit.Kind
+       }
+
+       switch typ := idType.Name; typ {
+       case "string":
+               if kind != token.STRING {
+                       return nil, fmt.Errorf("string literal value required for type string")
+               }
+               return strconv.Unquote(val)
+       case "byte", "rune":
+               if kind != token.CHAR {
+                       return nil, fmt.Errorf("character literal required for byte/rune types")
+               }
+               n := len(val)
+               if n < 2 {
+                       return nil, fmt.Errorf("malformed character literal, missing single quotes")
+               }
+               code, _, _, err := strconv.UnquoteChar(val[1:n-1], '\'')
+               if err != nil {
+                       return nil, err
+               }
+               if typ == "rune" {
+                       return code, nil
+               }
+               if code >= 256 {
+                       return nil, fmt.Errorf("can only encode single byte to a byte type")
+               }
+               return byte(code), nil
+       case "int", "int8", "int16", "int32", "int64":
+               if kind != token.INT {
+                       return nil, fmt.Errorf("integer literal required for int types")
+               }
+               return parseInt(val, typ)
+       case "uint", "uint8", "uint16", "uint32", "uint64":
+               if kind != token.INT {
+                       return nil, fmt.Errorf("integer literal required for uint types")
+               }
+               return parseUint(val, typ)
+       case "float32":
+               if kind != token.FLOAT && kind != token.INT {
+                       return nil, fmt.Errorf("float or integer literal required for float32 type")
+               }
+               v, err := strconv.ParseFloat(val, 32)
+               return float32(v), err
+       case "float64":
+               if kind != token.FLOAT && kind != token.INT {
+                       return nil, fmt.Errorf("float or integer literal required for float64 type")
+               }
+               return strconv.ParseFloat(val, 64)
+       default:
+               return nil, fmt.Errorf("expected []byte or primitive type")
+       }
+}
+
+// parseInt returns an integer of value val and type typ.
+func parseInt(val, typ string) (interface{}, error) {
+       switch typ {
+       case "int":
+               return strconv.Atoi(val)
+       case "int8":
+               i, err := strconv.ParseInt(val, 10, 8)
+               return int8(i), err
+       case "int16":
+               i, err := strconv.ParseInt(val, 10, 16)
+               return int16(i), err
+       case "int32":
+               i, err := strconv.ParseInt(val, 10, 32)
+               return int32(i), err
+       case "int64":
+               return strconv.ParseInt(val, 10, 64)
+       default:
+               panic("unreachable")
+       }
+}
+
+// parseInt returns an unsigned integer of value val and type typ.
+func parseUint(val, typ string) (interface{}, error) {
+       switch typ {
+       case "uint":
+               i, err := strconv.ParseUint(val, 10, 0)
+               return uint(i), err
+       case "uint8":
+               i, err := strconv.ParseUint(val, 10, 8)
+               return uint8(i), err
+       case "uint16":
+               i, err := strconv.ParseUint(val, 10, 16)
+               return uint16(i), err
+       case "uint32":
+               i, err := strconv.ParseUint(val, 10, 32)
+               return uint32(i), err
+       case "uint64":
+               return strconv.ParseUint(val, 10, 64)
+       default:
+               panic("unreachable")
+       }
+}
diff --git a/src/internal/fuzz/encoding_test.go b/src/internal/fuzz/encoding_test.go
new file mode 100644 (file)
index 0000000..b429d42
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "strconv"
+       "strings"
+       "testing"
+)
+
+func TestUnmarshalMarshal(t *testing.T) {
+       var tests = []struct {
+               in string
+               ok bool
+       }{
+               {
+                       in: "int(1234)",
+                       ok: false, // missing version
+               },
+               {
+                       in: `go test fuzz v1
+string("a"bcad")`,
+                       ok: false, // malformed
+               },
+               {
+                       in: `go test fuzz v1
+int()`,
+                       ok: false, // empty value
+               },
+               {
+                       in: `go test fuzz v1
+uint(-32)`,
+                       ok: false, // invalid negative uint
+               },
+               {
+                       in: `go test fuzz v1
+int8(1234456)`,
+                       ok: false, // int8 too large
+               },
+               {
+                       in: `go test fuzz v1
+int(20*5)`,
+                       ok: false, // expression in int value
+               },
+               {
+                       in: `go test fuzz v1
+int(--5)`,
+                       ok: false, // expression in int value
+               },
+               {
+                       in: `go test fuzz v1
+bool(0)`,
+                       ok: false, // malformed bool
+               },
+               {
+                       in: `go test fuzz v1
+byte('aa)`,
+                       ok: false, // malformed byte
+               },
+               {
+                       in: `go test fuzz v1
+byte('☃')`,
+                       ok: false, // byte out of range
+               },
+               {
+                       in: `go test fuzz v1
+string("has final newline")
+`,
+                       ok: true, // has final newline
+               },
+               {
+                       in: `go test fuzz v1
+string("extra")
+[]byte("spacing")  
+    `,
+                       ok: true, // extra spaces in the final newline
+               },
+               {
+                       in: `go test fuzz v1
+float64(0)
+float32(0)`,
+                       ok: true, // will be an integer literal since there is no decimal
+               },
+               {
+                       in: `go test fuzz v1
+int(-23)
+int8(-2)
+int64(2342425)
+uint(1)
+uint16(234)
+uint32(352342)
+uint64(123)
+rune('œ')
+byte('K')
+byte('ÿ')
+[]byte("hello¿")
+[]byte("a")
+bool(true)
+string("hello\\xbd\\xb2=\\xbc ⌘")
+float64(-12.5)
+float32(2.5)`,
+                       ok: true,
+               },
+       }
+       for _, test := range tests {
+               t.Run(test.in, func(t *testing.T) {
+                       vals, err := unmarshalCorpusFile([]byte(test.in))
+                       if test.ok && err != nil {
+                               t.Fatalf("unmarshal unexpected error: %v", err)
+                       } else if !test.ok && err == nil {
+                               t.Fatalf("unmarshal unexpected success")
+                       }
+                       if !test.ok {
+                               return // skip the rest of the test
+                       }
+                       newB := marshalCorpusFile(vals...)
+                       if err != nil {
+                               t.Fatalf("marshal unexpected error: %v", err)
+                       }
+                       if newB[len(newB)-1] != '\n' {
+                               t.Error("didn't write final newline to corpus file")
+                       }
+                       before, after := strings.TrimSpace(test.in), strings.TrimSpace(string(newB))
+                       if before != after {
+                               t.Errorf("values changed after unmarshal then marshal\nbefore: %q\nafter:  %q", before, after)
+                       }
+               })
+       }
+}
+
+// BenchmarkMarshalCorpusFile measures the time it takes to serialize byte
+// slices of various sizes to a corpus file. The slice contains a repeating
+// sequence of bytes 0-255 to mix escaped and non-escaped characters.
+func BenchmarkMarshalCorpusFile(b *testing.B) {
+       buf := make([]byte, 1024*1024)
+       for i := 0; i < len(buf); i++ {
+               buf[i] = byte(i)
+       }
+
+       for sz := 1; sz <= len(buf); sz <<= 1 {
+               sz := sz
+               b.Run(strconv.Itoa(sz), func(b *testing.B) {
+                       for i := 0; i < b.N; i++ {
+                               b.SetBytes(int64(sz))
+                               marshalCorpusFile(buf[:sz])
+                       }
+               })
+       }
+}
+
+// BenchmarkUnmarshalCorpusfile measures the time it takes to deserialize
+// files encoding byte slices of various sizes. The slice contains a repeating
+// sequence of bytes 0-255 to mix escaped and non-escaped characters.
+func BenchmarkUnmarshalCorpusFile(b *testing.B) {
+       buf := make([]byte, 1024*1024)
+       for i := 0; i < len(buf); i++ {
+               buf[i] = byte(i)
+       }
+
+       for sz := 1; sz <= len(buf); sz <<= 1 {
+               sz := sz
+               data := marshalCorpusFile(buf[:sz])
+               b.Run(strconv.Itoa(sz), func(b *testing.B) {
+                       for i := 0; i < b.N; i++ {
+                               b.SetBytes(int64(sz))
+                               unmarshalCorpusFile(data)
+                       }
+               })
+       }
+}
diff --git a/src/internal/fuzz/fuzz.go b/src/internal/fuzz/fuzz.go
new file mode 100644 (file)
index 0000000..8bd40fe
--- /dev/null
@@ -0,0 +1,1074 @@
+// 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 fuzz provides common fuzzing functionality for tests built with
+// "go test" and for programs that use fuzzing functionality in the testing
+// package.
+package fuzz
+
+import (
+       "context"
+       "crypto/sha256"
+       "errors"
+       "fmt"
+       "internal/godebug"
+       "io"
+       "io/ioutil"
+       "math/bits"
+       "os"
+       "path/filepath"
+       "reflect"
+       "runtime"
+       "strings"
+       "sync"
+       "time"
+)
+
+// CoordinateFuzzingOpts is a set of arguments for CoordinateFuzzing.
+// The zero value is valid for each field unless specified otherwise.
+type CoordinateFuzzingOpts struct {
+       // Log is a writer for logging progress messages and warnings.
+       // If nil, io.Discard will be used instead.
+       Log io.Writer
+
+       // Timeout is the amount of wall clock time to spend fuzzing after the corpus
+       // has loaded. If zero, there will be no time limit.
+       Timeout time.Duration
+
+       // Limit is the number of random values to generate and test. If zero,
+       // there will be no limit on the number of generated values.
+       Limit int64
+
+       // MinimizeTimeout is the amount of wall clock time to spend minimizing
+       // after discovering a crasher. If zero, there will be no time limit. If
+       // MinimizeTimeout and MinimizeLimit are both zero, then minimization will
+       // be disabled.
+       MinimizeTimeout time.Duration
+
+       // MinimizeLimit is the maximum number of calls to the fuzz function to be
+       // made while minimizing after finding a crash. If zero, there will be no
+       // limit. Calls to the fuzz function made when minimizing also count toward
+       // Limit. If MinimizeTimeout and MinimizeLimit are both zero, then
+       // minimization will be disabled.
+       MinimizeLimit int64
+
+       // parallel is the number of worker processes to run in parallel. If zero,
+       // CoordinateFuzzing will run GOMAXPROCS workers.
+       Parallel int
+
+       // Seed is a list of seed values added by the fuzz target with testing.F.Add
+       // and in testdata.
+       Seed []CorpusEntry
+
+       // Types is the list of types which make up a corpus entry.
+       // Types must be set and must match values in Seed.
+       Types []reflect.Type
+
+       // CorpusDir is a directory where files containing values that crash the
+       // code being tested may be written. CorpusDir must be set.
+       CorpusDir string
+
+       // CacheDir is a directory containing additional "interesting" values.
+       // The fuzzer may derive new values from these, and may write new values here.
+       CacheDir string
+}
+
+// CoordinateFuzzing creates several worker processes and communicates with
+// them to test random inputs that could trigger crashes and expose bugs.
+// The worker processes run the same binary in the same directory with the
+// same environment variables as the coordinator process. Workers also run
+// with the same arguments as the coordinator, except with the -test.fuzzworker
+// flag prepended to the argument list.
+//
+// If a crash occurs, the function will return an error containing information
+// about the crash, which can be reported to the user.
+func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err error) {
+       if err := ctx.Err(); err != nil {
+               return err
+       }
+       if opts.Log == nil {
+               opts.Log = io.Discard
+       }
+       if opts.Parallel == 0 {
+               opts.Parallel = runtime.GOMAXPROCS(0)
+       }
+       if opts.Limit > 0 && int64(opts.Parallel) > opts.Limit {
+               // Don't start more workers than we need.
+               opts.Parallel = int(opts.Limit)
+       }
+
+       c, err := newCoordinator(opts)
+       if err != nil {
+               return err
+       }
+
+       if opts.Timeout > 0 {
+               var cancel func()
+               ctx, cancel = context.WithTimeout(ctx, opts.Timeout)
+               defer cancel()
+       }
+
+       // fuzzCtx is used to stop workers, for example, after finding a crasher.
+       fuzzCtx, cancelWorkers := context.WithCancel(ctx)
+       defer cancelWorkers()
+       doneC := ctx.Done()
+
+       // stop is called when a worker encounters a fatal error.
+       var fuzzErr error
+       stopping := false
+       stop := func(err error) {
+               if err == fuzzCtx.Err() || isInterruptError(err) {
+                       // Suppress cancellation errors and terminations due to SIGINT.
+                       // The messages are not helpful since either the user triggered the error
+                       // (with ^C) or another more helpful message will be printed (a crasher).
+                       err = nil
+               }
+               if err != nil && (fuzzErr == nil || fuzzErr == ctx.Err()) {
+                       fuzzErr = err
+               }
+               if stopping {
+                       return
+               }
+               stopping = true
+               cancelWorkers()
+               doneC = nil
+       }
+
+       // Ensure that any crash we find is written to the corpus, even if an error
+       // or interruption occurs while minimizing it.
+       crashWritten := false
+       defer func() {
+               if c.crashMinimizing == nil || crashWritten {
+                       return
+               }
+               werr := writeToCorpus(&c.crashMinimizing.entry, opts.CorpusDir)
+               if werr != nil {
+                       err = fmt.Errorf("%w\n%v", err, werr)
+                       return
+               }
+               if err == nil {
+                       err = &crashError{
+                               path: c.crashMinimizing.entry.Path,
+                               err:  errors.New(c.crashMinimizing.crasherMsg),
+                       }
+               }
+       }()
+
+       // Start workers.
+       // TODO(jayconrod): do we want to support fuzzing different binaries?
+       dir := "" // same as self
+       binPath := os.Args[0]
+       args := append([]string{"-test.fuzzworker"}, os.Args[1:]...)
+       env := os.Environ() // same as self
+
+       errC := make(chan error)
+       workers := make([]*worker, opts.Parallel)
+       for i := range workers {
+               var err error
+               workers[i], err = newWorker(c, dir, binPath, args, env)
+               if err != nil {
+                       return err
+               }
+       }
+       for i := range workers {
+               w := workers[i]
+               go func() {
+                       err := w.coordinate(fuzzCtx)
+                       if fuzzCtx.Err() != nil || isInterruptError(err) {
+                               err = nil
+                       }
+                       cleanErr := w.cleanup()
+                       if err == nil {
+                               err = cleanErr
+                       }
+                       errC <- err
+               }()
+       }
+
+       // Main event loop.
+       // Do not return until all workers have terminated. We avoid a deadlock by
+       // receiving messages from workers even after ctx is cancelled.
+       activeWorkers := len(workers)
+       statTicker := time.NewTicker(3 * time.Second)
+       defer statTicker.Stop()
+       defer c.logStats()
+
+       c.logStats()
+       for {
+               var inputC chan fuzzInput
+               input, ok := c.peekInput()
+               if ok && c.crashMinimizing == nil && !stopping {
+                       inputC = c.inputC
+               }
+
+               var minimizeC chan fuzzMinimizeInput
+               minimizeInput, ok := c.peekMinimizeInput()
+               if ok && !stopping {
+                       minimizeC = c.minimizeC
+               }
+
+               select {
+               case <-doneC:
+                       // Interrupted, cancelled, or timed out.
+                       // stop sets doneC to nil so we don't busy wait here.
+                       stop(ctx.Err())
+
+               case err := <-errC:
+                       // A worker terminated, possibly after encountering a fatal error.
+                       stop(err)
+                       activeWorkers--
+                       if activeWorkers == 0 {
+                               return fuzzErr
+                       }
+
+               case result := <-c.resultC:
+                       // Received response from worker.
+                       if stopping {
+                               break
+                       }
+                       c.updateStats(result)
+
+                       if result.crasherMsg != "" {
+                               if c.warmupRun() && result.entry.IsSeed {
+                                       target := filepath.Base(c.opts.CorpusDir)
+                                       fmt.Fprintf(c.opts.Log, "found a crash while testing seed corpus entry: %s/%s\n", target, testName(result.entry.Parent))
+                                       stop(errors.New(result.crasherMsg))
+                                       break
+                               }
+                               if c.canMinimize() && result.canMinimize {
+                                       if c.crashMinimizing != nil {
+                                               // This crash is not minimized, and another crash is being minimized.
+                                               // Ignore this one and wait for the other one to finish.
+                                               break
+                                       }
+                                       // Found a crasher but haven't yet attempted to minimize it.
+                                       // Send it back to a worker for minimization. Disable inputC so
+                                       // other workers don't continue fuzzing.
+                                       c.crashMinimizing = &result
+                                       fmt.Fprintf(c.opts.Log, "fuzz: minimizing %d-byte crash file\n", len(result.entry.Data))
+                                       c.queueForMinimization(result, nil)
+                               } else if !crashWritten {
+                                       // Found a crasher that's either minimized or not minimizable.
+                                       // Write to corpus and stop.
+                                       err := writeToCorpus(&result.entry, opts.CorpusDir)
+                                       if err == nil {
+                                               crashWritten = true
+                                               err = &crashError{
+                                                       path: result.entry.Path,
+                                                       err:  errors.New(result.crasherMsg),
+                                               }
+                                       }
+                                       if shouldPrintDebugInfo() {
+                                               fmt.Fprintf(
+                                                       c.opts.Log,
+                                                       "DEBUG new crasher, elapsed: %s, id: %s, parent: %s, gen: %d, size: %d, exec time: %s\n",
+                                                       c.elapsed(),
+                                                       result.entry.Path,
+                                                       result.entry.Parent,
+                                                       result.entry.Generation,
+                                                       len(result.entry.Data),
+                                                       result.entryDuration,
+                                               )
+                                       }
+                                       stop(err)
+                               }
+                       } else if result.coverageData != nil {
+                               if c.warmupRun() {
+                                       if shouldPrintDebugInfo() {
+                                               fmt.Fprintf(
+                                                       c.opts.Log,
+                                                       "DEBUG processed an initial input, elapsed: %s, id: %s, new bits: %d, size: %d, exec time: %s\n",
+                                                       c.elapsed(),
+                                                       result.entry.Parent,
+                                                       countBits(diffCoverage(c.coverageMask, result.coverageData)),
+                                                       len(result.entry.Data),
+                                                       result.entryDuration,
+                                               )
+                                       }
+                                       c.updateCoverage(result.coverageData)
+                                       c.warmupInputLeft--
+                                       if c.warmupInputLeft == 0 {
+                                               fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, gathering baseline coverage: %d/%d completed, now fuzzing with %d workers\n", c.elapsed(), c.warmupInputCount, c.warmupInputCount, c.opts.Parallel)
+                                               if shouldPrintDebugInfo() {
+                                                       fmt.Fprintf(
+                                                               c.opts.Log,
+                                                               "DEBUG finished processing input corpus, elapsed: %s, entries: %d, initial coverage bits: %d\n",
+                                                               c.elapsed(),
+                                                               len(c.corpus.entries),
+                                                               countBits(c.coverageMask),
+                                                       )
+                                               }
+                                       }
+                               } else if keepCoverage := diffCoverage(c.coverageMask, result.coverageData); keepCoverage != nil {
+                                       // Found a value that expanded coverage.
+                                       // It's not a crasher, but we may want to add it to the on-disk
+                                       // corpus and prioritize it for future fuzzing.
+                                       // TODO(jayconrod, katiehockman): Prioritize fuzzing these
+                                       // values which expanded coverage, perhaps based on the
+                                       // number of new edges that this result expanded.
+                                       // TODO(jayconrod, katiehockman): Don't write a value that's already
+                                       // in the corpus.
+                                       if c.canMinimize() && result.canMinimize && c.crashMinimizing == nil {
+                                               // Send back to workers to find a smaller value that preserves
+                                               // at least one new coverage bit.
+                                               c.queueForMinimization(result, keepCoverage)
+                                       } else {
+                                               // Update the coordinator's coverage mask and save the value.
+                                               inputSize := len(result.entry.Data)
+                                               if opts.CacheDir != "" {
+                                                       // It is possible that the input that was discovered is already
+                                                       // present in the corpus, but the worker produced a coverage map
+                                                       // that still expanded our total coverage (this may happen due to
+                                                       // flakiness in the coverage counters). In order to prevent adding
+                                                       // duplicate entries to the corpus (and re-writing the file on
+                                                       // disk), skip it if the on disk file already exists.
+                                                       // TOOD(roland): this check is limited in that it will only be
+                                                       // applied if we are using the CacheDir. Another option would be
+                                                       // to iterate through the corpus and check if it is already present,
+                                                       // which would catch cases where we are not caching entries.
+                                                       // A slightly faster approach would be to keep some kind of map of
+                                                       // entry hashes, which would allow us to avoid iterating through
+                                                       // all entries.
+                                                       _, err = os.Stat(result.entry.Path)
+                                                       if err == nil {
+                                                               continue
+                                                       }
+                                                       err := writeToCorpus(&result.entry, opts.CacheDir)
+                                                       if err != nil {
+                                                               stop(err)
+                                                       }
+                                                       result.entry.Data = nil
+                                               }
+                                               c.updateCoverage(keepCoverage)
+                                               c.corpus.entries = append(c.corpus.entries, result.entry)
+                                               c.inputQueue.enqueue(result.entry)
+                                               c.interestingCount++
+                                               if shouldPrintDebugInfo() {
+                                                       fmt.Fprintf(
+                                                               c.opts.Log,
+                                                               "DEBUG new interesting input, elapsed: %s, id: %s, parent: %s, gen: %d, new bits: %d, total bits: %d, size: %d, exec time: %s\n",
+                                                               c.elapsed(),
+                                                               result.entry.Path,
+                                                               result.entry.Parent,
+                                                               result.entry.Generation,
+                                                               countBits(keepCoverage),
+                                                               countBits(c.coverageMask),
+                                                               inputSize,
+                                                               result.entryDuration,
+                                                       )
+                                               }
+                                       }
+                               } else {
+                                       if shouldPrintDebugInfo() {
+                                               fmt.Fprintf(
+                                                       c.opts.Log,
+                                                       "DEBUG worker reported interesting input that doesn't expand coverage, elapsed: %s, id: %s, parent: %s, canMinimize: %t\n",
+                                                       c.elapsed(),
+                                                       result.entry.Path,
+                                                       result.entry.Parent,
+                                                       result.canMinimize,
+                                               )
+                                       }
+                               }
+                       } else if c.warmupRun() {
+                               // No error or coverage data was reported for this input during
+                               // warmup, so continue processing results.
+                               c.warmupInputLeft--
+                               if c.warmupInputLeft == 0 {
+                                       fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, testing seed corpus: %d/%d completed, now fuzzing with %d workers\n", c.elapsed(), c.warmupInputCount, c.warmupInputCount, c.opts.Parallel)
+                                       if shouldPrintDebugInfo() {
+                                               fmt.Fprintf(
+                                                       c.opts.Log,
+                                                       "DEBUG finished testing-only phase, elapsed: %s, entries: %d\n",
+                                                       time.Since(c.startTime),
+                                                       len(c.corpus.entries),
+                                               )
+                                       }
+                               }
+                       }
+
+                       // Once the result has been processed, stop the worker if we
+                       // have reached the fuzzing limit.
+                       if c.opts.Limit > 0 && c.count >= c.opts.Limit {
+                               stop(nil)
+                       }
+
+               case inputC <- input:
+                       // Sent the next input to a worker.
+                       c.sentInput(input)
+
+               case minimizeC <- minimizeInput:
+                       // Sent the next input for minimization to a worker.
+                       c.sentMinimizeInput(minimizeInput)
+
+               case <-statTicker.C:
+                       c.logStats()
+               }
+       }
+
+       // TODO(jayconrod,katiehockman): if a crasher can't be written to the corpus,
+       // write to the cache instead.
+}
+
+// crashError wraps a crasher written to the seed corpus. It saves the name
+// of the file where the input causing the crasher was saved. The testing
+// framework uses this to report a command to re-run that specific input.
+type crashError struct {
+       path string
+       err  error
+}
+
+func (e *crashError) Error() string {
+       return e.err.Error()
+}
+
+func (e *crashError) Unwrap() error {
+       return e.err
+}
+
+func (e *crashError) CrashPath() string {
+       return e.path
+}
+
+type corpus struct {
+       entries []CorpusEntry
+}
+
+// CorpusEntry represents an individual input for fuzzing.
+//
+// We must use an equivalent type in the testing and testing/internal/testdeps
+// packages, but testing can't import this package directly, and we don't want
+// to export this type from testing. Instead, we use the same struct type and
+// use a type alias (not a defined type) for convenience.
+type CorpusEntry = struct {
+       Parent string
+
+       // Path is the path of the corpus file, if the entry was loaded from disk.
+       // For other entries, including seed values provided by f.Add, Path is the
+       // name of the test, e.g. seed#0 or its hash.
+       Path string
+
+       // Data is the raw input data. Data should only be populated for seed
+       // values. For on-disk corpus files, Data will be nil, as it will be loaded
+       // from disk using Path.
+       Data []byte
+
+       // Values is the unmarshaled values from a corpus file.
+       Values []interface{}
+
+       Generation int
+
+       // IsSeed indicates whether this entry is part of the seed corpus.
+       IsSeed bool
+}
+
+// Data returns the raw input bytes, either from the data struct field,
+// or from disk.
+func CorpusEntryData(ce CorpusEntry) ([]byte, error) {
+       if ce.Data != nil {
+               return ce.Data, nil
+       }
+
+       return os.ReadFile(ce.Path)
+}
+
+type fuzzInput struct {
+       // entry is the value to test initially. The worker will randomly mutate
+       // values from this starting point.
+       entry CorpusEntry
+
+       // timeout is the time to spend fuzzing variations of this input,
+       // not including starting or cleaning up.
+       timeout time.Duration
+
+       // limit is the maximum number of calls to the fuzz function the worker may
+       // make. The worker may make fewer calls, for example, if it finds an
+       // error early. If limit is zero, there is no limit on calls to the
+       // fuzz function.
+       limit int64
+
+       // warmup indicates whether this is a warmup input before fuzzing begins. If
+       // true, the input should not be fuzzed.
+       warmup bool
+
+       // coverageData reflects the coordinator's current coverageMask.
+       coverageData []byte
+}
+
+type fuzzResult struct {
+       // entry is an interesting value or a crasher.
+       entry CorpusEntry
+
+       // crasherMsg is an error message from a crash. It's "" if no crash was found.
+       crasherMsg string
+
+       // canMinimize is true if the worker should attempt to minimize this result.
+       // It may be false because an attempt has already been made.
+       canMinimize bool
+
+       // coverageData is set if the worker found new coverage.
+       coverageData []byte
+
+       // limit is the number of values the coordinator asked the worker
+       // to test. 0 if there was no limit.
+       limit int64
+
+       // count is the number of values the worker actually tested.
+       count int64
+
+       // totalDuration is the time the worker spent testing inputs.
+       totalDuration time.Duration
+
+       // entryDuration is the time the worker spent execution an interesting result
+       entryDuration time.Duration
+}
+
+type fuzzMinimizeInput struct {
+       // entry is an interesting value or crasher to minimize.
+       entry CorpusEntry
+
+       // crasherMsg is an error message from a crash. It's "" if no crash was found.
+       // If set, the worker will attempt to find a smaller input that also produces
+       // an error, though not necessarily the same error.
+       crasherMsg string
+
+       // limit is the maximum number of calls to the fuzz function the worker may
+       // make. The worker may make fewer calls, for example, if it can't reproduce
+       // an error. If limit is zero, there is no limit on calls to the fuzz function.
+       limit int64
+
+       // timeout is the time to spend minimizing this input.
+       // A zero timeout means no limit.
+       timeout time.Duration
+
+       // keepCoverage is a set of coverage bits that entry found that were not in
+       // the coordinator's combined set. When minimizing, the worker should find an
+       // input that preserves at least one of these bits. keepCoverage is nil for
+       // crashing inputs.
+       keepCoverage []byte
+}
+
+// coordinator holds channels that workers can use to communicate with
+// the coordinator.
+type coordinator struct {
+       opts CoordinateFuzzingOpts
+
+       // startTime is the time we started the workers after loading the corpus.
+       // Used for logging.
+       startTime time.Time
+
+       // inputC is sent values to fuzz by the coordinator. Any worker may receive
+       // values from this channel. Workers send results to resultC.
+       inputC chan fuzzInput
+
+       // minimizeC is sent values to minimize by the coordinator. Any worker may
+       // receive values from this channel. Workers send results to resultC.
+       minimizeC chan fuzzMinimizeInput
+
+       // resultC is sent results of fuzzing by workers. The coordinator
+       // receives these. Multiple types of messages are allowed.
+       resultC chan fuzzResult
+
+       // count is the number of values fuzzed so far.
+       count int64
+
+       // countLastLog is the number of values fuzzed when the output was last
+       // logged.
+       countLastLog int64
+
+       // timeLastLog is the time at which the output was last logged.
+       timeLastLog time.Time
+
+       // interestingCount is the number of unique interesting values which have
+       // been found this execution.
+       interestingCount int64
+
+       // warmupInputCount is the count of all entries in the corpus which will
+       // need to be received from workers to run once during warmup, but not fuzz.
+       // This could be for coverage data, or only for the purposes of verifying
+       // that the seed corpus doesn't have any crashers. See warmupRun.
+       warmupInputCount int
+
+       // warmupInputLeft is the number of entries in the corpus which still need
+       // to be received from workers to run once during warmup, but not fuzz.
+       // See warmupInputLeft.
+       warmupInputLeft int
+
+       // duration is the time spent fuzzing inside workers, not counting time
+       // starting up or tearing down.
+       duration time.Duration
+
+       // countWaiting is the number of fuzzing executions the coordinator is
+       // waiting on workers to complete.
+       countWaiting int64
+
+       // corpus is a set of interesting values, including the seed corpus and
+       // generated values that workers reported as interesting.
+       corpus corpus
+
+       // minimizationAllowed is true if one or more of the types of fuzz
+       // function's parameters can be minimized.
+       minimizationAllowed bool
+
+       // inputQueue is a queue of inputs that workers should try fuzzing. This is
+       // initially populated from the seed corpus and cached inputs. More inputs
+       // may be added as new coverage is discovered.
+       inputQueue queue
+
+       // minimizeQueue is a queue of inputs that caused errors or exposed new
+       // coverage. Workers should attempt to find smaller inputs that do the
+       // same thing.
+       minimizeQueue queue
+
+       // crashMinimizing is the crash that is currently being minimized.
+       crashMinimizing *fuzzResult
+
+       // coverageMask aggregates coverage that was found for all inputs in the
+       // corpus. Each byte represents a single basic execution block. Each set bit
+       // within the byte indicates that an input has triggered that block at least
+       // 1 << n times, where n is the position of the bit in the byte. For example, a
+       // value of 12 indicates that separate inputs have triggered this block
+       // between 4-7 times and 8-15 times.
+       coverageMask []byte
+}
+
+func newCoordinator(opts CoordinateFuzzingOpts) (*coordinator, error) {
+       // Make sure all of the seed corpus has marshalled data.
+       for i := range opts.Seed {
+               if opts.Seed[i].Data == nil && opts.Seed[i].Values != nil {
+                       opts.Seed[i].Data = marshalCorpusFile(opts.Seed[i].Values...)
+               }
+       }
+       corpus, err := readCache(opts.Seed, opts.Types, opts.CacheDir)
+       if err != nil {
+               return nil, err
+       }
+       c := &coordinator{
+               opts:        opts,
+               startTime:   time.Now(),
+               inputC:      make(chan fuzzInput),
+               minimizeC:   make(chan fuzzMinimizeInput),
+               resultC:     make(chan fuzzResult),
+               corpus:      corpus,
+               timeLastLog: time.Now(),
+       }
+       if opts.MinimizeLimit > 0 || opts.MinimizeTimeout > 0 {
+               for _, t := range opts.Types {
+                       if isMinimizable(t) {
+                               c.minimizationAllowed = true
+                               break
+                       }
+               }
+       }
+
+       covSize := len(coverage())
+       if covSize == 0 {
+               fmt.Fprintf(c.opts.Log, "warning: the test binary was not built with coverage instrumentation, so fuzzing will run without coverage guidance and may be inefficient\n")
+               // Even though a coverage-only run won't occur, we should still run all
+               // of the seed corpus to make sure there are no existing failures before
+               // we start fuzzing.
+               c.warmupInputCount = len(c.opts.Seed)
+               for _, e := range c.opts.Seed {
+                       c.inputQueue.enqueue(e)
+               }
+       } else {
+               c.warmupInputCount = len(c.corpus.entries)
+               for _, e := range c.corpus.entries {
+                       c.inputQueue.enqueue(e)
+               }
+               // Set c.coverageMask to a clean []byte full of zeros.
+               c.coverageMask = make([]byte, covSize)
+       }
+       c.warmupInputLeft = c.warmupInputCount
+
+       if len(c.corpus.entries) == 0 {
+               fmt.Fprintf(c.opts.Log, "warning: starting with empty corpus\n")
+               var vals []interface{}
+               for _, t := range opts.Types {
+                       vals = append(vals, zeroValue(t))
+               }
+               data := marshalCorpusFile(vals...)
+               h := sha256.Sum256(data)
+               name := fmt.Sprintf("%x", h[:4])
+               c.corpus.entries = append(c.corpus.entries, CorpusEntry{Path: name, Data: data})
+       }
+
+       return c, nil
+}
+
+func (c *coordinator) updateStats(result fuzzResult) {
+       c.count += result.count
+       c.countWaiting -= result.limit
+       c.duration += result.totalDuration
+}
+
+func (c *coordinator) logStats() {
+       now := time.Now()
+       if c.warmupRun() {
+               runSoFar := c.warmupInputCount - c.warmupInputLeft
+               if coverageEnabled {
+                       fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, gathering baseline coverage: %d/%d completed\n", c.elapsed(), runSoFar, c.warmupInputCount)
+               } else {
+                       fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, testing seed corpus: %d/%d completed\n", c.elapsed(), runSoFar, c.warmupInputCount)
+               }
+       } else if c.crashMinimizing != nil {
+               fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, minimizing\n", c.elapsed())
+       } else {
+               rate := float64(c.count-c.countLastLog) / now.Sub(c.timeLastLog).Seconds()
+               if coverageEnabled {
+                       interestingTotalCount := int64(c.warmupInputCount-len(c.opts.Seed)) + c.interestingCount
+                       fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, execs: %d (%.0f/sec), new interesting: %d (total: %d)\n", c.elapsed(), c.count, rate, c.interestingCount, interestingTotalCount)
+               } else {
+                       fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, execs: %d (%.0f/sec)\n", c.elapsed(), c.count, rate)
+               }
+       }
+       c.countLastLog = c.count
+       c.timeLastLog = now
+}
+
+// peekInput returns the next value that should be sent to workers.
+// If the number of executions is limited, the returned value includes
+// a limit for one worker. If there are no executions left, peekInput returns
+// a zero value and false.
+//
+// peekInput doesn't actually remove the input from the queue. The caller
+// must call sentInput after sending the input.
+//
+// If the input queue is empty and the coverage/testing-only run has completed,
+// queue refills it from the corpus.
+func (c *coordinator) peekInput() (fuzzInput, bool) {
+       if c.opts.Limit > 0 && c.count+c.countWaiting >= c.opts.Limit {
+               // Already making the maximum number of calls to the fuzz function.
+               // Don't send more inputs right now.
+               return fuzzInput{}, false
+       }
+       if c.inputQueue.len == 0 {
+               if c.warmupRun() {
+                       // Wait for coverage/testing-only run to finish before sending more
+                       // inputs.
+                       return fuzzInput{}, false
+               }
+               c.refillInputQueue()
+       }
+
+       entry, ok := c.inputQueue.peek()
+       if !ok {
+               panic("input queue empty after refill")
+       }
+       input := fuzzInput{
+               entry:   entry.(CorpusEntry),
+               timeout: workerFuzzDuration,
+               warmup:  c.warmupRun(),
+       }
+       if c.coverageMask != nil {
+               input.coverageData = make([]byte, len(c.coverageMask))
+               copy(input.coverageData, c.coverageMask)
+       }
+       if input.warmup {
+               // No fuzzing will occur, but it should count toward the limit set by
+               // -fuzztime.
+               input.limit = 1
+               return input, true
+       }
+
+       if c.opts.Limit > 0 {
+               input.limit = c.opts.Limit / int64(c.opts.Parallel)
+               if c.opts.Limit%int64(c.opts.Parallel) > 0 {
+                       input.limit++
+               }
+               remaining := c.opts.Limit - c.count - c.countWaiting
+               if input.limit > remaining {
+                       input.limit = remaining
+               }
+       }
+       return input, true
+}
+
+// sentInput updates internal counters after an input is sent to c.inputC.
+func (c *coordinator) sentInput(input fuzzInput) {
+       c.inputQueue.dequeue()
+       c.countWaiting += input.limit
+}
+
+// refillInputQueue refills the input queue from the corpus after it becomes
+// empty.
+func (c *coordinator) refillInputQueue() {
+       for _, e := range c.corpus.entries {
+               c.inputQueue.enqueue(e)
+       }
+}
+
+// queueForMinimization creates a fuzzMinimizeInput from result and adds it
+// to the minimization queue to be sent to workers.
+func (c *coordinator) queueForMinimization(result fuzzResult, keepCoverage []byte) {
+       if result.crasherMsg != "" {
+               c.minimizeQueue.clear()
+       }
+
+       input := fuzzMinimizeInput{
+               entry:        result.entry,
+               crasherMsg:   result.crasherMsg,
+               keepCoverage: keepCoverage,
+       }
+       c.minimizeQueue.enqueue(input)
+}
+
+// peekMinimizeInput returns the next input that should be sent to workers for
+// minimization.
+func (c *coordinator) peekMinimizeInput() (fuzzMinimizeInput, bool) {
+       if !c.canMinimize() {
+               // Already making the maximum number of calls to the fuzz function.
+               // Don't send more inputs right now.
+               return fuzzMinimizeInput{}, false
+       }
+       v, ok := c.minimizeQueue.peek()
+       if !ok {
+               return fuzzMinimizeInput{}, false
+       }
+       input := v.(fuzzMinimizeInput)
+
+       if c.opts.MinimizeTimeout > 0 {
+               input.timeout = c.opts.MinimizeTimeout
+       }
+       if c.opts.MinimizeLimit > 0 {
+               input.limit = c.opts.MinimizeLimit
+       } else if c.opts.Limit > 0 {
+               if input.crasherMsg != "" {
+                       input.limit = c.opts.Limit
+               } else {
+                       input.limit = c.opts.Limit / int64(c.opts.Parallel)
+                       if c.opts.Limit%int64(c.opts.Parallel) > 0 {
+                               input.limit++
+                       }
+               }
+       }
+       if c.opts.Limit > 0 {
+               remaining := c.opts.Limit - c.count - c.countWaiting
+               if input.limit > remaining {
+                       input.limit = remaining
+               }
+       }
+       return input, true
+}
+
+// sentMinimizeInput removes an input from the minimization queue after it's
+// sent to minimizeC.
+func (c *coordinator) sentMinimizeInput(input fuzzMinimizeInput) {
+       c.minimizeQueue.dequeue()
+       c.countWaiting += input.limit
+}
+
+// warmupRun returns true while the coordinator is running inputs without
+// mutating them as a warmup before fuzzing. This could be to gather baseline
+// coverage data for entries in the corpus, or to test all of the seed corpus
+// for errors before fuzzing begins.
+//
+// The coordinator doesn't store coverage data in the cache with each input
+// because that data would be invalid when counter offsets in the test binary
+// change.
+//
+// When gathering coverage, the coordinator sends each entry to a worker to
+// gather coverage for that entry only, without fuzzing or minimizing. This
+// phase ends when all workers have finished, and the coordinator has a combined
+// coverage map.
+func (c *coordinator) warmupRun() bool {
+       return c.warmupInputLeft > 0
+}
+
+// updateCoverage sets bits in c.coverageMask that are set in newCoverage.
+// updateCoverage returns the number of newly set bits. See the comment on
+// coverageMask for the format.
+func (c *coordinator) updateCoverage(newCoverage []byte) int {
+       if len(newCoverage) != len(c.coverageMask) {
+               panic(fmt.Sprintf("number of coverage counters changed at runtime: %d, expected %d", len(newCoverage), len(c.coverageMask)))
+       }
+       newBitCount := 0
+       for i := range newCoverage {
+               diff := newCoverage[i] &^ c.coverageMask[i]
+               newBitCount += bits.OnesCount8(diff)
+               c.coverageMask[i] |= newCoverage[i]
+       }
+       return newBitCount
+}
+
+// canMinimize returns whether the coordinator should attempt to find smaller
+// inputs that reproduce a crash or new coverage.
+func (c *coordinator) canMinimize() bool {
+       return c.minimizationAllowed &&
+               (c.opts.Limit == 0 || c.count+c.countWaiting < c.opts.Limit)
+}
+
+func (c *coordinator) elapsed() time.Duration {
+       return time.Since(c.startTime).Round(1 * time.Second)
+}
+
+// readCache creates a combined corpus from seed values and values in the cache
+// (in GOCACHE/fuzz).
+//
+// TODO(fuzzing): need a mechanism that can remove values that
+// aren't useful anymore, for example, because they have the wrong type.
+func readCache(seed []CorpusEntry, types []reflect.Type, cacheDir string) (corpus, error) {
+       var c corpus
+       c.entries = append(c.entries, seed...)
+       entries, err := ReadCorpus(cacheDir, types)
+       if err != nil {
+               if _, ok := err.(*MalformedCorpusError); !ok {
+                       // It's okay if some files in the cache directory are malformed and
+                       // are not included in the corpus, but fail if it's an I/O error.
+                       return corpus{}, err
+               }
+               // TODO(jayconrod,katiehockman): consider printing some kind of warning
+               // indicating the number of files which were skipped because they are
+               // malformed.
+       }
+       c.entries = append(c.entries, entries...)
+       return c, nil
+}
+
+// MalformedCorpusError is an error found while reading the corpus from the
+// filesystem. All of the errors are stored in the errs list. The testing
+// framework uses this to report malformed files in testdata.
+type MalformedCorpusError struct {
+       errs []error
+}
+
+func (e *MalformedCorpusError) Error() string {
+       var msgs []string
+       for _, s := range e.errs {
+               msgs = append(msgs, s.Error())
+       }
+       return strings.Join(msgs, "\n")
+}
+
+// ReadCorpus reads the corpus from the provided dir. The returned corpus
+// entries are guaranteed to match the given types. Any malformed files will
+// be saved in a MalformedCorpusError and returned, along with the most recent
+// error.
+func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) {
+       files, err := ioutil.ReadDir(dir)
+       if os.IsNotExist(err) {
+               return nil, nil // No corpus to read
+       } else if err != nil {
+               return nil, fmt.Errorf("reading seed corpus from testdata: %v", err)
+       }
+       var corpus []CorpusEntry
+       var errs []error
+       for _, file := range files {
+               // TODO(jayconrod,katiehockman): determine when a file is a fuzzing input
+               // based on its name. We should only read files created by writeToCorpus.
+               // If we read ALL files, we won't be able to change the file format by
+               // changing the extension. We also won't be able to add files like
+               // README.txt explaining why the directory exists.
+               if file.IsDir() {
+                       continue
+               }
+               filename := filepath.Join(dir, file.Name())
+               data, err := ioutil.ReadFile(filename)
+               if err != nil {
+                       return nil, fmt.Errorf("failed to read corpus file: %v", err)
+               }
+               var vals []interface{}
+               vals, err = readCorpusData(data, types)
+               if err != nil {
+                       errs = append(errs, fmt.Errorf("%q: %v", filename, err))
+                       continue
+               }
+               corpus = append(corpus, CorpusEntry{Path: filename, Values: vals})
+       }
+       if len(errs) > 0 {
+               return corpus, &MalformedCorpusError{errs: errs}
+       }
+       return corpus, nil
+}
+
+func readCorpusData(data []byte, types []reflect.Type) ([]interface{}, error) {
+       vals, err := unmarshalCorpusFile(data)
+       if err != nil {
+               return nil, fmt.Errorf("unmarshal: %v", err)
+       }
+       if err = CheckCorpus(vals, types); err != nil {
+               return nil, err
+       }
+       return vals, nil
+}
+
+// CheckCorpus verifies that the types in vals match the expected types
+// provided.
+func CheckCorpus(vals []interface{}, types []reflect.Type) error {
+       if len(vals) != len(types) {
+               return fmt.Errorf("wrong number of values in corpus entry: %d, want %d", len(vals), len(types))
+       }
+       valsT := make([]reflect.Type, len(vals))
+       for valsI, v := range vals {
+               valsT[valsI] = reflect.TypeOf(v)
+       }
+       for i := range types {
+               if valsT[i] != types[i] {
+                       return fmt.Errorf("mismatched types in corpus entry: %v, want %v", valsT, types)
+               }
+       }
+       return nil
+}
+
+// writeToCorpus atomically writes the given bytes to a new file in testdata. If
+// the directory does not exist, it will create one. If the file already exists,
+// writeToCorpus will not rewrite it. writeToCorpus sets entry.Path to the new
+// file that was just written or an error if it failed.
+func writeToCorpus(entry *CorpusEntry, dir string) (err error) {
+       sum := fmt.Sprintf("%x", sha256.Sum256(entry.Data))
+       entry.Path = filepath.Join(dir, sum)
+       if err := os.MkdirAll(dir, 0777); err != nil {
+               return err
+       }
+       if err := ioutil.WriteFile(entry.Path, entry.Data, 0666); err != nil {
+               os.Remove(entry.Path) // remove partially written file
+               return err
+       }
+       return nil
+}
+
+func testName(path string) string {
+       return filepath.Base(path)
+}
+
+func zeroValue(t reflect.Type) interface{} {
+       for _, v := range zeroVals {
+               if reflect.TypeOf(v) == t {
+                       return v
+               }
+       }
+       panic(fmt.Sprintf("unsupported type: %v", t))
+}
+
+var zeroVals []interface{} = []interface{}{
+       []byte(""),
+       string(""),
+       false,
+       byte(0),
+       rune(0),
+       float32(0),
+       float64(0),
+       int(0),
+       int8(0),
+       int16(0),
+       int32(0),
+       int64(0),
+       uint(0),
+       uint8(0),
+       uint16(0),
+       uint32(0),
+       uint64(0),
+}
+
+var (
+       debugInfo     bool
+       debugInfoOnce sync.Once
+)
+
+func shouldPrintDebugInfo() bool {
+       debugInfoOnce.Do(func() {
+               debugInfo = godebug.Get("fuzzdebug") == "1"
+       })
+       return debugInfo
+}
diff --git a/src/internal/fuzz/mem.go b/src/internal/fuzz/mem.go
new file mode 100644 (file)
index 0000000..ccd4da2
--- /dev/null
@@ -0,0 +1,134 @@
+// 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 fuzz
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "unsafe"
+)
+
+// sharedMem manages access to a region of virtual memory mapped from a file,
+// shared between multiple processes. The region includes space for a header and
+// a value of variable length.
+//
+// When fuzzing, the coordinator creates a sharedMem from a temporary file for
+// each worker. This buffer is used to pass values to fuzz between processes.
+// Care must be taken to manage access to shared memory across processes;
+// sharedMem provides no synchronization on its own. See workerComm for an
+// explanation.
+type sharedMem struct {
+       // f is the file mapped into memory.
+       f *os.File
+
+       // region is the mapped region of virtual memory for f. The content of f may
+       // be read or written through this slice.
+       region []byte
+
+       // removeOnClose is true if the file should be deleted by Close.
+       removeOnClose bool
+
+       // sys contains OS-specific information.
+       sys sharedMemSys
+}
+
+// sharedMemHeader stores metadata in shared memory.
+type sharedMemHeader struct {
+       // count is the number of times the worker has called the fuzz function.
+       // May be reset by coordinator.
+       count int64
+
+       // valueLen is the length of the value that was last fuzzed.
+       valueLen int
+
+       // randState and randInc hold the state of a pseudo-random number generator.
+       randState, randInc uint64
+}
+
+// sharedMemSize returns the size needed for a shared memory buffer that can
+// contain values of the given size.
+func sharedMemSize(valueSize int) int {
+       // TODO(jayconrod): set a reasonable maximum size per platform.
+       return int(unsafe.Sizeof(sharedMemHeader{})) + valueSize
+}
+
+// sharedMemTempFile creates a new temporary file of the given size, then maps
+// it into memory. The file will be removed when the Close method is called.
+func sharedMemTempFile(size int) (m *sharedMem, err error) {
+       // Create a temporary file.
+       f, err := ioutil.TempFile("", "fuzz-*")
+       if err != nil {
+               return nil, err
+       }
+       defer func() {
+               if err != nil {
+                       f.Close()
+                       os.Remove(f.Name())
+               }
+       }()
+
+       // Resize it to the correct size.
+       totalSize := sharedMemSize(size)
+       if err := f.Truncate(int64(totalSize)); err != nil {
+               return nil, err
+       }
+
+       // Map the file into memory.
+       removeOnClose := true
+       return sharedMemMapFile(f, totalSize, removeOnClose)
+}
+
+// header returns a pointer to metadata within the shared memory region.
+func (m *sharedMem) header() *sharedMemHeader {
+       return (*sharedMemHeader)(unsafe.Pointer(&m.region[0]))
+}
+
+// valueRef returns the value currently stored in shared memory. The returned
+// slice points to shared memory; it is not a copy.
+func (m *sharedMem) valueRef() []byte {
+       length := m.header().valueLen
+       valueOffset := int(unsafe.Sizeof(sharedMemHeader{}))
+       return m.region[valueOffset : valueOffset+length]
+}
+
+// valueCopy returns a copy of the value stored in shared memory.
+func (m *sharedMem) valueCopy() []byte {
+       ref := m.valueRef()
+       b := make([]byte, len(ref))
+       copy(b, ref)
+       return b
+}
+
+// setValue copies the data in b into the shared memory buffer and sets
+// the length. len(b) must be less than or equal to the capacity of the buffer
+// (as returned by cap(m.value())).
+func (m *sharedMem) setValue(b []byte) {
+       v := m.valueRef()
+       if len(b) > cap(v) {
+               panic(fmt.Sprintf("value length %d larger than shared memory capacity %d", len(b), cap(v)))
+       }
+       m.header().valueLen = len(b)
+       copy(v[:cap(v)], b)
+}
+
+// setValueLen sets the length of the shared memory buffer returned by valueRef
+// to n, which may be at most the cap of that slice.
+//
+// Note that we can only store the length in the shared memory header. The full
+// slice header contains a pointer, which is likely only valid for one process,
+// since each process can map shared memory at a different virtual address.
+func (m *sharedMem) setValueLen(n int) {
+       v := m.valueRef()
+       if n > cap(v) {
+               panic(fmt.Sprintf("length %d larger than shared memory capacity %d", n, cap(v)))
+       }
+       m.header().valueLen = n
+}
+
+// TODO(jayconrod): add method to resize the buffer. We'll need that when the
+// mutator can increase input length. Only the coordinator will be able to
+// do it, since we'll need to send a message to the worker telling it to
+// remap the file.
diff --git a/src/internal/fuzz/minimize.go b/src/internal/fuzz/minimize.go
new file mode 100644 (file)
index 0000000..c6e4559
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "math"
+       "reflect"
+)
+
+func isMinimizable(t reflect.Type) bool {
+       for _, v := range zeroVals {
+               if t == reflect.TypeOf(v) {
+                       return true
+               }
+       }
+       return false
+}
+
+func minimizeBytes(v []byte, try func(interface{}) bool, shouldStop func() bool) {
+       tmp := make([]byte, len(v))
+       // If minimization was successful at any point during minimizeBytes,
+       // then the vals slice in (*workerServer).minimizeInput will point to
+       // tmp. Since tmp is altered while making new candidates, we need to
+       // make sure that it is equal to the correct value, v, before exiting
+       // this function.
+       defer copy(tmp, v)
+
+       // First, try to cut the tail.
+       for n := 1024; n != 0; n /= 2 {
+               for len(v) > n {
+                       if shouldStop() {
+                               return
+                       }
+                       candidate := v[:len(v)-n]
+                       if !try(candidate) {
+                               break
+                       }
+                       // Set v to the new value to continue iterating.
+                       v = candidate
+               }
+       }
+
+       // Then, try to remove each individual byte.
+       for i := 0; i < len(v)-1; i++ {
+               if shouldStop() {
+                       return
+               }
+               candidate := tmp[:len(v)-1]
+               copy(candidate[:i], v[:i])
+               copy(candidate[i:], v[i+1:])
+               if !try(candidate) {
+                       continue
+               }
+               // Update v to delete the value at index i.
+               copy(v[i:], v[i+1:])
+               v = v[:len(candidate)]
+               // v[i] is now different, so decrement i to redo this iteration
+               // of the loop with the new value.
+               i--
+       }
+
+       // Then, try to remove each possible subset of bytes.
+       for i := 0; i < len(v)-1; i++ {
+               copy(tmp, v[:i])
+               for j := len(v); j > i+1; j-- {
+                       if shouldStop() {
+                               return
+                       }
+                       candidate := tmp[:len(v)-j+i]
+                       copy(candidate[i:], v[j:])
+                       if !try(candidate) {
+                               continue
+                       }
+                       // Update v and reset the loop with the new length.
+                       copy(v[i:], v[j:])
+                       v = v[:len(candidate)]
+                       j = len(v)
+               }
+       }
+
+       // Then, try to make it more simplified and human-readable by trying to replace each
+       // byte with a printable character.
+       printableChars := []byte("012789ABCXYZabcxyz !\"#$%&'()*+,.")
+       for i, b := range v {
+               if shouldStop() {
+                       return
+               }
+
+               for _, pc := range printableChars {
+                       v[i] = pc
+                       if try(v) {
+                               // Successful. Move on to the next byte in v.
+                               break
+                       }
+                       // Unsuccessful. Revert v[i] back to original value.
+                       v[i] = b
+               }
+       }
+}
+
+func minimizeInteger(v uint, try func(interface{}) bool, shouldStop func() bool) {
+       // TODO(rolandshoemaker): another approach could be either unsetting/setting all bits
+       // (depending on signed-ness), or rotating bits? When operating on cast signed integers
+       // this would probably be more complex though.
+       for ; v != 0; v /= 10 {
+               if shouldStop() {
+                       return
+               }
+               // We ignore the return value here because there is no point
+               // advancing the loop, since there is nothing after this check,
+               // and we don't return early because a smaller value could
+               // re-trigger the crash.
+               try(v)
+       }
+}
+
+func minimizeFloat(v float64, try func(interface{}) bool, shouldStop func() bool) {
+       if math.IsNaN(v) {
+               return
+       }
+       minimized := float64(0)
+       for div := 10.0; minimized < v; div *= 10 {
+               if shouldStop() {
+                       return
+               }
+               minimized = float64(int(v*div)) / div
+               if !try(minimized) {
+                       // Since we are searching from least precision -> highest precision we
+                       // can return early since we've already found the smallest value
+                       return
+               }
+       }
+}
diff --git a/src/internal/fuzz/minimize_test.go b/src/internal/fuzz/minimize_test.go
new file mode 100644 (file)
index 0000000..dc153d0
--- /dev/null
@@ -0,0 +1,323 @@
+// Copyright 2021 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:build darwin || linux || windows
+
+package fuzz
+
+import (
+       "bytes"
+       "context"
+       "errors"
+       "fmt"
+       "reflect"
+       "testing"
+       "unicode"
+       "unicode/utf8"
+)
+
+func TestMinimizeInput(t *testing.T) {
+       type testcase struct {
+               name     string
+               fn       func(CorpusEntry) error
+               input    []interface{}
+               expected []interface{}
+       }
+       cases := []testcase{
+               {
+                       name: "ones_byte",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].([]byte)
+                               ones := 0
+                               for _, v := range b {
+                                       if v == 1 {
+                                               ones++
+                                       }
+                               }
+                               if ones == 3 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{[]byte{0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+                       expected: []interface{}{[]byte{1, 1, 1}},
+               },
+               {
+                       name: "single_bytes",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].([]byte)
+                               if len(b) < 2 {
+                                       return nil
+                               }
+                               if len(b) == 2 && b[0] == 1 && b[1] == 2 {
+                                       return nil
+                               }
+                               return fmt.Errorf("bad %v", e.Values[0])
+                       },
+                       input:    []interface{}{[]byte{1, 2, 3, 4, 5}},
+                       expected: []interface{}{[]byte("00")},
+               },
+               {
+                       name: "set_of_bytes",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].([]byte)
+                               if len(b) < 3 {
+                                       return nil
+                               }
+                               if bytes.Equal(b, []byte{0, 1, 2, 3, 4, 5}) || bytes.Equal(b, []byte{0, 4, 5}) {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{[]byte{0, 1, 2, 3, 4, 5}},
+                       expected: []interface{}{[]byte{0, 4, 5}},
+               },
+               {
+                       name: "non_ascii_bytes",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].([]byte)
+                               if len(b) == 3 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{[]byte("ท")}, // ท is 3 bytes
+                       expected: []interface{}{[]byte("000")},
+               },
+               {
+                       name: "ones_string",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].(string)
+                               ones := 0
+                               for _, v := range b {
+                                       if v == '1' {
+                                               ones++
+                                       }
+                               }
+                               if ones == 3 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{"001010001000000000000000000"},
+                       expected: []interface{}{"111"},
+               },
+               {
+                       name: "string_length",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].(string)
+                               if len(b) == 5 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{"zzzzz"},
+                       expected: []interface{}{"00000"},
+               },
+               {
+                       name: "string_with_letter",
+                       fn: func(e CorpusEntry) error {
+                               b := e.Values[0].(string)
+                               r, _ := utf8.DecodeRune([]byte(b))
+                               if unicode.IsLetter(r) {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{"ZZZZZ"},
+                       expected: []interface{}{"A"},
+               },
+               {
+                       name: "int",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(int)
+                               if i > 100 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{123456},
+                       expected: []interface{}{123},
+               },
+               {
+                       name: "int8",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(int8)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{int8(1<<7 - 1)},
+                       expected: []interface{}{int8(12)},
+               },
+               {
+                       name: "int16",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(int16)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{int16(1<<15 - 1)},
+                       expected: []interface{}{int16(32)},
+               },
+               {
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(int32)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{int32(1<<31 - 1)},
+                       expected: []interface{}{int32(21)},
+               },
+               {
+                       name: "int32",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(uint)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{uint(123456)},
+                       expected: []interface{}{uint(12)},
+               },
+               {
+                       name: "uint8",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(uint8)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{uint8(1<<8 - 1)},
+                       expected: []interface{}{uint8(25)},
+               },
+               {
+                       name: "uint16",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(uint16)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{uint16(1<<16 - 1)},
+                       expected: []interface{}{uint16(65)},
+               },
+               {
+                       name: "uint32",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(uint32)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{uint32(1<<32 - 1)},
+                       expected: []interface{}{uint32(42)},
+               },
+               {
+                       name: "float32",
+                       fn: func(e CorpusEntry) error {
+                               if i := e.Values[0].(float32); i == 1.23 {
+                                       return nil
+                               }
+                               return fmt.Errorf("bad %v", e.Values[0])
+                       },
+                       input:    []interface{}{float32(1.23456789)},
+                       expected: []interface{}{float32(1.2)},
+               },
+               {
+                       name: "float64",
+                       fn: func(e CorpusEntry) error {
+                               if i := e.Values[0].(float64); i == 1.23 {
+                                       return nil
+                               }
+                               return fmt.Errorf("bad %v", e.Values[0])
+                       },
+                       input:    []interface{}{float64(1.23456789)},
+                       expected: []interface{}{float64(1.2)},
+               },
+       }
+
+       // If we are on a 64 bit platform add int64 and uint64 tests
+       if v := int64(1<<63 - 1); int64(int(v)) == v {
+               cases = append(cases, testcase{
+                       name: "int64",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(int64)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{int64(1<<63 - 1)},
+                       expected: []interface{}{int64(92)},
+               }, testcase{
+                       name: "uint64",
+                       fn: func(e CorpusEntry) error {
+                               i := e.Values[0].(uint64)
+                               if i > 10 {
+                                       return fmt.Errorf("bad %v", e.Values[0])
+                               }
+                               return nil
+                       },
+                       input:    []interface{}{uint64(1<<64 - 1)},
+                       expected: []interface{}{uint64(18)},
+               })
+       }
+
+       for _, tc := range cases {
+               tc := tc
+               t.Run(tc.name, func(t *testing.T) {
+                       t.Parallel()
+                       ws := &workerServer{
+                               fuzzFn: tc.fn,
+                       }
+                       count := int64(0)
+                       vals := tc.input
+                       success, err := ws.minimizeInput(context.Background(), vals, &count, 0, nil)
+                       if !success {
+                               t.Errorf("minimizeInput did not succeed")
+                       }
+                       if err == nil {
+                               t.Fatal("minimizeInput didn't provide an error")
+                       }
+                       if expected := fmt.Sprintf("bad %v", tc.expected[0]); err.Error() != expected {
+                               t.Errorf("unexpected error: got %q, want %q", err, expected)
+                       }
+                       if !reflect.DeepEqual(vals, tc.expected) {
+                               t.Errorf("unexpected results: got %v, want %v", vals, tc.expected)
+                       }
+               })
+       }
+}
+
+// TestMinimizeFlaky checks that if we're minimizing an interesting
+// input and a flaky failure occurs, that minimization was not indicated
+// to be successful, and the error isn't returned (since it's flaky).
+func TestMinimizeFlaky(t *testing.T) {
+       ws := &workerServer{fuzzFn: func(e CorpusEntry) error {
+               return errors.New("ohno")
+       }}
+       keepCoverage := make([]byte, len(coverageSnapshot))
+       count := int64(0)
+       vals := []interface{}{[]byte(nil)}
+       success, err := ws.minimizeInput(context.Background(), vals, &count, 0, keepCoverage)
+       if success {
+               t.Error("unexpected success")
+       }
+       if err != nil {
+               t.Errorf("unexpected error: %v", err)
+       }
+       if count != 1 {
+               t.Errorf("count: got %d, want 1", count)
+       }
+}
diff --git a/src/internal/fuzz/mutator.go b/src/internal/fuzz/mutator.go
new file mode 100644 (file)
index 0000000..da7200d
--- /dev/null
@@ -0,0 +1,312 @@
+// 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 fuzz
+
+import (
+       "encoding/binary"
+       "fmt"
+       "math"
+       "reflect"
+       "unsafe"
+)
+
+type mutator struct {
+       r       mutatorRand
+       scratch []byte // scratch slice to avoid additional allocations
+}
+
+func newMutator() *mutator {
+       return &mutator{r: newPcgRand()}
+}
+
+func (m *mutator) rand(n int) int {
+       return m.r.intn(n)
+}
+
+func (m *mutator) randByteOrder() binary.ByteOrder {
+       if m.r.bool() {
+               return binary.LittleEndian
+       }
+       return binary.BigEndian
+}
+
+// chooseLen chooses length of range mutation in range [1,n]. It gives
+// preference to shorter ranges.
+func (m *mutator) chooseLen(n int) int {
+       switch x := m.rand(100); {
+       case x < 90:
+               return m.rand(min(8, n)) + 1
+       case x < 99:
+               return m.rand(min(32, n)) + 1
+       default:
+               return m.rand(n) + 1
+       }
+}
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+// mutate performs several mutations on the provided values.
+func (m *mutator) mutate(vals []interface{}, maxBytes int) {
+       // TODO(katiehockman): pull some of these functions into helper methods and
+       // test that each case is working as expected.
+       // TODO(katiehockman): perform more types of mutations for []byte.
+
+       // maxPerVal will represent the maximum number of bytes that each value be
+       // allowed after mutating, giving an equal amount of capacity to each line.
+       // Allow a little wiggle room for the encoding.
+       maxPerVal := maxBytes/len(vals) - 100
+
+       // Pick a random value to mutate.
+       // TODO: consider mutating more than one value at a time.
+       i := m.rand(len(vals))
+       switch v := vals[i].(type) {
+       case int:
+               vals[i] = int(m.mutateInt(int64(v), maxInt))
+       case int8:
+               vals[i] = int8(m.mutateInt(int64(v), math.MaxInt8))
+       case int16:
+               vals[i] = int16(m.mutateInt(int64(v), math.MaxInt16))
+       case int64:
+               vals[i] = m.mutateInt(v, maxInt)
+       case uint:
+               vals[i] = uint(m.mutateUInt(uint64(v), maxUint))
+       case uint16:
+               vals[i] = uint16(m.mutateUInt(uint64(v), math.MaxUint16))
+       case uint32:
+               vals[i] = uint32(m.mutateUInt(uint64(v), math.MaxUint32))
+       case uint64:
+               vals[i] = m.mutateUInt(uint64(v), maxUint)
+       case float32:
+               vals[i] = float32(m.mutateFloat(float64(v), math.MaxFloat32))
+       case float64:
+               vals[i] = m.mutateFloat(v, math.MaxFloat64)
+       case bool:
+               if m.rand(2) == 1 {
+                       vals[i] = !v // 50% chance of flipping the bool
+               }
+       case rune: // int32
+               vals[i] = rune(m.mutateInt(int64(v), math.MaxInt32))
+       case byte: // uint8
+               vals[i] = byte(m.mutateUInt(uint64(v), math.MaxUint8))
+       case string:
+               if len(v) > maxPerVal {
+                       panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v)))
+               }
+               if cap(m.scratch) < maxPerVal {
+                       m.scratch = append(make([]byte, 0, maxPerVal), v...)
+               } else {
+                       m.scratch = m.scratch[:len(v)]
+                       copy(m.scratch, v)
+               }
+               m.mutateBytes(&m.scratch)
+               vals[i] = string(m.scratch)
+       case []byte:
+               if len(v) > maxPerVal {
+                       panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v)))
+               }
+               if cap(m.scratch) < maxPerVal {
+                       m.scratch = append(make([]byte, 0, maxPerVal), v...)
+               } else {
+                       m.scratch = m.scratch[:len(v)]
+                       copy(m.scratch, v)
+               }
+               m.mutateBytes(&m.scratch)
+               vals[i] = m.scratch
+       default:
+               panic(fmt.Sprintf("type not supported for mutating: %T", vals[i]))
+       }
+}
+
+func (m *mutator) mutateInt(v, maxValue int64) int64 {
+       numIters := 1 + m.r.exp2()
+       var max int64
+       for iter := 0; iter < numIters; iter++ {
+               max = 100
+               switch m.rand(2) {
+               case 0:
+                       // Add a random number
+                       if v >= maxValue {
+                               iter--
+                               continue
+                       }
+                       if v > 0 && maxValue-v < max {
+                               // Don't let v exceed maxValue
+                               max = maxValue - v
+                       }
+                       v += int64(1 + m.rand(int(max)))
+               case 1:
+                       // Subtract a random number
+                       if v <= -maxValue {
+                               iter--
+                               continue
+                       }
+                       if v < 0 && maxValue+v < max {
+                               // Don't let v drop below -maxValue
+                               max = maxValue + v
+                       }
+                       v -= int64(1 + m.rand(int(max)))
+               }
+       }
+       return v
+}
+
+func (m *mutator) mutateUInt(v, maxValue uint64) uint64 {
+       numIters := 1 + m.r.exp2()
+       var max uint64
+       for iter := 0; iter < numIters; iter++ {
+               max = 100
+               switch m.rand(2) {
+               case 0:
+                       // Add a random number
+                       if v >= maxValue {
+                               iter--
+                               continue
+                       }
+                       if v > 0 && maxValue-v < max {
+                               // Don't let v exceed maxValue
+                               max = maxValue - v
+                       }
+
+                       v += uint64(1 + m.rand(int(max)))
+               case 1:
+                       // Subtract a random number
+                       if v <= 0 {
+                               iter--
+                               continue
+                       }
+                       if v < max {
+                               // Don't let v drop below 0
+                               max = v
+                       }
+                       v -= uint64(1 + m.rand(int(max)))
+               }
+       }
+       return v
+}
+
+func (m *mutator) mutateFloat(v, maxValue float64) float64 {
+       numIters := 1 + m.r.exp2()
+       var max float64
+       for iter := 0; iter < numIters; iter++ {
+               switch m.rand(4) {
+               case 0:
+                       // Add a random number
+                       if v >= maxValue {
+                               iter--
+                               continue
+                       }
+                       max = 100
+                       if v > 0 && maxValue-v < max {
+                               // Don't let v exceed maxValue
+                               max = maxValue - v
+                       }
+                       v += float64(1 + m.rand(int(max)))
+               case 1:
+                       // Subtract a random number
+                       if v <= -maxValue {
+                               iter--
+                               continue
+                       }
+                       max = 100
+                       if v < 0 && maxValue+v < max {
+                               // Don't let v drop below -maxValue
+                               max = maxValue + v
+                       }
+                       v -= float64(1 + m.rand(int(max)))
+               case 2:
+                       // Multiply by a random number
+                       absV := math.Abs(v)
+                       if v == 0 || absV >= maxValue {
+                               iter--
+                               continue
+                       }
+                       max = 10
+                       if maxValue/absV < max {
+                               // Don't let v go beyond the minimum or maximum value
+                               max = maxValue / absV
+                       }
+                       v *= float64(1 + m.rand(int(max)))
+               case 3:
+                       // Divide by a random number
+                       if v == 0 {
+                               iter--
+                               continue
+                       }
+                       v /= float64(1 + m.rand(10))
+               }
+       }
+       return v
+}
+
+type byteSliceMutator func(*mutator, []byte) []byte
+
+var byteSliceMutators = []byteSliceMutator{
+       byteSliceRemoveBytes,
+       byteSliceInsertRandomBytes,
+       byteSliceDuplicateBytes,
+       byteSliceOverwriteBytes,
+       byteSliceBitFlip,
+       byteSliceXORByte,
+       byteSliceSwapByte,
+       byteSliceArithmeticUint8,
+       byteSliceArithmeticUint16,
+       byteSliceArithmeticUint32,
+       byteSliceArithmeticUint64,
+       byteSliceOverwriteInterestingUint8,
+       byteSliceOverwriteInterestingUint16,
+       byteSliceOverwriteInterestingUint32,
+       byteSliceInsertConstantBytes,
+       byteSliceOverwriteConstantBytes,
+       byteSliceShuffleBytes,
+       byteSliceSwapBytes,
+}
+
+func (m *mutator) mutateBytes(ptrB *[]byte) {
+       b := *ptrB
+       defer func() {
+               oldHdr := (*reflect.SliceHeader)(unsafe.Pointer(ptrB))
+               newHdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+               if oldHdr.Data != newHdr.Data {
+                       panic("data moved to new address")
+               }
+               *ptrB = b
+       }()
+
+       numIters := 1 + m.r.exp2()
+       for iter := 0; iter < numIters; iter++ {
+               mut := byteSliceMutators[m.rand(len(byteSliceMutators))]
+               mutated := mut(m, b)
+               if mutated == nil {
+                       iter--
+                       continue
+               }
+               b = mutated
+       }
+}
+
+var (
+       interesting8  = []int8{-128, -1, 0, 1, 16, 32, 64, 100, 127}
+       interesting16 = []int16{-32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767}
+       interesting32 = []int32{-2147483648, -100663046, -32769, 32768, 65535, 65536, 100663045, 2147483647}
+)
+
+const (
+       maxUint = uint64(^uint(0))
+       maxInt  = int64(maxUint >> 1)
+)
+
+func init() {
+       for _, v := range interesting8 {
+               interesting16 = append(interesting16, int16(v))
+       }
+       for _, v := range interesting16 {
+               interesting32 = append(interesting32, int32(v))
+       }
+}
diff --git a/src/internal/fuzz/mutator_test.go b/src/internal/fuzz/mutator_test.go
new file mode 100644 (file)
index 0000000..d8015ce
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "bytes"
+       "fmt"
+       "os"
+       "strconv"
+       "testing"
+)
+
+func BenchmarkMutatorBytes(b *testing.B) {
+       origEnv := os.Getenv("GODEBUG")
+       defer func() { os.Setenv("GODEBUG", origEnv) }()
+       os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv))
+       m := newMutator()
+
+       for _, size := range []int{
+               1,
+               10,
+               100,
+               1000,
+               10000,
+               100000,
+       } {
+               b.Run(strconv.Itoa(size), func(b *testing.B) {
+                       buf := make([]byte, size)
+                       b.ResetTimer()
+
+                       for i := 0; i < b.N; i++ {
+                               // resize buffer to the correct shape and reset the PCG
+                               buf = buf[0:size]
+                               m.r = newPcgRand()
+                               m.mutate([]interface{}{buf}, workerSharedMemSize)
+                       }
+               })
+       }
+}
+
+func BenchmarkMutatorString(b *testing.B) {
+       origEnv := os.Getenv("GODEBUG")
+       defer func() { os.Setenv("GODEBUG", origEnv) }()
+       os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv))
+       m := newMutator()
+
+       for _, size := range []int{
+               1,
+               10,
+               100,
+               1000,
+               10000,
+               100000,
+       } {
+               b.Run(strconv.Itoa(size), func(b *testing.B) {
+                       buf := make([]byte, size)
+                       b.ResetTimer()
+
+                       for i := 0; i < b.N; i++ {
+                               // resize buffer to the correct shape and reset the PCG
+                               buf = buf[0:size]
+                               m.r = newPcgRand()
+                               m.mutate([]interface{}{string(buf)}, workerSharedMemSize)
+                       }
+               })
+       }
+}
+
+func BenchmarkMutatorAllBasicTypes(b *testing.B) {
+       origEnv := os.Getenv("GODEBUG")
+       defer func() { os.Setenv("GODEBUG", origEnv) }()
+       os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv))
+       m := newMutator()
+
+       types := []interface{}{
+               []byte(""),
+               string(""),
+               false,
+               float32(0),
+               float64(0),
+               int(0),
+               int8(0),
+               int16(0),
+               int32(0),
+               int64(0),
+               uint8(0),
+               uint16(0),
+               uint32(0),
+               uint64(0),
+       }
+
+       for _, t := range types {
+               b.Run(fmt.Sprintf("%T", t), func(b *testing.B) {
+                       for i := 0; i < b.N; i++ {
+                               m.r = newPcgRand()
+                               m.mutate([]interface{}{t}, workerSharedMemSize)
+                       }
+               })
+       }
+}
+
+func TestStringImmutability(t *testing.T) {
+       v := []interface{}{"hello"}
+       m := newMutator()
+       m.mutate(v, 1024)
+       original := v[0].(string)
+       originalCopy := make([]byte, len(original))
+       copy(originalCopy, []byte(original))
+       for i := 0; i < 25; i++ {
+               m.mutate(v, 1024)
+       }
+       if !bytes.Equal([]byte(original), originalCopy) {
+               t.Fatalf("string was mutated: got %x, want %x", []byte(original), originalCopy)
+       }
+}
diff --git a/src/internal/fuzz/mutators_byteslice.go b/src/internal/fuzz/mutators_byteslice.go
new file mode 100644 (file)
index 0000000..7c96b59
--- /dev/null
@@ -0,0 +1,301 @@
+// Copyright 2021 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 fuzz
+
+// byteSliceRemoveBytes removes a random chunk of bytes from b.
+func byteSliceRemoveBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       pos0 := m.rand(len(b))
+       pos1 := pos0 + m.chooseLen(len(b)-pos0)
+       copy(b[pos0:], b[pos1:])
+       b = b[:len(b)-(pos1-pos0)]
+       return b
+}
+
+// byteSliceInsertRandomBytes inserts a chunk of random bytes into b at a random
+// position.
+func byteSliceInsertRandomBytes(m *mutator, b []byte) []byte {
+       pos := m.rand(len(b) + 1)
+       n := m.chooseLen(1024)
+       if len(b)+n >= cap(b) {
+               return nil
+       }
+       b = b[:len(b)+n]
+       copy(b[pos+n:], b[pos:])
+       for i := 0; i < n; i++ {
+               b[pos+i] = byte(m.rand(256))
+       }
+       return b
+}
+
+// byteSliceDuplicateBytes duplicates a chunk of bytes in b and inserts it into
+// a random position.
+func byteSliceDuplicateBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       src := m.rand(len(b))
+       dst := m.rand(len(b))
+       for dst == src {
+               dst = m.rand(len(b))
+       }
+       n := m.chooseLen(len(b) - src)
+       // Use the end of the slice as scratch space to avoid doing an
+       // allocation. If the slice is too small abort and try something
+       // else.
+       if len(b)+(n*2) >= cap(b) {
+               return nil
+       }
+       end := len(b)
+       // Increase the size of b to fit the duplicated block as well as
+       // some extra working space
+       b = b[:end+(n*2)]
+       // Copy the block of bytes we want to duplicate to the end of the
+       // slice
+       copy(b[end+n:], b[src:src+n])
+       // Shift the bytes after the splice point n positions to the right
+       // to make room for the new block
+       copy(b[dst+n:end+n], b[dst:end])
+       // Insert the duplicate block into the splice point
+       copy(b[dst:], b[end+n:])
+       b = b[:end+n]
+       return b
+}
+
+// byteSliceOverwriteBytes overwrites a chunk of b with another chunk of b.
+func byteSliceOverwriteBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       src := m.rand(len(b))
+       dst := m.rand(len(b))
+       for dst == src {
+               dst = m.rand(len(b))
+       }
+       n := m.chooseLen(len(b) - src - 1)
+       copy(b[dst:], b[src:src+n])
+       return b
+}
+
+// byteSliceBitFlip flips a random bit in a random byte in b.
+func byteSliceBitFlip(m *mutator, b []byte) []byte {
+       if len(b) == 0 {
+               return nil
+       }
+       pos := m.rand(len(b))
+       b[pos] ^= 1 << uint(m.rand(8))
+       return b
+}
+
+// byteSliceXORByte XORs a random byte in b with a random value.
+func byteSliceXORByte(m *mutator, b []byte) []byte {
+       if len(b) == 0 {
+               return nil
+       }
+       pos := m.rand(len(b))
+       // In order to avoid a no-op (where the random value matches
+       // the existing value), use XOR instead of just setting to
+       // the random value.
+       b[pos] ^= byte(1 + m.rand(255))
+       return b
+}
+
+// byteSliceSwapByte swaps two random bytes in b.
+func byteSliceSwapByte(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       src := m.rand(len(b))
+       dst := m.rand(len(b))
+       for dst == src {
+               dst = m.rand(len(b))
+       }
+       b[src], b[dst] = b[dst], b[src]
+       return b
+}
+
+// byteSliceArithmeticUint8 adds/subtracts from a random byte in b.
+func byteSliceArithmeticUint8(m *mutator, b []byte) []byte {
+       if len(b) == 0 {
+               return nil
+       }
+       pos := m.rand(len(b))
+       v := byte(m.rand(35) + 1)
+       if m.r.bool() {
+               b[pos] += v
+       } else {
+               b[pos] -= v
+       }
+       return b
+}
+
+// byteSliceArithmeticUint16 adds/subtracts from a random uint16 in b.
+func byteSliceArithmeticUint16(m *mutator, b []byte) []byte {
+       if len(b) < 2 {
+               return nil
+       }
+       v := uint16(m.rand(35) + 1)
+       if m.r.bool() {
+               v = 0 - v
+       }
+       pos := m.rand(len(b) - 1)
+       enc := m.randByteOrder()
+       enc.PutUint16(b[pos:], enc.Uint16(b[pos:])+v)
+       return b
+}
+
+// byteSliceArithmeticUint32 adds/subtracts from a random uint32 in b.
+func byteSliceArithmeticUint32(m *mutator, b []byte) []byte {
+       if len(b) < 4 {
+               return nil
+       }
+       v := uint32(m.rand(35) + 1)
+       if m.r.bool() {
+               v = 0 - v
+       }
+       pos := m.rand(len(b) - 3)
+       enc := m.randByteOrder()
+       enc.PutUint32(b[pos:], enc.Uint32(b[pos:])+v)
+       return b
+}
+
+// byteSliceArithmeticUint64 adds/subtracts from a random uint64 in b.
+func byteSliceArithmeticUint64(m *mutator, b []byte) []byte {
+       if len(b) < 8 {
+               return nil
+       }
+       v := uint64(m.rand(35) + 1)
+       if m.r.bool() {
+               v = 0 - v
+       }
+       pos := m.rand(len(b) - 7)
+       enc := m.randByteOrder()
+       enc.PutUint64(b[pos:], enc.Uint64(b[pos:])+v)
+       return b
+}
+
+// byteSliceOverwriteInterestingUint8 overwrites a random byte in b with an interesting
+// value.
+func byteSliceOverwriteInterestingUint8(m *mutator, b []byte) []byte {
+       if len(b) == 0 {
+               return nil
+       }
+       pos := m.rand(len(b))
+       b[pos] = byte(interesting8[m.rand(len(interesting8))])
+       return b
+}
+
+// byteSliceOverwriteInterestingUint16 overwrites a random uint16 in b with an interesting
+// value.
+func byteSliceOverwriteInterestingUint16(m *mutator, b []byte) []byte {
+       if len(b) < 2 {
+               return nil
+       }
+       pos := m.rand(len(b) - 1)
+       v := uint16(interesting16[m.rand(len(interesting16))])
+       m.randByteOrder().PutUint16(b[pos:], v)
+       return b
+}
+
+// byteSliceOverwriteInterestingUint32 overwrites a random uint16 in b with an interesting
+// value.
+func byteSliceOverwriteInterestingUint32(m *mutator, b []byte) []byte {
+       if len(b) < 4 {
+               return nil
+       }
+       pos := m.rand(len(b) - 3)
+       v := uint32(interesting32[m.rand(len(interesting32))])
+       m.randByteOrder().PutUint32(b[pos:], v)
+       return b
+}
+
+// byteSliceInsertConstantBytes inserts a chunk of constant bytes into a random position in b.
+func byteSliceInsertConstantBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       dst := m.rand(len(b))
+       // TODO(rolandshoemaker,katiehockman): 4096 was mainly picked
+       // randomly. We may want to either pick a much larger value
+       // (AFL uses 32768, paired with a similar impl to chooseLen
+       // which biases towards smaller lengths that grow over time),
+       // or set the max based on characteristics of the corpus
+       // (libFuzzer sets a min/max based on the min/max size of
+       // entries in the corpus and then picks uniformly from
+       // that range).
+       n := m.chooseLen(4096)
+       if len(b)+n >= cap(b) {
+               return nil
+       }
+       b = b[:len(b)+n]
+       copy(b[dst+n:], b[dst:])
+       rb := byte(m.rand(256))
+       for i := dst; i < dst+n; i++ {
+               b[i] = rb
+       }
+       return b
+}
+
+// byteSliceOverwriteConstantBytes overwrites a chunk of b with constant bytes.
+func byteSliceOverwriteConstantBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       dst := m.rand(len(b))
+       n := m.chooseLen(len(b) - dst)
+       rb := byte(m.rand(256))
+       for i := dst; i < dst+n; i++ {
+               b[i] = rb
+       }
+       return b
+}
+
+// byteSliceShuffleBytes shuffles a chunk of bytes in b.
+func byteSliceShuffleBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       dst := m.rand(len(b))
+       n := m.chooseLen(len(b) - dst)
+       if n <= 2 {
+               return nil
+       }
+       // Start at the end of the range, and iterate backwards
+       // to dst, swapping each element with another element in
+       // dst:dst+n (Fisher-Yates shuffle).
+       for i := n - 1; i > 0; i-- {
+               j := m.rand(i + 1)
+               b[dst+i], b[dst+j] = b[dst+j], b[dst+i]
+       }
+       return b
+}
+
+// byteSliceSwapBytes swaps two chunks of bytes in b.
+func byteSliceSwapBytes(m *mutator, b []byte) []byte {
+       if len(b) <= 1 {
+               return nil
+       }
+       src := m.rand(len(b))
+       dst := m.rand(len(b))
+       for dst == src {
+               dst = m.rand(len(b))
+       }
+       n := m.chooseLen(len(b) - src - 1)
+       // Use the end of the slice as scratch space to avoid doing an
+       // allocation. If the slice is too small abort and try something
+       // else.
+       if len(b)+n >= cap(b) {
+               return nil
+       }
+       end := len(b)
+       b = b[:end+n]
+       copy(b[end:], b[dst:dst+n])
+       copy(b[dst:], b[src:src+n])
+       copy(b[src:], b[end:])
+       b = b[:end]
+       return b
+}
diff --git a/src/internal/fuzz/mutators_byteslice_test.go b/src/internal/fuzz/mutators_byteslice_test.go
new file mode 100644 (file)
index 0000000..50a39a9
--- /dev/null
@@ -0,0 +1,179 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "bytes"
+       "testing"
+)
+
+type mockRand struct {
+       counter int
+       b       bool
+}
+
+func (mr *mockRand) uint32() uint32 {
+       c := mr.counter
+       mr.counter++
+       return uint32(c)
+}
+
+func (mr *mockRand) intn(n int) int {
+       c := mr.counter
+       mr.counter++
+       return c % n
+}
+
+func (mr *mockRand) uint32n(n uint32) uint32 {
+       c := mr.counter
+       mr.counter++
+       return uint32(c) % n
+}
+
+func (mr *mockRand) exp2() int {
+       c := mr.counter
+       mr.counter++
+       return c
+}
+
+func (mr *mockRand) bool() bool {
+       b := mr.b
+       mr.b = !mr.b
+       return b
+}
+
+func (mr *mockRand) save(*uint64, *uint64) {
+       panic("unimplemented")
+}
+
+func (mr *mockRand) restore(uint64, uint64) {
+       panic("unimplemented")
+}
+
+func TestByteSliceMutators(t *testing.T) {
+       for _, tc := range []struct {
+               name     string
+               mutator  func(*mutator, []byte) []byte
+               input    []byte
+               expected []byte
+       }{
+               {
+                       name:     "byteSliceRemoveBytes",
+                       mutator:  byteSliceRemoveBytes,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{4},
+               },
+               {
+                       name:     "byteSliceInsertRandomBytes",
+                       mutator:  byteSliceInsertRandomBytes,
+                       input:    make([]byte, 4, 8),
+                       expected: []byte{3, 4, 5, 0, 0, 0, 0},
+               },
+               {
+                       name:     "byteSliceDuplicateBytes",
+                       mutator:  byteSliceDuplicateBytes,
+                       input:    append(make([]byte, 0, 13), []byte{1, 2, 3, 4}...),
+                       expected: []byte{1, 1, 2, 3, 4, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceOverwriteBytes",
+                       mutator:  byteSliceOverwriteBytes,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{1, 1, 3, 4},
+               },
+               {
+                       name:     "byteSliceBitFlip",
+                       mutator:  byteSliceBitFlip,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{3, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceXORByte",
+                       mutator:  byteSliceXORByte,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{3, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceSwapByte",
+                       mutator:  byteSliceSwapByte,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{2, 1, 3, 4},
+               },
+               {
+                       name:     "byteSliceArithmeticUint8",
+                       mutator:  byteSliceArithmeticUint8,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{255, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceArithmeticUint16",
+                       mutator:  byteSliceArithmeticUint16,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{1, 3, 3, 4},
+               },
+               {
+                       name:     "byteSliceArithmeticUint32",
+                       mutator:  byteSliceArithmeticUint32,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{2, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceArithmeticUint64",
+                       mutator:  byteSliceArithmeticUint64,
+                       input:    []byte{1, 2, 3, 4, 5, 6, 7, 8},
+                       expected: []byte{2, 2, 3, 4, 5, 6, 7, 8},
+               },
+               {
+                       name:     "byteSliceOverwriteInterestingUint8",
+                       mutator:  byteSliceOverwriteInterestingUint8,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{255, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceOverwriteInterestingUint16",
+                       mutator:  byteSliceOverwriteInterestingUint16,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{255, 127, 3, 4},
+               },
+               {
+                       name:     "byteSliceOverwriteInterestingUint32",
+                       mutator:  byteSliceOverwriteInterestingUint32,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{250, 0, 0, 250},
+               },
+               {
+                       name:     "byteSliceInsertConstantBytes",
+                       mutator:  byteSliceInsertConstantBytes,
+                       input:    append(make([]byte, 0, 8), []byte{1, 2, 3, 4}...),
+                       expected: []byte{3, 3, 3, 1, 2, 3, 4},
+               },
+               {
+                       name:     "byteSliceOverwriteConstantBytes",
+                       mutator:  byteSliceOverwriteConstantBytes,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{3, 3, 3, 4},
+               },
+               {
+                       name:     "byteSliceShuffleBytes",
+                       mutator:  byteSliceShuffleBytes,
+                       input:    []byte{1, 2, 3, 4},
+                       expected: []byte{2, 3, 1, 4},
+               },
+               {
+                       name:     "byteSliceSwapBytes",
+                       mutator:  byteSliceSwapBytes,
+                       input:    append(make([]byte, 0, 9), []byte{1, 2, 3, 4}...),
+                       expected: []byte{2, 1, 3, 4},
+               },
+       } {
+               t.Run(tc.name, func(t *testing.T) {
+                       m := &mutator{r: &mockRand{}}
+                       b := tc.mutator(m, tc.input)
+                       if !bytes.Equal(b, tc.expected) {
+                               t.Errorf("got %x, want %x", b, tc.expected)
+                       }
+               })
+       }
+}
diff --git a/src/internal/fuzz/pcg.go b/src/internal/fuzz/pcg.go
new file mode 100644 (file)
index 0000000..c9ea0af
--- /dev/null
@@ -0,0 +1,145 @@
+// 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 fuzz
+
+import (
+       "math/bits"
+       "os"
+       "strconv"
+       "strings"
+       "sync/atomic"
+       "time"
+)
+
+type mutatorRand interface {
+       uint32() uint32
+       intn(int) int
+       uint32n(uint32) uint32
+       exp2() int
+       bool() bool
+
+       save(randState, randInc *uint64)
+       restore(randState, randInc uint64)
+}
+
+// The functions in pcg implement a 32 bit PRNG with a 64 bit period: pcg xsh rr
+// 64 32. See https://www.pcg-random.org/ for more information. This
+// implementation is geared specifically towards the needs of fuzzing: Simple
+// creation and use, no reproducibility, no concurrency safety, just the
+// necessary methods, optimized for speed.
+
+var globalInc uint64 // PCG stream
+
+const multiplier uint64 = 6364136223846793005
+
+// pcgRand is a PRNG. It should not be copied or shared. No Rand methods are
+// concurrency safe.
+type pcgRand struct {
+       noCopy noCopy // help avoid mistakes: ask vet to ensure that we don't make a copy
+       state  uint64
+       inc    uint64
+}
+
+func godebugSeed() *int {
+       debug := strings.Split(os.Getenv("GODEBUG"), ",")
+       for _, f := range debug {
+               if strings.HasPrefix(f, "fuzzseed=") {
+                       seed, err := strconv.Atoi(strings.TrimPrefix(f, "fuzzseed="))
+                       if err != nil {
+                               panic("malformed fuzzseed")
+                       }
+                       return &seed
+               }
+       }
+       return nil
+}
+
+// newPcgRand generates a new, seeded Rand, ready for use.
+func newPcgRand() *pcgRand {
+       r := new(pcgRand)
+       now := uint64(time.Now().UnixNano())
+       if seed := godebugSeed(); seed != nil {
+               now = uint64(*seed)
+       }
+       inc := atomic.AddUint64(&globalInc, 1)
+       r.state = now
+       r.inc = (inc << 1) | 1
+       r.step()
+       r.state += now
+       r.step()
+       return r
+}
+
+func (r *pcgRand) step() {
+       r.state *= multiplier
+       r.state += r.inc
+}
+
+func (r *pcgRand) save(randState, randInc *uint64) {
+       *randState = r.state
+       *randInc = r.inc
+}
+
+func (r *pcgRand) restore(randState, randInc uint64) {
+       r.state = randState
+       r.inc = randInc
+}
+
+// uint32 returns a pseudo-random uint32.
+func (r *pcgRand) uint32() uint32 {
+       x := r.state
+       r.step()
+       return bits.RotateLeft32(uint32(((x>>18)^x)>>27), -int(x>>59))
+}
+
+// intn returns a pseudo-random number in [0, n).
+// n must fit in a uint32.
+func (r *pcgRand) intn(n int) int {
+       if int(uint32(n)) != n {
+               panic("large Intn")
+       }
+       return int(r.uint32n(uint32(n)))
+}
+
+// uint32n returns a pseudo-random number in [0, n).
+//
+// For implementation details, see:
+// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction
+// https://lemire.me/blog/2016/06/30/fast-random-shuffling
+func (r *pcgRand) uint32n(n uint32) uint32 {
+       v := r.uint32()
+       prod := uint64(v) * uint64(n)
+       low := uint32(prod)
+       if low < n {
+               thresh := uint32(-int32(n)) % n
+               for low < thresh {
+                       v = r.uint32()
+                       prod = uint64(v) * uint64(n)
+                       low = uint32(prod)
+               }
+       }
+       return uint32(prod >> 32)
+}
+
+// exp2 generates n with probability 1/2^(n+1).
+func (r *pcgRand) exp2() int {
+       return bits.TrailingZeros32(r.uint32())
+}
+
+// bool generates a random bool.
+func (r *pcgRand) bool() bool {
+       return r.uint32()&1 == 0
+}
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://golang.org/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) lock()   {}
+func (*noCopy) unlock() {}
diff --git a/src/internal/fuzz/queue.go b/src/internal/fuzz/queue.go
new file mode 100644 (file)
index 0000000..cf67a28
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2021 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 fuzz
+
+// queue holds a growable sequence of inputs for fuzzing and minimization.
+//
+// For now, this is a simple ring buffer
+// (https://en.wikipedia.org/wiki/Circular_buffer).
+//
+// TODO(golang.org/issue/46224): use a priotization algorithm based on input
+// size, previous duration, coverage, and any other metrics that seem useful.
+type queue struct {
+       // elems holds a ring buffer.
+       // The queue is empty when begin = end.
+       // The queue is full (until grow is called) when end = begin + N - 1 (mod N)
+       // where N = cap(elems).
+       elems     []interface{}
+       head, len int
+}
+
+func (q *queue) cap() int {
+       return len(q.elems)
+}
+
+func (q *queue) grow() {
+       oldCap := q.cap()
+       newCap := oldCap * 2
+       if newCap == 0 {
+               newCap = 8
+       }
+       newElems := make([]interface{}, newCap)
+       oldLen := q.len
+       for i := 0; i < oldLen; i++ {
+               newElems[i] = q.elems[(q.head+i)%oldCap]
+       }
+       q.elems = newElems
+       q.head = 0
+}
+
+func (q *queue) enqueue(e interface{}) {
+       if q.len+1 > q.cap() {
+               q.grow()
+       }
+       i := (q.head + q.len) % q.cap()
+       q.elems[i] = e
+       q.len++
+}
+
+func (q *queue) dequeue() (interface{}, bool) {
+       if q.len == 0 {
+               return nil, false
+       }
+       e := q.elems[q.head]
+       q.elems[q.head] = nil
+       q.head = (q.head + 1) % q.cap()
+       q.len--
+       return e, true
+}
+
+func (q *queue) peek() (interface{}, bool) {
+       if q.len == 0 {
+               return nil, false
+       }
+       return q.elems[q.head], true
+}
+
+func (q *queue) clear() {
+       *q = queue{}
+}
diff --git a/src/internal/fuzz/queue_test.go b/src/internal/fuzz/queue_test.go
new file mode 100644 (file)
index 0000000..3b179af
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2021 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 fuzz
+
+import "testing"
+
+func TestQueue(t *testing.T) {
+       // Zero valued queue should have 0 length and capacity.
+       var q queue
+       if n := q.len; n != 0 {
+               t.Fatalf("empty queue has len %d; want 0", n)
+       }
+       if n := q.cap(); n != 0 {
+               t.Fatalf("empty queue has cap %d; want 0", n)
+       }
+
+       // As we add elements, len should grow.
+       N := 32
+       for i := 0; i < N; i++ {
+               q.enqueue(i)
+               if n := q.len; n != i+1 {
+                       t.Fatalf("after adding %d elements, queue has len %d", i, n)
+               }
+               if v, ok := q.peek(); !ok {
+                       t.Fatalf("couldn't peek after adding %d elements", i)
+               } else if v.(int) != 0 {
+                       t.Fatalf("after adding %d elements, peek is %d; want 0", i, v)
+               }
+       }
+
+       // As we remove and add elements, len should shrink and grow.
+       // We should also remove elements in the same order they were added.
+       want := 0
+       for _, r := range []int{1, 2, 3, 5, 8, 13, 21} {
+               s := make([]int, 0, r)
+               for i := 0; i < r; i++ {
+                       if got, ok := q.dequeue(); !ok {
+                               t.Fatalf("after removing %d of %d elements, could not dequeue", i+1, r)
+                       } else if got != want {
+                               t.Fatalf("after removing %d of %d elements, got %d; want %d", i+1, r, got, want)
+                       } else {
+                               s = append(s, got.(int))
+                       }
+                       want = (want + 1) % N
+                       if n := q.len; n != N-i-1 {
+                               t.Fatalf("after removing %d of %d elements, len is %d; want %d", i+1, r, n, N-i-1)
+                       }
+               }
+               for i, v := range s {
+                       q.enqueue(v)
+                       if n := q.len; n != N-r+i+1 {
+                               t.Fatalf("after adding back %d of %d elements, len is %d; want %d", i+1, r, n, n-r+i+1)
+                       }
+               }
+       }
+}
diff --git a/src/internal/fuzz/sys_posix.go b/src/internal/fuzz/sys_posix.go
new file mode 100644 (file)
index 0000000..89c86c1
--- /dev/null
@@ -0,0 +1,130 @@
+// 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.
+
+//go:build darwin || linux
+
+package fuzz
+
+import (
+       "fmt"
+       "os"
+       "os/exec"
+       "syscall"
+)
+
+type sharedMemSys struct{}
+
+func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (*sharedMem, error) {
+       prot := syscall.PROT_READ | syscall.PROT_WRITE
+       flags := syscall.MAP_FILE | syscall.MAP_SHARED
+       region, err := syscall.Mmap(int(f.Fd()), 0, size, prot, flags)
+       if err != nil {
+               return nil, err
+       }
+
+       return &sharedMem{f: f, region: region, removeOnClose: removeOnClose}, nil
+}
+
+// Close unmaps the shared memory and closes the temporary file. If this
+// sharedMem was created with sharedMemTempFile, Close also removes the file.
+func (m *sharedMem) Close() error {
+       // Attempt all operations, even if we get an error for an earlier operation.
+       // os.File.Close may fail due to I/O errors, but we still want to delete
+       // the temporary file.
+       var errs []error
+       errs = append(errs,
+               syscall.Munmap(m.region),
+               m.f.Close())
+       if m.removeOnClose {
+               errs = append(errs, os.Remove(m.f.Name()))
+       }
+       for _, err := range errs {
+               if err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+// setWorkerComm configures communication channels on the cmd that will
+// run a worker process.
+func setWorkerComm(cmd *exec.Cmd, comm workerComm) {
+       mem := <-comm.memMu
+       memFile := mem.f
+       comm.memMu <- mem
+       cmd.ExtraFiles = []*os.File{comm.fuzzIn, comm.fuzzOut, memFile}
+}
+
+// getWorkerComm returns communication channels in the worker process.
+func getWorkerComm() (comm workerComm, err error) {
+       fuzzIn := os.NewFile(3, "fuzz_in")
+       fuzzOut := os.NewFile(4, "fuzz_out")
+       memFile := os.NewFile(5, "fuzz_mem")
+       fi, err := memFile.Stat()
+       if err != nil {
+               return workerComm{}, err
+       }
+       size := int(fi.Size())
+       if int64(size) != fi.Size() {
+               return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size")
+       }
+       removeOnClose := false
+       mem, err := sharedMemMapFile(memFile, size, removeOnClose)
+       if err != nil {
+               return workerComm{}, err
+       }
+       memMu := make(chan *sharedMem, 1)
+       memMu <- mem
+       return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil
+}
+
+// isInterruptError returns whether an error was returned by a process that
+// was terminated by an interrupt signal (SIGINT).
+func isInterruptError(err error) bool {
+       exitErr, ok := err.(*exec.ExitError)
+       if !ok || exitErr.ExitCode() >= 0 {
+               return false
+       }
+       status := exitErr.Sys().(syscall.WaitStatus)
+       return status.Signal() == syscall.SIGINT
+}
+
+// terminationSignal checks if err is an exec.ExitError with a signal status.
+// If it is, terminationSignal returns the signal and true.
+// If not, -1 and false.
+func terminationSignal(err error) (os.Signal, bool) {
+       exitErr, ok := err.(*exec.ExitError)
+       if !ok || exitErr.ExitCode() >= 0 {
+               return syscall.Signal(-1), false
+       }
+       status := exitErr.Sys().(syscall.WaitStatus)
+       return status.Signal(), status.Signaled()
+}
+
+// isCrashSignal returns whether a signal was likely to have been caused by an
+// error in the program that received it, triggered by a fuzz input. For
+// example, SIGSEGV would be received after a nil pointer dereference.
+// Other signals like SIGKILL or SIGHUP are more likely to have been sent by
+// another process, and we shouldn't record a crasher if the worker process
+// receives one of these.
+//
+// Note that Go installs its own signal handlers on startup, so some of these
+// signals may only be received if signal handlers are changed. For example,
+// SIGSEGV is normally transformed into a panic that causes the process to exit
+// with status 2 if not recovered, which we handle as a crash.
+func isCrashSignal(signal os.Signal) bool {
+       switch signal {
+       case
+               syscall.SIGILL,  // illegal instruction
+               syscall.SIGTRAP, // breakpoint
+               syscall.SIGABRT, // abort() called
+               syscall.SIGBUS,  // invalid memory access (e.g., misaligned address)
+               syscall.SIGFPE,  // math error, e.g., integer divide by zero
+               syscall.SIGSEGV, // invalid memory access (e.g., write to read-only)
+               syscall.SIGPIPE: // sent data to closed pipe or socket
+               return true
+       default:
+               return false
+       }
+}
diff --git a/src/internal/fuzz/sys_unimplemented.go b/src/internal/fuzz/sys_unimplemented.go
new file mode 100644 (file)
index 0000000..123a325
--- /dev/null
@@ -0,0 +1,44 @@
+// 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.
+
+// If you update this constraint, also update cmd/internal/sys.FuzzSupported.
+//
+//go:build !darwin && !linux && !windows
+
+package fuzz
+
+import (
+       "os"
+       "os/exec"
+)
+
+type sharedMemSys struct{}
+
+func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (*sharedMem, error) {
+       panic("not implemented")
+}
+
+func (m *sharedMem) Close() error {
+       panic("not implemented")
+}
+
+func setWorkerComm(cmd *exec.Cmd, comm workerComm) {
+       panic("not implemented")
+}
+
+func getWorkerComm() (comm workerComm, err error) {
+       panic("not implemented")
+}
+
+func isInterruptError(err error) bool {
+       panic("not implemented")
+}
+
+func terminationSignal(err error) (os.Signal, bool) {
+       panic("not implemented")
+}
+
+func isCrashSignal(signal os.Signal) bool {
+       panic("not implemented")
+}
diff --git a/src/internal/fuzz/sys_windows.go b/src/internal/fuzz/sys_windows.go
new file mode 100644 (file)
index 0000000..9c006b0
--- /dev/null
@@ -0,0 +1,152 @@
+// 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 fuzz
+
+import (
+       "fmt"
+       "os"
+       "os/exec"
+       "reflect"
+       "syscall"
+       "unsafe"
+)
+
+type sharedMemSys struct {
+       mapObj syscall.Handle
+}
+
+func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (mem *sharedMem, err error) {
+       defer func() {
+               if err != nil {
+                       err = fmt.Errorf("mapping temporary file %s: %w", f.Name(), err)
+               }
+       }()
+
+       // Create a file mapping object. The object itself is not shared.
+       mapObj, err := syscall.CreateFileMapping(
+               syscall.Handle(f.Fd()), // fhandle
+               nil,                    // sa
+               syscall.PAGE_READWRITE, // prot
+               0,                      // maxSizeHigh
+               0,                      // maxSizeLow
+               nil,                    // name
+       )
+       if err != nil {
+               return nil, err
+       }
+
+       // Create a view from the file mapping object.
+       access := uint32(syscall.FILE_MAP_READ | syscall.FILE_MAP_WRITE)
+       addr, err := syscall.MapViewOfFile(
+               mapObj,        // handle
+               access,        // access
+               0,             // offsetHigh
+               0,             // offsetLow
+               uintptr(size), // length
+       )
+       if err != nil {
+               syscall.CloseHandle(mapObj)
+               return nil, err
+       }
+
+       var region []byte
+       header := (*reflect.SliceHeader)(unsafe.Pointer(&region))
+       header.Data = addr
+       header.Len = size
+       header.Cap = size
+       return &sharedMem{
+               f:             f,
+               region:        region,
+               removeOnClose: removeOnClose,
+               sys:           sharedMemSys{mapObj: mapObj},
+       }, nil
+}
+
+// Close unmaps the shared memory and closes the temporary file. If this
+// sharedMem was created with sharedMemTempFile, Close also removes the file.
+func (m *sharedMem) Close() error {
+       // Attempt all operations, even if we get an error for an earlier operation.
+       // os.File.Close may fail due to I/O errors, but we still want to delete
+       // the temporary file.
+       var errs []error
+       errs = append(errs,
+               syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&m.region[0]))),
+               syscall.CloseHandle(m.sys.mapObj),
+               m.f.Close())
+       if m.removeOnClose {
+               errs = append(errs, os.Remove(m.f.Name()))
+       }
+       for _, err := range errs {
+               if err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+// setWorkerComm configures communication channels on the cmd that will
+// run a worker process.
+func setWorkerComm(cmd *exec.Cmd, comm workerComm) {
+       mem := <-comm.memMu
+       memName := mem.f.Name()
+       comm.memMu <- mem
+       syscall.SetHandleInformation(syscall.Handle(comm.fuzzIn.Fd()), syscall.HANDLE_FLAG_INHERIT, 1)
+       syscall.SetHandleInformation(syscall.Handle(comm.fuzzOut.Fd()), syscall.HANDLE_FLAG_INHERIT, 1)
+       cmd.Env = append(cmd.Env, fmt.Sprintf("GO_TEST_FUZZ_WORKER_HANDLES=%x,%x,%q", comm.fuzzIn.Fd(), comm.fuzzOut.Fd(), memName))
+       cmd.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(comm.fuzzIn.Fd()), syscall.Handle(comm.fuzzOut.Fd())}}
+}
+
+// getWorkerComm returns communication channels in the worker process.
+func getWorkerComm() (comm workerComm, err error) {
+       v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES")
+       if v == "" {
+               return workerComm{}, fmt.Errorf("GO_TEST_FUZZ_WORKER_HANDLES not set")
+       }
+       var fuzzInFD, fuzzOutFD uintptr
+       var memName string
+       if _, err := fmt.Sscanf(v, "%x,%x,%q", &fuzzInFD, &fuzzOutFD, &memName); err != nil {
+               return workerComm{}, fmt.Errorf("parsing GO_TEST_FUZZ_WORKER_HANDLES=%s: %v", v, err)
+       }
+
+       fuzzIn := os.NewFile(fuzzInFD, "fuzz_in")
+       fuzzOut := os.NewFile(fuzzOutFD, "fuzz_out")
+       tmpFile, err := os.OpenFile(memName, os.O_RDWR, 0)
+       if err != nil {
+               return workerComm{}, fmt.Errorf("worker opening temp file: %w", err)
+       }
+       fi, err := tmpFile.Stat()
+       if err != nil {
+               return workerComm{}, fmt.Errorf("worker checking temp file size: %w", err)
+       }
+       size := int(fi.Size())
+       if int64(size) != fi.Size() {
+               return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size")
+       }
+       removeOnClose := false
+       mem, err := sharedMemMapFile(tmpFile, size, removeOnClose)
+       if err != nil {
+               return workerComm{}, err
+       }
+       memMu := make(chan *sharedMem, 1)
+       memMu <- mem
+
+       return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil
+}
+
+func isInterruptError(err error) bool {
+       // On Windows, we can't tell whether the process was interrupted by the error
+       // returned by Wait. It looks like an ExitError with status 1.
+       return false
+}
+
+// terminationSignal returns -1 and false because Windows doesn't have signals.
+func terminationSignal(err error) (os.Signal, bool) {
+       return syscall.Signal(-1), false
+}
+
+// isCrashSignal is not implemented because Windows doesn't have signals.
+func isCrashSignal(signal os.Signal) bool {
+       panic("not implemented: no signals on windows")
+}
diff --git a/src/internal/fuzz/trace.go b/src/internal/fuzz/trace.go
new file mode 100644 (file)
index 0000000..cab0838
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 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:build !libfuzzer
+
+package fuzz
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname libfuzzerTraceCmp1 runtime.libfuzzerTraceCmp1
+//go:linkname libfuzzerTraceCmp2 runtime.libfuzzerTraceCmp2
+//go:linkname libfuzzerTraceCmp4 runtime.libfuzzerTraceCmp4
+//go:linkname libfuzzerTraceCmp8 runtime.libfuzzerTraceCmp8
+
+//go:linkname libfuzzerTraceConstCmp1 runtime.libfuzzerTraceConstCmp1
+//go:linkname libfuzzerTraceConstCmp2 runtime.libfuzzerTraceConstCmp2
+//go:linkname libfuzzerTraceConstCmp4 runtime.libfuzzerTraceConstCmp4
+//go:linkname libfuzzerTraceConstCmp8 runtime.libfuzzerTraceConstCmp8
+
+func libfuzzerTraceCmp1(arg0, arg1 uint8)  {}
+func libfuzzerTraceCmp2(arg0, arg1 uint16) {}
+func libfuzzerTraceCmp4(arg0, arg1 uint32) {}
+func libfuzzerTraceCmp8(arg0, arg1 uint64) {}
+
+func libfuzzerTraceConstCmp1(arg0, arg1 uint8)  {}
+func libfuzzerTraceConstCmp2(arg0, arg1 uint16) {}
+func libfuzzerTraceConstCmp4(arg0, arg1 uint32) {}
+func libfuzzerTraceConstCmp8(arg0, arg1 uint64) {}
diff --git a/src/internal/fuzz/worker.go b/src/internal/fuzz/worker.go
new file mode 100644 (file)
index 0000000..02efa7f
--- /dev/null
@@ -0,0 +1,1165 @@
+// 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 fuzz
+
+import (
+       "bytes"
+       "context"
+       "crypto/sha256"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "runtime"
+       "sync"
+       "time"
+)
+
+const (
+       // workerFuzzDuration is the amount of time a worker can spend testing random
+       // variations of an input given by the coordinator.
+       workerFuzzDuration = 100 * time.Millisecond
+
+       // workerTimeoutDuration is the amount of time a worker can go without
+       // responding to the coordinator before being stopped.
+       workerTimeoutDuration = 1 * time.Second
+
+       // workerExitCode is used as an exit code by fuzz worker processes after an internal error.
+       // This distinguishes internal errors from uncontrolled panics and other crashes.
+       // Keep in sync with internal/fuzz.workerExitCode.
+       workerExitCode = 70
+
+       // workerSharedMemSize is the maximum size of the shared memory file used to
+       // communicate with workers. This limits the size of fuzz inputs.
+       workerSharedMemSize = 100 << 20 // 100 MB
+)
+
+// worker manages a worker process running a test binary. The worker object
+// exists only in the coordinator (the process started by 'go test -fuzz').
+// workerClient is used by the coordinator to send RPCs to the worker process,
+// which handles them with workerServer.
+type worker struct {
+       dir     string   // working directory, same as package directory
+       binPath string   // path to test executable
+       args    []string // arguments for test executable
+       env     []string // environment for test executable
+
+       coordinator *coordinator
+
+       memMu chan *sharedMem // mutex guarding shared memory with worker; persists across processes.
+
+       cmd         *exec.Cmd     // current worker process
+       client      *workerClient // used to communicate with worker process
+       waitErr     error         // last error returned by wait, set before termC is closed.
+       interrupted bool          // true after stop interrupts a running worker.
+       termC       chan struct{} // closed by wait when worker process terminates
+}
+
+func newWorker(c *coordinator, dir, binPath string, args, env []string) (*worker, error) {
+       mem, err := sharedMemTempFile(workerSharedMemSize)
+       if err != nil {
+               return nil, err
+       }
+       memMu := make(chan *sharedMem, 1)
+       memMu <- mem
+       return &worker{
+               dir:         dir,
+               binPath:     binPath,
+               args:        args,
+               env:         env[:len(env):len(env)], // copy on append to ensure workers don't overwrite each other.
+               coordinator: c,
+               memMu:       memMu,
+       }, nil
+}
+
+// cleanup releases persistent resources associated with the worker.
+func (w *worker) cleanup() error {
+       mem := <-w.memMu
+       if mem == nil {
+               return nil
+       }
+       close(w.memMu)
+       return mem.Close()
+}
+
+// coordinate runs the test binary to perform fuzzing.
+//
+// coordinate loops until ctx is cancelled or a fatal error is encountered.
+// If a test process terminates unexpectedly while fuzzing, coordinate will
+// attempt to restart and continue unless the termination can be attributed
+// to an interruption (from a timer or the user).
+//
+// While looping, coordinate receives inputs from the coordinator, passes
+// those inputs to the worker process, then passes the results back to
+// the coordinator.
+func (w *worker) coordinate(ctx context.Context) error {
+       // Main event loop.
+       for {
+               // Start or restart the worker if it's not running.
+               if !w.isRunning() {
+                       if err := w.startAndPing(ctx); err != nil {
+                               return err
+                       }
+               }
+
+               select {
+               case <-ctx.Done():
+                       // Worker was told to stop.
+                       err := w.stop()
+                       if err != nil && !w.interrupted && !isInterruptError(err) {
+                               return err
+                       }
+                       return ctx.Err()
+
+               case <-w.termC:
+                       // Worker process terminated unexpectedly while waiting for input.
+                       err := w.stop()
+                       if w.interrupted {
+                               panic("worker interrupted after unexpected termination")
+                       }
+                       if err == nil || isInterruptError(err) {
+                               // Worker stopped, either by exiting with status 0 or after being
+                               // interrupted with a signal that was not sent by the coordinator.
+                               //
+                               // When the user presses ^C, on POSIX platforms, SIGINT is delivered to
+                               // all processes in the group concurrently, and the worker may see it
+                               // before the coordinator. The worker should exit 0 gracefully (in
+                               // theory).
+                               //
+                               // This condition is probably intended by the user, so suppress
+                               // the error.
+                               return nil
+                       }
+                       if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == workerExitCode {
+                               // Worker exited with a code indicating F.Fuzz was not called correctly,
+                               // for example, F.Fail was called first.
+                               return fmt.Errorf("fuzzing process exited unexpectedly due to an internal failure: %w", err)
+                       }
+                       // Worker exited non-zero or was terminated by a non-interrupt
+                       // signal (for example, SIGSEGV) while fuzzing.
+                       return fmt.Errorf("fuzzing process terminated unexpectedly: %w", err)
+                       // TODO(jayconrod,katiehockman): if -keepfuzzing, restart worker.
+
+               case input := <-w.coordinator.inputC:
+                       // Received input from coordinator.
+                       args := fuzzArgs{
+                               Limit:        input.limit,
+                               Timeout:      input.timeout,
+                               Warmup:       input.warmup,
+                               CoverageData: input.coverageData,
+                       }
+                       entry, resp, isInternalError, err := w.client.fuzz(ctx, input.entry, args)
+                       canMinimize := true
+                       if err != nil {
+                               // Error communicating with worker.
+                               w.stop()
+                               if ctx.Err() != nil {
+                                       // Timeout or interruption.
+                                       return ctx.Err()
+                               }
+                               if w.interrupted {
+                                       // Communication error before we stopped the worker.
+                                       // Report an error, but don't record a crasher.
+                                       return fmt.Errorf("communicating with fuzzing process: %v", err)
+                               }
+                               if sig, ok := terminationSignal(w.waitErr); ok && !isCrashSignal(sig) {
+                                       // Worker terminated by a signal that probably wasn't caused by a
+                                       // specific input to the fuzz function. For example, on Linux,
+                                       // the kernel (OOM killer) may send SIGKILL to a process using a lot
+                                       // of memory. Or the shell might send SIGHUP when the terminal
+                                       // is closed. Don't record a crasher.
+                                       return fmt.Errorf("fuzzing process terminated by unexpected signal; no crash will be recorded: %v", w.waitErr)
+                               }
+                               if isInternalError {
+                                       // An internal error occurred which shouldn't be considered
+                                       // a crash.
+                                       return err
+                               }
+                               // Unexpected termination. Set error message and fall through.
+                               // We'll restart the worker on the next iteration.
+                               // Don't attempt to minimize this since it crashed the worker.
+                               resp.Err = fmt.Sprintf("fuzzing process terminated unexpectedly: %v", w.waitErr)
+                               canMinimize = false
+                       }
+                       result := fuzzResult{
+                               limit:         input.limit,
+                               count:         resp.Count,
+                               totalDuration: resp.TotalDuration,
+                               entryDuration: resp.InterestingDuration,
+                               entry:         entry,
+                               crasherMsg:    resp.Err,
+                               coverageData:  resp.CoverageData,
+                               canMinimize:   canMinimize,
+                       }
+                       w.coordinator.resultC <- result
+
+               case input := <-w.coordinator.minimizeC:
+                       // Received input to minimize from coordinator.
+                       result, err := w.minimize(ctx, input)
+                       if err != nil {
+                               // Error minimizing. Send back the original input. If it didn't cause
+                               // an error before, report it as causing an error now.
+                               // TODO: double-check this is handled correctly when
+                               // implementing -keepfuzzing.
+                               result = fuzzResult{
+                                       entry:       input.entry,
+                                       crasherMsg:  input.crasherMsg,
+                                       canMinimize: false,
+                                       limit:       input.limit,
+                               }
+                               if result.crasherMsg == "" {
+                                       result.crasherMsg = err.Error()
+                               }
+                       }
+                       w.coordinator.resultC <- result
+               }
+       }
+}
+
+// minimize tells a worker process to attempt to find a smaller value that
+// either causes an error (if we started minimizing because we found an input
+// that causes an error) or preserves new coverage (if we started minimizing
+// because we found an input that expands coverage).
+func (w *worker) minimize(ctx context.Context, input fuzzMinimizeInput) (min fuzzResult, err error) {
+       if w.coordinator.opts.MinimizeTimeout != 0 {
+               var cancel func()
+               ctx, cancel = context.WithTimeout(ctx, w.coordinator.opts.MinimizeTimeout)
+               defer cancel()
+       }
+
+       args := minimizeArgs{
+               Limit:        input.limit,
+               Timeout:      input.timeout,
+               KeepCoverage: input.keepCoverage,
+       }
+       entry, resp, err := w.client.minimize(ctx, input.entry, args)
+       if err != nil {
+               // Error communicating with worker.
+               w.stop()
+               if ctx.Err() != nil || w.interrupted || isInterruptError(w.waitErr) {
+                       // Worker was interrupted, possibly by the user pressing ^C.
+                       // Normally, workers can handle interrupts and timeouts gracefully and
+                       // will return without error. An error here indicates the worker
+                       // may not have been in a good state, but the error won't be meaningful
+                       // to the user. Just return the original crasher without logging anything.
+                       return fuzzResult{
+                               entry:        input.entry,
+                               crasherMsg:   input.crasherMsg,
+                               coverageData: input.keepCoverage,
+                               canMinimize:  false,
+                               limit:        input.limit,
+                       }, nil
+               }
+               return fuzzResult{}, fmt.Errorf("fuzzing process terminated unexpectedly while minimizing: %w", w.waitErr)
+       }
+
+       if input.crasherMsg != "" && resp.Err == "" {
+               return fuzzResult{}, fmt.Errorf("attempted to minimize a crash but could not reproduce")
+       }
+
+       return fuzzResult{
+               entry:         entry,
+               crasherMsg:    resp.Err,
+               coverageData:  resp.CoverageData,
+               canMinimize:   false,
+               limit:         input.limit,
+               count:         resp.Count,
+               totalDuration: resp.Duration,
+       }, nil
+}
+
+func (w *worker) isRunning() bool {
+       return w.cmd != nil
+}
+
+// startAndPing starts the worker process and sends it a message to make sure it
+// can communicate.
+//
+// startAndPing returns an error if any part of this didn't work, including if
+// the context is expired or the worker process was interrupted before it
+// responded. Errors that happen after start but before the ping response
+// likely indicate that the worker did not call F.Fuzz or called F.Fail first.
+// We don't record crashers for these errors.
+func (w *worker) startAndPing(ctx context.Context) error {
+       if ctx.Err() != nil {
+               return ctx.Err()
+       }
+       if err := w.start(); err != nil {
+               return err
+       }
+       if err := w.client.ping(ctx); err != nil {
+               w.stop()
+               if ctx.Err() != nil {
+                       return ctx.Err()
+               }
+               if isInterruptError(err) {
+                       // User may have pressed ^C before worker responded.
+                       return err
+               }
+               // TODO: record and return stderr.
+               return fmt.Errorf("fuzzing process terminated without fuzzing: %w", err)
+       }
+       return nil
+}
+
+// start runs a new worker process.
+//
+// If the process couldn't be started, start returns an error. Start won't
+// return later termination errors from the process if they occur.
+//
+// If the process starts successfully, start returns nil. stop must be called
+// once later to clean up, even if the process terminates on its own.
+//
+// When the process terminates, w.waitErr is set to the error (if any), and
+// w.termC is closed.
+func (w *worker) start() (err error) {
+       if w.isRunning() {
+               panic("worker already started")
+       }
+       w.waitErr = nil
+       w.interrupted = false
+       w.termC = nil
+
+       cmd := exec.Command(w.binPath, w.args...)
+       cmd.Dir = w.dir
+       cmd.Env = w.env[:len(w.env):len(w.env)] // copy on append to ensure workers don't overwrite each other.
+
+       // Create the "fuzz_in" and "fuzz_out" pipes so we can communicate with
+       // the worker. We don't use stdin and stdout, since the test binary may
+       // do something else with those.
+       //
+       // Each pipe has a reader and a writer. The coordinator writes to fuzzInW
+       // and reads from fuzzOutR. The worker inherits fuzzInR and fuzzOutW.
+       // The coordinator closes fuzzInR and fuzzOutW after starting the worker,
+       // since we have no further need of them.
+       fuzzInR, fuzzInW, err := os.Pipe()
+       if err != nil {
+               return err
+       }
+       defer fuzzInR.Close()
+       fuzzOutR, fuzzOutW, err := os.Pipe()
+       if err != nil {
+               fuzzInW.Close()
+               return err
+       }
+       defer fuzzOutW.Close()
+       setWorkerComm(cmd, workerComm{fuzzIn: fuzzInR, fuzzOut: fuzzOutW, memMu: w.memMu})
+
+       // Start the worker process.
+       if err := cmd.Start(); err != nil {
+               fuzzInW.Close()
+               fuzzOutR.Close()
+               return err
+       }
+
+       // Worker started successfully.
+       // After this, w.client owns fuzzInW and fuzzOutR, so w.client.Close must be
+       // called later by stop.
+       w.cmd = cmd
+       w.termC = make(chan struct{})
+       comm := workerComm{fuzzIn: fuzzInW, fuzzOut: fuzzOutR, memMu: w.memMu}
+       m := newMutator()
+       w.client = newWorkerClient(comm, m)
+
+       go func() {
+               w.waitErr = w.cmd.Wait()
+               close(w.termC)
+       }()
+
+       return nil
+}
+
+// stop tells the worker process to exit by closing w.client, then blocks until
+// it terminates. If the worker doesn't terminate after a short time, stop
+// signals it with os.Interrupt (where supported), then os.Kill.
+//
+// stop returns the error the process terminated with, if any (same as
+// w.waitErr).
+//
+// stop must be called at least once after start returns successfully, even if
+// the worker process terminates unexpectedly.
+func (w *worker) stop() error {
+       if w.termC == nil {
+               panic("worker was not started successfully")
+       }
+       select {
+       case <-w.termC:
+               // Worker already terminated.
+               if w.client == nil {
+                       // stop already called.
+                       return w.waitErr
+               }
+               // Possible unexpected termination.
+               w.client.Close()
+               w.cmd = nil
+               w.client = nil
+               return w.waitErr
+       default:
+               // Worker still running.
+       }
+
+       // Tell the worker to stop by closing fuzz_in. It won't actually stop until it
+       // finishes with earlier calls.
+       closeC := make(chan struct{})
+       go func() {
+               w.client.Close()
+               close(closeC)
+       }()
+
+       sig := os.Interrupt
+       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.
+               sig = os.Kill
+       }
+
+       t := time.NewTimer(workerTimeoutDuration)
+       for {
+               select {
+               case <-w.termC:
+                       // Worker terminated.
+                       t.Stop()
+                       <-closeC
+                       w.cmd = nil
+                       w.client = nil
+                       return w.waitErr
+
+               case <-t.C:
+                       // Timer fired before worker terminated.
+                       w.interrupted = true
+                       switch sig {
+                       case os.Interrupt:
+                               // Try to stop the worker with SIGINT and wait a little longer.
+                               w.cmd.Process.Signal(sig)
+                               sig = os.Kill
+                               t.Reset(workerTimeoutDuration)
+
+                       case os.Kill:
+                               // Try to stop the worker with SIGKILL and keep waiting.
+                               w.cmd.Process.Signal(sig)
+                               sig = nil
+                               t.Reset(workerTimeoutDuration)
+
+                       case nil:
+                               // Still waiting. Print a message to let the user know why.
+                               fmt.Fprintf(w.coordinator.opts.Log, "waiting for fuzzing process to terminate...\n")
+                       }
+               }
+       }
+}
+
+// RunFuzzWorker is called in a worker process to communicate with the
+// coordinator process in order to fuzz random inputs. RunFuzzWorker loops
+// until the coordinator tells it to stop.
+//
+// fn is a wrapper on the fuzz function. It may return an error to indicate
+// a given input "crashed". The coordinator will also record a crasher if
+// the function times out or terminates the process.
+//
+// RunFuzzWorker returns an error if it could not communicate with the
+// coordinator process.
+func RunFuzzWorker(ctx context.Context, fn func(CorpusEntry) error) error {
+       comm, err := getWorkerComm()
+       if err != nil {
+               return err
+       }
+       srv := &workerServer{
+               workerComm: comm,
+               fuzzFn:     fn,
+               m:          newMutator(),
+       }
+       return srv.serve(ctx)
+}
+
+// call is serialized and sent from the coordinator on fuzz_in. It acts as
+// a minimalist RPC mechanism. Exactly one of its fields must be set to indicate
+// which method to call.
+type call struct {
+       Ping     *pingArgs
+       Fuzz     *fuzzArgs
+       Minimize *minimizeArgs
+}
+
+// minimizeArgs contains arguments to workerServer.minimize. The value to
+// minimize is already in shared memory.
+type minimizeArgs struct {
+       // Timeout is the time to spend minimizing. This may include time to start up,
+       // especially if the input causes the worker process to terminated, requiring
+       // repeated restarts.
+       Timeout time.Duration
+
+       // Limit is the maximum number of values to test, without spending more time
+       // than Duration. 0 indicates no limit.
+       Limit int64
+
+       // KeepCoverage is a set of coverage counters the worker should attempt to
+       // keep in minimized values. When provided, the worker will reject inputs that
+       // don't cause at least one of these bits to be set.
+       KeepCoverage []byte
+}
+
+// minimizeResponse contains results from workerServer.minimize.
+type minimizeResponse struct {
+       // WroteToMem is true if the worker found a smaller input and wrote it to
+       // shared memory. If minimizeArgs.KeepCoverage was set, the minimized input
+       // preserved at least one coverage bit and did not cause an error.
+       // Otherwise, the minimized input caused some error, recorded in Err.
+       WroteToMem bool
+
+       // Err is the error string caused by the value in shared memory, if any.
+       Err string
+
+       // CoverageData is the set of coverage bits activated by the minimized value
+       // in shared memory. When set, it contains at least one bit from KeepCoverage.
+       // CoverageData will be nil if Err is set or if minimization failed.
+       CoverageData []byte
+
+       // Duration is the time spent minimizing, not including starting or cleaning up.
+       Duration time.Duration
+
+       // Count is the number of values tested.
+       Count int64
+}
+
+// fuzzArgs contains arguments to workerServer.fuzz. The value to fuzz is
+// passed in shared memory.
+type fuzzArgs struct {
+       // Timeout is the time to spend fuzzing, not including starting or
+       // cleaning up.
+       Timeout time.Duration
+
+       // Limit is the maximum number of values to test, without spending more time
+       // than Duration. 0 indicates no limit.
+       Limit int64
+
+       // Warmup indicates whether this is part of a warmup run, meaning that
+       // fuzzing should not occur. If coverageEnabled is true, then coverage data
+       // should be reported.
+       Warmup bool
+
+       // CoverageData is the coverage data. If set, the worker should update its
+       // local coverage data prior to fuzzing.
+       CoverageData []byte
+}
+
+// fuzzResponse contains results from workerServer.fuzz.
+type fuzzResponse struct {
+       // Duration is the time spent fuzzing, not including starting or cleaning up.
+       TotalDuration       time.Duration
+       InterestingDuration time.Duration
+
+       // Count is the number of values tested.
+       Count int64
+
+       // CoverageData is set if the value in shared memory expands coverage
+       // and therefore may be interesting to the coordinator.
+       CoverageData []byte
+
+       // Err is the error string caused by the value in shared memory, which is
+       // non-empty if the value in shared memory caused a crash.
+       Err string
+
+       // InternalErr is the error string caused by an internal error in the
+       // worker. This shouldn't be considered a crasher.
+       InternalErr string
+}
+
+// pingArgs contains arguments to workerServer.ping.
+type pingArgs struct{}
+
+// pingResponse contains results from workerServer.ping.
+type pingResponse struct{}
+
+// workerComm holds pipes and shared memory used for communication
+// between the coordinator process (client) and a worker process (server).
+// These values are unique to each worker; they are shared only with the
+// coordinator, not with other workers.
+//
+// Access to shared memory is synchronized implicitly over the RPC protocol
+// implemented in workerServer and workerClient. During a call, the client
+// (worker) has exclusive access to shared memory; at other times, the server
+// (coordinator) has exclusive access.
+type workerComm struct {
+       fuzzIn, fuzzOut *os.File
+       memMu           chan *sharedMem // mutex guarding shared memory
+}
+
+// workerServer is a minimalist RPC server, run by fuzz worker processes.
+// It allows the coordinator process (using workerClient) to call methods in a
+// worker process. This system allows the coordinator to run multiple worker
+// processes in parallel and to collect inputs that caused crashes from shared
+// memory after a worker process terminates unexpectedly.
+type workerServer struct {
+       workerComm
+       m *mutator
+
+       // coverageMask is the local coverage data for the worker. It is
+       // periodically updated to reflect the data in the coordinator when new
+       // coverage is found.
+       coverageMask []byte
+
+       // fuzzFn runs the worker's fuzz function on the given input and returns
+       // an error if it finds a crasher (the process may also exit or crash).
+       fuzzFn func(CorpusEntry) error
+}
+
+// serve reads serialized RPC messages on fuzzIn. When serve receives a message,
+// it calls the corresponding method, then sends the serialized result back
+// on fuzzOut.
+//
+// serve handles RPC calls synchronously; it will not attempt to read a message
+// until the previous call has finished.
+//
+// serve returns errors that occurred when communicating over pipes. serve
+// does not return errors from method calls; those are passed through serialized
+// responses.
+func (ws *workerServer) serve(ctx context.Context) error {
+       enc := json.NewEncoder(ws.fuzzOut)
+       dec := json.NewDecoder(&contextReader{ctx: ctx, r: ws.fuzzIn})
+       for {
+               var c call
+               if err := dec.Decode(&c); err != nil {
+                       if err == io.EOF || err == ctx.Err() {
+                               return nil
+                       } else {
+                               return err
+                       }
+               }
+
+               var resp interface{}
+               switch {
+               case c.Fuzz != nil:
+                       resp = ws.fuzz(ctx, *c.Fuzz)
+               case c.Minimize != nil:
+                       resp = ws.minimize(ctx, *c.Minimize)
+               case c.Ping != nil:
+                       resp = ws.ping(ctx, *c.Ping)
+               default:
+                       return errors.New("no arguments provided for any call")
+               }
+
+               if err := enc.Encode(resp); err != nil {
+                       return err
+               }
+       }
+}
+
+// fuzz runs the test function on random variations of the input value in shared
+// memory for a limited duration or number of iterations.
+//
+// fuzz returns early if it finds an input that crashes the fuzz function (with
+// fuzzResponse.Err set) or an input that expands coverage (with
+// fuzzResponse.InterestingDuration set).
+//
+// fuzz does not modify the input in shared memory. Instead, it saves the
+// initial PRNG state in shared memory and increments a counter in shared
+// memory before each call to the test function. The caller may reconstruct
+// the crashing input with this information, since the PRNG is deterministic.
+func (ws *workerServer) fuzz(ctx context.Context, args fuzzArgs) (resp fuzzResponse) {
+       if args.CoverageData != nil {
+               if ws.coverageMask != nil && len(args.CoverageData) != len(ws.coverageMask) {
+                       resp.InternalErr = fmt.Sprintf("unexpected size for CoverageData: got %d, expected %d", len(args.CoverageData), len(ws.coverageMask))
+                       return resp
+               }
+               ws.coverageMask = args.CoverageData
+       }
+       start := time.Now()
+       defer func() { resp.TotalDuration = time.Since(start) }()
+
+       if args.Timeout != 0 {
+               var cancel func()
+               ctx, cancel = context.WithTimeout(ctx, args.Timeout)
+               defer cancel()
+       }
+       mem := <-ws.memMu
+       ws.m.r.save(&mem.header().randState, &mem.header().randInc)
+       defer func() {
+               resp.Count = mem.header().count
+               ws.memMu <- mem
+       }()
+       if args.Limit > 0 && mem.header().count >= args.Limit {
+               resp.InternalErr = fmt.Sprintf("mem.header().count %d already exceeds args.Limit %d", mem.header().count, args.Limit)
+               return resp
+       }
+
+       vals, err := unmarshalCorpusFile(mem.valueCopy())
+       if err != nil {
+               resp.InternalErr = err.Error()
+               return resp
+       }
+
+       shouldStop := func() bool {
+               return args.Limit > 0 && mem.header().count >= args.Limit
+       }
+       fuzzOnce := func(entry CorpusEntry) (dur time.Duration, cov []byte, errMsg string) {
+               mem.header().count++
+               start := time.Now()
+               err := ws.fuzzFn(entry)
+               dur = time.Since(start)
+               if err != nil {
+                       errMsg = err.Error()
+                       if errMsg == "" {
+                               errMsg = "fuzz function failed with no input"
+                       }
+                       return dur, nil, errMsg
+               }
+               if ws.coverageMask != nil && countNewCoverageBits(ws.coverageMask, coverageSnapshot) > 0 {
+                       return dur, coverageSnapshot, ""
+               }
+               return dur, nil, ""
+       }
+
+       if args.Warmup {
+               dur, _, errMsg := fuzzOnce(CorpusEntry{Values: vals})
+               if errMsg != "" {
+                       resp.Err = errMsg
+                       return resp
+               }
+               resp.InterestingDuration = dur
+               if coverageEnabled {
+                       resp.CoverageData = coverageSnapshot
+               }
+               return resp
+       }
+
+       for {
+               select {
+               case <-ctx.Done():
+                       return resp
+
+               default:
+                       ws.m.mutate(vals, cap(mem.valueRef()))
+                       entry := CorpusEntry{Values: vals}
+                       dur, cov, errMsg := fuzzOnce(entry)
+                       if errMsg != "" {
+                               resp.Err = errMsg
+                               return resp
+                       }
+                       if cov != nil {
+                               resp.CoverageData = cov
+                               resp.InterestingDuration = dur
+                               return resp
+                       }
+                       if shouldStop() {
+                               return resp
+                       }
+               }
+       }
+}
+
+func (ws *workerServer) minimize(ctx context.Context, args minimizeArgs) (resp minimizeResponse) {
+       start := time.Now()
+       defer func() { resp.Duration = time.Now().Sub(start) }()
+       mem := <-ws.memMu
+       defer func() { ws.memMu <- mem }()
+       vals, err := unmarshalCorpusFile(mem.valueCopy())
+       if err != nil {
+               panic(err)
+       }
+       if args.Timeout != 0 {
+               var cancel func()
+               ctx, cancel = context.WithTimeout(ctx, args.Timeout)
+               defer cancel()
+       }
+
+       // Minimize the values in vals, then write to shared memory. We only write
+       // to shared memory after completing minimization.
+       // TODO(48165): If the worker terminates unexpectedly during minimization,
+       // the coordinator has no way of retrieving the crashing input.
+       success, err := ws.minimizeInput(ctx, vals, &mem.header().count, args.Limit, args.KeepCoverage)
+       if success {
+               writeToMem(vals, mem)
+               resp.WroteToMem = true
+               if err != nil {
+                       resp.Err = err.Error()
+               } else {
+                       resp.CoverageData = coverageSnapshot
+               }
+       }
+       return resp
+}
+
+// minimizeInput applies a series of minimizing transformations on the provided
+// vals, ensuring that each minimization still causes an error in fuzzFn. It
+// uses the context to determine how long to run, stopping once closed. It
+// returns a bool indicating whether minimization was successful and an error if
+// one was found.
+func (ws *workerServer) minimizeInput(ctx context.Context, vals []interface{}, count *int64, limit int64, keepCoverage []byte) (success bool, retErr error) {
+       shouldStop := func() bool {
+               return ctx.Err() != nil ||
+                       (limit > 0 && *count >= limit)
+       }
+       if shouldStop() {
+               return false, nil
+       }
+
+       // Check that the original value preserves coverage or causes an error.
+       // If not, then whatever caused us to think the value was interesting may
+       // have been a flake, and we can't minimize it.
+       *count++
+       retErr = ws.fuzzFn(CorpusEntry{Values: vals})
+       if keepCoverage != nil {
+               if !hasCoverageBit(keepCoverage, coverageSnapshot) || retErr != nil {
+                       return false, nil
+               }
+       } else if retErr == nil {
+               return false, nil
+       }
+
+       var valI int
+       // tryMinimized runs the fuzz function with candidate replacing the value
+       // at index valI. tryMinimized returns whether the input with candidate is
+       // interesting for the same reason as the original input: it returns
+       // an error if one was expected, or it preserves coverage.
+       tryMinimized := func(candidate interface{}) bool {
+               prev := vals[valI]
+               // Set vals[valI] to the candidate after it has been
+               // properly cast. We know that candidate must be of
+               // the same type as prev, so use that as a reference.
+               switch c := candidate.(type) {
+               case float64:
+                       switch prev.(type) {
+                       case float32:
+                               vals[valI] = float32(c)
+                       case float64:
+                               vals[valI] = c
+                       default:
+                               panic("impossible")
+                       }
+               case uint:
+                       switch prev.(type) {
+                       case uint:
+                               vals[valI] = c
+                       case uint8:
+                               vals[valI] = uint8(c)
+                       case uint16:
+                               vals[valI] = uint16(c)
+                       case uint32:
+                               vals[valI] = uint32(c)
+                       case uint64:
+                               vals[valI] = uint64(c)
+                       case int:
+                               vals[valI] = int(c)
+                       case int8:
+                               vals[valI] = int8(c)
+                       case int16:
+                               vals[valI] = int16(c)
+                       case int32:
+                               vals[valI] = int32(c)
+                       case int64:
+                               vals[valI] = int64(c)
+                       default:
+                               panic("impossible")
+                       }
+               case []byte:
+                       switch prev.(type) {
+                       case []byte:
+                               vals[valI] = c
+                       case string:
+                               vals[valI] = string(c)
+                       default:
+                               panic("impossible")
+                       }
+               default:
+                       panic("impossible")
+               }
+               *count++
+               err := ws.fuzzFn(CorpusEntry{Values: vals})
+               if err != nil {
+                       retErr = err
+                       if keepCoverage != nil {
+                               // Now that we've found a crash, that's more important than any
+                               // minimization of interesting inputs that was being done. Clear out
+                               // keepCoverage to only minimize the crash going forward.
+                               keepCoverage = nil
+                       }
+                       return true
+               }
+               if keepCoverage != nil && hasCoverageBit(keepCoverage, coverageSnapshot) {
+                       return true
+               }
+               vals[valI] = prev
+               return false
+       }
+
+       for valI = range vals {
+               if shouldStop() {
+                       break
+               }
+               switch v := vals[valI].(type) {
+               case bool:
+                       continue // can't minimize
+               case float32:
+                       minimizeFloat(float64(v), tryMinimized, shouldStop)
+               case float64:
+                       minimizeFloat(v, tryMinimized, shouldStop)
+               case uint:
+                       minimizeInteger(v, tryMinimized, shouldStop)
+               case uint8:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case uint16:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case uint32:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case uint64:
+                       if uint64(uint(v)) != v {
+                               // Skip minimizing a uint64 on 32 bit platforms, since we'll truncate the
+                               // value when casting
+                               continue
+                       }
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case int:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case int8:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case int16:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case int32:
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case int64:
+                       if int64(int(v)) != v {
+                               // Skip minimizing a int64 on 32 bit platforms, since we'll truncate the
+                               // value when casting
+                               continue
+                       }
+                       minimizeInteger(uint(v), tryMinimized, shouldStop)
+               case string:
+                       minimizeBytes([]byte(v), tryMinimized, shouldStop)
+               case []byte:
+                       minimizeBytes(v, tryMinimized, shouldStop)
+               default:
+                       panic("unreachable")
+               }
+       }
+       return true, retErr
+}
+
+func writeToMem(vals []interface{}, mem *sharedMem) {
+       b := marshalCorpusFile(vals...)
+       mem.setValue(b)
+}
+
+// ping does nothing. The coordinator calls this method to ensure the worker
+// has called F.Fuzz and can communicate.
+func (ws *workerServer) ping(ctx context.Context, args pingArgs) pingResponse {
+       return pingResponse{}
+}
+
+// workerClient is a minimalist RPC client. The coordinator process uses a
+// workerClient to call methods in each worker process (handled by
+// workerServer).
+type workerClient struct {
+       workerComm
+       mu sync.Mutex
+       m  *mutator
+}
+
+func newWorkerClient(comm workerComm, m *mutator) *workerClient {
+       return &workerClient{workerComm: comm, m: m}
+}
+
+// Close shuts down the connection to the RPC server (the worker process) by
+// closing fuzz_in. Close drains fuzz_out (avoiding a SIGPIPE in the worker),
+// and closes it after the worker process closes the other end.
+func (wc *workerClient) Close() error {
+       wc.mu.Lock()
+       defer wc.mu.Unlock()
+
+       // Close fuzzIn. This signals to the server that there are no more calls,
+       // and it should exit.
+       if err := wc.fuzzIn.Close(); err != nil {
+               wc.fuzzOut.Close()
+               return err
+       }
+
+       // Drain fuzzOut and close it. When the server exits, the kernel will close
+       // its end of fuzzOut, and we'll get EOF.
+       if _, err := io.Copy(ioutil.Discard, wc.fuzzOut); err != nil {
+               wc.fuzzOut.Close()
+               return err
+       }
+       return wc.fuzzOut.Close()
+}
+
+// errSharedMemClosed is returned by workerClient methods that cannot access
+// shared memory because it was closed and unmapped by another goroutine. That
+// can happen when worker.cleanup is called in the worker goroutine while a
+// workerClient.fuzz call runs concurrently.
+//
+// This error should not be reported. It indicates the operation was
+// interrupted.
+var errSharedMemClosed = errors.New("internal error: shared memory was closed and unmapped")
+
+// minimize tells the worker to call the minimize method. See
+// workerServer.minimize.
+func (wc *workerClient) minimize(ctx context.Context, entryIn CorpusEntry, args minimizeArgs) (entryOut CorpusEntry, resp minimizeResponse, err error) {
+       wc.mu.Lock()
+       defer wc.mu.Unlock()
+
+       mem, ok := <-wc.memMu
+       if !ok {
+               return CorpusEntry{}, minimizeResponse{}, errSharedMemClosed
+       }
+       mem.header().count = 0
+       inp, err := CorpusEntryData(entryIn)
+       if err != nil {
+               return CorpusEntry{}, minimizeResponse{}, err
+       }
+       mem.setValue(inp)
+       wc.memMu <- mem
+
+       c := call{Minimize: &args}
+       callErr := wc.callLocked(ctx, c, &resp)
+       mem, ok = <-wc.memMu
+       if !ok {
+               return CorpusEntry{}, minimizeResponse{}, errSharedMemClosed
+       }
+       defer func() { wc.memMu <- mem }()
+       resp.Count = mem.header().count
+       if resp.WroteToMem {
+               entryOut.Data = mem.valueCopy()
+               entryOut.Values, err = unmarshalCorpusFile(entryOut.Data)
+               h := sha256.Sum256(entryOut.Data)
+               name := fmt.Sprintf("%x", h[:4])
+               entryOut.Path = name
+               entryOut.Parent = entryIn.Parent
+               entryOut.Generation = entryIn.Generation
+               if err != nil {
+                       return CorpusEntry{}, minimizeResponse{}, fmt.Errorf("workerClient.minimize unmarshaling minimized value: %v", err)
+               }
+       } else {
+               // Did not minimize, but the original input may still be interesting,
+               // for example, if there was an error.
+               entryOut = entryIn
+       }
+
+       return entryOut, resp, callErr
+}
+
+// fuzz tells the worker to call the fuzz method. See workerServer.fuzz.
+func (wc *workerClient) fuzz(ctx context.Context, entryIn CorpusEntry, args fuzzArgs) (entryOut CorpusEntry, resp fuzzResponse, isInternalError bool, err error) {
+       wc.mu.Lock()
+       defer wc.mu.Unlock()
+
+       mem, ok := <-wc.memMu
+       if !ok {
+               return CorpusEntry{}, fuzzResponse{}, true, errSharedMemClosed
+       }
+       mem.header().count = 0
+       inp, err := CorpusEntryData(entryIn)
+       if err != nil {
+               return CorpusEntry{}, fuzzResponse{}, true, err
+       }
+       mem.setValue(inp)
+       wc.memMu <- mem
+
+       c := call{Fuzz: &args}
+       callErr := wc.callLocked(ctx, c, &resp)
+       if resp.InternalErr != "" {
+               return CorpusEntry{}, fuzzResponse{}, true, errors.New(resp.InternalErr)
+       }
+       mem, ok = <-wc.memMu
+       if !ok {
+               return CorpusEntry{}, fuzzResponse{}, true, errSharedMemClosed
+       }
+       defer func() { wc.memMu <- mem }()
+       resp.Count = mem.header().count
+
+       if !bytes.Equal(inp, mem.valueRef()) {
+               return CorpusEntry{}, fuzzResponse{}, true, errors.New("workerServer.fuzz modified input")
+       }
+       needEntryOut := callErr != nil || resp.Err != "" ||
+               (!args.Warmup && resp.CoverageData != nil)
+       if needEntryOut {
+               valuesOut, err := unmarshalCorpusFile(inp)
+               if err != nil {
+                       return CorpusEntry{}, fuzzResponse{}, true, fmt.Errorf("unmarshaling fuzz input value after call: %v", err)
+               }
+               wc.m.r.restore(mem.header().randState, mem.header().randInc)
+               if !args.Warmup {
+                       // Only mutate the valuesOut if fuzzing actually occurred.
+                       for i := int64(0); i < resp.Count; i++ {
+                               wc.m.mutate(valuesOut, cap(mem.valueRef()))
+                       }
+               }
+               dataOut := marshalCorpusFile(valuesOut...)
+
+               h := sha256.Sum256(dataOut)
+               name := fmt.Sprintf("%x", h[:4])
+               entryOut = CorpusEntry{
+                       Parent:     entryIn.Path,
+                       Path:       name,
+                       Data:       dataOut,
+                       Generation: entryIn.Generation + 1,
+               }
+               if args.Warmup {
+                       // The bytes weren't mutated, so if entryIn was a seed corpus value,
+                       // then entryOut is too.
+                       entryOut.IsSeed = entryIn.IsSeed
+               }
+       }
+
+       return entryOut, resp, false, callErr
+}
+
+// ping tells the worker to call the ping method. See workerServer.ping.
+func (wc *workerClient) ping(ctx context.Context) error {
+       wc.mu.Lock()
+       defer wc.mu.Unlock()
+       c := call{Ping: &pingArgs{}}
+       var resp pingResponse
+       return wc.callLocked(ctx, c, &resp)
+}
+
+// callLocked sends an RPC from the coordinator to the worker process and waits
+// for the response. The callLocked may be cancelled with ctx.
+func (wc *workerClient) callLocked(ctx context.Context, c call, resp interface{}) (err error) {
+       enc := json.NewEncoder(wc.fuzzIn)
+       dec := json.NewDecoder(&contextReader{ctx: ctx, r: wc.fuzzOut})
+       if err := enc.Encode(c); err != nil {
+               return err
+       }
+       return dec.Decode(resp)
+}
+
+// contextReader wraps a Reader with a Context. If the context is cancelled
+// while the underlying reader is blocked, Read returns immediately.
+//
+// This is useful for reading from a pipe. Closing a pipe file descriptor does
+// not unblock pending Reads on that file descriptor. All copies of the pipe's
+// other file descriptor (the write end) must be closed in all processes that
+// inherit it. This is difficult to do correctly in the situation we care about
+// (process group termination).
+type contextReader struct {
+       ctx context.Context
+       r   io.Reader
+}
+
+func (cr *contextReader) Read(b []byte) (int, error) {
+       if ctxErr := cr.ctx.Err(); ctxErr != nil {
+               return 0, ctxErr
+       }
+       done := make(chan struct{})
+
+       // This goroutine may stay blocked after Read returns because the underlying
+       // read is blocked.
+       var n int
+       var err error
+       go func() {
+               n, err = cr.r.Read(b)
+               close(done)
+       }()
+
+       select {
+       case <-cr.ctx.Done():
+               return 0, cr.ctx.Err()
+       case <-done:
+               return n, err
+       }
+}
diff --git a/src/internal/fuzz/worker_test.go b/src/internal/fuzz/worker_test.go
new file mode 100644 (file)
index 0000000..c6f83fd
--- /dev/null
@@ -0,0 +1,157 @@
+// Copyright 2021 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 fuzz
+
+import (
+       "context"
+       "flag"
+       "fmt"
+       "internal/race"
+       "io"
+       "os"
+       "os/signal"
+       "reflect"
+       "testing"
+)
+
+var benchmarkWorkerFlag = flag.Bool("benchmarkworker", false, "")
+
+func TestMain(m *testing.M) {
+       flag.Parse()
+       if *benchmarkWorkerFlag {
+               runBenchmarkWorker()
+               return
+       }
+       os.Exit(m.Run())
+}
+
+func BenchmarkWorkerFuzzOverhead(b *testing.B) {
+       if race.Enabled {
+               b.Skip("TODO(48504): fix and re-enable")
+       }
+       origEnv := os.Getenv("GODEBUG")
+       defer func() { os.Setenv("GODEBUG", origEnv) }()
+       os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv))
+
+       ws := &workerServer{
+               fuzzFn:     func(_ CorpusEntry) error { return nil },
+               workerComm: workerComm{memMu: make(chan *sharedMem, 1)},
+       }
+
+       mem, err := sharedMemTempFile(workerSharedMemSize)
+       if err != nil {
+               b.Fatalf("failed to create temporary shared memory file: %s", err)
+       }
+       defer func() {
+               if err := mem.Close(); err != nil {
+                       b.Error(err)
+               }
+       }()
+
+       initialVal := []interface{}{make([]byte, 32)}
+       encodedVals := marshalCorpusFile(initialVal...)
+       mem.setValue(encodedVals)
+
+       ws.memMu <- mem
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               ws.m = newMutator()
+               mem.setValue(encodedVals)
+               mem.header().count = 0
+
+               ws.fuzz(context.Background(), fuzzArgs{Limit: 1})
+       }
+}
+
+// BenchmarkWorkerPing acts as the coordinator and measures the time it takes
+// a worker to respond to N pings. This is a rough measure of our RPC latency.
+func BenchmarkWorkerPing(b *testing.B) {
+       if race.Enabled {
+               b.Skip("TODO(48504): fix and re-enable")
+       }
+       b.SetParallelism(1)
+       w := newWorkerForTest(b)
+       for i := 0; i < b.N; i++ {
+               if err := w.client.ping(context.Background()); err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
+// BenchmarkWorkerFuzz acts as the coordinator and measures the time it takes
+// a worker to mutate a given input and call a trivial fuzz function N times.
+func BenchmarkWorkerFuzz(b *testing.B) {
+       if race.Enabled {
+               b.Skip("TODO(48504): fix and re-enable")
+       }
+       b.SetParallelism(1)
+       w := newWorkerForTest(b)
+       entry := CorpusEntry{Values: []interface{}{[]byte(nil)}}
+       entry.Data = marshalCorpusFile(entry.Values...)
+       for i := int64(0); i < int64(b.N); {
+               args := fuzzArgs{
+                       Limit:   int64(b.N) - i,
+                       Timeout: workerFuzzDuration,
+               }
+               _, resp, _, err := w.client.fuzz(context.Background(), entry, args)
+               if err != nil {
+                       b.Fatal(err)
+               }
+               if resp.Err != "" {
+                       b.Fatal(resp.Err)
+               }
+               if resp.Count == 0 {
+                       b.Fatal("worker did not make progress")
+               }
+               i += resp.Count
+       }
+}
+
+// newWorkerForTest creates and starts a worker process for testing or
+// benchmarking. The worker process calls RunFuzzWorker, which responds to
+// RPC messages until it's stopped. The process is stopped and cleaned up
+// automatically when the test is done.
+func newWorkerForTest(tb testing.TB) *worker {
+       tb.Helper()
+       c, err := newCoordinator(CoordinateFuzzingOpts{
+               Types: []reflect.Type{reflect.TypeOf([]byte(nil))},
+               Log:   io.Discard,
+       })
+       if err != nil {
+               tb.Fatal(err)
+       }
+       dir := ""             // same as self
+       binPath := os.Args[0] // same as self
+       args := append(os.Args[1:], "-benchmarkworker")
+       env := os.Environ() // same as self
+       w, err := newWorker(c, dir, binPath, args, env)
+       if err != nil {
+               tb.Fatal(err)
+       }
+       tb.Cleanup(func() {
+               if err := w.cleanup(); err != nil {
+                       tb.Error(err)
+               }
+       })
+       if err := w.startAndPing(context.Background()); err != nil {
+               tb.Fatal(err)
+       }
+       tb.Cleanup(func() {
+               if err := w.stop(); err != nil {
+                       tb.Error(err)
+               }
+       })
+       return w
+}
+
+func runBenchmarkWorker() {
+       ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+       defer cancel()
+       fn := func(CorpusEntry) error { return nil }
+       if err := RunFuzzWorker(ctx, fn); err != nil && err != ctx.Err() {
+               panic(err)
+       }
+}
index af15518ad8bdc474d000e6ce93cf0124a60e9607..3c706e04ad0cc5a56bebe06408115c27e20c321e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
@@ -40,8 +39,7 @@ func main() {
                }
                var buf bytes.Buffer
                fmt.Fprintf(&buf, "// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.\n\n")
-               fmt.Fprintf(&buf, "//go:build %s\n", target)
-               fmt.Fprintf(&buf, "// +build %s\n\n", target) // must explicitly include target for bootstrapping purposes
+               fmt.Fprintf(&buf, "//go:build %s\n", target) // must explicitly include target for bootstrapping purposes
                fmt.Fprintf(&buf, "package goarch\n\n")
                fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target)
                for _, goarch := range goarches {
index 2395b8095149f49444fbeae7eb1551dcbc3ee7c8..4a9b0e67c454a7212c804269400f76a509aa3f2e 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build 386
-// +build 386
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index c301d279c17fa64a978f1fc5071d56cb50b9377f..7926392b77510ceade8475edd1978559e248679e 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build amd64
-// +build amd64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 4a5ff379995d096952bf99d752f97257d30c2498..6c03b8b060c1b4b7728e297bd46bf44a20737a52 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build arm
-// +build arm
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 1
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 840e280f94bd93c717773725a64a772a9a497924..ad342d79c96bb2feb1038cb1ff6588bf4bc48b81 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build arm64
-// +build arm64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 1
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index bdbe5faacf1535e6fe0c683fe39563fbfa881626..0f260030908ecad894c655cdac66113d593ff415 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build arm64be
-// +build arm64be
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 1
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 36be514a0b486df9f3a56bd26afc38bf5d097f4e..6092fee7516e3805f21eda7f2ad37cb093822203 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build armbe
-// +build armbe
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 1
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 9465cf5bf5de126e9fff0cc4a3a1e8b1c63cd499..21c67e1176838ece2818fb177b15970432361a95 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build loong64
-// +build loong64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 1
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index e1458c0485e3218aefd7d17a32f6e4a352c3e3a9..0db19746556adf77af6c6b938a7622c18217a8ce 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build mips
-// +build mips
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 1
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 7de345e32198aee8e1e507c8ec1dd95a6108c042..738806f0aef0afa8eee1011c0065a46fcfc55fef 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build mips64
-// +build mips64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 96b1c3c021c4737d586b507ae2facb8bc72df183..8de5beb88197290bc0afd54e19687cfd608523dc 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build mips64le
-// +build mips64le
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 1
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 91d1f3c4df88a0103eec56b4c276738d98ea6434..ea461bed70c26ceee2d68d65c57f23239ef80b24 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build mips64p32
-// +build mips64p32
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 1
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 18f2ef2347be5cc9cb1e6c55daabed4e93fd2da3..15473ce6c7a047fa0a4768cd9c2784c35f27e48f 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build mips64p32le
-// +build mips64p32le
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 1
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 4551de1a3259e1ebce7d809650bff4d4ccad86d8..4955142e876539c6b8d328a429347750c4c055f7 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build mipsle
-// +build mipsle
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 1
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index ffed58c2e514a4d5226e41c314a0dbec1509eed0..ec01763b3c3ca5cdd7c891e0ee148b5341760b0f 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build ppc
-// +build ppc
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 1
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index c369c741664faceef14ea207016b3151bb45188d..39be3925c8e919ac6f379dd44136b2a367261858 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build ppc64
-// +build ppc64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 1
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 1
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index de5bae2a810cea079eab7fd27228d41c79987a76..5f959e0e0245efbf5c0c6f1dbe58ac31dcbb04f8 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build ppc64le
-// +build ppc64le
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 1
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 1
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 07c9d81b397baa4e7072c84a0b2ba752a2eca9d8..8d81a14dd9beace1427502533023265c69675eaa 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build riscv
-// +build riscv
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 1
 const IsRiscv64 = 0
 const IsS390 = 0
index 24e6ef3fdf439161ff0ab628a5bcf90e0a2eecae..1df989c2a696ed0eedd8b4ddaa31e441bf55f90b 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build riscv64
-// +build riscv64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 1
 const IsS390 = 0
index 429206d653a6202eeb9c59a154efc5e21def8daa..56815b9f435567794cdc2dc5999772497719f944 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build s390
-// +build s390
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 1
index 0c5900521640de380c97a9e3511f87da1b42aed2..e61e9bd5938a8bb5b2c30ae761b1081611c09bc4 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build s390x
-// +build s390x
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 83a356e4c7a03bd6074cd8b7a28ffb4100143a63..ee5b746566ddd2d4fc7b717167933a5e19d5206f 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build sparc
-// +build sparc
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 7c9d40986ecb13a522a4ca2cc1b74f2fa89db585..519aaa10c13bb591f2a0e681e2856b3e0e7a54a4 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build sparc64
-// +build sparc64
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
index 5aac1dfc47975aacbeb3f9164b3213a89aeb6aad..25567a1b6481f6dbf2c864c527db3f53a5c83a03 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.
 
 //go:build wasm
-// +build wasm
 
 package goarch
 
@@ -14,8 +13,6 @@ const IsArm = 0
 const IsArmbe = 0
 const IsArm64 = 0
 const IsArm64be = 0
-const IsPpc64 = 0
-const IsPpc64le = 0
 const IsLoong64 = 0
 const IsMips = 0
 const IsMipsle = 0
@@ -24,6 +21,8 @@ const IsMips64le = 0
 const IsMips64p32 = 0
 const IsMips64p32le = 0
 const IsPpc = 0
+const IsPpc64 = 0
+const IsPpc64le = 0
 const IsRiscv = 0
 const IsRiscv64 = 0
 const IsS390 = 0
diff --git a/src/internal/godebug/godebug.go b/src/internal/godebug/godebug.go
new file mode 100644 (file)
index 0000000..ac434e5
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2021 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 godebug parses the GODEBUG environment variable.
+package godebug
+
+import "os"
+
+// Get returns the value for the provided GODEBUG key.
+func Get(key string) string {
+       return get(os.Getenv("GODEBUG"), key)
+}
+
+// get returns the value part of key=value in s (a GODEBUG value).
+func get(s, key string) string {
+       for i := 0; i < len(s)-len(key)-1; i++ {
+               if i > 0 && s[i-1] != ',' {
+                       continue
+               }
+               afterKey := s[i+len(key):]
+               if afterKey[0] != '=' || s[i:i+len(key)] != key {
+                       continue
+               }
+               val := afterKey[1:]
+               for i, b := range val {
+                       if b == ',' {
+                               return val[:i]
+                       }
+               }
+               return val
+       }
+       return ""
+}
diff --git a/src/internal/godebug/godebug_test.go b/src/internal/godebug/godebug_test.go
new file mode 100644 (file)
index 0000000..41b9117
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2021 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 godebug
+
+import "testing"
+
+func TestGet(t *testing.T) {
+       tests := []struct {
+               godebug string
+               key     string
+               want    string
+       }{
+               {"", "", ""},
+               {"", "foo", ""},
+               {"foo=bar", "foo", "bar"},
+               {"foo=bar,after=x", "foo", "bar"},
+               {"before=x,foo=bar,after=x", "foo", "bar"},
+               {"before=x,foo=bar", "foo", "bar"},
+               {",,,foo=bar,,,", "foo", "bar"},
+               {"foodecoy=wrong,foo=bar", "foo", "bar"},
+               {"foo=", "foo", ""},
+               {"foo", "foo", ""},
+               {",foo", "foo", ""},
+               {"foo=bar,baz", "loooooooong", ""},
+       }
+       for _, tt := range tests {
+               got := get(tt.godebug, tt.key)
+               if got != tt.want {
+                       t.Errorf("get(%q, %q) = %q; want %q", tt.godebug, tt.key, got, tt.want)
+               }
+       }
+}
diff --git a/src/internal/goexperiment/exp_pacerredesign_off.go b/src/internal/goexperiment/exp_pacerredesign_off.go
new file mode 100644 (file)
index 0000000..62e1831
--- /dev/null
@@ -0,0 +1,9 @@
+// Code generated by mkconsts.go. DO NOT EDIT.
+
+//go:build !goexperiment.pacerredesign
+// +build !goexperiment.pacerredesign
+
+package goexperiment
+
+const PacerRedesign = false
+const PacerRedesignInt = 0
diff --git a/src/internal/goexperiment/exp_pacerredesign_on.go b/src/internal/goexperiment/exp_pacerredesign_on.go
new file mode 100644 (file)
index 0000000..b22b031
--- /dev/null
@@ -0,0 +1,9 @@
+// Code generated by mkconsts.go. DO NOT EDIT.
+
+//go:build goexperiment.pacerredesign
+// +build goexperiment.pacerredesign
+
+package goexperiment
+
+const PacerRedesign = true
+const PacerRedesignInt = 1
index 0a61a0e5fc12adc1556cc38138bf14e2583b3cf9..3bf19222e1cb02f04f6b2d239735f169205f5dc5 100644 (file)
@@ -83,4 +83,10 @@ type Flags struct {
        // Requires wrappers (to do ABI translation), and reflect (so
        // reflection calls use registers).
        RegabiArgs bool
+
+       // PacerRedesign enables the new GC pacer in the runtime.
+       //
+       // Details regarding the new pacer may be found at
+       // https://golang.org/design/44167-gc-pacer-redesign
+       PacerRedesign bool
 }
index 1860cd700dfb278dd88c87dafd0385d1e2e922e7..1b62503fd007427fcfcc359edb4ebf900ce87fa2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
@@ -52,7 +51,6 @@ func main() {
                var buf bytes.Buffer
                fmt.Fprintf(&buf, "// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.\n\n")
                fmt.Fprintf(&buf, "//go:build %s\n", strings.Join(tags, " && "))
-               fmt.Fprintf(&buf, "// +build %s\n\n", strings.Join(tags, ","))
                fmt.Fprintf(&buf, "package goos\n\n")
                fmt.Fprintf(&buf, "const GOOS = `%s`\n\n", target)
                for _, goos := range gooses {
index 063e698b82c6db2229c5180fceeb3572be285f32..ff861550c4851ab7dbb33b9059ec14e88b744adf 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build aix
-// +build aix
 
 package goos
 
index e9e4864978226755dba341e4c9df890b939ac885..e8aaa1242842d15db905685340b820e047a6a149 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build android
-// +build android
 
 package goos
 
index 309d6a271729c18c7f7a117c545a2686279df6bc..decdd496425c7fb3c8424547d2f765fbc46c89e2 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build !ios && darwin
-// +build !ios,darwin
 
 package goos
 
index 4e8711b94c573dd87c54235d27d109cff164de27..2224baa2301831deaf4ac21f3fb4e9403be693c5 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build dragonfly
-// +build dragonfly
 
 package goos
 
index f312bd16081acbf7abc2053e42206e1f155deb37..3ee5bf998e21c3303edb6b789cf8908205010a5c 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build freebsd
-// +build freebsd
 
 package goos
 
index 0f0dd28b81b80b24863741d9c5dcaf86c7c1e39c..8a3d34304d8f7f8f4d848ceb0f0780f68a099bbf 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build hurd
-// +build hurd
 
 package goos
 
index 17e7c53a40334b29d7877a6f07b5e91c3a90831c..fc1b9a9e22fcc7eab192c68f0a6a38ec7d431c65 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build illumos
-// +build illumos
 
 package goos
 
index e4745ca41341753d8831079dbcd76795c40d9e73..746e769ef766a0cdb9864a2b3b05b21837136021 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build ios
-// +build ios
 
 package goos
 
index bd2417e9cea97f8d0a1c4f1f91b48d22955e2c39..6cf2a5d9e27133923e00735fea0cee949fc0e2d7 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build js
-// +build js
 
 package goos
 
index 476702f442adfdac096874983650c58a8ee7532e..cb9d6e8afaa90556587b7bb9fd1dd0acb85b9b76 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build !android && linux
-// +build !android,linux
 
 package goos
 
index 97b7564babd29d66ab84aa15c80e40357a518c15..8285928d3504716df16cdc89b1aa05d65a9f1dc8 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build netbsd
-// +build netbsd
 
 package goos
 
index 384a96480d69a8e10cb2def17ccfde1e2d18ed83..3f739a4a2f728c071ba30786423a6bafcbed08fe 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build openbsd
-// +build openbsd
 
 package goos
 
index fcc279a79ec52978150787f978baf38a8273a411..d4c1c651f7bf881b28b65e63d461fe4caee6e208 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build plan9
-// +build plan9
 
 package goos
 
index 3f366cf71018683fbfa8b3924d4558c24dbffeac..69e3285ab620465adadcc4c8c341b64ef40f199e 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build !illumos && solaris
-// +build !illumos,solaris
 
 package goos
 
index dfa55339d34cfe5db7ce68d8e83affa5055af7d2..16158be78b97e8f85e97754aff88fc02ab27f9d9 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build windows
-// +build windows
 
 package goos
 
index 714f24963a253f830d6f7b2df35ada18eafc92ad..fb6165c7a12ec8f4269c0e672933448a99ad9046 100644 (file)
@@ -1,7 +1,6 @@
 // Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
 
 //go:build zos
-// +build zos
 
 package goos
 
index 2338b78f3aa987a3e76c871c2eb3ca029d277f95..8c66cd13a81c2540cc9bae1a2a399d1eba6699ea 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gc
-// +build gc
 
 package goroot
 
index b1041da11d8b7c048b15c0758b6b334667bf950f..62841222a7efdbf9d24d8ed14801c162109760df 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build gccgo
-// +build gccgo
 
 package goroot
 
diff --git a/src/internal/intern/intern.go b/src/internal/intern/intern.go
new file mode 100644 (file)
index 0000000..666caa6
--- /dev/null
@@ -0,0 +1,178 @@
+// 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 intern lets you make smaller comparable values by boxing
+// a larger comparable value (such as a 16 byte string header) down
+// into a globally unique 8 byte pointer.
+//
+// The globally unique pointers are garbage collected with weak
+// references and finalizers. This package hides that.
+package intern
+
+import (
+       "internal/godebug"
+       "runtime"
+       "sync"
+       "unsafe"
+)
+
+// A Value pointer is the handle to an underlying comparable value.
+// See func Get for how Value pointers may be used.
+type Value struct {
+       _      [0]func() // prevent people from accidentally using value type as comparable
+       cmpVal interface{}
+       // resurrected is guarded by mu (for all instances of Value).
+       // It is set true whenever v is synthesized from a uintptr.
+       resurrected bool
+}
+
+// Get returns the comparable value passed to the Get func
+// that returned v.
+func (v *Value) Get() interface{} { return v.cmpVal }
+
+// key is a key in our global value map.
+// It contains type-specialized fields to avoid allocations
+// when converting common types to empty interfaces.
+type key struct {
+       s      string
+       cmpVal interface{}
+       // isString reports whether key contains a string.
+       // Without it, the zero value of key is ambiguous.
+       isString bool
+}
+
+// keyFor returns a key to use with cmpVal.
+func keyFor(cmpVal interface{}) key {
+       if s, ok := cmpVal.(string); ok {
+               return key{s: s, isString: true}
+       }
+       return key{cmpVal: cmpVal}
+}
+
+// Value returns a *Value built from k.
+func (k key) Value() *Value {
+       if k.isString {
+               return &Value{cmpVal: k.s}
+       }
+       return &Value{cmpVal: k.cmpVal}
+}
+
+var (
+       // mu guards valMap, a weakref map of *Value by underlying value.
+       // It also guards the resurrected field of all *Values.
+       mu      sync.Mutex
+       valMap  = map[key]uintptr{} // to uintptr(*Value)
+       valSafe = safeMap()         // non-nil in safe+leaky mode
+)
+
+// safeMap returns a non-nil map if we're in safe-but-leaky mode,
+// as controlled by GODEBUG=intern=leaky
+func safeMap() map[key]*Value {
+       if godebug.Get("intern") == "leaky" {
+               return map[key]*Value{}
+       }
+       return nil
+}
+
+// Get returns a pointer representing the comparable value cmpVal.
+//
+// The returned pointer will be the same for Get(v) and Get(v2)
+// if and only if v == v2, and can be used as a map key.
+func Get(cmpVal interface{}) *Value {
+       return get(keyFor(cmpVal))
+}
+
+// GetByString is identical to Get, except that it is specialized for strings.
+// This avoids an allocation from putting a string into an interface{}
+// to pass as an argument to Get.
+func GetByString(s string) *Value {
+       return get(key{s: s, isString: true})
+}
+
+// We play unsafe games that violate Go's rules (and assume a non-moving
+// collector). So we quiet Go here.
+// See the comment below Get for more implementation details.
+//go:nocheckptr
+func get(k key) *Value {
+       mu.Lock()
+       defer mu.Unlock()
+
+       var v *Value
+       if valSafe != nil {
+               v = valSafe[k]
+       } else if addr, ok := valMap[k]; ok {
+               v = (*Value)(unsafe.Pointer(addr))
+               v.resurrected = true
+       }
+       if v != nil {
+               return v
+       }
+       v = k.Value()
+       if valSafe != nil {
+               valSafe[k] = v
+       } else {
+               // SetFinalizer before uintptr conversion (theoretical concern;
+               // see https://github.com/go4org/intern/issues/13)
+               runtime.SetFinalizer(v, finalize)
+               valMap[k] = uintptr(unsafe.Pointer(v))
+       }
+       return v
+}
+
+func finalize(v *Value) {
+       mu.Lock()
+       defer mu.Unlock()
+       if v.resurrected {
+               // We lost the race. Somebody resurrected it while we
+               // were about to finalize it. Try again next round.
+               v.resurrected = false
+               runtime.SetFinalizer(v, finalize)
+               return
+       }
+       delete(valMap, keyFor(v.cmpVal))
+}
+
+// Interning is simple if you don't require that unused values be
+// garbage collectable. But we do require that; we don't want to be
+// DOS vector. We do this by using a uintptr to hide the pointer from
+// the garbage collector, and using a finalizer to eliminate the
+// pointer when no other code is using it.
+//
+// The obvious implementation of this is to use a
+// map[interface{}]uintptr-of-*interface{}, and set up a finalizer to
+// delete from the map. Unfortunately, this is racy. Because pointers
+// are being created in violation of Go's unsafety rules, it's
+// possible to create a pointer to a value concurrently with the GC
+// concluding that the value can be collected. There are other races
+// that break the equality invariant as well, but the use-after-free
+// will cause a runtime crash.
+//
+// To make this work, the finalizer needs to know that no references
+// have been unsafely created since the finalizer was set up. To do
+// this, values carry a "resurrected" sentinel, which gets set
+// whenever a pointer is unsafely created. If the finalizer encounters
+// the sentinel, it clears the sentinel and delays collection for one
+// additional GC cycle, by re-installing itself as finalizer. This
+// ensures that the unsafely created pointer is visible to the GC, and
+// will correctly prevent collection.
+//
+// This technique does mean that interned values that get reused take
+// at least 3 GC cycles to fully collect (1 to clear the sentinel, 1
+// to clean up the unsafe map, 1 to be actually deleted).
+//
+// @ianlancetaylor commented in
+// https://github.com/golang/go/issues/41303#issuecomment-717401656
+// that it is possible to implement weak references in terms of
+// finalizers without unsafe. Unfortunately, the approach he outlined
+// does not work here, for two reasons. First, there is no way to
+// construct a strong pointer out of a weak pointer; our map stores
+// weak pointers, but we must return strong pointers to callers.
+// Second, and more fundamentally, we must return not just _a_ strong
+// pointer to callers, but _the same_ strong pointer to callers. In
+// order to return _the same_ strong pointer to callers, we must track
+// it, which is exactly what we cannot do with strong pointers.
+//
+// See https://github.com/inetaf/netaddr/issues/53 for more
+// discussion, and https://github.com/go4org/intern/issues/2 for an
+// illustration of the subtleties at play.
diff --git a/src/internal/intern/intern_test.go b/src/internal/intern/intern_test.go
new file mode 100644 (file)
index 0000000..d1e409e
--- /dev/null
@@ -0,0 +1,199 @@
+// 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 intern
+
+import (
+       "fmt"
+       "runtime"
+       "testing"
+)
+
+func TestBasics(t *testing.T) {
+       clearMap()
+       foo := Get("foo")
+       bar := Get("bar")
+       empty := Get("")
+       nilEface := Get(nil)
+       i := Get(0x7777777)
+       foo2 := Get("foo")
+       bar2 := Get("bar")
+       empty2 := Get("")
+       nilEface2 := Get(nil)
+       i2 := Get(0x7777777)
+       foo3 := GetByString("foo")
+       empty3 := GetByString("")
+
+       if foo.Get() != foo2.Get() {
+               t.Error("foo/foo2 values differ")
+       }
+       if foo.Get() != foo3.Get() {
+               t.Error("foo/foo3 values differ")
+       }
+       if foo.Get() != "foo" {
+               t.Error("foo.Get not foo")
+       }
+       if foo != foo2 {
+               t.Error("foo/foo2 pointers differ")
+       }
+       if foo != foo3 {
+               t.Error("foo/foo3 pointers differ")
+       }
+
+       if bar.Get() != bar2.Get() {
+               t.Error("bar values differ")
+       }
+       if bar.Get() != "bar" {
+               t.Error("bar.Get not bar")
+       }
+       if bar != bar2 {
+               t.Error("bar pointers differ")
+       }
+
+       if i.Get() != i.Get() {
+               t.Error("i values differ")
+       }
+       if i.Get() != 0x7777777 {
+               t.Error("i.Get not 0x7777777")
+       }
+       if i != i2 {
+               t.Error("i pointers differ")
+       }
+
+       if empty.Get() != empty2.Get() {
+               t.Error("empty/empty2 values differ")
+       }
+       if empty.Get() != empty.Get() {
+               t.Error("empty/empty3 values differ")
+       }
+       if empty.Get() != "" {
+               t.Error("empty.Get not empty string")
+       }
+       if empty != empty2 {
+               t.Error("empty/empty2 pointers differ")
+       }
+       if empty != empty3 {
+               t.Error("empty/empty3 pointers differ")
+       }
+
+       if nilEface.Get() != nilEface2.Get() {
+               t.Error("nilEface values differ")
+       }
+       if nilEface.Get() != nil {
+               t.Error("nilEface.Get not nil")
+       }
+       if nilEface != nilEface2 {
+               t.Error("nilEface pointers differ")
+       }
+
+       if n := mapLen(); n != 5 {
+               t.Errorf("map len = %d; want 4", n)
+       }
+
+       wantEmpty(t)
+}
+
+func wantEmpty(t testing.TB) {
+       t.Helper()
+       const gcTries = 5000
+       for try := 0; try < gcTries; try++ {
+               runtime.GC()
+               n := mapLen()
+               if n == 0 {
+                       break
+               }
+               if try == gcTries-1 {
+                       t.Errorf("map len = %d after (%d GC tries); want 0, contents: %v", n, gcTries, mapKeys())
+               }
+       }
+}
+
+func TestStress(t *testing.T) {
+       iters := 10000
+       if testing.Short() {
+               iters = 1000
+       }
+       var sink []byte
+       for i := 0; i < iters; i++ {
+               _ = Get("foo")
+               sink = make([]byte, 1<<20)
+       }
+       _ = sink
+}
+
+func BenchmarkStress(b *testing.B) {
+       done := make(chan struct{})
+       defer close(done)
+       go func() {
+               for {
+                       select {
+                       case <-done:
+                               return
+                       default:
+                       }
+                       runtime.GC()
+               }
+       }()
+
+       clearMap()
+       v1 := Get("foo")
+       b.ReportAllocs()
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       v2 := Get("foo")
+                       if v1 != v2 {
+                               b.Fatal("wrong value")
+                       }
+                       // And also a key we don't retain:
+                       _ = Get("bar")
+               }
+       })
+       runtime.GC()
+       wantEmpty(b)
+}
+
+func mapLen() int {
+       mu.Lock()
+       defer mu.Unlock()
+       return len(valMap)
+}
+
+func mapKeys() (keys []string) {
+       mu.Lock()
+       defer mu.Unlock()
+       for k := range valMap {
+               keys = append(keys, fmt.Sprint(k))
+       }
+       return keys
+}
+
+func clearMap() {
+       mu.Lock()
+       defer mu.Unlock()
+       for k := range valMap {
+               delete(valMap, k)
+       }
+}
+
+var (
+       globalString = "not a constant"
+       sink         string
+)
+
+func TestGetByStringAllocs(t *testing.T) {
+       allocs := int(testing.AllocsPerRun(100, func() {
+               GetByString(globalString)
+       }))
+       if allocs != 0 {
+               t.Errorf("GetString allocated %d objects, want 0", allocs)
+       }
+}
+
+func BenchmarkGetByString(b *testing.B) {
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               v := GetByString(globalString)
+               sink = v.Get().(string)
+       }
+}
index 55c548824f8bdd428ccb32f2cc69edb4971b43a7..c17751973225211748bf406626268f0f08ec8126 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package poll
 
index c55f5f0df5057da6c96a0a68f3865217bfcaaae0..3679aa8c4c795b69df890dee58df38696af0b2b3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package poll
 
index bcc25dd666a7b292b16ecbf1e27e3b4aa9a98cf7..48e095254d38639c3f5c047cce701e901acb2643 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !linux
-// +build !linux
 
 package poll_test
 
index f59c1f6dfaba5341410d34518e263d137c7334ab..3fcafac0020e8491efe34575440d823c461fb826 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 // Export guts for testing on posix.
 // Since testing imports os and os imports internal/poll,
index 7bf0ddc792f642c163581289bbb16f20ffffb49a..0f42ef61a572be25bb0788c027a68122ed4f7458 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package poll
 
index cc609e48ad7af9f578a094bb6dc47a6da26e74bb..f503d7a336ffa02307c38cddc50801e746f21178 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || solaris
-// +build aix darwin solaris
 
 package poll
 
index 8db5b6650492eecc4aaad7aa891568662827cd85..accff5e0438955757eb0ba6a94651123fdfadda0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package poll
 
index 651a5ecd8b2d4f01e9774bedd92d16ea01314eb7..6f17019e73d8f2ab56dfac616d42e06237a6c55f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package poll
 
index 760e24802e3fbd625515d7fc7d556f960c336375..84bfcae633d9290448037512375e8b69b377199b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package poll
 
index b072af00ea569e528dacc5de244bccc20fc54ded..4a4dddfd2743cbebc3dec55ca4cd0ad1aa4585ef 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || windows || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd windows solaris
 
 package poll
 
index 487f3285ee9895438b16fdc84539de4fac7f0976..dc1e29c6b7861caa5a920da29a969d6283f0d25c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package poll
 
index 1dcf51d41946aa972671f10cbdec8c8847b45d46..0b7ef7a577fe9c7a2fc8dbb45ad3226268ee4a8b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package poll_test
 
index 3b17cd22b03b8f85d0f9b6eb250d3379d59b9cfa..85971a16cd3e6325b8c6f3f49e308c0b012432ac 100644 (file)
@@ -3,11 +3,11 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package poll
 
 import (
+       "internal/syscall/unix"
        "io"
        "sync/atomic"
        "syscall"
@@ -230,6 +230,60 @@ func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
        }
 }
 
+// ReadFromInet4 wraps the recvfrom network call for IPv4.
+func (fd *FD) ReadFromInet4(p []byte, from *syscall.SockaddrInet4) (int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
+               return 0, err
+       }
+       for {
+               n, err := unix.RecvfromInet4(fd.Sysfd, p, 0, from)
+               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 {
+                                       continue
+                               }
+                       }
+               }
+               err = fd.eofError(n, err)
+               return n, err
+       }
+}
+
+// ReadFromInet6 wraps the recvfrom network call for IPv6.
+func (fd *FD) ReadFromInet6(p []byte, from *syscall.SockaddrInet6) (int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
+               return 0, err
+       }
+       for {
+               n, err := unix.RecvfromInet6(fd.Sysfd, p, 0, from)
+               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 {
+                                       continue
+                               }
+                       }
+               }
+               err = fd.eofError(n, err)
+               return n, err
+       }
+}
+
 // ReadMsg wraps the recvmsg network call.
 func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) {
        if err := fd.readLock(); err != nil {
@@ -257,6 +311,60 @@ func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.S
        }
 }
 
+// ReadMsgInet4 is ReadMsg, but specialized for syscall.SockaddrInet4.
+func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.SockaddrInet4) (int, int, int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, 0, 0, err
+       }
+       defer fd.readUnlock()
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
+               return 0, 0, 0, err
+       }
+       for {
+               n, oobn, sysflags, err := unix.RecvmsgInet4(fd.Sysfd, p, oob, flags, sa4)
+               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 {
+                                       continue
+                               }
+                       }
+               }
+               err = fd.eofError(n, err)
+               return n, oobn, sysflags, err
+       }
+}
+
+// ReadMsgInet6 is ReadMsg, but specialized for syscall.SockaddrInet6.
+func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.SockaddrInet6) (int, int, int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, 0, 0, err
+       }
+       defer fd.readUnlock()
+       if err := fd.pd.prepareRead(fd.isFile); err != nil {
+               return 0, 0, 0, err
+       }
+       for {
+               n, oobn, sysflags, err := unix.RecvmsgInet6(fd.Sysfd, p, oob, flags, sa6)
+               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 {
+                                       continue
+                               }
+                       }
+               }
+               err = fd.eofError(n, err)
+               return n, oobn, sysflags, err
+       }
+}
+
 // Write implements io.Writer.
 func (fd *FD) Write(p []byte) (int, error) {
        if err := fd.writeLock(); err != nil {
@@ -327,6 +435,58 @@ func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
        }
 }
 
+// WriteToInet4 wraps the sendto network call for IPv4 addresses.
+func (fd *FD) WriteToInet4(p []byte, sa *syscall.SockaddrInet4) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+       if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+               return 0, err
+       }
+       for {
+               err := unix.SendtoInet4(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
+                       }
+               }
+               if err != nil {
+                       return 0, err
+               }
+               return len(p), nil
+       }
+}
+
+// WriteToInet6 wraps the sendto network call for IPv6 addresses.
+func (fd *FD) WriteToInet6(p []byte, sa *syscall.SockaddrInet6) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+       if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+               return 0, err
+       }
+       for {
+               err := unix.SendtoInet6(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
+                       }
+               }
+               if err != nil {
+                       return 0, err
+               }
+               return len(p), nil
+       }
+}
+
 // WriteTo wraps the sendto network call.
 func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
        if err := fd.writeLock(); err != nil {
@@ -379,6 +539,58 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err
        }
 }
 
+// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4.
+func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (int, int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, 0, err
+       }
+       defer fd.writeUnlock()
+       if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+               return 0, 0, err
+       }
+       for {
+               n, err := unix.SendmsgNInet4(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
+                       }
+               }
+               if err != nil {
+                       return n, 0, err
+               }
+               return n, len(oob), err
+       }
+}
+
+// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6.
+func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (int, int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, 0, err
+       }
+       defer fd.writeUnlock()
+       if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+               return 0, 0, err
+       }
+       for {
+               n, err := unix.SendmsgNInet6(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
+                       }
+               }
+               if err != nil {
+                       return n, 0, err
+               }
+               return n, len(oob), err
+       }
+}
+
 // Accept wraps the accept network call.
 func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
        if err := fd.readLock(); err != nil {
index 4a5169527c42b0592d13e6c75df3fc9773647347..0d8bf879921d2bcab93894bc8898a359373455c1 100644 (file)
@@ -593,6 +593,64 @@ func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
        return n, sa, nil
 }
 
+// ReadFrom wraps the recvfrom network call for IPv4.
+func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) {
+       if len(buf) == 0 {
+               return 0, nil
+       }
+       if len(buf) > maxRW {
+               buf = buf[:maxRW]
+       }
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+       o := &fd.rop
+       o.InitBuf(buf)
+       n, err := execIO(o, func(o *operation) error {
+               if o.rsa == nil {
+                       o.rsa = new(syscall.RawSockaddrAny)
+               }
+               o.rsan = int32(unsafe.Sizeof(*o.rsa))
+               return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err != nil {
+               return n, err
+       }
+       rawToSockaddrInet4(o.rsa, sa4)
+       return n, err
+}
+
+// ReadFrom wraps the recvfrom network call for IPv6.
+func (fd *FD) ReadFromInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) {
+       if len(buf) == 0 {
+               return 0, nil
+       }
+       if len(buf) > maxRW {
+               buf = buf[:maxRW]
+       }
+       if err := fd.readLock(); err != nil {
+               return 0, err
+       }
+       defer fd.readUnlock()
+       o := &fd.rop
+       o.InitBuf(buf)
+       n, err := execIO(o, func(o *operation) error {
+               if o.rsa == nil {
+                       o.rsa = new(syscall.RawSockaddrAny)
+               }
+               o.rsan = int32(unsafe.Sizeof(*o.rsa))
+               return syscall.WSARecvFrom(o.fd.Sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err != nil {
+               return n, err
+       }
+       rawToSockaddrInet6(o.rsa, sa6)
+       return n, err
+}
+
 // Write implements io.Writer.
 func (fd *FD) Write(buf []byte) (int, error) {
        if err := fd.writeLock(); err != nil {
@@ -791,6 +849,80 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
        return ntotal, nil
 }
 
+// WriteToInet4 is WriteTo, specialized for syscall.SockaddrInet4.
+func (fd *FD) WriteToInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+
+       if len(buf) == 0 {
+               // handle zero-byte payload
+               o := &fd.wop
+               o.InitBuf(buf)
+               n, err := execIO(o, func(o *operation) error {
+                       return windows.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa4, &o.o, nil)
+               })
+               return n, err
+       }
+
+       ntotal := 0
+       for len(buf) > 0 {
+               b := buf
+               if len(b) > maxRW {
+                       b = b[:maxRW]
+               }
+               o := &fd.wop
+               o.InitBuf(b)
+               n, err := execIO(o, func(o *operation) error {
+                       return windows.WSASendtoInet4(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa4, &o.o, nil)
+               })
+               ntotal += int(n)
+               if err != nil {
+                       return ntotal, err
+               }
+               buf = buf[n:]
+       }
+       return ntotal, nil
+}
+
+// WriteToInet6 is WriteTo, specialized for syscall.SockaddrInet6.
+func (fd *FD) WriteToInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error) {
+       if err := fd.writeLock(); err != nil {
+               return 0, err
+       }
+       defer fd.writeUnlock()
+
+       if len(buf) == 0 {
+               // handle zero-byte payload
+               o := &fd.wop
+               o.InitBuf(buf)
+               n, err := execIO(o, func(o *operation) error {
+                       return windows.WSASendtoInet6(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa6, &o.o, nil)
+               })
+               return n, err
+       }
+
+       ntotal := 0
+       for len(buf) > 0 {
+               b := buf
+               if len(b) > maxRW {
+                       b = b[:maxRW]
+               }
+               o := &fd.wop
+               o.InitBuf(b)
+               n, err := execIO(o, func(o *operation) error {
+                       return windows.WSASendtoInet6(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, sa6, &o.o, nil)
+               })
+               ntotal += int(n)
+               if err != nil {
+                       return ntotal, err
+               }
+               buf = buf[n:]
+       }
+       return ntotal, nil
+}
+
 // Call ConnectEx. This doesn't need any locking, since it is only
 // called when the descriptor is first created. This is here rather
 // than in the net package so that it can use fd.wop.
@@ -984,31 +1116,54 @@ func (fd *FD) RawWrite(f func(uintptr) bool) error {
        return syscall.EWINDOWS
 }
 
-func sockaddrToRaw(sa syscall.Sockaddr) (unsafe.Pointer, int32, error) {
+func sockaddrInet4ToRaw(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet4) int32 {
+       *rsa = syscall.RawSockaddrAny{}
+       raw := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
+       raw.Family = syscall.AF_INET
+       p := (*[2]byte)(unsafe.Pointer(&raw.Port))
+       p[0] = byte(sa.Port >> 8)
+       p[1] = byte(sa.Port)
+       raw.Addr = sa.Addr
+       return int32(unsafe.Sizeof(*raw))
+}
+
+func sockaddrInet6ToRaw(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet6) int32 {
+       *rsa = syscall.RawSockaddrAny{}
+       raw := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
+       raw.Family = syscall.AF_INET6
+       p := (*[2]byte)(unsafe.Pointer(&raw.Port))
+       p[0] = byte(sa.Port >> 8)
+       p[1] = byte(sa.Port)
+       raw.Scope_id = sa.ZoneId
+       raw.Addr = sa.Addr
+       return int32(unsafe.Sizeof(*raw))
+}
+
+func rawToSockaddrInet4(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet4) {
+       pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
+       p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+       sa.Port = int(p[0])<<8 + int(p[1])
+       sa.Addr = pp.Addr
+}
+
+func rawToSockaddrInet6(rsa *syscall.RawSockaddrAny, sa *syscall.SockaddrInet6) {
+       pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
+       p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+       sa.Port = int(p[0])<<8 + int(p[1])
+       sa.ZoneId = pp.Scope_id
+       sa.Addr = pp.Addr
+}
+
+func sockaddrToRaw(rsa *syscall.RawSockaddrAny, sa syscall.Sockaddr) (int32, error) {
        switch sa := sa.(type) {
        case *syscall.SockaddrInet4:
-               var raw syscall.RawSockaddrInet4
-               raw.Family = syscall.AF_INET
-               p := (*[2]byte)(unsafe.Pointer(&raw.Port))
-               p[0] = byte(sa.Port >> 8)
-               p[1] = byte(sa.Port)
-               for i := 0; i < len(sa.Addr); i++ {
-                       raw.Addr[i] = sa.Addr[i]
-               }
-               return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)), nil
+               sz := sockaddrInet4ToRaw(rsa, sa)
+               return sz, nil
        case *syscall.SockaddrInet6:
-               var raw syscall.RawSockaddrInet6
-               raw.Family = syscall.AF_INET6
-               p := (*[2]byte)(unsafe.Pointer(&raw.Port))
-               p[0] = byte(sa.Port >> 8)
-               p[1] = byte(sa.Port)
-               raw.Scope_id = sa.ZoneId
-               for i := 0; i < len(sa.Addr); i++ {
-                       raw.Addr[i] = sa.Addr[i]
-               }
-               return unsafe.Pointer(&raw), int32(unsafe.Sizeof(raw)), nil
+               sz := sockaddrInet6ToRaw(rsa, sa)
+               return sz, nil
        default:
-               return nil, 0, syscall.EWINDOWS
+               return 0, syscall.EWINDOWS
        }
 }
 
@@ -1025,7 +1180,9 @@ func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.S
 
        o := &fd.rop
        o.InitMsg(p, oob)
-       o.rsa = new(syscall.RawSockaddrAny)
+       if o.rsa == nil {
+               o.rsa = new(syscall.RawSockaddrAny)
+       }
        o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
        o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa))
        o.msg.Flags = uint32(flags)
@@ -1040,6 +1197,64 @@ func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.S
        return n, int(o.msg.Control.Len), int(o.msg.Flags), sa, err
 }
 
+// ReadMsgInet4 is ReadMsg, but specialized to return a syscall.SockaddrInet4.
+func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.SockaddrInet4) (int, int, int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, 0, 0, err
+       }
+       defer fd.readUnlock()
+
+       if len(p) > maxRW {
+               p = p[:maxRW]
+       }
+
+       o := &fd.rop
+       o.InitMsg(p, oob)
+       if o.rsa == nil {
+               o.rsa = new(syscall.RawSockaddrAny)
+       }
+       o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
+       o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa))
+       o.msg.Flags = uint32(flags)
+       n, err := execIO(o, func(o *operation) error {
+               return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err == nil {
+               rawToSockaddrInet4(o.rsa, sa4)
+       }
+       return n, int(o.msg.Control.Len), int(o.msg.Flags), err
+}
+
+// ReadMsgInet6 is ReadMsg, but specialized to return a syscall.SockaddrInet6.
+func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.SockaddrInet6) (int, int, int, error) {
+       if err := fd.readLock(); err != nil {
+               return 0, 0, 0, err
+       }
+       defer fd.readUnlock()
+
+       if len(p) > maxRW {
+               p = p[:maxRW]
+       }
+
+       o := &fd.rop
+       o.InitMsg(p, oob)
+       if o.rsa == nil {
+               o.rsa = new(syscall.RawSockaddrAny)
+       }
+       o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
+       o.msg.Namelen = int32(unsafe.Sizeof(*o.rsa))
+       o.msg.Flags = uint32(flags)
+       n, err := execIO(o, func(o *operation) error {
+               return windows.WSARecvMsg(o.fd.Sysfd, &o.msg, &o.qty, &o.o, nil)
+       })
+       err = fd.eofError(n, err)
+       if err == nil {
+               rawToSockaddrInet6(o.rsa, sa6)
+       }
+       return n, int(o.msg.Control.Len), int(o.msg.Flags), err
+}
+
 // WriteMsg wraps the WSASendMsg network call.
 func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
        if len(p) > maxRW {
@@ -1054,11 +1269,14 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err
        o := &fd.wop
        o.InitMsg(p, oob)
        if sa != nil {
-               rsa, len, err := sockaddrToRaw(sa)
+               if o.rsa == nil {
+                       o.rsa = new(syscall.RawSockaddrAny)
+               }
+               len, err := sockaddrToRaw(o.rsa, sa)
                if err != nil {
                        return 0, 0, err
                }
-               o.msg.Name = (syscall.Pointer)(rsa)
+               o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
                o.msg.Namelen = len
        }
        n, err := execIO(o, func(o *operation) error {
@@ -1066,3 +1284,53 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err
        })
        return n, int(o.msg.Control.Len), err
 }
+
+// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4.
+func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (int, int, error) {
+       if len(p) > maxRW {
+               return 0, 0, errors.New("packet is too large (only 1GB is allowed)")
+       }
+
+       if err := fd.writeLock(); err != nil {
+               return 0, 0, err
+       }
+       defer fd.writeUnlock()
+
+       o := &fd.wop
+       o.InitMsg(p, oob)
+       if o.rsa == nil {
+               o.rsa = new(syscall.RawSockaddrAny)
+       }
+       len := sockaddrInet4ToRaw(o.rsa, sa)
+       o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
+       o.msg.Namelen = len
+       n, err := execIO(o, func(o *operation) error {
+               return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil)
+       })
+       return n, int(o.msg.Control.Len), err
+}
+
+// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6.
+func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (int, int, error) {
+       if len(p) > maxRW {
+               return 0, 0, errors.New("packet is too large (only 1GB is allowed)")
+       }
+
+       if err := fd.writeLock(); err != nil {
+               return 0, 0, err
+       }
+       defer fd.writeUnlock()
+
+       o := &fd.wop
+       o.InitMsg(p, oob)
+       if o.rsa == nil {
+               o.rsa = new(syscall.RawSockaddrAny)
+       }
+       len := sockaddrInet6ToRaw(o.rsa, sa)
+       o.msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
+       o.msg.Namelen = len
+       n, err := execIO(o, func(o *operation) error {
+               return windows.WSASendMsg(o.fd.Sysfd, &o.msg, 0, &o.qty, &o.o, nil)
+       })
+       return n, int(o.msg.Control.Len), err
+}
index 805fa2ccd9ae79e706e15569aca5018c86d89385..8137510c8b44719e7e283dd4c90350d55bab88a6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin
-// +build darwin
 
 package poll
 
index a0b11ed5ae972c5337660291b52bf52c04177cdb..79190c2f6398a69da014eddb3aa3cb177a609ed5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 package poll
 
index 87f284a56a1b21d72c24b361287bb2c84c6313c7..aa96d104c89bf1f3125e7c984f10e611ca9b01b5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package poll
 
index d519f602c1e9850d23898c7924b881bb6793e660..c941cb52357938bb7aeac8d263dc307ea5b84a32 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build dragonfly freebsd illumos linux netbsd openbsd
 
 package poll
 
index c88d65cdc83de5ff8567065a08a24084d637d0bf..c9aa4b4ca23a484d23ae7740929fb0dab6e1c8b4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package poll
 
index f4058b298f35c5ae73ba5c3ff56fa920abcda1bc..00a65d7995b9b3954c92b1bfb5d86a643f82b34c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 package poll
 
index 6fd5d86630b6aa45a2c6ebfb4e4d34984c8fa583..c1500840ac243e09290fff84e770e9c3a58939af 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd linux netbsd openbsd
 
 package poll
 
index 3ba30a2154cd545c8616138ba6998a52359f00bb..89315a8c67352e988a5b5b6197f2cd1cafe3dacd 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build dragonfly || freebsd
-// +build dragonfly freebsd
+//go:build darwin || dragonfly || freebsd
 
 package poll
 
index b3038290b9216853c227fad6c0acc93079d81fad..d849fda0b06f87584c16b82d3333025f3e1f1d57 100644 (file)
@@ -6,7 +6,6 @@
 // setting SetNonblock and CloseOnExec.
 
 //go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build dragonfly freebsd illumos linux netbsd openbsd
 
 package poll
 
index 4f2e2fb455dc9bc23842b6368243b3b6a88aee36..2d354700c5d3a6862ac563dfba0a03ae5bdbee55 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package poll
 
index 4fb9600deedff1b9d8161b0e32551e4bdc2255e2..54be1cc4b6bed0ee244e4893dac259ceb541f4b5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package poll
 
index d86c4c1f81ad4c4ca7528b80dd1e56527af4db31..7fc9aeefb3b1d00a9584910a60cff01037e3db41 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package poll
 
index 8062d98fae945ccf214dc095ed8165e83dd556ad..2d87c3d023b14eb381e8a811f452f2f2632c091a 100644 (file)
@@ -154,12 +154,20 @@ func splice(out int, in int, max int, flags int) (int, error) {
        return int(n), err
 }
 
-type splicePipe struct {
+type splicePipeFields struct {
        rfd  int
        wfd  int
        data int
 }
 
+type splicePipe struct {
+       splicePipeFields
+
+       // We want to use a finalizer, so ensure that the size is
+       // large enough to not use the tiny allocator.
+       _ [24 - unsafe.Sizeof(splicePipeFields{})%24]byte
+}
+
 // splicePipePool caches pipes to avoid high-frequency construction and destruction of pipe buffers.
 // The garbage collector will free all pipes in the sync.Pool periodically, thus we need to set up
 // a finalizer for each pipe to close its file descriptors before the actual GC.
@@ -218,7 +226,7 @@ func newPipe() (sp *splicePipe) {
                return nil
        }
 
-       sp = &splicePipe{rfd: fds[0], wfd: fds[1]}
+       sp = &splicePipe{splicePipeFields: splicePipeFields{rfd: fds[0], wfd: fds[1]}}
 
        if p == nil {
                p = new(bool)
index 280468c7e748d85ec957e7a36eac0a8149440f0d..8c4363886e7e3f015d2e323041f3e2557448a538 100644 (file)
@@ -6,40 +6,48 @@ package poll_test
 
 import (
        "internal/poll"
-       "internal/syscall/unix"
        "runtime"
-       "syscall"
+       "sync"
+       "sync/atomic"
        "testing"
        "time"
 )
 
-// checkPipes returns true if all pipes are closed properly, false otherwise.
-func checkPipes(fds []int) bool {
-       for _, fd := range fds {
-               // Check if each pipe fd has been closed.
-               _, _, errno := syscall.Syscall(unix.FcntlSyscall, uintptr(fd), syscall.F_GETPIPE_SZ, 0)
-               if errno == 0 {
-                       return false
+var closeHook atomic.Value // func(fd int)
+
+func init() {
+       closeFunc := poll.CloseFunc
+       poll.CloseFunc = func(fd int) (err error) {
+               if v := closeHook.Load(); v != nil {
+                       if hook := v.(func(int)); hook != nil {
+                               hook(fd)
+                       }
                }
+               return closeFunc(fd)
        }
-       return true
 }
 
 func TestSplicePipePool(t *testing.T) {
        const N = 64
        var (
-               p   *poll.SplicePipe
-               ps  []*poll.SplicePipe
-               fds []int
-               err error
+               p          *poll.SplicePipe
+               ps         []*poll.SplicePipe
+               allFDs     []int
+               pendingFDs sync.Map // fd → struct{}{}
+               err        error
        )
+
+       closeHook.Store(func(fd int) { pendingFDs.Delete(fd) })
+       t.Cleanup(func() { closeHook.Store((func(int))(nil)) })
+
        for i := 0; i < N; i++ {
                p, _, err = poll.GetPipe()
                if err != nil {
-                       t.Skip("failed to create pipe, skip this test")
+                       t.Skipf("failed to create pipe due to error(%v), skip this test", err)
                }
                _, pwfd := poll.GetPipeFds(p)
-               fds = append(fds, pwfd)
+               allFDs = append(allFDs, pwfd)
+               pendingFDs.Store(pwfd, struct{}{})
                ps = append(ps, p)
        }
        for _, p = range ps {
@@ -62,12 +70,21 @@ func TestSplicePipePool(t *testing.T) {
        for {
                runtime.GC()
                time.Sleep(10 * time.Millisecond)
-               if checkPipes(fds) {
+
+               // Detect whether all pipes are closed properly.
+               var leakedFDs []int
+               pendingFDs.Range(func(k, v interface{}) bool {
+                       leakedFDs = append(leakedFDs, k.(int))
+                       return true
+               })
+               if len(leakedFDs) == 0 {
                        break
                }
+
                select {
                case <-expiredTime.C:
-                       t.Fatal("at least one pipe is still open")
+                       t.Logf("all descriptors: %v", allFDs)
+                       t.Fatalf("leaked descriptors: %v", leakedFDs)
                default:
                }
        }
index c98332d3dac63713b4093e31dbcf477a9c3b7266..2b052fa1747f3a4eb0a5cec5f4d7eadd5ec6721e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package poll
 
index 7e6d422d621cda8bf433e593d3e22f19a0f89d47..312ed24a44bc203645c0c05965719901c30514d9 100644 (file)
@@ -6,7 +6,6 @@
 // setting SetNonblock and CloseOnExec.
 
 //go:build aix || darwin || (js && wasm) || (solaris && !illumos)
-// +build aix darwin js,wasm solaris,!illumos
 
 package poll
 
index 824de7569e8a2cc96b7c430f52fceb17ab71ad21..cd600b63d7d61e8d97fa1a72328bd120d4cc6cf3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd illumos linux netbsd openbsd
 
 package poll
 
index d69f8deee7cb6aa677fdd36cdd8d0412419ca400..377a43d5858f08e066e59947d979a4994bc4e2d0 100644 (file)
@@ -750,11 +750,11 @@ func parseCppContention(r *bytes.Buffer) (*Profile, error) {
                        break
                }
 
-               attr := strings.SplitN(l, delimiter, 2)
-               if len(attr) != 2 {
+               key, val, ok := strings.Cut(l, delimiter)
+               if !ok {
                        break
                }
-               key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
+               key, val = strings.TrimSpace(key), strings.TrimSpace(val)
                var err error
                switch key {
                case "cycles/second":
@@ -1050,8 +1050,8 @@ func (p *Profile) ParseMemoryMap(rd io.Reader) error {
                        if err == errUnrecognized {
                                // Recognize assignments of the form: attr=value, and replace
                                // $attr with value on subsequent mappings.
-                               if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
-                                       attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
+                               if attr, value, ok := strings.Cut(l, delimiter); ok {
+                                       attrs = append(attrs, "$"+strings.TrimSpace(attr), strings.TrimSpace(value))
                                        r = strings.NewReplacer(attrs...)
                                }
                                // Ignore any unrecognized entries
index a1e5dae09d8663dc5f32593ca45574beafc1d39e..966b0bd849920337c648c6a017251f70c3728255 100644 (file)
@@ -44,7 +44,7 @@ func valueToStringImpl(val reflect.Value) string {
                } else {
                        return "false"
                }
-       case reflect.Ptr:
+       case reflect.Pointer:
                v := val
                str = typ.String() + "("
                if v.IsNil() {
index b1899b0191f3f9b77648945112d84b05ebc63d5a..fdf1584a272d0703383faa31dfd289e59ddf7144 100644 (file)
@@ -100,13 +100,15 @@ const (
        Func
        Interface
        Map
-       Ptr
+       Pointer
        Slice
        String
        Struct
        UnsafePointer
 )
 
+const Ptr = Pointer
+
 // tflag is used by an rtype to signal what extra type information is
 // available in the memory directly following the rtype value.
 //
index 136273842ceecb27c787bf479a3e85b78348ed53..073406925518ad8e7e3bf525373e311f352b6ed3 100644 (file)
@@ -87,7 +87,7 @@ func (f flag) ro() flag {
 }
 
 // pointer returns the underlying pointer represented by v.
-// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
+// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer
 func (v Value) pointer() unsafe.Pointer {
        if v.typ.size != goarch.PtrSize || !v.typ.pointers() {
                panic("can't call pointer on a non-pointer Value")
@@ -220,7 +220,7 @@ func (v Value) CanSet() bool {
 
 // Elem returns the value that the interface v contains
 // or that the pointer v points to.
-// It panics if v's Kind is not Interface or Ptr.
+// It panics if v's Kind is not Interface or Pointer.
 // It returns the zero Value if v is nil.
 func (v Value) Elem() Value {
        k := v.kind()
@@ -239,7 +239,7 @@ func (v Value) Elem() Value {
                        x.flag |= v.flag.ro()
                }
                return x
-       case Ptr:
+       case Pointer:
                ptr := v.ptr
                if v.flag&flagIndir != 0 {
                        ptr = *(*unsafe.Pointer)(ptr)
@@ -288,7 +288,7 @@ func valueInterface(v Value) interface{} {
 func (v Value) IsNil() bool {
        k := v.kind()
        switch k {
-       case Chan, Func, Map, Ptr, UnsafePointer:
+       case Chan, Func, Map, Pointer, UnsafePointer:
                // if v.flag&flagMethod != 0 {
                //      return false
                // }
index 73289f1cd05a89201c8c0db3d0d62081db0c6d86..335647c63813cd87ee7ddbfce44eca25d70edd90 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows
-// +build !windows
 
 package execenv
 
index 6c0654943e690613175113c4a97abe1292927a0e..a8aa1a644eeffa27151ca8839c5e9b6773026b8d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package execenv
 
index 9b08864f7f580dae8697db57a9bdfc2221a7a0b2..447d48e198966bb24f47727a3a9def9b4ac896e7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux || openbsd || netbsd || dragonfly
-// +build linux openbsd netbsd dragonfly
 
 package unix
 
index 4cc351ea278d88b9fe605c64a11bc8924db810a2..f48d3791e370c83f2218007416f6be607a34c2dd 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || solaris
-// +build aix solaris
 
 package unix
 
index 050d401bc0ef6addcc53bb6477f73b0cc42c6172..445b0c38546ac089e976471771370679bfcf390d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm || mips || mipsle || 386
-// +build arm mips mipsle 386
 
 package unix
 
index e53a2d1b75fb996631cceaac9c1d46f4c2424778..73a3da5bff2112b7940caccbe1b939d4f98d96c5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 || riscv64
-// +build arm64 riscv64
 
 package unix
 
index 4cb4a5976ba7371c72ea374bda4b6cbe1394b736..76edf675227f9b40611a2e67ae6542ec3f3eaf4b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || mips64 || mips64le || ppc64 || ppc64le || s390x
-// +build amd64 mips64 mips64le ppc64 ppc64le s390x
 
 package unix
 
index 46a4f6b030d46d929f7297f3097f9331bb0a77c5..7b39ee72bc494d9ac5c9bb2e1b56bd4c5bb2adc4 100644 (file)
@@ -6,7 +6,6 @@
 // If you change the build tags here, see syscall/flock_linux_32bit.go.
 
 //go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle)
-// +build linux,386 linux,arm linux,mips linux,mipsle
 
 package unix
 
index e1a410a454144627108c7e449430b671b2689930..7bab1f27b0c89695debed55061e21f38c686c0bf 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build darwin && !ios
+
 package unix
 
 import (
index d2c58c0f6fa459ba03e0c2843a2be2f5a49225ec..a6659331e46d87c022ac76b84c3d31761556c6a1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux
-// +build dragonfly freebsd linux
 
 package unix
 
index 19d56c36a13156563115d5bbdf248a08ccbf1627..d361533b5c4a43bdf3789f7711077d74278560bd 100644 (file)
@@ -16,7 +16,7 @@ var libc_ioctl uintptr
 // Implemented in syscall/syscall_aix.go.
 func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
 
-func Ioctl(fd int, cmd int, args uintptr) (err error) {
+func Ioctl(fd int, cmd int, args unsafe.Pointer) (err error) {
        _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_ioctl)), 3, uintptr(fd), uintptr(cmd), uintptr(args), 0, 0, 0)
        if e1 != 0 {
                err = e1
diff --git a/src/internal/syscall/unix/net.go b/src/internal/syscall/unix/net.go
new file mode 100644 (file)
index 0000000..85632e1
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2021 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:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+
+package unix
+
+import (
+       "syscall"
+       _ "unsafe"
+)
+
+//go:linkname RecvfromInet4 syscall.recvfromInet4
+//go:noescape
+func RecvfromInet4(fd int, p []byte, flags int, from *syscall.SockaddrInet4) (int, error)
+
+//go:linkname RecvfromInet6 syscall.recvfromInet6
+//go:noescape
+func RecvfromInet6(fd int, p []byte, flags int, from *syscall.SockaddrInet6) (n int, err error)
+
+//go:linkname SendtoInet4 syscall.sendtoInet4
+//go:noescape
+func SendtoInet4(fd int, p []byte, flags int, to *syscall.SockaddrInet4) (err error)
+
+//go:linkname SendtoInet6 syscall.sendtoInet6
+//go:noescape
+func SendtoInet6(fd int, p []byte, flags int, to *syscall.SockaddrInet6) (err error)
+
+//go:linkname SendmsgNInet4 syscall.sendmsgNInet4
+//go:noescape
+func SendmsgNInet4(fd int, p, oob []byte, to *syscall.SockaddrInet4, flags int) (n int, err error)
+
+//go:linkname SendmsgNInet6 syscall.sendmsgNInet6
+//go:noescape
+func SendmsgNInet6(fd int, p, oob []byte, to *syscall.SockaddrInet6, flags int) (n int, err error)
+
+//go:linkname RecvmsgInet4 syscall.recvmsgInet4
+//go:noescape
+func RecvmsgInet4(fd int, p, oob []byte, flags int, from *syscall.SockaddrInet4) (n, oobn int, recvflags int, err error)
+
+//go:linkname RecvmsgInet6 syscall.recvmsgInet6
+//go:noescape
+func RecvmsgInet6(fd int, p, oob []byte, flags int, from *syscall.SockaddrInet6) (n, oobn int, recvflags int, err error)
diff --git a/src/internal/syscall/unix/net_js.go b/src/internal/syscall/unix/net_js.go
new file mode 100644 (file)
index 0000000..622fc8e
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2021 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:build js
+
+package unix
+
+import (
+       "syscall"
+       _ "unsafe"
+)
+
+func RecvfromInet4(fd int, p []byte, flags int, from *syscall.SockaddrInet4) (int, error) {
+       return 0, syscall.ENOSYS
+}
+
+func RecvfromInet6(fd int, p []byte, flags int, from *syscall.SockaddrInet6) (n int, err error) {
+       return 0, syscall.ENOSYS
+}
+
+func SendtoInet4(fd int, p []byte, flags int, to *syscall.SockaddrInet4) (err error) {
+       return syscall.ENOSYS
+}
+
+func SendtoInet6(fd int, p []byte, flags int, to *syscall.SockaddrInet6) (err error) {
+       return syscall.ENOSYS
+}
+
+func SendmsgNInet4(fd int, p, oob []byte, to *syscall.SockaddrInet4, flags int) (n int, err error) {
+       return 0, syscall.ENOSYS
+}
+
+func SendmsgNInet6(fd int, p, oob []byte, to *syscall.SockaddrInet6, flags int) (n int, err error) {
+       return 0, syscall.ENOSYS
+}
+
+func RecvmsgInet4(fd int, p, oob []byte, flags int, from *syscall.SockaddrInet4) (n, oobn int, recvflags int, err error) {
+       return 0, 0, 0, syscall.ENOSYS
+}
+
+func RecvmsgInet6(fd int, p, oob []byte, flags int, from *syscall.SockaddrInet6) (n, oobn int, recvflags int, err error) {
+       return 0, 0, 0, syscall.ENOSYS
+}
index a22986cb8a402bb8759b61214cab952ad6b69178..9e5f0fb4a2d57a7e2c9d78943fd604050726fd39 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package unix
 
index a5a5080d46153a9bed00ede4cfd324b177b11e4d..8ed40f3f9104adcd09159a2e73e949d763a5259c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package unix
 
index d9565efcb6af46261bf36921483013564ffe29b9..75c6e92a6e23ef64b1e07a6945aea7fe27865d1f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || solaris
-// +build aix darwin solaris
 
 package unix
 
index b0aac895808deb568c4def6d39f99a1e6615f4e7..c6280f85e585e6f3dd6b14849a17f78569d119a1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 package unix
 
index a76025454cad46c8df043d534cce411ed11e9cf9..3c5394a96b1c1201c816ff242ab839dc9d8c3f1b 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (arm64 || riscv64)
-// +build linux
-// +build arm64 riscv64
 
 package unix
 
index f353d4d73e48f606c6e04b6565ad8985941f55c6..bca526d2b905bf6c15d3bda2a51f4bd3b5bda243 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips64 || mips64le
-// +build mips64 mips64le
 
 package unix
 
index 4ed471532a2a415edb4bd26a1808557720d8f9a1..c86195e49698a5a636ee13872edc11fd4a4e79e9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips || mipsle
-// +build mips mipsle
 
 package unix
 
index b484ffef80b97b42c897517f5c7ef57c9817c71b..a4dcf2bc9d71f53e7ca423c70d4f3032734f0db0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package unix
 
index f60949f662b58a7710acf27540740d56b7d8a20c..ee31be1302e5321f630c6d8406cd51b784f15735 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 package unix
 
index 0db626636e95d1308cd6defb0937cb4a60b1da05..3311da5474164620b6fa65e00084f9c453df53c1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package windows_test
 
index 39f745db7a3d40bb38e386ae30d1b201ae9f06e3..81f08c627e6496ac38a316947a56d8893a4e5053 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build generate
-// +build generate
 
 package windows
 
diff --git a/src/internal/syscall/windows/net_windows.go b/src/internal/syscall/windows/net_windows.go
new file mode 100644 (file)
index 0000000..3d3df71
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2021 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 windows
+
+import (
+       "syscall"
+       _ "unsafe"
+)
+
+//go:linkname WSASendtoInet4 syscall.wsaSendtoInet4
+//go:noescape
+func WSASendtoInet4(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet4, overlapped *syscall.Overlapped, croutine *byte) (err error)
+
+//go:linkname WSASendtoInet6 syscall.wsaSendtoInet6
+//go:noescape
+func WSASendtoInet6(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet6, overlapped *syscall.Overlapped, croutine *byte) (err error)
index d02d93f287522f62ae766b7f7a11fbcdb34bf2bd..7f1ac70e8fa01cf1b18e36edda1afde3ce61ca6f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package registry
 
index ebe73a2e02468336a514ce1f5d95a89b6ae456ba..ec38cf9288a6f66e0848d1e61ee43c6f3b5a5dbb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 // Package registry provides access to the Windows registry.
 //
 //
 package registry
 
-import "syscall"
+import (
+       "runtime"
+       "syscall"
+)
 
 const (
        // Registry key security and access rights.
@@ -89,6 +91,12 @@ func OpenKey(k Key, path string, access uint32) (Key, error) {
 
 // ReadSubKeyNames returns the names of subkeys of key k.
 func (k Key) ReadSubKeyNames() ([]string, error) {
+       // RegEnumKeyEx must be called repeatedly and to completion.
+       // During this time, this goroutine cannot migrate away from
+       // its current thread. See #49320.
+       runtime.LockOSThread()
+       defer runtime.UnlockOSThread()
+
        names := make([]string, 0)
        // Registry key size limit is 255 bytes and described there:
        // https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx
index 0a007df7ccd08322d0650c1e0612a41b6e3d7b38..0e0b4210d58a0d25f3a093d28c0f7c2df1be08ad 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build generate
-// +build generate
 
 package registry
 
index 69b84e1c4c5f995f7804ac086f71c27708efb3ac..134b5450fcace93772723bcb7e561dfdd147ffb3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package registry_test
 
index bb612793613f571a1250a417a2773c1f782fff73..cb315adadedf728a3f356bbc09d6f31c0e242908 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package registry
 
index e1fc99c40d4cdd8cd57bf15ef667939720a277b2..025574015f69e8ac7bd901268a7330bc07d54a8d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package registry
 
index 61b998e4cfc3d164b8f224d7264ee68686396efb..e79fd19edc0ebb3a3907d4302575e17a550264b7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 // Package sysdll is an internal leaf package that records and reports
 // which Windows DLL names are used by Go itself. These DLLs are then
index 02f08f57c717c590bc370457b47534e11c07f0ab..7426a29c1a6efca44692bdfb313b23560cae64f6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo
-// +build cgo
 
 package testenv
 
index 846ec9385647efabf512f47b8b9361d6b2a8ae95..81171fd193ffbade5ca560ff9b8015f15a6147f2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows
-// +build !windows
 
 package testenv
 
index a18df9feff696510d54adc9f53d135d15f07b23e..f6d9fd575f9be8d822f03e46cb18cd36466ce53d 100644 (file)
@@ -160,6 +160,21 @@ func ExampleSectionReader() {
        // io.Reader stream
 }
 
+func ExampleSectionReader_Read() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       s := io.NewSectionReader(r, 5, 17)
+
+       buf := make([]byte, 9)
+       if _, err := s.Read(buf); err != nil {
+               log.Fatal(err)
+       }
+
+       fmt.Printf("%s\n", buf)
+
+       // Output:
+       // io.Reader
+}
+
 func ExampleSectionReader_ReadAt() {
        r := strings.NewReader("some io.Reader stream to be read\n")
        s := io.NewSectionReader(r, 5, 17)
@@ -191,6 +206,16 @@ func ExampleSectionReader_Seek() {
        // stream
 }
 
+func ExampleSectionReader_Size() {
+       r := strings.NewReader("some io.Reader stream to be read\n")
+       s := io.NewSectionReader(r, 5, 17)
+
+       fmt.Println(s.Size())
+
+       // Output:
+       // 17
+}
+
 func ExampleSeeker_Seek() {
        r := strings.NewReader("some io.Reader stream to be read\n")
 
index 2724321ed9d42012e2e0d3de78c673fd4a063fcc..5635392dfb888805fe385746fb91413ebdcca3b1 100644 (file)
@@ -47,7 +47,7 @@ var EOF = errors.New("EOF")
 // middle of reading a fixed-size block or data structure.
 var ErrUnexpectedEOF = errors.New("unexpected EOF")
 
-// ErrNoProgress is returned by some clients of an Reader when
+// ErrNoProgress is returned by some clients of a Reader when
 // many calls to Read have failed to return any data or error,
 // usually the sign of a broken Reader implementation.
 var ErrNoProgress = errors.New("multiple Read calls return no data or error")
@@ -113,11 +113,12 @@ type Closer interface {
 // SeekCurrent means relative to the current offset, and
 // SeekEnd means relative to the end.
 // Seek returns the new offset relative to the start of the
-// file and an error, if any.
+// file or an error, if any.
 //
 // Seeking to an offset before the start of the file is an error.
-// Seeking to any positive offset is legal, but the behavior of subsequent
-// I/O operations on the underlying object is implementation-dependent.
+// Seeking to any positive offset may be allowed, but if the new offset exceeds
+// the size of the underlying object the behavior of subsequent I/O operations
+// is implementation-dependent.
 type Seeker interface {
        Seek(offset int64, whence int) (int64, error)
 }
@@ -261,10 +262,11 @@ type ByteReader interface {
 // ByteScanner is the interface that adds the UnreadByte method to the
 // basic ReadByte method.
 //
-// UnreadByte causes the next call to ReadByte to return the same byte
-// as the previous call to ReadByte.
-// It may be an error to call UnreadByte twice without an intervening
-// call to ReadByte.
+// UnreadByte causes the next call to ReadByte to return the last byte read.
+// If the last operation was not a successful call to ReadByte, UnreadByte may
+// return an error, unread the last byte read (or the byte prior to the
+// last-unread byte), or (in implementations that support the Seeker interface)
+// seek to one byte before the current offset.
 type ByteScanner interface {
        ByteReader
        UnreadByte() error
@@ -277,7 +279,7 @@ type ByteWriter interface {
 
 // RuneReader is the interface that wraps the ReadRune method.
 //
-// ReadRune reads a single UTF-8 encoded Unicode character
+// ReadRune reads a single encoded Unicode character
 // and returns the rune and its size in bytes. If no character is
 // available, err will be set.
 type RuneReader interface {
@@ -287,10 +289,11 @@ type RuneReader interface {
 // RuneScanner is the interface that adds the UnreadRune method to the
 // basic ReadRune method.
 //
-// UnreadRune causes the next call to ReadRune to return the same rune
-// as the previous call to ReadRune.
-// It may be an error to call UnreadRune twice without an intervening
-// call to ReadRune.
+// UnreadRune causes the next call to ReadRune to return the last rune read.
+// If the last operation was not a successful call to ReadRune, UnreadRune may
+// return an error, unread the last rune read (or the rune prior to the
+// last-unread rune), or (in implementations that support the Seeker interface)
+// seek to the start of the rune before the current offset.
 type RuneScanner interface {
        RuneReader
        UnreadRune() error
@@ -478,7 +481,16 @@ func (l *LimitedReader) Read(p []byte) (n int, err error) {
 // NewSectionReader returns a SectionReader that reads from r
 // starting at offset off and stops with EOF after n bytes.
 func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
-       return &SectionReader{r, off, off, off + n}
+       var remaining int64
+       const maxint64 = 1<<63 - 1
+       if off <= maxint64-n {
+               remaining = n + off
+       } else {
+               // Overflow, with no way to return error.
+               // Assume we can read up to an offset of 1<<63 - 1.
+               remaining = maxint64
+       }
+       return &SectionReader{r, off, off, remaining}
 }
 
 // SectionReader implements Read, Seek, and ReadAt on a section
index 5b355e8c55b1692eb543cdc66cbed0593bb6efd4..308846048095652c8974517dbac250a6278a2b88 100644 (file)
@@ -430,6 +430,20 @@ func TestSectionReader_Size(t *testing.T) {
        }
 }
 
+func TestSectionReader_Max(t *testing.T) {
+       r := strings.NewReader("abcdef")
+       const maxint64 = 1<<63 - 1
+       sr := NewSectionReader(r, 3, maxint64)
+       n, err := sr.Read(make([]byte, 3))
+       if n != 3 || err != nil {
+               t.Errorf("Read = %v %v, want 3, nil", n, err)
+       }
+       n, err = sr.Read(make([]byte, 3))
+       if n != 0 || err != EOF {
+               t.Errorf("Read = %v, %v, want 0, EOF", n, err)
+       }
+}
+
 // largeWriter returns an invalid count that is larger than the number
 // of bytes provided (issue 39978).
 type largeWriter struct {
index 909b6d8be283920861f5fe0430d5c77c2ea15277..e877e54571c4a31d2cbeeb1c308d93f79b0b5a7e 100644 (file)
@@ -141,7 +141,7 @@ func testMultiWriter(t *testing.T, sink interface {
        }
 }
 
-// writerFunc is an Writer implemented by the underlying func.
+// writerFunc is a Writer implemented by the underlying func.
 type writerFunc func(p []byte) (int, error)
 
 func (f writerFunc) Write(p []byte) (int, error) {
@@ -216,7 +216,7 @@ func TestMultiWriterCopy(t *testing.T) {
        }
 }
 
-// readerFunc is an Reader implemented by the underlying func.
+// readerFunc is a Reader implemented by the underlying func.
 type readerFunc func(p []byte) (int, error)
 
 func (f readerFunc) Read(p []byte) (int, error) {
index b5343bb6b73b50d4a75d86d7c1ece87abd38d4ed..2724e3f7abe4fddba4800b2ac7185ec66e031e0c 100644 (file)
@@ -47,7 +47,7 @@ type pipe struct {
        werr onceError
 }
 
-func (p *pipe) Read(b []byte) (n int, err error) {
+func (p *pipe) read(b []byte) (n int, err error) {
        select {
        case <-p.done:
                return 0, p.readCloseError()
@@ -64,15 +64,7 @@ func (p *pipe) Read(b []byte) (n int, err error) {
        }
 }
 
-func (p *pipe) readCloseError() error {
-       rerr := p.rerr.Load()
-       if werr := p.werr.Load(); rerr == nil && werr != nil {
-               return werr
-       }
-       return ErrClosedPipe
-}
-
-func (p *pipe) CloseRead(err error) error {
+func (p *pipe) closeRead(err error) error {
        if err == nil {
                err = ErrClosedPipe
        }
@@ -81,7 +73,7 @@ func (p *pipe) CloseRead(err error) error {
        return nil
 }
 
-func (p *pipe) Write(b []byte) (n int, err error) {
+func (p *pipe) write(b []byte) (n int, err error) {
        select {
        case <-p.done:
                return 0, p.writeCloseError()
@@ -103,15 +95,7 @@ func (p *pipe) Write(b []byte) (n int, err error) {
        return n, nil
 }
 
-func (p *pipe) writeCloseError() error {
-       werr := p.werr.Load()
-       if rerr := p.rerr.Load(); werr == nil && rerr != nil {
-               return rerr
-       }
-       return ErrClosedPipe
-}
-
-func (p *pipe) CloseWrite(err error) error {
+func (p *pipe) closeWrite(err error) error {
        if err == nil {
                err = EOF
        }
@@ -120,6 +104,24 @@ func (p *pipe) CloseWrite(err error) error {
        return nil
 }
 
+// readCloseError is considered internal to the pipe type.
+func (p *pipe) readCloseError() error {
+       rerr := p.rerr.Load()
+       if werr := p.werr.Load(); rerr == nil && werr != nil {
+               return werr
+       }
+       return ErrClosedPipe
+}
+
+// writeCloseError is considered internal to the pipe type.
+func (p *pipe) writeCloseError() error {
+       werr := p.werr.Load()
+       if rerr := p.rerr.Load(); werr == nil && rerr != nil {
+               return rerr
+       }
+       return ErrClosedPipe
+}
+
 // A PipeReader is the read half of a pipe.
 type PipeReader struct {
        p *pipe
@@ -131,7 +133,7 @@ type PipeReader struct {
 // If the write end is closed with an error, that error is
 // returned as err; otherwise err is EOF.
 func (r *PipeReader) Read(data []byte) (n int, err error) {
-       return r.p.Read(data)
+       return r.p.read(data)
 }
 
 // Close closes the reader; subsequent writes to the
@@ -146,7 +148,7 @@ func (r *PipeReader) Close() error {
 // CloseWithError never overwrites the previous error if it exists
 // and always returns nil.
 func (r *PipeReader) CloseWithError(err error) error {
-       return r.p.CloseRead(err)
+       return r.p.closeRead(err)
 }
 
 // A PipeWriter is the write half of a pipe.
@@ -160,7 +162,7 @@ type PipeWriter struct {
 // If the read end is closed with an error, that err is
 // returned as err; otherwise err is ErrClosedPipe.
 func (w *PipeWriter) Write(data []byte) (n int, err error) {
-       return w.p.Write(data)
+       return w.p.write(data)
 }
 
 // Close closes the writer; subsequent reads from the
@@ -176,7 +178,7 @@ func (w *PipeWriter) Close() error {
 // CloseWithError never overwrites the previous error if it exists
 // and always returns nil.
 func (w *PipeWriter) CloseWithError(err error) error {
-       return w.p.CloseWrite(err)
+       return w.p.closeWrite(err)
 }
 
 // Pipe creates a synchronous in-memory pipe.
index b77af29032927b8f36a94c55d718dfa41bf328fb..3172384718880af249bc62e7bd4bc7d5c7a94a2f 100644 (file)
@@ -20,6 +20,7 @@ import (
        "os"
        "runtime"
        "sync"
+       "sync/atomic"
        "time"
 )
 
@@ -50,11 +51,12 @@ const (
 // the Writer's Write method. A Logger can be used simultaneously from
 // multiple goroutines; it guarantees to serialize access to the Writer.
 type Logger struct {
-       mu     sync.Mutex // ensures atomic writes; protects the following fields
-       prefix string     // prefix on each line to identify the logger (but see Lmsgprefix)
-       flag   int        // properties
-       out    io.Writer  // destination for output
-       buf    []byte     // for accumulating text to write
+       mu        sync.Mutex // ensures atomic writes; protects the following fields
+       prefix    string     // prefix on each line to identify the logger (but see Lmsgprefix)
+       flag      int        // properties
+       out       io.Writer  // destination for output
+       buf       []byte     // for accumulating text to write
+       isDiscard int32      // atomic boolean: whether out == io.Discard
 }
 
 // New creates a new Logger. The out variable sets the
@@ -63,7 +65,11 @@ type Logger struct {
 // after the log header if the Lmsgprefix flag is provided.
 // The flag argument defines the logging properties.
 func New(out io.Writer, prefix string, flag int) *Logger {
-       return &Logger{out: out, prefix: prefix, flag: flag}
+       l := &Logger{out: out, prefix: prefix, flag: flag}
+       if out == io.Discard {
+               l.isDiscard = 1
+       }
+       return l
 }
 
 // SetOutput sets the output destination for the logger.
@@ -71,6 +77,11 @@ func (l *Logger) SetOutput(w io.Writer) {
        l.mu.Lock()
        defer l.mu.Unlock()
        l.out = w
+       isDiscard := int32(0)
+       if w == io.Discard {
+               isDiscard = 1
+       }
+       atomic.StoreInt32(&l.isDiscard, isDiscard)
 }
 
 var std = New(os.Stderr, "", LstdFlags)
@@ -188,16 +199,29 @@ func (l *Logger) Output(calldepth int, s string) error {
 // Printf calls l.Output to print to the logger.
 // Arguments are handled in the manner of fmt.Printf.
 func (l *Logger) Printf(format string, v ...interface{}) {
+       if atomic.LoadInt32(&l.isDiscard) != 0 {
+               return
+       }
        l.Output(2, fmt.Sprintf(format, v...))
 }
 
 // Print calls l.Output to print to the logger.
 // Arguments are handled in the manner of fmt.Print.
-func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
+func (l *Logger) Print(v ...interface{}) {
+       if atomic.LoadInt32(&l.isDiscard) != 0 {
+               return
+       }
+       l.Output(2, fmt.Sprint(v...))
+}
 
 // Println calls l.Output to print to the logger.
 // Arguments are handled in the manner of fmt.Println.
-func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
+func (l *Logger) Println(v ...interface{}) {
+       if atomic.LoadInt32(&l.isDiscard) != 0 {
+               return
+       }
+       l.Output(2, fmt.Sprintln(v...))
+}
 
 // Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
 func (l *Logger) Fatal(v ...interface{}) {
@@ -277,9 +301,7 @@ func (l *Logger) Writer() io.Writer {
 
 // SetOutput sets the output destination for the standard logger.
 func SetOutput(w io.Writer) {
-       std.mu.Lock()
-       defer std.mu.Unlock()
-       std.out = w
+       std.SetOutput(w)
 }
 
 // Flags returns the output flags for the standard logger.
@@ -314,18 +336,27 @@ func Writer() io.Writer {
 // Print calls Output to print to the standard logger.
 // Arguments are handled in the manner of fmt.Print.
 func Print(v ...interface{}) {
+       if atomic.LoadInt32(&std.isDiscard) != 0 {
+               return
+       }
        std.Output(2, fmt.Sprint(v...))
 }
 
 // Printf calls Output to print to the standard logger.
 // Arguments are handled in the manner of fmt.Printf.
 func Printf(format string, v ...interface{}) {
+       if atomic.LoadInt32(&std.isDiscard) != 0 {
+               return
+       }
        std.Output(2, fmt.Sprintf(format, v...))
 }
 
 // Println calls Output to print to the standard logger.
 // Arguments are handled in the manner of fmt.Println.
 func Println(v ...interface{}) {
+       if atomic.LoadInt32(&std.isDiscard) != 0 {
+               return
+       }
        std.Output(2, fmt.Sprintln(v...))
 }
 
index 5be8e822586f5bc83d88cb7b50a2d4809ecaef78..938ed423578cb8a8c9d646cd226aff87e7829df8 100644 (file)
@@ -9,6 +9,7 @@ package log
 import (
        "bytes"
        "fmt"
+       "io"
        "os"
        "regexp"
        "strings"
@@ -20,7 +21,7 @@ const (
        Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
        Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
        Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
-       Rline         = `(60|62):` // must update if the calls to l.Printf / l.Print below move
+       Rline         = `(61|63):` // must update if the calls to l.Printf / l.Print below move
        Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
        Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
 )
@@ -179,6 +180,17 @@ func TestEmptyPrintCreatesLine(t *testing.T) {
        }
 }
 
+func TestDiscard(t *testing.T) {
+       l := New(io.Discard, "", 0)
+       s := strings.Repeat("a", 102400)
+       c := testing.AllocsPerRun(100, func() { l.Printf("%s", s) })
+       // One allocation for slice passed to Printf,
+       // but none for formatting of long string.
+       if c > 1 {
+               t.Errorf("got %v allocs, want at most 1", c)
+       }
+}
+
 func BenchmarkItoa(b *testing.B) {
        dst := make([]byte, 0, 64)
        for i := 0; i < b.N; i++ {
index 993976569e2423b1e9649cb5151486eb289e6ce4..4df29c0af0bfe22643ecf6ab72eb59a3f99079c0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9
-// +build !windows,!plan9
 
 package syslog_test
 
index 6abd4ad124863d014de91a3a1e2037a121b65f32..8c6ba72135298c64c7e4b12c271328066cf5f163 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9
-// +build !windows,!plan9
 
 package syslog
 
index 62c62508452a06dcbf10905f9aa09035f52dfe02..26530480ee90e3a42755b4abe5843932ccc5fead 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9 && !js
-// +build !windows,!plan9,!js
 
 package syslog
 
index 2e45f0764fd9e430a652e2daf84d5b22b76467dc..f9cdcdc273493d6834776fcd2330d472721ea6f6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9
-// +build !windows,!plan9
 
 package syslog
 
index 7986125a06ffc652016aef3252a24f6337379ea9..3310692a18c4a542d0601e887937b9adf34c5cc0 100755 (executable)
@@ -152,12 +152,17 @@ if [ "$1" = "-v" ]; then
        shift
 fi
 
+goroot_bootstrap_set=${GOROOT_BOOTSTRAP+"true"}
 export GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
 export GOROOT="$(cd .. && pwd)"
 IFS=$'\n'; for go_exe in $(type -ap go); do
        if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then
                goroot=$(GOROOT='' GOOS='' GOARCH='' "$go_exe" env GOROOT)
                if [ "$goroot" != "$GOROOT" ]; then
+                       if [ "$goroot_bootstrap_set" = "true" ]; then
+                               printf 'WARNING: %s does not exist, found %s from env\n' "$GOROOT_BOOTSTRAP/bin/go" "$go_exe" >&2
+                               printf 'WARNING: set %s as GOROOT_BOOTSTRAP\n' "$goroot" >&2
+                       fi
                        GOROOT_BOOTSTRAP=$goroot
                fi
        fi
index 7bdc7dea1c1eefde25478f71b970b2466512b41c..ba8c5db2d9fe7c375ae8ed58d3ae67fde2e00ddc 100755 (executable)
@@ -51,13 +51,20 @@ GOENV=off
 GOFLAGS=()
 GO111MODULE=()
 GOROOT = `{cd .. && pwd}
-if(! ~ $#GOROOT_BOOTSTRAP 1)
+goroot_bootstrap_set = 'true'
+if(! ~ $#GOROOT_BOOTSTRAP 1){
+       goroot_bootstrap_set = 'false'
        GOROOT_BOOTSTRAP = $home/go1.4
+}
 for(p in $path){
        if(! test -x $GOROOT_BOOTSTRAP/bin/go){
                if(go_exe = `{path=$p whatis go}){
                        goroot = `{GOROOT='' $go_exe env GOROOT}
                        if(! ~ $goroot $GOROOT){
+                               if(~ $goroot_bootstrap_set 'true'){
+                                       echo 'WARNING: '$GOROOT_BOOTSTRAP'/bin/go does not exist, found '$go_exe' from env' >[1=2]
+                                       echo 'WARNING: set '$goroot' as GOROOT_BOOTSTRAP' >[1=2]
+                               }
                                GOROOT_BOOTSTRAP = $goroot
                        }
                }
index 59be952200f3c40d1ce684f2a5bfaa79e49614f8..5c72a27d8d8e5d82700d6a0219feb5604ac30cda 100644 (file)
@@ -379,7 +379,7 @@ E5: CMPQ BX, R11            // i < n
 
 // func addMulVVW(z, x []Word, y Word) (c Word)
 TEXT ·addMulVVW(SB),NOSPLIT,$0
-       CMPB    ·support_adx(SB), $1
+       CMPB ·support_adx(SB), $1
        JEQ adx
        MOVQ z+0(FP), R10
        MOVQ x+24(FP), R8
index 42050e2c39d76e2c703730ac8883b0dd2f31f715..a8c91a6e547c268371b1093ae0d57c5af2fa47a3 100644 (file)
@@ -304,7 +304,9 @@ func (z *Float) setExpAndRound(exp int64, sbit uint) {
 // SetMantExp sets z to mant × 2**exp and returns z.
 // The result z has the same precision and rounding mode
 // as mant. SetMantExp is an inverse of MantExp but does
-// not require 0.5 <= |mant| < 1.0. Specifically:
+// not require 0.5 <= |mant| < 1.0. Specifically, for a
+// given x of type *Float, SetMantExp relates to MantExp
+// as follows:
 //
 //     mant := new(Float)
 //     new(Float).SetMantExp(mant, x.MantExp(mant)).Cmp(x) == 0
index 78b42316de59d998eea787f476a40a7a2976365d..e794cf281abe6d24764d50390d80c5d9ad1f82f5 100644 (file)
@@ -6,7 +6,6 @@
 // accurate for huge arguments.
 
 //go:build !s390x
-// +build !s390x
 
 package cmplx
 
index 9ba742a407a27bf52419af92ad6f1f63f27d669f..f4adbd0ae5e11cdea85a685efbed2aea0c9ce5fe 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64 || riscv64 || s390x
-// +build amd64 arm64 riscv64 s390x
 
 package math
 
index ea46577d8ded7f2a78c62d4a687138562eb87051..5b9e06fed33d03ad6745ed9fcd0c2601129e8d66 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !arm64 && !riscv64 && !s390x
-// +build !amd64,!arm64,!riscv64,!s390x
 
 package math
 
index 9fc196796796c9ac1c1406a53242741fc207284d..a26d8cbe97d8b463cbcb1ea6e57197545a253dbc 100644 (file)
@@ -162,6 +162,11 @@ func ExampleLog10() {
        // Output: 2.0
 }
 
+func ExampleRemainder() {
+       fmt.Printf("%.1f", math.Remainder(100, 30))
+       // Output: 10.0
+}
+
 func ExampleMod() {
        c := math.Mod(7, 4)
        fmt.Printf("%.1f", c)
index 76d258f125264446c956dcf037ca34627025c54b..c26b2c3fab67c743e00d7539f9e0e188214ba18e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64
-// +build arm64
 
 package math
 
index 1b0ac87ebf0ed49f159a628e586a69fbe75f49bb..c2b409329f1e1f18deec411388e6a961ed4e2beb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !arm64
-// +build !arm64
 
 package math
 
index 654ccce48103508d82d091a1e9e32fa1060a9a24..0f701b1d6d8da1fa4bf3c8e14c3c45bb348df9d2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64
-// +build amd64
 
 package math
 
index a1673ea1ddbdace0d34cdef8e5ebfa9b35dd410e..424442845bb07e2645c28df400253e4de9fa4de9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64 || s390x
-// +build amd64 arm64 s390x
 
 package math
 
index b757e6e23033c7455d88cf128609be4446e2bb3b..bd3f02412a28a2ab2cb98d71e88e7b11d5deaa43 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !arm64 && !s390x
-// +build !amd64,!arm64,!s390x
 
 package math
 
index 1265e5171e9b747c096d11cc2c609154d18e02ae..fb419d6da2f6bfc98fcf8d12a82b39dc987f86d0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64 || arm64 || ppc64 || ppc64le || s390x || wasm
-// +build 386 amd64 arm64 ppc64 ppc64le s390x wasm
 
 package math
 
index 821af2102007c00539707000bd312ff45b9bac30..5641c7ea0a49caf563cf496e2be234612dd0d2c8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386 && !amd64 && !arm64 && !ppc64 && !ppc64le && !s390x && !wasm
-// +build !386,!amd64,!arm64,!ppc64,!ppc64le,!s390x,!wasm
 
 package math
 
index ec81a4a31da396fe4e9000f996a2dfe9aa6f1624..bc28c6ff693a55855ecee6fc124b224f8a057026 100644 (file)
@@ -6,7 +6,6 @@
 // accurate for huge arguments.
 
 //go:build !s390x
-// +build !s390x
 
 package math_test
 
index 9435af41cf8a9a76474bcb6befe5931e3b309c71..852691037f6f4bc4a8e848d17bebc682181073eb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64
-// +build 386 amd64
 
 package math
 
index bc41b136e56e27857e9fd3ad551e2c1b70aafd1c..8b64812a1c197e048839bf23858ff4bafbd3aaa7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386 && !amd64
-// +build !386,!amd64
 
 package math
 
index 4d3b7ee065a6cec1e0cd73b6f2cb111315b85391..848cce13b289b52e37c8f08e9c3d6d0c149831d7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || s390x
-// +build amd64 s390x
 
 package math
 
index e1697164364e096f30bd7d4af52955ab162fabe0..d35992bf37ab69227a4afe49a21cef7e37d0fc30 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !amd64 && !s390x
-// +build !amd64,!s390x
 
 package math
 
index ce431a9d8d41a901c89d4ee4995e3f6d596dbc22..c63be6cf361a5f4c6adfbfcbfdd9ee9a74f81965 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64 || ppc64 || ppc64le
-// +build arm64 ppc64 ppc64le
 
 package math
 
index 9607a0894b25a16549a262d365b8408ff992b472..55c6a7f6e20693d98502bbe70df51748806f586d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !arm64 && !ppc64 && !ppc64le
-// +build !arm64,!ppc64,!ppc64le
 
 package math
 
index 7950e09fd7c3f2b7a99a1e093b831c2d154e96ce..782bb6671d2e933943980d7faa8fc1e4487cb21a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // This program computes the value of rngCooked in rng.go,
 // which is used for seeding all instances of rand.Source.
index 73701f24f12fd813d590714df09e705a4a3283aa..d684968a3a87e684c80d166369fc3dc229a1186c 100644 (file)
@@ -56,11 +56,11 @@ GLOBL sinhe9<>+0(SB), RODATA, $8
 
 TEXT ·sinhAsm(SB),NOSPLIT,$0-16
        FMOVD   x+0(FP), F0
-       //specail case Sinh(±0) = ±0
+       //special case Sinh(±0) = ±0
        FMOVD   $(0.0), F1
        FCMPU   F0, F1
        BEQ     sinhIsZero
-       //specail case Sinh(±Inf = ±Inf
+       //special case Sinh(±Inf) = ±Inf
        FMOVD   $1.797693134862315708145274237317043567981e+308, F1
        FCMPU   F1, F0
        BLEU    sinhIsInf
index b9102568ed51cddf2d6943d02867b93d00d4c3da..2cec1a5903d708c9c114a797d791cdfe674c34a6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || amd64 || arm64 || arm || mips || mipsle || ppc64 || ppc64le || s390x || riscv64 || wasm
-// +build 386 amd64 arm64 arm mips mipsle ppc64 ppc64le s390x riscv64 wasm
 
 package math
 
index 7b546b7e8cb2cafe404171d8dfed871582c0479e..3979622023141e55b64a4744b12fcadbe1907927 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386 && !amd64 && !arm64 && !arm && !mips && !mipsle && !ppc64 && !ppc64le && !s390x && !riscv64 && !wasm
-// +build !386,!amd64,!arm64,!arm,!mips,!mipsle,!ppc64,!ppc64le,!s390x,!riscv64,!wasm
 
 package math
 
index e1345eb841dd25c601e6648b7e8c8876df155ae8..c4350d4b8758e12328241f994b7e05a445c3c2a2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !s390x
-// +build !s390x
 
 // This is a large group of functions that most architectures don't
 // implement in assembly.
index b6e2295874e6ee83f1a70b38502492ad7d591135..82267608b97ea6c17b1f7f89a218c1c87c0d15b5 100644 (file)
@@ -38,7 +38,7 @@ GLOBL ·tanxadd<> + 0(SB), RODATA, $8
 
 TEXT   ·tanAsm(SB), NOSPLIT, $0-16
        FMOVD   x+0(FP), F0
-       //specail case Tan(±0) = ±0
+       //special case Tan(±0) = ±0
        FMOVD   $(0.0), F1
        FCMPU   F0, F1
        BEQ     atanIsZero
index 58f60daec4312c673bf4b627a869273caf1033df..e6b470b1fb0ef83548656fc06f13d8e14cc6be02 100644 (file)
@@ -203,35 +203,25 @@ func (d *WordDecoder) Decode(word string) (string, error) {
        }
        word = word[2 : len(word)-2]
 
-       // split delimits the first 2 fields
-       split := strings.IndexByte(word, '?')
-
-       // split word "UTF-8?q?ascii" into "UTF-8", 'q', and "ascii"
-       charset := word[:split]
-       if len(charset) == 0 {
-               return "", errInvalidWord
-       }
-       if len(word) < split+3 {
+       // split word "UTF-8?q?text" into "UTF-8", 'q', and "text"
+       charset, text, _ := strings.Cut(word, "?")
+       if charset == "" {
                return "", errInvalidWord
        }
-       encoding := word[split+1]
-       // the field after split must only be one byte
-       if word[split+2] != '?' {
+       encoding, text, _ := strings.Cut(text, "?")
+       if len(encoding) != 1 {
                return "", errInvalidWord
        }
-       text := word[split+3:]
 
-       content, err := decode(encoding, text)
+       content, err := decode(encoding[0], text)
        if err != nil {
                return "", err
        }
 
        var buf strings.Builder
-
        if err := d.convert(&buf, charset, content); err != nil {
                return "", err
        }
-
        return buf.String(), nil
 }
 
index 56ceb488533fc9b94063b68c6250c2e4e0f4fea6..9456570cf1f35b4807cc1aafe68187ee1a8db1a5 100644 (file)
@@ -19,13 +19,12 @@ import (
 // FormatMediaType returns the empty string.
 func FormatMediaType(t string, param map[string]string) string {
        var b strings.Builder
-       if slash := strings.IndexByte(t, '/'); slash == -1 {
+       if major, sub, ok := strings.Cut(t, "/"); !ok {
                if !isToken(t) {
                        return ""
                }
                b.WriteString(strings.ToLower(t))
        } else {
-               major, sub := t[:slash], t[slash+1:]
                if !isToken(major) || !isToken(sub) {
                        return ""
                }
@@ -138,11 +137,8 @@ var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter")
 // The returned map, params, maps from the lowercase
 // attribute to the attribute value with its case preserved.
 func ParseMediaType(v string) (mediatype string, params map[string]string, err error) {
-       i := strings.Index(v, ";")
-       if i == -1 {
-               i = len(v)
-       }
-       mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
+       base, _, _ := strings.Cut(v, ";")
+       mediatype = strings.TrimSpace(strings.ToLower(base))
 
        err = checkMediaTypeDisposition(mediatype)
        if err != nil {
@@ -156,7 +152,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
        // Lazily initialized.
        var continuation map[string]map[string]string
 
-       v = v[i:]
+       v = v[len(base):]
        for len(v) > 0 {
                v = strings.TrimLeftFunc(v, unicode.IsSpace)
                if len(v) == 0 {
@@ -174,8 +170,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
                }
 
                pmap := params
-               if idx := strings.Index(key, "*"); idx != -1 {
-                       baseName := key[:idx]
+               if baseName, _, ok := strings.Cut(key, "*"); ok {
                        if continuation == nil {
                                continuation = make(map[string]map[string]string)
                        }
index f954bc8a1fba6811ef0daff83c3ab2ecada9aa2a..3abc1fa10e47216bcaea015918e78d451be49b82 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package mime
 
index 6e2988225c35ce17d21902d7171204529058038e..4d109aa71a228eb1124900ad22242bdf9d06c303 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package mime
 
index ae93c595afafe6955868a63cca6b0b3583cb268b..29e4ed85abc3b4aecd3a72a3d0c36263a9eeb56e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 // Minimal RFC 6724 address selection.
 
index dc13917018b23d0241ccb0adb02aa863437c7d6b..2894d5d846ab99fe3997b64d30aabda2d66bfcd5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index a94405ecc049698e9ec5c57a5ac5c3836c44180b..f3478148b4f60e352dec179b9c5e8304c446f6e2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo
-// +build cgo,!netgo
 
 package net
 
index 4b1a2e3e1d44bdcd737708b58ef15bac41125b98..5ab8b5fedea13aacbdc9bb0758c5e4b9da232b73 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo
-// +build cgo,!netgo
 
 package net
 
index 23be72140b694b0d01f6f819ab709b27b38449e3..1456289b0691ba29a3167afde13757f3b6e82c7b 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (darwin || dragonfly || freebsd)
-// +build cgo
-// +build !netgo
-// +build darwin dragonfly freebsd
 
 package net
 
index 1bd6be93f7891c2a632a23260a0092cd2962ebb9..de6e87f17622df6a46a73c1b99ae2e21be6672c4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !android && cgo && !netgo
-// +build !android,cgo,!netgo
 
 package net
 
index 3714793a52f3c5373f5346f56dd4b06f9d2e74da..03392e8ff34c596a979e6b20469e8f636a4925c2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo
-// +build cgo,!netgo
 
 package net
 
index 3714793a52f3c5373f5346f56dd4b06f9d2e74da..03392e8ff34c596a979e6b20469e8f636a4925c2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo
-// +build cgo,!netgo
 
 package net
 
index 154405270f17287c6bd3c801cd5f662f8d680bec..fa6e68770ce35f16d1fc7d30e387948b0008815e 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (darwin || (linux && !android) || netbsd || solaris)
-// +build cgo
-// +build !netgo
-// +build darwin linux,!android netbsd solaris
 
 package net
 
index c4aab33eaa05700bba9e812889220a2df294e841..37c75527f95c0dedf8b36792cc94fb22eb89abc9 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (android || freebsd || dragonfly || openbsd)
-// +build cgo
-// +build !netgo
-// +build android freebsd dragonfly openbsd
 
 package net
 
index f9cfad9909cce8c857459f90042b6851d32ec07a..fbb9e10f3401967f2018f477392fb8428f7df752 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (android || linux || solaris)
-// +build cgo
-// +build !netgo
-// +build android linux solaris
 
 package net
 
index 22c67252f55cece64f33b751dc4249337a292362..4d9869de04fabbf6f9dcf14375dfae035cfb1d5d 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || netbsd || openbsd)
-// +build cgo
-// +build !netgo
-// +build aix darwin dragonfly freebsd netbsd openbsd
 
 package net
 
index a84f5b0d34c1472e947bf7632917c8758c47e7f0..cde9c957fee53c33d5dc074b3b6ce8a879202479 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo
-// +build cgo,!netgo
 
 package net
 
index 039e4be88b908a257dd426daba8d6616a1d39421..cc84ca47aed0bc79b7791909474c7beab6e1d2fe 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !cgo || netgo
-// +build !cgo netgo
 
 package net
 
index 2ea86e074fb9436fa55f9a6884a828b4cd16ad24..6fc2c1930e8145c2b825fbcfdeac258bee8d06cf 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris)
-// +build cgo
-// +build !netgo
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
@@ -323,7 +320,7 @@ func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (na
                        break
                }
        }
-       return []string{absDomainName(b)}, nil
+       return []string{absDomainName(string(b))}, nil
 }
 
 func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *C.struct_sockaddr, salen C.socklen_t) {
index 1f3d9ea207ae93273aa584eaa62906c95ea9b69d..b4da25b84c1fb0f62357d8cce842922544e063fd 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris)
-// +build cgo
-// +build !netgo
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 1fd1f29787c8601a4875143da36d5e91fdbb21cc..6bb6cbbb2fdcfaaf652c5a0147d6ce80dacf6f91 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !netgo
-// +build cgo,!netgo
 
 package net
 
index 6b9569cd92f7f78c9ade438119ef0a17157c7a15..415caedacc41b2501f364bd2852df770a3e3103b 100644 (file)
@@ -3,12 +3,12 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
 import (
        "internal/bytealg"
+       "internal/godebug"
        "os"
        "runtime"
        "sync"
@@ -287,7 +287,7 @@ func (c *conf) hostLookupOrder(r *Resolver, hostname string) (ret hostLookupOrde
 //    cgo+2   // same, but debug level 2
 // etc.
 func goDebugNetDNS() (dnsMode string, debugLevel int) {
-       goDebug := goDebugString("netdns")
+       goDebug := godebug.Get("netdns")
        parsePart := func(s string) {
                if s == "" {
                        return
index 8f387ebc03e5cfbe681be0cd1752895a8454de09..82d1bb643e19f01ad08211a57dbf75dfbeb8f4e0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build netcgo
-// +build netcgo
 
 package net
 
index b1f2c55ea50909bba28834121a2eb7fae32cd3de..5ae705508601979982d871e074f19af3ba69c823 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 45e271c264267ae10f1ed58bc2d40f1d04c8fa3a..e3cb0c5ec7e3afd549b53dc1d869b153ac390490 100644 (file)
@@ -6,7 +6,6 @@
 // tag.
 
 //go:build !js
-// +build !js
 
 package net
 
index 723038c7a22a44b6dfc73443ca6b344b855f096f..896789219707529bb639afa48e53403aa89f87bc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 108b973099715c96dfb7d8e1b4f4e6a08d57f575..1113aaca90575b3ae94bc7ba8034c314ec733ad7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 1bbe39650bbac2f7ec755d8de90c2ccae3845632..3c1a12995a8033e044f74a19c1bb29da30f375a2 100644 (file)
@@ -5,6 +5,7 @@
 package net
 
 import (
+       "internal/bytealg"
        "internal/itoa"
        "sort"
 
@@ -136,18 +137,11 @@ func isDomainName(s string) bool {
 // It's hard to tell so we settle on the heuristic that names without dots
 // (like "localhost" or "myhost") do not get trailing dots, but any other
 // names do.
-func absDomainName(b []byte) string {
-       hasDots := false
-       for _, x := range b {
-               if x == '.' {
-                       hasDots = true
-                       break
-               }
-       }
-       if hasDots && b[len(b)-1] != '.' {
-               b = append(b, '.')
+func absDomainName(s string) string {
+       if bytealg.IndexByteString(s, '.') != -1 && s[len(s)-1] != '.' {
+               s += "."
        }
-       return string(b)
+       return s
 }
 
 // An SRV represents a single DNS SRV record.
index 50e9bb0f20dd70745541c67c016eab7fa068ccd2..21aa91f665ad3d481bd3dd22672fd1903b0e0096 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
index 350ad5def797bc9b95aa4a9c1a56b58e8f5db7f2..1d704d021e2bf0db62ce5a4890b3c2c7a372500c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index db9213a13fd3e95fb6f37226dc748df22920bdf4..5ad254cd7c9a5956c642eab80984dd808ea17e43 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 // Read system DNS config from /etc/resolv.conf
 
index 0e2317c46912f43fb55aabdd0c6b929db212f0a4..4d352214976de224f93ea8dcb6989989b417fbf4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index d851bf75667d3a6c6c00f75a8220ab67b8ea08d0..28b7c680feb16a27fa7ce3fd6d310c5cb80bc84b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 50eb66fc61740e2362313ffb1fef001f8e4ef5d7..10e3caa67b7498b0a7dd0efb99dee003323b4e36 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
index ea52a45ee89db67def805df8be4b21f3e9d57a97..081176f771aebf72fa02563e862e82da678dc3f8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9
-// +build !plan9
 
 package net
 
index c304390819a915331276a62c68760ec986d57b8d..30f8af3aeeadcba8d6dfce42c7b675c499571661 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index d0b5e2ce96905e2ca39e2662fb130b0e66166002..0e64b40ea1ccb4e71aa5c729ba38daee71a84a7f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || js || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js linux netbsd openbsd solaris
 
 package net
 
index 533a45e648f11803f10f51095954975e286f1c4b..1334aa86b6882f5325a07caf5b7b98d1bf7732b7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9 && !windows
-// +build !plan9,!windows
 
 package net
 
index 72c7183c13469ae32ee7e6121cd22206801792ed..2c045d73a24bcb01ee8ea08f10afcac4ae305c03 100644 (file)
@@ -124,6 +124,176 @@ func ExampleIP_DefaultMask() {
        // ffffff00
 }
 
+func ExampleIP_Equal() {
+       ipv4DNS := net.ParseIP("8.8.8.8")
+       ipv4Lo := net.ParseIP("127.0.0.1")
+       ipv6DNS := net.ParseIP("0:0:0:0:0:FFFF:0808:0808")
+
+       fmt.Println(ipv4DNS.Equal(ipv4DNS))
+       fmt.Println(ipv4DNS.Equal(ipv4Lo))
+       fmt.Println(ipv4DNS.Equal(ipv6DNS))
+
+       // Output:
+       // true
+       // false
+       // true
+}
+
+func ExampleIP_IsGlobalUnicast() {
+       ipv6Global := net.ParseIP("2000::")
+       ipv6UniqLocal := net.ParseIP("2000::")
+       ipv6Multi := net.ParseIP("FF00::")
+
+       ipv4Private := net.ParseIP("10.255.0.0")
+       ipv4Public := net.ParseIP("8.8.8.8")
+       ipv4Broadcast := net.ParseIP("255.255.255.255")
+
+       fmt.Println(ipv6Global.IsGlobalUnicast())
+       fmt.Println(ipv6UniqLocal.IsGlobalUnicast())
+       fmt.Println(ipv6Multi.IsGlobalUnicast())
+
+       fmt.Println(ipv4Private.IsGlobalUnicast())
+       fmt.Println(ipv4Public.IsGlobalUnicast())
+       fmt.Println(ipv4Broadcast.IsGlobalUnicast())
+
+       // Output:
+       // true
+       // true
+       // false
+       // true
+       // true
+       // false
+}
+
+func ExampleIP_IsInterfaceLocalMulticast() {
+       ipv6InterfaceLocalMulti := net.ParseIP("ff01::1")
+       ipv6Global := net.ParseIP("2000::")
+       ipv4 := net.ParseIP("255.0.0.0")
+
+       fmt.Println(ipv6InterfaceLocalMulti.IsInterfaceLocalMulticast())
+       fmt.Println(ipv6Global.IsInterfaceLocalMulticast())
+       fmt.Println(ipv4.IsInterfaceLocalMulticast())
+
+       // Output:
+       // true
+       // false
+       // false
+}
+
+func ExampleIP_IsLinkLocalMulticast() {
+       ipv6LinkLocalMulti := net.ParseIP("ff02::2")
+       ipv6LinkLocalUni := net.ParseIP("fe80::")
+       ipv4LinkLocalMulti := net.ParseIP("224.0.0.0")
+       ipv4LinkLocalUni := net.ParseIP("169.254.0.0")
+
+       fmt.Println(ipv6LinkLocalMulti.IsLinkLocalMulticast())
+       fmt.Println(ipv6LinkLocalUni.IsLinkLocalMulticast())
+       fmt.Println(ipv4LinkLocalMulti.IsLinkLocalMulticast())
+       fmt.Println(ipv4LinkLocalUni.IsLinkLocalMulticast())
+
+       // Output:
+       // true
+       // false
+       // true
+       // false
+}
+
+func ExampleIP_IsLinkLocalUnicast() {
+       ipv6LinkLocalUni := net.ParseIP("fe80::")
+       ipv6Global := net.ParseIP("2000::")
+       ipv4LinkLocalUni := net.ParseIP("169.254.0.0")
+       ipv4LinkLocalMulti := net.ParseIP("224.0.0.0")
+
+       fmt.Println(ipv6LinkLocalUni.IsLinkLocalUnicast())
+       fmt.Println(ipv6Global.IsLinkLocalUnicast())
+       fmt.Println(ipv4LinkLocalUni.IsLinkLocalUnicast())
+       fmt.Println(ipv4LinkLocalMulti.IsLinkLocalUnicast())
+
+       // Output:
+       // true
+       // false
+       // true
+       // false
+}
+
+func ExampleIP_IsLoopback() {
+       ipv6Lo := net.ParseIP("::1")
+       ipv6 := net.ParseIP("ff02::1")
+       ipv4Lo := net.ParseIP("127.0.0.0")
+       ipv4 := net.ParseIP("128.0.0.0")
+
+       fmt.Println(ipv6Lo.IsLoopback())
+       fmt.Println(ipv6.IsLoopback())
+       fmt.Println(ipv4Lo.IsLoopback())
+       fmt.Println(ipv4.IsLoopback())
+
+       // Output:
+       // true
+       // false
+       // true
+       // false
+}
+
+func ExampleIP_IsMulticast() {
+       ipv6Multi := net.ParseIP("FF00::")
+       ipv6LinkLocalMulti := net.ParseIP("ff02::1")
+       ipv6Lo := net.ParseIP("::1")
+       ipv4Multi := net.ParseIP("239.0.0.0")
+       ipv4LinkLocalMulti := net.ParseIP("224.0.0.0")
+       ipv4Lo := net.ParseIP("127.0.0.0")
+
+       fmt.Println(ipv6Multi.IsMulticast())
+       fmt.Println(ipv6LinkLocalMulti.IsMulticast())
+       fmt.Println(ipv6Lo.IsMulticast())
+       fmt.Println(ipv4Multi.IsMulticast())
+       fmt.Println(ipv4LinkLocalMulti.IsMulticast())
+       fmt.Println(ipv4Lo.IsMulticast())
+
+       // Output:
+       // true
+       // true
+       // false
+       // true
+       // true
+       // false
+}
+
+func ExampleIP_IsPrivate() {
+       ipv6Private := net.ParseIP("fc00::")
+       ipv6Public := net.ParseIP("fe00::")
+       ipv4Private := net.ParseIP("10.255.0.0")
+       ipv4Public := net.ParseIP("11.0.0.0")
+
+       fmt.Println(ipv6Private.IsPrivate())
+       fmt.Println(ipv6Public.IsPrivate())
+       fmt.Println(ipv4Private.IsPrivate())
+       fmt.Println(ipv4Public.IsPrivate())
+
+       // Output:
+       // true
+       // false
+       // true
+       // false
+}
+
+func ExampleIP_IsUnspecified() {
+       ipv6Unspecified := net.ParseIP("::")
+       ipv6Specified := net.ParseIP("fe00::")
+       ipv4Unspecified := net.ParseIP("0.0.0.0")
+       ipv4Specified := net.ParseIP("8.8.8.8")
+
+       fmt.Println(ipv6Unspecified.IsUnspecified())
+       fmt.Println(ipv6Specified.IsUnspecified())
+       fmt.Println(ipv4Unspecified.IsUnspecified())
+       fmt.Println(ipv4Specified.IsUnspecified())
+
+       // Output:
+       // true
+       // false
+       // true
+       // false
+}
+
 func ExampleIP_Mask() {
        ipv4Addr := net.ParseIP("192.0.2.1")
        // This mask corresponds to a /24 subnet for IPv4.
@@ -140,6 +310,42 @@ func ExampleIP_Mask() {
        // 2001:db8::
 }
 
+func ExampleIP_String() {
+       ipv6 := net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+       ipv4 := net.IPv4(10, 255, 0, 0)
+
+       fmt.Println(ipv6.String())
+       fmt.Println(ipv4.String())
+
+       // Output:
+       // fc00::
+       // 10.255.0.0
+}
+
+func ExampleIP_To16() {
+       ipv6 := net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+       ipv4 := net.IPv4(10, 255, 0, 0)
+
+       fmt.Println(ipv6.To16())
+       fmt.Println(ipv4.To16())
+
+       // Output:
+       // fc00::
+       // 10.255.0.0
+}
+
+func ExampleIP_to4() {
+       ipv6 := net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+       ipv4 := net.IPv4(10, 255, 0, 0)
+
+       fmt.Println(ipv6.To4())
+       fmt.Println(ipv4.To4())
+
+       // Output:
+       // <nil>
+       // 10.255.0.0
+}
+
 func ExampleCIDRMask() {
        // This mask corresponds to a /31 subnet for IPv4.
        fmt.Println(net.CIDRMask(31, 32))
index b8753cc092bf1b9d322db63db93addba66022be6..3a97011fe8570b65283046d79b6c3ada1b3ad3a8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 0320d63a8632131711354104cad69f16edcd1ab1..3478ce723188b579834afcec1b2a741844e019df 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || solaris
-// +build aix darwin solaris
 
 package net
 
index 0f04bb4ed65add47a256ccc53aeffcd4908695d5..2d1f7e22a459fcdb2dcbdb52265ed3eb49d65be9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package net
 
index 4703ff33a10c71ef22df5317f8b413cfe186e0d6..1845c173bb756c7f3b6f28964d868cb6d0666714 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package net
 
@@ -63,6 +62,17 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
        runtime.KeepAlive(fd)
        return n, sa, wrapSyscallError(readFromSyscallName, err)
 }
+func (fd *netFD) readFromInet4(p []byte, from *syscall.SockaddrInet4) (n int, err error) {
+       n, err = fd.pfd.ReadFromInet4(p, from)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError(readFromSyscallName, err)
+}
+
+func (fd *netFD) readFromInet6(p []byte, from *syscall.SockaddrInet6) (n int, err error) {
+       n, err = fd.pfd.ReadFromInet6(p, from)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError(readFromSyscallName, err)
+}
 
 func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
        n, oobn, retflags, sa, err = fd.pfd.ReadMsg(p, oob, flags)
@@ -70,6 +80,18 @@ func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int
        return n, oobn, retflags, sa, wrapSyscallError(readMsgSyscallName, err)
 }
 
+func (fd *netFD) readMsgInet4(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet4) (n, oobn, retflags int, err error) {
+       n, oobn, retflags, err = fd.pfd.ReadMsgInet4(p, oob, flags, sa)
+       runtime.KeepAlive(fd)
+       return n, oobn, retflags, wrapSyscallError(readMsgSyscallName, err)
+}
+
+func (fd *netFD) readMsgInet6(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet6) (n, oobn, retflags int, err error) {
+       n, oobn, retflags, err = fd.pfd.ReadMsgInet6(p, oob, flags, sa)
+       runtime.KeepAlive(fd)
+       return n, oobn, retflags, wrapSyscallError(readMsgSyscallName, err)
+}
+
 func (fd *netFD) Write(p []byte) (nn int, err error) {
        nn, err = fd.pfd.Write(p)
        runtime.KeepAlive(fd)
@@ -82,12 +104,36 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
        return n, wrapSyscallError(writeToSyscallName, err)
 }
 
+func (fd *netFD) writeToInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
+       n, err = fd.pfd.WriteToInet4(p, sa)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError(writeToSyscallName, err)
+}
+
+func (fd *netFD) writeToInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
+       n, err = fd.pfd.WriteToInet6(p, sa)
+       runtime.KeepAlive(fd)
+       return n, wrapSyscallError(writeToSyscallName, err)
+}
+
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
        n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
        runtime.KeepAlive(fd)
        return n, oobn, wrapSyscallError(writeMsgSyscallName, err)
 }
 
+func (fd *netFD) writeMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (n int, oobn int, err error) {
+       n, oobn, err = fd.pfd.WriteMsgInet4(p, oob, sa)
+       runtime.KeepAlive(fd)
+       return n, oobn, wrapSyscallError(writeMsgSyscallName, err)
+}
+
+func (fd *netFD) writeMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (n int, oobn int, err error) {
+       n, oobn, err = fd.pfd.WriteMsgInet6(p, oob, sa)
+       runtime.KeepAlive(fd)
+       return n, oobn, wrapSyscallError(writeMsgSyscallName, err)
+}
+
 func (fd *netFD) SetDeadline(t time.Time) error {
        return fd.pfd.SetDeadline(t)
 }
index a7bbdd26b458403a849fe1b39206680c38f333af..1bb029d370cc9fc3c3d82db06ccfa287e39d8fb6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 9f988fe89936179a3f177e266d15f2afd38f4219..91df926a5789144ef0ad8e197d854b8c5c01d1b0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
index a70ef1b312ff127eb8d4c430c5aa07d3bdb1933a..e86c15fac735fac0bbc2b055875c4083c60ba172 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 4520d4b839ed60d81c48e00e9e37f29175e140be..68d7eb9ca0198c15ed43b890e6dec6e076610314 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index b9153d1947f98ccf0646135ba6fd7781ba8ae65a..7c36b0d6e3272dfd17f8f07660cc14aba265fc4d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package net
 
index 5c560f3756ed1a2ec58ef9b08345f8a96530c3ba..e604031920b1fe55a495679f64b740683161fdfd 100644 (file)
@@ -82,10 +82,10 @@ func readHosts() {
                        continue
                }
                for i := 1; i < len(f); i++ {
-                       name := absDomainName([]byte(f[i]))
+                       name := absDomainName(f[i])
                        h := []byte(f[i])
                        lowerASCIIBytes(h)
-                       key := absDomainName(h)
+                       key := absDomainName(string(h))
                        hs[key] = append(hs[key], addr)
                        is[addr] = append(is[addr], name)
                }
@@ -106,11 +106,12 @@ func lookupStaticHost(host string) []string {
        defer hosts.Unlock()
        readHosts()
        if len(hosts.byName) != 0 {
-               // TODO(jbd,bradfitz): avoid this alloc if host is already all lowercase?
-               // or linear scan the byName map if it's small enough?
-               lowerHost := []byte(host)
-               lowerASCIIBytes(lowerHost)
-               if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok {
+               if hasUpperCase(host) {
+                       lowerHost := []byte(host)
+                       lowerASCIIBytes(lowerHost)
+                       host = string(lowerHost)
+               }
+               if ips, ok := hosts.byName[absDomainName(host)]; ok {
                        ipsCp := make([]string, len(ips))
                        copy(ipsCp, ips)
                        return ipsCp
index 19c43999f9291ca77a13053c92b7efedc1c8e95e..72919140e9c79f032b493e2642b863c3b026755b 100644 (file)
@@ -70,7 +70,7 @@ func TestLookupStaticHost(t *testing.T) {
 }
 
 func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
-       ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
+       ins := []string{ent.in, absDomainName(ent.in), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
        for _, in := range ins {
                addrs := lookupStaticHost(in)
                if !reflect.DeepEqual(addrs, ent.out) {
@@ -141,7 +141,7 @@ func TestLookupStaticAddr(t *testing.T) {
 func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) {
        hosts := lookupStaticAddr(ent.in)
        for i := range ent.out {
-               ent.out[i] = absDomainName([]byte(ent.out[i]))
+               ent.out[i] = absDomainName(ent.out[i])
        }
        if !reflect.DeepEqual(hosts, ent.out) {
                t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", hostsPath, ent.in, hosts, ent.out)
index 0114da377b564725f7d33d804625cb4aacc2994c..bdb35a64e50b97ec0e542458621141cc6f85cb2a 100644 (file)
@@ -39,8 +39,8 @@ func Request() (*http.Request, error) {
 func envMap(env []string) map[string]string {
        m := make(map[string]string)
        for _, kv := range env {
-               if idx := strings.Index(kv, "="); idx != -1 {
-                       m[kv[:idx]] = kv[idx+1:]
+               if k, v, ok := strings.Cut(kv, "="); ok {
+                       m[k] = v
                }
        }
        return m
index eff67caf4e6efbe242129f768898acbd1f95741b..e7124a2ab058a4386b5fc86d3a289e517b512588 100644 (file)
@@ -273,12 +273,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
                        break
                }
                headerLines++
-               parts := strings.SplitN(string(line), ":", 2)
-               if len(parts) < 2 {
+               header, val, ok := strings.Cut(string(line), ":")
+               if !ok {
                        h.printf("cgi: bogus header line: %s", string(line))
                        continue
                }
-               header, val := parts[0], parts[1]
                if !httpguts.ValidHeaderFieldName(header) {
                        h.printf("cgi: invalid header name: %q", header)
                        continue
index fb869a67282d60df9abd4626accfe737a9f995a3..f8abc88c8973775397063bb28468b9c1c57763c8 100644 (file)
@@ -62,12 +62,12 @@ readlines:
                }
                linesRead++
                trimmedLine := strings.TrimRight(line, "\r\n")
-               split := strings.SplitN(trimmedLine, "=", 2)
-               if len(split) != 2 {
-                       t.Fatalf("Unexpected %d parts from invalid line number %v: %q; existing map=%v",
-                               len(split), linesRead, line, m)
+               k, v, ok := strings.Cut(trimmedLine, "=")
+               if !ok {
+                       t.Fatalf("Unexpected response from invalid line number %v: %q; existing map=%v",
+                               linesRead, line, m)
                }
-               m[split[0]] = split[1]
+               m[k] = v
        }
 
        for key, expected := range expectedMap {
index f998bac6ea654cdc582e26caa579b057c9f14c40..b7ace3f81c94d572f6851e6f58baef38ea031790 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package cgi
 
index bc58ea94cc93b782f1c7efc17e073902cf471e4e..49b9470d4ae2a4128df7502503a335b529d1ec84 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9
-// +build !plan9
 
 package cgi
 
index 01d605c35194f88e954c2b348458f5e7aae9c478..fb6fbe71975941292f9836bff7fc25f497458e94 100644 (file)
@@ -431,11 +431,10 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
                if v := urlQuery.Get("code"); v != "" {
                        location := ts.URL
                        if final := urlQuery.Get("next"); final != "" {
-                               splits := strings.Split(final, ",")
-                               first, rest := splits[0], splits[1:]
+                               first, rest, _ := strings.Cut(final, ",")
                                location = fmt.Sprintf("%s?code=%s", location, first)
-                               if len(rest) > 0 {
-                                       location = fmt.Sprintf("%s&next=%s", location, strings.Join(rest, ","))
+                               if rest != "" {
+                                       location = fmt.Sprintf("%s&next=%s", location, rest)
                                }
                        }
                        code, _ := strconv.Atoi(v)
@@ -1206,64 +1205,80 @@ func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) }
 func testClientTimeout(t *testing.T, h2 bool) {
        setParallel(t)
        defer afterTest(t)
-       testDone := make(chan struct{}) // closed in defer below
 
-       sawRoot := make(chan bool, 1)
-       sawSlow := make(chan bool, 1)
+       var (
+               mu           sync.Mutex
+               nonce        string // a unique per-request string
+               sawSlowNonce bool   // true if the handler saw /slow?nonce=<nonce>
+       )
        cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+               _ = r.ParseForm()
                if r.URL.Path == "/" {
-                       sawRoot <- true
-                       Redirect(w, r, "/slow", StatusFound)
+                       Redirect(w, r, "/slow?nonce="+r.Form.Get("nonce"), StatusFound)
                        return
                }
                if r.URL.Path == "/slow" {
-                       sawSlow <- true
+                       mu.Lock()
+                       if r.Form.Get("nonce") == nonce {
+                               sawSlowNonce = true
+                       } else {
+                               t.Logf("mismatched nonce: received %s, want %s", r.Form.Get("nonce"), nonce)
+                       }
+                       mu.Unlock()
+
                        w.Write([]byte("Hello"))
                        w.(Flusher).Flush()
-                       <-testDone
+                       <-r.Context().Done()
                        return
                }
        }))
        defer cst.close()
-       defer close(testDone) // before cst.close, to unblock /slow handler
-
-       // 200ms should be long enough to get a normal request (the /
-       // handler), but not so long that it makes the test slow.
-       const timeout = 200 * time.Millisecond
-       cst.c.Timeout = timeout
 
-       res, err := cst.c.Get(cst.ts.URL)
-       if err != nil {
-               if strings.Contains(err.Error(), "Client.Timeout") {
-                       t.Skipf("host too slow to get fast resource in %v", timeout)
+       // Try to trigger a timeout after reading part of the response body.
+       // The initial timeout is emprically usually long enough on a decently fast
+       // machine, but if we undershoot we'll retry with exponentially longer
+       // timeouts until the test either passes or times out completely.
+       // This keeps the test reasonably fast in the typical case but allows it to
+       // also eventually succeed on arbitrarily slow machines.
+       timeout := 10 * time.Millisecond
+       nextNonce := 0
+       for ; ; timeout *= 2 {
+               if timeout <= 0 {
+                       // The only way we can feasibly hit this while the test is running is if
+                       // the request fails without actually waiting for the timeout to occur.
+                       t.Fatalf("timeout overflow")
+               }
+               if deadline, ok := t.Deadline(); ok && !time.Now().Add(timeout).Before(deadline) {
+                       t.Fatalf("failed to produce expected timeout before test deadline")
+               }
+               t.Logf("attempting test with timeout %v", timeout)
+               cst.c.Timeout = timeout
+
+               mu.Lock()
+               nonce = fmt.Sprint(nextNonce)
+               nextNonce++
+               sawSlowNonce = false
+               mu.Unlock()
+               res, err := cst.c.Get(cst.ts.URL + "/?nonce=" + nonce)
+               if err != nil {
+                       if strings.Contains(err.Error(), "Client.Timeout") {
+                               // Timed out before handler could respond.
+                               t.Logf("timeout before response received")
+                               continue
+                       }
+                       t.Fatal(err)
                }
-               t.Fatal(err)
-       }
-
-       select {
-       case <-sawRoot:
-               // good.
-       default:
-               t.Fatal("handler never got / request")
-       }
 
-       select {
-       case <-sawSlow:
-               // good.
-       default:
-               t.Fatal("handler never got /slow request")
-       }
+               mu.Lock()
+               ok := sawSlowNonce
+               mu.Unlock()
+               if !ok {
+                       t.Fatal("handler never got /slow request, but client returned response")
+               }
 
-       errc := make(chan error, 1)
-       go func() {
-               _, err := io.ReadAll(res.Body)
-               errc <- err
+               _, err = io.ReadAll(res.Body)
                res.Body.Close()
-       }()
 
-       const failTime = 5 * time.Second
-       select {
-       case err := <-errc:
                if err == nil {
                        t.Fatal("expected error from ReadAll")
                }
@@ -1276,8 +1291,8 @@ func testClientTimeout(t *testing.T, h2 bool) {
                if got := ne.Error(); !strings.Contains(got, "(Client.Timeout") {
                        t.Errorf("error string = %q; missing timeout substring", got)
                }
-       case <-time.After(failTime):
-               t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
+
+               break
        }
 }
 
@@ -2082,3 +2097,47 @@ func (b *issue40382Body) Close() error {
        }
        return nil
 }
+
+func TestProbeZeroLengthBody(t *testing.T) {
+       setParallel(t)
+       defer afterTest(t)
+       reqc := make(chan struct{})
+       cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) {
+               close(reqc)
+               if _, err := io.Copy(w, r.Body); err != nil {
+                       t.Errorf("error copying request body: %v", err)
+               }
+       }))
+       defer cst.close()
+
+       bodyr, bodyw := io.Pipe()
+       var gotBody string
+       var wg sync.WaitGroup
+       wg.Add(1)
+       go func() {
+               defer wg.Done()
+               req, _ := NewRequest("GET", cst.ts.URL, bodyr)
+               res, err := cst.c.Do(req)
+               b, err := io.ReadAll(res.Body)
+               if err != nil {
+                       t.Error(err)
+               }
+               gotBody = string(b)
+       }()
+
+       select {
+       case <-reqc:
+               // Request should be sent after trying to probe the request body for 200ms.
+       case <-time.After(60 * time.Second):
+               t.Errorf("request not sent after 60s")
+       }
+
+       // Write the request body and wait for the request to complete.
+       const content = "body"
+       bodyw.Write([]byte(content))
+       bodyw.Close()
+       wg.Wait()
+       if gotBody != content {
+               t.Fatalf("server got body %q, want %q", gotBody, content)
+       }
+}
index ca2c1c2506694cc7c636c09af3b7cf9921352287..cb37f2351f58890b0c73008946dded3456be1e28 100644 (file)
@@ -5,6 +5,8 @@
 package http
 
 import (
+       "errors"
+       "fmt"
        "log"
        "net"
        "net/http/internal/ascii"
@@ -67,15 +69,14 @@ func readSetCookies(h Header) []*Cookie {
                        continue
                }
                parts[0] = textproto.TrimString(parts[0])
-               j := strings.Index(parts[0], "=")
-               if j < 0 {
+               name, value, ok := strings.Cut(parts[0], "=")
+               if !ok {
                        continue
                }
-               name, value := parts[0][:j], parts[0][j+1:]
                if !isCookieNameValid(name) {
                        continue
                }
-               value, ok := parseCookieValue(value, true)
+               value, ok = parseCookieValue(value, true)
                if !ok {
                        continue
                }
@@ -90,10 +91,7 @@ func readSetCookies(h Header) []*Cookie {
                                continue
                        }
 
-                       attr, val := parts[i], ""
-                       if j := strings.Index(attr, "="); j >= 0 {
-                               attr, val = attr[:j], attr[j+1:]
-                       }
+                       attr, val, _ := strings.Cut(parts[i], "=")
                        lowerAttr, isASCII := ascii.ToLower(attr)
                        if !isASCII {
                                continue
@@ -240,6 +238,37 @@ func (c *Cookie) String() string {
        return b.String()
 }
 
+// Valid reports whether the cookie is valid.
+func (c *Cookie) Valid() error {
+       if c == nil {
+               return errors.New("http: nil Cookie")
+       }
+       if !isCookieNameValid(c.Name) {
+               return errors.New("http: invalid Cookie.Name")
+       }
+       if !validCookieExpires(c.Expires) {
+               return errors.New("http: invalid Cookie.Expires")
+       }
+       for i := 0; i < len(c.Value); i++ {
+               if !validCookieValueByte(c.Value[i]) {
+                       return fmt.Errorf("http: invalid byte %q in Cookie.Value", c.Value[i])
+               }
+       }
+       if len(c.Path) > 0 {
+               for i := 0; i < len(c.Path); i++ {
+                       if !validCookiePathByte(c.Path[i]) {
+                               return fmt.Errorf("http: invalid byte %q in Cookie.Path", c.Path[i])
+                       }
+               }
+       }
+       if len(c.Domain) > 0 {
+               if !validCookieDomain(c.Domain) {
+                       return errors.New("http: invalid Cookie.Domain")
+               }
+       }
+       return nil
+}
+
 // readCookies parses all "Cookie" values from the header h and
 // returns the successfully parsed Cookies.
 //
@@ -256,19 +285,12 @@ func readCookies(h Header, filter string) []*Cookie {
 
                var part string
                for len(line) > 0 { // continue since we have rest
-                       if splitIndex := strings.Index(line, ";"); splitIndex > 0 {
-                               part, line = line[:splitIndex], line[splitIndex+1:]
-                       } else {
-                               part, line = line, ""
-                       }
+                       part, line, _ = strings.Cut(line, ";")
                        part = textproto.TrimString(part)
-                       if len(part) == 0 {
+                       if part == "" {
                                continue
                        }
-                       name, val := part, ""
-                       if j := strings.Index(part, "="); j >= 0 {
-                               name, val = name[:j], name[j+1:]
-                       }
+                       name, val, _ := strings.Cut(part, "=")
                        if !isCookieNameValid(name) {
                                continue
                        }
@@ -379,7 +401,7 @@ func sanitizeCookieValue(v string) string {
        if len(v) == 0 {
                return v
        }
-       if strings.IndexByte(v, ' ') >= 0 || strings.IndexByte(v, ',') >= 0 {
+       if strings.ContainsAny(v, " ,") {
                return `"` + v + `"`
        }
        return v
index 959713a0dcf0a092e9cde35824517f89cecbb303..257dc57420b0d2cc6ca726b2eb997bb094aa76bc 100644 (file)
@@ -529,6 +529,31 @@ func TestCookieSanitizePath(t *testing.T) {
        }
 }
 
+func TestCookieValid(t *testing.T) {
+       tests := []struct {
+               cookie *Cookie
+               valid  bool
+       }{
+               {nil, false},
+               {&Cookie{Name: ""}, false},
+               {&Cookie{Name: "invalid-expires"}, false},
+               {&Cookie{Name: "invalid-value", Value: "foo\"bar"}, false},
+               {&Cookie{Name: "invalid-path", Path: "/foo;bar/"}, false},
+               {&Cookie{Name: "invalid-domain", Domain: "example.com:80"}, false},
+               {&Cookie{Name: "valid", Value: "foo", Path: "/bar", Domain: "example.com", Expires: time.Unix(0, 0)}, true},
+       }
+
+       for _, tt := range tests {
+               err := tt.cookie.Valid()
+               if err != nil && tt.valid {
+                       t.Errorf("%#v.Valid() returned error %v; want nil", tt.cookie, err)
+               }
+               if err == nil && !tt.valid {
+                       t.Errorf("%#v.Valid() returned nil; want error", tt.cookie)
+               }
+       }
+}
+
 func BenchmarkCookieString(b *testing.B) {
        const wantCookieString = `cookie-9=i3e01nf61b6t23bvfmplnanol3; Path=/restricted/; Domain=example.com; Expires=Tue, 10 Nov 2009 23:00:00 GMT; Max-Age=3600`
        c := &Cookie{
index 57e731e481ad49830b67a907dee59f554130579b..19b2894bf2ff388cbc0de14c38e26c4b342d2b4c 100644 (file)
@@ -881,11 +881,11 @@ func parseRange(s string, size int64) ([]httpRange, error) {
                if ra == "" {
                        continue
                }
-               i := strings.Index(ra, "-")
-               if i < 0 {
+               start, end, ok := strings.Cut(ra, "-")
+               if !ok {
                        return nil, errors.New("invalid range")
                }
-               start, end := textproto.TrimString(ra[:i]), textproto.TrimString(ra[i+1:])
+               start, end = textproto.TrimString(start), textproto.TrimString(end)
                var r httpRange
                if start == "" {
                        // If no start is specified, end specifies the
index a948ff3eed4af65f0ac3393d89355cd2eabfee05..29226d4065e36f5481f1284160525aeec161d990 100644 (file)
@@ -53,6 +53,10 @@ import (
        "golang.org/x/net/idna"
 )
 
+// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
+// contains helper functions which may use Unicode-aware functions which would
+// otherwise be unsafe and could introduce vulnerabilities if used improperly.
+
 // asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
 // are equal, ASCII-case-insensitively.
 func http2asciiEqualFold(s, t string) bool {
@@ -733,6 +737,12 @@ func http2isBadCipher(cipher uint16) bool {
 
 // ClientConnPool manages a pool of HTTP/2 client connections.
 type http2ClientConnPool interface {
+       // GetClientConn returns a specific HTTP/2 connection (usually
+       // a TLS-TCP connection) to an HTTP/2 server. On success, the
+       // returned ClientConn accounts for the upcoming RoundTrip
+       // call, so the caller should not omit it. If the caller needs
+       // to, ClientConn.RoundTrip can be called with a bogus
+       // new(http.Request) to release the stream reservation.
        GetClientConn(req *Request, addr string) (*http2ClientConn, error)
        MarkDead(*http2ClientConn)
 }
@@ -759,7 +769,7 @@ type http2clientConnPool struct {
        conns        map[string][]*http2ClientConn // key is host:port
        dialing      map[string]*http2dialCall     // currently in-flight dials
        keys         map[*http2ClientConn][]string
-       addConnCalls map[string]*http2addConnCall // in-flight addConnIfNeede calls
+       addConnCalls map[string]*http2addConnCall // in-flight addConnIfNeeded calls
 }
 
 func (p *http2clientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
@@ -771,28 +781,8 @@ const (
        http2noDialOnMiss = false
 )
 
-// shouldTraceGetConn reports whether getClientConn should call any
-// ClientTrace.GetConn hook associated with the http.Request.
-//
-// This complexity is needed to avoid double calls of the GetConn hook
-// during the back-and-forth between net/http and x/net/http2 (when the
-// net/http.Transport is upgraded to also speak http2), as well as support
-// the case where x/net/http2 is being used directly.
-func (p *http2clientConnPool) shouldTraceGetConn(st http2clientConnIdleState) bool {
-       // If our Transport wasn't made via ConfigureTransport, always
-       // trace the GetConn hook if provided, because that means the
-       // http2 package is being used directly and it's the one
-       // dialing, as opposed to net/http.
-       if _, ok := p.t.ConnPool.(http2noDialClientConnPool); !ok {
-               return true
-       }
-       // Otherwise, only use the GetConn hook if this connection has
-       // been used previously for other requests. For fresh
-       // connections, the net/http package does the dialing.
-       return !st.freshConn
-}
-
 func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) {
+       // TODO(dneil): Dial a new connection when t.DisableKeepAlives is set?
        if http2isConnectionCloseRequest(req) && dialOnMiss {
                // It gets its own connection.
                http2traceGetConn(req, addr)
@@ -806,10 +796,14 @@ func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMis
        for {
                p.mu.Lock()
                for _, cc := range p.conns[addr] {
-                       if st := cc.idleState(); st.canTakeNewRequest {
-                               if p.shouldTraceGetConn(st) {
+                       if cc.ReserveNewRequest() {
+                               // When a connection is presented to us by the net/http package,
+                               // the GetConn hook has already been called.
+                               // Don't call it a second time here.
+                               if !cc.getConnCalled {
                                        http2traceGetConn(req, addr)
                                }
+                               cc.getConnCalled = false
                                p.mu.Unlock()
                                return cc, nil
                        }
@@ -825,7 +819,13 @@ func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMis
                if http2shouldRetryDial(call, req) {
                        continue
                }
-               return call.res, call.err
+               cc, err := call.res, call.err
+               if err != nil {
+                       return nil, err
+               }
+               if cc.ReserveNewRequest() {
+                       return cc, nil
+               }
        }
 }
 
@@ -922,6 +922,7 @@ func (c *http2addConnCall) run(t *http2Transport, key string, tc *tls.Conn) {
        if err != nil {
                c.err = err
        } else {
+               cc.getConnCalled = true // already called by the net/http package
                p.addConnLocked(key, cc)
        }
        delete(p.addConnCalls, key)
@@ -1208,6 +1209,13 @@ func (e http2ErrCode) String() string {
        return fmt.Sprintf("unknown error code 0x%x", uint32(e))
 }
 
+func (e http2ErrCode) stringToken() string {
+       if s, ok := http2errCodeName[e]; ok {
+               return s
+       }
+       return fmt.Sprintf("ERR_UNKNOWN_%d", uint32(e))
+}
+
 // ConnectionError is an error that results in the termination of the
 // entire connection.
 type http2ConnectionError http2ErrCode
@@ -1224,6 +1232,11 @@ type http2StreamError struct {
        Cause    error // optional additional detail
 }
 
+// errFromPeer is a sentinel error value for StreamError.Cause to
+// indicate that the StreamError was sent from the peer over the wire
+// and wasn't locally generated in the Transport.
+var http2errFromPeer = errors.New("received from peer")
+
 func http2streamError(id uint32, code http2ErrCode) http2StreamError {
        return http2StreamError{StreamID: id, Code: code}
 }
@@ -1438,7 +1451,7 @@ var http2flagName = map[http2FrameType]map[http2Flags]string{
 // a frameParser parses a frame given its FrameHeader and payload
 // bytes. The length of payload will always equal fh.Length (which
 // might be 0).
-type http2frameParser func(fc *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error)
+type http2frameParser func(fc *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error)
 
 var http2frameParsers = map[http2FrameType]http2frameParser{
        http2FrameData:         http2parseDataFrame,
@@ -1583,6 +1596,11 @@ type http2Framer struct {
        lastFrame http2Frame
        errDetail error
 
+       // countError is a non-nil func that's called on a frame parse
+       // error with some unique error path token. It's initialized
+       // from Transport.CountError or Server.CountError.
+       countError func(errToken string)
+
        // lastHeaderStream is non-zero if the last frame was an
        // unfinished HEADERS/CONTINUATION.
        lastHeaderStream uint32
@@ -1745,6 +1763,7 @@ func http2NewFramer(w io.Writer, r io.Reader) *http2Framer {
        fr := &http2Framer{
                w:                 w,
                r:                 r,
+               countError:        func(string) {},
                logReads:          http2logFrameReads,
                logWrites:         http2logFrameWrites,
                debugReadLoggerf:  log.Printf,
@@ -1819,7 +1838,7 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
        if _, err := io.ReadFull(fr.r, payload); err != nil {
                return nil, err
        }
-       f, err := http2typeFrameParser(fh.Type)(fr.frameCache, fh, payload)
+       f, err := http2typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload)
        if err != nil {
                if ce, ok := err.(http2connError); ok {
                        return nil, fr.connError(ce.Code, ce.Reason)
@@ -1907,13 +1926,14 @@ func (f *http2DataFrame) Data() []byte {
        return f.data
 }
 
-func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) {
+func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error) {
        if fh.StreamID == 0 {
                // DATA frames MUST be associated with a stream. If a
                // DATA frame is received whose stream identifier
                // field is 0x0, the recipient MUST respond with a
                // connection error (Section 5.4.1) of type
                // PROTOCOL_ERROR.
+               countError("frame_data_stream_0")
                return nil, http2connError{http2ErrCodeProtocol, "DATA frame with stream ID 0"}
        }
        f := fc.getDataFrame()
@@ -1924,6 +1944,7 @@ func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, payload []byt
                var err error
                payload, padSize, err = http2readByte(payload)
                if err != nil {
+                       countError("frame_data_pad_byte_short")
                        return nil, err
                }
        }
@@ -1932,6 +1953,7 @@ func http2parseDataFrame(fc *http2frameCache, fh http2FrameHeader, payload []byt
                // length of the frame payload, the recipient MUST
                // treat this as a connection error.
                // Filed: https://github.com/http2/http2-spec/issues/610
+               countError("frame_data_pad_too_big")
                return nil, http2connError{http2ErrCodeProtocol, "pad size larger than data payload"}
        }
        f.data = payload[:len(payload)-int(padSize)]
@@ -2014,7 +2036,7 @@ type http2SettingsFrame struct {
        p []byte
 }
 
-func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
        if fh.Flags.Has(http2FlagSettingsAck) && fh.Length > 0 {
                // When this (ACK 0x1) bit is set, the payload of the
                // SETTINGS frame MUST be empty. Receipt of a
@@ -2022,6 +2044,7 @@ func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, p []byte)
                // field value other than 0 MUST be treated as a
                // connection error (Section 5.4.1) of type
                // FRAME_SIZE_ERROR.
+               countError("frame_settings_ack_with_length")
                return nil, http2ConnectionError(http2ErrCodeFrameSize)
        }
        if fh.StreamID != 0 {
@@ -2032,14 +2055,17 @@ func http2parseSettingsFrame(_ *http2frameCache, fh http2FrameHeader, p []byte)
                // field is anything other than 0x0, the endpoint MUST
                // respond with a connection error (Section 5.4.1) of
                // type PROTOCOL_ERROR.
+               countError("frame_settings_has_stream")
                return nil, http2ConnectionError(http2ErrCodeProtocol)
        }
        if len(p)%6 != 0 {
+               countError("frame_settings_mod_6")
                // Expecting even number of 6 byte settings.
                return nil, http2ConnectionError(http2ErrCodeFrameSize)
        }
        f := &http2SettingsFrame{http2FrameHeader: fh, p: p}
        if v, ok := f.Value(http2SettingInitialWindowSize); ok && v > (1<<31)-1 {
+               countError("frame_settings_window_size_too_big")
                // Values above the maximum flow control window size of 2^31 - 1 MUST
                // be treated as a connection error (Section 5.4.1) of type
                // FLOW_CONTROL_ERROR.
@@ -2151,11 +2177,13 @@ type http2PingFrame struct {
 
 func (f *http2PingFrame) IsAck() bool { return f.Flags.Has(http2FlagPingAck) }
 
-func http2parsePingFrame(_ *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) {
+func http2parsePingFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error) {
        if len(payload) != 8 {
+               countError("frame_ping_length")
                return nil, http2ConnectionError(http2ErrCodeFrameSize)
        }
        if fh.StreamID != 0 {
+               countError("frame_ping_has_stream")
                return nil, http2ConnectionError(http2ErrCodeProtocol)
        }
        f := &http2PingFrame{http2FrameHeader: fh}
@@ -2191,11 +2219,13 @@ func (f *http2GoAwayFrame) DebugData() []byte {
        return f.debugData
 }
 
-func http2parseGoAwayFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseGoAwayFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
        if fh.StreamID != 0 {
+               countError("frame_goaway_has_stream")
                return nil, http2ConnectionError(http2ErrCodeProtocol)
        }
        if len(p) < 8 {
+               countError("frame_goaway_short")
                return nil, http2ConnectionError(http2ErrCodeFrameSize)
        }
        return &http2GoAwayFrame{
@@ -2231,7 +2261,7 @@ func (f *http2UnknownFrame) Payload() []byte {
        return f.p
 }
 
-func http2parseUnknownFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseUnknownFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
        return &http2UnknownFrame{fh, p}, nil
 }
 
@@ -2242,8 +2272,9 @@ type http2WindowUpdateFrame struct {
        Increment uint32 // never read with high bit set
 }
 
-func http2parseWindowUpdateFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseWindowUpdateFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
        if len(p) != 4 {
+               countError("frame_windowupdate_bad_len")
                return nil, http2ConnectionError(http2ErrCodeFrameSize)
        }
        inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
@@ -2255,8 +2286,10 @@ func http2parseWindowUpdateFrame(_ *http2frameCache, fh http2FrameHeader, p []by
                // control window MUST be treated as a connection
                // error (Section 5.4.1).
                if fh.StreamID == 0 {
+                       countError("frame_windowupdate_zero_inc_conn")
                        return nil, http2ConnectionError(http2ErrCodeProtocol)
                }
+               countError("frame_windowupdate_zero_inc_stream")
                return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
        }
        return &http2WindowUpdateFrame{
@@ -2307,7 +2340,7 @@ func (f *http2HeadersFrame) HasPriority() bool {
        return f.http2FrameHeader.Flags.Has(http2FlagHeadersPriority)
 }
 
-func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
+func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (_ http2Frame, err error) {
        hf := &http2HeadersFrame{
                http2FrameHeader: fh,
        }
@@ -2316,11 +2349,13 @@ func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (
                // is received whose stream identifier field is 0x0, the recipient MUST
                // respond with a connection error (Section 5.4.1) of type
                // PROTOCOL_ERROR.
+               countError("frame_headers_zero_stream")
                return nil, http2connError{http2ErrCodeProtocol, "HEADERS frame with stream ID 0"}
        }
        var padLength uint8
        if fh.Flags.Has(http2FlagHeadersPadded) {
                if p, padLength, err = http2readByte(p); err != nil {
+                       countError("frame_headers_pad_short")
                        return
                }
        }
@@ -2328,16 +2363,19 @@ func http2parseHeadersFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (
                var v uint32
                p, v, err = http2readUint32(p)
                if err != nil {
+                       countError("frame_headers_prio_short")
                        return nil, err
                }
                hf.Priority.StreamDep = v & 0x7fffffff
                hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set
                p, hf.Priority.Weight, err = http2readByte(p)
                if err != nil {
+                       countError("frame_headers_prio_weight_short")
                        return nil, err
                }
        }
-       if len(p)-int(padLength) <= 0 {
+       if len(p)-int(padLength) < 0 {
+               countError("frame_headers_pad_too_big")
                return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
        }
        hf.headerFragBuf = p[:len(p)-int(padLength)]
@@ -2444,11 +2482,13 @@ func (p http2PriorityParam) IsZero() bool {
        return p == http2PriorityParam{}
 }
 
-func http2parsePriorityFrame(_ *http2frameCache, fh http2FrameHeader, payload []byte) (http2Frame, error) {
+func http2parsePriorityFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), payload []byte) (http2Frame, error) {
        if fh.StreamID == 0 {
+               countError("frame_priority_zero_stream")
                return nil, http2connError{http2ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
        }
        if len(payload) != 5 {
+               countError("frame_priority_bad_length")
                return nil, http2connError{http2ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
        }
        v := binary.BigEndian.Uint32(payload[:4])
@@ -2491,11 +2531,13 @@ type http2RSTStreamFrame struct {
        ErrCode http2ErrCode
 }
 
-func http2parseRSTStreamFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseRSTStreamFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
        if len(p) != 4 {
+               countError("frame_rststream_bad_len")
                return nil, http2ConnectionError(http2ErrCodeFrameSize)
        }
        if fh.StreamID == 0 {
+               countError("frame_rststream_zero_stream")
                return nil, http2ConnectionError(http2ErrCodeProtocol)
        }
        return &http2RSTStreamFrame{fh, http2ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
@@ -2521,8 +2563,9 @@ type http2ContinuationFrame struct {
        headerFragBuf []byte
 }
 
-func http2parseContinuationFrame(_ *http2frameCache, fh http2FrameHeader, p []byte) (http2Frame, error) {
+func http2parseContinuationFrame(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (http2Frame, error) {
        if fh.StreamID == 0 {
+               countError("frame_continuation_zero_stream")
                return nil, http2connError{http2ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
        }
        return &http2ContinuationFrame{fh, p}, nil
@@ -2571,7 +2614,7 @@ func (f *http2PushPromiseFrame) HeadersEnded() bool {
        return f.http2FrameHeader.Flags.Has(http2FlagPushPromiseEndHeaders)
 }
 
-func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, p []byte) (_ http2Frame, err error) {
+func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, countError func(string), p []byte) (_ http2Frame, err error) {
        pp := &http2PushPromiseFrame{
                http2FrameHeader: fh,
        }
@@ -2582,6 +2625,7 @@ func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, p []byte) (_
                // with. If the stream identifier field specifies the value
                // 0x0, a recipient MUST respond with a connection error
                // (Section 5.4.1) of type PROTOCOL_ERROR.
+               countError("frame_pushpromise_zero_stream")
                return nil, http2ConnectionError(http2ErrCodeProtocol)
        }
        // The PUSH_PROMISE frame includes optional padding.
@@ -2589,18 +2633,21 @@ func http2parsePushPromise(_ *http2frameCache, fh http2FrameHeader, p []byte) (_
        var padLength uint8
        if fh.Flags.Has(http2FlagPushPromisePadded) {
                if p, padLength, err = http2readByte(p); err != nil {
+                       countError("frame_pushpromise_pad_short")
                        return
                }
        }
 
        p, pp.PromiseID, err = http2readUint32(p)
        if err != nil {
+               countError("frame_pushpromise_promiseid_short")
                return
        }
        pp.PromiseID = pp.PromiseID & (1<<31 - 1)
 
        if int(padLength) > len(p) {
                // like the DATA frame, error out if padding is longer than the body.
+               countError("frame_pushpromise_pad_too_big")
                return nil, http2ConnectionError(http2ErrCodeProtocol)
        }
        pp.headerFragBuf = p[:len(p)-int(padLength)]
@@ -3570,6 +3617,17 @@ type http2pipeBuffer interface {
        io.Reader
 }
 
+// setBuffer initializes the pipe buffer.
+// It has no effect if the pipe is already closed.
+func (p *http2pipe) setBuffer(b http2pipeBuffer) {
+       p.mu.Lock()
+       defer p.mu.Unlock()
+       if p.err != nil || p.breakErr != nil {
+               return
+       }
+       p.b = b
+}
+
 func (p *http2pipe) Len() int {
        p.mu.Lock()
        defer p.mu.Unlock()
@@ -3786,6 +3844,12 @@ type http2Server struct {
        // If nil, a default scheduler is chosen.
        NewWriteScheduler func() http2WriteScheduler
 
+       // CountError, if non-nil, is called on HTTP/2 server errors.
+       // It's intended to increment a metric for monitoring, such
+       // as an expvar or Prometheus metric.
+       // The errType consists of only ASCII word characters.
+       CountError func(errType string)
+
        // Internal state. This is a pointer (rather than embedded directly)
        // so that we don't embed a Mutex in this struct, which will make the
        // struct non-copyable, which might break some callers.
@@ -3915,16 +3979,12 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
 
        s.TLSConfig.PreferServerCipherSuites = true
 
-       haveNPN := false
-       for _, p := range s.TLSConfig.NextProtos {
-               if p == http2NextProtoTLS {
-                       haveNPN = true
-                       break
-               }
-       }
-       if !haveNPN {
+       if !http2strSliceContains(s.TLSConfig.NextProtos, http2NextProtoTLS) {
                s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, http2NextProtoTLS)
        }
+       if !http2strSliceContains(s.TLSConfig.NextProtos, "http/1.1") {
+               s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "http/1.1")
+       }
 
        if s.TLSNextProto == nil {
                s.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
@@ -4065,6 +4125,9 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
        sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
 
        fr := http2NewFramer(sc.bw, c)
+       if s.CountError != nil {
+               fr.countError = s.CountError
+       }
        fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
        fr.MaxHeaderListSize = sc.maxHeaderListSize()
        fr.SetMaxReadFrameSize(s.maxReadFrameSize())
@@ -4479,7 +4542,7 @@ func (sc *http2serverConn) serve() {
        })
        sc.unackedSettings++
 
-       // Each connection starts with intialWindowSize inflow tokens.
+       // Each connection starts with initialWindowSize inflow tokens.
        // If a higher value is configured, we add more tokens.
        if diff := sc.srv.initialConnRecvWindowSize() - http2initialWindowSize; diff > 0 {
                sc.sendWindowUpdate(nil, int(diff))
@@ -4519,6 +4582,15 @@ func (sc *http2serverConn) serve() {
                case res := <-sc.wroteFrameCh:
                        sc.wroteFrame(res)
                case res := <-sc.readFrameCh:
+                       // Process any written frames before reading new frames from the client since a
+                       // written frame could have triggered a new stream to be started.
+                       if sc.writingFrameAsync {
+                               select {
+                               case wroteRes := <-sc.wroteFrameCh:
+                                       sc.wroteFrame(wroteRes)
+                               default:
+                               }
+                       }
                        if !sc.processFrameFromReader(res) {
                                return
                        }
@@ -5055,7 +5127,7 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
        // First frame received must be SETTINGS.
        if !sc.sawFirstSettings {
                if _, ok := f.(*http2SettingsFrame); !ok {
-                       return http2ConnectionError(http2ErrCodeProtocol)
+                       return sc.countError("first_settings", http2ConnectionError(http2ErrCodeProtocol))
                }
                sc.sawFirstSettings = true
        }
@@ -5080,7 +5152,7 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
        case *http2PushPromiseFrame:
                // A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
                // frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("push_promise", http2ConnectionError(http2ErrCodeProtocol))
        default:
                sc.vlogf("http2: server ignoring frame: %v", f.Header())
                return nil
@@ -5100,7 +5172,7 @@ func (sc *http2serverConn) processPing(f *http2PingFrame) error {
                // identifier field value other than 0x0, the recipient MUST
                // respond with a connection error (Section 5.4.1) of type
                // PROTOCOL_ERROR."
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("ping_on_stream", http2ConnectionError(http2ErrCodeProtocol))
        }
        if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
                return nil
@@ -5119,7 +5191,7 @@ func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error
                        // or PRIORITY on a stream in this state MUST be
                        // treated as a connection error (Section 5.4.1) of
                        // type PROTOCOL_ERROR."
-                       return http2ConnectionError(http2ErrCodeProtocol)
+                       return sc.countError("stream_idle", http2ConnectionError(http2ErrCodeProtocol))
                }
                if st == nil {
                        // "WINDOW_UPDATE can be sent by a peer that has sent a
@@ -5130,7 +5202,7 @@ func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error
                        return nil
                }
                if !st.flow.add(int32(f.Increment)) {
-                       return http2streamError(f.StreamID, http2ErrCodeFlowControl)
+                       return sc.countError("bad_flow", http2streamError(f.StreamID, http2ErrCodeFlowControl))
                }
        default: // connection-level flow control
                if !sc.flow.add(int32(f.Increment)) {
@@ -5151,7 +5223,7 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
                // identifying an idle stream is received, the
                // recipient MUST treat this as a connection error
                // (Section 5.4.1) of type PROTOCOL_ERROR.
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("reset_idle_stream", http2ConnectionError(http2ErrCodeProtocol))
        }
        if st != nil {
                st.cancelCtx()
@@ -5203,7 +5275,7 @@ func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
                        // Why is the peer ACKing settings we never sent?
                        // The spec doesn't mention this case, but
                        // hang up on them anyway.
-                       return http2ConnectionError(http2ErrCodeProtocol)
+                       return sc.countError("ack_mystery", http2ConnectionError(http2ErrCodeProtocol))
                }
                return nil
        }
@@ -5211,7 +5283,7 @@ func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
                // This isn't actually in the spec, but hang up on
                // suspiciously large settings frames or those with
                // duplicate entries.
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("settings_big_or_dups", http2ConnectionError(http2ErrCodeProtocol))
        }
        if err := f.ForeachSetting(sc.processSetting); err != nil {
                return err
@@ -5278,7 +5350,7 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
                        // control window to exceed the maximum size as a
                        // connection error (Section 5.4.1) of type
                        // FLOW_CONTROL_ERROR."
-                       return http2ConnectionError(http2ErrCodeFlowControl)
+                       return sc.countError("setting_win_size", http2ConnectionError(http2ErrCodeFlowControl))
                }
        }
        return nil
@@ -5311,7 +5383,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
                // or PRIORITY on a stream in this state MUST be
                // treated as a connection error (Section 5.4.1) of
                // type PROTOCOL_ERROR."
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("data_on_idle", http2ConnectionError(http2ErrCodeProtocol))
        }
 
        // "If a DATA frame is received whose stream is not in "open"
@@ -5328,7 +5400,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
                // and return any flow control bytes since we're not going
                // to consume them.
                if sc.inflow.available() < int32(f.Length) {
-                       return http2streamError(id, http2ErrCodeFlowControl)
+                       return sc.countError("data_flow", http2streamError(id, http2ErrCodeFlowControl))
                }
                // Deduct the flow control from inflow, since we're
                // going to immediately add it back in
@@ -5341,7 +5413,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
                        // Already have a stream error in flight. Don't send another.
                        return nil
                }
-               return http2streamError(id, http2ErrCodeStreamClosed)
+               return sc.countError("closed", http2streamError(id, http2ErrCodeStreamClosed))
        }
        if st.body == nil {
                panic("internal error: should have a body in this state")
@@ -5353,12 +5425,12 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
                // RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
                // value of a content-length header field does not equal the sum of the
                // DATA frame payload lengths that form the body.
-               return http2streamError(id, http2ErrCodeProtocol)
+               return sc.countError("send_too_much", http2streamError(id, http2ErrCodeProtocol))
        }
        if f.Length > 0 {
                // Check whether the client has flow control quota.
                if st.inflow.available() < int32(f.Length) {
-                       return http2streamError(id, http2ErrCodeFlowControl)
+                       return sc.countError("flow_on_data_length", http2streamError(id, http2ErrCodeFlowControl))
                }
                st.inflow.take(int32(f.Length))
 
@@ -5366,7 +5438,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
                        wrote, err := st.body.Write(data)
                        if err != nil {
                                sc.sendWindowUpdate(nil, int(f.Length)-wrote)
-                               return http2streamError(id, http2ErrCodeStreamClosed)
+                               return sc.countError("body_write_err", http2streamError(id, http2ErrCodeStreamClosed))
                        }
                        if wrote != len(data) {
                                panic("internal error: bad Writer")
@@ -5452,7 +5524,7 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
        // stream identifier MUST respond with a connection error
        // (Section 5.4.1) of type PROTOCOL_ERROR.
        if id%2 != 1 {
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("headers_even", http2ConnectionError(http2ErrCodeProtocol))
        }
        // A HEADERS frame can be used to create a new stream or
        // send a trailer for an open one. If we already have a stream
@@ -5469,7 +5541,7 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
                // this state, it MUST respond with a stream error (Section 5.4.2) of
                // type STREAM_CLOSED.
                if st.state == http2stateHalfClosedRemote {
-                       return http2streamError(id, http2ErrCodeStreamClosed)
+                       return sc.countError("headers_half_closed", http2streamError(id, http2ErrCodeStreamClosed))
                }
                return st.processTrailerHeaders(f)
        }
@@ -5480,7 +5552,7 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
        // receives an unexpected stream identifier MUST respond with
        // a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
        if id <= sc.maxClientStreamID {
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("stream_went_down", http2ConnectionError(http2ErrCodeProtocol))
        }
        sc.maxClientStreamID = id
 
@@ -5497,14 +5569,14 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
        if sc.curClientStreams+1 > sc.advMaxStreams {
                if sc.unackedSettings == 0 {
                        // They should know better.
-                       return http2streamError(id, http2ErrCodeProtocol)
+                       return sc.countError("over_max_streams", http2streamError(id, http2ErrCodeProtocol))
                }
                // Assume it's a network race, where they just haven't
                // received our last SETTINGS update. But actually
                // this can't happen yet, because we don't yet provide
                // a way for users to adjust server parameters at
                // runtime.
-               return http2streamError(id, http2ErrCodeRefusedStream)
+               return sc.countError("over_max_streams_race", http2streamError(id, http2ErrCodeRefusedStream))
        }
 
        initialState := http2stateOpen
@@ -5514,7 +5586,7 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
        st := sc.newStream(id, 0, initialState)
 
        if f.HasPriority() {
-               if err := http2checkPriority(f.StreamID, f.Priority); err != nil {
+               if err := sc.checkPriority(f.StreamID, f.Priority); err != nil {
                        return err
                }
                sc.writeSched.AdjustStream(st.id, f.Priority)
@@ -5558,15 +5630,15 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
        sc := st.sc
        sc.serveG.check()
        if st.gotTrailerHeader {
-               return http2ConnectionError(http2ErrCodeProtocol)
+               return sc.countError("dup_trailers", http2ConnectionError(http2ErrCodeProtocol))
        }
        st.gotTrailerHeader = true
        if !f.StreamEnded() {
-               return http2streamError(st.id, http2ErrCodeProtocol)
+               return sc.countError("trailers_not_ended", http2streamError(st.id, http2ErrCodeProtocol))
        }
 
        if len(f.PseudoFields()) > 0 {
-               return http2streamError(st.id, http2ErrCodeProtocol)
+               return sc.countError("trailers_pseudo", http2streamError(st.id, http2ErrCodeProtocol))
        }
        if st.trailer != nil {
                for _, hf := range f.RegularFields() {
@@ -5575,7 +5647,7 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
                                // TODO: send more details to the peer somehow. But http2 has
                                // no way to send debug data at a stream level. Discuss with
                                // HTTP folk.
-                               return http2streamError(st.id, http2ErrCodeProtocol)
+                               return sc.countError("trailers_bogus", http2streamError(st.id, http2ErrCodeProtocol))
                        }
                        st.trailer[key] = append(st.trailer[key], hf.Value)
                }
@@ -5584,13 +5656,13 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
        return nil
 }
 
-func http2checkPriority(streamID uint32, p http2PriorityParam) error {
+func (sc *http2serverConn) checkPriority(streamID uint32, p http2PriorityParam) error {
        if streamID == p.StreamDep {
                // Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat
                // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
                // Section 5.3.3 says that a stream can depend on one of its dependencies,
                // so it's only self-dependencies that are forbidden.
-               return http2streamError(streamID, http2ErrCodeProtocol)
+               return sc.countError("priority", http2streamError(streamID, http2ErrCodeProtocol))
        }
        return nil
 }
@@ -5599,7 +5671,7 @@ func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
        if sc.inGoAway {
                return nil
        }
-       if err := http2checkPriority(f.StreamID, f.http2PriorityParam); err != nil {
+       if err := sc.checkPriority(f.StreamID, f.http2PriorityParam); err != nil {
                return err
        }
        sc.writeSched.AdjustStream(f.StreamID, f.http2PriorityParam)
@@ -5656,7 +5728,7 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
        isConnect := rp.method == "CONNECT"
        if isConnect {
                if rp.path != "" || rp.scheme != "" || rp.authority == "" {
-                       return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
+                       return nil, nil, sc.countError("bad_connect", http2streamError(f.StreamID, http2ErrCodeProtocol))
                }
        } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
                // See 8.1.2.6 Malformed Requests and Responses:
@@ -5669,13 +5741,13 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
                // "All HTTP/2 requests MUST include exactly one valid
                // value for the :method, :scheme, and :path
                // pseudo-header fields"
-               return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
+               return nil, nil, sc.countError("bad_path_method", http2streamError(f.StreamID, http2ErrCodeProtocol))
        }
 
        bodyOpen := !f.StreamEnded()
        if rp.method == "HEAD" && bodyOpen {
                // HEAD requests can't have bodies
-               return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
+               return nil, nil, sc.countError("head_body", http2streamError(f.StreamID, http2ErrCodeProtocol))
        }
 
        rp.header = make(Header)
@@ -5758,7 +5830,7 @@ func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2re
                var err error
                url_, err = url.ParseRequestURI(rp.path)
                if err != nil {
-                       return nil, nil, http2streamError(st.id, http2ErrCodeProtocol)
+                       return nil, nil, sc.countError("bad_path", http2streamError(st.id, http2ErrCodeProtocol))
                }
                requestURI = rp.path
        }
@@ -6642,6 +6714,34 @@ func http2h1ServerKeepAlivesDisabled(hs *Server) bool {
        return false
 }
 
+func (sc *http2serverConn) countError(name string, err error) error {
+       if sc == nil || sc.srv == nil {
+               return err
+       }
+       f := sc.srv.CountError
+       if f == nil {
+               return err
+       }
+       var typ string
+       var code http2ErrCode
+       switch e := err.(type) {
+       case http2ConnectionError:
+               typ = "conn"
+               code = http2ErrCode(e)
+       case http2StreamError:
+               typ = "stream"
+               code = http2ErrCode(e.Code)
+       default:
+               return err
+       }
+       codeStr := http2errCodeName[code]
+       if codeStr == "" {
+               codeStr = strconv.Itoa(int(code))
+       }
+       f(fmt.Sprintf("%s_%s_%s", typ, codeStr, name))
+       return err
+}
+
 const (
        // transportDefaultConnFlow is how many connection-level flow control
        // tokens we give the server at start-up, past the default 64k.
@@ -6657,6 +6757,15 @@ const (
        http2transportDefaultStreamMinRefresh = 4 << 10
 
        http2defaultUserAgent = "Go-http-client/2.0"
+
+       // initialMaxConcurrentStreams is a connections maxConcurrentStreams until
+       // it's received servers initial SETTINGS frame, which corresponds with the
+       // spec's minimum recommended value.
+       http2initialMaxConcurrentStreams = 100
+
+       // defaultMaxConcurrentStreams is a connections default maxConcurrentStreams
+       // if the server doesn't include one in its initial SETTINGS frame.
+       http2defaultMaxConcurrentStreams = 1000
 )
 
 // Transport is an HTTP/2 Transport.
@@ -6727,6 +6836,12 @@ type http2Transport struct {
        // Defaults to 15s.
        PingTimeout time.Duration
 
+       // CountError, if non-nil, is called on HTTP/2 transport errors.
+       // It's intended to increment a metric for monitoring, such
+       // as an expvar or Prometheus metric.
+       // The errType consists of only ASCII word characters.
+       CountError func(errType string)
+
        // t1, if non-nil, is the standard library Transport using
        // this transport. Its settings are used (but not its
        // RoundTrip method, etc).
@@ -6833,11 +6948,12 @@ func (t *http2Transport) initConnPool() {
 // ClientConn is the state of a single HTTP/2 client connection to an
 // HTTP/2 server.
 type http2ClientConn struct {
-       t         *http2Transport
-       tconn     net.Conn             // usually *tls.Conn, except specialized impls
-       tlsState  *tls.ConnectionState // nil only for specialized impls
-       reused    uint32               // whether conn is being reused; atomic
-       singleUse bool                 // whether being used for a single http.Request
+       t             *http2Transport
+       tconn         net.Conn             // usually *tls.Conn, except specialized impls
+       tlsState      *tls.ConnectionState // nil only for specialized impls
+       reused        uint32               // whether conn is being reused; atomic
+       singleUse     bool                 // whether being used for a single http.Request
+       getConnCalled bool                 // used by clientConnPool
 
        // readLoop goroutine fields:
        readerDone chan struct{} // closed on error
@@ -6850,32 +6966,41 @@ type http2ClientConn struct {
        cond            *sync.Cond // hold mu; broadcast on flow/closed changes
        flow            http2flow  // our conn-level flow control quota (cs.flow is per stream)
        inflow          http2flow  // peer's conn-level flow control
+       doNotReuse      bool       // whether conn is marked to not be reused for any future requests
        closing         bool
        closed          bool
+       seenSettings    bool                          // true if we've seen a settings frame, false otherwise
        wantSettingsAck bool                          // we sent a SETTINGS frame and haven't heard back
        goAway          *http2GoAwayFrame             // if non-nil, the GoAwayFrame we received
        goAwayDebug     string                        // goAway frame's debug data, retained as a string
        streams         map[uint32]*http2clientStream // client-initiated
+       streamsReserved int                           // incr by ReserveNewRequest; decr on RoundTrip
        nextStreamID    uint32
        pendingRequests int                       // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams
        pings           map[[8]byte]chan struct{} // in flight ping data to notification channel
-       bw              *bufio.Writer
        br              *bufio.Reader
-       fr              *http2Framer
        lastActive      time.Time
        lastIdle        time.Time // time last idle
-       // Settings from peer: (also guarded by mu)
+       // Settings from peer: (also guarded by wmu)
        maxFrameSize          uint32
        maxConcurrentStreams  uint32
        peerMaxHeaderListSize uint64
        initialWindowSize     uint32
 
-       hbuf    bytes.Buffer // HPACK encoder writes into this
-       henc    *hpack.Encoder
-       freeBuf [][]byte
+       // reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
+       // Write to reqHeaderMu to lock it, read from it to unlock.
+       // Lock reqmu BEFORE mu or wmu.
+       reqHeaderMu chan struct{}
 
-       wmu  sync.Mutex // held while writing; acquire AFTER mu if holding both
-       werr error      // first write error that has occurred
+       // wmu is held while writing.
+       // Acquire BEFORE mu when holding both, to avoid blocking mu on network writes.
+       // Only acquire both at the same time when changing peer settings.
+       wmu  sync.Mutex
+       bw   *bufio.Writer
+       fr   *http2Framer
+       werr error        // first write error that has occurred
+       hbuf bytes.Buffer // HPACK encoder writes into this
+       henc *hpack.Encoder
 }
 
 // clientStream is the state for a single HTTP/2 stream. One of these
@@ -6885,52 +7010,42 @@ type http2clientStream struct {
        req           *Request
        trace         *httptrace.ClientTrace // or nil
        ID            uint32
-       resc          chan http2resAndError
        bufPipe       http2pipe // buffered pipe with the flow-controlled response payload
-       startedWrite  bool      // started request body write; guarded by cc.mu
        requestedGzip bool
-       on100         func() // optional code to run if get a 100 continue response
+
+       abortOnce sync.Once
+       abort     chan struct{} // closed to signal stream should end immediately
+       abortErr  error         // set if abort is closed
+
+       peerClosed chan struct{} // closed when the peer sends an END_STREAM flag
+       donec      chan struct{} // closed after the stream is in the closed state
+       on100      chan struct{} // buffered; written to if a 100 is received
+
+       respHeaderRecv chan struct{} // closed when headers are received
+       res            *Response     // set if respHeaderRecv is closed
 
        flow        http2flow // guarded by cc.mu
        inflow      http2flow // guarded by cc.mu
        bytesRemain int64     // -1 means unknown; owned by transportResponseBody.Read
        readErr     error     // sticky read error; owned by transportResponseBody.Read
        stopReqBody error     // if non-nil, stop writing req body; guarded by cc.mu
-       didReset    bool      // whether we sent a RST_STREAM to the server; guarded by cc.mu
 
-       peerReset chan struct{} // closed on peer reset
-       resetErr  error         // populated before peerReset is closed
-
-       done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
+       // owned by writeRequest:
+       sentEndStream bool // sent an END_STREAM flag to the peer
+       sentHeaders   bool
 
        // owned by clientConnReadLoop:
        firstByte    bool  // got the first response byte
        pastHeaders  bool  // got first MetaHeadersFrame (actual headers)
        pastTrailers bool  // got optional second MetaHeadersFrame (trailers)
        num1xx       uint8 // number of 1xx responses seen
+       readClosed   bool  // peer sent an END_STREAM flag
+       readAborted  bool  // read loop reset the stream
 
        trailer    Header  // accumulated trailers
        resTrailer *Header // client's Response.Trailer
 }
 
-// awaitRequestCancel waits for the user to cancel a request or for the done
-// channel to be signaled. A non-nil error is returned only if the request was
-// canceled.
-func http2awaitRequestCancel(req *Request, done <-chan struct{}) error {
-       ctx := req.Context()
-       if req.Cancel == nil && ctx.Done() == nil {
-               return nil
-       }
-       select {
-       case <-req.Cancel:
-               return http2errRequestCanceled
-       case <-ctx.Done():
-               return ctx.Err()
-       case <-done:
-               return nil
-       }
-}
-
 var http2got1xxFuncForTests func(int, textproto.MIMEHeader) error
 
 // get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func,
@@ -6942,58 +7057,34 @@ func (cs *http2clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) e
        return http2traceGot1xxResponseFunc(cs.trace)
 }
 
-// awaitRequestCancel waits for the user to cancel a request, its context to
-// expire, or for the request to be done (any way it might be removed from the
-// cc.streams map: peer reset, successful completion, TCP connection breakage,
-// etc). If the request is canceled, then cs will be canceled and closed.
-func (cs *http2clientStream) awaitRequestCancel(req *Request) {
-       if err := http2awaitRequestCancel(req, cs.done); err != nil {
-               cs.cancelStream()
-               cs.bufPipe.CloseWithError(err)
-       }
-}
-
-func (cs *http2clientStream) cancelStream() {
-       cc := cs.cc
-       cc.mu.Lock()
-       didReset := cs.didReset
-       cs.didReset = true
-       cc.mu.Unlock()
-
-       if !didReset {
-               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
-               cc.forgetStreamID(cs.ID)
-       }
+func (cs *http2clientStream) abortStream(err error) {
+       cs.cc.mu.Lock()
+       defer cs.cc.mu.Unlock()
+       cs.abortStreamLocked(err)
 }
 
-// checkResetOrDone reports any error sent in a RST_STREAM frame by the
-// server, or errStreamClosed if the stream is complete.
-func (cs *http2clientStream) checkResetOrDone() error {
-       select {
-       case <-cs.peerReset:
-               return cs.resetErr
-       case <-cs.done:
-               return http2errStreamClosed
-       default:
-               return nil
+func (cs *http2clientStream) abortStreamLocked(err error) {
+       cs.abortOnce.Do(func() {
+               cs.abortErr = err
+               close(cs.abort)
+       })
+       // TODO(dneil): Clean up tests where cs.cc.cond is nil.
+       if cs.cc.cond != nil {
+               // Wake up writeRequestBody if it is waiting on flow control.
+               cs.cc.cond.Broadcast()
        }
 }
 
-func (cs *http2clientStream) getStartedWrite() bool {
-       cc := cs.cc
-       cc.mu.Lock()
-       defer cc.mu.Unlock()
-       return cs.startedWrite
-}
-
 func (cs *http2clientStream) abortRequestBodyWrite(err error) {
        if err == nil {
                panic("nil error")
        }
        cc := cs.cc
        cc.mu.Lock()
-       cs.stopReqBody = err
-       cc.cond.Broadcast()
+       if cs.stopReqBody == nil {
+               cs.stopReqBody = err
+               cc.cond.Broadcast()
+       }
        cc.mu.Unlock()
 }
 
@@ -7082,9 +7173,9 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res
                }
                reused := !atomic.CompareAndSwapUint32(&cc.reused, 0, 1)
                http2traceGotConn(req, cc, reused)
-               res, gotErrAfterReqBodyWrite, err := cc.roundTrip(req)
+               res, err := cc.RoundTrip(req)
                if err != nil && retry <= 6 {
-                       if req, err = http2shouldRetryRequest(req, err, gotErrAfterReqBodyWrite); err == nil {
+                       if req, err = http2shouldRetryRequest(req, err); err == nil {
                                // After the first retry, do exponential backoff with 10% jitter.
                                if retry == 0 {
                                        continue
@@ -7095,7 +7186,7 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res
                                case <-time.After(time.Second * time.Duration(backoff)):
                                        continue
                                case <-req.Context().Done():
-                                       return nil, req.Context().Err()
+                                       err = req.Context().Err()
                                }
                        }
                }
@@ -7126,7 +7217,7 @@ var (
 // response headers. It is always called with a non-nil error.
 // It returns either a request to retry (either the same request, or a
 // modified clone), or an error if the request can't be replayed.
-func http2shouldRetryRequest(req *Request, err error, afterBodyWrite bool) (*Request, error) {
+func http2shouldRetryRequest(req *Request, err error) (*Request, error) {
        if !http2canRetryError(err) {
                return nil, err
        }
@@ -7139,7 +7230,6 @@ func http2shouldRetryRequest(req *Request, err error, afterBodyWrite bool) (*Req
        // If the request body can be reset back to its original
        // state via the optional req.GetBody, do that.
        if req.GetBody != nil {
-               // TODO: consider a req.Body.Close here? or audit that all caller paths do?
                body, err := req.GetBody()
                if err != nil {
                        return nil, err
@@ -7151,10 +7241,8 @@ func http2shouldRetryRequest(req *Request, err error, afterBodyWrite bool) (*Req
 
        // The Request.Body can't reset back to the beginning, but we
        // don't seem to have started to read from it yet, so reuse
-       // the request directly. The "afterBodyWrite" means the
-       // bodyWrite process has started, which becomes true before
-       // the first Read.
-       if !afterBodyWrite {
+       // the request directly.
+       if err == http2errClientConnUnusable {
                return req, nil
        }
 
@@ -7166,6 +7254,10 @@ func http2canRetryError(err error) bool {
                return true
        }
        if se, ok := err.(http2StreamError); ok {
+               if se.Code == http2ErrCodeProtocol && se.Cause == http2errFromPeer {
+                       // See golang/go#47635, golang/go#42777
+                       return true
+               }
                return se.Code == http2ErrCodeRefusedStream
        }
        return false
@@ -7240,14 +7332,15 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
                tconn:                 c,
                readerDone:            make(chan struct{}),
                nextStreamID:          1,
-               maxFrameSize:          16 << 10,           // spec default
-               initialWindowSize:     65535,              // spec default
-               maxConcurrentStreams:  1000,               // "infinite", per spec. 1000 seems good enough.
-               peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead.
+               maxFrameSize:          16 << 10,                         // spec default
+               initialWindowSize:     65535,                            // spec default
+               maxConcurrentStreams:  http2initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings.
+               peerMaxHeaderListSize: 0xffffffffffffffff,               // "infinite", per spec. Use 2^64-1 instead.
                streams:               make(map[uint32]*http2clientStream),
                singleUse:             singleUse,
                wantSettingsAck:       true,
                pings:                 make(map[[8]byte]chan struct{}),
+               reqHeaderMu:           make(chan struct{}, 1),
        }
        if d := t.idleConnTimeout(); d != 0 {
                cc.idleTimeout = d
@@ -7265,6 +7358,9 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
        cc.bw = bufio.NewWriter(http2stickyErrWriter{c, &cc.werr})
        cc.br = bufio.NewReader(c)
        cc.fr = http2NewFramer(cc.bw, cc.br)
+       if t.CountError != nil {
+               cc.fr.countError = t.CountError
+       }
        cc.fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
        cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
 
@@ -7317,6 +7413,13 @@ func (cc *http2ClientConn) healthCheck() {
        }
 }
 
+// SetDoNotReuse marks cc as not reusable for future HTTP requests.
+func (cc *http2ClientConn) SetDoNotReuse() {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       cc.doNotReuse = true
+}
+
 func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
        cc.mu.Lock()
        defer cc.mu.Unlock()
@@ -7334,27 +7437,39 @@ func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
        last := f.LastStreamID
        for streamID, cs := range cc.streams {
                if streamID > last {
-                       select {
-                       case cs.resc <- http2resAndError{err: http2errClientConnGotGoAway}:
-                       default:
-                       }
+                       cs.abortStreamLocked(http2errClientConnGotGoAway)
                }
        }
 }
 
 // CanTakeNewRequest reports whether the connection can take a new request,
 // meaning it has not been closed or received or sent a GOAWAY.
+//
+// If the caller is going to immediately make a new request on this
+// connection, use ReserveNewRequest instead.
 func (cc *http2ClientConn) CanTakeNewRequest() bool {
        cc.mu.Lock()
        defer cc.mu.Unlock()
        return cc.canTakeNewRequestLocked()
 }
 
+// ReserveNewRequest is like CanTakeNewRequest but also reserves a
+// concurrent stream in cc. The reservation is decremented on the
+// next call to RoundTrip.
+func (cc *http2ClientConn) ReserveNewRequest() bool {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       if st := cc.idleStateLocked(); !st.canTakeNewRequest {
+               return false
+       }
+       cc.streamsReserved++
+       return true
+}
+
 // clientConnIdleState describes the suitability of a client
 // connection to initiate a new RoundTrip request.
 type http2clientConnIdleState struct {
        canTakeNewRequest bool
-       freshConn         bool // whether it's unused by any previous request
 }
 
 func (cc *http2ClientConn) idleState() http2clientConnIdleState {
@@ -7375,13 +7490,13 @@ func (cc *http2ClientConn) idleStateLocked() (st http2clientConnIdleState) {
                // writing it.
                maxConcurrentOkay = true
        } else {
-               maxConcurrentOkay = int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams)
+               maxConcurrentOkay = int64(len(cc.streams)+cc.streamsReserved+1) <= int64(cc.maxConcurrentStreams)
        }
 
        st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && maxConcurrentOkay &&
+               !cc.doNotReuse &&
                int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
                !cc.tooIdleLocked()
-       st.freshConn = cc.nextStreamID == 1 && st.canTakeNewRequest
        return
 }
 
@@ -7412,7 +7527,7 @@ func (cc *http2ClientConn) onIdleTimeout() {
 
 func (cc *http2ClientConn) closeIfIdle() {
        cc.mu.Lock()
-       if len(cc.streams) > 0 {
+       if len(cc.streams) > 0 || cc.streamsReserved > 0 {
                cc.mu.Unlock()
                return
        }
@@ -7427,9 +7542,15 @@ func (cc *http2ClientConn) closeIfIdle() {
        cc.tconn.Close()
 }
 
+func (cc *http2ClientConn) isDoNotReuseAndIdle() bool {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       return cc.doNotReuse && len(cc.streams) == 0
+}
+
 var http2shutdownEnterWaitStateHook = func() {}
 
-// Shutdown gracefully close the client connection, waiting for running streams to complete.
+// Shutdown gracefully closes the client connection, waiting for running streams to complete.
 func (cc *http2ClientConn) Shutdown(ctx context.Context) error {
        if err := cc.sendGoAway(); err != nil {
                return err
@@ -7468,15 +7589,18 @@ func (cc *http2ClientConn) Shutdown(ctx context.Context) error {
 
 func (cc *http2ClientConn) sendGoAway() error {
        cc.mu.Lock()
-       defer cc.mu.Unlock()
-       cc.wmu.Lock()
-       defer cc.wmu.Unlock()
-       if cc.closing {
+       closing := cc.closing
+       cc.closing = true
+       maxStreamID := cc.nextStreamID
+       cc.mu.Unlock()
+       if closing {
                // GOAWAY sent already
                return nil
        }
+
+       cc.wmu.Lock()
+       defer cc.wmu.Unlock()
        // Send a graceful shutdown frame to server
-       maxStreamID := cc.nextStreamID
        if err := cc.fr.WriteGoAway(maxStreamID, http2ErrCodeNo, nil); err != nil {
                return err
        }
@@ -7484,7 +7608,6 @@ func (cc *http2ClientConn) sendGoAway() error {
                return err
        }
        // Prevent new requests
-       cc.closing = true
        return nil
 }
 
@@ -7492,17 +7615,12 @@ func (cc *http2ClientConn) sendGoAway() error {
 // err is sent to streams.
 func (cc *http2ClientConn) closeForError(err error) error {
        cc.mu.Lock()
+       cc.closed = true
+       for _, cs := range cc.streams {
+               cs.abortStreamLocked(err)
+       }
        defer cc.cond.Broadcast()
        defer cc.mu.Unlock()
-       for id, cs := range cc.streams {
-               select {
-               case cs.resc <- http2resAndError{err: err}:
-               default:
-               }
-               cs.bufPipe.CloseWithError(err)
-               delete(cc.streams, id)
-       }
-       cc.closed = true
        return cc.tconn.Close()
 }
 
@@ -7517,47 +7635,10 @@ func (cc *http2ClientConn) Close() error {
 // closes the client connection immediately. In-flight requests are interrupted.
 func (cc *http2ClientConn) closeForLostPing() error {
        err := errors.New("http2: client connection lost")
-       return cc.closeForError(err)
-}
-
-const http2maxAllocFrameSize = 512 << 10
-
-// frameBuffer returns a scratch buffer suitable for writing DATA frames.
-// They're capped at the min of the peer's max frame size or 512KB
-// (kinda arbitrarily), but definitely capped so we don't allocate 4GB
-// bufers.
-func (cc *http2ClientConn) frameScratchBuffer() []byte {
-       cc.mu.Lock()
-       size := cc.maxFrameSize
-       if size > http2maxAllocFrameSize {
-               size = http2maxAllocFrameSize
-       }
-       for i, buf := range cc.freeBuf {
-               if len(buf) >= int(size) {
-                       cc.freeBuf[i] = nil
-                       cc.mu.Unlock()
-                       return buf[:size]
-               }
-       }
-       cc.mu.Unlock()
-       return make([]byte, size)
-}
-
-func (cc *http2ClientConn) putFrameScratchBuffer(buf []byte) {
-       cc.mu.Lock()
-       defer cc.mu.Unlock()
-       const maxBufs = 4 // arbitrary; 4 concurrent requests per conn? investigate.
-       if len(cc.freeBuf) < maxBufs {
-               cc.freeBuf = append(cc.freeBuf, buf)
-               return
-       }
-       for i, old := range cc.freeBuf {
-               if old == nil {
-                       cc.freeBuf[i] = buf
-                       return
-               }
+       if f := cc.t.CountError; f != nil {
+               f("conn_close_lost_ping")
        }
-       // forget about it.
+       return cc.closeForError(err)
 }
 
 // errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
@@ -7621,37 +7702,132 @@ func http2actualContentLength(req *Request) int64 {
        return -1
 }
 
-func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
-       resp, _, err := cc.roundTrip(req)
-       return resp, err
+func (cc *http2ClientConn) decrStreamReservations() {
+       cc.mu.Lock()
+       defer cc.mu.Unlock()
+       cc.decrStreamReservationsLocked()
 }
 
-func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterReqBodyWrite bool, err error) {
-       if err := http2checkConnHeaders(req); err != nil {
-               return nil, false, err
+func (cc *http2ClientConn) decrStreamReservationsLocked() {
+       if cc.streamsReserved > 0 {
+               cc.streamsReserved--
        }
-       if cc.idleTimer != nil {
-               cc.idleTimer.Stop()
+}
+
+func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
+       ctx := req.Context()
+       cs := &http2clientStream{
+               cc:             cc,
+               req:            req,
+               trace:          httptrace.ContextClientTrace(req.Context()),
+               peerClosed:     make(chan struct{}),
+               abort:          make(chan struct{}),
+               respHeaderRecv: make(chan struct{}),
+               donec:          make(chan struct{}),
        }
+       go cs.doRequest()
 
-       trailers, err := http2commaSeparatedTrailers(req)
-       if err != nil {
-               return nil, false, err
+       waitDone := func() error {
+               select {
+               case <-cs.donec:
+                       return nil
+               case <-ctx.Done():
+                       return ctx.Err()
+               case <-req.Cancel:
+                       return http2errRequestCanceled
+               }
+       }
+
+       for {
+               select {
+               case <-cs.respHeaderRecv:
+                       res := cs.res
+                       if res.StatusCode > 299 {
+                               // On error or status code 3xx, 4xx, 5xx, etc abort any
+                               // ongoing write, assuming that the server doesn't care
+                               // about our request body. If the server replied with 1xx or
+                               // 2xx, however, then assume the server DOES potentially
+                               // want our body (e.g. full-duplex streaming:
+                               // golang.org/issue/13444). If it turns out the server
+                               // doesn't, they'll RST_STREAM us soon enough. This is a
+                               // heuristic to avoid adding knobs to Transport. Hopefully
+                               // we can keep it.
+                               cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
+                       }
+                       res.Request = req
+                       res.TLS = cc.tlsState
+                       if res.Body == http2noBody && http2actualContentLength(req) == 0 {
+                               // If there isn't a request or response body still being
+                               // written, then wait for the stream to be closed before
+                               // RoundTrip returns.
+                               if err := waitDone(); err != nil {
+                                       return nil, err
+                               }
+                       }
+                       return res, nil
+               case <-cs.abort:
+                       waitDone()
+                       return nil, cs.abortErr
+               case <-ctx.Done():
+                       return nil, ctx.Err()
+               case <-req.Cancel:
+                       return nil, http2errRequestCanceled
+               }
+       }
+}
+
+// doRequest runs for the duration of the request lifetime.
+//
+// It sends the request and performs post-request cleanup (closing Request.Body, etc.).
+func (cs *http2clientStream) doRequest() {
+       err := cs.writeRequest()
+       cs.cleanupWriteRequest(err)
+}
+
+// writeRequest sends a request.
+//
+// It returns nil after the request is written, the response read,
+// and the request stream is half-closed by the peer.
+//
+// It returns non-nil if the request ends otherwise.
+// If the returned error is StreamError, the error Code may be used in resetting the stream.
+func (cs *http2clientStream) writeRequest() (err error) {
+       cc := cs.cc
+       req := cs.req
+       ctx := req.Context()
+
+       if err := http2checkConnHeaders(cs.req); err != nil {
+               return err
+       }
+
+       // Acquire the new-request lock by writing to reqHeaderMu.
+       // This lock guards the critical section covering allocating a new stream ID
+       // (requires mu) and creating the stream (requires wmu).
+       if cc.reqHeaderMu == nil {
+               panic("RoundTrip on uninitialized ClientConn") // for tests
+       }
+       select {
+       case cc.reqHeaderMu <- struct{}{}:
+       case <-req.Cancel:
+               return http2errRequestCanceled
+       case <-ctx.Done():
+               return ctx.Err()
        }
-       hasTrailers := trailers != ""
 
        cc.mu.Lock()
-       if err := cc.awaitOpenSlotForRequest(req); err != nil {
+       if cc.idleTimer != nil {
+               cc.idleTimer.Stop()
+       }
+       cc.decrStreamReservationsLocked()
+       if err := cc.awaitOpenSlotForStreamLocked(cs); err != nil {
                cc.mu.Unlock()
-               return nil, false, err
+               <-cc.reqHeaderMu
+               return err
        }
-
-       body := req.Body
-       contentLen := http2actualContentLength(req)
-       hasBody := contentLen != 0
+       cc.addStreamLocked(cs) // assigns stream ID
+       cc.mu.Unlock()
 
        // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
-       var requestedGzip bool
        if !cc.t.disableCompression() &&
                req.Header.Get("Accept-Encoding") == "" &&
                req.Header.Get("Range") == "" &&
@@ -7668,195 +7844,218 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
                // We don't request gzip if the request is for a range, since
                // auto-decoding a portion of a gzipped document will just fail
                // anyway. See https://golang.org/issue/8923
-               requestedGzip = true
+               cs.requestedGzip = true
        }
 
-       // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
-       // sent by writeRequestBody below, along with any Trailers,
-       // again in form HEADERS{1}, CONTINUATION{0,})
-       hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen)
-       if err != nil {
-               cc.mu.Unlock()
-               return nil, false, err
+       continueTimeout := cc.t.expectContinueTimeout()
+       if continueTimeout != 0 &&
+               !httpguts.HeaderValuesContainsToken(
+                       cs.req.Header["Expect"],
+                       "100-continue") {
+               continueTimeout = 0
+               cs.on100 = make(chan struct{}, 1)
        }
 
-       cs := cc.newStream()
-       cs.req = req
-       cs.trace = httptrace.ContextClientTrace(req.Context())
-       cs.requestedGzip = requestedGzip
-       bodyWriter := cc.t.getBodyWriterState(cs, body)
-       cs.on100 = bodyWriter.on100
-
-       defer func() {
-               cc.wmu.Lock()
-               werr := cc.werr
-               cc.wmu.Unlock()
-               if werr != nil {
-                       cc.Close()
-               }
-       }()
-
-       cc.wmu.Lock()
-       endStream := !hasBody && !hasTrailers
-       werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
-       cc.wmu.Unlock()
-       http2traceWroteHeaders(cs.trace)
-       cc.mu.Unlock()
-
-       if werr != nil {
-               if hasBody {
-                       req.Body.Close() // per RoundTripper contract
-                       bodyWriter.cancel()
-               }
-               cc.forgetStreamID(cs.ID)
-               // Don't bother sending a RST_STREAM (our write already failed;
-               // no need to keep writing)
-               http2traceWroteRequest(cs.trace, werr)
-               return nil, false, werr
+       err = cs.encodeAndWriteHeaders()
+       <-cc.reqHeaderMu
+       if err != nil {
+               return err
        }
 
-       var respHeaderTimer <-chan time.Time
-       if hasBody {
-               bodyWriter.scheduleBodyWrite()
+       hasBody := http2actualContentLength(cs.req) != 0
+       if !hasBody {
+               cs.sentEndStream = true
        } else {
-               http2traceWroteRequest(cs.trace, nil)
-               if d := cc.responseHeaderTimeout(); d != 0 {
-                       timer := time.NewTimer(d)
-                       defer timer.Stop()
-                       respHeaderTimer = timer.C
+               if continueTimeout != 0 {
+                       http2traceWait100Continue(cs.trace)
+                       timer := time.NewTimer(continueTimeout)
+                       select {
+                       case <-timer.C:
+                               err = nil
+                       case <-cs.on100:
+                               err = nil
+                       case <-cs.abort:
+                               err = cs.abortErr
+                       case <-ctx.Done():
+                               err = ctx.Err()
+                       case <-req.Cancel:
+                               err = http2errRequestCanceled
+                       }
+                       timer.Stop()
+                       if err != nil {
+                               http2traceWroteRequest(cs.trace, err)
+                               return err
+                       }
                }
-       }
-
-       readLoopResCh := cs.resc
-       bodyWritten := false
-       ctx := req.Context()
 
-       handleReadLoopResponse := func(re http2resAndError) (*Response, bool, error) {
-               res := re.res
-               if re.err != nil || res.StatusCode > 299 {
-                       // On error or status code 3xx, 4xx, 5xx, etc abort any
-                       // ongoing write, assuming that the server doesn't care
-                       // about our request body. If the server replied with 1xx or
-                       // 2xx, however, then assume the server DOES potentially
-                       // want our body (e.g. full-duplex streaming:
-                       // golang.org/issue/13444). If it turns out the server
-                       // doesn't, they'll RST_STREAM us soon enough. This is a
-                       // heuristic to avoid adding knobs to Transport. Hopefully
-                       // we can keep it.
-                       bodyWriter.cancel()
-                       cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
-                       if hasBody && !bodyWritten {
-                               <-bodyWriter.resc
+               if err = cs.writeRequestBody(req.Body); err != nil {
+                       if err != http2errStopReqBodyWrite {
+                               http2traceWroteRequest(cs.trace, err)
+                               return err
                        }
+               } else {
+                       cs.sentEndStream = true
                }
-               if re.err != nil {
-                       cc.forgetStreamID(cs.ID)
-                       return nil, cs.getStartedWrite(), re.err
-               }
-               res.Request = req
-               res.TLS = cc.tlsState
-               return res, false, nil
        }
 
+       http2traceWroteRequest(cs.trace, err)
+
+       var respHeaderTimer <-chan time.Time
+       var respHeaderRecv chan struct{}
+       if d := cc.responseHeaderTimeout(); d != 0 {
+               timer := time.NewTimer(d)
+               defer timer.Stop()
+               respHeaderTimer = timer.C
+               respHeaderRecv = cs.respHeaderRecv
+       }
+       // Wait until the peer half-closes its end of the stream,
+       // or until the request is aborted (via context, error, or otherwise),
+       // whichever comes first.
        for {
                select {
-               case re := <-readLoopResCh:
-                       return handleReadLoopResponse(re)
+               case <-cs.peerClosed:
+                       return nil
                case <-respHeaderTimer:
-                       if !hasBody || bodyWritten {
-                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
-                       } else {
-                               bodyWriter.cancel()
-                               cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
-                               <-bodyWriter.resc
-                       }
-                       cc.forgetStreamID(cs.ID)
-                       return nil, cs.getStartedWrite(), http2errTimeout
+                       return http2errTimeout
+               case <-respHeaderRecv:
+                       respHeaderTimer = nil // keep waiting for END_STREAM
+               case <-cs.abort:
+                       return cs.abortErr
                case <-ctx.Done():
-                       if !hasBody || bodyWritten {
-                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
-                       } else {
-                               bodyWriter.cancel()
-                               cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
-                               <-bodyWriter.resc
-                       }
-                       cc.forgetStreamID(cs.ID)
-                       return nil, cs.getStartedWrite(), ctx.Err()
+                       return ctx.Err()
                case <-req.Cancel:
-                       if !hasBody || bodyWritten {
-                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+                       return http2errRequestCanceled
+               }
+       }
+}
+
+func (cs *http2clientStream) encodeAndWriteHeaders() error {
+       cc := cs.cc
+       req := cs.req
+       ctx := req.Context()
+
+       cc.wmu.Lock()
+       defer cc.wmu.Unlock()
+
+       // If the request was canceled while waiting for cc.mu, just quit.
+       select {
+       case <-cs.abort:
+               return cs.abortErr
+       case <-ctx.Done():
+               return ctx.Err()
+       case <-req.Cancel:
+               return http2errRequestCanceled
+       default:
+       }
+
+       // Encode headers.
+       //
+       // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
+       // sent by writeRequestBody below, along with any Trailers,
+       // again in form HEADERS{1}, CONTINUATION{0,})
+       trailers, err := http2commaSeparatedTrailers(cs.req)
+       if err != nil {
+               return err
+       }
+       hasTrailers := trailers != ""
+       contentLen := http2actualContentLength(cs.req)
+       hasBody := contentLen != 0
+       hdrs, err := cc.encodeHeaders(cs.req, cs.requestedGzip, trailers, contentLen)
+       if err != nil {
+               return err
+       }
+
+       // Write the request.
+       endStream := !hasBody && !hasTrailers
+       cs.sentHeaders = true
+       err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
+       http2traceWroteHeaders(cs.trace)
+       return err
+}
+
+// cleanupWriteRequest performs post-request tasks.
+//
+// If err (the result of writeRequest) is non-nil and the stream is not closed,
+// cleanupWriteRequest will send a reset to the peer.
+func (cs *http2clientStream) cleanupWriteRequest(err error) {
+       cc := cs.cc
+       req := cs.req
+
+       if cs.ID == 0 {
+               // We were canceled before creating the stream, so return our reservation.
+               cc.decrStreamReservations()
+       }
+
+       // TODO: write h12Compare test showing whether
+       // Request.Body is closed by the Transport,
+       // and in multiple cases: server replies <=299 and >299
+       // while still writing request body
+       if req.Body != nil {
+               if e := req.Body.Close(); err == nil {
+                       err = e
+               }
+       }
+
+       if err != nil && cs.sentEndStream {
+               // If the connection is closed immediately after the response is read,
+               // we may be aborted before finishing up here. If the stream was closed
+               // cleanly on both sides, there is no error.
+               select {
+               case <-cs.peerClosed:
+                       err = nil
+               default:
+               }
+       }
+       if err != nil {
+               cs.abortStream(err) // possibly redundant, but harmless
+               if cs.sentHeaders {
+                       if se, ok := err.(http2StreamError); ok {
+                               if se.Cause != http2errFromPeer {
+                                       cc.writeStreamReset(cs.ID, se.Code, err)
+                               }
                        } else {
-                               bodyWriter.cancel()
-                               cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
-                               <-bodyWriter.resc
-                       }
-                       cc.forgetStreamID(cs.ID)
-                       return nil, cs.getStartedWrite(), http2errRequestCanceled
-               case <-cs.peerReset:
-                       // processResetStream already removed the
-                       // stream from the streams map; no need for
-                       // forgetStreamID.
-                       return nil, cs.getStartedWrite(), cs.resetErr
-               case err := <-bodyWriter.resc:
-                       bodyWritten = true
-                       // Prefer the read loop's response, if available. Issue 16102.
-                       select {
-                       case re := <-readLoopResCh:
-                               return handleReadLoopResponse(re)
-                       default:
-                       }
-                       if err != nil {
-                               cc.forgetStreamID(cs.ID)
-                               return nil, cs.getStartedWrite(), err
-                       }
-                       if d := cc.responseHeaderTimeout(); d != 0 {
-                               timer := time.NewTimer(d)
-                               defer timer.Stop()
-                               respHeaderTimer = timer.C
+                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, err)
                        }
                }
+               cs.bufPipe.CloseWithError(err) // no-op if already closed
+       } else {
+               if cs.sentHeaders && !cs.sentEndStream {
+                       cc.writeStreamReset(cs.ID, http2ErrCodeNo, nil)
+               }
+               cs.bufPipe.CloseWithError(http2errRequestCanceled)
+       }
+       if cs.ID != 0 {
+               cc.forgetStreamID(cs.ID)
+       }
+       close(cs.donec)
+
+       cc.wmu.Lock()
+       werr := cc.werr
+       cc.wmu.Unlock()
+       if werr != nil {
+               cc.Close()
        }
 }
 
-// awaitOpenSlotForRequest waits until len(streams) < maxConcurrentStreams.
+// awaitOpenSlotForStream waits until len(streams) < maxConcurrentStreams.
 // Must hold cc.mu.
-func (cc *http2ClientConn) awaitOpenSlotForRequest(req *Request) error {
-       var waitingForConn chan struct{}
-       var waitingForConnErr error // guarded by cc.mu
+func (cc *http2ClientConn) awaitOpenSlotForStreamLocked(cs *http2clientStream) error {
        for {
                cc.lastActive = time.Now()
                if cc.closed || !cc.canTakeNewRequestLocked() {
-                       if waitingForConn != nil {
-                               close(waitingForConn)
-                       }
                        return http2errClientConnUnusable
                }
                cc.lastIdle = time.Time{}
-               if int64(len(cc.streams))+1 <= int64(cc.maxConcurrentStreams) {
-                       if waitingForConn != nil {
-                               close(waitingForConn)
-                       }
+               if int64(len(cc.streams)) < int64(cc.maxConcurrentStreams) {
                        return nil
                }
-               // Unfortunately, we cannot wait on a condition variable and channel at
-               // the same time, so instead, we spin up a goroutine to check if the
-               // request is canceled while we wait for a slot to open in the connection.
-               if waitingForConn == nil {
-                       waitingForConn = make(chan struct{})
-                       go func() {
-                               if err := http2awaitRequestCancel(req, waitingForConn); err != nil {
-                                       cc.mu.Lock()
-                                       waitingForConnErr = err
-                                       cc.cond.Broadcast()
-                                       cc.mu.Unlock()
-                               }
-                       }()
-               }
                cc.pendingRequests++
                cc.cond.Wait()
                cc.pendingRequests--
-               if waitingForConnErr != nil {
-                       return waitingForConnErr
+               select {
+               case <-cs.abort:
+                       return cs.abortErr
+               default:
                }
        }
 }
@@ -7883,10 +8082,6 @@ func (cc *http2ClientConn) writeHeaders(streamID uint32, endStream bool, maxFram
                        cc.fr.WriteContinuation(streamID, endHeaders, chunk)
                }
        }
-       // TODO(bradfitz): this Flush could potentially block (as
-       // could the WriteHeaders call(s) above), which means they
-       // wouldn't respond to Request.Cancel being readable. That's
-       // rare, but this should probably be in a goroutine.
        cc.bw.Flush()
        return cc.werr
 }
@@ -7902,32 +8097,59 @@ var (
        http2errReqBodyTooLong = errors.New("http2: request body larger than specified content length")
 )
 
-func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) {
+// frameScratchBufferLen returns the length of a buffer to use for
+// outgoing request bodies to read/write to/from.
+//
+// It returns max(1, min(peer's advertised max frame size,
+// Request.ContentLength+1, 512KB)).
+func (cs *http2clientStream) frameScratchBufferLen(maxFrameSize int) int {
+       const max = 512 << 10
+       n := int64(maxFrameSize)
+       if n > max {
+               n = max
+       }
+       if cl := http2actualContentLength(cs.req); cl != -1 && cl+1 < n {
+               // Add an extra byte past the declared content-length to
+               // give the caller's Request.Body io.Reader a chance to
+               // give us more bytes than they declared, so we can catch it
+               // early.
+               n = cl + 1
+       }
+       if n < 1 {
+               return 1
+       }
+       return int(n) // doesn't truncate; max is 512K
+}
+
+var http2bufPool sync.Pool // of *[]byte
+
+func (cs *http2clientStream) writeRequestBody(body io.Reader) (err error) {
        cc := cs.cc
        sentEnd := false // whether we sent the final DATA frame w/ END_STREAM
-       buf := cc.frameScratchBuffer()
-       defer cc.putFrameScratchBuffer(buf)
-
-       defer func() {
-               http2traceWroteRequest(cs.trace, err)
-               // TODO: write h12Compare test showing whether
-               // Request.Body is closed by the Transport,
-               // and in multiple cases: server replies <=299 and >299
-               // while still writing request body
-               cerr := bodyCloser.Close()
-               if err == nil {
-                       err = cerr
-               }
-       }()
 
        req := cs.req
        hasTrailers := req.Trailer != nil
        remainLen := http2actualContentLength(req)
        hasContentLen := remainLen != -1
 
+       cc.mu.Lock()
+       maxFrameSize := int(cc.maxFrameSize)
+       cc.mu.Unlock()
+
+       // Scratch buffer for reading into & writing from.
+       scratchLen := cs.frameScratchBufferLen(maxFrameSize)
+       var buf []byte
+       if bp, ok := http2bufPool.Get().(*[]byte); ok && len(*bp) >= scratchLen {
+               defer http2bufPool.Put(bp)
+               buf = *bp
+       } else {
+               buf = make([]byte, scratchLen)
+               defer http2bufPool.Put(&buf)
+       }
+
        var sawEOF bool
        for !sawEOF {
-               n, err := body.Read(buf[:len(buf)-1])
+               n, err := body.Read(buf[:len(buf)])
                if hasContentLen {
                        remainLen -= int64(n)
                        if remainLen == 0 && err == nil {
@@ -7938,13 +8160,13 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
                                // to send the END_STREAM bit early, double-check that we're actually
                                // at EOF. Subsequent reads should return (0, EOF) at this point.
                                // If either value is different, we return an error in one of two ways below.
+                               var scratch [1]byte
                                var n1 int
-                               n1, err = body.Read(buf[n:])
+                               n1, err = body.Read(scratch[:])
                                remainLen -= int64(n1)
                        }
                        if remainLen < 0 {
                                err = http2errReqBodyTooLong
-                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, err)
                                return err
                        }
                }
@@ -7952,7 +8174,6 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
                        sawEOF = true
                        err = nil
                } else if err != nil {
-                       cc.writeStreamReset(cs.ID, http2ErrCodeCancel, err)
                        return err
                }
 
@@ -7964,7 +8185,6 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
                        case err == http2errStopReqBodyWrite:
                                return err
                        case err == http2errStopReqBodyWriteAndCancel:
-                               cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
                                return err
                        case err != nil:
                                return err
@@ -7997,23 +8217,15 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
                return nil
        }
 
+       cc.wmu.Lock()
        var trls []byte
        if hasTrailers {
-               cc.mu.Lock()
                trls, err = cc.encodeTrailers(req)
-               cc.mu.Unlock()
                if err != nil {
-                       cc.writeStreamReset(cs.ID, http2ErrCodeInternal, err)
-                       cc.forgetStreamID(cs.ID)
+                       cc.wmu.Unlock()
                        return err
                }
        }
-
-       cc.mu.Lock()
-       maxFrameSize := int(cc.maxFrameSize)
-       cc.mu.Unlock()
-
-       cc.wmu.Lock()
        defer cc.wmu.Unlock()
 
        // Two ways to send END_STREAM: either with trailers, or
@@ -8035,6 +8247,8 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
 // if the stream is dead.
 func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {
        cc := cs.cc
+       req := cs.req
+       ctx := req.Context()
        cc.mu.Lock()
        defer cc.mu.Unlock()
        for {
@@ -8044,8 +8258,14 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er
                if cs.stopReqBody != nil {
                        return 0, cs.stopReqBody
                }
-               if err := cs.checkResetOrDone(); err != nil {
-                       return 0, err
+               select {
+               case <-cs.abort:
+                       return 0, cs.abortErr
+               case <-ctx.Done():
+                       return 0, ctx.Err()
+               case <-req.Cancel:
+                       return 0, http2errRequestCanceled
+               default:
                }
                if a := cs.flow.available(); a > 0 {
                        take := a
@@ -8063,9 +8283,14 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er
        }
 }
 
-// requires cc.mu be held.
+var http2errNilRequestURL = errors.New("http2: Request.URI is nil")
+
+// requires cc.wmu be held.
 func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
        cc.hbuf.Reset()
+       if req.URL == nil {
+               return nil, http2errNilRequestURL
+       }
 
        host := req.Host
        if host == "" {
@@ -8251,7 +8476,7 @@ func http2shouldSendReqContentLength(method string, contentLength int64) bool {
        }
 }
 
-// requires cc.mu be held.
+// requires cc.wmu be held.
 func (cc *http2ClientConn) encodeTrailers(req *Request) ([]byte, error) {
        cc.hbuf.Reset()
 
@@ -8296,51 +8521,51 @@ type http2resAndError struct {
 }
 
 // requires cc.mu be held.
-func (cc *http2ClientConn) newStream() *http2clientStream {
-       cs := &http2clientStream{
-               cc:        cc,
-               ID:        cc.nextStreamID,
-               resc:      make(chan http2resAndError, 1),
-               peerReset: make(chan struct{}),
-               done:      make(chan struct{}),
-       }
+func (cc *http2ClientConn) addStreamLocked(cs *http2clientStream) {
        cs.flow.add(int32(cc.initialWindowSize))
        cs.flow.setConnFlow(&cc.flow)
        cs.inflow.add(http2transportDefaultStreamFlow)
        cs.inflow.setConnFlow(&cc.inflow)
+       cs.ID = cc.nextStreamID
        cc.nextStreamID += 2
        cc.streams[cs.ID] = cs
-       return cs
+       if cs.ID == 0 {
+               panic("assigned stream ID 0")
+       }
 }
 
 func (cc *http2ClientConn) forgetStreamID(id uint32) {
-       cc.streamByID(id, true)
-}
-
-func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStream {
        cc.mu.Lock()
-       defer cc.mu.Unlock()
-       cs := cc.streams[id]
-       if andRemove && cs != nil && !cc.closed {
-               cc.lastActive = time.Now()
-               delete(cc.streams, id)
-               if len(cc.streams) == 0 && cc.idleTimer != nil {
-                       cc.idleTimer.Reset(cc.idleTimeout)
-                       cc.lastIdle = time.Now()
-               }
-               close(cs.done)
-               // Wake up checkResetOrDone via clientStream.awaitFlowControl and
-               // wake up RoundTrip if there is a pending request.
-               cc.cond.Broadcast()
+       slen := len(cc.streams)
+       delete(cc.streams, id)
+       if len(cc.streams) != slen-1 {
+               panic("forgetting unknown stream id")
+       }
+       cc.lastActive = time.Now()
+       if len(cc.streams) == 0 && cc.idleTimer != nil {
+               cc.idleTimer.Reset(cc.idleTimeout)
+               cc.lastIdle = time.Now()
+       }
+       // Wake up writeRequestBody via clientStream.awaitFlowControl and
+       // wake up RoundTrip if there is a pending request.
+       cc.cond.Broadcast()
+
+       closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives()
+       if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
+               if http2VerboseLogs {
+                       cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2)
+               }
+               cc.closed = true
+               defer cc.tconn.Close()
        }
-       return cs
+
+       cc.mu.Unlock()
 }
 
 // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
 type http2clientConnReadLoop struct {
-       _             http2incomparable
-       cc            *http2ClientConn
-       closeWhenIdle bool
+       _  http2incomparable
+       cc *http2ClientConn
 }
 
 // readLoop runs in its own goroutine and reads and dispatches frames.
@@ -8400,23 +8625,43 @@ func (rl *http2clientConnReadLoop) cleanup() {
        } else if err == io.EOF {
                err = io.ErrUnexpectedEOF
        }
+       cc.closed = true
        for _, cs := range cc.streams {
-               cs.bufPipe.CloseWithError(err) // no-op if already closed
-               select {
-               case cs.resc <- http2resAndError{err: err}:
-               default:
-               }
-               close(cs.done)
+               cs.abortStreamLocked(err)
        }
-       cc.closed = true
        cc.cond.Broadcast()
        cc.mu.Unlock()
 }
 
+// countReadFrameError calls Transport.CountError with a string
+// representing err.
+func (cc *http2ClientConn) countReadFrameError(err error) {
+       f := cc.t.CountError
+       if f == nil || err == nil {
+               return
+       }
+       if ce, ok := err.(http2ConnectionError); ok {
+               errCode := http2ErrCode(ce)
+               f(fmt.Sprintf("read_frame_conn_error_%s", errCode.stringToken()))
+               return
+       }
+       if errors.Is(err, io.EOF) {
+               f("read_frame_eof")
+               return
+       }
+       if errors.Is(err, io.ErrUnexpectedEOF) {
+               f("read_frame_unexpected_eof")
+               return
+       }
+       if errors.Is(err, http2ErrFrameTooLarge) {
+               f("read_frame_too_large")
+               return
+       }
+       f("read_frame_other")
+}
+
 func (rl *http2clientConnReadLoop) run() error {
        cc := rl.cc
-       rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse
-       gotReply := false // ever saw a HEADERS reply
        gotSettings := false
        readIdleTimeout := cc.t.ReadIdleTimeout
        var t *time.Timer
@@ -8433,9 +8678,7 @@ func (rl *http2clientConnReadLoop) run() error {
                        cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
                }
                if se, ok := err.(http2StreamError); ok {
-                       if cs := cc.streamByID(se.StreamID, false); cs != nil {
-                               cs.cc.writeStreamReset(cs.ID, se.Code, err)
-                               cs.cc.forgetStreamID(cs.ID)
+                       if cs := rl.streamByID(se.StreamID); cs != nil {
                                if se.Cause == nil {
                                        se.Cause = cc.fr.errDetail
                                }
@@ -8443,6 +8686,7 @@ func (rl *http2clientConnReadLoop) run() error {
                        }
                        continue
                } else if err != nil {
+                       cc.countReadFrameError(err)
                        return err
                }
                if http2VerboseLogs {
@@ -8455,22 +8699,16 @@ func (rl *http2clientConnReadLoop) run() error {
                        }
                        gotSettings = true
                }
-               maybeIdle := false // whether frame might transition us to idle
 
                switch f := f.(type) {
                case *http2MetaHeadersFrame:
                        err = rl.processHeaders(f)
-                       maybeIdle = true
-                       gotReply = true
                case *http2DataFrame:
                        err = rl.processData(f)
-                       maybeIdle = true
                case *http2GoAwayFrame:
                        err = rl.processGoAway(f)
-                       maybeIdle = true
                case *http2RSTStreamFrame:
                        err = rl.processResetStream(f)
-                       maybeIdle = true
                case *http2SettingsFrame:
                        err = rl.processSettings(f)
                case *http2PushPromiseFrame:
@@ -8488,38 +8726,24 @@ func (rl *http2clientConnReadLoop) run() error {
                        }
                        return err
                }
-               if rl.closeWhenIdle && gotReply && maybeIdle {
-                       cc.closeIfIdle()
-               }
        }
 }
 
 func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) error {
-       cc := rl.cc
-       cs := cc.streamByID(f.StreamID, false)
+       cs := rl.streamByID(f.StreamID)
        if cs == nil {
                // We'd get here if we canceled a request while the
                // server had its response still in flight. So if this
                // was just something we canceled, ignore it.
                return nil
        }
-       if f.StreamEnded() {
-               // Issue 20521: If the stream has ended, streamByID() causes
-               // clientStream.done to be closed, which causes the request's bodyWriter
-               // to be closed with an errStreamClosed, which may be received by
-               // clientConn.RoundTrip before the result of processing these headers.
-               // Deferring stream closure allows the header processing to occur first.
-               // clientConn.RoundTrip may still receive the bodyWriter error first, but
-               // the fix for issue 16102 prioritises any response.
-               //
-               // Issue 22413: If there is no request body, we should close the
-               // stream before writing to cs.resc so that the stream is closed
-               // immediately once RoundTrip returns.
-               if cs.req.Body != nil {
-                       defer cc.forgetStreamID(f.StreamID)
-               } else {
-                       cc.forgetStreamID(f.StreamID)
-               }
+       if cs.readClosed {
+               rl.endStreamError(cs, http2StreamError{
+                       StreamID: f.StreamID,
+                       Code:     http2ErrCodeProtocol,
+                       Cause:    errors.New("protocol error: headers after END_STREAM"),
+               })
+               return nil
        }
        if !cs.firstByte {
                if cs.trace != nil {
@@ -8543,9 +8767,11 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro
                        return err
                }
                // Any other error type is a stream error.
-               cs.cc.writeStreamReset(f.StreamID, http2ErrCodeProtocol, err)
-               cc.forgetStreamID(cs.ID)
-               cs.resc <- http2resAndError{err: err}
+               rl.endStreamError(cs, http2StreamError{
+                       StreamID: f.StreamID,
+                       Code:     http2ErrCodeProtocol,
+                       Cause:    err,
+               })
                return nil // return nil from process* funcs to keep conn alive
        }
        if res == nil {
@@ -8553,7 +8779,11 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro
                return nil
        }
        cs.resTrailer = &res.Trailer
-       cs.resc <- http2resAndError{res: res}
+       cs.res = res
+       close(cs.respHeaderRecv)
+       if f.StreamEnded() {
+               rl.endStream(cs)
+       }
        return nil
 }
 
@@ -8615,6 +8845,9 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
        }
 
        if statusCode >= 100 && statusCode <= 199 {
+               if f.StreamEnded() {
+                       return nil, errors.New("1xx informational response with END_STREAM flag")
+               }
                cs.num1xx++
                const max1xxResponses = 5 // arbitrary bound on number of informational responses, same as net/http
                if cs.num1xx > max1xxResponses {
@@ -8627,8 +8860,9 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
                }
                if statusCode == 100 {
                        http2traceGot100Continue(cs.trace)
-                       if cs.on100 != nil {
-                               cs.on100() // forces any write delay timer to fire
+                       select {
+                       case cs.on100 <- struct{}{}:
+                       default:
                        }
                }
                cs.pastHeaders = false // do it all again
@@ -8657,10 +8891,9 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http
                return res, nil
        }
 
-       cs.bufPipe = http2pipe{b: &http2dataBuffer{expected: res.ContentLength}}
+       cs.bufPipe.setBuffer(&http2dataBuffer{expected: res.ContentLength})
        cs.bytesRemain = res.ContentLength
        res.Body = http2transportResponseBody{cs}
-       go cs.awaitRequestCancel(cs.req)
 
        if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
                res.Header.Del("Content-Encoding")
@@ -8720,7 +8953,7 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
                        n = int(cs.bytesRemain)
                        if err == nil {
                                err = errors.New("net/http: server replied with more than declared Content-Length; truncated")
-                               cc.writeStreamReset(cs.ID, http2ErrCodeProtocol, err)
+                               cs.abortStream(err)
                        }
                        cs.readErr = err
                        return int(cs.bytesRemain), err
@@ -8738,8 +8971,6 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
        }
 
        cc.mu.Lock()
-       defer cc.mu.Unlock()
-
        var connAdd, streamAdd int32
        // Check the conn-level first, before the stream-level.
        if v := cc.inflow.available(); v < http2transportDefaultConnFlow/2 {
@@ -8756,6 +8987,8 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
                        cs.inflow.add(streamAdd)
                }
        }
+       cc.mu.Unlock()
+
        if connAdd != 0 || streamAdd != 0 {
                cc.wmu.Lock()
                defer cc.wmu.Unlock()
@@ -8776,34 +9009,40 @@ func (b http2transportResponseBody) Close() error {
        cs := b.cs
        cc := cs.cc
 
-       serverSentStreamEnd := cs.bufPipe.Err() == io.EOF
        unread := cs.bufPipe.Len()
-
-       if unread > 0 || !serverSentStreamEnd {
+       if unread > 0 {
                cc.mu.Lock()
-               cc.wmu.Lock()
-               if !serverSentStreamEnd {
-                       cc.fr.WriteRSTStream(cs.ID, http2ErrCodeCancel)
-                       cs.didReset = true
-               }
                // Return connection-level flow control.
                if unread > 0 {
                        cc.inflow.add(int32(unread))
+               }
+               cc.mu.Unlock()
+
+               cc.wmu.Lock()
+               // Return connection-level flow control.
+               if unread > 0 {
                        cc.fr.WriteWindowUpdate(0, uint32(unread))
                }
                cc.bw.Flush()
                cc.wmu.Unlock()
-               cc.mu.Unlock()
        }
 
        cs.bufPipe.BreakWithError(http2errClosedResponseBody)
-       cc.forgetStreamID(cs.ID)
+       cs.abortStream(http2errClosedResponseBody)
+
+       select {
+       case <-cs.donec:
+       case <-cs.req.Context().Done():
+               return cs.req.Context().Err()
+       case <-cs.req.Cancel:
+               return http2errRequestCanceled
+       }
        return nil
 }
 
 func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
        cc := rl.cc
-       cs := cc.streamByID(f.StreamID, f.StreamEnded())
+       cs := rl.streamByID(f.StreamID)
        data := f.Data()
        if cs == nil {
                cc.mu.Lock()
@@ -8832,6 +9071,14 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
                }
                return nil
        }
+       if cs.readClosed {
+               cc.logf("protocol error: received DATA after END_STREAM")
+               rl.endStreamError(cs, http2StreamError{
+                       StreamID: f.StreamID,
+                       Code:     http2ErrCodeProtocol,
+               })
+               return nil
+       }
        if !cs.firstByte {
                cc.logf("protocol error: received DATA before a HEADERS frame")
                rl.endStreamError(cs, http2StreamError{
@@ -8863,30 +9110,39 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
                if pad := int(f.Length) - len(data); pad > 0 {
                        refund += pad
                }
-               // Return len(data) now if the stream is already closed,
-               // since data will never be read.
-               didReset := cs.didReset
-               if didReset {
-                       refund += len(data)
+
+               didReset := false
+               var err error
+               if len(data) > 0 {
+                       if _, err = cs.bufPipe.Write(data); err != nil {
+                               // Return len(data) now if the stream is already closed,
+                               // since data will never be read.
+                               didReset = true
+                               refund += len(data)
+                       }
                }
+
                if refund > 0 {
                        cc.inflow.add(int32(refund))
+                       if !didReset {
+                               cs.inflow.add(int32(refund))
+                       }
+               }
+               cc.mu.Unlock()
+
+               if refund > 0 {
                        cc.wmu.Lock()
                        cc.fr.WriteWindowUpdate(0, uint32(refund))
                        if !didReset {
-                               cs.inflow.add(int32(refund))
                                cc.fr.WriteWindowUpdate(cs.ID, uint32(refund))
                        }
                        cc.bw.Flush()
                        cc.wmu.Unlock()
                }
-               cc.mu.Unlock()
 
-               if len(data) > 0 && !didReset {
-                       if _, err := cs.bufPipe.Write(data); err != nil {
-                               rl.endStreamError(cs, err)
-                               return err
-                       }
+               if err != nil {
+                       rl.endStreamError(cs, err)
+                       return nil
                }
        }
 
@@ -8899,24 +9155,26 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
 func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
        // TODO: check that any declared content-length matches, like
        // server.go's (*stream).endStream method.
-       rl.endStreamError(cs, nil)
+       if !cs.readClosed {
+               cs.readClosed = true
+               cs.bufPipe.closeWithErrorAndCode(io.EOF, cs.copyTrailers)
+               close(cs.peerClosed)
+       }
 }
 
 func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err error) {
-       var code func()
-       if err == nil {
-               err = io.EOF
-               code = cs.copyTrailers
-       }
-       if http2isConnectionCloseRequest(cs.req) {
-               rl.closeWhenIdle = true
-       }
-       cs.bufPipe.closeWithErrorAndCode(err, code)
+       cs.readAborted = true
+       cs.abortStream(err)
+}
 
-       select {
-       case cs.resc <- http2resAndError{err: err}:
-       default:
+func (rl *http2clientConnReadLoop) streamByID(id uint32) *http2clientStream {
+       rl.cc.mu.Lock()
+       defer rl.cc.mu.Unlock()
+       cs := rl.cc.streams[id]
+       if cs != nil && !cs.readAborted {
+               return cs
        }
+       return nil
 }
 
 func (cs *http2clientStream) copyTrailers() {
@@ -8935,12 +9193,33 @@ func (rl *http2clientConnReadLoop) processGoAway(f *http2GoAwayFrame) error {
        if f.ErrCode != 0 {
                // TODO: deal with GOAWAY more. particularly the error code
                cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
+               if fn := cc.t.CountError; fn != nil {
+                       fn("recv_goaway_" + f.ErrCode.stringToken())
+               }
+
        }
        cc.setGoAway(f)
        return nil
 }
 
 func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error {
+       cc := rl.cc
+       // Locking both mu and wmu here allows frame encoding to read settings with only wmu held.
+       // Acquiring wmu when f.IsAck() is unnecessary, but convenient and mostly harmless.
+       cc.wmu.Lock()
+       defer cc.wmu.Unlock()
+
+       if err := rl.processSettingsNoWrite(f); err != nil {
+               return err
+       }
+       if !f.IsAck() {
+               cc.fr.WriteSettingsAck()
+               cc.bw.Flush()
+       }
+       return nil
+}
+
+func (rl *http2clientConnReadLoop) processSettingsNoWrite(f *http2SettingsFrame) error {
        cc := rl.cc
        cc.mu.Lock()
        defer cc.mu.Unlock()
@@ -8953,12 +9232,14 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
                return http2ConnectionError(http2ErrCodeProtocol)
        }
 
+       var seenMaxConcurrentStreams bool
        err := f.ForeachSetting(func(s http2Setting) error {
                switch s.ID {
                case http2SettingMaxFrameSize:
                        cc.maxFrameSize = s.Val
                case http2SettingMaxConcurrentStreams:
                        cc.maxConcurrentStreams = s.Val
+                       seenMaxConcurrentStreams = true
                case http2SettingMaxHeaderListSize:
                        cc.peerMaxHeaderListSize = uint64(s.Val)
                case http2SettingInitialWindowSize:
@@ -8990,17 +9271,23 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
                return err
        }
 
-       cc.wmu.Lock()
-       defer cc.wmu.Unlock()
+       if !cc.seenSettings {
+               if !seenMaxConcurrentStreams {
+                       // This was the servers initial SETTINGS frame and it
+                       // didn't contain a MAX_CONCURRENT_STREAMS field so
+                       // increase the number of concurrent streams this
+                       // connection can establish to our default.
+                       cc.maxConcurrentStreams = http2defaultMaxConcurrentStreams
+               }
+               cc.seenSettings = true
+       }
 
-       cc.fr.WriteSettingsAck()
-       cc.bw.Flush()
-       return cc.werr
+       return nil
 }
 
 func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error {
        cc := rl.cc
-       cs := cc.streamByID(f.StreamID, false)
+       cs := rl.streamByID(f.StreamID)
        if f.StreamID != 0 && cs == nil {
                return nil
        }
@@ -9020,24 +9307,22 @@ func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame
 }
 
 func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) error {
-       cs := rl.cc.streamByID(f.StreamID, true)
+       cs := rl.streamByID(f.StreamID)
        if cs == nil {
-               // TODO: return error if server tries to RST_STEAM an idle stream
+               // TODO: return error if server tries to RST_STREAM an idle stream
                return nil
        }
-       select {
-       case <-cs.peerReset:
-               // Already reset.
-               // This is the only goroutine
-               // which closes this, so there
-               // isn't a race.
-       default:
-               err := http2streamError(cs.ID, f.ErrCode)
-               cs.resetErr = err
-               close(cs.peerReset)
-               cs.bufPipe.CloseWithError(err)
-               cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl
+       serr := http2streamError(cs.ID, f.ErrCode)
+       serr.Cause = http2errFromPeer
+       if f.ErrCode == http2ErrCodeProtocol {
+               rl.cc.SetDoNotReuse()
+       }
+       if fn := cs.cc.t.CountError; fn != nil {
+               fn("recv_rststream_" + f.ErrCode.stringToken())
        }
+       cs.abortStream(serr)
+
+       cs.bufPipe.CloseWithError(serr)
        return nil
 }
 
@@ -9194,87 +9479,6 @@ type http2errorReader struct{ err error }
 
 func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err }
 
-// bodyWriterState encapsulates various state around the Transport's writing
-// of the request body, particularly regarding doing delayed writes of the body
-// when the request contains "Expect: 100-continue".
-type http2bodyWriterState struct {
-       cs     *http2clientStream
-       timer  *time.Timer   // if non-nil, we're doing a delayed write
-       fnonce *sync.Once    // to call fn with
-       fn     func()        // the code to run in the goroutine, writing the body
-       resc   chan error    // result of fn's execution
-       delay  time.Duration // how long we should delay a delayed write for
-}
-
-func (t *http2Transport) getBodyWriterState(cs *http2clientStream, body io.Reader) (s http2bodyWriterState) {
-       s.cs = cs
-       if body == nil {
-               return
-       }
-       resc := make(chan error, 1)
-       s.resc = resc
-       s.fn = func() {
-               cs.cc.mu.Lock()
-               cs.startedWrite = true
-               cs.cc.mu.Unlock()
-               resc <- cs.writeRequestBody(body, cs.req.Body)
-       }
-       s.delay = t.expectContinueTimeout()
-       if s.delay == 0 ||
-               !httpguts.HeaderValuesContainsToken(
-                       cs.req.Header["Expect"],
-                       "100-continue") {
-               return
-       }
-       s.fnonce = new(sync.Once)
-
-       // Arm the timer with a very large duration, which we'll
-       // intentionally lower later. It has to be large now because
-       // we need a handle to it before writing the headers, but the
-       // s.delay value is defined to not start until after the
-       // request headers were written.
-       const hugeDuration = 365 * 24 * time.Hour
-       s.timer = time.AfterFunc(hugeDuration, func() {
-               s.fnonce.Do(s.fn)
-       })
-       return
-}
-
-func (s http2bodyWriterState) cancel() {
-       if s.timer != nil {
-               if s.timer.Stop() {
-                       s.resc <- nil
-               }
-       }
-}
-
-func (s http2bodyWriterState) on100() {
-       if s.timer == nil {
-               // If we didn't do a delayed write, ignore the server's
-               // bogus 100 continue response.
-               return
-       }
-       s.timer.Stop()
-       go func() { s.fnonce.Do(s.fn) }()
-}
-
-// scheduleBodyWrite starts writing the body, either immediately (in
-// the common case) or after the delay timeout. It should not be
-// called until after the headers have been written.
-func (s http2bodyWriterState) scheduleBodyWrite() {
-       if s.timer == nil {
-               // We're not doing a delayed write (see
-               // getBodyWriterState), so just start the writing
-               // goroutine immediately.
-               go s.fn()
-               return
-       }
-       http2traceWait100Continue(s.cs.trace)
-       if s.timer.Stop() {
-               s.timer.Reset(s.delay)
-       }
-}
-
 // isConnectionCloseRequest reports whether req should use its own
 // connection for a single request and then close the connection.
 func http2isConnectionCloseRequest(req *Request) bool {
index 4c72dcb2c88d254f3e8b81a483bb6b40079f4b37..5c77cbb8826661dfcaab9f9283c2d7e9f04acf09 100644 (file)
@@ -13,6 +13,8 @@ import (
        "strings"
        "sync"
        "time"
+
+       "golang.org/x/net/http/httpguts"
 )
 
 // A Header represents the key-value pairs in an HTTP header.
@@ -192,6 +194,13 @@ func (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptra
        kvs, sorter := h.sortedKeyValues(exclude)
        var formattedVals []string
        for _, kv := range kvs {
+               if !httpguts.ValidHeaderFieldName(kv.key) {
+                       // This could be an error. In the common case of
+                       // writing response headers, however, we have no good
+                       // way to provide the error back to the server
+                       // handler, so just drop invalid headers instead.
+                       continue
+               }
                for _, v := range kv.values {
                        v = headerNewlineToSpace.Replace(v)
                        v = textproto.TrimString(v)
index 47893629194b6a6dedde343b06c73ac0db976f34..57d16f51a5d62e662847b47fbf33203048c8b8bb 100644 (file)
@@ -89,6 +89,19 @@ var headerWriteTests = []struct {
                        "k4: 4a\r\nk4: 4b\r\nk6: 6a\r\nk6: 6b\r\n" +
                        "k7: 7a\r\nk7: 7b\r\nk8: 8a\r\nk8: 8b\r\nk9: 9a\r\nk9: 9b\r\n",
        },
+       // Tests invalid characters in headers.
+       {
+               Header{
+                       "Content-Type":             {"text/html; charset=UTF-8"},
+                       "NewlineInValue":           {"1\r\nBar: 2"},
+                       "NewlineInKey\r\n":         {"1"},
+                       "Colon:InKey":              {"1"},
+                       "Evil: 1\r\nSmuggledValue": {"1"},
+               },
+               nil,
+               "Content-Type: text/html; charset=UTF-8\r\n" +
+                       "NewlineInValue: 1  Bar: 2\r\n",
+       },
 }
 
 func TestHeaderWrite(t *testing.T) {
index 8b63368386f43ba81a574e571ada7bcfffd195e0..71849bb8f72f5202c4757bb19d873f48e61af330 100644 (file)
@@ -11,6 +11,7 @@ import (
        "fmt"
        "io"
        "log"
+       "mime"
        "net"
        "net/http"
        "net/http/internal/ascii"
@@ -412,7 +413,7 @@ func (p *ReverseProxy) flushInterval(res *http.Response) time.Duration {
 
        // For Server-Sent Events responses, flush immediately.
        // The MIME type is defined in https://www.w3.org/TR/eventsource/#text-event-stream
-       if resCT == "text/event-stream" {
+       if baseCT, _, _ := mime.ParseMediaType(resCT); baseCT == "text/event-stream" {
                return -1 // negative means immediately
        }
 
index 4b6ad77a29466fe0fbb9f1e79fa1bd804b2264ea..90e8903e9cfd5bfa3086422cb9f442a0861bd250 100644 (file)
@@ -1194,6 +1194,26 @@ func TestSelectFlushInterval(t *testing.T) {
                        p:    &ReverseProxy{FlushInterval: 0},
                        want: -1,
                },
+               {
+                       name: "server-sent events with media-type parameters overrides non-zero",
+                       res: &http.Response{
+                               Header: http.Header{
+                                       "Content-Type": {"text/event-stream;charset=utf-8"},
+                               },
+                       },
+                       p:    &ReverseProxy{FlushInterval: 123},
+                       want: -1,
+               },
+               {
+                       name: "server-sent events with media-type parameters overrides zero",
+                       res: &http.Response{
+                               Header: http.Header{
+                                       "Content-Type": {"text/event-stream;charset=utf-8"},
+                               },
+                       },
+                       p:    &ReverseProxy{FlushInterval: 0},
+                       want: -1,
+               },
                {
                        name: "Content-Length: -1, overrides non-zero",
                        res: &http.Response{
index f06e5725f3477988281ef10ae078cd945083a428..37a72e9031a1127f573d3f34f42d1ad0740593ae 100644 (file)
@@ -81,6 +81,11 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
                                        cr.err = errors.New("malformed chunked encoding")
                                        break
                                }
+                       } else {
+                               if cr.err == io.EOF {
+                                       cr.err = io.ErrUnexpectedEOF
+                               }
+                               break
                        }
                        cr.checkEnd = false
                }
@@ -109,6 +114,8 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
                // bytes to verify they are "\r\n".
                if cr.n == 0 && cr.err == nil {
                        cr.checkEnd = true
+               } else if cr.err == io.EOF {
+                       cr.err = io.ErrUnexpectedEOF
                }
        }
        return n, cr.err
@@ -152,6 +159,8 @@ func isASCIISpace(b byte) bool {
        return b == ' ' || b == '\t' || b == '\n' || b == '\r'
 }
 
+var semi = []byte(";")
+
 // removeChunkExtension removes any chunk-extension from p.
 // For example,
 //     "0" => "0"
@@ -159,14 +168,11 @@ func isASCIISpace(b byte) bool {
 //     "0;token=val" => "0"
 //     `0;token="quoted string"` => "0"
 func removeChunkExtension(p []byte) ([]byte, error) {
-       semi := bytes.IndexByte(p, ';')
-       if semi == -1 {
-               return p, nil
-       }
+       p, _, _ = bytes.Cut(p, semi)
        // TODO: care about exact syntax of chunk extensions? We're
        // ignoring and stripping them anyway. For now just never
        // return an error.
-       return p[:semi], nil
+       return p, nil
 }
 
 // NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
index 08152ed1e24d67cbc439a4d90ffbe65682144ad6..5e29a786dd61e42d9380df0aaa6bf9d343293fa3 100644 (file)
@@ -11,6 +11,7 @@ import (
        "io"
        "strings"
        "testing"
+       "testing/iotest"
 )
 
 func TestChunk(t *testing.T) {
@@ -211,3 +212,30 @@ func TestChunkReadPartial(t *testing.T) {
        }
 
 }
+
+// Issue 48861: ChunkedReader should report incomplete chunks
+func TestIncompleteChunk(t *testing.T) {
+       const valid = "4\r\nabcd\r\n" + "5\r\nabc\r\n\r\n" + "0\r\n"
+
+       for i := 0; i < len(valid); i++ {
+               incomplete := valid[:i]
+               r := NewChunkedReader(strings.NewReader(incomplete))
+               if _, err := io.ReadAll(r); err != io.ErrUnexpectedEOF {
+                       t.Errorf("expected io.ErrUnexpectedEOF for %q, got %v", incomplete, err)
+               }
+       }
+
+       r := NewChunkedReader(strings.NewReader(valid))
+       if _, err := io.ReadAll(r); err != nil {
+               t.Errorf("unexpected error for %q: %v", valid, err)
+       }
+}
+
+func TestChunkEndReadError(t *testing.T) {
+       readErr := fmt.Errorf("chunk end read error")
+
+       r := NewChunkedReader(io.MultiReader(strings.NewReader("4\r\nabcd"), iotest.ErrReader(readErr)))
+       if _, err := io.ReadAll(r); err != readErr {
+               t.Errorf("expected %v, got %v", readErr, err)
+       }
+}
index 6564627998f53eb988cead8f72cbfbfc4202e54f..632a308a5ce2eb0da306356e80d026e77689d054 100644 (file)
@@ -31,11 +31,8 @@ func interestingGoroutines() (gs []string) {
        buf := make([]byte, 2<<20)
        buf = buf[:runtime.Stack(buf, true)]
        for _, g := range strings.Split(string(buf), "\n\n") {
-               sl := strings.SplitN(g, "\n", 2)
-               if len(sl) != 2 {
-                       continue
-               }
-               stack := strings.TrimSpace(sl[1])
+               _, stack, _ := strings.Cut(g, "\n")
+               stack = strings.TrimSpace(stack)
                if stack == "" ||
                        strings.Contains(stack, "testing.(*M).before.func1") ||
                        strings.Contains(stack, "os/signal.signal_recv") ||
index 79599d006aaf94dc1537c6024d200de2b6d0c961..63c0e92d6a6f653194bfdbb8b2c79c0a27a37884 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build nethttpomithttp2
-// +build nethttpomithttp2
 
 package http
 
index 888ea35c9a6c5229c50c946926f17a256c8da59c..dc855c8a6da9a04acde7784ed8638ff1dc4f12fc 100644 (file)
@@ -44,7 +44,7 @@
 // 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
+//     curl -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/
index 09cb0c7f564f745f1b50c9f861f441603055e764..76c2317d28256dfbbce67752b0951290bbea5656 100644 (file)
@@ -779,11 +779,10 @@ func removeZone(host string) string {
        return host[:j] + host[i:]
 }
 
-// ParseHTTPVersion parses an HTTP version string.
+// ParseHTTPVersion parses an HTTP version string according to RFC 7230, section 2.6.
 // "HTTP/1.0" returns (1, 0, true). Note that strings without
 // a minor version, such as "HTTP/2", are not valid.
 func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
-       const Big = 1000000 // arbitrary upper bound
        switch vers {
        case "HTTP/1.1":
                return 1, 1, true
@@ -793,19 +792,21 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
        if !strings.HasPrefix(vers, "HTTP/") {
                return 0, 0, false
        }
-       dot := strings.Index(vers, ".")
-       if dot < 0 {
+       if len(vers) != len("HTTP/X.Y") {
                return 0, 0, false
        }
-       major, err := strconv.Atoi(vers[5:dot])
-       if err != nil || major < 0 || major > Big {
+       if vers[6] != '.' {
                return 0, 0, false
        }
-       minor, err = strconv.Atoi(vers[dot+1:])
-       if err != nil || minor < 0 || minor > Big {
+       maj, err := strconv.ParseUint(vers[5:6], 10, 0)
+       if err != nil {
                return 0, 0, false
        }
-       return major, minor, true
+       min, err := strconv.ParseUint(vers[7:8], 10, 0)
+       if err != nil {
+               return 0, 0, false
+       }
+       return int(maj), int(min), true
 }
 
 func validMethod(method string) bool {
@@ -939,7 +940,7 @@ func NewRequestWithContext(ctx context.Context, method, url string, body io.Read
 func (r *Request) BasicAuth() (username, password string, ok bool) {
        auth := r.Header.Get("Authorization")
        if auth == "" {
-               return
+               return "", "", false
        }
        return parseBasicAuth(auth)
 }
@@ -950,18 +951,18 @@ func parseBasicAuth(auth string) (username, password string, ok bool) {
        const prefix = "Basic "
        // Case insensitive prefix match. See Issue 22736.
        if len(auth) < len(prefix) || !ascii.EqualFold(auth[:len(prefix)], prefix) {
-               return
+               return "", "", false
        }
        c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
        if err != nil {
-               return
+               return "", "", false
        }
        cs := string(c)
-       s := strings.IndexByte(cs, ':')
-       if s < 0 {
-               return
+       username, password, ok = strings.Cut(cs, ":")
+       if !ok {
+               return "", "", false
        }
-       return cs[:s], cs[s+1:], true
+       return username, password, true
 }
 
 // SetBasicAuth sets the request's Authorization header to use HTTP
@@ -979,13 +980,12 @@ func (r *Request) SetBasicAuth(username, password string) {
 
 // parseRequestLine parses "GET /foo HTTP/1.1" into its three parts.
 func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
-       s1 := strings.Index(line, " ")
-       s2 := strings.Index(line[s1+1:], " ")
-       if s1 < 0 || s2 < 0 {
-               return
+       method, rest, ok1 := strings.Cut(line, " ")
+       requestURI, proto, ok2 := strings.Cut(rest, " ")
+       if !ok1 || !ok2 {
+               return "", "", "", false
        }
-       s2 += s1 + 1
-       return line[:s1], line[s1+1 : s2], line[s2+1:], true
+       return method, requestURI, proto, true
 }
 
 var textprotoReaderPool sync.Pool
index 4e0c4ba207f8be66a7f529de7aa7ac7fb052021a..4363e1103332567d28e7d0a4103945241cda87a1 100644 (file)
@@ -639,10 +639,10 @@ var parseHTTPVersionTests = []struct {
        major, minor int
        ok           bool
 }{
+       {"HTTP/0.0", 0, 0, true},
        {"HTTP/0.9", 0, 9, true},
        {"HTTP/1.0", 1, 0, true},
        {"HTTP/1.1", 1, 1, true},
-       {"HTTP/3.14", 3, 14, true},
 
        {"HTTP", 0, 0, false},
        {"HTTP/one.one", 0, 0, false},
@@ -651,6 +651,12 @@ var parseHTTPVersionTests = []struct {
        {"HTTP/0,-1", 0, 0, false},
        {"HTTP/", 0, 0, false},
        {"HTTP/1,1", 0, 0, false},
+       {"HTTP/+1.1", 0, 0, false},
+       {"HTTP/1.+1", 0, 0, false},
+       {"HTTP/0000000001.1", 0, 0, false},
+       {"HTTP/1.0000000001", 0, 0, false},
+       {"HTTP/3.14", 0, 0, false},
+       {"HTTP/12.3", 0, 0, false},
 }
 
 func TestParseHTTPVersion(t *testing.T) {
index b8985da3c80fc413ef30f640bbd8fd282e65465e..297394eabebed53dc1853d4547c5e19e73256e4b 100644 (file)
@@ -165,16 +165,14 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
                }
                return nil, err
        }
-       if i := strings.IndexByte(line, ' '); i == -1 {
+       proto, status, ok := strings.Cut(line, " ")
+       if !ok {
                return nil, badStringError("malformed HTTP response", line)
-       } else {
-               resp.Proto = line[:i]
-               resp.Status = strings.TrimLeft(line[i+1:], " ")
-       }
-       statusCode := resp.Status
-       if i := strings.IndexByte(resp.Status, ' '); i != -1 {
-               statusCode = resp.Status[:i]
        }
+       resp.Proto = proto
+       resp.Status = strings.TrimLeft(status, " ")
+
+       statusCode, _, _ := strings.Cut(resp.Status, " ")
        if len(statusCode) != 3 {
                return nil, badStringError("malformed HTTP status code", statusCode)
        }
@@ -182,7 +180,6 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
        if err != nil || resp.StatusCode < 0 {
                return nil, badStringError("malformed HTTP status code", statusCode)
        }
-       var ok bool
        if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
                return nil, badStringError("malformed HTTP version", resp.Proto)
        }
index eef7c79293e643e08677e24ba9d5c1e2fb769ffc..c4c5d3b6ebb3dd67786808e8885876fcfe036a52 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js || !wasm
-// +build !js !wasm
 
 package http
 
index 74c83a9172cab2524156d097394fb1fe5f1ef202..dd042e9a01c3ea62a1be3ea480035050784ed182 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package http
 
@@ -41,11 +40,19 @@ const jsFetchCreds = "js.fetch:credentials"
 // Reference: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters
 const jsFetchRedirect = "js.fetch:redirect"
 
-var useFakeNetwork = js.Global().Get("fetch").IsUndefined()
+// jsFetchMissing will be true if the Fetch API is not present in
+// the browser globals.
+var jsFetchMissing = js.Global().Get("fetch").IsUndefined()
 
 // RoundTrip implements the RoundTripper interface using the WHATWG Fetch API.
 func (t *Transport) RoundTrip(req *Request) (*Response, error) {
-       if useFakeNetwork {
+       // The Transport has a documented contract that states that if the DialContext or
+       // DialTLSContext functions are set, they will be used to set up the connections.
+       // If they aren't set then the documented contract is to use Dial or DialTLS, even
+       // though they are deprecated. Therefore, if any of these are set, we should obey
+       // the contract and dial using the regular round-trip instead. Otherwise, we'll try
+       // to fall back on the Fetch API, unless it's not available.
+       if t.Dial != nil || t.DialContext != nil || t.DialTLS != nil || t.DialTLSContext != nil || jsFetchMissing {
                return t.roundTrip(req)
        }
 
@@ -131,8 +138,24 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
                }
 
                contentLength := int64(0)
-               if cl, err := strconv.ParseInt(header.Get("Content-Length"), 10, 64); err == nil {
+               clHeader := header.Get("Content-Length")
+               switch {
+               case clHeader != "":
+                       cl, err := strconv.ParseInt(clHeader, 10, 64)
+                       if err != nil {
+                               errCh <- fmt.Errorf("net/http: ill-formed Content-Length header: %v", err)
+                               return nil
+                       }
+                       if cl < 0 {
+                               // Content-Length values less than 0 are invalid.
+                               // See: https://datatracker.ietf.org/doc/html/rfc2616/#section-14.13
+                               errCh <- fmt.Errorf("net/http: invalid Content-Length header: %q", clHeader)
+                               return nil
+                       }
                        contentLength = cl
+               default:
+                       // If the response length is not declared, set it to -1.
+                       contentLength = -1
                }
 
                b := result.Get("body")
index 6394da3bb7cf60d0263e723bb611967f64d43820..a98d6c313f86cba5f0e86c4339cca146cb96cf22 100644 (file)
@@ -23,6 +23,7 @@ import (
        "net"
        . "net/http"
        "net/http/httptest"
+       "net/http/httptrace"
        "net/http/httputil"
        "net/http/internal"
        "net/http/internal/testcert"
@@ -5689,22 +5690,37 @@ func testServerKeepAlivesEnabled(t *testing.T, h2 bool) {
        }
        // Not parallel: messes with global variable. (http2goAwayTimeout)
        defer afterTest(t)
-       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
-               fmt.Fprintf(w, "%v", r.RemoteAddr)
-       }))
+       cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {}))
        defer cst.close()
        srv := cst.ts.Config
        srv.SetKeepAlivesEnabled(false)
-       a := cst.getURL(cst.ts.URL)
-       if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
-               t.Fatalf("test server has active conns")
-       }
-       b := cst.getURL(cst.ts.URL)
-       if a == b {
-               t.Errorf("got same connection between first and second requests")
-       }
-       if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
-               t.Fatalf("test server has active conns")
+       for try := 0; try < 2; try++ {
+               if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
+                       t.Fatalf("request %v: test server has active conns", try)
+               }
+               conns := 0
+               var info httptrace.GotConnInfo
+               ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
+                       GotConn: func(v httptrace.GotConnInfo) {
+                               conns++
+                               info = v
+                       },
+               })
+               req, err := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               res, err := cst.c.Do(req)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               res.Body.Close()
+               if conns != 1 {
+                       t.Fatalf("request %v: got %v conns, want 1", try, conns)
+               }
+               if info.Reused || info.WasIdle {
+                       t.Fatalf("request %v: Reused=%v (want false), WasIdle=%v (want false)", try, info.Reused, info.WasIdle)
+               }
        }
 }
 
index 5b113cff970dc19148c5ba4fe96020b54bfd0d5a..91fad68694b51659b579ee8eef7e1360ce44a0f6 100644 (file)
@@ -13,6 +13,7 @@ import (
        "crypto/tls"
        "errors"
        "fmt"
+       "internal/godebug"
        "io"
        "log"
        "math/rand"
@@ -20,7 +21,6 @@ import (
        "net/textproto"
        "net/url"
        urlpkg "net/url"
-       "os"
        "path"
        "runtime"
        "sort"
@@ -865,6 +865,28 @@ func (srv *Server) initialReadLimitSize() int64 {
        return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
 }
 
+// tlsHandshakeTimeout returns the time limit permitted for the TLS
+// handshake, or zero for unlimited.
+//
+// It returns the minimum of any positive ReadHeaderTimeout,
+// ReadTimeout, or WriteTimeout.
+func (srv *Server) tlsHandshakeTimeout() time.Duration {
+       var ret time.Duration
+       for _, v := range [...]time.Duration{
+               srv.ReadHeaderTimeout,
+               srv.ReadTimeout,
+               srv.WriteTimeout,
+       } {
+               if v <= 0 {
+                       continue
+               }
+               if ret == 0 || v < ret {
+                       ret = v
+               }
+       }
+       return ret
+}
+
 // wrapper around io.ReadCloser which on first read, sends an
 // HTTP/1.1 100 Continue header
 type expectContinueReader struct {
@@ -1794,6 +1816,7 @@ func isCommonNetReadError(err error) bool {
 func (c *conn) serve(ctx context.Context) {
        c.remoteAddr = c.rwc.RemoteAddr().String()
        ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
+       var inFlightResponse *response
        defer func() {
                if err := recover(); err != nil && err != ErrAbortHandler {
                        const size = 64 << 10
@@ -1801,18 +1824,25 @@ func (c *conn) serve(ctx context.Context) {
                        buf = buf[:runtime.Stack(buf, false)]
                        c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
                }
+               if inFlightResponse != nil {
+                       inFlightResponse.cancelCtx()
+               }
                if !c.hijacked() {
+                       if inFlightResponse != nil {
+                               inFlightResponse.conn.r.abortPendingRead()
+                               inFlightResponse.reqBody.Close()
+                       }
                        c.close()
                        c.setState(c.rwc, StateClosed, runHooks)
                }
        }()
 
        if tlsConn, ok := c.rwc.(*tls.Conn); ok {
-               if d := c.server.ReadTimeout; d > 0 {
-                       c.rwc.SetReadDeadline(time.Now().Add(d))
-               }
-               if d := c.server.WriteTimeout; d > 0 {
-                       c.rwc.SetWriteDeadline(time.Now().Add(d))
+               tlsTO := c.server.tlsHandshakeTimeout()
+               if tlsTO > 0 {
+                       dl := time.Now().Add(tlsTO)
+                       c.rwc.SetReadDeadline(dl)
+                       c.rwc.SetWriteDeadline(dl)
                }
                if err := tlsConn.HandshakeContext(ctx); err != nil {
                        // If the handshake failed due to the client not speaking
@@ -1826,6 +1856,11 @@ func (c *conn) serve(ctx context.Context) {
                        c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
                        return
                }
+               // Restore Conn-level deadlines.
+               if tlsTO > 0 {
+                       c.rwc.SetReadDeadline(time.Time{})
+                       c.rwc.SetWriteDeadline(time.Time{})
+               }
                c.tlsState = new(tls.ConnectionState)
                *c.tlsState = tlsConn.ConnectionState()
                if proto := c.tlsState.NegotiatedProtocol; validNextProto(proto) {
@@ -1926,7 +1961,9 @@ func (c *conn) serve(ctx context.Context) {
                // in parallel even if their responses need to be serialized.
                // But we're not going to implement HTTP pipelining because it
                // was never deployed in the wild and the answer is HTTP/2.
+               inFlightResponse = w
                serverHandler{c.server}.ServeHTTP(w, w.req)
+               inFlightResponse = nil
                w.cancelCtx()
                if c.hijacked() {
                        return
@@ -2272,7 +2309,7 @@ func cleanPath(p string) string {
 // stripHostPort returns h without any trailing ":<port>".
 func stripHostPort(h string) string {
        // If no port on host, return unchanged
-       if strings.IndexByte(h, ':') == -1 {
+       if !strings.Contains(h, ":") {
                return h
        }
        host, _, err := net.SplitHostPort(h)
@@ -3259,7 +3296,7 @@ func (srv *Server) onceSetNextProtoDefaults_Serve() {
 // configured otherwise. (by setting srv.TLSNextProto non-nil)
 // It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*).
 func (srv *Server) onceSetNextProtoDefaults() {
-       if omitBundledHTTP2 || strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
+       if omitBundledHTTP2 || godebug.Get("http2server") == "0" {
                return
        }
        // Enable HTTP/2 by default if the user hasn't otherwise
index 0132f3ba5fbd77611fb22d9c965f98f98afccb33..d17c5c1e7ef5e6329587d37761f38f3d8329825f 100644 (file)
@@ -9,8 +9,61 @@ package http
 import (
        "fmt"
        "testing"
+       "time"
 )
 
+func TestServerTLSHandshakeTimeout(t *testing.T) {
+       tests := []struct {
+               s    *Server
+               want time.Duration
+       }{
+               {
+                       s:    &Server{},
+                       want: 0,
+               },
+               {
+                       s: &Server{
+                               ReadTimeout: -1,
+                       },
+                       want: 0,
+               },
+               {
+                       s: &Server{
+                               ReadTimeout: 5 * time.Second,
+                       },
+                       want: 5 * time.Second,
+               },
+               {
+                       s: &Server{
+                               ReadTimeout:  5 * time.Second,
+                               WriteTimeout: -1,
+                       },
+                       want: 5 * time.Second,
+               },
+               {
+                       s: &Server{
+                               ReadTimeout:  5 * time.Second,
+                               WriteTimeout: 4 * time.Second,
+                       },
+                       want: 4 * time.Second,
+               },
+               {
+                       s: &Server{
+                               ReadTimeout:       5 * time.Second,
+                               ReadHeaderTimeout: 2 * time.Second,
+                               WriteTimeout:      4 * time.Second,
+                       },
+                       want: 2 * time.Second,
+               },
+       }
+       for i, tt := range tests {
+               got := tt.s.tlsHandshakeTimeout()
+               if got != tt.want {
+                       t.Errorf("%d. got %v; want %v", i, got, tt.want)
+               }
+       }
+}
+
 func BenchmarkServerMatch(b *testing.B) {
        fn := func(w ResponseWriter, r *Request) {
                fmt.Fprintf(w, "OK")
index 85c2e5a360d68676f2f6c4574b0e5833fc68ca24..5ff89cc17f10cbd83a0dfcd8da9455f0ef54ae68 100644 (file)
@@ -212,6 +212,7 @@ func (t *transferWriter) probeRequestBody() {
                        rres.b = buf[0]
                }
                t.ByteReadCh <- rres
+               close(t.ByteReadCh)
        }(t.Body)
        timer := time.NewTimer(200 * time.Millisecond)
        select {
@@ -1072,6 +1073,9 @@ func (fr finishAsyncByteRead) Read(p []byte) (n int, err error) {
        if n == 1 {
                p[0] = rres.b
        }
+       if err == nil {
+               err = io.EOF
+       }
        return
 }
 
index 309194e8e52c86f8ef17109464f8b28a1f244bfa..05a16591369f777a91836813bcddc951966511c8 100644 (file)
@@ -17,6 +17,7 @@ import (
        "crypto/tls"
        "errors"
        "fmt"
+       "internal/godebug"
        "io"
        "log"
        "net"
@@ -24,7 +25,6 @@ import (
        "net/http/internal/ascii"
        "net/textproto"
        "net/url"
-       "os"
        "reflect"
        "strings"
        "sync"
@@ -42,10 +42,10 @@ import (
 // $no_proxy) environment variables.
 var DefaultTransport RoundTripper = &Transport{
        Proxy: ProxyFromEnvironment,
-       DialContext: (&net.Dialer{
+       DialContext: defaultTransportDialContext(&net.Dialer{
                Timeout:   30 * time.Second,
                KeepAlive: 30 * time.Second,
-       }).DialContext,
+       }),
        ForceAttemptHTTP2:     true,
        MaxIdleConns:          100,
        IdleConnTimeout:       90 * time.Second,
@@ -360,7 +360,7 @@ func (t *Transport) hasCustomTLSDialer() bool {
 // It must be called via t.nextProtoOnce.Do.
 func (t *Transport) onceSetNextProtoDefaults() {
        t.tlsNextProtoWasNil = (t.TLSNextProto == nil)
-       if strings.Contains(os.Getenv("GODEBUG"), "http2client=0") {
+       if godebug.Get("http2client") == "0" {
                return
        }
 
@@ -1715,12 +1715,12 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
                        return nil, err
                }
                if resp.StatusCode != 200 {
-                       f := strings.SplitN(resp.Status, " ", 2)
+                       _, text, ok := strings.Cut(resp.Status, " ")
                        conn.Close()
-                       if len(f) < 2 {
+                       if !ok {
                                return nil, errors.New("unknown status code")
                        }
-                       return nil, errors.New(f[1])
+                       return nil, errors.New(text)
                }
        }
 
diff --git a/src/net/http/transport_default_js.go b/src/net/http/transport_default_js.go
new file mode 100644 (file)
index 0000000..c07d35e
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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:build js && wasm
+// +build js,wasm
+
+package http
+
+import (
+       "context"
+       "net"
+)
+
+func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
+       return nil
+}
diff --git a/src/net/http/transport_default_other.go b/src/net/http/transport_default_other.go
new file mode 100644 (file)
index 0000000..8a2f1cc
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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:build !(js && wasm)
+// +build !js !wasm
+
+package http
+
+import (
+       "context"
+       "net"
+)
+
+func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
+       return dialer.DialContext
+}
index eeaa49264450de6785415669622801410d8abca9..0cdd946de4269a4e2fc50844d031944bcbc4303b 100644 (file)
@@ -6512,3 +6512,32 @@ func TestCancelRequestWhenSharingConnection(t *testing.T) {
        close(r2c)
        wg.Wait()
 }
+
+func TestHandlerAbortRacesBodyRead(t *testing.T) {
+       setParallel(t)
+       defer afterTest(t)
+
+       ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+               go io.Copy(io.Discard, req.Body)
+               panic(ErrAbortHandler)
+       }))
+       defer ts.Close()
+
+       var wg sync.WaitGroup
+       for i := 0; i < 2; i++ {
+               wg.Add(1)
+               go func() {
+                       defer wg.Done()
+                       for j := 0; j < 10; j++ {
+                               const reqLen = 6 * 1024 * 1024
+                               req, _ := NewRequest("POST", ts.URL, &io.LimitedReader{R: neverEnding('x'), N: reqLen})
+                               req.ContentLength = reqLen
+                               resp, _ := ts.Client().Transport.RoundTrip(req)
+                               if resp != nil {
+                                       resp.Body.Close()
+                               }
+                       }
+               }()
+       }
+       wg.Wait()
+}
index 4dc62407c6d5ecef2049db623b31c5db4d21df8f..11b19ab30c55be11df0a5e4afb2cc9c847c94d4f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 package main
 
index 49f78c2abbcbfa78eba1c57e3f8755842dc4a095..7ad45d11756a0646096121fdcf200a0e61ecd5e9 100644 (file)
@@ -78,7 +78,7 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                                // Retrieve MTU
                                ifr := &ifreq{}
                                copy(ifr.Name[:], ifi.Name)
-                               err = unix.Ioctl(sock, syscall.SIOCGIFMTU, uintptr(unsafe.Pointer(ifr)))
+                               err = unix.Ioctl(sock, syscall.SIOCGIFMTU, unsafe.Pointer(ifr))
                                if err != nil {
                                        return nil, err
                                }
index 7578b1a16a91a90baabeef015e2f84d18fe14fb3..db7bc756d8cfa597bea4407e7621ee5ec1173141 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 package net
 
index 8d0d9c367198d0abd5ba602c4209c6b0988c55ee..ce59962f6108f42e50f4f740b368933dbd420b15 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 package net
 
index 6230e0bfeec1d56a117c107beb69e9db7861d61b..e9bea3d3798a0672c4132114a93767e66b3d7f15 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || netbsd || openbsd
-// +build dragonfly netbsd openbsd
 
 package net
 
index 2b51fcb632a3f7add6cb1a0ece5b920899263e4d..8536bd3cf6482bbd46a9934497c1c0705fd3d8bf 100644 (file)
@@ -11,16 +11,11 @@ import (
 )
 
 func interfaceMessages(ifindex int) ([]route.Message, error) {
-       typ := route.RIBType(syscall.NET_RT_IFLISTL)
-       rib, err := route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
+       rib, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeInterface, ifindex)
        if err != nil {
-               typ = route.RIBType(syscall.NET_RT_IFLIST)
-               rib, err = route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
-               if err != nil {
-                       return nil, err
-               }
+               return nil, err
        }
-       return route.ParseRIB(typ, rib)
+       return route.ParseRIB(route.RIBTypeInterface, rib)
 }
 
 // interfaceMulticastAddrTable returns addresses for a specific
index efe67c24d3cde8d219488dcb3500471245a9a0b2..2d4475f63eeba33722afd2e6234abf4b073da104 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
index 754db36e3c44306edfa986165478611b574b3905..f6c98684181efbc4c68c0ec4db2c3c8da2bad035 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 0d69fa5da4127d2f9c863ec597db31ee8bdfcfa4..92ec13a909ca72ba736cd01c521ce65e2ab7b26a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd linux netbsd openbsd
 
 package net
 
index 8af85d382eb0935cbb606e9c6869a5b7354b69c8..c7c8d16d4c9a7e0435994022eae9ed7f7f252daf 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9
-// +build !js,!plan9
 
 package socktest_test
 
index 6aa8875b66cf6c1cee258401128c733ee49d4c66..7d21f6f99f6baadfa6735a23a09444c9a640efd7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9 && !windows
-// +build !js,!plan9,!windows
 
 package socktest_test
 
index cda74e8639986909c9a3bf740a825e547f12ba35..fcad4ceae31e8ed87018c12783821a62362e074b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9
-// +build !plan9
 
 package socktest
 
index 5aa2ecec08fd31ad596e475345c0befa72fc8721..8a2fc353f05816aa61f98c931bcc54e3705a6d06 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package socktest
 
index bfe9d4dbd3622927e8fa330219baa6404f007996..77d68f61120fdd904c8f576475c4c4a925770de4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package socktest
 
index c7f8331c2e52765321579b6d17a052cc7b3c3e97..cc7cefbe2c5cf046b35c692cb18b005d39e5f269 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build dragonfly freebsd illumos linux netbsd openbsd
 
 package socktest
 
index e7cc45922e09d1c6815c15cad54ee66673f08070..0424164ed3095eb79bf76284d2d08318ed7c7cd7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package socktest
 
index 5bbda6024dc3d9dd54189eb202afcb5cda572ad7..10e77f3bdb4aaee64c3cadea0d301a8f8faed3d1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index b94eec0e182b3d006771e30238078fdb93dd9f44..74f977e1efe079940e5d911686087095542def14 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
index a96448ee6c656817f1a16e5ff6fd27ca774048fa..ca5ab480c0eca9419e5a532979e6cf34668ae982 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index c51c2274015dcf8382e079bcb8ef3759d1a87f88..e433e8a91c75c0b025e657a98bebc33da9658e6e 100644 (file)
@@ -3,13 +3,13 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
 import (
        "context"
        "internal/poll"
+       "net/netip"
        "runtime"
        "syscall"
 )
@@ -142,42 +142,87 @@ func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, soty
        return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr, ctrlFn)
 }
 
+func ipToSockaddrInet4(ip IP, port int) (syscall.SockaddrInet4, error) {
+       if len(ip) == 0 {
+               ip = IPv4zero
+       }
+       ip4 := ip.To4()
+       if ip4 == nil {
+               return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+       }
+       sa := syscall.SockaddrInet4{Port: port}
+       copy(sa.Addr[:], ip4)
+       return sa, nil
+}
+
+func ipToSockaddrInet6(ip IP, port int, zone string) (syscall.SockaddrInet6, error) {
+       // In general, an IP wildcard address, which is either
+       // "0.0.0.0" or "::", means the entire IP addressing
+       // space. For some historical reason, it is used to
+       // specify "any available address" on some operations
+       // of IP node.
+       //
+       // When the IP node supports IPv4-mapped IPv6 address,
+       // we allow a listener to listen to the wildcard
+       // address of both IP addressing spaces by specifying
+       // IPv6 wildcard address.
+       if len(ip) == 0 || ip.Equal(IPv4zero) {
+               ip = IPv6zero
+       }
+       // We accept any IPv6 address including IPv4-mapped
+       // IPv6 address.
+       ip6 := ip.To16()
+       if ip6 == nil {
+               return syscall.SockaddrInet6{}, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+       }
+       sa := syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))}
+       copy(sa.Addr[:], ip6)
+       return sa, nil
+}
+
 func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
        switch family {
        case syscall.AF_INET:
-               if len(ip) == 0 {
-                       ip = IPv4zero
-               }
-               ip4 := ip.To4()
-               if ip4 == nil {
-                       return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+               sa, err := ipToSockaddrInet4(ip, port)
+               if err != nil {
+                       return nil, err
                }
-               sa := &syscall.SockaddrInet4{Port: port}
-               copy(sa.Addr[:], ip4)
-               return sa, nil
+               return &sa, nil
        case syscall.AF_INET6:
-               // In general, an IP wildcard address, which is either
-               // "0.0.0.0" or "::", means the entire IP addressing
-               // space. For some historical reason, it is used to
-               // specify "any available address" on some operations
-               // of IP node.
-               //
-               // When the IP node supports IPv4-mapped IPv6 address,
-               // we allow a listener to listen to the wildcard
-               // address of both IP addressing spaces by specifying
-               // IPv6 wildcard address.
-               if len(ip) == 0 || ip.Equal(IPv4zero) {
-                       ip = IPv6zero
-               }
-               // We accept any IPv6 address including IPv4-mapped
-               // IPv6 address.
-               ip6 := ip.To16()
-               if ip6 == nil {
-                       return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+               sa, err := ipToSockaddrInet6(ip, port, zone)
+               if err != nil {
+                       return nil, err
                }
-               sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))}
-               copy(sa.Addr[:], ip6)
-               return sa, nil
+               return &sa, nil
        }
        return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
 }
+
+func addrPortToSockaddrInet4(ap netip.AddrPort) (syscall.SockaddrInet4, error) {
+       // ipToSockaddrInet4 has special handling here for zero length slices.
+       // We do not, because netip has no concept of a generic zero IP address.
+       addr := ap.Addr()
+       if !addr.Is4() {
+               return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: addr.String()}
+       }
+       sa := syscall.SockaddrInet4{
+               Addr: addr.As4(),
+               Port: int(ap.Port()),
+       }
+       return sa, nil
+}
+
+func addrPortToSockaddrInet6(ap netip.AddrPort) (syscall.SockaddrInet6, error) {
+       // ipToSockaddrInet6 has special handling here for zero length slices.
+       // We do not, because netip has no concept of a generic zero IP address.
+       addr := ap.Addr()
+       if !addr.Is6() {
+               return syscall.SockaddrInet6{}, &AddrError{Err: "non-IPv6 address", Addr: addr.String()}
+       }
+       sa := syscall.SockaddrInet6{
+               Addr:   addr.As16(),
+               Port:   int(ap.Port()),
+               ZoneId: uint32(zoneCache.index(addr.Zone())),
+       }
+       return sa, nil
+}
index b1dce29ac209a91e45436583ef3ffa2788e39378..7aaebe8fa195d47bc91bb1136323607fa5a00e8b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9
-// +build !js,!plan9
 
 package net
 
@@ -535,8 +534,6 @@ func TestIPv4MulticastListener(t *testing.T) {
        switch runtime.GOOS {
        case "android", "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
-       case "solaris", "illumos":
-               t.Skipf("not supported on solaris or illumos, see golang.org/issue/7399")
        }
        if !supportsIPv4() {
                t.Skip("IPv4 is not supported")
@@ -610,8 +607,6 @@ func TestIPv6MulticastListener(t *testing.T) {
        switch runtime.GOOS {
        case "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
-       case "solaris", "illumos":
-               t.Skipf("not supported on solaris or illumos, see issue 7399")
        }
        if !supportsIPv6() {
                t.Skip("IPv6 is not supported")
index d350ef7fc03b0b6259a562e5f28b04a40157fdf0..e10c71ae753a91a6262d34a69f7310144c0e3a9e 100644 (file)
@@ -8,6 +8,7 @@ import (
        "context"
        "internal/nettrace"
        "internal/singleflight"
+       "net/netip"
        "sync"
 )
 
@@ -232,6 +233,28 @@ func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, er
        return ips, nil
 }
 
+// LookupNetIP looks up host using the local resolver.
+// It returns a slice of that host's IP addresses of the type specified by
+// network.
+// The network must be one of "ip", "ip4" or "ip6".
+func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
+       // TODO(bradfitz): make this efficient, making the internal net package
+       // type throughout be netip.Addr and only converting to the net.IP slice
+       // version at the edge. But for now (2021-10-20), this is a wrapper around
+       // the old way.
+       ips, err := r.LookupIP(ctx, network, host)
+       if err != nil {
+               return nil, err
+       }
+       ret := make([]netip.Addr, 0, len(ips))
+       for _, ip := range ips {
+               if a, ok := netip.AddrFromSlice(ip); ok {
+                       ret = append(ret, a)
+               }
+       }
+       return ret, nil
+}
+
 // onlyValuesCtx is a context that uses an underlying context
 // for value lookup if the underlying context hasn't yet expired.
 type onlyValuesCtx struct {
@@ -316,18 +339,39 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
                                lookupGroupCancel()
                        }()
                }
-               err := mapErr(ctx.Err())
+               ctxErr := ctx.Err()
+               err := &DNSError{
+                       Err:       mapErr(ctxErr).Error(),
+                       Name:      host,
+                       IsTimeout: ctxErr == context.DeadlineExceeded,
+               }
                if trace != nil && trace.DNSDone != nil {
                        trace.DNSDone(nil, false, err)
                }
                return nil, err
        case r := <-ch:
                lookupGroupCancel()
+               err := r.Err
+               if err != nil {
+                       if _, ok := err.(*DNSError); !ok {
+                               isTimeout := false
+                               if err == context.DeadlineExceeded {
+                                       isTimeout = true
+                               } else if terr, ok := err.(timeout); ok {
+                                       isTimeout = terr.Timeout()
+                               }
+                               err = &DNSError{
+                                       Err:       err.Error(),
+                                       Name:      host,
+                                       IsTimeout: isTimeout,
+                               }
+                       }
+               }
                if trace != nil && trace.DNSDone != nil {
                        addrs, _ := r.Val.([]IPAddr)
-                       trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
+                       trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
                }
-               return lookupIPReturn(r.Val, r.Err, r.Shared)
+               return lookupIPReturn(r.Val, err, r.Shared)
        }
 }
 
@@ -442,7 +486,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
 // The returned service names are validated to be properly
 // formatted presentation-format domain names. If the response contains
 // invalid names, those records are filtered out and an error
-// will be returned alongside the the remaining results, if any.
+// will be returned alongside the remaining results, if any.
 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
        return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
 }
@@ -460,7 +504,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
 // The returned service names are validated to be properly
 // formatted presentation-format domain names. If the response contains
 // invalid names, those records are filtered out and an error
-// will be returned alongside the the remaining results, if any.
+// will be returned alongside the remaining results, if any.
 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
        cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
        if err != nil {
@@ -490,7 +534,7 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (
 // The returned mail server names are validated to be properly
 // formatted presentation-format domain names. If the response contains
 // invalid names, those records are filtered out and an error
-// will be returned alongside the the remaining results, if any.
+// will be returned alongside the remaining results, if any.
 //
 // LookupMX uses context.Background internally; to specify the context, use
 // Resolver.LookupMX.
@@ -503,7 +547,7 @@ func LookupMX(name string) ([]*MX, error) {
 // The returned mail server names are validated to be properly
 // formatted presentation-format domain names. If the response contains
 // invalid names, those records are filtered out and an error
-// will be returned alongside the the remaining results, if any.
+// will be returned alongside the remaining results, if any.
 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
        records, err := r.lookupMX(ctx, name)
        if err != nil {
@@ -532,7 +576,7 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
 // The returned name server names are validated to be properly
 // formatted presentation-format domain names. If the response contains
 // invalid names, those records are filtered out and an error
-// will be returned alongside the the remaining results, if any.
+// will be returned alongside the remaining results, if any.
 //
 // LookupNS uses context.Background internally; to specify the context, use
 // Resolver.LookupNS.
@@ -545,7 +589,7 @@ func LookupNS(name string) ([]*NS, error) {
 // The returned name server names are validated to be properly
 // formatted presentation-format domain names. If the response contains
 // invalid names, those records are filtered out and an error
-// will be returned alongside the the remaining results, if any.
+// will be returned alongside the remaining results, if any.
 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
        records, err := r.lookupNS(ctx, name)
        if err != nil {
@@ -585,7 +629,7 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error)
 //
 // The returned names are validated to be properly formatted presentation-format
 // domain names. If the response contains invalid names, those records are filtered
-// out and an error will be returned alongside the the remaining results, if any.
+// out and an error will be returned alongside the remaining results, if any.
 //
 // When using the host C library resolver, at most one result will be
 // returned. To bypass the host resolver, use a custom Resolver.
@@ -601,7 +645,7 @@ func LookupAddr(addr string) (names []string, err error) {
 //
 // The returned names are validated to be properly formatted presentation-format
 // domain names. If the response contains invalid names, those records are filtered
-// out and an error will be returned alongside the the remaining results, if any.
+// out and an error will be returned alongside the remaining results, if any.
 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
        names, err := r.lookupAddr(ctx, addr)
        if err != nil {
@@ -620,6 +664,6 @@ func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error
 }
 
 // errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
-// method recieves DNS records which contain invalid DNS names. This may be returned alongside
+// method receives DNS records which contain invalid DNS names. This may be returned alongside
 // results which have had the malformed records filtered out.
 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
index f4fcaed5cfa1c78d9ca3b80d81926b20074de7dd..c27eae4ba5097e11460aae0f40f7206eb3c0a9df 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
index 75c18b33ac06f0eca362200a8909b45bf3ab23c3..d43a03b778d477a3327dfd00f96667a6f56b9507 100644 (file)
@@ -262,8 +262,8 @@ func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cn
                if !(portOk && priorityOk && weightOk) {
                        continue
                }
-               addrs = append(addrs, &SRV{absDomainName([]byte(f[5])), uint16(port), uint16(priority), uint16(weight)})
-               cname = absDomainName([]byte(f[0]))
+               addrs = append(addrs, &SRV{absDomainName(f[5]), uint16(port), uint16(priority), uint16(weight)})
+               cname = absDomainName(f[0])
        }
        byPriorityWeight(addrs).sort()
        return
@@ -280,7 +280,7 @@ func (*Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err error
                        continue
                }
                if pref, _, ok := dtoi(f[2]); ok {
-                       mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
+                       mx = append(mx, &MX{absDomainName(f[3]), uint16(pref)})
                }
        }
        byPref(mx).sort()
@@ -297,7 +297,7 @@ func (*Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err error
                if len(f) < 3 {
                        continue
                }
-               ns = append(ns, &NS{absDomainName([]byte(f[2]))})
+               ns = append(ns, &NS{absDomainName(f[2])})
        }
        return
 }
@@ -329,7 +329,7 @@ func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, er
                if len(f) < 3 {
                        continue
                }
-               name = append(name, absDomainName([]byte(f[2])))
+               name = append(name, absDomainName(f[2]))
        }
        return
 }
index 3faaf007106b7c7327f1eb194dfc8d944f8b53d4..7bcc5c5be839ed819af080c999ddf52f25a834fd 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
@@ -890,7 +889,7 @@ func TestLookupContextCancel(t *testing.T) {
        ctx, ctxCancel := context.WithCancel(context.Background())
        ctxCancel()
        _, err := DefaultResolver.LookupIPAddr(ctx, "google.com")
-       if err != errCanceled {
+       if err.(*DNSError).Err != errCanceled.Error() {
                testenv.SkipFlakyNet(t)
                t.Fatal(err)
        }
@@ -1267,3 +1266,71 @@ func TestResolverLookupIP(t *testing.T) {
                })
        }
 }
+
+// A context timeout should still return a DNSError.
+func TestDNSTimeout(t *testing.T) {
+       origTestHookLookupIP := testHookLookupIP
+       defer func() { testHookLookupIP = origTestHookLookupIP }()
+       defer dnsWaitGroup.Wait()
+
+       timeoutHookGo := make(chan bool, 1)
+       timeoutHook := func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
+               <-timeoutHookGo
+               return nil, context.DeadlineExceeded
+       }
+       testHookLookupIP = timeoutHook
+
+       checkErr := func(err error) {
+               t.Helper()
+               if err == nil {
+                       t.Error("expected an error")
+               } else if dnserr, ok := err.(*DNSError); !ok {
+                       t.Errorf("got error type %T, want %T", err, (*DNSError)(nil))
+               } else if !dnserr.IsTimeout {
+                       t.Errorf("got error %#v, want IsTimeout == true", dnserr)
+               } else if isTimeout := dnserr.Timeout(); !isTimeout {
+                       t.Errorf("got err.Timeout() == %t, want true", isTimeout)
+               }
+       }
+
+       // Single lookup.
+       timeoutHookGo <- true
+       _, err := LookupIP("golang.org")
+       checkErr(err)
+
+       // Double lookup.
+       var err1, err2 error
+       var wg sync.WaitGroup
+       wg.Add(2)
+       go func() {
+               defer wg.Done()
+               _, err1 = LookupIP("golang1.org")
+       }()
+       go func() {
+               defer wg.Done()
+               _, err2 = LookupIP("golang1.org")
+       }()
+       close(timeoutHookGo)
+       wg.Wait()
+       checkErr(err1)
+       checkErr(err2)
+
+       // Double lookup with context.
+       timeoutHookGo = make(chan bool)
+       ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
+       wg.Add(2)
+       go func() {
+               defer wg.Done()
+               _, err1 = DefaultResolver.LookupIPAddr(ctx, "golang2.org")
+       }()
+       go func() {
+               defer wg.Done()
+               _, err2 = DefaultResolver.LookupIPAddr(ctx, "golang2.org")
+       }()
+       time.Sleep(10 * time.Nanosecond)
+       close(timeoutHookGo)
+       wg.Wait()
+       checkErr(err1)
+       checkErr(err2)
+       cancel()
+}
index 8030e3d99e1e13dfb5e3f2ef8f361edba6e34af4..255a19dfdb4dd4bf8da0e6d6392688147e8fcd56 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index bb34a081336930dee36c8a6d17e67ded263f9058..27e5f86910e0fcff75b14b80731b4bebb46d21d4 100644 (file)
@@ -226,7 +226,7 @@ func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
        // windows returns DNS_INFO_NO_RECORDS if there are no CNAME-s
        if errno, ok := e.(syscall.Errno); ok && errno == syscall.DNS_INFO_NO_RECORDS {
                // if there are no aliases, the canonical name is the input name
-               return absDomainName([]byte(name)), nil
+               return absDomainName(name), nil
        }
        if e != nil {
                return "", &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
@@ -235,7 +235,7 @@ func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
 
        resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
        cname := windows.UTF16PtrToString(resolved)
-       return absDomainName([]byte(cname)), nil
+       return absDomainName(cname), nil
 }
 
 func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
@@ -258,10 +258,10 @@ func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (st
        srvs := make([]*SRV, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
                v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
-               srvs = append(srvs, &SRV{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]))), v.Port, v.Priority, v.Weight})
+               srvs = append(srvs, &SRV{absDomainName(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:])), v.Port, v.Priority, v.Weight})
        }
        byPriorityWeight(srvs).sort()
-       return absDomainName([]byte(target)), srvs, nil
+       return absDomainName(target), srvs, nil
 }
 
 func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
@@ -278,7 +278,7 @@ func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
        mxs := make([]*MX, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
                v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
-               mxs = append(mxs, &MX{absDomainName([]byte(windows.UTF16PtrToString(v.NameExchange))), v.Preference})
+               mxs = append(mxs, &MX{absDomainName(windows.UTF16PtrToString(v.NameExchange)), v.Preference})
        }
        byPref(mxs).sort()
        return mxs, nil
@@ -298,7 +298,7 @@ func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
        nss := make([]*NS, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
                v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-               nss = append(nss, &NS{absDomainName([]byte(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:])))})
+               nss = append(nss, &NS{absDomainName(syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))})
        }
        return nss, nil
 }
@@ -344,7 +344,7 @@ func (*Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error)
        ptrs := make([]string, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
                v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-               ptrs = append(ptrs, absDomainName([]byte(windows.UTF16PtrToString(v.Host))))
+               ptrs = append(ptrs, absDomainName(windows.UTF16PtrToString(v.Host)))
        }
        return ptrs, nil
 }
index aa95501d023930d114970e828296e9d10b531d9e..f726ef0f3475b064d59be85972f5cde95a7a9010 100644 (file)
@@ -220,14 +220,14 @@ func nslookupMX(name string) (mx []*MX, err error) {
        rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`)
        for _, ans := range rx.FindAllStringSubmatch(r, -1) {
                pref, _, _ := dtoi(ans[2])
-               mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
+               mx = append(mx, &MX{absDomainName(ans[3]), uint16(pref)})
        }
        // windows nslookup syntax
        // gmail.com       MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com
        rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`)
        for _, ans := range rx.FindAllStringSubmatch(r, -1) {
                pref, _, _ := dtoi(ans[2])
-               mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
+               mx = append(mx, &MX{absDomainName(ans[3]), uint16(pref)})
        }
        return
 }
@@ -241,7 +241,7 @@ func nslookupNS(name string) (ns []*NS, err error) {
        // golang.org      nameserver = ns1.google.com.
        rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+nameserver\s*=\s*([a-z0-9.\-]+)$`)
        for _, ans := range rx.FindAllStringSubmatch(r, -1) {
-               ns = append(ns, &NS{absDomainName([]byte(ans[2]))})
+               ns = append(ns, &NS{absDomainName(ans[2])})
        }
        return
 }
@@ -258,7 +258,7 @@ func nslookupCNAME(name string) (cname string, err error) {
        for _, ans := range rx.FindAllStringSubmatch(r, -1) {
                last = ans[2]
        }
-       return absDomainName([]byte(last)), nil
+       return absDomainName(last), nil
 }
 
 func nslookupTXT(name string) (txt []string, err error) {
@@ -299,7 +299,7 @@ func lookupPTR(name string) (ptr []string, err error) {
        ptr = make([]string, 0, 10)
        rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`)
        for _, ans := range rx.FindAllStringSubmatch(r, -1) {
-               ptr = append(ptr, absDomainName([]byte(ans[1])))
+               ptr = append(ptr, absDomainName(ans[1]))
        }
        return
 }
index 47bbf6ca9771bdcf23f3cd37357d21f721816ef3..c120316730c55a4ab127fa2017267fea041be126 100644 (file)
@@ -100,7 +100,7 @@ func ParseDate(date string) (time.Time, error) {
        dateLayoutsBuildOnce.Do(buildDateLayouts)
        // CR and LF must match and are tolerated anywhere in the date field.
        date = strings.ReplaceAll(date, "\r\n", "")
-       if strings.Index(date, "\r") != -1 {
+       if strings.Contains(date, "\r") {
                return time.Time{}, errors.New("mail: header has a CR without LF")
        }
        // Re-using some addrParser methods which support obsolete text, i.e. non-printable ASCII
index 742be2fcd81eef81e3300193e4d037a22897f5b3..ca7fc7849137a2d961284913076045d9f38f3b22 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build dragonfly freebsd illumos linux netbsd openbsd
 
 package net
 
index 645b267b78090835050a56c68e768759239b0f5f..41b78eda1d8219f58388e58512fe5e757450e1b8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9 && !windows
-// +build !js,!plan9,!windows
 
 package net
 
index bcea630cd3c4ccb037b4d19582c927892d13a825..ab050fac2b4ec04aad5b38be65d88a96fa1b1fb0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (js && wasm) || plan9 || windows
-// +build js,wasm plan9 windows
 
 package net
 
index c9ab25a4ad572ebb8e663fbf6bfe1d2c18999802..8899aa9c94ec7200b1e25b17062428e99d16eac3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9
-// +build !js,!plan9
 
 package net
 
@@ -18,9 +17,9 @@ func enableSocketConnect() {
 }
 
 func disableSocketConnect(network string) {
-       ss := strings.Split(network, ":")
+       net, _, _ := strings.Cut(network, ":")
        sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
-               switch ss[0] {
+               switch net {
                case "tcp4":
                        if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_STREAM {
                                return nil, syscall.EHOSTUNREACH
index dc17d3fbb84d1547879afa575352561299aa510e..1ee8c2efe717b44c1723a5f8e6435ce4f0b213f3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
@@ -174,11 +173,8 @@ func runningGoroutines() []string {
        b := make([]byte, 2<<20)
        b = b[:runtime.Stack(b, true)]
        for _, s := range strings.Split(string(b), "\n\n") {
-               ss := strings.SplitN(s, "\n", 2)
-               if len(ss) != 2 {
-                       continue
-               }
-               stack := strings.TrimSpace(ss[1])
+               _, stack, _ := strings.Cut(s, "\n")
+               stack = strings.TrimSpace(stack)
                if !strings.Contains(stack, "created by net") {
                        continue
                }
index c8cff2d305aa9998395a6641db90c359bf187b0a..2ed0615ad86a2ea8b6b33d87c1649410ae74bed9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index b50a1e59a1a9239b7da034fe38f6b1619e88ea95..43b11a72189895a8a3f157d4c560bc48297d2cb5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index a7c65fff79526d1ce70fef7a96eaafd9ff06dd18..ab6aeaac2f64bb0a71cb16a96375c4843c5712ee 100644 (file)
@@ -396,8 +396,12 @@ type Listener interface {
 // An Error represents a network error.
 type Error interface {
        error
-       Timeout() bool   // Is the error a timeout?
-       Temporary() bool // Is the error temporary?
+       Timeout() bool // Is the error a timeout?
+
+       // Deprecated: Temporary errors are not well-defined.
+       // Most "temporary" errors are timeouts, and the few exceptions are surprising.
+       // Do not use this method.
+       Temporary() bool
 }
 
 // Various errors contained in OpError.
index 74fc1da6fd80af665696880153bfc49a508900d6..ee5644c67f087f77c021aa747a61c5f368b18b1e 100644 (file)
@@ -5,7 +5,6 @@
 // Fake networking for js/wasm. It is intended to allow tests of other package to pass.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
@@ -266,16 +265,48 @@ func sysSocket(family, sotype, proto int) (int, error) {
 
 func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
        return 0, nil, syscall.ENOSYS
+
+}
+func (fd *netFD) readFromInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
+       return 0, syscall.ENOSYS
+}
+
+func (fd *netFD) readFromInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
+       return 0, syscall.ENOSYS
 }
 
 func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
        return 0, 0, 0, nil, syscall.ENOSYS
 }
 
+func (fd *netFD) readMsgInet4(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet4) (n, oobn, retflags int, err error) {
+       return 0, 0, 0, syscall.ENOSYS
+}
+
+func (fd *netFD) readMsgInet6(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet6) (n, oobn, retflags int, err error) {
+       return 0, 0, 0, syscall.ENOSYS
+}
+
+func (fd *netFD) writeMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (n int, oobn int, err error) {
+       return 0, 0, syscall.ENOSYS
+}
+
+func (fd *netFD) writeMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (n int, oobn int, err error) {
+       return 0, 0, syscall.ENOSYS
+}
+
 func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
        return 0, syscall.ENOSYS
 }
 
+func (fd *netFD) writeToInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
+       return 0, syscall.ENOSYS
+}
+
+func (fd *netFD) writeToInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
+       return 0, syscall.ENOSYS
+}
+
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
        return 0, 0, syscall.ENOSYS
 }
index 6e7be4db23c1e2a26733bf251ff47546efcddd0d..35acac509be0314c99333611e2f8f968efc4098f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 5551e47de7ff7d2c616be585492eb13ebf4aa52e..019772aa6aaab4ed183ca1089e44b6b89adba2e0 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (!cgo || netgo) && (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris)
-// +build !cgo netgo
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
diff --git a/src/net/netip/export_test.go b/src/net/netip/export_test.go
new file mode 100644 (file)
index 0000000..59971fa
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2021 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 netip
+
+import "internal/intern"
+
+var (
+       Z0    = z0
+       Z4    = z4
+       Z6noz = z6noz
+)
+
+type Uint128 = uint128
+
+func Mk128(hi, lo uint64) Uint128 {
+       return uint128{hi, lo}
+}
+
+func MkAddr(u Uint128, z *intern.Value) Addr {
+       return Addr{u, z}
+}
+
+func IPv4(a, b, c, d uint8) Addr { return AddrFrom4([4]byte{a, b, c, d}) }
+
+var TestAppendToMarshal = testAppendToMarshal
+
+func (a Addr) IsZero() bool   { return a.isZero() }
+func (p Prefix) IsZero() bool { return p.isZero() }
diff --git a/src/net/netip/inlining_test.go b/src/net/netip/inlining_test.go
new file mode 100644 (file)
index 0000000..107fe1f
--- /dev/null
@@ -0,0 +1,110 @@
+// 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 netip
+
+import (
+       "internal/testenv"
+       "os/exec"
+       "path/filepath"
+       "regexp"
+       "runtime"
+       "strings"
+       "testing"
+)
+
+func TestInlining(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       t.Parallel()
+       var exe string
+       if runtime.GOOS == "windows" {
+               exe = ".exe"
+       }
+       out, err := exec.Command(
+               filepath.Join(runtime.GOROOT(), "bin", "go"+exe),
+               "build",
+               "--gcflags=-m",
+               "net/netip").CombinedOutput()
+       if err != nil {
+               t.Fatalf("go build: %v, %s", err, out)
+       }
+       got := map[string]bool{}
+       regexp.MustCompile(` can inline (\S+)`).ReplaceAllFunc(out, func(match []byte) []byte {
+               got[strings.TrimPrefix(string(match), " can inline ")] = true
+               return nil
+       })
+       wantInlinable := []string{
+               "(*uint128).halves",
+               "Addr.BitLen",
+               "Addr.hasZone",
+               "Addr.Is4",
+               "Addr.Is4In6",
+               "Addr.Is6",
+               "Addr.IsLoopback",
+               "Addr.IsMulticast",
+               "Addr.IsInterfaceLocalMulticast",
+               "Addr.IsValid",
+               "Addr.IsUnspecified",
+               "Addr.Less",
+               "Addr.lessOrEq",
+               "Addr.Unmap",
+               "Addr.Zone",
+               "Addr.v4",
+               "Addr.v6",
+               "Addr.v6u16",
+               "Addr.withoutZone",
+               "AddrPortFrom",
+               "AddrPort.Addr",
+               "AddrPort.Port",
+               "AddrPort.IsValid",
+               "Prefix.IsSingleIP",
+               "Prefix.Masked",
+               "Prefix.IsValid",
+               "PrefixFrom",
+               "Prefix.Addr",
+               "Prefix.Bits",
+               "AddrFrom4",
+               "IPv6LinkLocalAllNodes",
+               "IPv6Unspecified",
+               "MustParseAddr",
+               "MustParseAddrPort",
+               "MustParsePrefix",
+               "appendDecimal",
+               "appendHex",
+               "uint128.addOne",
+               "uint128.and",
+               "uint128.bitsClearedFrom",
+               "uint128.bitsSetFrom",
+               "uint128.isZero",
+               "uint128.not",
+               "uint128.or",
+               "uint128.subOne",
+               "uint128.xor",
+       }
+       switch runtime.GOARCH {
+       case "amd64", "arm64":
+               // These don't inline on 32-bit.
+               wantInlinable = append(wantInlinable,
+                       "u64CommonPrefixLen",
+                       "uint128.commonPrefixLen",
+                       "Addr.Next",
+                       "Addr.Prev",
+               )
+       }
+
+       for _, want := range wantInlinable {
+               if !got[want] {
+                       t.Errorf("%q is no longer inlinable", want)
+                       continue
+               }
+               delete(got, want)
+       }
+       for sym := range got {
+               if strings.Contains(sym, ".func") {
+                       continue
+               }
+               t.Logf("not in expected set, but also inlinable: %q", sym)
+
+       }
+}
diff --git a/src/net/netip/leaf_alts.go b/src/net/netip/leaf_alts.go
new file mode 100644 (file)
index 0000000..c51f7df
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2021 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.
+
+// Stuff that exists in std, but we can't use due to being a dependency
+// of net, for go/build deps_test policy reasons.
+
+package netip
+
+func stringsLastIndexByte(s string, b byte) int {
+       for i := len(s) - 1; i >= 0; i-- {
+               if s[i] == b {
+                       return i
+               }
+       }
+       return -1
+}
+
+func beUint64(b []byte) uint64 {
+       _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+               uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func bePutUint64(b []byte, v uint64) {
+       _ = b[7] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v >> 56)
+       b[1] = byte(v >> 48)
+       b[2] = byte(v >> 40)
+       b[3] = byte(v >> 32)
+       b[4] = byte(v >> 24)
+       b[5] = byte(v >> 16)
+       b[6] = byte(v >> 8)
+       b[7] = byte(v)
+}
+
+func bePutUint32(b []byte, v uint32) {
+       _ = b[3] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v >> 24)
+       b[1] = byte(v >> 16)
+       b[2] = byte(v >> 8)
+       b[3] = byte(v)
+}
diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go
new file mode 100644 (file)
index 0000000..02a4aa0
--- /dev/null
@@ -0,0 +1,1414 @@
+// 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 netip defines an IP address type that's a small value type.
+// Building on that Addr type, the package also defines AddrPort (an
+// IP address and a port), and Prefix (an IP address and a bit length
+// prefix).
+//
+// Compared to the net.IP type, this package's Addr type takes less
+// memory, is immutable, and is comparable (supports == and being a
+// map key).
+package netip
+
+import (
+       "errors"
+       "math"
+       "strconv"
+
+       "internal/bytealg"
+       "internal/intern"
+       "internal/itoa"
+)
+
+// Sizes: (64-bit)
+//   net.IP:     24 byte slice header + {4, 16} = 28 to 40 bytes
+//   net.IPAddr: 40 byte slice header + {4, 16} = 44 to 56 bytes + zone length
+//   netip.Addr: 24 bytes (zone is per-name singleton, shared across all users)
+
+// Addr represents an IPv4 or IPv6 address (with or without a scoped
+// addressing zone), similar to net.IP or net.IPAddr.
+//
+// Unlike net.IP or net.IPAddr, Addr is a comparable value
+// type (it supports == and can be a map key) and is immutable.
+type Addr struct {
+       // addr is the hi and lo bits of an IPv6 address. If z==z4,
+       // hi and lo contain the IPv4-mapped IPv6 address.
+       //
+       // hi and lo are constructed by interpreting a 16-byte IPv6
+       // address as a big-endian 128-bit number. The most significant
+       // bits of that number go into hi, the rest into lo.
+       //
+       // For example, 0011:2233:4455:6677:8899:aabb:ccdd:eeff is stored as:
+       //  addr.hi = 0x0011223344556677
+       //  addr.lo = 0x8899aabbccddeeff
+       //
+       // We store IPs like this, rather than as [16]byte, because it
+       // turns most operations on IPs into arithmetic and bit-twiddling
+       // operations on 64-bit registers, which is much faster than
+       // bytewise processing.
+       addr uint128
+
+       // z is a combination of the address family and the IPv6 zone.
+       //
+       // nil means invalid IP address (for a zero Addr).
+       // z4 means an IPv4 address.
+       // z6noz means an IPv6 address without a zone.
+       //
+       // Otherwise it's the interned zone name string.
+       z *intern.Value
+}
+
+// z0, z4, and z6noz are sentinel IP.z values.
+// See the IP type's field docs.
+var (
+       z0    = (*intern.Value)(nil)
+       z4    = new(intern.Value)
+       z6noz = new(intern.Value)
+)
+
+// IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast
+// address ff02::1.
+func IPv6LinkLocalAllNodes() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) }
+
+// IPv6Unspecified returns the IPv6 unspecified address "::".
+func IPv6Unspecified() Addr { return Addr{z: z6noz} }
+
+// AddrFrom4 returns the address of the IPv4 address given by the bytes in addr.
+func AddrFrom4(addr [4]byte) Addr {
+       return Addr{
+               addr: uint128{0, 0xffff00000000 | uint64(addr[0])<<24 | uint64(addr[1])<<16 | uint64(addr[2])<<8 | uint64(addr[3])},
+               z:    z4,
+       }
+}
+
+// AddrFrom16 returns the IPv6 address given by the bytes in addr.
+// An IPv6-mapped IPv4 address is left as an IPv6 address.
+// (Use Unmap to convert them if needed.)
+func AddrFrom16(addr [16]byte) Addr {
+       return Addr{
+               addr: uint128{
+                       beUint64(addr[:8]),
+                       beUint64(addr[8:]),
+               },
+               z: z6noz,
+       }
+}
+
+// ipv6Slice is like IPv6Raw, but operates on a 16-byte slice. Assumes
+// slice is 16 bytes, caller must enforce this.
+func ipv6Slice(addr []byte) Addr {
+       return Addr{
+               addr: uint128{
+                       beUint64(addr[:8]),
+                       beUint64(addr[8:]),
+               },
+               z: z6noz,
+       }
+}
+
+// ParseAddr parses s as an IP address, returning the result. The string
+// s can be in dotted decimal ("192.0.2.1"), IPv6 ("2001:db8::68"),
+// or IPv6 with a scoped addressing zone ("fe80::1cc0:3e8c:119f:c2e1%ens18").
+func ParseAddr(s string) (Addr, error) {
+       for i := 0; i < len(s); i++ {
+               switch s[i] {
+               case '.':
+                       return parseIPv4(s)
+               case ':':
+                       return parseIPv6(s)
+               case '%':
+                       // Assume that this was trying to be an IPv6 address with
+                       // a zone specifier, but the address is missing.
+                       return Addr{}, parseAddrError{in: s, msg: "missing IPv6 address"}
+               }
+       }
+       return Addr{}, parseAddrError{in: s, msg: "unable to parse IP"}
+}
+
+// MustParseAddr calls ParseAddr(s) and panics on error.
+// It is intended for use in tests with hard-coded strings.
+func MustParseAddr(s string) Addr {
+       ip, err := ParseAddr(s)
+       if err != nil {
+               panic(err)
+       }
+       return ip
+}
+
+type parseAddrError struct {
+       in  string // the string given to ParseAddr
+       msg string // an explanation of the parse failure
+       at  string // optionally, the unparsed portion of in at which the error occurred.
+}
+
+func (err parseAddrError) Error() string {
+       q := strconv.Quote
+       if err.at != "" {
+               return "ParseAddr(" + q(err.in) + "): " + err.msg + " (at " + q(err.at) + ")"
+       }
+       return "ParseAddr(" + q(err.in) + "): " + err.msg
+}
+
+// parseIPv4 parses s as an IPv4 address (in form "192.168.0.1").
+func parseIPv4(s string) (ip Addr, err error) {
+       var fields [4]uint8
+       var val, pos int
+       for i := 0; i < len(s); i++ {
+               if s[i] >= '0' && s[i] <= '9' {
+                       val = val*10 + int(s[i]) - '0'
+                       if val > 255 {
+                               return Addr{}, parseAddrError{in: s, msg: "IPv4 field has value >255"}
+                       }
+               } else if s[i] == '.' {
+                       // .1.2.3
+                       // 1.2.3.
+                       // 1..2.3
+                       if i == 0 || i == len(s)-1 || s[i-1] == '.' {
+                               return Addr{}, parseAddrError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]}
+                       }
+                       // 1.2.3.4.5
+                       if pos == 3 {
+                               return Addr{}, parseAddrError{in: s, msg: "IPv4 address too long"}
+                       }
+                       fields[pos] = uint8(val)
+                       pos++
+                       val = 0
+               } else {
+                       return Addr{}, parseAddrError{in: s, msg: "unexpected character", at: s[i:]}
+               }
+       }
+       if pos < 3 {
+               return Addr{}, parseAddrError{in: s, msg: "IPv4 address too short"}
+       }
+       fields[3] = uint8(val)
+       return AddrFrom4(fields), nil
+}
+
+// parseIPv6 parses s as an IPv6 address (in form "2001:db8::68").
+func parseIPv6(in string) (Addr, error) {
+       s := in
+
+       // Split off the zone right from the start. Yes it's a second scan
+       // of the string, but trying to handle it inline makes a bunch of
+       // other inner loop conditionals more expensive, and it ends up
+       // being slower.
+       zone := ""
+       i := bytealg.IndexByteString(s, '%')
+       if i != -1 {
+               s, zone = s[:i], s[i+1:]
+               if zone == "" {
+                       // Not allowed to have an empty zone if explicitly specified.
+                       return Addr{}, parseAddrError{in: in, msg: "zone must be a non-empty string"}
+               }
+       }
+
+       var ip [16]byte
+       ellipsis := -1 // position of ellipsis in ip
+
+       // Might have leading ellipsis
+       if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
+               ellipsis = 0
+               s = s[2:]
+               // Might be only ellipsis
+               if len(s) == 0 {
+                       return IPv6Unspecified().WithZone(zone), nil
+               }
+       }
+
+       // Loop, parsing hex numbers followed by colon.
+       i = 0
+       for i < 16 {
+               // Hex number. Similar to parseIPv4, inlining the hex number
+               // parsing yields a significant performance increase.
+               off := 0
+               acc := uint32(0)
+               for ; off < len(s); off++ {
+                       c := s[off]
+                       if c >= '0' && c <= '9' {
+                               acc = (acc << 4) + uint32(c-'0')
+                       } else if c >= 'a' && c <= 'f' {
+                               acc = (acc << 4) + uint32(c-'a'+10)
+                       } else if c >= 'A' && c <= 'F' {
+                               acc = (acc << 4) + uint32(c-'A'+10)
+                       } else {
+                               break
+                       }
+                       if acc > math.MaxUint16 {
+                               // Overflow, fail.
+                               return Addr{}, parseAddrError{in: in, msg: "IPv6 field has value >=2^16", at: s}
+                       }
+               }
+               if off == 0 {
+                       // No digits found, fail.
+                       return Addr{}, parseAddrError{in: in, msg: "each colon-separated field must have at least one digit", at: s}
+               }
+
+               // If followed by dot, might be in trailing IPv4.
+               if off < len(s) && s[off] == '.' {
+                       if ellipsis < 0 && i != 12 {
+                               // Not the right place.
+                               return Addr{}, parseAddrError{in: in, msg: "embedded IPv4 address must replace the final 2 fields of the address", at: s}
+                       }
+                       if i+4 > 16 {
+                               // Not enough room.
+                               return Addr{}, parseAddrError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s}
+                       }
+                       // TODO: could make this a bit faster by having a helper
+                       // that parses to a [4]byte, and have both parseIPv4 and
+                       // parseIPv6 use it.
+                       ip4, err := parseIPv4(s)
+                       if err != nil {
+                               return Addr{}, parseAddrError{in: in, msg: err.Error(), at: s}
+                       }
+                       ip[i] = ip4.v4(0)
+                       ip[i+1] = ip4.v4(1)
+                       ip[i+2] = ip4.v4(2)
+                       ip[i+3] = ip4.v4(3)
+                       s = ""
+                       i += 4
+                       break
+               }
+
+               // Save this 16-bit chunk.
+               ip[i] = byte(acc >> 8)
+               ip[i+1] = byte(acc)
+               i += 2
+
+               // Stop at end of string.
+               s = s[off:]
+               if len(s) == 0 {
+                       break
+               }
+
+               // Otherwise must be followed by colon and more.
+               if s[0] != ':' {
+                       return Addr{}, parseAddrError{in: in, msg: "unexpected character, want colon", at: s}
+               } else if len(s) == 1 {
+                       return Addr{}, parseAddrError{in: in, msg: "colon must be followed by more characters", at: s}
+               }
+               s = s[1:]
+
+               // Look for ellipsis.
+               if s[0] == ':' {
+                       if ellipsis >= 0 { // already have one
+                               return Addr{}, parseAddrError{in: in, msg: "multiple :: in address", at: s}
+                       }
+                       ellipsis = i
+                       s = s[1:]
+                       if len(s) == 0 { // can be at end
+                               break
+                       }
+               }
+       }
+
+       // Must have used entire string.
+       if len(s) != 0 {
+               return Addr{}, parseAddrError{in: in, msg: "trailing garbage after address", at: s}
+       }
+
+       // If didn't parse enough, expand ellipsis.
+       if i < 16 {
+               if ellipsis < 0 {
+                       return Addr{}, parseAddrError{in: in, msg: "address string too short"}
+               }
+               n := 16 - i
+               for j := i - 1; j >= ellipsis; j-- {
+                       ip[j+n] = ip[j]
+               }
+               for j := ellipsis + n - 1; j >= ellipsis; j-- {
+                       ip[j] = 0
+               }
+       } else if ellipsis >= 0 {
+               // Ellipsis must represent at least one 0 group.
+               return Addr{}, parseAddrError{in: in, msg: "the :: must expand to at least one field of zeros"}
+       }
+       return AddrFrom16(ip).WithZone(zone), nil
+}
+
+// AddrFromSlice parses the 4- or 16-byte byte slice as an IPv4 or IPv6 address.
+// Note that a net.IP can be passed directly as the []byte argument.
+// If slice's length is not 4 or 16, AddrFromSlice returns Addr{}, false.
+func AddrFromSlice(slice []byte) (ip Addr, ok bool) {
+       switch len(slice) {
+       case 4:
+               return AddrFrom4(*(*[4]byte)(slice)), true
+       case 16:
+               return ipv6Slice(slice), true
+       }
+       return Addr{}, false
+}
+
+// v4 returns the i'th byte of ip. If ip is not an IPv4, v4 returns
+// unspecified garbage.
+func (ip Addr) v4(i uint8) uint8 {
+       return uint8(ip.addr.lo >> ((3 - i) * 8))
+}
+
+// v6 returns the i'th byte of ip. If ip is an IPv4 address, this
+// accesses the IPv4-mapped IPv6 address form of the IP.
+func (ip Addr) v6(i uint8) uint8 {
+       return uint8(*(ip.addr.halves()[(i/8)%2]) >> ((7 - i%8) * 8))
+}
+
+// v6u16 returns the i'th 16-bit word of ip. If ip is an IPv4 address,
+// this accesses the IPv4-mapped IPv6 address form of the IP.
+func (ip Addr) v6u16(i uint8) uint16 {
+       return uint16(*(ip.addr.halves()[(i/4)%2]) >> ((3 - i%4) * 16))
+}
+
+// isZero reports whether ip is the zero value of the IP type.
+// The zero value is not a valid IP address of any type.
+//
+// Note that "0.0.0.0" and "::" are not the zero value. Use IsUnspecified to
+// check for these values instead.
+func (ip Addr) isZero() bool {
+       // Faster than comparing ip == Addr{}, but effectively equivalent,
+       // as there's no way to make an IP with a nil z from this package.
+       return ip.z == z0
+}
+
+// IsValid reports whether the Addr is an initialized address (not the zero Addr).
+//
+// Note that "0.0.0.0" and "::" are both valid values.
+func (ip Addr) IsValid() bool { return ip.z != z0 }
+
+// BitLen returns the number of bits in the IP address:
+// 128 for IPv6, 32 for IPv4, and 0 for the zero Addr.
+//
+// Note that IPv4-mapped IPv6 addresses are considered IPv6 addresses
+// and therefore have bit length 128.
+func (ip Addr) BitLen() int {
+       switch ip.z {
+       case z0:
+               return 0
+       case z4:
+               return 32
+       }
+       return 128
+}
+
+// Zone returns ip's IPv6 scoped addressing zone, if any.
+func (ip Addr) Zone() string {
+       if ip.z == nil {
+               return ""
+       }
+       zone, _ := ip.z.Get().(string)
+       return zone
+}
+
+// Compare returns an integer comparing two IPs.
+// The result will be 0 if ip == ip2, -1 if ip < ip2, and +1 if ip > ip2.
+// The definition of "less than" is the same as the Less method.
+func (ip Addr) Compare(ip2 Addr) int {
+       f1, f2 := ip.BitLen(), ip2.BitLen()
+       if f1 < f2 {
+               return -1
+       }
+       if f1 > f2 {
+               return 1
+       }
+       hi1, hi2 := ip.addr.hi, ip2.addr.hi
+       if hi1 < hi2 {
+               return -1
+       }
+       if hi1 > hi2 {
+               return 1
+       }
+       lo1, lo2 := ip.addr.lo, ip2.addr.lo
+       if lo1 < lo2 {
+               return -1
+       }
+       if lo1 > lo2 {
+               return 1
+       }
+       if ip.Is6() {
+               za, zb := ip.Zone(), ip2.Zone()
+               if za < zb {
+                       return -1
+               }
+               if za > zb {
+                       return 1
+               }
+       }
+       return 0
+}
+
+// Less reports whether ip sorts before ip2.
+// IP addresses sort first by length, then their address.
+// IPv6 addresses with zones sort just after the same address without a zone.
+func (ip Addr) Less(ip2 Addr) bool { return ip.Compare(ip2) == -1 }
+
+func (ip Addr) lessOrEq(ip2 Addr) bool { return ip.Compare(ip2) <= 0 }
+
+// ipZone returns the standard library net.IP from ip, as well
+// as the zone.
+// The optional reuse IP provides memory to reuse.
+func (ip Addr) ipZone(reuse []byte) (stdIP []byte, zone string) {
+       base := reuse[:0]
+       switch {
+       case ip.z == z0:
+               return nil, ""
+       case ip.Is4():
+               a4 := ip.As4()
+               return append(base, a4[:]...), ""
+       default:
+               a16 := ip.As16()
+               return append(base, a16[:]...), ip.Zone()
+       }
+}
+
+// IPAddrParts returns the net.IPAddr representation of an Addr.
+//
+// The slice will be nil if ip is the zero Addr.
+// The zone is the empty string if there is no zone.
+func (ip Addr) IPAddrParts() (slice []byte, zone string) {
+       return ip.ipZone(nil)
+}
+
+// Is4 reports whether ip is an IPv4 address.
+//
+// It returns false for IP4-mapped IPv6 addresses. See IP.Unmap.
+func (ip Addr) Is4() bool {
+       return ip.z == z4
+}
+
+// Is4In6 reports whether ip is an IPv4-mapped IPv6 address.
+func (ip Addr) Is4In6() bool {
+       return ip.Is6() && ip.addr.hi == 0 && ip.addr.lo>>32 == 0xffff
+}
+
+// Is6 reports whether ip is an IPv6 address, including IPv4-mapped
+// IPv6 addresses.
+func (ip Addr) Is6() bool {
+       return ip.z != z0 && ip.z != z4
+}
+
+// Unmap returns ip with any IPv4-mapped IPv6 address prefix removed.
+//
+// That is, if ip is an IPv6 address wrapping an IPv4 adddress, it
+// returns the wrapped IPv4 address. Otherwise it returns ip unmodified.
+func (ip Addr) Unmap() Addr {
+       if ip.Is4In6() {
+               ip.z = z4
+       }
+       return ip
+}
+
+// WithZone returns an IP that's the same as ip but with the provided
+// zone. If zone is empty, the zone is removed. If ip is an IPv4
+// address, WithZone is a no-op and returns ip unchanged.
+func (ip Addr) WithZone(zone string) Addr {
+       if !ip.Is6() {
+               return ip
+       }
+       if zone == "" {
+               ip.z = z6noz
+               return ip
+       }
+       ip.z = intern.GetByString(zone)
+       return ip
+}
+
+// withoutZone unconditionally strips the zone from IP.
+// It's similar to WithZone, but small enough to be inlinable.
+func (ip Addr) withoutZone() Addr {
+       if !ip.Is6() {
+               return ip
+       }
+       ip.z = z6noz
+       return ip
+}
+
+// hasZone reports whether IP has an IPv6 zone.
+func (ip Addr) hasZone() bool {
+       return ip.z != z0 && ip.z != z4 && ip.z != z6noz
+}
+
+// IsLinkLocalUnicast reports whether ip is a link-local unicast address.
+func (ip Addr) IsLinkLocalUnicast() bool {
+       // Dynamic Configuration of IPv4 Link-Local Addresses
+       // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1
+       if ip.Is4() {
+               return ip.v4(0) == 169 && ip.v4(1) == 254
+       }
+       // IP Version 6 Addressing Architecture (2.4 Address Type Identification)
+       // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
+       if ip.Is6() {
+               return ip.v6u16(0)&0xffc0 == 0xfe80
+       }
+       return false // zero value
+}
+
+// IsLoopback reports whether ip is a loopback address.
+func (ip Addr) IsLoopback() bool {
+       // Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing)
+       // https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3
+       if ip.Is4() {
+               return ip.v4(0) == 127
+       }
+       // IP Version 6 Addressing Architecture (2.4 Address Type Identification)
+       // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
+       if ip.Is6() {
+               return ip.addr.hi == 0 && ip.addr.lo == 1
+       }
+       return false // zero value
+}
+
+// IsMulticast reports whether ip is a multicast address.
+func (ip Addr) IsMulticast() bool {
+       // Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES)
+       // https://datatracker.ietf.org/doc/html/rfc1112#section-4
+       if ip.Is4() {
+               return ip.v4(0)&0xf0 == 0xe0
+       }
+       // IP Version 6 Addressing Architecture (2.4 Address Type Identification)
+       // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
+       if ip.Is6() {
+               return ip.addr.hi>>(64-8) == 0xff // ip.v6(0) == 0xff
+       }
+       return false // zero value
+}
+
+// IsInterfaceLocalMulticast reports whether ip is an IPv6 interface-local
+// multicast address.
+func (ip Addr) IsInterfaceLocalMulticast() bool {
+       // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses)
+       // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
+       if ip.Is6() {
+               return ip.v6u16(0)&0xff0f == 0xff01
+       }
+       return false // zero value
+}
+
+// IsLinkLocalMulticast reports whether ip is a link-local multicast address.
+func (ip Addr) IsLinkLocalMulticast() bool {
+       // IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24))
+       // https://datatracker.ietf.org/doc/html/rfc5771#section-4
+       if ip.Is4() {
+               return ip.v4(0) == 224 && ip.v4(1) == 0 && ip.v4(2) == 0
+       }
+       // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses)
+       // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
+       if ip.Is6() {
+               return ip.v6u16(0)&0xff0f == 0xff02
+       }
+       return false // zero value
+}
+
+// IsGlobalUnicast reports whether ip is a global unicast address.
+//
+// It returns true for IPv6 addresses which fall outside of the current
+// IANA-allocated 2000::/3 global unicast space, with the exception of the
+// link-local address space. It also returns true even if ip is in the IPv4
+// private address space or IPv6 unique local address space.
+// It returns false for the zero Addr.
+//
+// For reference, see RFC 1122, RFC 4291, and RFC 4632.
+func (ip Addr) IsGlobalUnicast() bool {
+       if ip.z == z0 {
+               // Invalid or zero-value.
+               return false
+       }
+
+       // Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses
+       // and ULA IPv6 addresses are still considered "global unicast".
+       if ip.Is4() && (ip == AddrFrom4([4]byte{}) || ip == AddrFrom4([4]byte{255, 255, 255, 255})) {
+               return false
+       }
+
+       return ip != IPv6Unspecified() &&
+               !ip.IsLoopback() &&
+               !ip.IsMulticast() &&
+               !ip.IsLinkLocalUnicast()
+}
+
+// IsPrivate reports whether ip is a private address, according to RFC 1918
+// (IPv4 addresses) and RFC 4193 (IPv6 addresses). That is, it reports whether
+// ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the
+// same as net.IP.IsPrivate.
+func (ip Addr) IsPrivate() bool {
+       // Match the stdlib's IsPrivate logic.
+       if ip.Is4() {
+               // RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as
+               // private IPv4 address subnets.
+               return ip.v4(0) == 10 ||
+                       (ip.v4(0) == 172 && ip.v4(1)&0xf0 == 16) ||
+                       (ip.v4(0) == 192 && ip.v4(1) == 168)
+       }
+
+       if ip.Is6() {
+               // RFC 4193 allocates fc00::/7 as the unique local unicast IPv6 address
+               // subnet.
+               return ip.v6(0)&0xfe == 0xfc
+       }
+
+       return false // zero value
+}
+
+// IsUnspecified reports whether ip is an unspecified address, either the IPv4
+// address "0.0.0.0" or the IPv6 address "::".
+//
+// Note that the zero Addr is not an unspecified address.
+func (ip Addr) IsUnspecified() bool {
+       return ip == AddrFrom4([4]byte{}) || ip == IPv6Unspecified()
+}
+
+// Prefix keeps only the top b bits of IP, producing a Prefix
+// of the specified length.
+// If ip is a zero Addr, Prefix always returns a zero Prefix and a nil error.
+// Otherwise, if bits is less than zero or greater than ip.BitLen(),
+// Prefix returns an error.
+func (ip Addr) Prefix(b int) (Prefix, error) {
+       if b < 0 {
+               return Prefix{}, errors.New("negative Prefix bits")
+       }
+       effectiveBits := b
+       switch ip.z {
+       case z0:
+               return Prefix{}, nil
+       case z4:
+               if b > 32 {
+                       return Prefix{}, errors.New("prefix length " + itoa.Itoa(b) + " too large for IPv4")
+               }
+               effectiveBits += 96
+       default:
+               if b > 128 {
+                       return Prefix{}, errors.New("prefix length " + itoa.Itoa(b) + " too large for IPv6")
+               }
+       }
+       ip.addr = ip.addr.and(mask6(effectiveBits))
+       return PrefixFrom(ip, b), nil
+}
+
+const (
+       netIPv4len = 4
+       netIPv6len = 16
+)
+
+// As16 returns the IP address in its 16-byte representation.
+// IPv4 addresses are returned in their v6-mapped form.
+// IPv6 addresses with zones are returned without their zone (use the
+// Zone method to get it).
+// The ip zero value returns all zeroes.
+func (ip Addr) As16() [16]byte {
+       var ret [16]byte
+       bePutUint64(ret[:8], ip.addr.hi)
+       bePutUint64(ret[8:], ip.addr.lo)
+       return ret
+}
+
+// As4 returns an IPv4 or IPv4-in-IPv6 address in its 4-byte representation.
+// If ip is the zero Addr or an IPv6 address, As4 panics.
+// Note that 0.0.0.0 is not the zero Addr.
+func (ip Addr) As4() [4]byte {
+       if ip.z == z4 || ip.Is4In6() {
+               var ret [4]byte
+               bePutUint32(ret[:], uint32(ip.addr.lo))
+               return ret
+       }
+       if ip.z == z0 {
+               panic("As4 called on IP zero value")
+       }
+       panic("As4 called on IPv6 address")
+}
+
+// Next returns the address following ip.
+// If there is none, it returns the zero Addr.
+func (ip Addr) Next() Addr {
+       ip.addr = ip.addr.addOne()
+       if ip.Is4() {
+               if uint32(ip.addr.lo) == 0 {
+                       // Overflowed.
+                       return Addr{}
+               }
+       } else {
+               if ip.addr.isZero() {
+                       // Overflowed
+                       return Addr{}
+               }
+       }
+       return ip
+}
+
+// Prev returns the IP before ip.
+// If there is none, it returns the IP zero value.
+func (ip Addr) Prev() Addr {
+       if ip.Is4() {
+               if uint32(ip.addr.lo) == 0 {
+                       return Addr{}
+               }
+       } else if ip.addr.isZero() {
+               return Addr{}
+       }
+       ip.addr = ip.addr.subOne()
+       return ip
+}
+
+// String returns the string form of the IP address ip.
+// It returns one of 5 forms:
+//
+//   - "invalid IP", if ip is the zero Addr
+//   - IPv4 dotted decimal ("192.0.2.1")
+//   - IPv6 ("2001:db8::1")
+//   - "::ffff:1.2.3.4" (if Is4In6)
+//   - IPv6 with zone ("fe80:db8::1%eth0")
+//
+// Note that unlike package net's IP.String method,
+// IP4-mapped IPv6 addresses format with a "::ffff:"
+// prefix before the dotted quad.
+func (ip Addr) String() string {
+       switch ip.z {
+       case z0:
+               return "invalid IP"
+       case z4:
+               return ip.string4()
+       default:
+               if ip.Is4In6() {
+                       // TODO(bradfitz): this could alloc less.
+                       return "::ffff:" + ip.Unmap().String()
+               }
+               return ip.string6()
+       }
+}
+
+// AppendTo appends a text encoding of ip,
+// as generated by MarshalText,
+// to b and returns the extended buffer.
+func (ip Addr) AppendTo(b []byte) []byte {
+       switch ip.z {
+       case z0:
+               return b
+       case z4:
+               return ip.appendTo4(b)
+       default:
+               if ip.Is4In6() {
+                       b = append(b, "::ffff:"...)
+                       return ip.Unmap().appendTo4(b)
+               }
+               return ip.appendTo6(b)
+       }
+}
+
+// digits is a string of the hex digits from 0 to f. It's used in
+// appendDecimal and appendHex to format IP addresses.
+const digits = "0123456789abcdef"
+
+// appendDecimal appends the decimal string representation of x to b.
+func appendDecimal(b []byte, x uint8) []byte {
+       // Using this function rather than strconv.AppendUint makes IPv4
+       // string building 2x faster.
+
+       if x >= 100 {
+               b = append(b, digits[x/100])
+       }
+       if x >= 10 {
+               b = append(b, digits[x/10%10])
+       }
+       return append(b, digits[x%10])
+}
+
+// appendHex appends the hex string representation of x to b.
+func appendHex(b []byte, x uint16) []byte {
+       // Using this function rather than strconv.AppendUint makes IPv6
+       // string building 2x faster.
+
+       if x >= 0x1000 {
+               b = append(b, digits[x>>12])
+       }
+       if x >= 0x100 {
+               b = append(b, digits[x>>8&0xf])
+       }
+       if x >= 0x10 {
+               b = append(b, digits[x>>4&0xf])
+       }
+       return append(b, digits[x&0xf])
+}
+
+// appendHexPad appends the fully padded hex string representation of x to b.
+func appendHexPad(b []byte, x uint16) []byte {
+       return append(b, digits[x>>12], digits[x>>8&0xf], digits[x>>4&0xf], digits[x&0xf])
+}
+
+func (ip Addr) string4() string {
+       const max = len("255.255.255.255")
+       ret := make([]byte, 0, max)
+       ret = ip.appendTo4(ret)
+       return string(ret)
+}
+
+func (ip Addr) appendTo4(ret []byte) []byte {
+       ret = appendDecimal(ret, ip.v4(0))
+       ret = append(ret, '.')
+       ret = appendDecimal(ret, ip.v4(1))
+       ret = append(ret, '.')
+       ret = appendDecimal(ret, ip.v4(2))
+       ret = append(ret, '.')
+       ret = appendDecimal(ret, ip.v4(3))
+       return ret
+}
+
+// string6 formats ip in IPv6 textual representation. It follows the
+// guidelines in section 4 of RFC 5952
+// (https://tools.ietf.org/html/rfc5952#section-4): no unnecessary
+// zeros, use :: to elide the longest run of zeros, and don't use ::
+// to compact a single zero field.
+func (ip Addr) string6() string {
+       // Use a zone with a "plausibly long" name, so that most zone-ful
+       // IP addresses won't require additional allocation.
+       //
+       // The compiler does a cool optimization here, where ret ends up
+       // stack-allocated and so the only allocation this function does
+       // is to construct the returned string. As such, it's okay to be a
+       // bit greedy here, size-wise.
+       const max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
+       ret := make([]byte, 0, max)
+       ret = ip.appendTo6(ret)
+       return string(ret)
+}
+
+func (ip Addr) appendTo6(ret []byte) []byte {
+       zeroStart, zeroEnd := uint8(255), uint8(255)
+       for i := uint8(0); i < 8; i++ {
+               j := i
+               for j < 8 && ip.v6u16(j) == 0 {
+                       j++
+               }
+               if l := j - i; l >= 2 && l > zeroEnd-zeroStart {
+                       zeroStart, zeroEnd = i, j
+               }
+       }
+
+       for i := uint8(0); i < 8; i++ {
+               if i == zeroStart {
+                       ret = append(ret, ':', ':')
+                       i = zeroEnd
+                       if i >= 8 {
+                               break
+                       }
+               } else if i > 0 {
+                       ret = append(ret, ':')
+               }
+
+               ret = appendHex(ret, ip.v6u16(i))
+       }
+
+       if ip.z != z6noz {
+               ret = append(ret, '%')
+               ret = append(ret, ip.Zone()...)
+       }
+       return ret
+}
+
+// StringExpanded is like String but IPv6 addresses are expanded with leading
+// zeroes and no "::" compression. For example, "2001:db8::1" becomes
+// "2001:0db8:0000:0000:0000:0000:0000:0001".
+func (ip Addr) StringExpanded() string {
+       switch ip.z {
+       case z0, z4:
+               return ip.String()
+       }
+
+       const size = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
+       ret := make([]byte, 0, size)
+       for i := uint8(0); i < 8; i++ {
+               if i > 0 {
+                       ret = append(ret, ':')
+               }
+
+               ret = appendHexPad(ret, ip.v6u16(i))
+       }
+
+       if ip.z != z6noz {
+               // The addition of a zone will cause a second allocation, but when there
+               // is no zone the ret slice will be stack allocated.
+               ret = append(ret, '%')
+               ret = append(ret, ip.Zone()...)
+       }
+       return string(ret)
+}
+
+// MarshalText implements the encoding.TextMarshaler interface,
+// The encoding is the same as returned by String, with one exception:
+// If ip is the zero Addr, the encoding is the empty string.
+func (ip Addr) MarshalText() ([]byte, error) {
+       switch ip.z {
+       case z0:
+               return []byte(""), nil
+       case z4:
+               max := len("255.255.255.255")
+               b := make([]byte, 0, max)
+               return ip.appendTo4(b), nil
+       default:
+               max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
+               b := make([]byte, 0, max)
+               if ip.Is4In6() {
+                       b = append(b, "::ffff:"...)
+                       return ip.Unmap().appendTo4(b), nil
+               }
+               return ip.appendTo6(b), nil
+       }
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// The IP address is expected in a form accepted by ParseAddr.
+//
+// If text is empty, UnmarshalText sets *ip to the zero Addr and
+// returns no error.
+func (ip *Addr) UnmarshalText(text []byte) error {
+       if len(text) == 0 {
+               *ip = Addr{}
+               return nil
+       }
+       var err error
+       *ip, err = ParseAddr(string(text))
+       return err
+}
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+// It returns a zero-length slice for the zero Addr,
+// the 4-byte form for an IPv4 address,
+// and the 16-byte form with zone appended for an IPv6 address.
+func (ip Addr) MarshalBinary() ([]byte, error) {
+       switch ip.z {
+       case z0:
+               return nil, nil
+       case z4:
+               b := ip.As4()
+               return b[:], nil
+       default:
+               b16 := ip.As16()
+               b := b16[:]
+               if z := ip.Zone(); z != "" {
+                       b = append(b, []byte(z)...)
+               }
+               return b, nil
+       }
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+// It expects data in the form generated by MarshalBinary.
+func (ip *Addr) UnmarshalBinary(b []byte) error {
+       n := len(b)
+       switch {
+       case n == 0:
+               *ip = Addr{}
+               return nil
+       case n == 4:
+               *ip = AddrFrom4(*(*[4]byte)(b))
+               return nil
+       case n == 16:
+               *ip = ipv6Slice(b)
+               return nil
+       case n > 16:
+               *ip = ipv6Slice(b[:16]).WithZone(string(b[16:]))
+               return nil
+       }
+       return errors.New("unexpected slice size")
+}
+
+// AddrPort is an IP and a port number.
+type AddrPort struct {
+       ip   Addr
+       port uint16
+}
+
+// AddrPortFrom returns an AddrPort with the provided IP and port.
+// It does not allocate.
+func AddrPortFrom(ip Addr, port uint16) AddrPort { return AddrPort{ip: ip, port: port} }
+
+// Addr returns p's IP address.
+func (p AddrPort) Addr() Addr { return p.ip }
+
+// Port returns p's port.
+func (p AddrPort) Port() uint16 { return p.port }
+
+// splitAddrPort splits s into an IP address string and a port
+// string. It splits strings shaped like "foo:bar" or "[foo]:bar",
+// without further validating the substrings. v6 indicates whether the
+// ip string should parse as an IPv6 address or an IPv4 address, in
+// order for s to be a valid ip:port string.
+func splitAddrPort(s string) (ip, port string, v6 bool, err error) {
+       i := stringsLastIndexByte(s, ':')
+       if i == -1 {
+               return "", "", false, errors.New("not an ip:port")
+       }
+
+       ip, port = s[:i], s[i+1:]
+       if len(ip) == 0 {
+               return "", "", false, errors.New("no IP")
+       }
+       if len(port) == 0 {
+               return "", "", false, errors.New("no port")
+       }
+       if ip[0] == '[' {
+               if len(ip) < 2 || ip[len(ip)-1] != ']' {
+                       return "", "", false, errors.New("missing ]")
+               }
+               ip = ip[1 : len(ip)-1]
+               v6 = true
+       }
+
+       return ip, port, v6, nil
+}
+
+// ParseAddrPort parses s as an AddrPort.
+//
+// It doesn't do any name resolution: both the address and the port
+// must be numeric.
+func ParseAddrPort(s string) (AddrPort, error) {
+       var ipp AddrPort
+       ip, port, v6, err := splitAddrPort(s)
+       if err != nil {
+               return ipp, err
+       }
+       port16, err := strconv.ParseUint(port, 10, 16)
+       if err != nil {
+               return ipp, errors.New("invalid port " + strconv.Quote(port) + " parsing " + strconv.Quote(s))
+       }
+       ipp.port = uint16(port16)
+       ipp.ip, err = ParseAddr(ip)
+       if err != nil {
+               return AddrPort{}, err
+       }
+       if v6 && ipp.ip.Is4() {
+               return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", square brackets can only be used with IPv6 addresses")
+       } else if !v6 && ipp.ip.Is6() {
+               return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", IPv6 addresses must be surrounded by square brackets")
+       }
+       return ipp, nil
+}
+
+// MustParseAddrPort calls ParseAddrPort(s) and panics on error.
+// It is intended for use in tests with hard-coded strings.
+func MustParseAddrPort(s string) AddrPort {
+       ip, err := ParseAddrPort(s)
+       if err != nil {
+               panic(err)
+       }
+       return ip
+}
+
+// isZero reports whether p is the zero AddrPort.
+func (p AddrPort) isZero() bool { return p == AddrPort{} }
+
+// IsValid reports whether p.IP() is valid.
+// All ports are valid, including zero.
+func (p AddrPort) IsValid() bool { return p.ip.IsValid() }
+
+func (p AddrPort) String() string {
+       switch p.ip.z {
+       case z0:
+               return "invalid AddrPort"
+       case z4:
+               a := p.ip.As4()
+               buf := make([]byte, 0, 21)
+               for i := range a {
+                       buf = strconv.AppendUint(buf, uint64(a[i]), 10)
+                       buf = append(buf, "...:"[i])
+               }
+               buf = strconv.AppendUint(buf, uint64(p.port), 10)
+               return string(buf)
+       default:
+               // TODO: this could be more efficient allocation-wise:
+               return joinHostPort(p.ip.String(), itoa.Itoa(int(p.port)))
+       }
+}
+
+func joinHostPort(host, port string) string {
+       // We assume that host is a literal IPv6 address if host has
+       // colons.
+       if bytealg.IndexByteString(host, ':') >= 0 {
+               return "[" + host + "]:" + port
+       }
+       return host + ":" + port
+}
+
+// AppendTo appends a text encoding of p,
+// as generated by MarshalText,
+// to b and returns the extended buffer.
+func (p AddrPort) AppendTo(b []byte) []byte {
+       switch p.ip.z {
+       case z0:
+               return b
+       case z4:
+               b = p.ip.appendTo4(b)
+       default:
+               b = append(b, '[')
+               b = p.ip.appendTo6(b)
+               b = append(b, ']')
+       }
+       b = append(b, ':')
+       b = strconv.AppendInt(b, int64(p.port), 10)
+       return b
+}
+
+// MarshalText implements the encoding.TextMarshaler interface. The
+// encoding is the same as returned by String, with one exception: if
+// p.Addr() is the zero Addr, the encoding is the empty string.
+func (p AddrPort) MarshalText() ([]byte, error) {
+       var max int
+       switch p.ip.z {
+       case z0:
+       case z4:
+               max = len("255.255.255.255:65535")
+       default:
+               max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
+       }
+       b := make([]byte, 0, max)
+       b = p.AppendTo(b)
+       return b, nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler
+// interface. The AddrPort is expected in a form
+// generated by MarshalText or accepted by ParseAddrPort.
+func (p *AddrPort) UnmarshalText(text []byte) error {
+       if len(text) == 0 {
+               *p = AddrPort{}
+               return nil
+       }
+       var err error
+       *p, err = ParseAddrPort(string(text))
+       return err
+}
+
+// Prefix is an IP address prefix (CIDR) representing an IP network.
+//
+// The first Bits() of Addr() are specified. The remaining bits match any address.
+// The range of Bits() is [0,32] for IPv4 or [0,128] for IPv6.
+type Prefix struct {
+       ip Addr
+
+       // bits is logically a uint8 (storing [0,128]) but also
+       // encodes an "invalid" bit, currently represented by the
+       // invalidPrefixBits sentinel value. It could be packed into
+       // the uint8 more with more complicated expressions in the
+       // accessors, but the extra byte (in padding anyway) doesn't
+       // hurt and simplifies code below.
+       bits int16
+}
+
+// invalidPrefixBits is the Prefix.bits value used when PrefixFrom is
+// outside the range of a uint8. It's returned as the int -1 in the
+// public API.
+const invalidPrefixBits = -1
+
+// PrefixFrom returns a Prefix with the provided IP address and bit
+// prefix length.
+//
+// It does not allocate. Unlike Addr.Prefix, PrefixFrom does not mask
+// off the host bits of ip.
+//
+// If bits is less than zero or greater than ip.BitLen, Prefix.Bits
+// will return an invalid value -1.
+func PrefixFrom(ip Addr, bits int) Prefix {
+       if bits < 0 || bits > ip.BitLen() {
+               bits = invalidPrefixBits
+       }
+       b16 := int16(bits)
+       return Prefix{
+               ip:   ip.withoutZone(),
+               bits: b16,
+       }
+}
+
+// Addr returns p's IP address.
+func (p Prefix) Addr() Addr { return p.ip }
+
+// Bits returns p's prefix length.
+//
+// It reports -1 if invalid.
+func (p Prefix) Bits() int { return int(p.bits) }
+
+// IsValid reports whether p.Bits() has a valid range for p.IP().
+// If p.Addr() is the zero Addr, IsValid returns false.
+// Note that if p is the zero Prefix, then p.IsValid() == false.
+func (p Prefix) IsValid() bool { return !p.ip.isZero() && p.bits >= 0 && int(p.bits) <= p.ip.BitLen() }
+
+func (p Prefix) isZero() bool { return p == Prefix{} }
+
+// IsSingleIP reports whether p contains exactly one IP.
+func (p Prefix) IsSingleIP() bool { return p.bits != 0 && int(p.bits) == p.ip.BitLen() }
+
+// ParsePrefix parses s as an IP address prefix.
+// The string can be in the form "192.168.1.0/24" or "2001::db8::/32",
+// the CIDR notation defined in RFC 4632 and RFC 4291.
+//
+// Note that masked address bits are not zeroed. Use Masked for that.
+func ParsePrefix(s string) (Prefix, error) {
+       i := stringsLastIndexByte(s, '/')
+       if i < 0 {
+               return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): no '/'")
+       }
+       ip, err := ParseAddr(s[:i])
+       if err != nil {
+               return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): " + err.Error())
+       }
+       bitsStr := s[i+1:]
+       bits, err := strconv.Atoi(bitsStr)
+       if err != nil {
+               return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + ": bad bits after slash: " + strconv.Quote(bitsStr))
+       }
+       maxBits := 32
+       if ip.Is6() {
+               maxBits = 128
+       }
+       if bits < 0 || bits > maxBits {
+               return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + ": prefix length out of range")
+       }
+       return PrefixFrom(ip, bits), nil
+}
+
+// MustParsePrefix calls ParsePrefix(s) and panics on error.
+// It is intended for use in tests with hard-coded strings.
+func MustParsePrefix(s string) Prefix {
+       ip, err := ParsePrefix(s)
+       if err != nil {
+               panic(err)
+       }
+       return ip
+}
+
+// Masked returns p in its canonical form, with all but the high
+// p.Bits() bits of p.Addr() masked off.
+//
+// If p is zero or otherwise invalid, Masked returns the zero Prefix.
+func (p Prefix) Masked() Prefix {
+       if m, err := p.ip.Prefix(int(p.bits)); err == nil {
+               return m
+       }
+       return Prefix{}
+}
+
+// Contains reports whether the network p includes ip.
+//
+// An IPv4 address will not match an IPv6 prefix.
+// A v6-mapped IPv6 address will not match an IPv4 prefix.
+// A zero-value IP will not match any prefix.
+// If ip has an IPv6 zone, Contains returns false,
+// because Prefixes strip zones.
+func (p Prefix) Contains(ip Addr) bool {
+       if !p.IsValid() || ip.hasZone() {
+               return false
+       }
+       if f1, f2 := p.ip.BitLen(), ip.BitLen(); f1 == 0 || f2 == 0 || f1 != f2 {
+               return false
+       }
+       if ip.Is4() {
+               // xor the IP addresses together; mismatched bits are now ones.
+               // Shift away the number of bits we don't care about.
+               // Shifts in Go are more efficient if the compiler can prove
+               // that the shift amount is smaller than the width of the shifted type (64 here).
+               // We know that p.bits is in the range 0..32 because p is Valid;
+               // the compiler doesn't know that, so mask with 63 to help it.
+               // Now truncate to 32 bits, because this is IPv4.
+               // If all the bits we care about are equal, the result will be zero.
+               return uint32((ip.addr.lo^p.ip.addr.lo)>>((32-p.bits)&63)) == 0
+       } else {
+               // xor the IP addresses together.
+               // Mask away the bits we don't care about.
+               // If all the bits we care about are equal, the result will be zero.
+               return ip.addr.xor(p.ip.addr).and(mask6(int(p.bits))).isZero()
+       }
+}
+
+// Overlaps reports whether p and o contain any IP addresses in common.
+//
+// If p and o are of different address families or either have a zero
+// IP, it reports false. Like the Contains method, a prefix with a
+// v6-mapped IPv4 IP is still treated as an IPv6 mask.
+func (p Prefix) Overlaps(o Prefix) bool {
+       if !p.IsValid() || !o.IsValid() {
+               return false
+       }
+       if p == o {
+               return true
+       }
+       if p.ip.Is4() != o.ip.Is4() {
+               return false
+       }
+       var minBits int16
+       if p.bits < o.bits {
+               minBits = p.bits
+       } else {
+               minBits = o.bits
+       }
+       if minBits == 0 {
+               return true
+       }
+       // One of these Prefix calls might look redundant, but we don't require
+       // that p and o values are normalized (via Prefix.Masked) first,
+       // so the Prefix call on the one that's already minBits serves to zero
+       // out any remaining bits in IP.
+       var err error
+       if p, err = p.ip.Prefix(int(minBits)); err != nil {
+               return false
+       }
+       if o, err = o.ip.Prefix(int(minBits)); err != nil {
+               return false
+       }
+       return p.ip == o.ip
+}
+
+// AppendTo appends a text encoding of p,
+// as generated by MarshalText,
+// to b and returns the extended buffer.
+func (p Prefix) AppendTo(b []byte) []byte {
+       if p.isZero() {
+               return b
+       }
+       if !p.IsValid() {
+               return append(b, "invalid Prefix"...)
+       }
+
+       // p.ip is non-nil, because p is valid.
+       if p.ip.z == z4 {
+               b = p.ip.appendTo4(b)
+       } else {
+               b = p.ip.appendTo6(b)
+       }
+
+       b = append(b, '/')
+       b = appendDecimal(b, uint8(p.bits))
+       return b
+}
+
+// MarshalText implements the encoding.TextMarshaler interface,
+// The encoding is the same as returned by String, with one exception:
+// If p is the zero value, the encoding is the empty string.
+func (p Prefix) MarshalText() ([]byte, error) {
+       var max int
+       switch p.ip.z {
+       case z0:
+       case z4:
+               max = len("255.255.255.255/32")
+       default:
+               max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0/128")
+       }
+       b := make([]byte, 0, max)
+       b = p.AppendTo(b)
+       return b, nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// The IP address is expected in a form accepted by ParsePrefix
+// or generated by MarshalText.
+func (p *Prefix) UnmarshalText(text []byte) error {
+       if len(text) == 0 {
+               *p = Prefix{}
+               return nil
+       }
+       var err error
+       *p, err = ParsePrefix(string(text))
+       return err
+}
+
+// String returns the CIDR notation of p: "<ip>/<bits>".
+func (p Prefix) String() string {
+       if !p.IsValid() {
+               return "invalid Prefix"
+       }
+       return p.ip.String() + "/" + itoa.Itoa(int(p.bits))
+}
diff --git a/src/net/netip/netip_pkg_test.go b/src/net/netip/netip_pkg_test.go
new file mode 100644 (file)
index 0000000..f5cd9ee
--- /dev/null
@@ -0,0 +1,359 @@
+// 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 netip
+
+import (
+       "bytes"
+       "encoding"
+       "encoding/json"
+       "strings"
+       "testing"
+)
+
+var (
+       mustPrefix = MustParsePrefix
+       mustIP     = MustParseAddr
+)
+
+func TestPrefixValid(t *testing.T) {
+       v4 := MustParseAddr("1.2.3.4")
+       v6 := MustParseAddr("::1")
+       tests := []struct {
+               ipp  Prefix
+               want bool
+       }{
+               {Prefix{v4, -2}, false},
+               {Prefix{v4, -1}, false},
+               {Prefix{v4, 0}, true},
+               {Prefix{v4, 32}, true},
+               {Prefix{v4, 33}, false},
+
+               {Prefix{v6, -2}, false},
+               {Prefix{v6, -1}, false},
+               {Prefix{v6, 0}, true},
+               {Prefix{v6, 32}, true},
+               {Prefix{v6, 128}, true},
+               {Prefix{v6, 129}, false},
+
+               {Prefix{Addr{}, -2}, false},
+               {Prefix{Addr{}, -1}, false},
+               {Prefix{Addr{}, 0}, false},
+               {Prefix{Addr{}, 32}, false},
+               {Prefix{Addr{}, 128}, false},
+       }
+       for _, tt := range tests {
+               got := tt.ipp.IsValid()
+               if got != tt.want {
+                       t.Errorf("(%v).IsValid() = %v want %v", tt.ipp, got, tt.want)
+               }
+       }
+}
+
+var nextPrevTests = []struct {
+       ip   Addr
+       next Addr
+       prev Addr
+}{
+       {mustIP("10.0.0.1"), mustIP("10.0.0.2"), mustIP("10.0.0.0")},
+       {mustIP("10.0.0.255"), mustIP("10.0.1.0"), mustIP("10.0.0.254")},
+       {mustIP("127.0.0.1"), mustIP("127.0.0.2"), mustIP("127.0.0.0")},
+       {mustIP("254.255.255.255"), mustIP("255.0.0.0"), mustIP("254.255.255.254")},
+       {mustIP("255.255.255.255"), Addr{}, mustIP("255.255.255.254")},
+       {mustIP("0.0.0.0"), mustIP("0.0.0.1"), Addr{}},
+       {mustIP("::"), mustIP("::1"), Addr{}},
+       {mustIP("::%x"), mustIP("::1%x"), Addr{}},
+       {mustIP("::1"), mustIP("::2"), mustIP("::")},
+       {mustIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), Addr{}, mustIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")},
+}
+
+func TestIPNextPrev(t *testing.T) {
+       doNextPrev(t)
+
+       for _, ip := range []Addr{
+               mustIP("0.0.0.0"),
+               mustIP("::"),
+       } {
+               got := ip.Prev()
+               if !got.isZero() {
+                       t.Errorf("IP(%v).Prev = %v; want zero", ip, got)
+               }
+       }
+
+       var allFF [16]byte
+       for i := range allFF {
+               allFF[i] = 0xff
+       }
+
+       for _, ip := range []Addr{
+               mustIP("255.255.255.255"),
+               AddrFrom16(allFF),
+       } {
+               got := ip.Next()
+               if !got.isZero() {
+                       t.Errorf("IP(%v).Next = %v; want zero", ip, got)
+               }
+       }
+}
+
+func BenchmarkIPNextPrev(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               doNextPrev(b)
+       }
+}
+
+func doNextPrev(t testing.TB) {
+       for _, tt := range nextPrevTests {
+               gnext, gprev := tt.ip.Next(), tt.ip.Prev()
+               if gnext != tt.next {
+                       t.Errorf("IP(%v).Next = %v; want %v", tt.ip, gnext, tt.next)
+               }
+               if gprev != tt.prev {
+                       t.Errorf("IP(%v).Prev = %v; want %v", tt.ip, gprev, tt.prev)
+               }
+               if !tt.ip.Next().isZero() && tt.ip.Next().Prev() != tt.ip {
+                       t.Errorf("IP(%v).Next.Prev = %v; want %v", tt.ip, tt.ip.Next().Prev(), tt.ip)
+               }
+               if !tt.ip.Prev().isZero() && tt.ip.Prev().Next() != tt.ip {
+                       t.Errorf("IP(%v).Prev.Next = %v; want %v", tt.ip, tt.ip.Prev().Next(), tt.ip)
+               }
+       }
+}
+
+func TestIPBitLen(t *testing.T) {
+       tests := []struct {
+               ip   Addr
+               want int
+       }{
+               {Addr{}, 0},
+               {mustIP("0.0.0.0"), 32},
+               {mustIP("10.0.0.1"), 32},
+               {mustIP("::"), 128},
+               {mustIP("fed0::1"), 128},
+               {mustIP("::ffff:10.0.0.1"), 128},
+       }
+       for _, tt := range tests {
+               got := tt.ip.BitLen()
+               if got != tt.want {
+                       t.Errorf("BitLen(%v) = %d; want %d", tt.ip, got, tt.want)
+               }
+       }
+}
+
+func TestPrefixContains(t *testing.T) {
+       tests := []struct {
+               ipp  Prefix
+               ip   Addr
+               want bool
+       }{
+               {mustPrefix("9.8.7.6/0"), mustIP("9.8.7.6"), true},
+               {mustPrefix("9.8.7.6/16"), mustIP("9.8.7.6"), true},
+               {mustPrefix("9.8.7.6/16"), mustIP("9.8.6.4"), true},
+               {mustPrefix("9.8.7.6/16"), mustIP("9.9.7.6"), false},
+               {mustPrefix("9.8.7.6/32"), mustIP("9.8.7.6"), true},
+               {mustPrefix("9.8.7.6/32"), mustIP("9.8.7.7"), false},
+               {mustPrefix("9.8.7.6/32"), mustIP("9.8.7.7"), false},
+               {mustPrefix("::1/0"), mustIP("::1"), true},
+               {mustPrefix("::1/0"), mustIP("::2"), true},
+               {mustPrefix("::1/127"), mustIP("::1"), true},
+               {mustPrefix("::1/127"), mustIP("::2"), false},
+               {mustPrefix("::1/128"), mustIP("::1"), true},
+               {mustPrefix("::1/127"), mustIP("::2"), false},
+               // zones support
+               {mustPrefix("::1%a/128"), mustIP("::1"), true},    // prefix zones are stripped...
+               {mustPrefix("::1%a/128"), mustIP("::1%a"), false}, // but ip zones are not
+               // invalid IP
+               {mustPrefix("::1/0"), Addr{}, false},
+               {mustPrefix("1.2.3.4/0"), Addr{}, false},
+               // invalid Prefix
+               {Prefix{mustIP("::1"), 129}, mustIP("::1"), false},
+               {Prefix{mustIP("1.2.3.4"), 33}, mustIP("1.2.3.4"), false},
+               {Prefix{Addr{}, 0}, mustIP("1.2.3.4"), false},
+               {Prefix{Addr{}, 32}, mustIP("1.2.3.4"), false},
+               {Prefix{Addr{}, 128}, mustIP("::1"), false},
+               // wrong IP family
+               {mustPrefix("::1/0"), mustIP("1.2.3.4"), false},
+               {mustPrefix("1.2.3.4/0"), mustIP("::1"), false},
+       }
+       for _, tt := range tests {
+               got := tt.ipp.Contains(tt.ip)
+               if got != tt.want {
+                       t.Errorf("(%v).Contains(%v) = %v want %v", tt.ipp, tt.ip, got, tt.want)
+               }
+       }
+}
+
+func TestParseIPError(t *testing.T) {
+       tests := []struct {
+               ip     string
+               errstr string
+       }{
+               {
+                       ip: "localhost",
+               },
+               {
+                       ip:     "500.0.0.1",
+                       errstr: "field has value >255",
+               },
+               {
+                       ip:     "::gggg%eth0",
+                       errstr: "must have at least one digit",
+               },
+               {
+                       ip:     "fe80::1cc0:3e8c:119f:c2e1%",
+                       errstr: "zone must be a non-empty string",
+               },
+               {
+                       ip:     "%eth0",
+                       errstr: "missing IPv6 address",
+               },
+       }
+       for _, test := range tests {
+               t.Run(test.ip, func(t *testing.T) {
+                       _, err := ParseAddr(test.ip)
+                       if err == nil {
+                               t.Fatal("no error")
+                       }
+                       if _, ok := err.(parseAddrError); !ok {
+                               t.Errorf("error type is %T, want parseIPError", err)
+                       }
+                       if test.errstr == "" {
+                               test.errstr = "unable to parse IP"
+                       }
+                       if got := err.Error(); !strings.Contains(got, test.errstr) {
+                               t.Errorf("error is missing substring %q: %s", test.errstr, got)
+                       }
+               })
+       }
+}
+
+func TestParseAddrPort(t *testing.T) {
+       tests := []struct {
+               in      string
+               want    AddrPort
+               wantErr bool
+       }{
+               {in: "1.2.3.4:1234", want: AddrPort{mustIP("1.2.3.4"), 1234}},
+               {in: "1.1.1.1:123456", wantErr: true},
+               {in: "1.1.1.1:-123", wantErr: true},
+               {in: "[::1]:1234", want: AddrPort{mustIP("::1"), 1234}},
+               {in: "[1.2.3.4]:1234", wantErr: true},
+               {in: "fe80::1:1234", wantErr: true},
+               {in: ":0", wantErr: true}, // if we need to parse this form, there should be a separate function that explicitly allows it
+       }
+       for _, test := range tests {
+               t.Run(test.in, func(t *testing.T) {
+                       got, err := ParseAddrPort(test.in)
+                       if err != nil {
+                               if test.wantErr {
+                                       return
+                               }
+                               t.Fatal(err)
+                       }
+                       if got != test.want {
+                               t.Errorf("got %v; want %v", got, test.want)
+                       }
+                       if got.String() != test.in {
+                               t.Errorf("String = %q; want %q", got.String(), test.in)
+                       }
+               })
+
+               t.Run(test.in+"/AppendTo", func(t *testing.T) {
+                       got, err := ParseAddrPort(test.in)
+                       if err == nil {
+                               testAppendToMarshal(t, got)
+                       }
+               })
+
+               // TextMarshal and TextUnmarshal mostly behave like
+               // ParseAddrPort and String. Divergent behavior are handled in
+               // TestAddrPortMarshalUnmarshal.
+               t.Run(test.in+"/Marshal", func(t *testing.T) {
+                       var got AddrPort
+                       jsin := `"` + test.in + `"`
+                       err := json.Unmarshal([]byte(jsin), &got)
+                       if err != nil {
+                               if test.wantErr {
+                                       return
+                               }
+                               t.Fatal(err)
+                       }
+                       if got != test.want {
+                               t.Errorf("got %v; want %v", got, test.want)
+                       }
+                       gotb, err := json.Marshal(got)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if string(gotb) != jsin {
+                               t.Errorf("Marshal = %q; want %q", string(gotb), jsin)
+                       }
+               })
+       }
+}
+
+func TestAddrPortMarshalUnmarshal(t *testing.T) {
+       tests := []struct {
+               in   string
+               want AddrPort
+       }{
+               {"", AddrPort{}},
+       }
+
+       for _, test := range tests {
+               t.Run(test.in, func(t *testing.T) {
+                       orig := `"` + test.in + `"`
+
+                       var ipp AddrPort
+                       if err := json.Unmarshal([]byte(orig), &ipp); err != nil {
+                               t.Fatalf("failed to unmarshal: %v", err)
+                       }
+
+                       ippb, err := json.Marshal(ipp)
+                       if err != nil {
+                               t.Fatalf("failed to marshal: %v", err)
+                       }
+
+                       back := string(ippb)
+                       if orig != back {
+                               t.Errorf("Marshal = %q; want %q", back, orig)
+                       }
+
+                       testAppendToMarshal(t, ipp)
+               })
+       }
+}
+
+type appendMarshaler interface {
+       encoding.TextMarshaler
+       AppendTo([]byte) []byte
+}
+
+// testAppendToMarshal tests that x's AppendTo and MarshalText methods yield the same results.
+// x's MarshalText method must not return an error.
+func testAppendToMarshal(t *testing.T, x appendMarshaler) {
+       t.Helper()
+       m, err := x.MarshalText()
+       if err != nil {
+               t.Fatalf("(%v).MarshalText: %v", x, err)
+       }
+       a := make([]byte, 0, len(m))
+       a = x.AppendTo(a)
+       if !bytes.Equal(m, a) {
+               t.Errorf("(%v).MarshalText = %q, (%v).AppendTo = %q", x, m, x, a)
+       }
+}
+
+func TestIPv6Accessor(t *testing.T) {
+       var a [16]byte
+       for i := range a {
+               a[i] = uint8(i) + 1
+       }
+       ip := AddrFrom16(a)
+       for i := range a {
+               if got, want := ip.v6(uint8(i)), uint8(i)+1; got != want {
+                       t.Errorf("v6(%v) = %v; want %v", i, got, want)
+               }
+       }
+}
diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go
new file mode 100644 (file)
index 0000000..5d935c8
--- /dev/null
@@ -0,0 +1,1798 @@
+// 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 netip_test
+
+import (
+       "bytes"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "internal/intern"
+       "net"
+       . "net/netip"
+       "reflect"
+       "sort"
+       "strings"
+       "testing"
+)
+
+var long = flag.Bool("long", false, "run long tests")
+
+type uint128 = Uint128
+
+var (
+       mustPrefix = MustParsePrefix
+       mustIP     = MustParseAddr
+)
+
+func TestParseAddr(t *testing.T) {
+       var validIPs = []struct {
+               in  string
+               ip  Addr   // output of ParseAddr()
+               str string // output of String(). If "", use in.
+       }{
+               // Basic zero IPv4 address.
+               {
+                       in: "0.0.0.0",
+                       ip: MkAddr(Mk128(0, 0xffff00000000), Z4),
+               },
+               // Basic non-zero IPv4 address.
+               {
+                       in: "192.168.140.255",
+                       ip: MkAddr(Mk128(0, 0xffffc0a88cff), Z4),
+               },
+               // IPv4 address in windows-style "print all the digits" form.
+               {
+                       in:  "010.000.015.001",
+                       ip:  MkAddr(Mk128(0, 0xffff0a000f01), Z4),
+                       str: "10.0.15.1",
+               },
+               // IPv4 address with a silly amount of leading zeros.
+               {
+                       in:  "000001.00000002.00000003.000000004",
+                       ip:  MkAddr(Mk128(0, 0xffff01020304), Z4),
+                       str: "1.2.3.4",
+               },
+               // Basic zero IPv6 address.
+               {
+                       in: "::",
+                       ip: MkAddr(Mk128(0, 0), Z6noz),
+               },
+               // Localhost IPv6.
+               {
+                       in: "::1",
+                       ip: MkAddr(Mk128(0, 1), Z6noz),
+               },
+               // Fully expanded IPv6 address.
+               {
+                       in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b",
+                       ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), Z6noz),
+               },
+               // IPv6 with elided fields in the middle.
+               {
+                       in: "fd7a:115c::626b:430b",
+                       ip: MkAddr(Mk128(0xfd7a115c00000000, 0x00000000626b430b), Z6noz),
+               },
+               // IPv6 with elided fields at the end.
+               {
+                       in: "fd7a:115c:a1e0:ab12:4843:cd96::",
+                       ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd9600000000), Z6noz),
+               },
+               // IPv6 with single elided field at the end.
+               {
+                       in:  "fd7a:115c:a1e0:ab12:4843:cd96:626b::",
+                       ip:  MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b0000), Z6noz),
+                       str: "fd7a:115c:a1e0:ab12:4843:cd96:626b:0",
+               },
+               // IPv6 with single elided field in the middle.
+               {
+                       in:  "fd7a:115c:a1e0::4843:cd96:626b:430b",
+                       ip:  MkAddr(Mk128(0xfd7a115ca1e00000, 0x4843cd96626b430b), Z6noz),
+                       str: "fd7a:115c:a1e0:0:4843:cd96:626b:430b",
+               },
+               // IPv6 with the trailing 32 bits written as IPv4 dotted decimal. (4in6)
+               {
+                       in:  "::ffff:192.168.140.255",
+                       ip:  MkAddr(Mk128(0, 0x0000ffffc0a88cff), Z6noz),
+                       str: "::ffff:192.168.140.255",
+               },
+               // IPv6 with a zone specifier.
+               {
+                       in: "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b%eth0",
+                       ip: MkAddr(Mk128(0xfd7a115ca1e0ab12, 0x4843cd96626b430b), intern.Get("eth0")),
+               },
+               // IPv6 with dotted decimal and zone specifier.
+               {
+                       in:  "1:2::ffff:192.168.140.255%eth1",
+                       ip:  MkAddr(Mk128(0x0001000200000000, 0x0000ffffc0a88cff), intern.Get("eth1")),
+                       str: "1:2::ffff:c0a8:8cff%eth1",
+               },
+               // IPv6 with capital letters.
+               {
+                       in:  "FD9E:1A04:F01D::1",
+                       ip:  MkAddr(Mk128(0xfd9e1a04f01d0000, 0x1), Z6noz),
+                       str: "fd9e:1a04:f01d::1",
+               },
+       }
+
+       for _, test := range validIPs {
+               t.Run(test.in, func(t *testing.T) {
+                       got, err := ParseAddr(test.in)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if got != test.ip {
+                               t.Errorf("ParseAddr(%q) got %#v, want %#v", test.in, got, test.ip)
+                       }
+
+                       // Check that ParseAddr is a pure function.
+                       got2, err := ParseAddr(test.in)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if got != got2 {
+                               t.Errorf("ParseAddr(%q) got 2 different results: %#v, %#v", test.in, got, got2)
+                       }
+
+                       // Check that ParseAddr(ip.String()) is the identity function.
+                       s := got.String()
+                       got3, err := ParseAddr(s)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if got != got3 {
+                               t.Errorf("ParseAddr(%q) != ParseAddr(ParseIP(%q).String()). Got %#v, want %#v", test.in, test.in, got3, got)
+                       }
+
+                       // Check that the slow-but-readable parser produces the same result.
+                       slow, err := parseIPSlow(test.in)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if got != slow {
+                               t.Errorf("ParseAddr(%q) = %#v, parseIPSlow(%q) = %#v", test.in, got, test.in, slow)
+                       }
+
+                       // Check that the parsed IP formats as expected.
+                       s = got.String()
+                       wants := test.str
+                       if wants == "" {
+                               wants = test.in
+                       }
+                       if s != wants {
+                               t.Errorf("ParseAddr(%q).String() got %q, want %q", test.in, s, wants)
+                       }
+
+                       // Check that AppendTo matches MarshalText.
+                       TestAppendToMarshal(t, got)
+
+                       // Check that MarshalText/UnmarshalText work similarly to
+                       // ParseAddr/String (see TestIPMarshalUnmarshal for
+                       // marshal-specific behavior that's not common with
+                       // ParseAddr/String).
+                       js := `"` + test.in + `"`
+                       var jsgot Addr
+                       if err := json.Unmarshal([]byte(js), &jsgot); err != nil {
+                               t.Fatal(err)
+                       }
+                       if jsgot != got {
+                               t.Errorf("json.Unmarshal(%q) = %#v, want %#v", test.in, jsgot, got)
+                       }
+                       jsb, err := json.Marshal(jsgot)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       jswant := `"` + wants + `"`
+                       jsback := string(jsb)
+                       if jsback != jswant {
+                               t.Errorf("Marshal(Unmarshal(%q)) = %s, want %s", test.in, jsback, jswant)
+                       }
+               })
+       }
+
+       var invalidIPs = []string{
+               // Empty string
+               "",
+               // Garbage non-IP
+               "bad",
+               // Single number. Some parsers accept this as an IPv4 address in
+               // big-endian uint32 form, but we don't.
+               "1234",
+               // IPv4 with a zone specifier
+               "1.2.3.4%eth0",
+               // IPv4 field must have at least one digit
+               ".1.2.3",
+               "1.2.3.",
+               "1..2.3",
+               // IPv4 address too long
+               "1.2.3.4.5",
+               // IPv4 in dotted octal form
+               "0300.0250.0214.0377",
+               // IPv4 in dotted hex form
+               "0xc0.0xa8.0x8c.0xff",
+               // IPv4 in class B form
+               "192.168.12345",
+               // IPv4 in class B form, with a small enough number to be
+               // parseable as a regular dotted decimal field.
+               "127.0.1",
+               // IPv4 in class A form
+               "192.1234567",
+               // IPv4 in class A form, with a small enough number to be
+               // parseable as a regular dotted decimal field.
+               "127.1",
+               // IPv4 field has value >255
+               "192.168.300.1",
+               // IPv4 with too many fields
+               "192.168.0.1.5.6",
+               // IPv6 with not enough fields
+               "1:2:3:4:5:6:7",
+               // IPv6 with too many fields
+               "1:2:3:4:5:6:7:8:9",
+               // IPv6 with 8 fields and a :: expander
+               "1:2:3:4::5:6:7:8",
+               // IPv6 with a field bigger than 2b
+               "fe801::1",
+               // IPv6 with non-hex values in field
+               "fe80:tail:scal:e::",
+               // IPv6 with a zone delimiter but no zone.
+               "fe80::1%",
+               // IPv6 (without ellipsis) with too many fields for trailing embedded IPv4.
+               "ffff:ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
+               // IPv6 (with ellipsis) with too many fields for trailing embedded IPv4.
+               "ffff::ffff:ffff:ffff:ffff:ffff:ffff:192.168.140.255",
+               // IPv6 with invalid embedded IPv4.
+               "::ffff:192.168.140.bad",
+               // IPv6 with multiple ellipsis ::.
+               "fe80::1::1",
+               // IPv6 with invalid non hex/colon character.
+               "fe80:1?:1",
+               // IPv6 with truncated bytes after single colon.
+               "fe80:",
+       }
+
+       for _, s := range invalidIPs {
+               t.Run(s, func(t *testing.T) {
+                       got, err := ParseAddr(s)
+                       if err == nil {
+                               t.Errorf("ParseAddr(%q) = %#v, want error", s, got)
+                       }
+
+                       slow, err := parseIPSlow(s)
+                       if err == nil {
+                               t.Errorf("parseIPSlow(%q) = %#v, want error", s, slow)
+                       }
+
+                       std := net.ParseIP(s)
+                       if std != nil {
+                               t.Errorf("net.ParseIP(%q) = %#v, want error", s, std)
+                       }
+
+                       if s == "" {
+                               // Don't test unmarshaling of "" here, do it in
+                               // IPMarshalUnmarshal.
+                               return
+                       }
+                       var jsgot Addr
+                       js := []byte(`"` + s + `"`)
+                       if err := json.Unmarshal(js, &jsgot); err == nil {
+                               t.Errorf("json.Unmarshal(%q) = %#v, want error", s, jsgot)
+                       }
+               })
+       }
+}
+
+func TestIPv4Constructors(t *testing.T) {
+       if AddrFrom4([4]byte{1, 2, 3, 4}) != MustParseAddr("1.2.3.4") {
+               t.Errorf("don't match")
+       }
+}
+
+func TestAddrMarshalUnmarshalBinary(t *testing.T) {
+       tests := []struct {
+               ip       string
+               wantSize int
+       }{
+               {"", 0}, // zero IP
+               {"1.2.3.4", 4},
+               {"fd7a:115c:a1e0:ab12:4843:cd96:626b:430b", 16},
+               {"::ffff:c000:0280", 16},
+               {"::ffff:c000:0280%eth0", 20},
+       }
+       for _, tc := range tests {
+               var ip Addr
+               if len(tc.ip) > 0 {
+                       ip = mustIP(tc.ip)
+               }
+               b, err := ip.MarshalBinary()
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if len(b) != tc.wantSize {
+                       t.Fatalf("%q encoded to size %d; want %d", tc.ip, len(b), tc.wantSize)
+               }
+               var ip2 Addr
+               if err := ip2.UnmarshalBinary(b); err != nil {
+                       t.Fatal(err)
+               }
+               if ip != ip2 {
+                       t.Fatalf("got %v; want %v", ip2, ip)
+               }
+       }
+
+       // Cannot unmarshal from unexpected IP length.
+       for _, l := range []int{3, 5} {
+               var ip2 Addr
+               if err := ip2.UnmarshalBinary(bytes.Repeat([]byte{1}, l)); err == nil {
+                       t.Fatalf("unmarshaled from unexpected IP length %d", l)
+               }
+       }
+}
+
+func TestAddrMarshalUnmarshal(t *testing.T) {
+       // This only tests the cases where Marshal/Unmarshal diverges from
+       // the behavior of ParseAddr/String. For the rest of the test cases,
+       // see TestParseAddr above.
+       orig := `""`
+       var ip Addr
+       if err := json.Unmarshal([]byte(orig), &ip); err != nil {
+               t.Fatalf("Unmarshal(%q) got error %v", orig, err)
+       }
+       if ip != (Addr{}) {
+               t.Errorf("Unmarshal(%q) is not the zero Addr", orig)
+       }
+
+       jsb, err := json.Marshal(ip)
+       if err != nil {
+               t.Fatalf("Marshal(%v) got error %v", ip, err)
+       }
+       back := string(jsb)
+       if back != orig {
+               t.Errorf("Marshal(Unmarshal(%q)) got %q, want %q", orig, back, orig)
+       }
+}
+
+func TestAddrFrom16(t *testing.T) {
+       tests := []struct {
+               name string
+               in   [16]byte
+               want Addr
+       }{
+               {
+                       name: "v6-raw",
+                       in:   [...]byte{15: 1},
+                       want: MkAddr(Mk128(0, 1), Z6noz),
+               },
+               {
+                       name: "v4-raw",
+                       in:   [...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4},
+                       want: MkAddr(Mk128(0, 0xffff01020304), Z6noz),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       got := AddrFrom16(tt.in)
+                       if got != tt.want {
+                               t.Errorf("got %#v; want %#v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func TestIPProperties(t *testing.T) {
+       var (
+               nilIP Addr
+
+               unicast4           = mustIP("192.0.2.1")
+               unicast6           = mustIP("2001:db8::1")
+               unicastZone6       = mustIP("2001:db8::1%eth0")
+               unicast6Unassigned = mustIP("4000::1") // not in 2000::/3.
+
+               multicast4     = mustIP("224.0.0.1")
+               multicast6     = mustIP("ff02::1")
+               multicastZone6 = mustIP("ff02::1%eth0")
+
+               llu4     = mustIP("169.254.0.1")
+               llu6     = mustIP("fe80::1")
+               llu6Last = mustIP("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
+               lluZone6 = mustIP("fe80::1%eth0")
+
+               loopback4 = mustIP("127.0.0.1")
+               loopback6 = mustIP("::1")
+
+               ilm6     = mustIP("ff01::1")
+               ilmZone6 = mustIP("ff01::1%eth0")
+
+               private4a = mustIP("10.0.0.1")
+               private4b = mustIP("172.16.0.1")
+               private4c = mustIP("192.168.1.1")
+               private6  = mustIP("fd00::1")
+
+               unspecified4 = AddrFrom4([4]byte{})
+               unspecified6 = IPv6Unspecified()
+       )
+
+       tests := []struct {
+               name                    string
+               ip                      Addr
+               globalUnicast           bool
+               interfaceLocalMulticast bool
+               linkLocalMulticast      bool
+               linkLocalUnicast        bool
+               loopback                bool
+               multicast               bool
+               private                 bool
+               unspecified             bool
+       }{
+               {
+                       name: "nil",
+                       ip:   nilIP,
+               },
+               {
+                       name:          "unicast v4Addr",
+                       ip:            unicast4,
+                       globalUnicast: true,
+               },
+               {
+                       name:          "unicast v6Addr",
+                       ip:            unicast6,
+                       globalUnicast: true,
+               },
+               {
+                       name:          "unicast v6AddrZone",
+                       ip:            unicastZone6,
+                       globalUnicast: true,
+               },
+               {
+                       name:          "unicast v6Addr unassigned",
+                       ip:            unicast6Unassigned,
+                       globalUnicast: true,
+               },
+               {
+                       name:               "multicast v4Addr",
+                       ip:                 multicast4,
+                       linkLocalMulticast: true,
+                       multicast:          true,
+               },
+               {
+                       name:               "multicast v6Addr",
+                       ip:                 multicast6,
+                       linkLocalMulticast: true,
+                       multicast:          true,
+               },
+               {
+                       name:               "multicast v6AddrZone",
+                       ip:                 multicastZone6,
+                       linkLocalMulticast: true,
+                       multicast:          true,
+               },
+               {
+                       name:             "link-local unicast v4Addr",
+                       ip:               llu4,
+                       linkLocalUnicast: true,
+               },
+               {
+                       name:             "link-local unicast v6Addr",
+                       ip:               llu6,
+                       linkLocalUnicast: true,
+               },
+               {
+                       name:             "link-local unicast v6Addr upper bound",
+                       ip:               llu6Last,
+                       linkLocalUnicast: true,
+               },
+               {
+                       name:             "link-local unicast v6AddrZone",
+                       ip:               lluZone6,
+                       linkLocalUnicast: true,
+               },
+               {
+                       name:     "loopback v4Addr",
+                       ip:       loopback4,
+                       loopback: true,
+               },
+               {
+                       name:     "loopback v6Addr",
+                       ip:       loopback6,
+                       loopback: true,
+               },
+               {
+                       name:                    "interface-local multicast v6Addr",
+                       ip:                      ilm6,
+                       interfaceLocalMulticast: true,
+                       multicast:               true,
+               },
+               {
+                       name:                    "interface-local multicast v6AddrZone",
+                       ip:                      ilmZone6,
+                       interfaceLocalMulticast: true,
+                       multicast:               true,
+               },
+               {
+                       name:          "private v4Addr 10/8",
+                       ip:            private4a,
+                       globalUnicast: true,
+                       private:       true,
+               },
+               {
+                       name:          "private v4Addr 172.16/12",
+                       ip:            private4b,
+                       globalUnicast: true,
+                       private:       true,
+               },
+               {
+                       name:          "private v4Addr 192.168/16",
+                       ip:            private4c,
+                       globalUnicast: true,
+                       private:       true,
+               },
+               {
+                       name:          "private v6Addr",
+                       ip:            private6,
+                       globalUnicast: true,
+                       private:       true,
+               },
+               {
+                       name:        "unspecified v4Addr",
+                       ip:          unspecified4,
+                       unspecified: true,
+               },
+               {
+                       name:        "unspecified v6Addr",
+                       ip:          unspecified6,
+                       unspecified: true,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       gu := tt.ip.IsGlobalUnicast()
+                       if gu != tt.globalUnicast {
+                               t.Errorf("IsGlobalUnicast(%v) = %v; want %v", tt.ip, gu, tt.globalUnicast)
+                       }
+
+                       ilm := tt.ip.IsInterfaceLocalMulticast()
+                       if ilm != tt.interfaceLocalMulticast {
+                               t.Errorf("IsInterfaceLocalMulticast(%v) = %v; want %v", tt.ip, ilm, tt.interfaceLocalMulticast)
+                       }
+
+                       llu := tt.ip.IsLinkLocalUnicast()
+                       if llu != tt.linkLocalUnicast {
+                               t.Errorf("IsLinkLocalUnicast(%v) = %v; want %v", tt.ip, llu, tt.linkLocalUnicast)
+                       }
+
+                       llm := tt.ip.IsLinkLocalMulticast()
+                       if llm != tt.linkLocalMulticast {
+                               t.Errorf("IsLinkLocalMulticast(%v) = %v; want %v", tt.ip, llm, tt.linkLocalMulticast)
+                       }
+
+                       lo := tt.ip.IsLoopback()
+                       if lo != tt.loopback {
+                               t.Errorf("IsLoopback(%v) = %v; want %v", tt.ip, lo, tt.loopback)
+                       }
+
+                       multicast := tt.ip.IsMulticast()
+                       if multicast != tt.multicast {
+                               t.Errorf("IsMulticast(%v) = %v; want %v", tt.ip, multicast, tt.multicast)
+                       }
+
+                       private := tt.ip.IsPrivate()
+                       if private != tt.private {
+                               t.Errorf("IsPrivate(%v) = %v; want %v", tt.ip, private, tt.private)
+                       }
+
+                       unspecified := tt.ip.IsUnspecified()
+                       if unspecified != tt.unspecified {
+                               t.Errorf("IsUnspecified(%v) = %v; want %v", tt.ip, unspecified, tt.unspecified)
+                       }
+               })
+       }
+}
+
+func TestAddrWellKnown(t *testing.T) {
+       tests := []struct {
+               name string
+               ip   Addr
+               std  net.IP
+       }{
+               {
+                       name: "IPv6 link-local all nodes",
+                       ip:   IPv6LinkLocalAllNodes(),
+                       std:  net.IPv6linklocalallnodes,
+               },
+               {
+                       name: "IPv6 unspecified",
+                       ip:   IPv6Unspecified(),
+                       std:  net.IPv6unspecified,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       want := tt.std.String()
+                       got := tt.ip.String()
+
+                       if got != want {
+                               t.Fatalf("got %s, want %s", got, want)
+                       }
+               })
+       }
+}
+
+func TestLessCompare(t *testing.T) {
+       tests := []struct {
+               a, b Addr
+               want bool
+       }{
+               {Addr{}, Addr{}, false},
+               {Addr{}, mustIP("1.2.3.4"), true},
+               {mustIP("1.2.3.4"), Addr{}, false},
+
+               {mustIP("1.2.3.4"), mustIP("0102:0304::0"), true},
+               {mustIP("0102:0304::0"), mustIP("1.2.3.4"), false},
+               {mustIP("1.2.3.4"), mustIP("1.2.3.4"), false},
+
+               {mustIP("::1"), mustIP("::2"), true},
+               {mustIP("::1"), mustIP("::1%foo"), true},
+               {mustIP("::1%foo"), mustIP("::2"), true},
+               {mustIP("::2"), mustIP("::3"), true},
+
+               {mustIP("::"), mustIP("0.0.0.0"), false},
+               {mustIP("0.0.0.0"), mustIP("::"), true},
+
+               {mustIP("::1%a"), mustIP("::1%b"), true},
+               {mustIP("::1%a"), mustIP("::1%a"), false},
+               {mustIP("::1%b"), mustIP("::1%a"), false},
+       }
+       for _, tt := range tests {
+               got := tt.a.Less(tt.b)
+               if got != tt.want {
+                       t.Errorf("Less(%q, %q) = %v; want %v", tt.a, tt.b, got, tt.want)
+               }
+               cmp := tt.a.Compare(tt.b)
+               if got && cmp != -1 {
+                       t.Errorf("Less(%q, %q) = true, but Compare = %v (not -1)", tt.a, tt.b, cmp)
+               }
+               if cmp < -1 || cmp > 1 {
+                       t.Errorf("bogus Compare return value %v", cmp)
+               }
+               if cmp == 0 && tt.a != tt.b {
+                       t.Errorf("Compare(%q, %q) = 0; but not equal", tt.a, tt.b)
+               }
+               if cmp == 1 && !tt.b.Less(tt.a) {
+                       t.Errorf("Compare(%q, %q) = 1; but b.Less(a) isn't true", tt.a, tt.b)
+               }
+
+               // Also check inverse.
+               if got == tt.want && got {
+                       got2 := tt.b.Less(tt.a)
+                       if got2 {
+                               t.Errorf("Less(%q, %q) was correctly %v, but so was Less(%q, %q)", tt.a, tt.b, got, tt.b, tt.a)
+                       }
+               }
+       }
+
+       // And just sort.
+       values := []Addr{
+               mustIP("::1"),
+               mustIP("::2"),
+               Addr{},
+               mustIP("1.2.3.4"),
+               mustIP("8.8.8.8"),
+               mustIP("::1%foo"),
+       }
+       sort.Slice(values, func(i, j int) bool { return values[i].Less(values[j]) })
+       got := fmt.Sprintf("%s", values)
+       want := `[invalid IP 1.2.3.4 8.8.8.8 ::1 ::1%foo ::2]`
+       if got != want {
+               t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
+       }
+}
+
+func TestIPStringExpanded(t *testing.T) {
+       tests := []struct {
+               ip Addr
+               s  string
+       }{
+               {
+                       ip: Addr{},
+                       s:  "invalid IP",
+               },
+               {
+                       ip: mustIP("192.0.2.1"),
+                       s:  "192.0.2.1",
+               },
+               {
+                       ip: mustIP("::ffff:192.0.2.1"),
+                       s:  "0000:0000:0000:0000:0000:ffff:c000:0201",
+               },
+               {
+                       ip: mustIP("2001:db8::1"),
+                       s:  "2001:0db8:0000:0000:0000:0000:0000:0001",
+               },
+               {
+                       ip: mustIP("2001:db8::1%eth0"),
+                       s:  "2001:0db8:0000:0000:0000:0000:0000:0001%eth0",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.ip.String(), func(t *testing.T) {
+                       want := tt.s
+                       got := tt.ip.StringExpanded()
+
+                       if got != want {
+                               t.Fatalf("got %s, want %s", got, want)
+                       }
+               })
+       }
+}
+
+func TestPrefixMasking(t *testing.T) {
+       type subtest struct {
+               ip   Addr
+               bits uint8
+               p    Prefix
+               ok   bool
+       }
+
+       // makeIPv6 produces a set of IPv6 subtests with an optional zone identifier.
+       makeIPv6 := func(zone string) []subtest {
+               if zone != "" {
+                       zone = "%" + zone
+               }
+
+               return []subtest{
+                       {
+                               ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
+                               bits: 255,
+                       },
+                       {
+                               ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
+                               bits: 32,
+                               p:    mustPrefix(fmt.Sprintf("2001:db8::%s/32", zone)),
+                               ok:   true,
+                       },
+                       {
+                               ip:   mustIP(fmt.Sprintf("fe80::dead:beef:dead:beef%s", zone)),
+                               bits: 96,
+                               p:    mustPrefix(fmt.Sprintf("fe80::dead:beef:0:0%s/96", zone)),
+                               ok:   true,
+                       },
+                       {
+                               ip:   mustIP(fmt.Sprintf("aaaa::%s", zone)),
+                               bits: 4,
+                               p:    mustPrefix(fmt.Sprintf("a000::%s/4", zone)),
+                               ok:   true,
+                       },
+                       {
+                               ip:   mustIP(fmt.Sprintf("::%s", zone)),
+                               bits: 63,
+                               p:    mustPrefix(fmt.Sprintf("::%s/63", zone)),
+                               ok:   true,
+                       },
+               }
+       }
+
+       tests := []struct {
+               family   string
+               subtests []subtest
+       }{
+               {
+                       family: "nil",
+                       subtests: []subtest{
+                               {
+                                       bits: 255,
+                                       ok:   true,
+                               },
+                               {
+                                       bits: 16,
+                                       ok:   true,
+                               },
+                       },
+               },
+               {
+                       family: "IPv4",
+                       subtests: []subtest{
+                               {
+                                       ip:   mustIP("192.0.2.0"),
+                                       bits: 255,
+                               },
+                               {
+                                       ip:   mustIP("192.0.2.0"),
+                                       bits: 16,
+                                       p:    mustPrefix("192.0.0.0/16"),
+                                       ok:   true,
+                               },
+                               {
+                                       ip:   mustIP("255.255.255.255"),
+                                       bits: 20,
+                                       p:    mustPrefix("255.255.240.0/20"),
+                                       ok:   true,
+                               },
+                               {
+                                       // Partially masking one byte that contains both
+                                       // 1s and 0s on either side of the mask limit.
+                                       ip:   mustIP("100.98.156.66"),
+                                       bits: 10,
+                                       p:    mustPrefix("100.64.0.0/10"),
+                                       ok:   true,
+                               },
+                       },
+               },
+               {
+                       family:   "IPv6",
+                       subtests: makeIPv6(""),
+               },
+               {
+                       family:   "IPv6 zone",
+                       subtests: makeIPv6("eth0"),
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.family, func(t *testing.T) {
+                       for _, st := range tt.subtests {
+                               t.Run(st.p.String(), func(t *testing.T) {
+                                       // Ensure st.ip is not mutated.
+                                       orig := st.ip.String()
+
+                                       p, err := st.ip.Prefix(int(st.bits))
+                                       if st.ok && err != nil {
+                                               t.Fatalf("failed to produce prefix: %v", err)
+                                       }
+                                       if !st.ok && err == nil {
+                                               t.Fatal("expected an error, but none occurred")
+                                       }
+                                       if err != nil {
+                                               t.Logf("err: %v", err)
+                                               return
+                                       }
+
+                                       if !reflect.DeepEqual(p, st.p) {
+                                               t.Errorf("prefix = %q, want %q", p, st.p)
+                                       }
+
+                                       if got := st.ip.String(); got != orig {
+                                               t.Errorf("IP was mutated: %q, want %q", got, orig)
+                                       }
+                               })
+                       }
+               })
+       }
+}
+
+func TestPrefixMarshalUnmarshal(t *testing.T) {
+       tests := []string{
+               "",
+               "1.2.3.4/32",
+               "0.0.0.0/0",
+               "::/0",
+               "::1/128",
+               "::ffff:c000:1234/128",
+               "2001:db8::/32",
+       }
+
+       for _, s := range tests {
+               t.Run(s, func(t *testing.T) {
+                       // Ensure that JSON  (and by extension, text) marshaling is
+                       // sane by entering quoted input.
+                       orig := `"` + s + `"`
+
+                       var p Prefix
+                       if err := json.Unmarshal([]byte(orig), &p); err != nil {
+                               t.Fatalf("failed to unmarshal: %v", err)
+                       }
+
+                       pb, err := json.Marshal(p)
+                       if err != nil {
+                               t.Fatalf("failed to marshal: %v", err)
+                       }
+
+                       back := string(pb)
+                       if orig != back {
+                               t.Errorf("Marshal = %q; want %q", back, orig)
+                       }
+               })
+       }
+}
+
+func TestPrefixMarshalUnmarshalZone(t *testing.T) {
+       orig := `"fe80::1cc0:3e8c:119f:c2e1%ens18/128"`
+       unzoned := `"fe80::1cc0:3e8c:119f:c2e1/128"`
+
+       var p Prefix
+       if err := json.Unmarshal([]byte(orig), &p); err != nil {
+               t.Fatalf("failed to unmarshal: %v", err)
+       }
+
+       pb, err := json.Marshal(p)
+       if err != nil {
+               t.Fatalf("failed to marshal: %v", err)
+       }
+
+       back := string(pb)
+       if back != unzoned {
+               t.Errorf("Marshal = %q; want %q", back, unzoned)
+       }
+}
+
+func TestPrefixUnmarshalTextNonZero(t *testing.T) {
+       ip := mustPrefix("fe80::/64")
+       if err := ip.UnmarshalText([]byte("xxx")); err == nil {
+               t.Fatal("unmarshaled into non-empty Prefix")
+       }
+}
+
+func TestIs4AndIs6(t *testing.T) {
+       tests := []struct {
+               ip  Addr
+               is4 bool
+               is6 bool
+       }{
+               {Addr{}, false, false},
+               {mustIP("1.2.3.4"), true, false},
+               {mustIP("127.0.0.2"), true, false},
+               {mustIP("::1"), false, true},
+               {mustIP("::ffff:192.0.2.128"), false, true},
+               {mustIP("::fffe:c000:0280"), false, true},
+               {mustIP("::1%eth0"), false, true},
+       }
+       for _, tt := range tests {
+               got4 := tt.ip.Is4()
+               if got4 != tt.is4 {
+                       t.Errorf("Is4(%q) = %v; want %v", tt.ip, got4, tt.is4)
+               }
+
+               got6 := tt.ip.Is6()
+               if got6 != tt.is6 {
+                       t.Errorf("Is6(%q) = %v; want %v", tt.ip, got6, tt.is6)
+               }
+       }
+}
+
+func TestIs4In6(t *testing.T) {
+       tests := []struct {
+               ip        Addr
+               want      bool
+               wantUnmap Addr
+       }{
+               {Addr{}, false, Addr{}},
+               {mustIP("::ffff:c000:0280"), true, mustIP("192.0.2.128")},
+               {mustIP("::ffff:192.0.2.128"), true, mustIP("192.0.2.128")},
+               {mustIP("::ffff:192.0.2.128%eth0"), true, mustIP("192.0.2.128")},
+               {mustIP("::fffe:c000:0280"), false, mustIP("::fffe:c000:0280")},
+               {mustIP("::ffff:127.001.002.003"), true, mustIP("127.1.2.3")},
+               {mustIP("::ffff:7f01:0203"), true, mustIP("127.1.2.3")},
+               {mustIP("0:0:0:0:0000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
+               {mustIP("0:0:0:0:000000:ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
+               {mustIP("0:0:0:0::ffff:127.1.2.3"), true, mustIP("127.1.2.3")},
+               {mustIP("::1"), false, mustIP("::1")},
+               {mustIP("1.2.3.4"), false, mustIP("1.2.3.4")},
+       }
+       for _, tt := range tests {
+               got := tt.ip.Is4In6()
+               if got != tt.want {
+                       t.Errorf("Is4In6(%q) = %v; want %v", tt.ip, got, tt.want)
+               }
+               u := tt.ip.Unmap()
+               if u != tt.wantUnmap {
+                       t.Errorf("Unmap(%q) = %v; want %v", tt.ip, u, tt.wantUnmap)
+               }
+       }
+}
+
+func TestPrefixMasked(t *testing.T) {
+       tests := []struct {
+               prefix Prefix
+               masked Prefix
+       }{
+               {
+                       prefix: mustPrefix("192.168.0.255/24"),
+                       masked: mustPrefix("192.168.0.0/24"),
+               },
+               {
+                       prefix: mustPrefix("2100::/3"),
+                       masked: mustPrefix("2000::/3"),
+               },
+               {
+                       prefix: PrefixFrom(mustIP("2000::"), 129),
+                       masked: Prefix{},
+               },
+               {
+                       prefix: PrefixFrom(mustIP("1.2.3.4"), 33),
+                       masked: Prefix{},
+               },
+       }
+       for _, test := range tests {
+               t.Run(test.prefix.String(), func(t *testing.T) {
+                       got := test.prefix.Masked()
+                       if got != test.masked {
+                               t.Errorf("Masked=%s, want %s", got, test.masked)
+                       }
+               })
+       }
+}
+
+func TestPrefix(t *testing.T) {
+       tests := []struct {
+               prefix      string
+               ip          Addr
+               bits        int
+               str         string
+               contains    []Addr
+               notContains []Addr
+       }{
+               {
+                       prefix:      "192.168.0.0/24",
+                       ip:          mustIP("192.168.0.0"),
+                       bits:        24,
+                       contains:    mustIPs("192.168.0.1", "192.168.0.55"),
+                       notContains: mustIPs("192.168.1.1", "1.1.1.1"),
+               },
+               {
+                       prefix:      "192.168.1.1/32",
+                       ip:          mustIP("192.168.1.1"),
+                       bits:        32,
+                       contains:    mustIPs("192.168.1.1"),
+                       notContains: mustIPs("192.168.1.2"),
+               },
+               {
+                       prefix:      "100.64.0.0/10", // CGNAT range; prefix not multiple of 8
+                       ip:          mustIP("100.64.0.0"),
+                       bits:        10,
+                       contains:    mustIPs("100.64.0.0", "100.64.0.1", "100.81.251.94", "100.100.100.100", "100.127.255.254", "100.127.255.255"),
+                       notContains: mustIPs("100.63.255.255", "100.128.0.0"),
+               },
+               {
+                       prefix:      "2001:db8::/96",
+                       ip:          mustIP("2001:db8::"),
+                       bits:        96,
+                       contains:    mustIPs("2001:db8::aaaa:bbbb", "2001:db8::1"),
+                       notContains: mustIPs("2001:db8::1:aaaa:bbbb", "2001:db9::"),
+               },
+               {
+                       prefix:      "0.0.0.0/0",
+                       ip:          mustIP("0.0.0.0"),
+                       bits:        0,
+                       contains:    mustIPs("192.168.0.1", "1.1.1.1"),
+                       notContains: append(mustIPs("2001:db8::1"), Addr{}),
+               },
+               {
+                       prefix:      "::/0",
+                       ip:          mustIP("::"),
+                       bits:        0,
+                       contains:    mustIPs("::1", "2001:db8::1"),
+                       notContains: mustIPs("192.0.2.1"),
+               },
+               {
+                       prefix:      "2000::/3",
+                       ip:          mustIP("2000::"),
+                       bits:        3,
+                       contains:    mustIPs("2001:db8::1"),
+                       notContains: mustIPs("fe80::1"),
+               },
+               {
+                       prefix:      "::%0/00/80",
+                       ip:          mustIP("::"),
+                       bits:        80,
+                       str:         "::/80",
+                       contains:    mustIPs("::"),
+                       notContains: mustIPs("ff::%0/00", "ff::%1/23", "::%0/00", "::%1/23"),
+               },
+       }
+       for _, test := range tests {
+               t.Run(test.prefix, func(t *testing.T) {
+                       prefix, err := ParsePrefix(test.prefix)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if prefix.Addr() != test.ip {
+                               t.Errorf("IP=%s, want %s", prefix.Addr(), test.ip)
+                       }
+                       if prefix.Bits() != test.bits {
+                               t.Errorf("bits=%d, want %d", prefix.Bits(), test.bits)
+                       }
+                       for _, ip := range test.contains {
+                               if !prefix.Contains(ip) {
+                                       t.Errorf("does not contain %s", ip)
+                               }
+                       }
+                       for _, ip := range test.notContains {
+                               if prefix.Contains(ip) {
+                                       t.Errorf("contains %s", ip)
+                               }
+                       }
+                       want := test.str
+                       if want == "" {
+                               want = test.prefix
+                       }
+                       if got := prefix.String(); got != want {
+                               t.Errorf("prefix.String()=%q, want %q", got, want)
+                       }
+
+                       TestAppendToMarshal(t, prefix)
+               })
+       }
+}
+
+func TestPrefixFromInvalidBits(t *testing.T) {
+       v4 := MustParseAddr("1.2.3.4")
+       v6 := MustParseAddr("66::66")
+       tests := []struct {
+               ip       Addr
+               in, want int
+       }{
+               {v4, 0, 0},
+               {v6, 0, 0},
+               {v4, 1, 1},
+               {v4, 33, -1},
+               {v6, 33, 33},
+               {v6, 127, 127},
+               {v6, 128, 128},
+               {v4, 254, -1},
+               {v4, 255, -1},
+               {v4, -1, -1},
+               {v6, -1, -1},
+               {v4, -5, -1},
+               {v6, -5, -1},
+       }
+       for _, tt := range tests {
+               p := PrefixFrom(tt.ip, tt.in)
+               if got := p.Bits(); got != tt.want {
+                       t.Errorf("for (%v, %v), Bits out = %v; want %v", tt.ip, tt.in, got, tt.want)
+               }
+       }
+}
+
+func TestParsePrefixAllocs(t *testing.T) {
+       tests := []struct {
+               ip    string
+               slash string
+       }{
+               {"192.168.1.0", "/24"},
+               {"aaaa:bbbb:cccc::", "/24"},
+       }
+       for _, test := range tests {
+               prefix := test.ip + test.slash
+               t.Run(prefix, func(t *testing.T) {
+                       ipAllocs := int(testing.AllocsPerRun(5, func() {
+                               ParseAddr(test.ip)
+                       }))
+                       prefixAllocs := int(testing.AllocsPerRun(5, func() {
+                               ParsePrefix(prefix)
+                       }))
+                       if got := prefixAllocs - ipAllocs; got != 0 {
+                               t.Errorf("allocs=%d, want 0", got)
+                       }
+               })
+       }
+}
+
+func TestParsePrefixError(t *testing.T) {
+       tests := []struct {
+               prefix string
+               errstr string
+       }{
+               {
+                       prefix: "192.168.0.0",
+                       errstr: "no '/'",
+               },
+               {
+                       prefix: "1.257.1.1/24",
+                       errstr: "value >255",
+               },
+               {
+                       prefix: "1.1.1.0/q",
+                       errstr: "bad bits",
+               },
+               {
+                       prefix: "1.1.1.0/-1",
+                       errstr: "out of range",
+               },
+               {
+                       prefix: "1.1.1.0/33",
+                       errstr: "out of range",
+               },
+               {
+                       prefix: "2001::/129",
+                       errstr: "out of range",
+               },
+       }
+       for _, test := range tests {
+               t.Run(test.prefix, func(t *testing.T) {
+                       _, err := ParsePrefix(test.prefix)
+                       if err == nil {
+                               t.Fatal("no error")
+                       }
+                       if got := err.Error(); !strings.Contains(got, test.errstr) {
+                               t.Errorf("error is missing substring %q: %s", test.errstr, got)
+                       }
+               })
+       }
+}
+
+func TestPrefixIsSingleIP(t *testing.T) {
+       tests := []struct {
+               ipp  Prefix
+               want bool
+       }{
+               {ipp: mustPrefix("127.0.0.1/32"), want: true},
+               {ipp: mustPrefix("127.0.0.1/31"), want: false},
+               {ipp: mustPrefix("127.0.0.1/0"), want: false},
+               {ipp: mustPrefix("::1/128"), want: true},
+               {ipp: mustPrefix("::1/127"), want: false},
+               {ipp: mustPrefix("::1/0"), want: false},
+               {ipp: Prefix{}, want: false},
+       }
+       for _, tt := range tests {
+               got := tt.ipp.IsSingleIP()
+               if got != tt.want {
+                       t.Errorf("IsSingleIP(%v) = %v want %v", tt.ipp, got, tt.want)
+               }
+       }
+}
+
+func mustIPs(strs ...string) []Addr {
+       var res []Addr
+       for _, s := range strs {
+               res = append(res, mustIP(s))
+       }
+       return res
+}
+
+func BenchmarkBinaryMarshalRoundTrip(b *testing.B) {
+       b.ReportAllocs()
+       tests := []struct {
+               name string
+               ip   string
+       }{
+               {"ipv4", "1.2.3.4"},
+               {"ipv6", "2001:db8::1"},
+               {"ipv6+zone", "2001:db8::1%eth0"},
+       }
+       for _, tc := range tests {
+               b.Run(tc.name, func(b *testing.B) {
+                       ip := mustIP(tc.ip)
+                       for i := 0; i < b.N; i++ {
+                               bt, err := ip.MarshalBinary()
+                               if err != nil {
+                                       b.Fatal(err)
+                               }
+                               var ip2 Addr
+                               if err := ip2.UnmarshalBinary(bt); err != nil {
+                                       b.Fatal(err)
+                               }
+                       }
+               })
+       }
+}
+
+func BenchmarkStdIPv4(b *testing.B) {
+       b.ReportAllocs()
+       ips := []net.IP{}
+       for i := 0; i < b.N; i++ {
+               ip := net.IPv4(8, 8, 8, 8)
+               ips = ips[:0]
+               for i := 0; i < 100; i++ {
+                       ips = append(ips, ip)
+               }
+       }
+}
+
+func BenchmarkIPv4(b *testing.B) {
+       b.ReportAllocs()
+       ips := []Addr{}
+       for i := 0; i < b.N; i++ {
+               ip := IPv4(8, 8, 8, 8)
+               ips = ips[:0]
+               for i := 0; i < 100; i++ {
+                       ips = append(ips, ip)
+               }
+       }
+}
+
+// ip4i was one of the possible representations of IP that came up in
+// discussions, inlining IPv4 addresses, but having an "overflow"
+// interface for IPv6 or IPv6 + zone. This is here for benchmarking.
+type ip4i struct {
+       ip4    [4]byte
+       flags1 byte
+       flags2 byte
+       flags3 byte
+       flags4 byte
+       ipv6   interface{}
+}
+
+func newip4i_v4(a, b, c, d byte) ip4i {
+       return ip4i{ip4: [4]byte{a, b, c, d}}
+}
+
+// BenchmarkIPv4_inline benchmarks the candidate representation, ip4i.
+func BenchmarkIPv4_inline(b *testing.B) {
+       b.ReportAllocs()
+       ips := []ip4i{}
+       for i := 0; i < b.N; i++ {
+               ip := newip4i_v4(8, 8, 8, 8)
+               ips = ips[:0]
+               for i := 0; i < 100; i++ {
+                       ips = append(ips, ip)
+               }
+       }
+}
+
+func BenchmarkStdIPv6(b *testing.B) {
+       b.ReportAllocs()
+       ips := []net.IP{}
+       for i := 0; i < b.N; i++ {
+               ip := net.ParseIP("2001:db8::1")
+               ips = ips[:0]
+               for i := 0; i < 100; i++ {
+                       ips = append(ips, ip)
+               }
+       }
+}
+
+func BenchmarkIPv6(b *testing.B) {
+       b.ReportAllocs()
+       ips := []Addr{}
+       for i := 0; i < b.N; i++ {
+               ip := mustIP("2001:db8::1")
+               ips = ips[:0]
+               for i := 0; i < 100; i++ {
+                       ips = append(ips, ip)
+               }
+       }
+}
+
+func BenchmarkIPv4Contains(b *testing.B) {
+       b.ReportAllocs()
+       prefix := PrefixFrom(IPv4(192, 168, 1, 0), 24)
+       ip := IPv4(192, 168, 1, 1)
+       for i := 0; i < b.N; i++ {
+               prefix.Contains(ip)
+       }
+}
+
+func BenchmarkIPv6Contains(b *testing.B) {
+       b.ReportAllocs()
+       prefix := MustParsePrefix("::1/128")
+       ip := MustParseAddr("::1")
+       for i := 0; i < b.N; i++ {
+               prefix.Contains(ip)
+       }
+}
+
+var parseBenchInputs = []struct {
+       name string
+       ip   string
+}{
+       {"v4", "192.168.1.1"},
+       {"v6", "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b"},
+       {"v6_ellipsis", "fd7a:115c::626b:430b"},
+       {"v6_v4", "::ffff:192.168.140.255"},
+       {"v6_zone", "1:2::ffff:192.168.140.255%eth1"},
+}
+
+func BenchmarkParseAddr(b *testing.B) {
+       sinkInternValue = intern.Get("eth1") // Pin to not benchmark the intern package
+       for _, test := range parseBenchInputs {
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sinkIP, _ = ParseAddr(test.ip)
+                       }
+               })
+       }
+}
+
+func BenchmarkStdParseIP(b *testing.B) {
+       for _, test := range parseBenchInputs {
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sinkStdIP = net.ParseIP(test.ip)
+                       }
+               })
+       }
+}
+
+func BenchmarkIPString(b *testing.B) {
+       for _, test := range parseBenchInputs {
+               ip := MustParseAddr(test.ip)
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sinkString = ip.String()
+                       }
+               })
+       }
+}
+
+func BenchmarkIPStringExpanded(b *testing.B) {
+       for _, test := range parseBenchInputs {
+               ip := MustParseAddr(test.ip)
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sinkString = ip.StringExpanded()
+                       }
+               })
+       }
+}
+
+func BenchmarkIPMarshalText(b *testing.B) {
+       b.ReportAllocs()
+       ip := MustParseAddr("66.55.44.33")
+       for i := 0; i < b.N; i++ {
+               sinkBytes, _ = ip.MarshalText()
+       }
+}
+
+func BenchmarkAddrPortString(b *testing.B) {
+       for _, test := range parseBenchInputs {
+               ip := MustParseAddr(test.ip)
+               ipp := AddrPortFrom(ip, 60000)
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sinkString = ipp.String()
+                       }
+               })
+       }
+}
+
+func BenchmarkAddrPortMarshalText(b *testing.B) {
+       for _, test := range parseBenchInputs {
+               ip := MustParseAddr(test.ip)
+               ipp := AddrPortFrom(ip, 60000)
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sinkBytes, _ = ipp.MarshalText()
+                       }
+               })
+       }
+}
+
+func BenchmarkPrefixMasking(b *testing.B) {
+       tests := []struct {
+               name string
+               ip   Addr
+               bits int
+       }{
+               {
+                       name: "IPv4 /32",
+                       ip:   IPv4(192, 0, 2, 0),
+                       bits: 32,
+               },
+               {
+                       name: "IPv4 /17",
+                       ip:   IPv4(192, 0, 2, 0),
+                       bits: 17,
+               },
+               {
+                       name: "IPv4 /0",
+                       ip:   IPv4(192, 0, 2, 0),
+                       bits: 0,
+               },
+               {
+                       name: "IPv6 /128",
+                       ip:   mustIP("2001:db8::1"),
+                       bits: 128,
+               },
+               {
+                       name: "IPv6 /65",
+                       ip:   mustIP("2001:db8::1"),
+                       bits: 65,
+               },
+               {
+                       name: "IPv6 /0",
+                       ip:   mustIP("2001:db8::1"),
+                       bits: 0,
+               },
+               {
+                       name: "IPv6 zone /128",
+                       ip:   mustIP("2001:db8::1%eth0"),
+                       bits: 128,
+               },
+               {
+                       name: "IPv6 zone /65",
+                       ip:   mustIP("2001:db8::1%eth0"),
+                       bits: 65,
+               },
+               {
+                       name: "IPv6 zone /0",
+                       ip:   mustIP("2001:db8::1%eth0"),
+                       bits: 0,
+               },
+       }
+
+       for _, tt := range tests {
+               b.Run(tt.name, func(b *testing.B) {
+                       b.ReportAllocs()
+
+                       for i := 0; i < b.N; i++ {
+                               sinkPrefix, _ = tt.ip.Prefix(tt.bits)
+                       }
+               })
+       }
+}
+
+func BenchmarkPrefixMarshalText(b *testing.B) {
+       b.ReportAllocs()
+       ipp := MustParsePrefix("66.55.44.33/22")
+       for i := 0; i < b.N; i++ {
+               sinkBytes, _ = ipp.MarshalText()
+       }
+}
+
+func BenchmarkParseAddrPort(b *testing.B) {
+       for _, test := range parseBenchInputs {
+               var ipp string
+               if strings.HasPrefix(test.name, "v6") {
+                       ipp = fmt.Sprintf("[%s]:1234", test.ip)
+               } else {
+                       ipp = fmt.Sprintf("%s:1234", test.ip)
+               }
+               b.Run(test.name, func(b *testing.B) {
+                       b.ReportAllocs()
+
+                       for i := 0; i < b.N; i++ {
+                               sinkAddrPort, _ = ParseAddrPort(ipp)
+                       }
+               })
+       }
+}
+
+func TestAs4(t *testing.T) {
+       tests := []struct {
+               ip        Addr
+               want      [4]byte
+               wantPanic bool
+       }{
+               {
+                       ip:   mustIP("1.2.3.4"),
+                       want: [4]byte{1, 2, 3, 4},
+               },
+               {
+                       ip:   AddrFrom16(mustIP("1.2.3.4").As16()), // IPv4-in-IPv6
+                       want: [4]byte{1, 2, 3, 4},
+               },
+               {
+                       ip:   mustIP("0.0.0.0"),
+                       want: [4]byte{0, 0, 0, 0},
+               },
+               {
+                       ip:        Addr{},
+                       wantPanic: true,
+               },
+               {
+                       ip:        mustIP("::1"),
+                       wantPanic: true,
+               },
+       }
+       as4 := func(ip Addr) (v [4]byte, gotPanic bool) {
+               defer func() {
+                       if recover() != nil {
+                               gotPanic = true
+                               return
+                       }
+               }()
+               v = ip.As4()
+               return
+       }
+       for i, tt := range tests {
+               got, gotPanic := as4(tt.ip)
+               if gotPanic != tt.wantPanic {
+                       t.Errorf("%d. panic on %v = %v; want %v", i, tt.ip, gotPanic, tt.wantPanic)
+                       continue
+               }
+               if got != tt.want {
+                       t.Errorf("%d. %v = %v; want %v", i, tt.ip, got, tt.want)
+               }
+       }
+}
+
+func TestPrefixOverlaps(t *testing.T) {
+       pfx := mustPrefix
+       tests := []struct {
+               a, b Prefix
+               want bool
+       }{
+               {Prefix{}, pfx("1.2.0.0/16"), false},    // first zero
+               {pfx("1.2.0.0/16"), Prefix{}, false},    // second zero
+               {pfx("::0/3"), pfx("0.0.0.0/3"), false}, // different families
+
+               {pfx("1.2.0.0/16"), pfx("1.2.0.0/16"), true}, // equal
+
+               {pfx("1.2.0.0/16"), pfx("1.2.3.0/24"), true},
+               {pfx("1.2.3.0/24"), pfx("1.2.0.0/16"), true},
+
+               {pfx("1.2.0.0/16"), pfx("1.2.3.0/32"), true},
+               {pfx("1.2.3.0/32"), pfx("1.2.0.0/16"), true},
+
+               // Match /0 either order
+               {pfx("1.2.3.0/32"), pfx("0.0.0.0/0"), true},
+               {pfx("0.0.0.0/0"), pfx("1.2.3.0/32"), true},
+
+               {pfx("1.2.3.0/32"), pfx("5.5.5.5/0"), true}, // normalization not required; /0 means true
+
+               // IPv6 overlapping
+               {pfx("5::1/128"), pfx("5::0/8"), true},
+               {pfx("5::0/8"), pfx("5::1/128"), true},
+
+               // IPv6 not overlapping
+               {pfx("1::1/128"), pfx("2::2/128"), false},
+               {pfx("0100::0/8"), pfx("::1/128"), false},
+
+               // v6-mapped v4 should not overlap with IPv4.
+               {PrefixFrom(AddrFrom16(mustIP("1.2.0.0").As16()), 16), pfx("1.2.3.0/24"), false},
+
+               // Invalid prefixes
+               {PrefixFrom(mustIP("1.2.3.4"), 33), pfx("1.2.3.0/24"), false},
+               {PrefixFrom(mustIP("2000::"), 129), pfx("2000::/64"), false},
+       }
+       for i, tt := range tests {
+               if got := tt.a.Overlaps(tt.b); got != tt.want {
+                       t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.a, tt.b, got, tt.want)
+               }
+               // Overlaps is commutative
+               if got := tt.b.Overlaps(tt.a); got != tt.want {
+                       t.Errorf("%d. (%v).Overlaps(%v) = %v; want %v", i, tt.b, tt.a, got, tt.want)
+               }
+       }
+}
+
+// Sink variables are here to force the compiler to not elide
+// seemingly useless work in benchmarks and allocation tests. If you
+// were to just `_ = foo()` within a test function, the compiler could
+// correctly deduce that foo() does nothing and doesn't need to be
+// called. By writing results to a global variable, we hide that fact
+// from the compiler and force it to keep the code under test.
+var (
+       sinkIP          Addr
+       sinkStdIP       net.IP
+       sinkAddrPort    AddrPort
+       sinkPrefix      Prefix
+       sinkPrefixSlice []Prefix
+       sinkInternValue *intern.Value
+       sinkIP16        [16]byte
+       sinkIP4         [4]byte
+       sinkBool        bool
+       sinkString      string
+       sinkBytes       []byte
+       sinkUDPAddr     = &net.UDPAddr{IP: make(net.IP, 0, 16)}
+)
+
+func TestNoAllocs(t *testing.T) {
+       // Wrappers that panic on error, to prove that our alloc-free
+       // methods are returning successfully.
+       panicIP := func(ip Addr, err error) Addr {
+               if err != nil {
+                       panic(err)
+               }
+               return ip
+       }
+       panicPfx := func(pfx Prefix, err error) Prefix {
+               if err != nil {
+                       panic(err)
+               }
+               return pfx
+       }
+       panicIPP := func(ipp AddrPort, err error) AddrPort {
+               if err != nil {
+                       panic(err)
+               }
+               return ipp
+       }
+       test := func(name string, f func()) {
+               t.Run(name, func(t *testing.T) {
+                       n := testing.AllocsPerRun(1000, f)
+                       if n != 0 {
+                               t.Fatalf("allocs = %d; want 0", int(n))
+                       }
+               })
+       }
+
+       // IP constructors
+       test("IPv4", func() { sinkIP = IPv4(1, 2, 3, 4) })
+       test("AddrFrom4", func() { sinkIP = AddrFrom4([4]byte{1, 2, 3, 4}) })
+       test("AddrFrom16", func() { sinkIP = AddrFrom16([16]byte{}) })
+       test("ParseAddr/4", func() { sinkIP = panicIP(ParseAddr("1.2.3.4")) })
+       test("ParseAddr/6", func() { sinkIP = panicIP(ParseAddr("::1")) })
+       test("MustParseAddr", func() { sinkIP = MustParseAddr("1.2.3.4") })
+       test("IPv6LinkLocalAllNodes", func() { sinkIP = IPv6LinkLocalAllNodes() })
+       test("IPv6Unspecified", func() { sinkIP = IPv6Unspecified() })
+
+       // IP methods
+       test("IP.IsZero", func() { sinkBool = MustParseAddr("1.2.3.4").IsZero() })
+       test("IP.BitLen", func() { sinkBool = MustParseAddr("1.2.3.4").BitLen() == 8 })
+       test("IP.Zone/4", func() { sinkBool = MustParseAddr("1.2.3.4").Zone() == "" })
+       test("IP.Zone/6", func() { sinkBool = MustParseAddr("fe80::1").Zone() == "" })
+       test("IP.Zone/6zone", func() { sinkBool = MustParseAddr("fe80::1%zone").Zone() == "" })
+       test("IP.Compare", func() {
+               a := MustParseAddr("1.2.3.4")
+               b := MustParseAddr("2.3.4.5")
+               sinkBool = a.Compare(b) == 0
+       })
+       test("IP.Less", func() {
+               a := MustParseAddr("1.2.3.4")
+               b := MustParseAddr("2.3.4.5")
+               sinkBool = a.Less(b)
+       })
+       test("IP.Is4", func() { sinkBool = MustParseAddr("1.2.3.4").Is4() })
+       test("IP.Is6", func() { sinkBool = MustParseAddr("fe80::1").Is6() })
+       test("IP.Is4In6", func() { sinkBool = MustParseAddr("fe80::1").Is4In6() })
+       test("IP.Unmap", func() { sinkIP = MustParseAddr("ffff::2.3.4.5").Unmap() })
+       test("IP.WithZone", func() { sinkIP = MustParseAddr("fe80::1").WithZone("") })
+       test("IP.IsGlobalUnicast", func() { sinkBool = MustParseAddr("2001:db8::1").IsGlobalUnicast() })
+       test("IP.IsInterfaceLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsInterfaceLocalMulticast() })
+       test("IP.IsLinkLocalMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalMulticast() })
+       test("IP.IsLinkLocalUnicast", func() { sinkBool = MustParseAddr("fe80::1").IsLinkLocalUnicast() })
+       test("IP.IsLoopback", func() { sinkBool = MustParseAddr("fe80::1").IsLoopback() })
+       test("IP.IsMulticast", func() { sinkBool = MustParseAddr("fe80::1").IsMulticast() })
+       test("IP.IsPrivate", func() { sinkBool = MustParseAddr("fd00::1").IsPrivate() })
+       test("IP.IsUnspecified", func() { sinkBool = IPv6Unspecified().IsUnspecified() })
+       test("IP.Prefix/4", func() { sinkPrefix = panicPfx(MustParseAddr("1.2.3.4").Prefix(20)) })
+       test("IP.Prefix/6", func() { sinkPrefix = panicPfx(MustParseAddr("fe80::1").Prefix(64)) })
+       test("IP.As16", func() { sinkIP16 = MustParseAddr("1.2.3.4").As16() })
+       test("IP.As4", func() { sinkIP4 = MustParseAddr("1.2.3.4").As4() })
+       test("IP.Next", func() { sinkIP = MustParseAddr("1.2.3.4").Next() })
+       test("IP.Prev", func() { sinkIP = MustParseAddr("1.2.3.4").Prev() })
+
+       // AddrPort constructors
+       test("AddrPortFrom", func() { sinkAddrPort = AddrPortFrom(IPv4(1, 2, 3, 4), 22) })
+       test("ParseAddrPort", func() { sinkAddrPort = panicIPP(ParseAddrPort("[::1]:1234")) })
+       test("MustParseAddrPort", func() { sinkAddrPort = MustParseAddrPort("[::1]:1234") })
+
+       // Prefix constructors
+       test("PrefixFrom", func() { sinkPrefix = PrefixFrom(IPv4(1, 2, 3, 4), 32) })
+       test("ParsePrefix/4", func() { sinkPrefix = panicPfx(ParsePrefix("1.2.3.4/20")) })
+       test("ParsePrefix/6", func() { sinkPrefix = panicPfx(ParsePrefix("fe80::1/64")) })
+       test("MustParsePrefix", func() { sinkPrefix = MustParsePrefix("1.2.3.4/20") })
+
+       // Prefix methods
+       test("Prefix.Contains", func() { sinkBool = MustParsePrefix("1.2.3.0/24").Contains(MustParseAddr("1.2.3.4")) })
+       test("Prefix.Overlaps", func() {
+               a, b := MustParsePrefix("1.2.3.0/24"), MustParsePrefix("1.2.0.0/16")
+               sinkBool = a.Overlaps(b)
+       })
+       test("Prefix.IsZero", func() { sinkBool = MustParsePrefix("1.2.0.0/16").IsZero() })
+       test("Prefix.IsSingleIP", func() { sinkBool = MustParsePrefix("1.2.3.4/32").IsSingleIP() })
+       test("IPPRefix.Masked", func() { sinkPrefix = MustParsePrefix("1.2.3.4/16").Masked() })
+}
+
+func TestPrefixString(t *testing.T) {
+       tests := []struct {
+               ipp  Prefix
+               want string
+       }{
+               {Prefix{}, "invalid Prefix"},
+               {PrefixFrom(Addr{}, 8), "invalid Prefix"},
+               {PrefixFrom(MustParseAddr("1.2.3.4"), 88), "invalid Prefix"},
+       }
+
+       for _, tt := range tests {
+               if got := tt.ipp.String(); got != tt.want {
+                       t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
+               }
+       }
+}
+
+func TestInvalidAddrPortString(t *testing.T) {
+       tests := []struct {
+               ipp  AddrPort
+               want string
+       }{
+               {AddrPort{}, "invalid AddrPort"},
+               {AddrPortFrom(Addr{}, 80), "invalid AddrPort"},
+       }
+
+       for _, tt := range tests {
+               if got := tt.ipp.String(); got != tt.want {
+                       t.Errorf("(%#v).String() = %q want %q", tt.ipp, got, tt.want)
+               }
+       }
+}
diff --git a/src/net/netip/slow_test.go b/src/net/netip/slow_test.go
new file mode 100644 (file)
index 0000000..5b46a39
--- /dev/null
@@ -0,0 +1,190 @@
+// 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 netip_test
+
+import (
+       "fmt"
+       . "net/netip"
+       "strconv"
+       "strings"
+)
+
+// zeros is a slice of eight stringified zeros. It's used in
+// parseIPSlow to construct slices of specific amounts of zero fields,
+// from 1 to 8.
+var zeros = []string{"0", "0", "0", "0", "0", "0", "0", "0"}
+
+// parseIPSlow is like ParseIP, but aims for readability above
+// speed. It's the reference implementation for correctness checking
+// and against which we measure optimized parsers.
+//
+// parseIPSlow understands the following forms of IP addresses:
+//  - Regular IPv4: 1.2.3.4
+//  - IPv4 with many leading zeros: 0000001.0000002.0000003.0000004
+//  - Regular IPv6: 1111:2222:3333:4444:5555:6666:7777:8888
+//  - IPv6 with many leading zeros: 00000001:0000002:0000003:0000004:0000005:0000006:0000007:0000008
+//  - IPv6 with zero blocks elided: 1111:2222::7777:8888
+//  - IPv6 with trailing 32 bits expressed as IPv4: 1111:2222:3333:4444:5555:6666:77.77.88.88
+//
+// It does not process the following IP address forms, which have been
+// varyingly accepted by some programs due to an under-specification
+// of the shapes of IPv4 addresses:
+//
+//  - IPv4 as a single 32-bit uint: 4660 (same as "1.2.3.4")
+//  - IPv4 with octal numbers: 0300.0250.0.01 (same as "192.168.0.1")
+//  - IPv4 with hex numbers: 0xc0.0xa8.0x0.0x1 (same as "192.168.0.1")
+//  - IPv4 in "class-B style": 1.2.52 (same as "1.2.3.4")
+//  - IPv4 in "class-A style": 1.564 (same as "1.2.3.4")
+func parseIPSlow(s string) (Addr, error) {
+       // Identify and strip out the zone, if any. There should be 0 or 1
+       // '%' in the string.
+       var zone string
+       fs := strings.Split(s, "%")
+       switch len(fs) {
+       case 1:
+               // No zone, that's fine.
+       case 2:
+               s, zone = fs[0], fs[1]
+               if zone == "" {
+                       return Addr{}, fmt.Errorf("netaddr.ParseIP(%q): no zone after zone specifier", s)
+               }
+       default:
+               return Addr{}, fmt.Errorf("netaddr.ParseIP(%q): too many zone specifiers", s) // TODO: less specific?
+       }
+
+       // IPv4 by itself is easy to do in a helper.
+       if strings.Count(s, ":") == 0 {
+               if zone != "" {
+                       return Addr{}, fmt.Errorf("netaddr.ParseIP(%q): IPv4 addresses cannot have a zone", s)
+               }
+               return parseIPv4Slow(s)
+       }
+
+       normal, err := normalizeIPv6Slow(s)
+       if err != nil {
+               return Addr{}, err
+       }
+
+       // At this point, we've normalized the address back into 8 hex
+       // fields of 16 bits each. Parse that.
+       fs = strings.Split(normal, ":")
+       if len(fs) != 8 {
+               return Addr{}, fmt.Errorf("netaddr.ParseIP(%q): wrong size address", s)
+       }
+       var ret [16]byte
+       for i, f := range fs {
+               a, b, err := parseWord(f)
+               if err != nil {
+                       return Addr{}, err
+               }
+               ret[i*2] = a
+               ret[i*2+1] = b
+       }
+
+       return AddrFrom16(ret).WithZone(zone), nil
+}
+
+// normalizeIPv6Slow expands s, which is assumed to be an IPv6
+// address, to its canonical text form.
+//
+// The canonical form of an IPv6 address is 8 colon-separated fields,
+// where each field should be a hex value from 0 to ffff. This
+// function does not verify the contents of each field.
+//
+// This function performs two transformations:
+//  - The last 32 bits of an IPv6 address may be represented in
+//    IPv4-style dotted quad form, as in 1:2:3:4:5:6:7.8.9.10. That
+//    address is transformed to its hex equivalent,
+//    e.g. 1:2:3:4:5:6:708:90a.
+//  - An address may contain one "::", which expands into as many
+//    16-bit blocks of zeros as needed to make the address its correct
+//    full size. For example, fe80::1:2 expands to fe80:0:0:0:0:0:1:2.
+//
+// Both short forms may be present in a single address,
+// e.g. fe80::1.2.3.4.
+func normalizeIPv6Slow(orig string) (string, error) {
+       s := orig
+
+       // Find and convert an IPv4 address in the final field, if any.
+       i := strings.LastIndex(s, ":")
+       if i == -1 {
+               return "", fmt.Errorf("netaddr.ParseIP(%q): invalid IP address", orig)
+       }
+       if strings.Contains(s[i+1:], ".") {
+               ip, err := parseIPv4Slow(s[i+1:])
+               if err != nil {
+                       return "", err
+               }
+               a4 := ip.As4()
+               s = fmt.Sprintf("%s:%02x%02x:%02x%02x", s[:i], a4[0], a4[1], a4[2], a4[3])
+       }
+
+       // Find and expand a ::, if any.
+       fs := strings.Split(s, "::")
+       switch len(fs) {
+       case 1:
+               // No ::, nothing to do.
+       case 2:
+               lhs, rhs := fs[0], fs[1]
+               // Found a ::, figure out how many zero blocks need to be
+               // inserted.
+               nblocks := strings.Count(lhs, ":") + strings.Count(rhs, ":")
+               if lhs != "" {
+                       nblocks++
+               }
+               if rhs != "" {
+                       nblocks++
+               }
+               if nblocks > 7 {
+                       return "", fmt.Errorf("netaddr.ParseIP(%q): address too long", orig)
+               }
+               fs = nil
+               // Either side of the :: can be empty. We don't want empty
+               // fields to feature in the final normalized address.
+               if lhs != "" {
+                       fs = append(fs, lhs)
+               }
+               fs = append(fs, zeros[:8-nblocks]...)
+               if rhs != "" {
+                       fs = append(fs, rhs)
+               }
+               s = strings.Join(fs, ":")
+       default:
+               // Too many ::
+               return "", fmt.Errorf("netaddr.ParseIP(%q): invalid IP address", orig)
+       }
+
+       return s, nil
+}
+
+// parseIPv4Slow parses and returns an IPv4 address in dotted quad
+// form, e.g. "192.168.0.1". It is slow but easy to read, and the
+// reference implementation against which we compare faster
+// implementations for correctness.
+func parseIPv4Slow(s string) (Addr, error) {
+       fs := strings.Split(s, ".")
+       if len(fs) != 4 {
+               return Addr{}, fmt.Errorf("netaddr.ParseIP(%q): invalid IP address", s)
+       }
+       var ret [4]byte
+       for i := range ret {
+               val, err := strconv.ParseUint(fs[i], 10, 8)
+               if err != nil {
+                       return Addr{}, err
+               }
+               ret[i] = uint8(val)
+       }
+       return AddrFrom4([4]byte{ret[0], ret[1], ret[2], ret[3]}), nil
+}
+
+// parseWord converts a 16-bit hex string into its corresponding
+// two-byte value.
+func parseWord(s string) (byte, byte, error) {
+       ret, err := strconv.ParseUint(s, 16, 16)
+       if err != nil {
+               return 0, 0, err
+       }
+       return uint8(ret >> 8), uint8(ret), nil
+}
diff --git a/src/net/netip/uint128.go b/src/net/netip/uint128.go
new file mode 100644 (file)
index 0000000..738939d
--- /dev/null
@@ -0,0 +1,92 @@
+// 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 netip
+
+import "math/bits"
+
+// uint128 represents a uint128 using two uint64s.
+//
+// When the methods below mention a bit number, bit 0 is the most
+// significant bit (in hi) and bit 127 is the lowest (lo&1).
+type uint128 struct {
+       hi uint64
+       lo uint64
+}
+
+// mask6 returns a uint128 bitmask with the topmost n bits of a
+// 128-bit number.
+func mask6(n int) uint128 {
+       return uint128{^(^uint64(0) >> n), ^uint64(0) << (128 - n)}
+}
+
+// isZero reports whether u == 0.
+//
+// It's faster than u == (uint128{}) because the compiler (as of Go
+// 1.15/1.16b1) doesn't do this trick and instead inserts a branch in
+// its eq alg's generated code.
+func (u uint128) isZero() bool { return u.hi|u.lo == 0 }
+
+// and returns the bitwise AND of u and m (u&m).
+func (u uint128) and(m uint128) uint128 {
+       return uint128{u.hi & m.hi, u.lo & m.lo}
+}
+
+// xor returns the bitwise XOR of u and m (u^m).
+func (u uint128) xor(m uint128) uint128 {
+       return uint128{u.hi ^ m.hi, u.lo ^ m.lo}
+}
+
+// or returns the bitwise OR of u and m (u|m).
+func (u uint128) or(m uint128) uint128 {
+       return uint128{u.hi | m.hi, u.lo | m.lo}
+}
+
+// not returns the bitwise NOT of u.
+func (u uint128) not() uint128 {
+       return uint128{^u.hi, ^u.lo}
+}
+
+// subOne returns u - 1.
+func (u uint128) subOne() uint128 {
+       lo, borrow := bits.Sub64(u.lo, 1, 0)
+       return uint128{u.hi - borrow, lo}
+}
+
+// addOne returns u + 1.
+func (u uint128) addOne() uint128 {
+       lo, carry := bits.Add64(u.lo, 1, 0)
+       return uint128{u.hi + carry, lo}
+}
+
+func u64CommonPrefixLen(a, b uint64) uint8 {
+       return uint8(bits.LeadingZeros64(a ^ b))
+}
+
+func (u uint128) commonPrefixLen(v uint128) (n uint8) {
+       if n = u64CommonPrefixLen(u.hi, v.hi); n == 64 {
+               n += u64CommonPrefixLen(u.lo, v.lo)
+       }
+       return
+}
+
+// halves returns the two uint64 halves of the uint128.
+//
+// Logically, think of it as returning two uint64s.
+// It only returns pointers for inlining reasons on 32-bit platforms.
+func (u *uint128) halves() [2]*uint64 {
+       return [2]*uint64{&u.hi, &u.lo}
+}
+
+// bitsSetFrom returns a copy of u with the given bit
+// and all subsequent ones set.
+func (u uint128) bitsSetFrom(bit uint8) uint128 {
+       return u.or(mask6(int(bit)).not())
+}
+
+// bitsClearedFrom returns a copy of u with the given bit
+// and all subsequent ones cleared.
+func (u uint128) bitsClearedFrom(bit uint8) uint128 {
+       return u.and(mask6(int(bit)))
+}
diff --git a/src/net/netip/uint128_test.go b/src/net/netip/uint128_test.go
new file mode 100644 (file)
index 0000000..dd1ae0e
--- /dev/null
@@ -0,0 +1,89 @@
+// 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 netip
+
+import (
+       "testing"
+)
+
+func TestUint128AddSub(t *testing.T) {
+       const add1 = 1
+       const sub1 = -1
+       tests := []struct {
+               in   uint128
+               op   int // +1 or -1 to add vs subtract
+               want uint128
+       }{
+               {uint128{0, 0}, add1, uint128{0, 1}},
+               {uint128{0, 1}, add1, uint128{0, 2}},
+               {uint128{1, 0}, add1, uint128{1, 1}},
+               {uint128{0, ^uint64(0)}, add1, uint128{1, 0}},
+               {uint128{^uint64(0), ^uint64(0)}, add1, uint128{0, 0}},
+
+               {uint128{0, 0}, sub1, uint128{^uint64(0), ^uint64(0)}},
+               {uint128{0, 1}, sub1, uint128{0, 0}},
+               {uint128{0, 2}, sub1, uint128{0, 1}},
+               {uint128{1, 0}, sub1, uint128{0, ^uint64(0)}},
+               {uint128{1, 1}, sub1, uint128{1, 0}},
+       }
+       for _, tt := range tests {
+               var got uint128
+               switch tt.op {
+               case add1:
+                       got = tt.in.addOne()
+               case sub1:
+                       got = tt.in.subOne()
+               default:
+                       panic("bogus op")
+               }
+               if got != tt.want {
+                       t.Errorf("%v add %d = %v; want %v", tt.in, tt.op, got, tt.want)
+               }
+       }
+}
+
+func TestBitsSetFrom(t *testing.T) {
+       tests := []struct {
+               bit  uint8
+               want uint128
+       }{
+               {0, uint128{^uint64(0), ^uint64(0)}},
+               {1, uint128{^uint64(0) >> 1, ^uint64(0)}},
+               {63, uint128{1, ^uint64(0)}},
+               {64, uint128{0, ^uint64(0)}},
+               {65, uint128{0, ^uint64(0) >> 1}},
+               {127, uint128{0, 1}},
+               {128, uint128{0, 0}},
+       }
+       for _, tt := range tests {
+               var zero uint128
+               got := zero.bitsSetFrom(tt.bit)
+               if got != tt.want {
+                       t.Errorf("0.bitsSetFrom(%d) = %064b want %064b", tt.bit, got, tt.want)
+               }
+       }
+}
+
+func TestBitsClearedFrom(t *testing.T) {
+       tests := []struct {
+               bit  uint8
+               want uint128
+       }{
+               {0, uint128{0, 0}},
+               {1, uint128{1 << 63, 0}},
+               {63, uint128{^uint64(0) &^ 1, 0}},
+               {64, uint128{^uint64(0), 0}},
+               {65, uint128{^uint64(0), 1 << 63}},
+               {127, uint128{^uint64(0), ^uint64(0) &^ 1}},
+               {128, uint128{^uint64(0), ^uint64(0)}},
+       }
+       for _, tt := range tests {
+               ones := uint128{^uint64(0), ^uint64(0)}
+               got := ones.bitsClearedFrom(tt.bit)
+               if got != tt.want {
+                       t.Errorf("ones.bitsClearedFrom(%d) = %064b want %064b", tt.bit, got, tt.want)
+               }
+       }
+}
index 85177cab9b92da2cbd26aeff0959180c8df34252..ee5568883f2d473736f6835442e7d8e5b78ef68f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 4b73886c5119c453f953b43d830713cd11facff2..c9ccc60cb787225413d2cd96a9e6c7700a41aa3d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index aeb9845fa77b8fc12828c797908910b673bfe9dc..b3b17156555a8a28e9673096b991a74a99d2653b 100644 (file)
@@ -6,7 +6,6 @@
 // tag.
 
 //go:build !js
-// +build !js
 
 package net
 
index 6c230ab63fa0c7906a5c80b95f0e2443be5d139f..ee2890fe2ce5b33a18a692c48a36c50587d835a9 100644 (file)
@@ -208,6 +208,16 @@ func last(s string, b byte) int {
        return i
 }
 
+// hasUpperCase tells whether the given string contains at least one upper-case.
+func hasUpperCase(s string) bool {
+       for i := range s {
+               if 'A' <= s[i] && s[i] <= 'Z' {
+                       return true
+               }
+       }
+       return false
+}
+
 // lowerASCIIBytes makes x ASCII lowercase in-place.
 func lowerASCIIBytes(x []byte) {
        for i, b := range x {
@@ -331,26 +341,3 @@ func readFull(r io.Reader) (all []byte, err error) {
                }
        }
 }
-
-// goDebugString returns the value of the named GODEBUG key.
-// GODEBUG is of the form "key=val,key2=val2"
-func goDebugString(key string) string {
-       s := os.Getenv("GODEBUG")
-       for i := 0; i < len(s)-len(key)-1; i++ {
-               if i > 0 && s[i-1] != ',' {
-                       continue
-               }
-               afterKey := s[i+len(key):]
-               if afterKey[0] != '=' || s[i:i+len(key)] != key {
-                       continue
-               }
-               val := afterKey[1:]
-               for i, b := range val {
-                       if b == ',' {
-                               return val[:i]
-                       }
-               }
-               return val
-       }
-       return ""
-}
index c5f8bfd198ce4f519beae58f25407ffe747b44cb..97716d769a9b498c037dcae8f89e0d4bc32aa1b5 100644 (file)
@@ -51,33 +51,6 @@ func TestReadLine(t *testing.T) {
        }
 }
 
-func TestGoDebugString(t *testing.T) {
-       defer os.Setenv("GODEBUG", os.Getenv("GODEBUG"))
-       tests := []struct {
-               godebug string
-               key     string
-               want    string
-       }{
-               {"", "foo", ""},
-               {"foo=", "foo", ""},
-               {"foo=bar", "foo", "bar"},
-               {"foo=bar,", "foo", "bar"},
-               {"foo,foo=bar,", "foo", "bar"},
-               {"foo1=bar,foo=bar,", "foo", "bar"},
-               {"foo=bar,foo=bar,", "foo", "bar"},
-               {"foo=", "foo", ""},
-               {"foo", "foo", ""},
-               {",foo", "foo", ""},
-               {"foo=bar,baz", "loooooooong", ""},
-       }
-       for _, tt := range tests {
-               os.Setenv("GODEBUG", tt.godebug)
-               if got := goDebugString(tt.key); got != tt.want {
-                       t.Errorf("for %q, goDebugString(%q) = %q; want %q", tt.godebug, tt.key, got, tt.want)
-               }
-       }
-}
-
 func TestDtoi(t *testing.T) {
        for _, tt := range []struct {
                in  string
index 2da23dedcea6749a74997c3804e376dc7b9b3801..7d92a0de5de7f675eb335b0b87dbed2d3ab3935e 100644 (file)
@@ -34,8 +34,8 @@ func init() {
 // testableNetwork reports whether network is testable on the current
 // platform configuration.
 func testableNetwork(network string) bool {
-       ss := strings.Split(network, ":")
-       switch ss[0] {
+       net, _, _ := strings.Cut(network, ":")
+       switch net {
        case "ip+nopriv":
        case "ip", "ip4", "ip6":
                switch runtime.GOOS {
@@ -68,7 +68,7 @@ func testableNetwork(network string) bool {
                        }
                }
        }
-       switch ss[0] {
+       switch net {
        case "tcp4", "udp4", "ip4":
                if !supportsIPv4() {
                        return false
@@ -88,7 +88,7 @@ func iOS() bool {
 // testableAddress reports whether address of network is testable on
 // the current platform configuration.
 func testableAddress(network, address string) bool {
-       switch ss := strings.Split(network, ":"); ss[0] {
+       switch net, _, _ := strings.Cut(network, ":"); net {
        case "unix", "unixgram", "unixpacket":
                // Abstract unix domain sockets, a Linux-ism.
                if address[0] == '@' && runtime.GOOS != "linux" {
@@ -107,7 +107,7 @@ func testableListenArgs(network, address, client string) bool {
 
        var err error
        var addr Addr
-       switch ss := strings.Split(network, ":"); ss[0] {
+       switch net, _, _ := strings.Cut(network, ":"); net {
        case "tcp", "tcp4", "tcp6":
                addr, err = ResolveTCPAddr("tcp", address)
        case "udp", "udp4", "udp6":
index a9a96a2323b80d0a104e3de0dc132a08d3450c7a..102722b2ca7045f6ea655c9e8c9db2920bc21bea 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 // Read system port mappings from /etc/services
 
index fc9b3862563e9a2c0cef4a76eee225eb281848dc..9f7d8ee4ef5071cda2ac4c0340b0ffccb1f47561 100644 (file)
@@ -6,7 +6,6 @@
 // tag.
 
 //go:build !js
-// +build !js
 
 package net
 
index 975aa8d9569162ff52f750d58f648e0f6f77502a..ff3d829893d06e07c6ff8631b9d1f5add88a5caa 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (js && wasm) || plan9
-// +build js,wasm plan9
 
 package net
 
index 3ef7af33b7330e307d31d61f1bf2fc330ef72369..645d82a1a6ab4321994272f7a16ede94e00549c0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 75bbab8b27eeb4dbd19086b3ecdf252548bd7683..e6e1ad771a5a35489b54dbd05470f3a0dbf9546f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 03225e3d0104b5277d8a0af2fea98be725676c02..38a10ce0b3156f25040d35631a9ff497be201e6d 100644 (file)
@@ -57,8 +57,8 @@ func TestGobError(t *testing.T) {
                if err == nil {
                        t.Fatal("no error")
                }
-               if !strings.Contains(err.(error).Error(), "reading body EOF") {
-                       t.Fatal("expected `reading body EOF', got", err)
+               if !strings.Contains(err.(error).Error(), "reading body unexpected EOF") {
+                       t.Fatal("expected `reading body unexpected EOF', got", err)
                }
        }()
        Register(new(S))
index 074c5b9b0d7a5ecaf84aaef241cb29225a3a2ed4..223a53cfa78317fc72320275be430baa33e30ea4 100644 (file)
@@ -203,7 +203,7 @@ var DefaultServer = NewServer()
 
 // Is this type exported or a builtin?
 func isExportedOrBuiltinType(t reflect.Type) bool {
-       for t.Kind() == reflect.Ptr {
+       for t.Kind() == reflect.Pointer {
                t = t.Elem()
        }
        // PkgPath will be non-empty even for an exported type,
@@ -231,6 +231,10 @@ func (server *Server) RegisterName(name string, rcvr interface{}) error {
        return server.register(rcvr, name, true)
 }
 
+// logRegisterError specifies whether to log problems during method registration.
+// To debug registration, recompile the package with this set to true.
+const logRegisterError = false
+
 func (server *Server) register(rcvr interface{}, name string, useName bool) error {
        s := new(service)
        s.typ = reflect.TypeOf(rcvr)
@@ -252,13 +256,13 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
        s.name = sname
 
        // Install the methods
-       s.method = suitableMethods(s.typ, true)
+       s.method = suitableMethods(s.typ, logRegisterError)
 
        if len(s.method) == 0 {
                str := ""
 
                // To help the user, see if a pointer receiver would work.
-               method := suitableMethods(reflect.PtrTo(s.typ), false)
+               method := suitableMethods(reflect.PointerTo(s.typ), false)
                if len(method) != 0 {
                        str = "rpc.Register: type " + sname + " has no exported methods of suitable type (hint: pass a pointer to value of that type)"
                } else {
@@ -274,9 +278,9 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro
        return nil
 }
 
-// suitableMethods returns suitable Rpc methods of typ, it will report
-// error using log if reportErr is true.
-func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
+// suitableMethods returns suitable Rpc methods of typ. It will log
+// errors if logErr is true.
+func suitableMethods(typ reflect.Type, logErr bool) map[string]*methodType {
        methods := make(map[string]*methodType)
        for m := 0; m < typ.NumMethod(); m++ {
                method := typ.Method(m)
@@ -288,7 +292,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
                }
                // Method needs three ins: receiver, *args, *reply.
                if mtype.NumIn() != 3 {
-                       if reportErr {
+                       if logErr {
                                log.Printf("rpc.Register: method %q has %d input parameters; needs exactly three\n", mname, mtype.NumIn())
                        }
                        continue
@@ -296,36 +300,36 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
                // First arg need not be a pointer.
                argType := mtype.In(1)
                if !isExportedOrBuiltinType(argType) {
-                       if reportErr {
+                       if logErr {
                                log.Printf("rpc.Register: argument type of method %q is not exported: %q\n", mname, argType)
                        }
                        continue
                }
                // Second arg must be a pointer.
                replyType := mtype.In(2)
-               if replyType.Kind() != reflect.Ptr {
-                       if reportErr {
+               if replyType.Kind() != reflect.Pointer {
+                       if logErr {
                                log.Printf("rpc.Register: reply type of method %q is not a pointer: %q\n", mname, replyType)
                        }
                        continue
                }
                // Reply type must be exported.
                if !isExportedOrBuiltinType(replyType) {
-                       if reportErr {
+                       if logErr {
                                log.Printf("rpc.Register: reply type of method %q is not exported: %q\n", mname, replyType)
                        }
                        continue
                }
                // Method needs one out.
                if mtype.NumOut() != 1 {
-                       if reportErr {
+                       if logErr {
                                log.Printf("rpc.Register: method %q has %d output parameters; needs exactly one\n", mname, mtype.NumOut())
                        }
                        continue
                }
                // The return type of the method must be error.
                if returnType := mtype.Out(0); returnType != typeOfError {
-                       if reportErr {
+                       if logErr {
                                log.Printf("rpc.Register: return type of method %q is %q, must be error\n", mname, returnType)
                        }
                        continue
@@ -552,7 +556,7 @@ func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *m
 
        // Decode the argument value.
        argIsValue := false // if true, need to indirect before calling.
-       if mtype.ArgType.Kind() == reflect.Ptr {
+       if mtype.ArgType.Kind() == reflect.Pointer {
                argv = reflect.New(mtype.ArgType.Elem())
        } else {
                argv = reflect.New(mtype.ArgType)
index 5753bc02898742181c55fd7979f17ef6ed2422d5..4ddae852e174bc1cc8d9488234ab34854cd490b1 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build aix || darwin || (js && wasm) || netbsd || openbsd
-// +build aix darwin js,wasm netbsd openbsd
+//go:build aix || (js && wasm) || netbsd || openbsd
 
 package net
 
index 54e51fa0abc66e38a1646bd04cd443f82ef04833..492333d0c85714477f038d134df11c362843eee3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 54667d672f87b405e2c599999664ce193fe575ff..8845a981f58baf6b86e1e47e3605076cbaa72e9e 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build dragonfly || freebsd || solaris
-// +build dragonfly freebsd solaris
+//go:build darwin || dragonfly || freebsd || solaris
 
 package net
 
index 7cbf15229887155f05ac91092e3e4d079fa961bd..5192c1e0afc76479ad44d7b2365786f8ec2880c0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 1a6864a0f2436caf5ad74a5aa05350d1f99c2f48..bcccaa25979599fb18b714bd0115e86f70669d29 100644 (file)
@@ -136,12 +136,8 @@ func (c *Client) ehlo() error {
        if len(extList) > 1 {
                extList = extList[1:]
                for _, line := range extList {
-                       args := strings.SplitN(line, " ", 2)
-                       if len(args) > 1 {
-                               ext[args[0]] = args[1]
-                       } else {
-                               ext[args[0]] = ""
-                       }
+                       k, v, _ := strings.Cut(line, " ")
+                       ext[k] = v
                }
        }
        if mechs, ok := ext["AUTH"]; ok {
index 4c883ada78f91ef2d9dcd16e9641d664ce6125d4..27daf722b53466318304097a043ae9e93d1431f4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 package net
 
index 6861c4bf635dcfb3fda8b7b1cc6a1cd8cf25e81f..56dab31b1466a18cb3584671c8e906460f455c16 100644 (file)
@@ -6,7 +6,6 @@
 // setting SetNonblock and CloseOnExec.
 
 //go:build dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build dragonfly freebsd illumos linux netbsd openbsd
 
 package net
 
index 9b1e7880aed4494b947ba57e1a76b92054f80da0..98a48229c755517e9eff597cae1dfa944feaf5c4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package net
 
index d804bfaacce3a0edbca43a53213f7ed952a45050..4b73e575fe3a3fd7a7e9dcb7f232ecd02cf57651 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || (js && wasm) || solaris
-// +build aix js,wasm solaris
 
 package net
 
index 9d77cb569b938ebe3a22b87f935cda3f4a8044cd..c8e91936ade1d940969f52b1f0bf7b0188794e43 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
index ee1f98b834cf3753de73a653a33fc0aca47e937f..ff998119808e48d67a2bfbdd8116f65768133d9f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 package net
 
index 50b9bfa0a78ea5da5b0a920f3397fdc0dc5a3567..645080f9885e5374fb0504745c6d6e5870c5cd4f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package net
 
index 99b5277ed0a874c098ed936633f44d8dc4cad436..98e23714d9a267060dca78a2551110d6d57fd218 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
index 56022fd1a59e37ba7a00292b7488d5e8ebe6b940..3e9ba1ee7867e75746d460ab926055d1e668e35d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd netbsd openbsd solaris
 
 package net
 
index a2143aec2cba6787b9ed486d4e811a6f1994408f..22031df22c221a344627ac1122e7b79507331dd1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package net
 
index 4175922cec5f6f7d013626c3a28a928d979a2d7f..2c993eb71953f67ff37fff0521140e06c42602e0 100644 (file)
@@ -3,38 +3,31 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
 import "syscall"
 
 func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
-       // See golang.org/issue/7399.
        return syscall.ENOPROTOOPT
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       // See golang.org/issue/7399.
        return syscall.ENOPROTOOPT
 }
 
 func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
-       // See golang.org/issue/7399.
        return syscall.ENOPROTOOPT
 }
 
 func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
-       // See golang.org/issue/7399.
        return syscall.ENOPROTOOPT
 }
 
 func setIPv6MulticastLoopback(fd *netFD, v bool) error {
-       // See golang.org/issue/7399.
        return syscall.ENOPROTOOPT
 }
 
 func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
-       // See golang.org/issue/7399.
        return syscall.ENOPROTOOPT
 }
index ce2e9046a9440f9506c808fdb9934bc42ffd2944..3cdadb11c5615f6fa628f87facfc61351da3b569 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !linux
-// +build !linux
 
 package net
 
index be13cc924d04f50536e75ec4ea075d55e7ad920d..43e0b926f7a4ec00e3d1a78f2742cf68a2480b13 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package net
 
index a32483e2df94e4101948501042aba46ef7790394..26eac5585a8a29ab301089883a35eba9001d3775 100644 (file)
@@ -6,7 +6,6 @@
 // for setting SetNonblock and CloseOnExec.
 
 //go:build aix || darwin || (solaris && !illumos)
-// +build aix darwin solaris,!illumos
 
 package net
 
index 19a90143f34861be7efc3ddb6de3a102bef59391..fddb018aab846831472d223bd650ec2ecd18570f 100644 (file)
@@ -8,6 +8,7 @@ import (
        "context"
        "internal/itoa"
        "io"
+       "net/netip"
        "os"
        "syscall"
        "time"
@@ -23,6 +24,20 @@ type TCPAddr struct {
        Zone string // IPv6 scoped addressing zone
 }
 
+// AddrPort returns the TCPAddr a as a netip.AddrPort.
+//
+// If a.Port does not fit in a uint16, it's silently truncated.
+//
+// If a is nil, a zero value is returned.
+func (a *TCPAddr) AddrPort() netip.AddrPort {
+       if a == nil {
+               return netip.AddrPort{}
+       }
+       na, _ := netip.AddrFromSlice(a.IP)
+       na = na.WithZone(a.Zone)
+       return netip.AddrPortFrom(na, uint16(a.Port))
+}
+
 // Network returns the address's network name, "tcp".
 func (a *TCPAddr) Network() string { return "tcp" }
 
index 7c4523c5eea8ec6352728cc70cf9907728e716c7..ed6b18b5517eb1c38ac6921e05e4b26f3d11fc1e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
index 9c9f1eae93d832e7f295badc182abe00368697a2..fdf5c330a990138decfb55349f213b30ad2fe7e6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index 41bd229132d912883a18aefb1b24b6b56d2e59a2..b1f2876d4ed82b7bb60f41f45098f71f0262a215 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9 && !windows
-// +build !js,!plan9,!windows
 
 package net
 
index d08832adc04c98b0f8a772ad906dcc42ae193c8e..73754b1a0f7fe2c30dc5687f535f770912354b85 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
 
 package net
 
index 028d5fd29cff8ebda730b1e9eb7bf46c72fd2430..0fe91829c0e05a91b7d1442c459abb90b247078c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package net
 
index a945889e00e86f9cef70d2e1d356123a87ab6f64..bdcdc4023983944dbe39b8483786df7555418f8c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || freebsd || linux || netbsd
-// +build aix freebsd linux netbsd
 
 package net
 
index 5c3084f8a7c9fd8be8eb93af87cb9e758bca1fa2..157c59b17accfb2a48ca5ace16bf1d214ebe388c 100644 (file)
@@ -460,6 +460,8 @@ func (r *Reader) ReadDotLines() ([]string, error) {
        return v, err
 }
 
+var colon = []byte(":")
+
 // ReadMIMEHeader reads a MIME-style header from r.
 // The header is a sequence of possibly continued Key: Value lines
 // ending in a blank line.
@@ -508,11 +510,11 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
                }
 
                // Key ends at first colon.
-               i := bytes.IndexByte(kv, ':')
-               if i < 0 {
+               k, v, ok := bytes.Cut(kv, colon)
+               if !ok {
                        return m, ProtocolError("malformed MIME header line: " + string(kv))
                }
-               key := canonicalMIMEHeaderKey(kv[:i])
+               key := canonicalMIMEHeaderKey(k)
 
                // As per RFC 7230 field-name is a token, tokens consist of one or more chars.
                // We could return a ProtocolError here, but better to be liberal in what we
@@ -522,11 +524,7 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
                }
 
                // Skip initial spaces in value.
-               i++ // skip colon
-               for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
-                       i++
-               }
-               value := string(kv[i:])
+               value := strings.TrimLeft(string(v), " \t")
 
                vv := m[key]
                if vv == nil && len(strs) > 0 {
@@ -561,6 +559,8 @@ func mustHaveFieldNameColon(line []byte) error {
        return nil
 }
 
+var nl = []byte("\n")
+
 // upcomingHeaderNewlines returns an approximation of the number of newlines
 // that will be in this header. If it gets confused, it returns 0.
 func (r *Reader) upcomingHeaderNewlines() (n int) {
@@ -571,17 +571,7 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
                return
        }
        peek, _ := r.R.Peek(s)
-       for len(peek) > 0 {
-               i := bytes.IndexByte(peek, '\n')
-               if i < 3 {
-                       // Not present (-1) or found within the next few bytes,
-                       // implying we're at the end ("\r\n\r\n" or "\n\n")
-                       return
-               }
-               n++
-               peek = peek[i+1:]
-       }
-       return
+       return bytes.Count(peek, nl)
 }
 
 // CanonicalMIMEHeaderKey returns the canonical format of the
index e1cf1467c36f00aca3bf254d9c0676a91398a173..82069b347a5cdf258b0f3c886bc33097027344e0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
@@ -93,53 +92,38 @@ func TestDialTimeout(t *testing.T) {
        }
 }
 
-var dialTimeoutMaxDurationTests = []struct {
-       timeout time.Duration
-       delta   time.Duration // for deadline
-}{
-       // Large timeouts that will overflow an int64 unix nanos.
-       {1<<63 - 1, 0},
-       {0, 1<<63 - 1},
-}
-
 func TestDialTimeoutMaxDuration(t *testing.T) {
-       if runtime.GOOS == "openbsd" {
-               testenv.SkipFlaky(t, 15157)
-       }
-
        ln, err := newLocalListener("tcp")
        if err != nil {
                t.Fatal(err)
        }
-       defer ln.Close()
+       defer func() {
+               if err := ln.Close(); err != nil {
+                       t.Error(err)
+               }
+       }()
 
-       for i, tt := range dialTimeoutMaxDurationTests {
-               ch := make(chan error)
-               max := time.NewTimer(250 * time.Millisecond)
-               defer max.Stop()
-               go func() {
+       for _, tt := range []struct {
+               timeout time.Duration
+               delta   time.Duration // for deadline
+       }{
+               // Large timeouts that will overflow an int64 unix nanos.
+               {1<<63 - 1, 0},
+               {0, 1<<63 - 1},
+       } {
+               t.Run(fmt.Sprintf("timeout=%s/delta=%s", tt.timeout, tt.delta), func(t *testing.T) {
                        d := Dialer{Timeout: tt.timeout}
                        if tt.delta != 0 {
                                d.Deadline = time.Now().Add(tt.delta)
                        }
                        c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
-                       if err == nil {
-                               c.Close()
-                       }
-                       ch <- err
-               }()
-
-               select {
-               case <-max.C:
-                       t.Fatalf("#%d: Dial didn't return in an expected time", i)
-               case err := <-ch:
-                       if perr := parseDialError(err); perr != nil {
-                               t.Error(perr)
-                       }
                        if err != nil {
-                               t.Errorf("#%d: %v", i, err)
+                               t.Fatal(err)
                        }
-               }
+                       if err := c.Close(); err != nil {
+                               t.Error(err)
+                       }
+               })
        }
 }
 
index 70f2ce226aa7b149471b23432baf1d7fae3e62ea..622b1f83fb2b4423aedbbdad6d823eca5986e6ff 100644 (file)
@@ -7,6 +7,7 @@ package net
 import (
        "context"
        "internal/itoa"
+       "net/netip"
        "syscall"
 )
 
@@ -26,6 +27,20 @@ type UDPAddr struct {
        Zone string // IPv6 scoped addressing zone
 }
 
+// AddrPort returns the UDPAddr a as a netip.AddrPort.
+//
+// If a.Port does not fit in a uint16, it's silently truncated.
+//
+// If a is nil, a zero value is returned.
+func (a *UDPAddr) AddrPort() netip.AddrPort {
+       if a == nil {
+               return netip.AddrPort{}
+       }
+       na, _ := netip.AddrFromSlice(a.IP)
+       na = na.WithZone(a.Zone)
+       return netip.AddrPortFrom(na, uint16(a.Port))
+}
+
 // Network returns the address's network name, "udp".
 func (a *UDPAddr) Network() string { return "udp" }
 
@@ -84,6 +99,28 @@ func ResolveUDPAddr(network, address string) (*UDPAddr, error) {
        return addrs.forResolve(network, address).(*UDPAddr), nil
 }
 
+// UDPAddrFromAddrPort returns addr as a UDPAddr.
+//
+// If addr is not valid, it returns nil.
+func UDPAddrFromAddrPort(addr netip.AddrPort) *UDPAddr {
+       if !addr.IsValid() {
+               return nil
+       }
+       ip16 := addr.Addr().As16()
+       return &UDPAddr{
+               IP:   IP(ip16[:]),
+               Zone: addr.Addr().Zone(),
+               Port: int(addr.Port()),
+       }
+}
+
+// An addrPortUDPAddr is a netip.AddrPort-based UDP address that satisfies the Addr interface.
+type addrPortUDPAddr struct {
+       netip.AddrPort
+}
+
+func (addrPortUDPAddr) Network() string { return "udp" }
+
 // UDPConn is the implementation of the Conn and PacketConn interfaces
 // for UDP network connections.
 type UDPConn struct {
@@ -130,6 +167,18 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
        return n, addr, err
 }
 
+// ReadFromUDPAddrPort acts like ReadFrom but returns a netip.AddrPort.
+func (c *UDPConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) {
+       if !c.ok() {
+               return 0, netip.AddrPort{}, syscall.EINVAL
+       }
+       n, addr, err = c.readFromAddrPort(b)
+       if err != nil {
+               err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+       }
+       return n, addr, err
+}
+
 // ReadMsgUDP reads a message from c, copying the payload into b and
 // the associated out-of-band data into oob. It returns the number of
 // bytes copied into b, the number of bytes copied into oob, the flags
@@ -138,8 +187,16 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
 // The packages golang.org/x/net/ipv4 and golang.org/x/net/ipv6 can be
 // used to manipulate IP-level socket options in oob.
 func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+       var ap netip.AddrPort
+       n, oobn, flags, ap, err = c.ReadMsgUDPAddrPort(b, oob)
+       addr = UDPAddrFromAddrPort(ap)
+       return
+}
+
+// ReadMsgUDPAddrPort is like ReadMsgUDP but returns an netip.AddrPort instead of a UDPAddr.
+func (c *UDPConn) ReadMsgUDPAddrPort(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
        if !c.ok() {
-               return 0, 0, 0, nil, syscall.EINVAL
+               return 0, 0, 0, netip.AddrPort{}, syscall.EINVAL
        }
        n, oobn, flags, addr, err = c.readMsg(b, oob)
        if err != nil {
@@ -160,6 +217,18 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
        return n, err
 }
 
+// WriteToUDPAddrPort acts like WriteTo but takes a netip.AddrPort.
+func (c *UDPConn) WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (int, error) {
+       if !c.ok() {
+               return 0, syscall.EINVAL
+       }
+       n, err := c.writeToAddrPort(b, addr)
+       if err != nil {
+               err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addrPortUDPAddr{addr}, Err: err}
+       }
+       return n, err
+}
+
 // WriteTo implements the PacketConn WriteTo method.
 func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
        if !c.ok() {
@@ -195,6 +264,18 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
        return
 }
 
+// WriteMsgUDPAddrPort is like WriteMsgUDP but takes a netip.AddrPort instead of a UDPAddr.
+func (c *UDPConn) WriteMsgUDPAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) {
+       if !c.ok() {
+               return 0, 0, syscall.EINVAL
+       }
+       n, oobn, err = c.writeMsgAddrPort(b, oob, addr)
+       if err != nil {
+               err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addrPortUDPAddr{addr}, Err: err}
+       }
+       return
+}
+
 func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
 
 // DialUDP acts like Dial for UDP networks.
index 1df293d1db93525d91938d8e5b291142ce9c3a6f..732a3b07eec0b42792f5155226f967e072c25464 100644 (file)
@@ -7,6 +7,7 @@ package net
 import (
        "context"
        "errors"
+       "net/netip"
        "os"
        "syscall"
 )
@@ -28,8 +29,27 @@ func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
        return n, addr, nil
 }
 
-func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-       return 0, 0, 0, nil, syscall.EPLAN9
+func (c *UDPConn) readFromAddrPort(b []byte) (int, netip.AddrPort, error) {
+       // TODO: optimize. The equivalent code on posix is alloc-free.
+       buf := make([]byte, udpHeaderSize+len(b))
+       m, err := c.fd.Read(buf)
+       if err != nil {
+               return 0, netip.AddrPort{}, err
+       }
+       if m < udpHeaderSize {
+               return 0, netip.AddrPort{}, errors.New("short read reading UDP header")
+       }
+       buf = buf[:m]
+
+       h, buf := unmarshalUDPHeader(buf)
+       n := copy(b, buf)
+       ip, _ := netip.AddrFromSlice(h.raddr)
+       addr := netip.AddrPortFrom(ip, h.rport)
+       return n, addr, nil
+}
+
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
+       return 0, 0, 0, netip.AddrPort{}, syscall.EPLAN9
 }
 
 func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
@@ -52,10 +72,18 @@ func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
        return len(b), nil
 }
 
+func (c *UDPConn) writeToAddrPort(b []byte, addr netip.AddrPort) (int, error) {
+       return c.writeTo(b, UDPAddrFromAddrPort(addr)) // TODO: optimize instead of allocating
+}
+
 func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
        return 0, 0, syscall.EPLAN9
 }
 
+func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) {
+       return 0, 0, syscall.EPLAN9
+}
+
 func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
        fd, err := dialPlan9(ctx, sd.network, laddr, raddr)
        if err != nil {
index 96fb373ce770ca91a8a8dc0eec2f1712ca381ed1..654439767378a86bcb73ddd959eec7a57e4948c1 100644 (file)
@@ -3,12 +3,12 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
 import (
        "context"
+       "net/netip"
        "syscall"
 )
 
@@ -44,27 +44,68 @@ func (a *UDPAddr) toLocal(net string) sockaddr {
 }
 
 func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
-       n, sa, err := c.fd.readFrom(b)
-       switch sa := sa.(type) {
-       case *syscall.SockaddrInet4:
-               *addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
-       case *syscall.SockaddrInet6:
-               *addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
-       default:
+       var n int
+       var err error
+       switch c.fd.family {
+       case syscall.AF_INET:
+               var from syscall.SockaddrInet4
+               n, err = c.fd.readFromInet4(b, &from)
+               if err == nil {
+                       ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes
+                       *addr = UDPAddr{IP: ip[:], Port: from.Port}
+               }
+       case syscall.AF_INET6:
+               var from syscall.SockaddrInet6
+               n, err = c.fd.readFromInet6(b, &from)
+               if err == nil {
+                       ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes
+                       *addr = UDPAddr{IP: ip[:], Port: from.Port, Zone: zoneCache.name(int(from.ZoneId))}
+               }
+       }
+       if err != nil {
                // No sockaddr, so don't return UDPAddr.
                addr = nil
        }
        return n, addr, err
 }
 
-func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-       var sa syscall.Sockaddr
-       n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
-       switch sa := sa.(type) {
-       case *syscall.SockaddrInet4:
-               addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
-       case *syscall.SockaddrInet6:
-               addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
+func (c *UDPConn) readFromAddrPort(b []byte) (n int, addr netip.AddrPort, err error) {
+       var ip netip.Addr
+       var port int
+       switch c.fd.family {
+       case syscall.AF_INET:
+               var from syscall.SockaddrInet4
+               n, err = c.fd.readFromInet4(b, &from)
+               if err == nil {
+                       ip = netip.AddrFrom4(from.Addr)
+                       port = from.Port
+               }
+       case syscall.AF_INET6:
+               var from syscall.SockaddrInet6
+               n, err = c.fd.readFromInet6(b, &from)
+               if err == nil {
+                       ip = netip.AddrFrom16(from.Addr).WithZone(zoneCache.name(int(from.ZoneId)))
+                       port = from.Port
+               }
+       }
+       if err == nil {
+               addr = netip.AddrPortFrom(ip, uint16(port))
+       }
+       return n, addr, err
+}
+
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
+       switch c.fd.family {
+       case syscall.AF_INET:
+               var sa syscall.SockaddrInet4
+               n, oobn, flags, err = c.fd.readMsgInet4(b, oob, 0, &sa)
+               ip := netip.AddrFrom4(sa.Addr)
+               addr = netip.AddrPortFrom(ip, uint16(sa.Port))
+       case syscall.AF_INET6:
+               var sa syscall.SockaddrInet6
+               n, oobn, flags, err = c.fd.readMsgInet6(b, oob, 0, &sa)
+               ip := netip.AddrFrom16(sa.Addr).WithZone(zoneCache.name(int(sa.ZoneId)))
+               addr = netip.AddrPortFrom(ip, uint16(sa.Port))
        }
        return
 }
@@ -76,11 +117,49 @@ func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
        if addr == nil {
                return 0, errMissingAddress
        }
-       sa, err := addr.sockaddr(c.fd.family)
-       if err != nil {
-               return 0, err
+
+       switch c.fd.family {
+       case syscall.AF_INET:
+               sa, err := ipToSockaddrInet4(addr.IP, addr.Port)
+               if err != nil {
+                       return 0, err
+               }
+               return c.fd.writeToInet4(b, &sa)
+       case syscall.AF_INET6:
+               sa, err := ipToSockaddrInet6(addr.IP, addr.Port, addr.Zone)
+               if err != nil {
+                       return 0, err
+               }
+               return c.fd.writeToInet6(b, &sa)
+       default:
+               return 0, &AddrError{Err: "invalid address family", Addr: addr.IP.String()}
+       }
+}
+
+func (c *UDPConn) writeToAddrPort(b []byte, addr netip.AddrPort) (int, error) {
+       if c.fd.isConnected {
+               return 0, ErrWriteToConnected
+       }
+       if !addr.IsValid() {
+               return 0, errMissingAddress
+       }
+
+       switch c.fd.family {
+       case syscall.AF_INET:
+               sa, err := addrPortToSockaddrInet4(addr)
+               if err != nil {
+                       return 0, err
+               }
+               return c.fd.writeToInet4(b, &sa)
+       case syscall.AF_INET6:
+               sa, err := addrPortToSockaddrInet6(addr)
+               if err != nil {
+                       return 0, err
+               }
+               return c.fd.writeToInet6(b, &sa)
+       default:
+               return 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()}
        }
-       return c.fd.writeTo(b, sa)
 }
 
 func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
@@ -97,6 +176,32 @@ func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error
        return c.fd.writeMsg(b, oob, sa)
 }
 
+func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn int, err error) {
+       if c.fd.isConnected && addr.IsValid() {
+               return 0, 0, ErrWriteToConnected
+       }
+       if !c.fd.isConnected && !addr.IsValid() {
+               return 0, 0, errMissingAddress
+       }
+
+       switch c.fd.family {
+       case syscall.AF_INET:
+               sa, err := addrPortToSockaddrInet4(addr)
+               if err != nil {
+                       return 0, 0, err
+               }
+               return c.fd.writeMsgInet4(b, oob, &sa)
+       case syscall.AF_INET6:
+               sa, err := addrPortToSockaddrInet6(addr)
+               if err != nil {
+                       return 0, 0, err
+               }
+               return c.fd.writeMsgInet6(b, oob, &sa)
+       default:
+               return 0, 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()}
+       }
+}
+
 func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
        fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_DGRAM, 0, "dial", sd.Dialer.Control)
        if err != nil {
index 0e8c3511c36e459258d617d7217b81d1b8ed6a3c..518c66c33147a3b5944fd35ee6bf46575eb4fd8c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
@@ -475,11 +474,87 @@ func TestUDPReadTimeout(t *testing.T) {
        }
 }
 
+func TestAllocs(t *testing.T) {
+       conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer conn.Close()
+       addr := conn.LocalAddr()
+       addrPort := addr.(*UDPAddr).AddrPort()
+       buf := make([]byte, 8)
+
+       allocs := testing.AllocsPerRun(1000, func() {
+               _, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addrPort)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               _, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
+               if err != nil {
+                       t.Fatal(err)
+               }
+       })
+       if got := int(allocs); got != 0 {
+               t.Errorf("WriteMsgUDPAddrPort/ReadMsgUDPAddrPort allocated %d objects", got)
+       }
+
+       allocs = testing.AllocsPerRun(1000, func() {
+               _, err := conn.WriteToUDPAddrPort(buf, addrPort)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               _, _, err = conn.ReadFromUDPAddrPort(buf)
+               if err != nil {
+                       t.Fatal(err)
+               }
+       })
+       if got := int(allocs); got != 0 {
+               t.Errorf("WriteToUDPAddrPort/ReadFromUDPAddrPort allocated %d objects", got)
+       }
+
+       allocs = testing.AllocsPerRun(1000, func() {
+               _, err := conn.WriteTo(buf, addr)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               _, _, err = conn.ReadFromUDP(buf)
+               if err != nil {
+                       t.Fatal(err)
+               }
+       })
+       if got := int(allocs); got != 1 {
+               t.Errorf("WriteTo/ReadFromUDP allocated %d objects", got)
+       }
+}
+
+func BenchmarkReadWriteMsgUDPAddrPort(b *testing.B) {
+       conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
+       if err != nil {
+               b.Fatal(err)
+       }
+       defer conn.Close()
+       addr := conn.LocalAddr().(*UDPAddr).AddrPort()
+       buf := make([]byte, 8)
+       b.ResetTimer()
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               _, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addr)
+               if err != nil {
+                       b.Fatal(err)
+               }
+               _, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
 func BenchmarkWriteToReadFromUDP(b *testing.B) {
        conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
        if err != nil {
                b.Fatal(err)
        }
+       defer conn.Close()
        addr := conn.LocalAddr()
        buf := make([]byte, 8)
        b.ResetTimer()
@@ -495,3 +570,25 @@ func BenchmarkWriteToReadFromUDP(b *testing.B) {
                }
        }
 }
+
+func BenchmarkWriteToReadFromUDPAddrPort(b *testing.B) {
+       conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
+       if err != nil {
+               b.Fatal(err)
+       }
+       defer conn.Close()
+       addr := conn.LocalAddr().(*UDPAddr).AddrPort()
+       buf := make([]byte, 8)
+       b.ResetTimer()
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               _, err := conn.WriteToUDPAddrPort(buf, addr)
+               if err != nil {
+                       b.Fatal(err)
+               }
+               _, _, err = conn.ReadFromUDPAddrPort(buf)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
index 99a89c827b8abbebf361141c42458e6c0c6c55f9..1b69df53bfd3256088bf9f8acfcd39d02dc6dbe1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package net
 
index 716484cc6ce95704e6d817018f41387045a0c063..fa4fd7d9331f422bdad34e3efbb24786df5739f3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || freebsd || solaris
-// +build aix darwin freebsd solaris
 
 package net
 
index bb851b89c05bd395150e9cee60b272f2f882a076..6b0de875ad5c3f1cca2d50c84c7af60c5f23087f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || linux || netbsd || openbsd
-// +build dragonfly linux netbsd openbsd
 
 package net
 
index 329076183aece9894ee1e539bbdb0db5cd9a2cfc..b3d19fe73dda2891f8261d691a82e9f29eba80b8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (js && wasm) || windows
-// +build js,wasm windows
 
 package net
 
index a4d2fca69cefde72dc464f67c7f6008be73ea445..c3bfbf9af2f1f867509a1ad5e8130b16de8480ae 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index 71092e88fb600f98f0b1f642d7e121475d0985f6..a75578235f8e7c147fe27988ae1003253dd10d38 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9 && !windows
-// +build !js,!plan9,!windows
 
 package net
 
index 29244f64710337f97c79068fe0c965da2d388211..dedd761c56744657ba5678e99c002337047f0254 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package net
 
index 476132a1c93aa0306de9469531c2664b20d8625c..87b6e74a856449327022571b4dbf9901a7046238 100644 (file)
@@ -12,6 +12,46 @@ import (
        "strings"
 )
 
+func ExamplePathEscape() {
+       path := url.PathEscape("my/cool+blog&about,stuff")
+       fmt.Println(path)
+
+       // Output:
+       // my%2Fcool+blog&about%2Cstuff
+}
+
+func ExamplePathUnescape() {
+       escapedPath := "my%2Fcool+blog&about%2Cstuff"
+       path, err := url.PathUnescape(escapedPath)
+       if err != nil {
+               log.Fatal(err)
+       }
+       fmt.Println(path)
+
+       // Output:
+       // my/cool+blog&about,stuff
+}
+
+func ExampleQueryEscape() {
+       query := url.QueryEscape("my/cool+blog&about,stuff")
+       fmt.Println(query)
+
+       // Output:
+       // my%2Fcool%2Bblog%26about%2Cstuff
+}
+
+func ExampleQueryUnescape() {
+       escapedQuery := "my%2Fcool%2Bblog%26about%2Cstuff"
+       query, err := url.QueryUnescape(escapedQuery)
+       if err != nil {
+               log.Fatal(err)
+       }
+       fmt.Println(query)
+
+       // Output:
+       // my/cool+blog&about,stuff
+}
+
 func ExampleValues() {
        v := url.Values{}
        v.Set("name", "Ava")
@@ -28,6 +68,84 @@ func ExampleValues() {
        // [Jess Sarah Zoe]
 }
 
+func ExampleValues_Add() {
+       v := url.Values{}
+       v.Add("cat sounds", "meow")
+       v.Add("cat sounds", "mew")
+       v.Add("cat sounds", "mau")
+       fmt.Println(v["cat sounds"])
+
+       // Output:
+       // [meow mew mau]
+}
+
+func ExampleValues_Del() {
+       v := url.Values{}
+       v.Add("cat sounds", "meow")
+       v.Add("cat sounds", "mew")
+       v.Add("cat sounds", "mau")
+       fmt.Println(v["cat sounds"])
+
+       v.Del("cat sounds")
+       fmt.Println(v["cat sounds"])
+
+       // Output:
+       // [meow mew mau]
+       // []
+}
+
+func ExampleValues_Encode() {
+       v := url.Values{}
+       v.Add("cat sounds", "meow")
+       v.Add("cat sounds", "mew/")
+       v.Add("cat sounds", "mau$")
+       fmt.Println(v.Encode())
+
+       // Output:
+       // cat+sounds=meow&cat+sounds=mew%2F&cat+sounds=mau%24
+}
+
+func ExampleValues_Get() {
+       v := url.Values{}
+       v.Add("cat sounds", "meow")
+       v.Add("cat sounds", "mew")
+       v.Add("cat sounds", "mau")
+       fmt.Printf("%q\n", v.Get("cat sounds"))
+       fmt.Printf("%q\n", v.Get("dog sounds"))
+
+       // Output:
+       // "meow"
+       // ""
+}
+
+func ExampleValues_Has() {
+       v := url.Values{}
+       v.Add("cat sounds", "meow")
+       v.Add("cat sounds", "mew")
+       v.Add("cat sounds", "mau")
+       fmt.Println(v.Has("cat sounds"))
+       fmt.Println(v.Has("dog sounds"))
+
+       // Output:
+       // true
+       // false
+}
+
+func ExampleValues_Set() {
+       v := url.Values{}
+       v.Add("cat sounds", "meow")
+       v.Add("cat sounds", "mew")
+       v.Add("cat sounds", "mau")
+       fmt.Println(v["cat sounds"])
+
+       v.Set("cat sounds", "meow")
+       fmt.Println(v["cat sounds"])
+
+       // Output:
+       // [meow mew mau]
+       // [meow]
+}
+
 func ExampleURL() {
        u, err := url.Parse("http://bing.com/search?q=dotnet")
        if err != nil {
index 20de0f6f5178a1e9f4cb39ab7352973d44732bdf..f31aa08b5929db2880fd22ec735e2db3692cc222 100644 (file)
@@ -452,20 +452,6 @@ func getScheme(rawURL string) (scheme, path string, err error) {
        return "", rawURL, nil
 }
 
-// split slices s into two substrings separated by the first occurrence of
-// sep. If cutc is true then sep is excluded from the second substring.
-// If sep does not occur in s then s and the empty string is returned.
-func split(s string, sep byte, cutc bool) (string, string) {
-       i := strings.IndexByte(s, sep)
-       if i < 0 {
-               return s, ""
-       }
-       if cutc {
-               return s[:i], s[i+1:]
-       }
-       return s[:i], s[i:]
-}
-
 // Parse parses a raw url into a URL structure.
 //
 // The url may be relative (a path, without a host) or absolute
@@ -474,7 +460,7 @@ func split(s string, sep byte, cutc bool) (string, string) {
 // error, due to parsing ambiguities.
 func Parse(rawURL string) (*URL, error) {
        // Cut off #frag
-       u, frag := split(rawURL, '#', true)
+       u, frag, _ := strings.Cut(rawURL, "#")
        url, err := parse(u, false)
        if err != nil {
                return nil, &Error{"parse", u, err}
@@ -534,7 +520,7 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
                url.ForceQuery = true
                rest = rest[:len(rest)-1]
        } else {
-               rest, url.RawQuery = split(rest, '?', true)
+               rest, url.RawQuery, _ = strings.Cut(rest, "?")
        }
 
        if !strings.HasPrefix(rest, "/") {
@@ -553,9 +539,7 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
                // RFC 3986, §3.3:
                // In addition, a URI reference (Section 4.1) may be a relative-path reference,
                // in which case the first path segment cannot contain a colon (":") character.
-               colon := strings.Index(rest, ":")
-               slash := strings.Index(rest, "/")
-               if colon >= 0 && (slash < 0 || colon < slash) {
+               if segment, _, _ := strings.Cut(rest, "/"); strings.Contains(segment, ":") {
                        // First path segment has colon. Not allowed in relative URL.
                        return nil, errors.New("first path segment in URL cannot contain colon")
                }
@@ -563,7 +547,10 @@ func parse(rawURL string, viaRequest bool) (*URL, error) {
 
        if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
                var authority string
-               authority, rest = split(rest[2:], '/', false)
+               authority, rest = rest[2:], ""
+               if i := strings.Index(authority, "/"); i >= 0 {
+                       authority, rest = authority[:i], authority[i:]
+               }
                url.User, url.Host, err = parseAuthority(authority)
                if err != nil {
                        return nil, err
@@ -602,7 +589,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
                }
                user = User(userinfo)
        } else {
-               username, password := split(userinfo, ':', true)
+               username, password, _ := strings.Cut(userinfo, ":")
                if username, err = unescape(username, encodeUserPassword); err != nil {
                        return nil, "", err
                }
@@ -840,7 +827,7 @@ func (u *URL) String() string {
                        // it would be mistaken for a scheme name. Such a segment must be
                        // preceded by a dot-segment (e.g., "./this:that") to make a relative-
                        // path reference.
-                       if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 {
+                       if segment, _, _ := strings.Cut(path, "/"); strings.Contains(segment, ":") {
                                buf.WriteString("./")
                        }
                }
@@ -933,12 +920,8 @@ func ParseQuery(query string) (Values, error) {
 
 func parseQuery(m Values, query string) (err error) {
        for query != "" {
-               key := query
-               if i := strings.IndexAny(key, "&"); i >= 0 {
-                       key, query = key[:i], key[i+1:]
-               } else {
-                       query = ""
-               }
+               var key string
+               key, query, _ = strings.Cut(query, "&")
                if strings.Contains(key, ";") {
                        err = fmt.Errorf("invalid semicolon separator in query")
                        continue
@@ -946,10 +929,7 @@ func parseQuery(m Values, query string) (err error) {
                if key == "" {
                        continue
                }
-               value := ""
-               if i := strings.Index(key, "="); i >= 0 {
-                       key, value = key[:i], key[i+1:]
-               }
+               key, value, _ := strings.Cut(key, "=")
                key, err1 := QueryUnescape(key)
                if err1 != nil {
                        if err == nil {
@@ -1013,22 +993,16 @@ func resolvePath(base, ref string) string {
        }
 
        var (
-               last string
                elem string
-               i    int
                dst  strings.Builder
        )
        first := true
        remaining := full
        // We want to return a leading '/', so write it now.
        dst.WriteByte('/')
-       for i >= 0 {
-               i = strings.IndexByte(remaining, '/')
-               if i < 0 {
-                       last, elem, remaining = remaining, remaining, ""
-               } else {
-                       elem, remaining = remaining[:i], remaining[i+1:]
-               }
+       found := true
+       for found {
+               elem, remaining, found = strings.Cut(remaining, "/")
                if elem == "." {
                        first = false
                        // drop
@@ -1056,7 +1030,7 @@ func resolvePath(base, ref string) string {
                }
        }
 
-       if last == "." || last == ".." {
+       if elem == "." || elem == ".." {
                dst.WriteByte('/')
        }
 
@@ -1109,7 +1083,7 @@ func (u *URL) ResolveReference(ref *URL) *URL {
                url.Path = ""
                return &url
        }
-       if ref.Path == "" && ref.RawQuery == "" {
+       if ref.Path == "" && !ref.ForceQuery && ref.RawQuery == "" {
                url.RawQuery = u.RawQuery
                if ref.Fragment == "" {
                        url.Fragment = u.Fragment
index 63c8e695af765050f5bfa0c1db616d0cf905a7f9..7c807d7a38528853e7e2d59eaaa6771921199bf1 100644 (file)
@@ -1172,7 +1172,7 @@ var resolveReferenceTests = []struct {
        {"http://foo.com/bar/baz", "quux/./dotdot/../dotdot/../dot/./tail/..", "http://foo.com/bar/quux/dot/"},
 
        // Remove any dot-segments prior to forming the target URI.
-       // http://tools.ietf.org/html/rfc3986#section-5.2.4
+       // https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
        {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/baz"},
 
        // Triple dot isn't special
@@ -1192,7 +1192,7 @@ var resolveReferenceTests = []struct {
        {"http://foo.com/foo%2dbar/", "./baz-quux", "http://foo.com/foo%2dbar/baz-quux"},
 
        // RFC 3986: Normal Examples
-       // http://tools.ietf.org/html/rfc3986#section-5.4.1
+       // https://datatracker.ietf.org/doc/html/rfc3986#section-5.4.1
        {"http://a/b/c/d;p?q", "g:h", "g:h"},
        {"http://a/b/c/d;p?q", "g", "http://a/b/c/g"},
        {"http://a/b/c/d;p?q", "./g", "http://a/b/c/g"},
@@ -1218,7 +1218,7 @@ var resolveReferenceTests = []struct {
        {"http://a/b/c/d;p?q", "../../g", "http://a/g"},
 
        // RFC 3986: Abnormal Examples
-       // http://tools.ietf.org/html/rfc3986#section-5.4.2
+       // https://datatracker.ietf.org/doc/html/rfc3986#section-5.4.2
        {"http://a/b/c/d;p?q", "../../../g", "http://a/g"},
        {"http://a/b/c/d;p?q", "../../../../g", "http://a/g"},
        {"http://a/b/c/d;p?q", "/./g", "http://a/g"},
@@ -1244,6 +1244,9 @@ var resolveReferenceTests = []struct {
        {"https://a/b/c/d;p?q", "//g/d/e/f?y#s", "https://g/d/e/f?y#s"},
        {"https://a/b/c/d;p#s", "?y", "https://a/b/c/d;p?y"},
        {"https://a/b/c/d;p?q#s", "?y", "https://a/b/c/d;p?y"},
+
+       // Empty path and query but with ForceQuery (issue 46033).
+       {"https://a/b/c/d;p?q#s", "?", "https://a/b/c/d;p?"},
 }
 
 func TestResolveReference(t *testing.T) {
@@ -2059,12 +2062,3 @@ func BenchmarkPathUnescape(b *testing.B) {
                })
        }
 }
-
-var sink string
-
-func BenchmarkSplit(b *testing.B) {
-       url := "http://www.google.com/?q=go+language#foo%26bar"
-       for i := 0; i < b.N; i++ {
-               sink, sink = split(url, '#', true)
-       }
-}
index f79f2d0865d559ebb358430d32956ea65e95d858..23e8befa92dc9ece8265eab762a9033f815c7771 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
index bf40ca2023ac9e52902bf8514194a8c2852db0d1..b75229586208693cf1773a30b815810185968b82 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package net
 
index a0fedc2f99061df9424f712d55be2d65ec4c4bf9..51ab29dc312a170e9a14ff68db882af615f134a3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd illumos linux netbsd openbsd
 
 package net
 
index 5589c9c68256b0a09cdaae143526c3d475d7b486..4eeb9ab86ca3a177fb4aa81cfd0c16d65e37753a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os
 
index 0529dccd6f214325541430ab168839f6b45d1f43..0375e533726ef4f642465e6d686c64543382980e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 //
 //go:build ppc64 || s390x || mips || mips64
-// +build ppc64 s390x mips mips64
 
 package os
 
index 6be6020f534229330d7a5e8d8517503279c7335e..10643a804e03b0d8014f9ebca02b4413ec577617 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 //
 //go:build 386 || amd64 || arm || arm64 || ppc64le || mips64le || mipsle || riscv64 || wasm
-// +build 386 amd64 arm arm64 ppc64le mips64le mipsle riscv64 wasm
 
 package os
 
index d45e1deb833897b52ca82c0fac8e90426c1f5808..75225d85476f22b920e5faa0593b1cdfc5bd36b5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package os_test
 
index 580e915b73c3db1cf7a33005b143fee58f9ba62e..c8140461a4dd9fd2596c23a70a39456fe2ecb141 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9
-// +build !plan9
 
 package os
 
index 268b3a923ab1abc03563f18f7688b2d0042980b0..234f4eb6921fb5493946a8c676f0cb9b33095bf7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package os
 
index e45282a0fdb4778a934e5a0fd4c57ab89c09728d..81bccebedbba6edf814523779f5a4bcf3e05f07f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os_test
 
index aa0c14b7d46e36b295497ab1164ad3a7e2ab8729..86c8a985bb3359af155eb91604edb16af92cd11d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package os_test
 
index bc75d4dd66c9103ccf27df5729baa074d4fa0cdd..2beac55f89b67a31cdb654855ae84ce719b41076 100644 (file)
@@ -149,6 +149,8 @@ func (p *ProcessState) SystemTime() time.Duration {
 }
 
 // Exited reports whether the program has exited.
+// On Unix systems this reports true if the program exited due to calling exit,
+// but false if the program terminated due to a signal.
 func (p *ProcessState) Exited() bool {
        return p.exited()
 }
index 0c495755116f5254030d45284ea31515cadb8487..9551c22d6e468e9a569cdb2e08776a912ef2cbc7 100644 (file)
@@ -748,12 +748,11 @@ func dedupEnvCase(caseInsensitive bool, env []string) []string {
        out := make([]string, 0, len(env))
        saw := make(map[string]int, len(env)) // key => index into out
        for _, kv := range env {
-               eq := strings.Index(kv, "=")
-               if eq < 0 {
+               k, _, ok := strings.Cut(kv, "=")
+               if !ok {
                        out = append(out, kv)
                        continue
                }
-               k := kv[:eq]
                if caseInsensitive {
                        k = strings.ToLower(k)
                }
@@ -775,11 +774,10 @@ func addCriticalEnv(env []string) []string {
                return env
        }
        for _, kv := range env {
-               eq := strings.Index(kv, "=")
-               if eq < 0 {
+               k, _, ok := strings.Cut(kv, "=")
+               if !ok {
                        continue
                }
-               k := kv[:eq]
                if strings.EqualFold(k, "SYSTEMROOT") {
                        // We already have it.
                        return env
index 3cfa30ee72477ee3c89fa096656138ebe860834f..4a37c96e63a0ad66be60aff2e77a1a391a7c8f83 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && cgo
-// +build linux,cgo
 
 // On systems that use glibc, calling malloc can create a new arena,
 // and creating a new arena can read /sys/devices/system/cpu/online.
index 7b2c0c0c111b35edcb2c7639e6cd0a250db752bb..fd7fb42d36a4e92a67c94305f23ca2c68787ae8d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package exec_test
 
index d854e0de843d69eff3da155b0710812c412d068b..459ba39dff8f50a48b00d496289555f4a0e35ad6 100644 (file)
@@ -166,12 +166,10 @@ func TestCatGoodAndBadFile(t *testing.T) {
        if _, ok := err.(*exec.ExitError); !ok {
                t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err)
        }
-       s := string(bs)
-       sp := strings.SplitN(s, "\n", 2)
-       if len(sp) != 2 {
-               t.Fatalf("expected two lines from cat; got %q", s)
+       errLine, body, ok := strings.Cut(string(bs), "\n")
+       if !ok {
+               t.Fatalf("expected two lines from cat; got %q", bs)
        }
-       errLine, body := sp[0], sp[1]
        if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") {
                t.Errorf("expected stderr to complain about file; got %q", errLine)
        }
index 467c069e1ca48cb7fca9ea887d293cc210d44c1e..c20f35276c66fb6fc42809aa79aff4a970007cc5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9 && !windows
-// +build !plan9,!windows
 
 package exec
 
index fbccffec0e9c9735388ee01d5c6a2f3510e5a3a4..8e31e47190feaf374ed0b6163f49e5b289018903 100644 (file)
@@ -3,13 +3,13 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows
-// +build windows
 
 package exec_test
 
 import (
        "io"
        "os"
+       "os/exec"
        "strconv"
        "syscall"
        "testing"
@@ -41,3 +41,16 @@ func TestPipePassing(t *testing.T) {
                t.Error(err)
        }
 }
+
+func TestNoInheritHandles(t *testing.T) {
+       cmd := exec.Command("cmd", "/c exit 88")
+       cmd.SysProcAttr = &syscall.SysProcAttr{NoInheritHandles: true}
+       err := cmd.Run()
+       exitError, ok := err.(*exec.ExitError)
+       if !ok {
+               t.Fatalf("got error %v; want ExitError", err)
+       }
+       if exitError.ExitCode() != 88 {
+               t.Fatalf("got exit code %d; want 88", exitError.ExitCode())
+       }
+}
index 4eac25fe6f402177eb596ff6fe5637f57ef0cd3a..54ddc4d5b483bc6f0ef67bfb8ad2a8ded4e3bb8c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package exec
 
index d1d246accf18b4c3379f198295be295e70428338..38b9fc7c27fefb34399d27c95b4f2a70341ccafa 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package exec
 
index 9fded0eb0af37c501f2133ca8357825835dd3dbc..52e401e58016c10532c9b5960f073195b30f1525 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package exec
 
index a8c71831d8806e8e126162130ff118f5c1dd85b4..8aae5735c49caff3ca42c9c4a9b5a6ea94d11e97 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // This is a test program that verifies that it can read from
 // descriptor 3 and that no other descriptors are open.
index e8736f7c54eaab44bd1d1a812c1d7112077ac48a..07e2b36f622abd3fb68673b58dcdd5924ba45a3e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package os
 
index d1bbeb752987c597f40d9f03caf83860ededc304..250c5c6402e9573d70a60f24c96b059c749d187c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os
 
index f14b3519fbe759864fe6b824fd201f69b20b824c..fa332bf1ed840a6494b244e2c035b26bb43673e8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package os_test
 
index 625430ecfca1e53cb9af7fcc1c501eef286abcea..d6161bcb08bbecae79f716de1b53acc29ebe3ff2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || openbsd
-// +build aix openbsd
 
 package os
 
index ad7a4410dcdd03747b656befb5a12c5016535d49..8d8c83260f59ca6601be1499cedd522fd76b8fea 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package os
 
index 76ba0e6d085e5bac291c47374cd971c49d42e1ce..18348eab912aa0e440a5bb3c6cfd2e7bdc479fa4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux || netbsd || (js && wasm)
-// +build linux netbsd js,wasm
 
 package os
 
index 039448b5573a920b97a8f68f17e293cd41273aec..3c2aeacf7da53f82e43ed698596ac2c4018adf78 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd || dragonfly
-// +build freebsd dragonfly
 
 package os
 
index 10f8312831792c637f52b822c08b95ea541b304d..d4eb7a4fb146a9d1a678cef7afdc59d595bfa129 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os
 
index 007ed2912933bbcde5fe99d1d877f89c5d790586..de70927961314c2f4e50025482ac4c97cd243178 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd linux netbsd openbsd
 
 package os_test
 
index 211f2a1798aba3fbe87a285d3b30d2f04f051fda..0dc6da090879364b68dd9964dfa9ae0c2c32d613 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package os
 
index a2531b9656278cac8e3bd4155b83e4813415bf1a..a38db189548551cc00688ef291a2f4cd8f736426 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os
 
index 506f1fb0ee6071e513d96a6a9f21702e8f8afdfd..717330e86a2b7f46989a3a900d0ccea625422281 100644 (file)
@@ -115,20 +115,16 @@ func size(name string, t *testing.T) int64 {
        if err != nil {
                t.Fatal("open failed:", err)
        }
-       defer file.Close()
-       var buf [100]byte
-       len := 0
-       for {
-               n, e := file.Read(buf[0:])
-               len += n
-               if e == io.EOF {
-                       break
-               }
-               if e != nil {
-                       t.Fatal("read failed:", e)
+       defer func() {
+               if err := file.Close(); err != nil {
+                       t.Error(err)
                }
+       }()
+       n, err := io.Copy(io.Discard, file)
+       if err != nil {
+               t.Fatal(err)
        }
-       return int64(len)
+       return n
 }
 
 func equal(name1, name2 string) (r bool) {
@@ -1761,8 +1757,8 @@ func TestHostname(t *testing.T) {
        // and the /bin/hostname only returns the first component
        want := runBinHostname(t)
        if hostname != want {
-               i := strings.Index(hostname, ".")
-               if i < 0 || hostname[0:i] != want {
+               host, _, ok := strings.Cut(hostname, ".")
+               if !ok || host != want {
                        t.Errorf("Hostname() = %q, want %q", hostname, want)
                }
        }
index 9b4c0ab290bc072a73df89696b1f1c4d05c3ff29..3ec3dee24ba6f3374e8a5b6001c7d453d8240757 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os_test
 
index db383594920e97db5f3342d53c9b335d2a218dde..d1ffe2c1877bdc3f92b5069460b11b2b9cb73b70 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os
 
index bf6d081db5b83c9cfe8e47d392fba4db71fd4eaa..7eb1350d025347dd37ce09810511ae3f8d0d5511 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || netbsd || openbsd
-// +build dragonfly freebsd netbsd openbsd
 
 package os
 
index 71b8cb8e25be5706532908826dfb25d5e6b768ed..354b35cc462ee71632c38bbcc9e7aeae7d73374d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 package os
 
index 097b32e7eb33cf0414a28209c681b399449e07ba..554d62111a570b6c65feae24ba3737ea68d1bb27 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || (js && wasm) || (solaris && !illumos)
-// +build aix darwin js,wasm solaris,!illumos
 
 package os
 
index acd7b88e1d45d70d5f29e197699d72ddfc74e081..52f4e21e7c6616e95ccacfa72b8d52efcf91e945 100644 (file)
@@ -12,20 +12,7 @@ func Pipe() (r *File, w *File, err error) {
        var p [2]int
 
        e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC)
-       // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it
-       // might not be implemented.
-       if e == syscall.ENOSYS {
-               // See ../syscall/exec.go for description of lock.
-               syscall.ForkLock.RLock()
-               e = syscall.Pipe(p[0:])
-               if e != nil {
-                       syscall.ForkLock.RUnlock()
-                       return nil, nil, NewSyscallError("pipe", e)
-               }
-               syscall.CloseOnExec(p[0])
-               syscall.CloseOnExec(p[1])
-               syscall.ForkLock.RUnlock()
-       } else if e != nil {
+       if e != nil {
                return nil, nil, NewSyscallError("pipe2", e)
        }
 
index 41a1e9c78aa36542a892392b63ae136cfd3403be..ab6d1ce2b61f577d8ba8210537f9be9df402dc2d 100644 (file)
@@ -4,7 +4,6 @@
 
 // Test broken pipes on Unix systems.
 //go:build !plan9 && !js
-// +build !plan9,!js
 
 package os_test
 
index ffc598b0618987c1a9c5928c7de6896e11df63eb..14a495d9c0a59d66e2eff0f00633d0f007423404 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9
-// +build !plan9
 
 package os
 
index 8aebaf87a60760623531ffc402e12f0feeba3ab2..fd2038a2332a1688fc5061fc29132107edc5a27e 100644 (file)
@@ -4,7 +4,6 @@
 
 // Test use of raw connections.
 //go:build !plan9 && !js
-// +build !plan9,!js
 
 package os_test
 
index 826760f3df65cc290470e171032e16a62c57b013..8b7d5fb8f9e35c88dbce07825c73e97614c1a64d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !linux
-// +build !linux
 
 package os
 
index d04540bc63eb2ca8918021ae7faa854240b68f5d..da804c436f6978060ae975a79deace8af4572940 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package os
 
index 853e0eddfc8920478d2fd3f2f5735d845c88186b..a0332e8c3560e956a911f5bce45a736096cd6a5d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris
-// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
 
 package os
 
index 3f7795b8cf9558dfb4a1b0b573ae1eaee21cbc11..b279ee9491f6ca3aa726fb50b2df9ebcb9670911 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package signal_test
 
index 8d2eac71035f2274f6e4df918c14c3745a539dd8..537febba553c6916c49314465ea66739e32d5258 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (aix || darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo
-// +build aix darwin dragonfly freebsd linux,!android netbsd openbsd
-// +build cgo
 
 // Package pty is a simple pseudo-terminal package for Unix systems,
 // implemented by calling C functions via cgo.
index e1e4509e2a723b9ae4df542a485703a7fde79b82..67bad66e0b2fa2a838ee0a7c6f2de43762aca6ca 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo
-// +build darwin dragonfly freebsd linux,!android netbsd openbsd
-// +build cgo
 
 // Note that this test does not work on Solaris: issue #22849.
 // Don't run the test on Android because at least some versions of the
index 7abe1ec5a0a5954464b92dc79cb497bc6feeec04..f70f108442bb07eb72fcfabfbace0136bd321340 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package signal
 
index 649854b746c149e0dc2a9002f299b3b962a44e99..3e85d936f8a8c74e858f728bb46a24e85935475a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package signal
 
index 9e241c43acef2c7137898f082a160ccdba50a608..e2e5c4ae970d48d75068fd05bd2f4a7143d0e585 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package signal
 
index 3badf5ba575b24de3a77895dcee9e21a6e9ffc10..c3e9b5b5e53176fd443ee65176ce3a79ea1ae215 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package os
 
index 8c17805f71fc30622d193fbdf5dcfe0bbfb5e308..eb15db5453b785fd77b131bd8852de343bbe204d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package os
 
index ab23d8111d3b4e8bf8f2df3e21b84b59f9f87707..e71daf7c7494aba8c594fe6572dbbec70e04665d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm netbsd openbsd solaris
 
 package os
 
index 9979b43e8e69d011470c91da9e4521cfbe7fe9f5..9a87fbde92c2ba6837c1149ea6f9fcfb52860608 100644 (file)
@@ -3,14 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !dragonfly && !freebsd && (!js || !wasm) && !netbsd && !openbsd && !solaris
-// +build !aix
-// +build !darwin
-// +build !dragonfly
-// +build !freebsd
-// +build !js !wasm
-// +build !netbsd
-// +build !openbsd
-// +build !solaris
 
 package os
 
index 1e245eb53a2d947f2b0d48252a59099c5e947fcc..e272c245717cbbf9e8fb985e457b19e6bd34ea65 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || (js && wasm) || netbsd || openbsd
-// +build darwin dragonfly freebsd js,wasm netbsd openbsd
 
 package os
 
index 4d6a64e8ebeaec86baadf818747eab59e825b504..4fd0e2d7c7dd128fc2a07efa39b2c9651a52afe2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package os
 
index e316eaf06c4f768920bffc582e647d7d7e546f4d..5ff39780e5e8fa54914add0f05999955d279f6a3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package os
 
index 6d65e420f044ef5df3f606fb3b1aab93fbd57348..2ff58110d65bdf8eac448a14ddc0fc056a59093e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js && !plan9 && !windows
-// +build !js,!plan9,!windows
 
 package os_test
 
index e9b8b8ba3ac7af2de64026385ee26881f21d8277..105bb78765a337f808a6a5791774bf87723a9e67 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9
-// +build !windows,!plan9
 
 package os
 
diff --git a/src/os/user/cgo_listgroups_unix.go b/src/os/user/cgo_listgroups_unix.go
new file mode 100644 (file)
index 0000000..0d937da
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2016 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:build (dragonfly || darwin || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos)) && cgo && !osusergo
+
+package user
+
+import (
+       "fmt"
+       "strconv"
+       "unsafe"
+)
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+*/
+import "C"
+
+const maxGroups = 2048
+
+func listGroups(u *User) ([]string, error) {
+       ug, err := strconv.Atoi(u.Gid)
+       if err != nil {
+               return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
+       }
+       userGID := C.gid_t(ug)
+       nameC := make([]byte, len(u.Username)+1)
+       copy(nameC, u.Username)
+
+       n := C.int(256)
+       gidsC := make([]C.gid_t, n)
+       rv := getGroupList((*C.char)(unsafe.Pointer(&nameC[0])), userGID, &gidsC[0], &n)
+       if rv == -1 {
+               // Mac is the only Unix that does not set n properly when rv == -1, so
+               // we need to use different logic for Mac vs. the other OS's.
+               if err := groupRetry(u.Username, nameC, userGID, &gidsC, &n); err != nil {
+                       return nil, err
+               }
+       }
+       gidsC = gidsC[:n]
+       gids := make([]string, 0, n)
+       for _, g := range gidsC[:n] {
+               gids = append(gids, strconv.Itoa(int(g)))
+       }
+       return gids, nil
+}
index abc9e9ce6d617d8c79e58b20c4774424eccde2a2..523269086e68f8ab32ccf8d930be68c55ab60f98 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && cgo && !osusergo
-// +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris
-// +build cgo
-// +build !osusergo
 
 package user
 
@@ -125,9 +122,7 @@ func buildUser(pwd *C.struct_passwd) *User {
        // say: "It is expected to be a comma separated list of
        // personal data where the first item is the full name of the
        // user."
-       if i := strings.Index(u.Name, ","); i >= 0 {
-               u.Name = u.Name[:i]
-       }
+       u.Name, _, _ = strings.Cut(u.Name, ",")
        return u
 }
 
index 9ec32b3a7889694953d795b8c811fd5500478970..6d16aa20b30ec827cdc9837bd7b65896f254d525 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && cgo && !osusergo
-// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
-// +build cgo
-// +build !osusergo
 
 package user
 
index 23d12e3247624e94e73f3aba3650f989be4b0f6b..db6fb87e23fb99f02dd3e72e24696ef6b02c5fb1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo && !osusergo
-// +build cgo,!osusergo
 
 package user
 
index fd66961ccf716616648d8132413169672bc7e6da..104c2243df618cd7cedf33a663e9b3da37ec25b5 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (dragonfly || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos)) && cgo && !osusergo
-// +build dragonfly freebsd !android,linux netbsd openbsd solaris,!illumos
-// +build cgo
-// +build !osusergo
 
 package user
 
diff --git a/src/os/user/listgroups_aix.go b/src/os/user/listgroups_aix.go
deleted file mode 100644 (file)
index d2fdfdc..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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.
-
-//go:build cgo && !osusergo
-// +build cgo,!osusergo
-
-package user
-
-import "fmt"
-
-func listGroups(u *User) ([]string, error) {
-       return nil, fmt.Errorf("user: list groups for %s: not supported on AIX", u.Username)
-}
diff --git a/src/os/user/listgroups_illumos.go b/src/os/user/listgroups_illumos.go
deleted file mode 100644 (file)
index d25e033..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 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:build cgo && !osusergo
-// +build cgo,!osusergo
-
-// Even though this file requires no C, it is used to provide a
-// listGroup stub because all the other illumos calls work.  Otherwise,
-// this stub will conflict with the lookup_stubs.go fallback.
-
-package user
-
-import "fmt"
-
-func listGroups(u *User) ([]string, error) {
-       return nil, fmt.Errorf("user: list groups for %s: not supported on illumos", u.Username)
-}
diff --git a/src/os/user/listgroups_stub.go b/src/os/user/listgroups_stub.go
new file mode 100644 (file)
index 0000000..4cf808b
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2021 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:build android || (js && !wasm)
+
+package user
+
+import (
+       "errors"
+)
+
+func init() {
+       groupListImplemented = false
+}
+
+func listGroups(*User) ([]string, error) {
+       return nil, errors.New("user: list groups not implemented")
+}
index 38aa7653b054f6b2cb101b76865b4cc7aa75017d..fa2df4931c152e76144fcb30041947c8e3bc770e 100644 (file)
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2021 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:build (dragonfly || darwin || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos)) && cgo && !osusergo
-// +build dragonfly darwin freebsd !android,linux netbsd openbsd solaris,!illumos
-// +build cgo
-// +build !osusergo
+//go:build ((darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo)) || aix || illumos
 
 package user
 
 import (
+       "bufio"
+       "bytes"
+       "errors"
        "fmt"
+       "io"
+       "os"
        "strconv"
-       "unsafe"
 )
 
-/*
-#include <unistd.h>
-#include <sys/types.h>
-*/
-import "C"
+const groupFile = "/etc/group"
 
-const maxGroups = 2048
+var colon = []byte{':'}
 
-func listGroups(u *User) ([]string, error) {
-       ug, err := strconv.Atoi(u.Gid)
+func listGroupsFromReader(u *User, r io.Reader) ([]string, error) {
+       if u.Username == "" {
+               return nil, errors.New("user: list groups: empty username")
+       }
+       primaryGid, err := strconv.Atoi(u.Gid)
        if err != nil {
                return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
        }
-       userGID := C.gid_t(ug)
-       nameC := make([]byte, len(u.Username)+1)
-       copy(nameC, u.Username)
-
-       n := C.int(256)
-       gidsC := make([]C.gid_t, n)
-       rv := getGroupList((*C.char)(unsafe.Pointer(&nameC[0])), userGID, &gidsC[0], &n)
-       if rv == -1 {
-               // Mac is the only Unix that does not set n properly when rv == -1, so
-               // we need to use different logic for Mac vs. the other OS's.
-               if err := groupRetry(u.Username, nameC, userGID, &gidsC, &n); err != nil {
-                       return nil, err
+
+       userCommas := []byte("," + u.Username + ",")  // ,john,
+       userFirst := userCommas[1:]                   // john,
+       userLast := userCommas[:len(userCommas)-1]    // ,john
+       userOnly := userCommas[1 : len(userCommas)-1] // john
+
+       // Add primary Gid first.
+       groups := []string{u.Gid}
+
+       rd := bufio.NewReader(r)
+       done := false
+       for !done {
+               line, err := rd.ReadBytes('\n')
+               if err != nil {
+                       if err == io.EOF {
+                               done = true
+                       } else {
+                               return groups, err
+                       }
+               }
+
+               // Look for username in the list of users. If user is found,
+               // append the GID to the groups slice.
+
+               // There's no spec for /etc/passwd or /etc/group, but we try to follow
+               // the same rules as the glibc parser, which allows comments and blank
+               // space at the beginning of a line.
+               line = bytes.TrimSpace(line)
+               if len(line) == 0 || line[0] == '#' ||
+                       // If you search for a gid in a row where the group
+                       // name (the first field) starts with "+" or "-",
+                       // glibc fails to find the record, and so should we.
+                       line[0] == '+' || line[0] == '-' {
+                       continue
+               }
+
+               // Format of /etc/group is
+               //      groupname:password:GID:user_list
+               // for example
+               //      wheel:x:10:john,paul,jack
+               //      tcpdump:x:72:
+               listIdx := bytes.LastIndexByte(line, ':')
+               if listIdx == -1 || listIdx == len(line)-1 {
+                       // No commas, or empty group list.
+                       continue
+               }
+               if bytes.Count(line[:listIdx], colon) != 2 {
+                       // Incorrect number of colons.
+                       continue
                }
+               list := line[listIdx+1:]
+               // Check the list for user without splitting or copying.
+               if !(bytes.Equal(list, userOnly) || bytes.HasPrefix(list, userFirst) || bytes.HasSuffix(list, userLast) || bytes.Contains(list, userCommas)) {
+                       continue
+               }
+
+               // groupname:password:GID
+               parts := bytes.Split(line[:listIdx], colon)
+               if len(parts) != 3 || len(parts[0]) == 0 {
+                       continue
+               }
+               gid := string(parts[2])
+               // Make sure it's numeric and not the same as primary GID.
+               numGid, err := strconv.Atoi(gid)
+               if err != nil || numGid == primaryGid {
+                       continue
+               }
+
+               groups = append(groups, gid)
        }
-       gidsC = gidsC[:n]
-       gids := make([]string, 0, n)
-       for _, g := range gidsC[:n] {
-               gids = append(gids, strconv.Itoa(int(g)))
+
+       return groups, nil
+}
+
+func listGroups(u *User) ([]string, error) {
+       f, err := os.Open(groupFile)
+       if err != nil {
+               return nil, err
        }
-       return gids, nil
+       defer f.Close()
+
+       return listGroupsFromReader(u, f)
 }
diff --git a/src/os/user/listgroups_unix_test.go b/src/os/user/listgroups_unix_test.go
new file mode 100644 (file)
index 0000000..a9f79ec
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2021 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:build ((darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo)) || aix || illumos
+
+package user
+
+import (
+       "fmt"
+       "sort"
+       "strings"
+       "testing"
+)
+
+var testGroupFile = `# See the opendirectoryd(8) man page for additional
+# information about Open Directory.
+##
+nobody:*:-2:
+nogroup:*:-1:
+wheel:*:0:root
+emptyid:*::root
+invalidgid:*:notanumber:root
++plussign:*:20:root
+-minussign:*:21:root
+# Next line is invalid (empty group name)
+:*:22:root
+      
+daemon:*:1:root
+    indented:*:7:root
+# comment:*:4:found
+     # comment:*:4:found
+kmem:*:2:root
+manymembers:x:777:jill,jody,john,jack,jov,user777
+` + largeGroup()
+
+func largeGroup() (res string) {
+       var b strings.Builder
+       b.WriteString("largegroup:x:1000:user1")
+       for i := 2; i <= 7500; i++ {
+               fmt.Fprintf(&b, ",user%d", i)
+       }
+       return b.String()
+}
+
+var listGroupsTests = []struct {
+       // input
+       in   string
+       user string
+       gid  string
+       // output
+       gids []string
+       err  bool
+}{
+       {in: testGroupFile, user: "root", gid: "0", gids: []string{"0", "1", "2", "7"}},
+       {in: testGroupFile, user: "jill", gid: "33", gids: []string{"33", "777"}},
+       {in: testGroupFile, user: "jody", gid: "34", gids: []string{"34", "777"}},
+       {in: testGroupFile, user: "john", gid: "35", gids: []string{"35", "777"}},
+       {in: testGroupFile, user: "jov", gid: "37", gids: []string{"37", "777"}},
+       {in: testGroupFile, user: "user777", gid: "7", gids: []string{"7", "777", "1000"}},
+       {in: testGroupFile, user: "user1111", gid: "1111", gids: []string{"1111", "1000"}},
+       {in: testGroupFile, user: "user1000", gid: "1000", gids: []string{"1000"}},
+       {in: testGroupFile, user: "user7500", gid: "7500", gids: []string{"1000", "7500"}},
+       {in: testGroupFile, user: "no-such-user", gid: "2345", gids: []string{"2345"}},
+       {in: "", user: "no-such-user", gid: "2345", gids: []string{"2345"}},
+       // Error cases.
+       {in: "", user: "", gid: "2345", err: true},
+       {in: "", user: "joanna", gid: "bad", err: true},
+}
+
+func TestListGroups(t *testing.T) {
+       for _, tc := range listGroupsTests {
+               u := &User{Username: tc.user, Gid: tc.gid}
+               got, err := listGroupsFromReader(u, strings.NewReader(tc.in))
+               if tc.err {
+                       if err == nil {
+                               t.Errorf("listGroups(%q): got nil; want error", tc.user)
+                       }
+                       continue // no more checks
+               }
+               if err != nil {
+                       t.Errorf("listGroups(%q): got %v error, want nil", tc.user, err)
+                       continue // no more checks
+               }
+               checkSameIDs(t, got, tc.gids)
+       }
+}
+
+func checkSameIDs(t *testing.T, got, want []string) {
+       t.Helper()
+       if len(got) != len(want) {
+               t.Errorf("ID list mismatch: got %v; want %v", got, want)
+               return
+       }
+       sort.Strings(got)
+       sort.Strings(want)
+       mismatch := -1
+       for i, g := range want {
+               if got[i] != g {
+                       mismatch = i
+                       break
+               }
+       }
+       if mismatch != -1 {
+               t.Errorf("ID list mismatch (at index %d): got %v; want %v", mismatch, got, want)
+       }
+}
index 151aab49c203d7a0f75b418941819aa69ad634e1..0ae31fd8189bf200fb3bbd52c98838cc80b8db1e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build android
-// +build android
 
 package user
 
index 33ae3a6adf416c5d74523e5fba68b51c002e64c2..07939363e739c69440db6a81da8cf2625b7b3c3a 100644 (file)
@@ -18,7 +18,9 @@ const (
 )
 
 func init() {
+       userImplemented = false
        groupImplemented = false
+       groupListImplemented = false
 }
 
 func current() (*User, error) {
index c975a11964c11c83d7e6b721bc16a62ac00f14bf..ce1617d2507bdf24be8ccc3e82a521dd1297d58a 100644 (file)
@@ -3,22 +3,16 @@
 // license that can be found in the LICENSE file.
 
 //go:build (!cgo && !windows && !plan9) || android || (osusergo && !windows && !plan9)
-// +build !cgo,!windows,!plan9 android osusergo,!windows,!plan9
 
 package user
 
 import (
-       "errors"
        "fmt"
        "os"
        "runtime"
        "strconv"
 )
 
-func init() {
-       groupImplemented = false
-}
-
 func current() (*User, error) {
        uid := currentUID()
        // $USER and /etc/passwd may disagree; prefer the latter if we can get it.
@@ -64,13 +58,6 @@ func current() (*User, error) {
        return u, fmt.Errorf("user: Current requires cgo or %s set in environment", missing)
 }
 
-func listGroups(*User) ([]string, error) {
-       if runtime.GOOS == "android" || runtime.GOOS == "aix" {
-               return nil, fmt.Errorf("user: GroupIds not implemented on %s", runtime.GOOS)
-       }
-       return nil, errors.New("user: GroupIds requires cgo")
-}
-
 func currentUID() string {
        if id := os.Getuid(); id >= 0 {
                return strconv.Itoa(id)
index 97c611fad42fdf264af9bbef9259d10b5c2662a0..e25323fbadbcbc40ffb1306178365ddeb0f2d48b 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (aix || darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo)
-// +build aix darwin dragonfly freebsd js,wasm !android,linux netbsd openbsd solaris
-// +build !cgo osusergo
 
 package user
 
@@ -18,15 +16,8 @@ import (
        "strings"
 )
 
-const groupFile = "/etc/group"
 const userFile = "/etc/passwd"
 
-var colon = []byte{':'}
-
-func init() {
-       groupImplemented = false
-}
-
 // lineFunc returns a value, an error, or (nil, nil) to skip the row.
 type lineFunc func(line []byte) (v interface{}, err error)
 
@@ -181,9 +172,7 @@ func matchUserIndexValue(value string, idx int) lineFunc {
                // say: "It is expected to be a comma separated list of
                // personal data where the first item is the full name of the
                // user."
-               if i := strings.Index(u.Name, ","); i >= 0 {
-                       u.Name = u.Name[:i]
-               }
+               u.Name, _, _ = strings.Cut(u.Name, ",")
                return u, nil
        }
 }
index 060cfe186f5ced2d288611965300d1163bda5571..77917677fc1dc6c96fa8297f36497a4788b02312 100644 (file)
@@ -3,36 +3,15 @@
 // license that can be found in the LICENSE file.
 
 //go:build (aix || darwin || dragonfly || freebsd || (!android && linux) || netbsd || openbsd || solaris) && !cgo
-// +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris
-// +build !cgo
 
 package user
 
 import (
-       "fmt"
        "reflect"
        "strings"
        "testing"
 )
 
-var testGroupFile = `# See the opendirectoryd(8) man page for additional 
-# information about Open Directory.
-##
-nobody:*:-2:
-nogroup:*:-1:
-wheel:*:0:root
-emptyid:*::root
-invalidgid:*:notanumber:root
-+plussign:*:20:root
--minussign:*:21:root
-      
-daemon:*:1:root
-    indented:*:7:
-# comment:*:4:found
-     # comment:*:4:found
-kmem:*:2:root
-` + largeGroup()
-
 var groupTests = []struct {
        in   string
        name string
@@ -51,19 +30,10 @@ var groupTests = []struct {
        {testGroupFile, "indented", "7"},
        {testGroupFile, "# comment", ""},
        {testGroupFile, "largegroup", "1000"},
+       {testGroupFile, "manymembers", "777"},
        {"", "emptyfile", ""},
 }
 
-// Generate a proper "largegroup" entry for testGroupFile string
-func largeGroup() (res string) {
-       var b strings.Builder
-       b.WriteString("largegroup:x:1000:user1")
-       for i := 2; i <= 7500; i++ {
-               fmt.Fprintf(&b, ",user%d", i)
-       }
-       return b.String()
-}
-
 func TestFindGroupName(t *testing.T) {
        for _, tt := range groupTests {
                got, err := findGroupName(tt.name, strings.NewReader(tt.in))
index c1b8101c8629cb889efa0ca9208b3fae647cf853..0307d2ad6a12713e2e1339d92a5a0800adb621c0 100644 (file)
@@ -6,11 +6,13 @@
 Package user allows user account lookups by name or id.
 
 For most Unix systems, this package has two internal implementations of
-resolving user and group ids to names. One is written in pure Go and
-parses /etc/passwd and /etc/group. The other is cgo-based and relies on
-the standard C library (libc) routines such as getpwuid_r and getgrnam_r.
+resolving user and group ids to names, and listing supplementary group IDs.
+One is written in pure Go and parses /etc/passwd and /etc/group. The other
+is cgo-based and relies on the standard C library (libc) routines such as
+getpwuid_r, getgrnam_r, and getgrouplist.
 
-When cgo is available, cgo-based (libc-backed) code is used by default.
+When cgo is available, and the required routines are implemented in libc
+for a particular platform, cgo-based (libc-backed) code is used.
 This can be overridden by using osusergo build tag, which enforces
 the pure Go implementation.
 */
@@ -20,9 +22,12 @@ import (
        "strconv"
 )
 
+// These may be set to false in init() for a particular platform and/or
+// build flags to let the tests know to skip tests of some features.
 var (
-       userImplemented  = true // set to false by lookup_stubs.go's init
-       groupImplemented = true // set to false by lookup_stubs.go's init
+       userImplemented      = true
+       groupImplemented     = true
+       groupListImplemented = true
 )
 
 // User represents a user account.
index 49920317bed93b9c7c32baea3d4f809c2127f538..80251749a7d670e4306aa60abce77583b728cdba 100644 (file)
@@ -5,7 +5,6 @@
 package user
 
 import (
-       "runtime"
        "testing"
 )
 
@@ -56,10 +55,6 @@ func compare(t *testing.T, want, got *User) {
 func TestLookup(t *testing.T) {
        checkUser(t)
 
-       if runtime.GOOS == "plan9" {
-               t.Skipf("Lookup not implemented on %q", runtime.GOOS)
-       }
-
        want, err := Current()
        if err != nil {
                t.Fatalf("Current: %v", err)
@@ -77,10 +72,6 @@ func TestLookup(t *testing.T) {
 func TestLookupId(t *testing.T) {
        checkUser(t)
 
-       if runtime.GOOS == "plan9" {
-               t.Skipf("LookupId not implemented on %q", runtime.GOOS)
-       }
-
        want, err := Current()
        if err != nil {
                t.Fatalf("Current: %v", err)
@@ -127,14 +118,15 @@ func TestLookupGroup(t *testing.T) {
        }
 }
 
-func TestGroupIds(t *testing.T) {
-       checkGroup(t)
-       if runtime.GOOS == "aix" {
-               t.Skip("skipping GroupIds, see golang.org/issue/30563")
-       }
-       if runtime.GOOS == "illumos" {
-               t.Skip("skipping GroupIds, see golang.org/issue/14709")
+func checkGroupList(t *testing.T) {
+       t.Helper()
+       if !groupListImplemented {
+               t.Skip("user: group list not implemented; skipping test")
        }
+}
+
+func TestGroupIds(t *testing.T) {
+       checkGroupList(t)
        user, err := Current()
        if err != nil {
                t.Fatalf("Current(): %v", err)
index 9bb85da80262b01fef4ce289c3b597caf7e4ba8e..721b9f9f7e33233a07d3c965504d7fdc6f0c707b 100644 (file)
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build aix || darwin || (js && wasm) || openbsd || solaris
-// +build aix darwin js,wasm openbsd solaris
+// aix, darwin, js/wasm, openbsd and solaris don't implement
+// waitid/wait6. netbsd implements wait6, but that is causing test
+// failures, see issue #48789.
+
+//go:build aix || darwin || (js && wasm) || netbsd || openbsd || solaris
 
 package os
 
@@ -11,7 +14,9 @@ package os
 // succeed immediately, and reports whether it has done so.
 // It does not actually call p.Wait.
 // This version is used on systems that do not implement waitid,
-// or where we have not implemented it yet.
+// or where we have not implemented it yet. Note that this is racy:
+// a call to Process.Signal can in an extremely unlikely case send a
+// signal to the wrong process, see issue #13987.
 func (p *Process) blockUntilWaitable() (bool, error) {
        return false, nil
 }
index 45b370a802e8ae1ae14f76d138085e761d35c0b4..d395dac40b491b124a1756a190e320f170b0698d 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build dragonfly || freebsd || netbsd
-// +build dragonfly freebsd netbsd
+//go:build dragonfly || freebsd
 
 package os
 
index 44962c8534e086a6108f2489e5120f24602868fa..c0503b209c082ca4af3e2fce95da69c492e243e0 100644 (file)
@@ -6,7 +6,6 @@
 // waitid returns if the process is stopped, even when using WEXITED.
 
 //go:build linux
-// +build linux
 
 package os
 
index 4ce10095e67360e21f62352d7bce451e93cc69ae..b364cf0608de2b2464fc7562bb47f4b81a092582 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9
-// +build !windows,!plan9
 
 package filepath_test
 
index d72efcebe6130505a2c30f4ddeb081291a63b011..86146dba5be6cff43b7679779e90781b8cb32a7f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows && !plan9
-// +build !windows,!plan9
 
 package filepath_test
 
index bc5509b49cf1ab7e4820405a10a869d9b56edd61..55b27f1af88928df36c993dd28d500105676a35c 100644 (file)
@@ -791,6 +791,8 @@ var winisabstests = []IsAbsTest{
        {`c:a\b`, false},
        {`c:\a\b`, true},
        {`c:/a/b`, true},
+       {`\\host\share`, true},
+       {`\\host\share\`, true},
        {`\\host\share\foo`, true},
        {`//host/share/foo/bar`, true},
 }
index d4b6f967a3f785f8c6021a52117a4791c80c7b9e..dcf1d187e7ae927f2cc4ff0b22e724c12f45bb70 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package filepath
 
index 445c868e41460456469d1459d868352fdaa3e5c2..b4d8ac33010e753bf158f3c7f550995e52c7e5e1 100644 (file)
@@ -45,6 +45,10 @@ func IsAbs(path string) (b bool) {
        if l == 0 {
                return false
        }
+       // If the volume name starts with a double slash, this is a UNC path.
+       if isSlash(path[0]) && isSlash(path[1]) {
+               return true
+       }
        path = path[l:]
        if path == "" {
                return false
index 657945a81a3361797b7b4768b2fa8d721b0ccece..7bfe17e2fd1746dceec7951f60acf03d361d3db8 100644 (file)
@@ -1,5 +1,4 @@
 //go:build !windows
-// +build !windows
 
 package filepath
 
index aa85d4831ce84952aeb112d2a33f17b21caf0d11..5fff329fc50a5025ed5919705a20be0483c5f29a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (linux && cgo) || (darwin && cgo) || (freebsd && cgo)
-// +build linux,cgo darwin,cgo freebsd,cgo
 
 package plugin
 
index 67855bed4ba82a5d56949dc34b5c0b6fc47b0863..2e9492e7c657e66d5a4c8483902095d495ff0a13 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (!linux && !freebsd && !darwin) || !cgo
-// +build !linux,!freebsd,!darwin !cgo
 
 package plugin
 
index 4ce912132c911f27219fb6d0f7057aeb1e33a50e..8185095f8580bdc039d4b555b377f8bf4ae8d74d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !linux || (linux && !arm64)
-// +build !linux linux,!arm64
 
 package plugin_test
 
index 81fb4be60646b70cc0b7541beb82695d673a25e8..f795ec9b7b75f27976eea9ecec92144f627d8311 100755 (executable)
@@ -13,35 +13,16 @@ function usage {
        exit 1
 }
 
-case $(uname) in
-"Darwin")
-       if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "arm64" ]; then
-               usage
-       fi
-       ;;
-"Linux")
-       if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ] && [ $(uname -m) != "aarch64" ]; then
-               usage
-       fi
-       ;;
-"FreeBSD")
-       if [ $(uname -m) != "amd64" ]; then
-               usage
-       fi
-       ;;
-"NetBSD")
-       if [ $(uname -m) != "amd64" ]; then
-               usage
-       fi
-       ;;
-"OpenBSD")
-       if [ $(uname -m) != "amd64" ]; then
-               usage
-       fi
-       ;;
-*)
-       usage
-       ;;
+case $(uname -s -m) in
+  "Darwin x86_64") ;;
+  "Darwin arm64")  ;;
+  "Linux x86_64")  ;;
+  "Linux ppc64le") ;;
+  "Linux aarch64") ;;
+  "FreeBSD amd64") ;;
+  "NetBSD amd64")  ;;
+  "OpenBSD amd64") ;;
+  *) usage         ;;
 esac
 
 if [ ! -f make.bash ]; then
index 9ddde3ae57cfca4b49413efccb6c126d6902f40d..28204b81937fc3abbd464fd16657002cc1cd70c1 100644 (file)
@@ -198,7 +198,7 @@ func (a *abiSeq) addRcvr(rcvr *rtype) (*abiStep, bool) {
 // complete register-assignment algorithm for the Go ABI.
 func (a *abiSeq) regAssign(t *rtype, offset uintptr) bool {
        switch t.Kind() {
-       case UnsafePointer, Ptr, Chan, Map, Func:
+       case UnsafePointer, Pointer, Chan, Map, Func:
                return a.assignIntN(offset, t.size, 1, 0b1)
        case Bool, Int, Uint, Int8, Uint8, Int16, Uint16, Int32, Uint32, Uintptr:
                return a.assignIntN(offset, t.size, 1, 0b0)
@@ -467,3 +467,45 @@ func newAbiDesc(t *funcType, rcvr *rtype) abiDesc {
        out.stackBytes -= retOffset
        return abiDesc{in, out, stackCallArgsSize, retOffset, spill, stackPtrs, inRegPtrs, outRegPtrs}
 }
+
+// intFromReg loads an argSize sized integer from reg and places it at to.
+//
+// argSize must be non-zero, fit in a register, and a power-of-two.
+func intFromReg(r *abi.RegArgs, reg int, argSize uintptr, to unsafe.Pointer) {
+       memmove(to, r.IntRegArgAddr(reg, argSize), argSize)
+}
+
+// intToReg loads an argSize sized integer and stores it into reg.
+//
+// argSize must be non-zero, fit in a register, and a power-of-two.
+func intToReg(r *abi.RegArgs, reg int, argSize uintptr, from unsafe.Pointer) {
+       memmove(r.IntRegArgAddr(reg, argSize), from, argSize)
+}
+
+// floatFromReg loads a float value from its register representation in r.
+//
+// argSize must be 4 or 8.
+func floatFromReg(r *abi.RegArgs, reg int, argSize uintptr, to unsafe.Pointer) {
+       switch argSize {
+       case 4:
+               *(*float32)(to) = archFloat32FromReg(r.Floats[reg])
+       case 8:
+               *(*float64)(to) = *(*float64)(unsafe.Pointer(&r.Floats[reg]))
+       default:
+               panic("bad argSize")
+       }
+}
+
+// floatToReg stores a float value in its register representation in r.
+//
+// argSize must be either 4 or 8.
+func floatToReg(r *abi.RegArgs, reg int, argSize uintptr, from unsafe.Pointer) {
+       switch argSize {
+       case 4:
+               r.Floats[reg] = archFloat32ToReg(*(*float32)(from))
+       case 8:
+               r.Floats[reg] = *(*uint64)(from)
+       default:
+               panic("bad argSize")
+       }
+}
index 2b247d1d7986ff4a72156882b23c51b1f3d5e0bb..41cfd9d08235ac887695c4f16af205bbe370da2c 100644 (file)
@@ -3,12 +3,12 @@
 // license that can be found in the LICENSE file.
 
 //go:build goexperiment.regabireflect && goexperiment.regabiargs
-// +build goexperiment.regabireflect,goexperiment.regabiargs
 
 package reflect_test
 
 import (
        "internal/abi"
+       "math"
        "math/rand"
        "reflect"
        "runtime"
@@ -962,3 +962,27 @@ func genValue(t *testing.T, typ reflect.Type, r *rand.Rand) reflect.Value {
        }
        return v
 }
+
+func TestSignalingNaNArgument(t *testing.T) {
+       v := reflect.ValueOf(func(x float32) {
+               // make sure x is a signaling NaN.
+               u := math.Float32bits(x)
+               if u != snan {
+                       t.Fatalf("signaling NaN not correct: %x\n", u)
+               }
+       })
+       v.Call([]reflect.Value{reflect.ValueOf(math.Float32frombits(snan))})
+}
+
+func TestSignalingNaNReturn(t *testing.T) {
+       v := reflect.ValueOf(func() float32 {
+               return math.Float32frombits(snan)
+       })
+       var x float32
+       reflect.ValueOf(&x).Elem().Set(v.Call(nil)[0])
+       // make sure x is a signaling NaN.
+       u := math.Float32bits(x)
+       if u != snan {
+               t.Fatalf("signaling NaN not correct: %x\n", u)
+       }
+}
index 5e5e4c1e6040893688f9c19d18b6863483553ae2..acc09962a0bc933c14cf9b05924b7e36cd4d41db 100644 (file)
@@ -336,6 +336,115 @@ func TestSetValue(t *testing.T) {
        }
 }
 
+func TestMapIterSet(t *testing.T) {
+       m := make(map[string]interface{}, len(valueTests))
+       for _, tt := range valueTests {
+               m[tt.s] = tt.i
+       }
+       v := ValueOf(m)
+
+       k := New(v.Type().Key()).Elem()
+       e := New(v.Type().Elem()).Elem()
+
+       iter := v.MapRange()
+       for iter.Next() {
+               k.SetIterKey(iter)
+               e.SetIterValue(iter)
+               want := m[k.String()]
+               got := e.Interface()
+               if got != want {
+                       t.Errorf("%q: want (%T) %v, got (%T) %v", k.String(), want, want, got, got)
+               }
+               if setkey, key := valueToString(k), valueToString(iter.Key()); setkey != key {
+                       t.Errorf("MapIter.Key() = %q, MapIter.SetKey() = %q", key, setkey)
+               }
+               if setval, val := valueToString(e), valueToString(iter.Value()); setval != val {
+                       t.Errorf("MapIter.Value() = %q, MapIter.SetValue() = %q", val, setval)
+               }
+       }
+
+       got := int(testing.AllocsPerRun(10, func() {
+               iter := v.MapRange()
+               for iter.Next() {
+                       k.SetIterKey(iter)
+                       e.SetIterValue(iter)
+               }
+       }))
+       // Making a *MapIter allocates. This should be the only allocation.
+       if got != 1 {
+               t.Errorf("wanted 1 alloc, got %d", got)
+       }
+}
+
+func TestCanIntUintFloatComplex(t *testing.T) {
+       type integer int
+       type uinteger uint
+       type float float64
+       type complex complex128
+
+       var ops = [...]string{"CanInt", "CanUint", "CanFloat", "CanComplex"}
+
+       var testCases = []struct {
+               i    interface{}
+               want [4]bool
+       }{
+               // signed integer
+               {132, [...]bool{true, false, false, false}},
+               {int8(8), [...]bool{true, false, false, false}},
+               {int16(16), [...]bool{true, false, false, false}},
+               {int32(32), [...]bool{true, false, false, false}},
+               {int64(64), [...]bool{true, false, false, false}},
+               // unsigned integer
+               {uint(132), [...]bool{false, true, false, false}},
+               {uint8(8), [...]bool{false, true, false, false}},
+               {uint16(16), [...]bool{false, true, false, false}},
+               {uint32(32), [...]bool{false, true, false, false}},
+               {uint64(64), [...]bool{false, true, false, false}},
+               {uintptr(0xABCD), [...]bool{false, true, false, false}},
+               // floating-point
+               {float32(256.25), [...]bool{false, false, true, false}},
+               {float64(512.125), [...]bool{false, false, true, false}},
+               // complex
+               {complex64(532.125 + 10i), [...]bool{false, false, false, true}},
+               {complex128(564.25 + 1i), [...]bool{false, false, false, true}},
+               // underlying
+               {integer(-132), [...]bool{true, false, false, false}},
+               {uinteger(132), [...]bool{false, true, false, false}},
+               {float(256.25), [...]bool{false, false, true, false}},
+               {complex(532.125 + 10i), [...]bool{false, false, false, true}},
+               // not-acceptable
+               {"hello world", [...]bool{false, false, false, false}},
+               {new(int), [...]bool{false, false, false, false}},
+               {new(uint), [...]bool{false, false, false, false}},
+               {new(float64), [...]bool{false, false, false, false}},
+               {new(complex64), [...]bool{false, false, false, false}},
+               {new([5]int), [...]bool{false, false, false, false}},
+               {new(integer), [...]bool{false, false, false, false}},
+               {new(map[int]int), [...]bool{false, false, false, false}},
+               {new(chan<- int), [...]bool{false, false, false, false}},
+               {new(func(a int8)), [...]bool{false, false, false, false}},
+               {new(struct{ i int }), [...]bool{false, false, false, false}},
+       }
+
+       for i, tc := range testCases {
+               v := ValueOf(tc.i)
+               got := [...]bool{v.CanInt(), v.CanUint(), v.CanFloat(), v.CanComplex()}
+
+               for j := range tc.want {
+                       if got[j] != tc.want[j] {
+                               t.Errorf(
+                                       "#%d: v.%s() returned %t for type %T, want %t",
+                                       i,
+                                       ops[j],
+                                       got[j],
+                                       tc.i,
+                                       tc.want[j],
+                               )
+                       }
+               }
+       }
+}
+
 func TestCanSetField(t *testing.T) {
        type embed struct{ x, X int }
        type Embed struct{ x, X int }
@@ -437,7 +546,7 @@ func TestCanSetField(t *testing.T) {
                        for _, tc := range tt.cases {
                                f := tt.val
                                for _, i := range tc.index {
-                                       if f.Kind() == Ptr {
+                                       if f.Kind() == Pointer {
                                                f = f.Elem()
                                        }
                                        if i == -1 {
@@ -865,6 +974,9 @@ var deepEqualTests = []DeepEqualTest{
        {error(nil), error(nil), true},
        {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
        {fn1, fn2, true},
+       {[]byte{1, 2, 3}, []byte{1, 2, 3}, true},
+       {[]MyByte{1, 2, 3}, []MyByte{1, 2, 3}, true},
+       {MyBytes{1, 2, 3}, MyBytes{1, 2, 3}, true},
 
        // Inequalities
        {1, 2, false},
@@ -885,6 +997,9 @@ var deepEqualTests = []DeepEqualTest{
        {fn1, fn3, false},
        {fn3, fn3, false},
        {[][]int{{1}}, [][]int{{2}}, false},
+       {&structWithSelfPtr{p: &structWithSelfPtr{s: "a"}}, &structWithSelfPtr{p: &structWithSelfPtr{s: "b"}}, false},
+
+       // Fun with floating point.
        {math.NaN(), math.NaN(), false},
        {&[1]float64{math.NaN()}, &[1]float64{math.NaN()}, false},
        {&[1]float64{math.NaN()}, self{}, true},
@@ -892,7 +1007,6 @@ 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},
@@ -910,6 +1024,9 @@ var deepEqualTests = []DeepEqualTest{
        {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
        {Basic{1, 0.5}, NotBasic{1, 0.5}, false},
        {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+       {[]byte{1, 2, 3}, []MyByte{1, 2, 3}, false},
+       {[]MyByte{1, 2, 3}, MyBytes{1, 2, 3}, false},
+       {[]byte{1, 2, 3}, MyBytes{1, 2, 3}, false},
 
        // Possible loops.
        {&loop1, &loop1, true},
@@ -1009,6 +1126,82 @@ func TestDeepEqualUnexportedMap(t *testing.T) {
        }
 }
 
+var deepEqualPerfTests = []struct {
+       x, y interface{}
+}{
+       {x: int8(99), y: int8(99)},
+       {x: []int8{99}, y: []int8{99}},
+       {x: int16(99), y: int16(99)},
+       {x: []int16{99}, y: []int16{99}},
+       {x: int32(99), y: int32(99)},
+       {x: []int32{99}, y: []int32{99}},
+       {x: int64(99), y: int64(99)},
+       {x: []int64{99}, y: []int64{99}},
+       {x: int(999999), y: int(999999)},
+       {x: []int{999999}, y: []int{999999}},
+
+       {x: uint8(99), y: uint8(99)},
+       {x: []uint8{99}, y: []uint8{99}},
+       {x: uint16(99), y: uint16(99)},
+       {x: []uint16{99}, y: []uint16{99}},
+       {x: uint32(99), y: uint32(99)},
+       {x: []uint32{99}, y: []uint32{99}},
+       {x: uint64(99), y: uint64(99)},
+       {x: []uint64{99}, y: []uint64{99}},
+       {x: uint(999999), y: uint(999999)},
+       {x: []uint{999999}, y: []uint{999999}},
+       {x: uintptr(999999), y: uintptr(999999)},
+       {x: []uintptr{999999}, y: []uintptr{999999}},
+
+       {x: float32(1.414), y: float32(1.414)},
+       {x: []float32{1.414}, y: []float32{1.414}},
+       {x: float64(1.414), y: float64(1.414)},
+       {x: []float64{1.414}, y: []float64{1.414}},
+
+       {x: complex64(1.414), y: complex64(1.414)},
+       {x: []complex64{1.414}, y: []complex64{1.414}},
+       {x: complex128(1.414), y: complex128(1.414)},
+       {x: []complex128{1.414}, y: []complex128{1.414}},
+
+       {x: true, y: true},
+       {x: []bool{true}, y: []bool{true}},
+
+       {x: "abcdef", y: "abcdef"},
+       {x: []string{"abcdef"}, y: []string{"abcdef"}},
+
+       {x: []byte("abcdef"), y: []byte("abcdef")},
+       {x: [][]byte{[]byte("abcdef")}, y: [][]byte{[]byte("abcdef")}},
+
+       {x: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}, y: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}},
+       {x: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}, y: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}},
+}
+
+func TestDeepEqualAllocs(t *testing.T) {
+       for _, tt := range deepEqualPerfTests {
+               t.Run(ValueOf(tt.x).Type().String(), func(t *testing.T) {
+                       got := testing.AllocsPerRun(100, func() {
+                               if !DeepEqual(tt.x, tt.y) {
+                                       t.Errorf("DeepEqual(%v, %v)=false", tt.x, tt.y)
+                               }
+                       })
+                       if int(got) != 0 {
+                               t.Errorf("DeepEqual(%v, %v) allocated %d times", tt.x, tt.y, int(got))
+                       }
+               })
+       }
+}
+
+func BenchmarkDeepEqual(b *testing.B) {
+       for _, bb := range deepEqualPerfTests {
+               b.Run(ValueOf(bb.x).Type().String(), func(b *testing.B) {
+                       b.ReportAllocs()
+                       for i := 0; i < b.N; i++ {
+                               sink = DeepEqual(bb.x, bb.y)
+                       }
+               })
+       }
+}
+
 func check2ndField(x interface{}, offs uintptr, t *testing.T) {
        s := ValueOf(x)
        f := s.Type().Field(1)
@@ -1180,7 +1373,7 @@ func TestIsZero(t *testing.T) {
                {(map[string]string)(nil), true},
                {map[string]string{}, false},
                {make(map[string]string), false},
-               // Ptr
+               // Pointer
                {(*func())(nil), true},
                {(*int)(nil), true},
                {new(int), false},
@@ -2318,6 +2511,11 @@ func TestMethodValue(t *testing.T) {
        p := Point{3, 4}
        var i int64
 
+       // Check that method value have the same underlying code pointers.
+       if p1, p2 := ValueOf(Point{1, 1}).Method(1), ValueOf(Point{2, 2}).Method(1); p1.Pointer() != p2.Pointer() {
+               t.Errorf("methodValueCall mismatched: %v - %v", p1, p2)
+       }
+
        // Curried method of value.
        tfunc := TypeOf((func(int) int)(nil))
        v := ValueOf(p).Method(1)
@@ -3025,11 +3223,11 @@ func (*outer) M() {}
 
 func TestNestedMethods(t *testing.T) {
        typ := TypeOf((*outer)(nil))
-       if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() {
+       if typ.NumMethod() != 1 || typ.Method(0).Func.UnsafePointer() != ValueOf((*outer).M).UnsafePointer() {
                t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M)
                for i := 0; i < typ.NumMethod(); i++ {
                        m := typ.Method(i)
-                       t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
+                       t.Errorf("\t%d: %s %p\n", i, m.Name, m.Func.UnsafePointer())
                }
        }
 }
@@ -3068,11 +3266,11 @@ func (i *InnerInt) M() int {
 
 func TestEmbeddedMethods(t *testing.T) {
        typ := TypeOf((*OuterInt)(nil))
-       if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*OuterInt).M).Pointer() {
+       if typ.NumMethod() != 1 || typ.Method(0).Func.UnsafePointer() != ValueOf((*OuterInt).M).UnsafePointer() {
                t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
                for i := 0; i < typ.NumMethod(); i++ {
                        m := typ.Method(i)
-                       t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
+                       t.Errorf("\t%d: %s %p\n", i, m.Name, m.Func.UnsafePointer())
                }
        }
 
@@ -3115,20 +3313,20 @@ func TestPtrTo(t *testing.T) {
 
        typ := TypeOf(z)
        for i = 0; i < 100; i++ {
-               typ = PtrTo(typ)
+               typ = PointerTo(typ)
        }
        for i = 0; i < 100; i++ {
                typ = typ.Elem()
        }
        if typ != TypeOf(z) {
-               t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(z))
+               t.Errorf("after 100 PointerTo and Elem, have %s, want %s", typ, TypeOf(z))
        }
 }
 
 func TestPtrToGC(t *testing.T) {
        type T *uintptr
        tt := TypeOf(T(nil))
-       pt := PtrTo(tt)
+       pt := PointerTo(tt)
        const n = 100
        var x []interface{}
        for i := 0; i < n; i++ {
@@ -3162,11 +3360,11 @@ func BenchmarkPtrTo(b *testing.B) {
        }
        b.ResetTimer()
 
-       // Now benchmark calling PtrTo on it: we'll have to hit the ptrMap cache on
+       // Now benchmark calling PointerTo on it: we'll have to hit the ptrMap cache on
        // every call.
        b.RunParallel(func(pb *testing.PB) {
                for pb.Next() {
-                       PtrTo(t)
+                       PointerTo(t)
                }
        })
 }
@@ -3330,11 +3528,11 @@ func TestSlice(t *testing.T) {
 
        rv := ValueOf(&xs).Elem()
        rv = rv.Slice(3, 4)
-       ptr2 := rv.Pointer()
+       ptr2 := rv.UnsafePointer()
        rv = rv.Slice(5, 5)
-       ptr3 := rv.Pointer()
+       ptr3 := rv.UnsafePointer()
        if ptr3 != ptr2 {
-               t.Errorf("xs.Slice(3,4).Slice3(5,5).Pointer() = %#x, want %#x", ptr3, ptr2)
+               t.Errorf("xs.Slice(3,4).Slice3(5,5).UnsafePointer() = %p, want %p", ptr3, ptr2)
        }
 }
 
@@ -3377,11 +3575,11 @@ func TestSlice3(t *testing.T) {
 
        rv = ValueOf(&xs).Elem()
        rv = rv.Slice3(3, 5, 7)
-       ptr2 := rv.Pointer()
+       ptr2 := rv.UnsafePointer()
        rv = rv.Slice3(4, 4, 4)
-       ptr3 := rv.Pointer()
+       ptr3 := rv.UnsafePointer()
        if ptr3 != ptr2 {
-               t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).Pointer() = %#x, want %#x", ptr3, ptr2)
+               t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).UnsafePointer() = %p, want %p", ptr3, ptr2)
        }
 }
 
@@ -4388,8 +4586,17 @@ func TestConvertPanic(t *testing.T) {
 
 var gFloat32 float32
 
+const snan uint32 = 0x7f800001
+
 func TestConvertNaNs(t *testing.T) {
-       const snan uint32 = 0x7f800001
+       // Test to see if a store followed by a load of a signaling NaN
+       // maintains the signaling bit. (This used to fail on the 387 port.)
+       gFloat32 = math.Float32frombits(snan)
+       runtime.Gosched() // make sure we don't optimize the store/load away
+       if got := math.Float32bits(gFloat32); got != snan {
+               t.Errorf("store/load of sNaN not faithful, got %x want %x", got, snan)
+       }
+       // Test reflect's conversion between float32s. See issue 36400.
        type myFloat32 float32
        x := V(myFloat32(math.Float32frombits(snan)))
        y := x.Convert(TypeOf(float32(0)))
@@ -4689,7 +4896,7 @@ func TestArrayOfDirectIface(t *testing.T) {
                v1 := ValueOf(&i1).Elem()
                p1 := v1.InterfaceData()[1]
 
-               i2 := Zero(ArrayOf(1, PtrTo(TypeOf(int8(0))))).Interface()
+               i2 := Zero(ArrayOf(1, PointerTo(TypeOf(int8(0))))).Interface()
                v2 := ValueOf(&i2).Elem()
                p2 := v2.InterfaceData()[1]
 
@@ -4707,7 +4914,7 @@ func TestArrayOfDirectIface(t *testing.T) {
                v1 := ValueOf(&i1).Elem()
                p1 := v1.InterfaceData()[1]
 
-               i2 := Zero(ArrayOf(0, PtrTo(TypeOf(int8(0))))).Interface()
+               i2 := Zero(ArrayOf(0, PointerTo(TypeOf(int8(0))))).Interface()
                v2 := ValueOf(&i2).Elem()
                p2 := v2.InterfaceData()[1]
 
@@ -5408,7 +5615,7 @@ func TestStructOfWithInterface(t *testing.T) {
                },
                {
                        name: "StructI",
-                       typ:  PtrTo(TypeOf(StructI(want))),
+                       typ:  PointerTo(TypeOf(StructI(want))),
                        val: ValueOf(func() interface{} {
                                v := StructI(want)
                                return &v
@@ -5417,7 +5624,7 @@ func TestStructOfWithInterface(t *testing.T) {
                },
                {
                        name: "StructIPtr",
-                       typ:  PtrTo(TypeOf(StructIPtr(want))),
+                       typ:  PointerTo(TypeOf(StructIPtr(want))),
                        val: ValueOf(func() interface{} {
                                v := StructIPtr(want)
                                return &v
@@ -5506,7 +5713,7 @@ func TestStructOfWithInterface(t *testing.T) {
        fields := []StructField{{
                Name:      "StructIPtr",
                Anonymous: true,
-               Type:      PtrTo(TypeOf(StructIPtr(want))),
+               Type:      PointerTo(TypeOf(StructIPtr(want))),
        }}
        rt := StructOf(fields)
        rv := New(rt).Elem()
@@ -5520,7 +5727,7 @@ func TestStructOfWithInterface(t *testing.T) {
        fields = []StructField{{
                Name:      "SettableStruct",
                Anonymous: true,
-               Type:      PtrTo(TypeOf(SettableStruct{})),
+               Type:      PointerTo(TypeOf(SettableStruct{})),
        }}
        rt = StructOf(fields)
        rv = New(rt).Elem()
@@ -5536,7 +5743,7 @@ func TestStructOfWithInterface(t *testing.T) {
                {
                        Name:      "SettableStruct",
                        Anonymous: true,
-                       Type:      PtrTo(TypeOf(SettableStruct{})),
+                       Type:      PointerTo(TypeOf(SettableStruct{})),
                },
                {
                        Name:      "EmptyStruct",
@@ -6611,7 +6818,7 @@ func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
        // repeat a bitmap for a small array or executing a repeat in
        // a GC program.
        val := MakeSlice(typ, 0, cap)
-       data := NewAt(ArrayOf(cap, typ), unsafe.Pointer(val.Pointer()))
+       data := NewAt(ArrayOf(cap, typ), val.UnsafePointer())
        heapBits := GCBits(data.Interface())
        // Repeat the bitmap for the slice size, trimming scalars in
        // the last element.
@@ -6752,7 +6959,7 @@ func TestGCBits(t *testing.T) {
        verifyGCBits(t, MapOf(ArrayOf(10000, Tscalarptr), Tscalar), lit(1))
 
        verifyGCBits(t, TypeOf((*[10000]Xscalar)(nil)), lit(1))
-       verifyGCBits(t, PtrTo(ArrayOf(10000, Tscalar)), lit(1))
+       verifyGCBits(t, PointerTo(ArrayOf(10000, Tscalar)), lit(1))
 
        verifyGCBits(t, TypeOf(([][10000]Xscalar)(nil)), lit(1))
        verifyGCBits(t, SliceOf(ArrayOf(10000, Tscalar)), lit(1))
@@ -6821,7 +7028,7 @@ func TestTypeOfTypeOf(t *testing.T) {
        check("ChanOf", ChanOf(BothDir, TypeOf(T{})))
        check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false))
        check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{})))
-       check("PtrTo", PtrTo(TypeOf(T{})))
+       check("PtrTo", PointerTo(TypeOf(T{})))
        check("SliceOf", SliceOf(TypeOf(T{})))
 }
 
@@ -7001,6 +7208,53 @@ func BenchmarkNew(b *testing.B) {
        })
 }
 
+func BenchmarkMap(b *testing.B) {
+       type V *int
+       value := ValueOf((V)(nil))
+       stringKeys := []string{}
+       mapOfStrings := map[string]V{}
+       uint64Keys := []uint64{}
+       mapOfUint64s := map[uint64]V{}
+       for i := 0; i < 100; i++ {
+               stringKey := fmt.Sprintf("key%d", i)
+               stringKeys = append(stringKeys, stringKey)
+               mapOfStrings[stringKey] = nil
+
+               uint64Key := uint64(i)
+               uint64Keys = append(uint64Keys, uint64Key)
+               mapOfUint64s[uint64Key] = nil
+       }
+
+       tests := []struct {
+               label          string
+               m, keys, value Value
+       }{
+               {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
+               {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
+       }
+
+       for _, tt := range tests {
+               b.Run(tt.label, func(b *testing.B) {
+                       b.Run("MapIndex", func(b *testing.B) {
+                               b.ReportAllocs()
+                               for i := 0; i < b.N; i++ {
+                                       for j := tt.keys.Len() - 1; j >= 0; j-- {
+                                               tt.m.MapIndex(tt.keys.Index(j))
+                                       }
+                               }
+                       })
+                       b.Run("SetMapIndex", func(b *testing.B) {
+                               b.ReportAllocs()
+                               for i := 0; i < b.N; i++ {
+                                       for j := tt.keys.Len() - 1; j >= 0; j-- {
+                                               tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
 func TestSwapper(t *testing.T) {
        type I int
        var a, b, c I
@@ -7183,6 +7437,72 @@ func TestMapIterNilMap(t *testing.T) {
        }
 }
 
+func TestMapIterReset(t *testing.T) {
+       iter := new(MapIter)
+
+       // Use of zero iterator should panic.
+       func() {
+               defer func() { recover() }()
+               iter.Next()
+               t.Error("Next did not panic")
+       }()
+
+       // Reset to new Map should work.
+       m := map[string]int{"one": 1, "two": 2, "three": 3}
+       iter.Reset(ValueOf(m))
+       if got, want := iterateToString(iter), `[one: 1, three: 3, two: 2]`; got != want {
+               t.Errorf("iterator returned %s (after sorting), want %s", got, want)
+       }
+
+       // Reset to Zero value should work, but iterating over it should panic.
+       iter.Reset(Value{})
+       func() {
+               defer func() { recover() }()
+               iter.Next()
+               t.Error("Next did not panic")
+       }()
+
+       // Reset to a different Map with different types should work.
+       m2 := map[int]string{1: "one", 2: "two", 3: "three"}
+       iter.Reset(ValueOf(m2))
+       if got, want := iterateToString(iter), `[1: one, 2: two, 3: three]`; got != want {
+               t.Errorf("iterator returned %s (after sorting), want %s", got, want)
+       }
+
+       // Check that Reset, Next, and SetKey/SetValue play nicely together.
+       m3 := map[uint64]uint64{
+               1 << 0: 1 << 1,
+               1 << 1: 1 << 2,
+               1 << 2: 1 << 3,
+       }
+       kv := New(TypeOf(uint64(0))).Elem()
+       for i := 0; i < 5; i++ {
+               var seenk, seenv uint64
+               iter.Reset(ValueOf(m3))
+               for iter.Next() {
+                       kv.SetIterKey(iter)
+                       seenk ^= kv.Uint()
+                       kv.SetIterValue(iter)
+                       seenv ^= kv.Uint()
+               }
+               if seenk != 0b111 {
+                       t.Errorf("iteration yielded keys %b, want %b", seenk, 0b111)
+               }
+               if seenv != 0b1110 {
+                       t.Errorf("iteration yielded values %b, want %b", seenv, 0b1110)
+               }
+       }
+
+       // Reset should not allocate.
+       n := int(testing.AllocsPerRun(10, func() {
+               iter.Reset(ValueOf(m2))
+               iter.Reset(Value{})
+       }))
+       if n > 0 {
+               t.Errorf("MapIter.Reset allocated %d times", n)
+       }
+}
+
 func TestMapIterSafety(t *testing.T) {
        // Using a zero MapIter causes a panic, but not a crash.
        func() {
@@ -7248,6 +7568,16 @@ func TestMapIterNext(t *testing.T) {
        }
 }
 
+func BenchmarkMapIterNext(b *testing.B) {
+       m := ValueOf(map[string]int{"a": 0, "b": 1, "c": 2, "d": 3})
+       it := m.MapRange()
+       for i := 0; i < b.N; i++ {
+               for it.Next() {
+               }
+               it.Reset(m)
+       }
+}
+
 func TestMapIterDelete0(t *testing.T) {
        // Delete all elements before first iteration.
        m := map[string]int{"one": 1, "two": 2, "three": 3}
@@ -7296,4 +7626,122 @@ func TestConvertibleTo(t *testing.T) {
        if t1.ConvertibleTo(t2) {
                t.Fatalf("(%s).ConvertibleTo(%s) = true, want false", t1, t2)
        }
+
+       t3 := ValueOf([]example1.MyStruct{}).Type()
+       t4 := ValueOf([]example2.MyStruct{}).Type()
+
+       if t3.ConvertibleTo(t4) {
+               t.Fatalf("(%s).ConvertibleTo(%s) = true, want false", t3, t4)
+       }
+}
+
+func TestSetIter(t *testing.T) {
+       data := map[string]int{
+               "foo": 1,
+               "bar": 2,
+               "baz": 3,
+       }
+
+       m := ValueOf(data)
+       i := m.MapRange()
+       k := New(TypeOf("")).Elem()
+       v := New(TypeOf(0)).Elem()
+       shouldPanic("Value.SetIterKey called before Next", func() {
+               k.SetIterKey(i)
+       })
+       shouldPanic("Value.SetIterValue called before Next", func() {
+               v.SetIterValue(i)
+       })
+       data2 := map[string]int{}
+       for i.Next() {
+               k.SetIterKey(i)
+               v.SetIterValue(i)
+               data2[k.Interface().(string)] = v.Interface().(int)
+       }
+       if !DeepEqual(data, data2) {
+               t.Errorf("maps not equal, got %v want %v", data2, data)
+       }
+       shouldPanic("Value.SetIterKey called on exhausted iterator", func() {
+               k.SetIterKey(i)
+       })
+       shouldPanic("Value.SetIterValue called on exhausted iterator", func() {
+               v.SetIterValue(i)
+       })
+
+       i.Reset(m)
+       i.Next()
+       shouldPanic("Value.SetIterKey using unaddressable value", func() {
+               ValueOf("").SetIterKey(i)
+       })
+       shouldPanic("Value.SetIterValue using unaddressable value", func() {
+               ValueOf(0).SetIterValue(i)
+       })
+       shouldPanic("value of type string is not assignable to type int", func() {
+               New(TypeOf(0)).Elem().SetIterKey(i)
+       })
+       shouldPanic("value of type int is not assignable to type string", func() {
+               New(TypeOf("")).Elem().SetIterValue(i)
+       })
+
+       // Make sure assignment conversion works.
+       var x interface{}
+       y := ValueOf(&x).Elem()
+       y.SetIterKey(i)
+       if _, ok := data[x.(string)]; !ok {
+               t.Errorf("got key %s which is not in map", x)
+       }
+       y.SetIterValue(i)
+       if x.(int) < 1 || x.(int) > 3 {
+               t.Errorf("got value %d which is not in map", x)
+       }
+
+       // Try some key/value types which are direct interfaces.
+       a := 88
+       b := 99
+       pp := map[*int]*int{
+               &a: &b,
+       }
+       i = ValueOf(pp).MapRange()
+       i.Next()
+       y.SetIterKey(i)
+       if got := *y.Interface().(*int); got != a {
+               t.Errorf("pointer incorrect: got %d want %d", got, a)
+       }
+       y.SetIterValue(i)
+       if got := *y.Interface().(*int); got != b {
+               t.Errorf("pointer incorrect: got %d want %d", got, b)
+       }
+}
+
+//go:notinheap
+type nih struct{ x int }
+
+var global_nih = nih{x: 7}
+
+func TestNotInHeapDeref(t *testing.T) {
+       // See issue 48399.
+       v := ValueOf((*nih)(nil))
+       v.Elem()
+       shouldPanic("reflect: call of reflect.Value.Field on zero Value", func() { v.Elem().Field(0) })
+
+       v = ValueOf(&global_nih)
+       if got := v.Elem().Field(0).Int(); got != 7 {
+               t.Fatalf("got %d, want 7", got)
+       }
+
+       v = ValueOf((*nih)(unsafe.Pointer(new(int))))
+       shouldPanic("reflect: reflect.Value.Elem on an invalid notinheap pointer", func() { v.Elem() })
+       shouldPanic("reflect: reflect.Value.Pointer on an invalid notinheap pointer", func() { v.Pointer() })
+       shouldPanic("reflect: reflect.Value.UnsafePointer on an invalid notinheap pointer", func() { v.UnsafePointer() })
+}
+
+func TestMethodCallValueCodePtr(t *testing.T) {
+       m := ValueOf(Point{}).Method(1)
+       want := MethodValueCallCodePtr()
+       if got := uintptr(m.UnsafePointer()); got != want {
+               t.Errorf("methodValueCall code pointer mismatched, want: %v, got: %v", want, got)
+       }
+       if got := m.Pointer(); got != want {
+               t.Errorf("methodValueCall code pointer mismatched, want: %v, got: %v", want, got)
+       }
 }
index d955e4110f8b789afaa0a90a3b25457a607bdf40..1ccfb25b94141be9959852943f574696a89a7481 100644 (file)
@@ -9,34 +9,76 @@
 #include "funcdata.h"
 #include "asm_ppc64x.h"
 
+// The frames of each of the two functions below contain two locals, at offsets
+// that are known to the runtime.
+//
+// The first local is a bool called retValid with a whole pointer-word reserved
+// for it on the stack. The purpose of this word is so that the runtime knows
+// whether the stack-allocated return space contains valid values for stack
+// scanning.
+//
+// The second local is an abi.RegArgs value whose offset is also known to the
+// runtime, so that a stack map for it can be constructed, since it contains
+// pointers visible to the GC.
+
+#define LOCAL_RETVALID 32+FIXED_FRAME
+#define LOCAL_REGARGS 40+FIXED_FRAME
+
+// The frame size of the functions below is
+// 32 (args of callReflect) + 8 (bool + padding) + 296 (abi.RegArgs) = 336.
+
 // makeFuncStub is the code half of the function returned by MakeFunc.
 // See the comment on the declaration of makeFuncStub in makefunc.go
 // for more details.
 // No arg size here, runtime pulls arg map out of the func value.
-TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$336
        NO_LOCAL_POINTERS
-       MOVD    R11, FIXED_FRAME+0(R1)
-       MOVD    $argframe+0(FP), R3
-       MOVD    R3, FIXED_FRAME+8(R1)
-       MOVB    R0, FIXED_FRAME+32(R1)
-       ADD     $FIXED_FRAME+32, R1, R3
-       MOVD    R3, FIXED_FRAME+16(R1)
-       MOVD    R0, FIXED_FRAME+24(R1)
+       // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this
+       // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID.
+       ADD     $LOCAL_REGARGS, R1, R20
+       CALL    runtime·spillArgs(SB)
+       MOVD    R11, FIXED_FRAME+32(R1) // save R11
+       MOVD    R11, FIXED_FRAME+0(R1)  // arg for moveMakeFuncArgPtrs
+       MOVD    R20, FIXED_FRAME+8(R1)  // arg for local args
+       CALL    ·moveMakeFuncArgPtrs(SB)
+       MOVD    FIXED_FRAME+32(R1), R11 // restore R11 ctxt
+       MOVD    R11, FIXED_FRAME+0(R1)  // ctxt (arg0)
+       MOVD    $argframe+0(FP), R3     // save arg to callArg
+       MOVD    R3, FIXED_FRAME+8(R1)   // frame (arg1)
+       ADD     $LOCAL_RETVALID, R1, R3 // addr of return flag
+       MOVB    R0, (R3)                // clear flag
+       MOVD    R3, FIXED_FRAME+16(R1)  // addr retvalid (arg2)
+       ADD     $LOCAL_REGARGS, R1, R3
+       MOVD    R3, FIXED_FRAME+24(R1)  // abiregargs (arg3)
        BL      ·callReflect(SB)
+       ADD     $LOCAL_REGARGS, R1, R20 // set address of spill area
+       CALL    runtime·unspillArgs(SB)
        RET
 
 // methodValueCall is the code half of the function returned by makeMethodValue.
 // See the comment on the declaration of methodValueCall in makefunc.go
 // for more details.
 // No arg size here; runtime pulls arg map out of the func value.
-TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$40
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$336
        NO_LOCAL_POINTERS
-       MOVD    R11, FIXED_FRAME+0(R1)
-       MOVD    $argframe+0(FP), R3
-       MOVD    R3, FIXED_FRAME+8(R1)
-       MOVB    R0, FIXED_FRAME+32(R1)
-       ADD     $FIXED_FRAME+32, R1, R3
-       MOVD    R3, FIXED_FRAME+16(R1)
-       MOVD    R0, FIXED_FRAME+24(R1)
+       // NO_LOCAL_POINTERS is a lie. The stack map for the two locals in this
+       // frame is specially handled in the runtime. See the comment above LOCAL_RETVALID.
+       ADD     $LOCAL_REGARGS, R1, R20
+       CALL    runtime·spillArgs(SB)
+       MOVD    R11, FIXED_FRAME+0(R1) // arg0 ctxt
+       MOVD    R11, FIXED_FRAME+32(R1) // save for later
+       MOVD    R20, FIXED_FRAME+8(R1) // arg1 abiregargs
+       CALL    ·moveMakeFuncArgPtrs(SB)
+       MOVD    FIXED_FRAME+32(R1), R11 // restore ctxt
+       MOVD    R11, FIXED_FRAME+0(R1) // set as arg0
+       MOVD    $argframe+0(FP), R3     // frame pointer
+       MOVD    R3, FIXED_FRAME+8(R1)   // set as arg1
+       ADD     $LOCAL_RETVALID, R1, R3
+       MOVB    $0, (R3)                // clear ret flag
+       MOVD    R3, FIXED_FRAME+16(R1)  // addr of return flag
+       ADD     $LOCAL_REGARGS, R1, R3  // addr of abiregargs
+       MOVD    R3, FIXED_FRAME+24(R1)  // set as arg3
        BL      ·callMethod(SB)
+       ADD     $LOCAL_REGARGS, R1, R20
+       CALL    runtime·unspillArgs(SB)
        RET
index d951d8d9997b36075b230c8d3ea1b647465c59db..b71504fa211179268749a95ec79ff8e0e2df7971 100644 (file)
@@ -6,7 +6,10 @@
 
 package reflect
 
-import "unsafe"
+import (
+       "internal/bytealg"
+       "unsafe"
+)
 
 // During deepValueEqual, must keep track of checks that are
 // in progress. The comparison algorithm assumes that all
@@ -35,7 +38,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
        // and it's safe and valid to get Value's internal pointer.
        hard := func(v1, v2 Value) bool {
                switch v1.Kind() {
-               case Ptr:
+               case Pointer:
                        if v1.typ.ptrdata == 0 {
                                // go:notinheap pointers can't be cyclic.
                                // At least, all of our current uses of go:notinheap have
@@ -53,13 +56,13 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
        }
 
        if hard(v1, v2) {
-               // For a Ptr or Map value, we need to check flagIndir,
+               // For a Pointer 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:
+                       case Pointer, Map:
                                return v.pointer()
                        default:
                                return v.ptr
@@ -99,9 +102,13 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
                if v1.Len() != v2.Len() {
                        return false
                }
-               if v1.Pointer() == v2.Pointer() {
+               if v1.UnsafePointer() == v2.UnsafePointer() {
                        return true
                }
+               // Special case for []byte, which is common.
+               if v1.Type().Elem().Kind() == Uint8 {
+                       return bytealg.Equal(v1.Bytes(), v2.Bytes())
+               }
                for i := 0; i < v1.Len(); i++ {
                        if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
                                return false
@@ -113,8 +120,8 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
                        return v1.IsNil() == v2.IsNil()
                }
                return deepValueEqual(v1.Elem(), v2.Elem(), visited)
-       case Ptr:
-               if v1.Pointer() == v2.Pointer() {
+       case Pointer:
+               if v1.UnsafePointer() == v2.UnsafePointer() {
                        return true
                }
                return deepValueEqual(v1.Elem(), v2.Elem(), visited)
@@ -132,7 +139,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
                if v1.Len() != v2.Len() {
                        return false
                }
-               if v1.Pointer() == v2.Pointer() {
+               if v1.UnsafePointer() == v2.UnsafePointer() {
                        return true
                }
                for _, k := range v1.MapKeys() {
@@ -149,6 +156,18 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool {
                }
                // Can't do better than this:
                return false
+       case Int, Int8, Int16, Int32, Int64:
+               return v1.Int() == v2.Int()
+       case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+               return v1.Uint() == v2.Uint()
+       case String:
+               return v1.String() == v2.String()
+       case Bool:
+               return v1.Bool() == v2.Bool()
+       case Float32, Float64:
+               return v1.Float() == v2.Float()
+       case Complex64, Complex128:
+               return v1.Complex() == v2.Complex()
        default:
                // Normal equality suffices
                return valueInterface(v1, false) == valueInterface(v2, false)
index 23c08e4950049ed44f818d1d118ef1892adb1ad9..684bafd64869bb16fb4ad6a5be6dbfdd7c83ebe6 100644 (file)
@@ -166,3 +166,31 @@ func ExampleStructOf() {
        // json:  {"height":0.4,"age":2}
        // value: &{Height:1.5 Age:10}
 }
+
+func ExampleValue_FieldByIndex() {
+       // This example shows a case in which the name of a promoted field
+       // is hidden by another field: FieldByName will not work, so
+       // FieldByIndex must be used instead.
+       type user struct {
+               firstName string
+               lastName  string
+       }
+
+       type data struct {
+               user
+               firstName string
+               lastName  string
+       }
+
+       u := data{
+               user:      user{"Embedded John", "Embedded Doe"},
+               firstName: "John",
+               lastName:  "Doe",
+       }
+
+       s := reflect.ValueOf(u).FieldByIndex([]int{0, 1})
+       fmt.Println("embedded last name:", s)
+
+       // Output:
+       // embedded last name: Embedded Doe
+}
index 01749e30d85229a43ad976f738e60f324b9a7057..ba7fb68067a9370ca84e7f63a41dc7ff7c73af08 100644 (file)
@@ -161,3 +161,5 @@ func SetArgRegs(ints, floats int, floatSize uintptr) (oldInts, oldFloats int, ol
        clearLayoutCache()
        return
 }
+
+var MethodValueCallCodePtr = methodValueCallCodePtr
diff --git a/src/reflect/float32reg_generic.go b/src/reflect/float32reg_generic.go
new file mode 100644 (file)
index 0000000..307c0bb
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 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:build !ppc64 && !ppc64le
+
+package reflect
+
+import "unsafe"
+
+// This file implements a straightforward conversion of a float32
+// value into its representation in a register. This conversion
+// applies for amd64 and arm64. It is also chosen for the case of
+// zero argument registers, but is not used.
+
+func archFloat32FromReg(reg uint64) float32 {
+       i := uint32(reg)
+       return *(*float32)(unsafe.Pointer(&i))
+}
+
+func archFloat32ToReg(val float32) uint64 {
+       return uint64(*(*uint32)(unsafe.Pointer(&val)))
+}
diff --git a/src/reflect/float32reg_ppc64x.s b/src/reflect/float32reg_ppc64x.s
new file mode 100644 (file)
index 0000000..391edfa
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2021 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:build ppc64 || ppc64le
+// +build ppc64 ppc64le
+
+#include "textflag.h"
+
+// On PPC64, the float32 becomes a float64
+// when loaded in a register, different from
+// other platforms. These functions are
+// needed to ensure correct conversions on PPC64.
+
+// Convert float32->uint64
+TEXT ·archFloat32ToReg(SB),NOSPLIT,$0-16
+       FMOVS   val+0(FP), F1
+       FMOVD   F1, ret+8(FP)
+       RET
+
+// Convert uint64->float32
+TEXT ·archFloat32FromReg(SB),NOSPLIT,$0-12
+       FMOVD   reg+0(FP), F1
+       // Normally a float64->float32 conversion
+       // would need rounding, but that is not needed
+       // here since the uint64 was originally converted
+       // from float32, and should be avoided to
+       // preserve SNaN values.
+       FMOVS   F1, ret+8(FP)
+       RET
+
index 588be8bcc155602cdad79e7f4b7003444fbe7772..d0b0935cb8cb2944fadb591c04ff3b42f0207c05 100644 (file)
@@ -107,7 +107,7 @@ func makeMethodValue(op string, v Value) Value {
        // v.Type returns the actual type of the method value.
        ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
 
-       code := abi.FuncPCABI0(methodValueCall)
+       code := methodValueCallCodePtr()
 
        // methodValue contains a stack map for use by the runtime
        _, _, abi := funcLayout(ftyp, nil)
@@ -130,6 +130,10 @@ func makeMethodValue(op string, v Value) Value {
        return Value{&ftyp.rtype, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
 }
 
+func methodValueCallCodePtr() uintptr {
+       return abi.FuncPCABI0(methodValueCall)
+}
+
 // methodValueCall is an assembly function that is the code half of
 // the function returned from makeMethodValue. It expects a *methodValue
 // as its context register, and its job is to invoke callMethod(ctxt, frame)
index a633e6eee2b3e4e1cae1a128b86a815f719ec9fa..566dc7fb6578af530eac7e9a8694039c95efd3c5 100644 (file)
@@ -79,7 +79,7 @@ func TestImplicitMapConversion(t *testing.T) {
                if x != b2 {
                        t.Errorf("#5 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m)
                }
-               if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) {
+               if p := mv.MapIndex(ValueOf(b1)).Elem().UnsafePointer(); p != unsafe.Pointer(b2) {
                        t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2)
                }
        }
@@ -94,7 +94,7 @@ func TestImplicitMapConversion(t *testing.T) {
                if x != c2 {
                        t.Errorf("#6 after SetMapIndex(c1, c2): %p (!= %p), %t (map=%v)", x, c2, ok, m)
                }
-               if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() {
+               if p := mv.MapIndex(ValueOf(c1)).UnsafePointer(); p != ValueOf(c2).UnsafePointer() {
                        t.Errorf("#6 MapIndex(c1) = %#x want %p", p, c2)
                }
        }
@@ -110,7 +110,7 @@ func TestImplicitMapConversion(t *testing.T) {
                if x != b2 {
                        t.Errorf("#7 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m)
                }
-               if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) {
+               if p := mv.MapIndex(ValueOf(b1)).UnsafePointer(); p != unsafe.Pointer(b2) {
                        t.Errorf("#7 MapIndex(b1) = %#x want %p", p, b2)
                }
        }
diff --git a/src/reflect/stubs_ppc64x.go b/src/reflect/stubs_ppc64x.go
new file mode 100644 (file)
index 0000000..06c8bf5
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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:build ppc64le || ppc64
+
+package reflect
+
+func archFloat32FromReg(reg uint64) float32
+func archFloat32ToReg(val float32) uint64
index e416fd84da7bd15c355775a6843a034aa0b38178..193484a01bc4eb9548d8510db8a91bd92d367243 100644 (file)
@@ -39,7 +39,7 @@ func valueToString(val Value) string {
                } else {
                        return "false"
                }
-       case Ptr:
+       case Pointer:
                v := val
                str = typ.String() + "("
                if v.IsNil() {
index 278426da09e3a6431cc518d7488839f906266f88..4701e06c49bb8b52264c1da9b156cf5f333b431e 100644 (file)
@@ -126,7 +126,7 @@ type Type interface {
        //      Chan: ChanDir, Elem
        //      Func: In, NumIn, Out, NumOut, IsVariadic.
        //      Map: Key, Elem
-       //      Ptr: Elem
+       //      Pointer: Elem
        //      Slice: Elem
        //      Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
 
@@ -154,7 +154,7 @@ type Type interface {
        IsVariadic() bool
 
        // Elem returns a type's element type.
-       // It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
+       // It panics if the type's Kind is not Array, Chan, Map, Pointer, or Slice.
        Elem() Type
 
        // Field returns a struct type's i'th field.
@@ -261,13 +261,16 @@ const (
        Func
        Interface
        Map
-       Ptr
+       Pointer
        Slice
        String
        Struct
        UnsafePointer
 )
 
+// Ptr is the old name for the Pointer kind.
+const Ptr = Pointer
+
 // tflag is used by an rtype to signal what extra type information is
 // available in the memory directly following the rtype value.
 //
@@ -658,7 +661,7 @@ var kindNames = []string{
        Func:          "func",
        Interface:     "interface",
        Map:           "map",
-       Ptr:           "ptr",
+       Pointer:       "ptr",
        Slice:         "slice",
        String:        "string",
        Struct:        "struct",
@@ -741,7 +744,7 @@ func (t *rtype) uncommon() *uncommonType {
        switch t.Kind() {
        case Struct:
                return &(*structTypeUncommon)(unsafe.Pointer(t)).u
-       case Ptr:
+       case Pointer:
                type u struct {
                        ptrType
                        u uncommonType
@@ -945,7 +948,7 @@ func (t *rtype) Elem() Type {
        case Map:
                tt := (*mapType)(unsafe.Pointer(t))
                return toType(tt.elem)
-       case Ptr:
+       case Pointer:
                tt := (*ptrType)(unsafe.Pointer(t))
                return toType(tt.elem)
        case Slice:
@@ -1265,7 +1268,7 @@ func (t *structType) FieldByIndex(index []int) (f StructField) {
        for i, x := range index {
                if i > 0 {
                        ft := f.Type
-                       if ft.Kind() == Ptr && ft.Elem().Kind() == Struct {
+                       if ft.Kind() == Pointer && ft.Elem().Kind() == Struct {
                                ft = ft.Elem()
                        }
                        f.Type = ft
@@ -1336,7 +1339,7 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
                                if f.embedded() {
                                        // Embedded field of type T or *T.
                                        ntyp = f.typ
-                                       if ntyp.Kind() == Ptr {
+                                       if ntyp.Kind() == Pointer {
                                                ntyp = ntyp.Elem().common()
                                        }
                                }
@@ -1416,12 +1419,19 @@ func TypeOf(i interface{}) Type {
        return toType(eface.typ)
 }
 
-// ptrMap is the cache for PtrTo.
+// ptrMap is the cache for PointerTo.
 var ptrMap sync.Map // map[*rtype]*ptrType
 
 // PtrTo returns the pointer type with element t.
 // For example, if t represents type Foo, PtrTo(t) represents *Foo.
-func PtrTo(t Type) Type {
+//
+// PtrTo is the old spelling of PointerTo.
+// The two functions behave identically.
+func PtrTo(t Type) Type { return PointerTo(t) }
+
+// PointerTo returns the pointer type with element t.
+// For example, if t represents type Foo, PointerTo(t) represents *Foo.
+func PointerTo(t Type) Type {
        return t.(*rtype).ptrTo()
 }
 
@@ -1695,7 +1705,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
        case Map:
                return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
 
-       case Ptr, Slice:
+       case Pointer, Slice:
                return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
 
        case Struct:
@@ -2136,7 +2146,7 @@ func funcStr(ft *funcType) string {
 // That is, x == x for all values x of type t.
 func isReflexive(t *rtype) bool {
        switch t.Kind() {
-       case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, String, UnsafePointer:
+       case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, String, UnsafePointer:
                return true
        case Float32, Float64, Complex64, Complex128, Interface:
                return false
@@ -2160,7 +2170,7 @@ func isReflexive(t *rtype) bool {
 // needKeyUpdate reports whether map overwrites require the key to be copied.
 func needKeyUpdate(t *rtype) bool {
        switch t.Kind() {
-       case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, UnsafePointer:
+       case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, UnsafePointer:
                return false
        case Float32, Float64, Complex64, Complex128, Interface, String:
                // Float keys can be updated from +0 to -0.
@@ -2217,10 +2227,10 @@ const (
 
 func bucketOf(ktyp, etyp *rtype) *rtype {
        if ktyp.size > maxKeySize {
-               ktyp = PtrTo(ktyp).(*rtype)
+               ktyp = PointerTo(ktyp).(*rtype)
        }
        if etyp.size > maxValSize {
-               etyp = PtrTo(etyp).(*rtype)
+               etyp = PointerTo(etyp).(*rtype)
        }
 
        // Prepare GC data if any.
@@ -2458,10 +2468,10 @@ func StructOf(fields []StructField) Type {
                repr = append(repr, (" " + name)...)
                if f.embedded() {
                        // Embedded field
-                       if f.typ.Kind() == Ptr {
+                       if f.typ.Kind() == Pointer {
                                // Embedded ** and *interface{} are illegal
                                elem := ft.Elem()
-                               if k := elem.Kind(); k == Ptr || k == Interface {
+                               if k := elem.Kind(); k == Pointer || k == Interface {
                                        panic("reflect.StructOf: illegal embedded field type " + ft.String())
                                }
                        }
@@ -2526,7 +2536,7 @@ func StructOf(fields []StructField) Type {
                                                tfn:  resolveReflectText(unsafe.Pointer(&tfn)),
                                        })
                                }
-                       case Ptr:
+                       case Pointer:
                                ptr := (*ptrType)(unsafe.Pointer(ft))
                                if unt := ptr.uncommon(); unt != nil {
                                        if i > 0 && unt.mcount > 0 {
@@ -2594,7 +2604,7 @@ func StructOf(fields []StructField) Type {
                                }
                        }
                }
-               if _, dup := fset[name]; dup {
+               if _, dup := fset[name]; dup && name != "_" {
                        panic("reflect.StructOf: duplicate field " + name)
                }
                fset[name] = struct{}{}
@@ -2654,8 +2664,8 @@ func StructOf(fields []StructField) Type {
                        {Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))},
                }))
 
-               typ = (*structType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
-               ut = (*uncommonType)(unsafe.Pointer(tt.Elem().Field(1).UnsafeAddr()))
+               typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer())
+               ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer())
 
                copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]method), methods)
        }
@@ -3123,7 +3133,7 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
        }
 
        switch Kind(t.kind & kindMask) {
-       case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
+       case Chan, Func, Map, Pointer, Slice, String, UnsafePointer:
                // 1 pointer at start of representation
                for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
                        bv.append(0)
index b4b2d2e38b86be46918b85cdab6dcb4289f098ef..ecf9dd7bc86fb933b2bfb718d32d5f50a79e0c21 100644 (file)
@@ -5,6 +5,7 @@
 package reflect
 
 import (
+       "errors"
        "internal/abi"
        "internal/goarch"
        "internal/itoa"
@@ -90,8 +91,8 @@ func (f flag) ro() flag {
 }
 
 // pointer returns the underlying pointer represented by v.
-// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
-// if v.Kind() == Ptr, the base type must not be go:notinheap.
+// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer
+// if v.Kind() == Pointer, the base type must not be go:notinheap.
 func (v Value) pointer() unsafe.Pointer {
        if v.typ.size != goarch.PtrSize || !v.typ.pointers() {
                panic("can't call pointer on a non-pointer Value")
@@ -274,7 +275,7 @@ func (v Value) Addr() Value {
        // Preserve flagRO instead of using v.flag.ro() so that
        // v.Addr().Elem() is equivalent to v (#32772)
        fl := v.flag & flagRO
-       return Value{v.typ.ptrTo(), v.ptr, fl | flag(Ptr)}
+       return Value{v.typ.ptrTo(), v.ptr, fl | flag(Pointer)}
 }
 
 // Bool returns v's underlying value.
@@ -508,7 +509,7 @@ func (v Value) call(op string, in []Value) []Value {
                                // Copy values to "integer registers."
                                if v.flag&flagIndir != 0 {
                                        offset := add(v.ptr, st.offset, "precomputed value offset")
-                                       memmove(unsafe.Pointer(&regArgs.Ints[st.ireg]), offset, st.size)
+                                       intToReg(&regArgs, st.ireg, st.size, offset)
                                } else {
                                        if st.kind == abiStepPointer {
                                                // Duplicate this pointer in the pointer area of the
@@ -524,7 +525,7 @@ func (v Value) call(op string, in []Value) []Value {
                                        panic("attempted to copy pointer to FP register")
                                }
                                offset := add(v.ptr, st.offset, "precomputed value offset")
-                               memmove(unsafe.Pointer(&regArgs.Floats[st.freg]), offset, st.size)
+                               floatToReg(&regArgs, st.freg, st.size, offset)
                        default:
                                panic("unknown ABI part kind")
                        }
@@ -610,13 +611,13 @@ func (v Value) call(op string, in []Value) []Value {
                                switch st.kind {
                                case abiStepIntReg:
                                        offset := add(s, st.offset, "precomputed value offset")
-                                       memmove(offset, unsafe.Pointer(&regArgs.Ints[st.ireg]), st.size)
+                                       intFromReg(&regArgs, st.ireg, st.size, offset)
                                case abiStepPointer:
                                        s := add(s, st.offset, "precomputed value offset")
                                        *((*unsafe.Pointer)(s)) = regArgs.Ptrs[st.ireg]
                                case abiStepFloatReg:
                                        offset := add(s, st.offset, "precomputed value offset")
-                                       memmove(offset, unsafe.Pointer(&regArgs.Floats[st.freg]), st.size)
+                                       floatFromReg(&regArgs, st.freg, st.size, offset)
                                case abiStepStack:
                                        panic("register-based return value has stack component")
                                default:
@@ -698,13 +699,13 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs
                                        switch st.kind {
                                        case abiStepIntReg:
                                                offset := add(v.ptr, st.offset, "precomputed value offset")
-                                               memmove(offset, unsafe.Pointer(&regs.Ints[st.ireg]), st.size)
+                                               intFromReg(regs, st.ireg, st.size, offset)
                                        case abiStepPointer:
                                                s := add(v.ptr, st.offset, "precomputed value offset")
                                                *((*unsafe.Pointer)(s)) = regs.Ptrs[st.ireg]
                                        case abiStepFloatReg:
                                                offset := add(v.ptr, st.offset, "precomputed value offset")
-                                               memmove(offset, unsafe.Pointer(&regs.Floats[st.freg]), st.size)
+                                               floatFromReg(regs, st.freg, st.size, offset)
                                        case abiStepStack:
                                                panic("register-based return value has stack component")
                                        default:
@@ -784,7 +785,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs
                                        // Copy values to "integer registers."
                                        if v.flag&flagIndir != 0 {
                                                offset := add(v.ptr, st.offset, "precomputed value offset")
-                                               memmove(unsafe.Pointer(&regs.Ints[st.ireg]), offset, st.size)
+                                               intToReg(regs, st.ireg, st.size, offset)
                                        } else {
                                                // Only populate the Ints space on the return path.
                                                // This is safe because out is kept alive until the
@@ -799,7 +800,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs
                                                panic("attempted to copy pointer to FP register")
                                        }
                                        offset := add(v.ptr, st.offset, "precomputed value offset")
-                                       memmove(unsafe.Pointer(&regs.Floats[st.freg]), offset, st.size)
+                                       floatToReg(regs, st.freg, st.size, offset)
                                default:
                                        panic("unknown ABI part kind")
                                }
@@ -930,7 +931,7 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
 
        // Deal with the receiver. It's guaranteed to only be one word in size.
        if st := methodABI.call.steps[0]; st.kind == abiStepStack {
-               // Only copy the reciever to the stack if the ABI says so.
+               // Only copy the receiver to the stack if the ABI says so.
                // Otherwise, it'll be in a register already.
                storeRcvr(rcvr, methodFrame)
        } else {
@@ -982,9 +983,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
                                        methodRegs.Ptrs[mStep.ireg] = *(*unsafe.Pointer)(from)
                                        fallthrough // We need to make sure this ends up in Ints, too.
                                case abiStepIntReg:
-                                       memmove(methodRegs.IntRegArgAddr(mStep.ireg, mStep.size), from, mStep.size)
+                                       intToReg(&methodRegs, mStep.ireg, mStep.size, from)
                                case abiStepFloatReg:
-                                       memmove(methodRegs.FloatRegArgAddr(mStep.freg, mStep.size), from, mStep.size)
+                                       floatToReg(&methodRegs, mStep.freg, mStep.size, from)
                                default:
                                        panic("unexpected method step")
                                }
@@ -1000,9 +1001,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
                                        // Do the pointer copy directly so we get a write barrier.
                                        *(*unsafe.Pointer)(to) = valueRegs.Ptrs[vStep.ireg]
                                case abiStepIntReg:
-                                       memmove(to, valueRegs.IntRegArgAddr(vStep.ireg, vStep.size), vStep.size)
+                                       intFromReg(valueRegs, vStep.ireg, vStep.size, to)
                                case abiStepFloatReg:
-                                       memmove(to, valueRegs.FloatRegArgAddr(vStep.freg, vStep.size), vStep.size)
+                                       floatFromReg(valueRegs, vStep.freg, vStep.size, to)
                                default:
                                        panic("unexpected value step")
                                }
@@ -1122,6 +1123,16 @@ func (v Value) Close() {
        chanclose(v.pointer())
 }
 
+// CanComplex reports whether Complex can be used without panicking.
+func (v Value) CanComplex() bool {
+       switch v.kind() {
+       case Complex64, Complex128:
+               return true
+       default:
+               return false
+       }
+}
+
 // Complex returns v's underlying value, as a complex128.
 // It panics if v's Kind is not Complex64 or Complex128
 func (v Value) Complex() complex128 {
@@ -1137,7 +1148,7 @@ func (v Value) Complex() complex128 {
 
 // Elem returns the value that the interface v contains
 // or that the pointer v points to.
-// It panics if v's Kind is not Interface or Ptr.
+// It panics if v's Kind is not Interface or Pointer.
 // It returns the zero Value if v is nil.
 func (v Value) Elem() Value {
        k := v.kind()
@@ -1156,9 +1167,24 @@ func (v Value) Elem() Value {
                        x.flag |= v.flag.ro()
                }
                return x
-       case Ptr:
+       case Pointer:
                ptr := v.ptr
                if v.flag&flagIndir != 0 {
+                       if ifaceIndir(v.typ) {
+                               // This is a pointer to a not-in-heap object. ptr points to a uintptr
+                               // in the heap. That uintptr is the address of a not-in-heap object.
+                               // In general, pointers to not-in-heap objects can be total junk.
+                               // But Elem() is asking to dereference it, so the user has asserted
+                               // that at least it is a valid pointer (not just an integer stored in
+                               // a pointer slot). So let's check, to make sure that it isn't a pointer
+                               // that the runtime will crash on if it sees it during GC or write barriers.
+                               // Since it is a not-in-heap pointer, all pointers to the heap are
+                               // forbidden! That makes the test pretty easy.
+                               // See issue 48399.
+                               if !verifyNotInHeapPtr(*(*uintptr)(ptr)) {
+                                       panic("reflect: reflect.Value.Elem on an invalid notinheap pointer")
+                               }
+                       }
                        ptr = *(*unsafe.Pointer)(ptr)
                }
                // The returned value's address is v's value.
@@ -1207,7 +1233,8 @@ func (v Value) Field(i int) Value {
 }
 
 // FieldByIndex returns the nested field corresponding to index.
-// It panics if v's Kind is not struct.
+// It panics if evaluation requires stepping through a nil
+// pointer or a field that is not a struct.
 func (v Value) FieldByIndex(index []int) Value {
        if len(index) == 1 {
                return v.Field(index[0])
@@ -1215,7 +1242,7 @@ func (v Value) FieldByIndex(index []int) Value {
        v.mustBe(Struct)
        for i, x := range index {
                if i > 0 {
-                       if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct {
+                       if v.Kind() == Pointer && v.typ.Elem().Kind() == Struct {
                                if v.IsNil() {
                                        panic("reflect: indirection through nil pointer to embedded struct")
                                }
@@ -1227,6 +1254,29 @@ func (v Value) FieldByIndex(index []int) Value {
        return v
 }
 
+// FieldByIndexErr returns the nested field corresponding to index.
+// It returns an error if evaluation requires stepping through a nil
+// pointer, but panics if it must step through a field that
+// is not a struct.
+func (v Value) FieldByIndexErr(index []int) (Value, error) {
+       if len(index) == 1 {
+               return v.Field(index[0]), nil
+       }
+       v.mustBe(Struct)
+       for i, x := range index {
+               if i > 0 {
+                       if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct {
+                               if v.IsNil() {
+                                       return Value{}, errors.New("reflect: indirection through nil pointer to embedded struct field " + v.typ.Elem().Name())
+                               }
+                               v = v.Elem()
+                       }
+               }
+               v = v.Field(x)
+       }
+       return v, nil
+}
+
 // FieldByName returns the struct field with the given name.
 // It returns the zero Value if no field was found.
 // It panics if v's Kind is not struct.
@@ -1249,6 +1299,16 @@ func (v Value) FieldByNameFunc(match func(string) bool) Value {
        return Value{}
 }
 
+// CanFloat reports whether Float can be used without panicking.
+func (v Value) CanFloat() bool {
+       switch v.kind() {
+       case Float32, Float64:
+               return true
+       default:
+               return false
+       }
+}
+
 // Float returns v's underlying value, as a float64.
 // It panics if v's Kind is not Float32 or Float64
 func (v Value) Float() float64 {
@@ -1286,7 +1346,7 @@ func (v Value) Index(i int) Value {
                return Value{typ, val, fl}
 
        case Slice:
-               // Element flag same as Elem of Ptr.
+               // Element flag same as Elem of Pointer.
                // Addressable, indirect, possibly read-only.
                s := (*unsafeheader.Slice)(v.ptr)
                if uint(i) >= uint(s.Len) {
@@ -1310,6 +1370,16 @@ func (v Value) Index(i int) Value {
        panic(&ValueError{"reflect.Value.Index", v.kind()})
 }
 
+// CanInt reports whether Int can be used without panicking.
+func (v Value) CanInt() bool {
+       switch v.kind() {
+       case Int, Int8, Int16, Int32, Int64:
+               return true
+       default:
+               return false
+       }
+}
+
 // Int returns v's underlying value, as an int64.
 // It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64.
 func (v Value) Int() int64 {
@@ -1406,7 +1476,7 @@ func (v Value) InterfaceData() [2]uintptr {
 func (v Value) IsNil() bool {
        k := v.kind()
        switch k {
-       case Chan, Func, Map, Ptr, UnsafePointer:
+       case Chan, Func, Map, Pointer, UnsafePointer:
                if v.flag&flagMethod != 0 {
                        return false
                }
@@ -1454,7 +1524,7 @@ func (v Value) IsZero() bool {
                        }
                }
                return true
-       case Chan, Func, Interface, Map, Ptr, Slice, UnsafePointer:
+       case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer:
                return v.IsNil()
        case String:
                return v.Len() == 0
@@ -1515,15 +1585,21 @@ func (v Value) MapIndex(key Value) Value {
        // considered unexported. This is consistent with the
        // behavior for structs, which allow read but not write
        // of unexported fields.
-       key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
 
-       var k unsafe.Pointer
-       if key.flag&flagIndir != 0 {
-               k = key.ptr
+       var e unsafe.Pointer
+       if key.kind() == String && tt.key.Kind() == String && tt.elem.size <= maxValSize {
+               k := *(*string)(key.ptr)
+               e = mapaccess_faststr(v.typ, v.pointer(), k)
        } else {
-               k = unsafe.Pointer(&key.ptr)
+               key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
+               var k unsafe.Pointer
+               if key.flag&flagIndir != 0 {
+                       k = key.ptr
+               } else {
+                       k = unsafe.Pointer(&key.ptr)
+               }
+               e = mapaccess(v.typ, v.pointer(), k)
        }
-       e := mapaccess(v.typ, v.pointer(), k)
        if e == nil {
                return Value{}
        }
@@ -1549,11 +1625,12 @@ func (v Value) MapKeys() []Value {
        if m != nil {
                mlen = maplen(m)
        }
-       it := mapiterinit(v.typ, m)
+       var it hiter
+       mapiterinit(v.typ, m, &it)
        a := make([]Value, mlen)
        var i int
        for i = 0; i < len(a); i++ {
-               key := mapiterkey(it)
+               key := mapiterkey(&it)
                if key == nil {
                        // Someone deleted an entry from the map since we
                        // called maplen above. It's a data race, but nothing
@@ -1561,59 +1638,154 @@ func (v Value) MapKeys() []Value {
                        break
                }
                a[i] = copyVal(keyType, fl, key)
-               mapiternext(it)
+               mapiternext(&it)
        }
        return a[:i]
 }
 
+// hiter's structure matches runtime.hiter's structure.
+// Having a clone here allows us to embed a map iterator
+// inside type MapIter so that MapIters can be re-used
+// without doing any allocations.
+type hiter struct {
+       key         unsafe.Pointer
+       elem        unsafe.Pointer
+       t           unsafe.Pointer
+       h           unsafe.Pointer
+       buckets     unsafe.Pointer
+       bptr        unsafe.Pointer
+       overflow    *[]unsafe.Pointer
+       oldoverflow *[]unsafe.Pointer
+       startBucket uintptr
+       offset      uint8
+       wrapped     bool
+       B           uint8
+       i           uint8
+       bucket      uintptr
+       checkBucket uintptr
+}
+
+func (h *hiter) initialized() bool {
+       return h.t != nil
+}
+
 // A MapIter is an iterator for ranging over a map.
 // See Value.MapRange.
 type MapIter struct {
-       m  Value
-       it unsafe.Pointer
+       m     Value
+       hiter hiter
 }
 
-// Key returns the key of the iterator's current map entry.
-func (it *MapIter) Key() Value {
-       if it.it == nil {
+// Key returns the key of iter's current map entry.
+func (iter *MapIter) Key() Value {
+       if !iter.hiter.initialized() {
                panic("MapIter.Key called before Next")
        }
-       if mapiterkey(it.it) == nil {
+       iterkey := mapiterkey(&iter.hiter)
+       if iterkey == nil {
                panic("MapIter.Key called on exhausted iterator")
        }
 
-       t := (*mapType)(unsafe.Pointer(it.m.typ))
+       t := (*mapType)(unsafe.Pointer(iter.m.typ))
+       ktype := t.key
+       return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey)
+}
+
+// SetIterKey assigns to v the key of iter's current map entry.
+// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value.
+// As in Go, the key must be assignable to v's type.
+func (v Value) SetIterKey(iter *MapIter) {
+       if !iter.hiter.initialized() {
+               panic("reflect: Value.SetIterKey called before Next")
+       }
+       iterkey := mapiterkey(&iter.hiter)
+       if iterkey == nil {
+               panic("reflect: Value.SetIterKey called on exhausted iterator")
+       }
+
+       v.mustBeAssignable()
+       var target unsafe.Pointer
+       if v.kind() == Interface {
+               target = v.ptr
+       }
+
+       t := (*mapType)(unsafe.Pointer(iter.m.typ))
        ktype := t.key
-       return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), mapiterkey(it.it))
+
+       key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir}
+       key = key.assignTo("reflect.MapIter.SetKey", v.typ, target)
+       typedmemmove(v.typ, v.ptr, key.ptr)
 }
 
-// Value returns the value of the iterator's current map entry.
-func (it *MapIter) Value() Value {
-       if it.it == nil {
+// Value returns the value of iter's current map entry.
+func (iter *MapIter) Value() Value {
+       if !iter.hiter.initialized() {
                panic("MapIter.Value called before Next")
        }
-       if mapiterkey(it.it) == nil {
+       iterelem := mapiterelem(&iter.hiter)
+       if iterelem == nil {
                panic("MapIter.Value called on exhausted iterator")
        }
 
-       t := (*mapType)(unsafe.Pointer(it.m.typ))
+       t := (*mapType)(unsafe.Pointer(iter.m.typ))
        vtype := t.elem
-       return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapiterelem(it.it))
+       return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem)
+}
+
+// SetIterValue assigns to v the value of iter's current map entry.
+// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value.
+// As in Go, the value must be assignable to v's type.
+func (v Value) SetIterValue(iter *MapIter) {
+       if !iter.hiter.initialized() {
+               panic("reflect: Value.SetIterValue called before Next")
+       }
+       iterelem := mapiterelem(&iter.hiter)
+       if iterelem == nil {
+               panic("reflect: Value.SetIterValue called on exhausted iterator")
+       }
+
+       v.mustBeAssignable()
+       var target unsafe.Pointer
+       if v.kind() == Interface {
+               target = v.ptr
+       }
+
+       t := (*mapType)(unsafe.Pointer(iter.m.typ))
+       vtype := t.elem
+
+       elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir}
+       elem = elem.assignTo("reflect.MapIter.SetValue", v.typ, target)
+       typedmemmove(v.typ, v.ptr, elem.ptr)
 }
 
 // Next advances the map iterator and reports whether there is another
-// entry. It returns false when the iterator is exhausted; subsequent
+// entry. It returns false when iter is exhausted; subsequent
 // calls to Key, Value, or Next will panic.
-func (it *MapIter) Next() bool {
-       if it.it == nil {
-               it.it = mapiterinit(it.m.typ, it.m.pointer())
+func (iter *MapIter) Next() bool {
+       if !iter.m.IsValid() {
+               panic("MapIter.Next called on an iterator that does not have an associated map Value")
+       }
+       if !iter.hiter.initialized() {
+               mapiterinit(iter.m.typ, iter.m.pointer(), &iter.hiter)
        } else {
-               if mapiterkey(it.it) == nil {
+               if mapiterkey(&iter.hiter) == nil {
                        panic("MapIter.Next called on exhausted iterator")
                }
-               mapiternext(it.it)
+               mapiternext(&iter.hiter)
+       }
+       return mapiterkey(&iter.hiter) != nil
+}
+
+// Reset modifies iter to iterate over v.
+// It panics if v's Kind is not Map and v is not the zero Value.
+// Reset(Value{}) causes iter to not to refer to any map,
+// which may allow the previously iterated-over map to be garbage collected.
+func (iter *MapIter) Reset(v Value) {
+       if v.IsValid() {
+               v.mustBe(Map)
        }
-       return mapiterkey(it.it) != nil
+       iter.m = v
+       iter.hiter = hiter{}
 }
 
 // MapRange returns a range iterator for a map.
@@ -1776,7 +1948,7 @@ func (v Value) OverflowUint(x uint64) bool {
 // It returns uintptr instead of unsafe.Pointer so that
 // code using reflect cannot obtain unsafe.Pointers
 // without importing the unsafe package explicitly.
-// It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer.
+// It panics if v's Kind is not Chan, Func, Map, Pointer, Slice, or UnsafePointer.
 //
 // If v's Kind is Func, the returned pointer is an underlying
 // code pointer, but not necessarily enough to identify a
@@ -1786,17 +1958,20 @@ func (v Value) OverflowUint(x uint64) bool {
 // If v's Kind is Slice, the returned pointer is to the first
 // element of the slice. If the slice is nil the returned value
 // is 0.  If the slice is empty but non-nil the return value is non-zero.
+//
+// It's preferred to use uintptr(Value.UnsafePointer()) to get the equivalent result.
 func (v Value) Pointer() uintptr {
-       // TODO: deprecate
        k := v.kind()
        switch k {
-       case Ptr:
+       case Pointer:
                if v.typ.ptrdata == 0 {
-                       // Handle pointers to go:notinheap types directly,
-                       // so we never materialize such pointers as an
-                       // unsafe.Pointer. (Such pointers are always indirect.)
-                       // See issue 42076.
-                       return *(*uintptr)(v.ptr)
+                       val := *(*uintptr)(v.ptr)
+                       // Since it is a not-in-heap pointer, all pointers to the heap are
+                       // forbidden! See comment in Value.Elem and issue #48399.
+                       if !verifyNotInHeapPtr(val) {
+                               panic("reflect: reflect.Value.Pointer on an invalid notinheap pointer")
+                       }
+                       return val
                }
                fallthrough
        case Chan, Map, UnsafePointer:
@@ -1809,8 +1984,7 @@ func (v Value) Pointer() uintptr {
                        // created via reflect have the same underlying code pointer,
                        // so their Pointers are equal. The function used here must
                        // match the one used in makeMethodValue.
-                       f := methodValueCall
-                       return **(**uintptr)(unsafe.Pointer(&f))
+                       return methodValueCallCodePtr()
                }
                p := v.pointer()
                // Non-nil func value points at data block.
@@ -2025,6 +2199,25 @@ func (v Value) SetMapIndex(key, elem Value) {
        v.mustBeExported()
        key.mustBeExported()
        tt := (*mapType)(unsafe.Pointer(v.typ))
+
+       if key.kind() == String && tt.key.Kind() == String && tt.elem.size <= maxValSize {
+               k := *(*string)(key.ptr)
+               if elem.typ == nil {
+                       mapdelete_faststr(v.typ, v.pointer(), k)
+                       return
+               }
+               elem.mustBeExported()
+               elem = elem.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+               var e unsafe.Pointer
+               if elem.flag&flagIndir != 0 {
+                       e = elem.ptr
+               } else {
+                       e = unsafe.Pointer(&elem.ptr)
+               }
+               mapassign_faststr(v.typ, v.pointer(), k, e)
+               return
+       }
+
        key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil)
        var k unsafe.Pointer
        if key.flag&flagIndir != 0 {
@@ -2270,6 +2463,16 @@ func (v Value) Type() Type {
        return v.typ.typeOff(m.mtyp)
 }
 
+// CanUint reports whether Uint can be used without panicking.
+func (v Value) CanUint() bool {
+       switch v.kind() {
+       case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+               return true
+       default:
+               return false
+       }
+}
+
 // Uint returns v's underlying value, as a uint64.
 // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
 func (v Value) Uint() uint64 {
@@ -2297,11 +2500,12 @@ func (v Value) Uint() uint64 {
 // which ensures cmd/compile can recognize unsafe.Pointer(v.UnsafeAddr())
 // and make an exception.
 
-// UnsafeAddr returns a pointer to v's data.
+// UnsafeAddr returns a pointer to v's data, as a uintptr.
 // It is for advanced clients that also import the "unsafe" package.
 // It panics if v is not addressable.
+//
+// It's preferred to use uintptr(Value.Addr().UnsafePointer()) to get the equivalent result.
 func (v Value) UnsafeAddr() uintptr {
-       // TODO: deprecate
        if v.typ == nil {
                panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
        }
@@ -2311,6 +2515,57 @@ func (v Value) UnsafeAddr() uintptr {
        return uintptr(v.ptr)
 }
 
+// UnsafePointer returns v's value as a unsafe.Pointer.
+// It panics if v's Kind is not Chan, Func, Map, Pointer, Slice, or UnsafePointer.
+//
+// If v's Kind is Func, the returned pointer is an underlying
+// code pointer, but not necessarily enough to identify a
+// single function uniquely. The only guarantee is that the
+// result is zero if and only if v is a nil func Value.
+//
+// If v's Kind is Slice, the returned pointer is to the first
+// element of the slice. If the slice is nil the returned value
+// is nil.  If the slice is empty but non-nil the return value is non-nil.
+func (v Value) UnsafePointer() unsafe.Pointer {
+       k := v.kind()
+       switch k {
+       case Pointer:
+               if v.typ.ptrdata == 0 {
+                       // Since it is a not-in-heap pointer, all pointers to the heap are
+                       // forbidden! See comment in Value.Elem and issue #48399.
+                       if !verifyNotInHeapPtr(*(*uintptr)(v.ptr)) {
+                               panic("reflect: reflect.Value.UnsafePointer on an invalid notinheap pointer")
+                       }
+                       return *(*unsafe.Pointer)(v.ptr)
+               }
+               fallthrough
+       case Chan, Map, UnsafePointer:
+               return v.pointer()
+       case Func:
+               if v.flag&flagMethod != 0 {
+                       // As the doc comment says, the returned pointer is an
+                       // underlying code pointer but not necessarily enough to
+                       // identify a single function uniquely. All method expressions
+                       // created via reflect have the same underlying code pointer,
+                       // so their Pointers are equal. The function used here must
+                       // match the one used in makeMethodValue.
+                       code := methodValueCallCodePtr()
+                       return *(*unsafe.Pointer)(unsafe.Pointer(&code))
+               }
+               p := v.pointer()
+               // Non-nil func value points at data block.
+               // First word of data block is actual code.
+               if p != nil {
+                       p = *(*unsafe.Pointer)(p)
+               }
+               return p
+
+       case Slice:
+               return (*unsafeheader.Slice)(v.ptr).Data
+       }
+       panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()})
+}
+
 // StringHeader is the runtime representation of a string.
 // It cannot be used safely or portably and its representation may
 // change in a later release.
@@ -2366,11 +2621,12 @@ func grow(s Value, extra int) (Value, int, int) {
        if m == 0 {
                m = extra
        } else {
+               const threshold = 256
                for m < i1 {
-                       if i0 < 1024 {
+                       if i0 < threshold {
                                m += m
                        } else {
-                               m += m / 4
+                               m += (m + 3*threshold) / 4
                        }
                }
        }
@@ -2677,7 +2933,7 @@ func MakeMapWithSize(typ Type, n int) Value {
 // If v is a nil pointer, Indirect returns a zero Value.
 // If v is not a pointer, Indirect returns v.
 func Indirect(v Value) Value {
-       if v.Kind() != Ptr {
+       if v.Kind() != Pointer {
                return v
        }
        return v.Elem()
@@ -2729,7 +2985,7 @@ const maxZero = 1024
 var zeroVal [maxZero]byte
 
 // New returns a Value representing a pointer to a new zero value
-// for the specified type. That is, the returned Value's Type is PtrTo(typ).
+// for the specified type. That is, the returned Value's Type is PointerTo(typ).
 func New(typ Type) Value {
        if typ == nil {
                panic("reflect: New(nil)")
@@ -2741,14 +2997,14 @@ func New(typ Type) Value {
                panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)")
        }
        ptr := unsafe_New(t)
-       fl := flag(Ptr)
+       fl := flag(Pointer)
        return Value{pt, ptr, fl}
 }
 
 // NewAt returns a Value representing a pointer to a value of the
 // specified type, using p as that pointer.
 func NewAt(typ Type, p unsafe.Pointer) Value {
-       fl := flag(Ptr)
+       fl := flag(Pointer)
        t := typ.(*rtype)
        return Value{t.ptrTo(), p, fl}
 }
@@ -2817,10 +3073,9 @@ func (v Value) CanConvert(t Type) bool {
        // Currently the only conversion that is OK in terms of type
        // but that can panic depending on the value is converting
        // from slice to pointer-to-array.
-       if vt.Kind() == Slice && t.Kind() == Ptr && t.Elem().Kind() == Array {
+       if vt.Kind() == Slice && t.Kind() == Pointer && t.Elem().Kind() == Array {
                n := t.Elem().Len()
-               h := (*unsafeheader.Slice)(v.ptr)
-               if n > h.Len {
+               if n > v.Len() {
                        return false
                }
        }
@@ -2888,7 +3143,7 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
                }
                // "x is a slice, T is a pointer-to-array type,
                // and the slice and array types have identical element types."
-               if dst.Kind() == Ptr && dst.Elem().Kind() == Array && src.Elem() == dst.Elem().Elem() {
+               if dst.Kind() == Pointer && dst.Elem().Kind() == Array && src.Elem() == dst.Elem().Elem() {
                        return cvtSliceArrayPtr
                }
 
@@ -2904,8 +3159,8 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
        }
 
        // dst and src are non-defined pointer types with same underlying base type.
-       if dst.Kind() == Ptr && dst.Name() == "" &&
-               src.Kind() == Ptr && src.Name() == "" &&
+       if dst.Kind() == Pointer && dst.Name() == "" &&
+               src.Kind() == Pointer && src.Name() == "" &&
                haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) {
                return cvtDirect
        }
@@ -3087,11 +3342,11 @@ func cvtStringRunes(v Value, t Type) Value {
 // convertOp: []T -> *[N]T
 func cvtSliceArrayPtr(v Value, t Type) Value {
        n := t.Elem().Len()
-       h := (*unsafeheader.Slice)(v.ptr)
-       if n > h.Len {
-               panic("reflect: cannot convert slice with length " + itoa.Itoa(h.Len) + " to pointer to array with length " + itoa.Itoa(n))
+       if n > v.Len() {
+               panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to pointer to array with length " + itoa.Itoa(n))
        }
-       return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Ptr)}
+       h := (*unsafeheader.Slice)(v.ptr)
+       return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Pointer)}
 }
 
 // convertOp: direct copy
@@ -3156,25 +3411,32 @@ func makemap(t *rtype, cap int) (m unsafe.Pointer)
 //go:noescape
 func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
 
+//go:noescape
+func mapaccess_faststr(t *rtype, m unsafe.Pointer, key string) (val unsafe.Pointer)
+
 //go:noescape
 func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
 
+//go:noescape
+func mapassign_faststr(t *rtype, m unsafe.Pointer, key string, val unsafe.Pointer)
+
 //go:noescape
 func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
 
-// m escapes into the return value, but the caller of mapiterinit
-// doesn't let the return value escape.
 //go:noescape
-func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+func mapdelete_faststr(t *rtype, m unsafe.Pointer, key string)
+
+//go:noescape
+func mapiterinit(t *rtype, m unsafe.Pointer, it *hiter)
 
 //go:noescape
-func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+func mapiterkey(it *hiter) (key unsafe.Pointer)
 
 //go:noescape
-func mapiterelem(it unsafe.Pointer) (elem unsafe.Pointer)
+func mapiterelem(it *hiter) (elem unsafe.Pointer)
 
 //go:noescape
-func mapiternext(it unsafe.Pointer)
+func mapiternext(it *hiter)
 
 //go:noescape
 func maplen(m unsafe.Pointer) int
@@ -3238,6 +3500,8 @@ func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int
 //go:noescape
 func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr
 
+func verifyNotInHeapPtr(p uintptr) bool
+
 // Dummy annotation marking that the value x escapes,
 // for use in cases where the reflect code is so clever that
 // the compiler cannot follow.
index 1a2b53570bef857d37ac0aedd08572a4747d3a3f..9375faa11045a6b5b473b72dd189b654cd964276 100644 (file)
@@ -92,7 +92,7 @@ func (w *visibleFieldsWalker) walk(t Type) {
                        w.fields = append(w.fields, f)
                }
                if f.Anonymous {
-                       if f.Type.Kind() == Ptr {
+                       if f.Type.Kind() == Pointer {
                                f.Type = f.Type.Elem()
                        }
                        if f.Type.Kind() == Struct {
index 915bbee867c60db0c491a97d822def430fa16213..5ae322321b2de8365522ec503ca43799709e4fe9 100644 (file)
@@ -6,6 +6,7 @@ package reflect_test
 
 import (
        . "reflect"
+       "strings"
        "testing"
 )
 
@@ -328,3 +329,21 @@ func TestFields(t *testing.T) {
                })
        }
 }
+
+// Must not panic with nil embedded pointer.
+func TestFieldByIndexErr(t *testing.T) {
+       type A struct {
+               S string
+       }
+       type B struct {
+               *A
+       }
+       v := ValueOf(B{})
+       _, err := v.FieldByIndexErr([]int{0, 0})
+       if err == nil {
+               t.Fatal("expected error")
+       }
+       if !strings.Contains(err.Error(), "embedded struct field A") {
+               t.Fatal(err)
+       }
+}
index be7a2e7111876de6d6f7f6be2514556a587bfa87..c233cfa9eaac75fb1f33de6db2aa3b53887a9177 100644 (file)
@@ -372,6 +372,9 @@ var literalPrefixTests = []MetaTest{
        {`^^0$$`, ``, ``, false},
        {`^$^$`, ``, ``, false},
        {`$$0^^`, ``, ``, false},
+       {`a\x{fffd}b`, ``, `a`, false},
+       {`\x{fffd}b`, ``, ``, false},
+       {"\ufffd", ``, ``, false},
 }
 
 func TestQuoteMeta(t *testing.T) {
index 6444bc12f90ebdfd34d446c9973edbe01eb1f412..b6dac4a058f0cecdba4bca8f35fbd433c4c6a334 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !race
-// +build !race
 
 package regexp
 
index 1f9a7a96e0c67d5eeb9b479b973dc0698f17f86e..5f8442668ca3c65dcc1f4be54bec12e693cb45b9 100644 (file)
@@ -294,12 +294,9 @@ func parseResult(t *testing.T, file string, lineno int, res string) []int {
                                out[n] = -1
                                out[n+1] = -1
                        } else {
-                               k := strings.Index(pair, "-")
-                               if k < 0 {
-                                       t.Fatalf("%s:%d: invalid pair %s", file, lineno, pair)
-                               }
-                               lo, err1 := strconv.Atoi(pair[:k])
-                               hi, err2 := strconv.Atoi(pair[k+1:])
+                               loStr, hiStr, _ := strings.Cut(pair, "-")
+                               lo, err1 := strconv.Atoi(loStr)
+                               hi, err2 := strconv.Atoi(hiStr)
                                if err1 != nil || err2 != nil || lo > hi {
                                        t.Fatalf("%s:%d: invalid pair %s", file, lineno, pair)
                                }
@@ -457,12 +454,11 @@ Reading:
                                continue Reading
                        }
                case ':':
-                       i := strings.Index(flag[1:], ":")
-                       if i < 0 {
+                       var ok bool
+                       if _, flag, ok = strings.Cut(flag[1:], ":"); !ok {
                                t.Logf("skip: %s", line)
                                continue Reading
                        }
-                       flag = flag[1+i+1:]
                case 'C', 'N', 'T', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
                        t.Logf("skip: %s", line)
                        continue Reading
index 64c2239d905fdff2e26df72ba42b51cc1c85caca..2edbe9b86e61547d11c50040e8a39150378371ab 100644 (file)
@@ -116,6 +116,13 @@ var findTests = []FindTest{
        {"\\`", "`", build(1, 0, 1)},
        {"[\\`]+", "`", build(1, 0, 1)},
 
+       {"\ufffd", "\xff", build(1, 0, 1)},
+       {"\ufffd", "hello\xffworld", build(1, 5, 6)},
+       {`.*`, "hello\xffworld", build(1, 0, 11)},
+       {`\x{fffd}`, "\xc2\x00", build(1, 0, 1)},
+       {"[\ufffd]", "\xff", build(1, 0, 1)},
+       {`[\x{fffd}]`, "\xc2\x00", build(1, 0, 1)},
+
        // long set of matches (longer than startSize)
        {
                ".",
index 2f3ce6f9f6cb877f9e4eda1d7c3d427ca9b1f741..bc47f4c4a830da065ca5053227a97b0a53588ad0 100644 (file)
@@ -9,6 +9,7 @@ import (
        "sort"
        "strings"
        "unicode"
+       "unicode/utf8"
 )
 
 // "One-pass" regexp execution.
@@ -55,7 +56,7 @@ func onePassPrefix(p *syntax.Prog) (prefix string, complete bool, pc uint32) {
 
        // Have prefix; gather characters.
        var buf strings.Builder
-       for iop(i) == syntax.InstRune && len(i.Rune) == 1 && syntax.Flags(i.Arg)&syntax.FoldCase == 0 {
+       for iop(i) == syntax.InstRune && len(i.Rune) == 1 && syntax.Flags(i.Arg)&syntax.FoldCase == 0 && i.Rune[0] != utf8.RuneError {
                buf.WriteRune(i.Rune[0])
                pc, i = i.Out, &p.Inst[i.Out]
        }
index b547a2ab97d71a8e26f427942d307d39ddfb28b6..af7259c9bfd2cbd0e2d9f3b1f587db97de612f35 100644 (file)
@@ -20,6 +20,8 @@
 // or any book about automata theory.
 //
 // All characters are UTF-8-encoded code points.
+// Following utf8.DecodeRune, each byte of an invalid UTF-8 sequence
+// is treated as if it encoded utf8.RuneError (U+FFFD).
 //
 // There are 16 methods of Regexp that match a regular expression and identify
 // the matched text. Their names are matched by this regular expression:
@@ -276,7 +278,11 @@ func minInputLen(re *syntax.Regexp) int {
        case syntax.OpLiteral:
                l := 0
                for _, r := range re.Rune {
-                       l += utf8.RuneLen(r)
+                       if r == utf8.RuneError {
+                               l++
+                       } else {
+                               l += utf8.RuneLen(r)
+                       }
                }
                return l
        case syntax.OpCapture, syntax.OpPlus:
@@ -922,23 +928,22 @@ func (re *Regexp) ExpandString(dst []byte, template string, src string, match []
 
 func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, match []int) []byte {
        for len(template) > 0 {
-               i := strings.Index(template, "$")
-               if i < 0 {
+               before, after, ok := strings.Cut(template, "$")
+               if !ok {
                        break
                }
-               dst = append(dst, template[:i]...)
-               template = template[i:]
-               if len(template) > 1 && template[1] == '$' {
+               dst = append(dst, before...)
+               template = after
+               if template != "" && template[0] == '$' {
                        // Treat $$ as $.
                        dst = append(dst, '$')
-                       template = template[2:]
+                       template = template[1:]
                        continue
                }
                name, num, rest, ok := extract(template)
                if !ok {
                        // Malformed; treat $ as raw text.
                        dst = append(dst, '$')
-                       template = template[1:]
                        continue
                }
                template = rest
@@ -967,17 +972,16 @@ func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, m
        return dst
 }
 
-// extract returns the name from a leading "$name" or "${name}" in str.
+// extract returns the name from a leading "name" or "{name}" in str.
+// (The $ has already been removed by the caller.)
 // If it is a number, extract returns num set to that number; otherwise num = -1.
 func extract(str string) (name string, num int, rest string, ok bool) {
-       if len(str) < 2 || str[0] != '$' {
+       if str == "" {
                return
        }
        brace := false
-       if str[1] == '{' {
+       if str[0] == '{' {
                brace = true
-               str = str[2:]
-       } else {
                str = str[1:]
        }
        i := 0
index 7b4030935a7bb5056163af5794786cd6c6b727ec..06a92fb3d75322a89987d410b2f794c4039df242 100644 (file)
@@ -824,13 +824,7 @@ func Parse(s string, flags Flags) (*Regexp, error) {
                                case 'Q':
                                        // \Q ... \E: the ... is always literals
                                        var lit string
-                                       if i := strings.Index(t, `\E`); i < 0 {
-                                               lit = t[2:]
-                                               t = ""
-                                       } else {
-                                               lit = t[2:i]
-                                               t = t[i+2:]
-                                       }
+                                       lit, t, _ = strings.Cut(t[2:], `\E`)
                                        for lit != "" {
                                                c, rest, err := nextRune(lit)
                                                if err != nil {
index ae7a9a2fe0118a11f02451d32586193a10a08bce..8583f55e5421d88789cb7e036695d5244ec7a87b 100644 (file)
@@ -8,6 +8,7 @@ import (
        "strconv"
        "strings"
        "unicode"
+       "unicode/utf8"
 )
 
 // Compiled program.
@@ -154,7 +155,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) {
 
        // Have prefix; gather characters.
        var buf strings.Builder
-       for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 {
+       for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 && i.Rune[0] != utf8.RuneError {
                buf.WriteRune(i.Rune[0])
                i = p.skipNop(i.Out)
        }
index f69d3a9d5012d6c3ce79968533348f2cabe05ddc..5c1f1f40672a51266f7c8ea59cb785e57dc441f0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build goexperiment.regabireflect
-// +build goexperiment.regabireflect
 
 // This file contains tests specific to making sure the register ABI
 // works in a bunch of contexts in the runtime.
diff --git a/src/runtime/asan.go b/src/runtime/asan.go
new file mode 100644 (file)
index 0000000..a22b56b
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2021 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:build asan
+
+package runtime
+
+import (
+       "unsafe"
+)
+
+// Public address sanitizer API.
+
+func ASanRead(addr unsafe.Pointer, len int) {
+       asanread(addr, uintptr(len))
+}
+
+func ASanWrite(addr unsafe.Pointer, len int) {
+       asanwrite(addr, uintptr(len))
+}
+
+// Private interface for the runtime.
+const asanenabled = true
+
+//go:noescape
+func asanread(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func asanwrite(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func asanunpoison(addr unsafe.Pointer, sz uintptr)
+
+//go:noescape
+func asanpoison(addr unsafe.Pointer, sz uintptr)
+
+// These are called from asan_GOARCH.s
+//go:cgo_import_static __asan_read_go
+//go:cgo_import_static __asan_write_go
+//go:cgo_import_static __asan_unpoison_go
+//go:cgo_import_static __asan_poison_go
diff --git a/src/runtime/asan/asan.go b/src/runtime/asan/asan.go
new file mode 100644 (file)
index 0000000..eb66b3a
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2021 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:build asan && linux && (arm64 || amd64)
+
+package asan
+
+/*
+#cgo CFLAGS: -fsanitize=address
+#cgo LDFLAGS: -fsanitize=address
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sanitizer/asan_interface.h>
+
+extern void __asan_report_load1(void*);
+extern void __asan_report_load2(void*);
+extern void __asan_report_load4(void*);
+extern void __asan_report_load8(void*);
+extern void __asan_report_load_n(void*, uintptr_t);
+extern void __asan_report_store1(void*);
+extern void __asan_report_store2(void*);
+extern void __asan_report_store4(void*);
+extern void __asan_report_store8(void*);
+extern void __asan_report_store_n(void*, uintptr_t);
+
+void __asan_read_go(void *addr, uintptr_t sz) {
+       if (__asan_region_is_poisoned(addr, sz)) {
+               switch (sz) {
+               case 1: __asan_report_load1(addr); break;
+               case 2: __asan_report_load2(addr); break;
+               case 4: __asan_report_load4(addr); break;
+               case 8: __asan_report_load8(addr); break;
+               default: __asan_report_load_n(addr, sz); break;
+               }
+       }
+}
+
+void __asan_write_go(void *addr, uintptr_t sz) {
+       if (__asan_region_is_poisoned(addr, sz)) {
+               switch (sz) {
+               case 1: __asan_report_store1(addr); break;
+               case 2: __asan_report_store2(addr); break;
+               case 4: __asan_report_store4(addr); break;
+               case 8: __asan_report_store8(addr); break;
+               default: __asan_report_store_n(addr, sz); break;
+               }
+       }
+}
+
+void __asan_unpoison_go(void *addr, uintptr_t sz) {
+       __asan_unpoison_memory_region(addr, sz);
+}
+
+void __asan_poison_go(void *addr, uintptr_t sz) {
+       __asan_poison_memory_region(addr, sz);
+}
+
+*/
+import "C"
diff --git a/src/runtime/asan0.go b/src/runtime/asan0.go
new file mode 100644 (file)
index 0000000..d5478d6
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 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:build !asan
+
+// Dummy ASan support API, used when not built with -asan.
+
+package runtime
+
+import (
+       "unsafe"
+)
+
+const asanenabled = false
+
+// Because asanenabled is false, none of these functions should be called.
+
+func asanread(addr unsafe.Pointer, sz uintptr)     { throw("asan") }
+func asanwrite(addr unsafe.Pointer, sz uintptr)    { throw("asan") }
+func asanunpoison(addr unsafe.Pointer, sz uintptr) { throw("asan") }
+func asanpoison(addr unsafe.Pointer, sz uintptr)   { throw("asan") }
diff --git a/src/runtime/asan_amd64.s b/src/runtime/asan_amd64.s
new file mode 100644 (file)
index 0000000..01bd612
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2021 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:build asan
+// +build asan
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// This is like race_amd64.s, but for the asan calls.
+// See race_amd64.s for detailed comments.
+
+#ifdef GOOS_windows
+#define RARG0 CX
+#define RARG1 DX
+#else
+#define RARG0 DI
+#define RARG1 SI
+#endif
+
+// Called from intrumented code.
+// func runtime·asanread(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanread(SB), NOSPLIT, $0-16
+       MOVQ    addr+0(FP), RARG0
+       MOVQ    size+8(FP), RARG1
+       // void __asan_read_go(void *addr, uintptr_t sz);
+       MOVQ    $__asan_read_go(SB), AX
+       JMP     asancall<>(SB)
+
+// func runtime·asanwrite(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanwrite(SB), NOSPLIT, $0-16
+       MOVQ    addr+0(FP), RARG0
+       MOVQ    size+8(FP), RARG1
+       // void __asan_write_go(void *addr, uintptr_t sz);
+       MOVQ    $__asan_write_go(SB), AX
+       JMP     asancall<>(SB)
+
+// func runtime·asanunpoison(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanunpoison(SB), NOSPLIT, $0-16
+       MOVQ    addr+0(FP), RARG0
+       MOVQ    size+8(FP), RARG1
+       // void __asan_unpoison_go(void *addr, uintptr_t sz);
+       MOVQ    $__asan_unpoison_go(SB), AX
+       JMP     asancall<>(SB)
+
+// func runtime·asanpoison(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanpoison(SB), NOSPLIT, $0-16
+       MOVQ    addr+0(FP), RARG0
+       MOVQ    size+8(FP), RARG1
+       // void __asan_poison_go(void *addr, uintptr_t sz);
+       MOVQ    $__asan_poison_go(SB), AX
+       JMP     asancall<>(SB)
+
+// Switches SP to g0 stack and calls (AX). Arguments already set.
+TEXT   asancall<>(SB), NOSPLIT, $0-0
+       get_tls(R12)
+       MOVQ    g(R12), R14
+       MOVQ    SP, R12         // callee-saved, preserved across the CALL
+       CMPQ    R14, $0
+       JE      call    // no g; still on a system stack
+
+       MOVQ    g_m(R14), R13
+       // Switch to g0 stack.
+       MOVQ    m_g0(R13), R10
+       CMPQ    R10, R14
+       JE      call    // already on g0
+
+       MOVQ    (g_sched+gobuf_sp)(R10), SP
+call:
+       ANDQ    $~15, SP        // alignment for gcc ABI
+       CALL    AX
+       MOVQ    R12, SP
+       RET
diff --git a/src/runtime/asan_arm64.s b/src/runtime/asan_arm64.s
new file mode 100644 (file)
index 0000000..eb0f9bd
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2021 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:build asan
+// +build asan
+
+#include "go_asm.h"
+#include "textflag.h"
+
+#define RARG0 R0
+#define RARG1 R1
+#define FARG R3
+
+// Called from instrumented code.
+// func runtime·asanread(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanread(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __asan_read_go(void *addr, uintptr_t sz);
+       MOVD    $__asan_read_go(SB), FARG
+       JMP     asancall<>(SB)
+
+// func runtime·asanwrite(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanwrite(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __asan_write_go(void *addr, uintptr_t sz);
+       MOVD    $__asan_write_go(SB), FARG
+       JMP     asancall<>(SB)
+
+// func runtime·asanunpoison(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanunpoison(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __asan_unpoison_go(void *addr, uintptr_t sz);
+       MOVD    $__asan_unpoison_go(SB), FARG
+       JMP     asancall<>(SB)
+
+// func runtime·asanpoison(addr unsafe.Pointer, sz uintptr)
+TEXT   runtime·asanpoison(SB), NOSPLIT, $0-16
+       MOVD    addr+0(FP), RARG0
+       MOVD    size+8(FP), RARG1
+       // void __asan_poison_go(void *addr, uintptr_t sz);
+       MOVD    $__asan_poison_go(SB), FARG
+       JMP     asancall<>(SB)
+
+// Switches SP to g0 stack and calls (FARG). Arguments already set.
+TEXT   asancall<>(SB), NOSPLIT, $0-0
+       MOVD    RSP, R19                  // callee-saved
+       CBZ     g, g0stack                // no g, still on a system stack
+       MOVD    g_m(g), R10
+       MOVD    m_g0(R10), R11
+       CMP     R11, g
+       BEQ     g0stack
+
+       MOVD    (g_sched+gobuf_sp)(R11), R4
+       MOVD    R4, RSP
+
+g0stack:
+       BL      (FARG)
+       MOVD    R19, RSP
+       RET
index 0e14fcd3e6a3569f17357b31e3cefa4a142c0ae8..84d56de7dd85168084987b2ef7f47b48eaca6e36 100644 (file)
@@ -4,14 +4,6 @@
 
 #include "textflag.h"
 
-// funcdata for functions with no local variables in frame.
-// Define two zero-length bitmaps, because the same index is used
-// for the local variables as for the argument frame, and assembly
-// frames have two argument bitmaps, one without results and one with results.
-DATA runtime·no_pointers_stackmap+0x00(SB)/4, $2
-DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0
-GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8
-
 #ifndef GOARCH_amd64
 TEXT ·sigpanic0(SB),NOSPLIT,$0-0
        JMP     ·sigpanic<ABIInternal>(SB)
index 11c60309f4e07e55895bff83d97737fa8a1ba288..594cd5ed0d9592fad2a2fa38f71accd0b2ef6471 100644 (file)
@@ -137,9 +137,6 @@ has_cpuid:
        CMPL    AX, $0
        JE      nocpuinfo
 
-       // Figure out how to serialize RDTSC.
-       // On Intel processors LFENCE is enough. AMD requires MFENCE.
-       // Don't know about the rest, so let's do MFENCE.
        CMPL    BX, $0x756E6547  // "Genu"
        JNE     notintel
        CMPL    DX, $0x49656E69  // "ineI"
@@ -147,7 +144,6 @@ has_cpuid:
        CMPL    CX, $0x6C65746E  // "ntel"
        JNE     notintel
        MOVB    $1, runtime·isIntel(SB)
-       MOVB    $1, runtime·lfenceBeforeRdtsc(SB)
 notintel:
 
        // Load EAX=1 cpuid flags
@@ -633,18 +629,18 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        get_tls(CX)
-       MOVL    g(CX), BP
-       CMPL    BP, $0
-       JEQ     nosave  // Don't even have a G yet.
-       MOVL    g_m(BP), BP
-       MOVL    m_g0(BP), SI
        MOVL    g(CX), DI
-       CMPL    SI, DI
-       JEQ     noswitch
+       CMPL    DI, $0
+       JEQ     nosave  // Don't even have a G yet.
+       MOVL    g_m(DI), BP
        CMPL    DI, m_gsignal(BP)
        JEQ     noswitch
+       MOVL    m_g0(BP), SI
+       CMPL    DI, SI
+       JEQ     noswitch
        CALL    gosave_systemstack_switch<>(SB)
        get_tls(CX)
        MOVL    SI, g(CX)
@@ -838,19 +834,37 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 
 // func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-8
-       CMPB    internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE     done
-       CMPB    runtime·lfenceBeforeRdtsc(SB), $1
-       JNE     mfence
-       LFENCE
-       JMP     done
-mfence:
-       MFENCE
+       // LFENCE/MFENCE instruction support is dependent on SSE2.
+       // When no SSE2 support is present do not enforce any serialization
+       // since using CPUID to serialize the instruction stream is
+       // very costly.
+#ifdef GO386_softfloat
+       JMP     rdtsc  // no fence instructions available
+#endif
+       CMPB    internal∕cpu·X86+const_offsetX86HasRDTSCP(SB), $1
+       JNE     fences
+       // Instruction stream serializing RDTSCP is supported.
+       // RDTSCP is supported by Intel Nehalem (2008) and
+       // AMD K8 Rev. F (2006) and newer.
+       RDTSCP
 done:
-       RDTSC
        MOVL    AX, ret_lo+0(FP)
        MOVL    DX, ret_hi+4(FP)
        RET
+fences:
+       // MFENCE is instruction stream serializing and flushes the
+       // store buffers on AMD. The serialization semantics of LFENCE on AMD
+       // are dependent on MSR C001_1029 and CPU generation.
+       // LFENCE on Intel does wait for all previous instructions to have executed.
+       // Intel recommends MFENCE;LFENCE in its manuals before RDTSC to have all
+       // previous instructions executed and all previous loads and stores to globally visible.
+       // Using MFENCE;LFENCE here aligns the serializing properties without
+       // runtime detection of CPU manufacturer.
+       MFENCE
+       LFENCE
+rdtsc:
+       RDTSC
+       JMP done
 
 TEXT ldt0setup<>(SB),NOSPLIT,$16-0
        // set up ldt 7 to point at m0.tls
index 2083ecb53e8bfc40d612df2f17fcdd786c91e89c..0f0e5be21acac6be949293b5e71887f95814ed7f 100644 (file)
@@ -78,6 +78,87 @@ GLOBL _rt0_amd64_lib_argc<>(SB),NOPTR, $8
 DATA _rt0_amd64_lib_argv<>(SB)/8, $0
 GLOBL _rt0_amd64_lib_argv<>(SB),NOPTR, $8
 
+#ifdef GOAMD64_v2
+DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v2 microarchitecture support.\n"
+#endif
+
+#ifdef GOAMD64_v3
+DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v3 microarchitecture support.\n"
+#endif
+
+#ifdef GOAMD64_v4
+DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v4 microarchitecture support.\n"
+#endif
+
+GLOBL bad_cpu_msg<>(SB), RODATA, $84
+
+// Define a list of AMD64 microarchitecture level features
+// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
+
+                     // SSE3     SSSE3    CMPXCHNG16 SSE4.1    SSE4.2    POPCNT
+#define V2_FEATURES_CX (1 << 0 | 1 << 9 | 1 << 13  | 1 << 19 | 1 << 20 | 1 << 23)
+                         // LAHF/SAHF
+#define V2_EXT_FEATURES_CX (1 << 0)
+                                      // FMA       MOVBE     OSXSAVE   AVX       F16C
+#define V3_FEATURES_CX (V2_FEATURES_CX | 1 << 12 | 1 << 22 | 1 << 27 | 1 << 28 | 1 << 29)
+                                              // ABM (FOR LZNCT)
+#define V3_EXT_FEATURES_CX (V2_EXT_FEATURES_CX | 1 << 5)
+                         // BMI1     AVX2     BMI2
+#define V3_EXT_FEATURES_BX (1 << 3 | 1 << 5 | 1 << 8)
+                       // XMM      YMM
+#define V3_OS_SUPPORT_AX (1 << 1 | 1 << 2)
+
+#define V4_FEATURES_CX V3_FEATURES_CX
+
+#define V4_EXT_FEATURES_CX V3_EXT_FEATURES_CX
+                                              // AVX512F   AVX512DQ  AVX512CD  AVX512BW  AVX512VL
+#define V4_EXT_FEATURES_BX (V3_EXT_FEATURES_BX | 1 << 16 | 1 << 17 | 1 << 28 | 1 << 30 | 1 << 31)
+                                          // OPMASK   ZMM
+#define V4_OS_SUPPORT_AX (V3_OS_SUPPORT_AX | 1 << 5 | (1 << 6 | 1 << 7))
+
+#ifdef GOAMD64_v2
+#define NEED_MAX_CPUID 0x80000001
+#define NEED_FEATURES_CX V2_FEATURES_CX
+#define NEED_EXT_FEATURES_CX V2_EXT_FEATURES_CX
+#endif
+
+#ifdef GOAMD64_v3
+#define NEED_MAX_CPUID 0x80000001
+#define NEED_FEATURES_CX V3_FEATURES_CX
+#define NEED_EXT_FEATURES_CX V3_EXT_FEATURES_CX
+#define NEED_EXT_FEATURES_BX V3_EXT_FEATURES_BX
+#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX
+#endif
+
+#ifdef GOAMD64_v4
+#define NEED_MAX_CPUID 0x80000001
+#define NEED_FEATURES_CX V4_FEATURES_CX
+#define NEED_EXT_FEATURES_CX V4_EXT_FEATURES_CX
+#define NEED_EXT_FEATURES_BX V4_EXT_FEATURES_BX
+
+// Downgrading v4 OS checks on Darwin for now, see CL 285572.
+#ifdef GOOS_darwin
+#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX
+#else
+#define NEED_OS_SUPPORT_AX V4_OS_SUPPORT_AX
+#endif
+
+#endif
+
+#ifdef GOAMD64_v1
+#define SKIP_GOAMD64_CHECK
+#endif
+
+#ifndef GOAMD64_v1
+#ifndef GOAMD64_v2
+#ifndef GOAMD64_v3
+#ifndef GOAMD64_v4
+#define SKIP_GOAMD64_CHECK
+#endif
+#endif
+#endif
+#endif
+
 TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        // copy arguments forward on an even stack
        MOVQ    DI, AX          // argc
@@ -99,13 +180,24 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        // find out information about the processor we're on
        MOVL    $0, AX
        CPUID
-       MOVL    AX, SI
        CMPL    AX, $0
+#ifdef SKIP_GOAMD64_CHECK
        JE      nocpuinfo
+#else
+       JNE     has_cpuinfo
 
-       // Figure out how to serialize RDTSC.
-       // On Intel processors LFENCE is enough. AMD requires MFENCE.
-       // Don't know about the rest, so let's do MFENCE.
+bad_cpu: // show that the program requires a certain microarchitecture level.
+       MOVQ    $2, 0(SP)
+       MOVQ    $bad_cpu_msg<>(SB), AX
+       MOVQ    AX, 8(SP)
+       MOVQ    $84, 16(SP)
+       CALL    runtime·write(SB)
+       MOVQ    $1, 0(SP)
+       CALL    runtime·exit(SB)
+       CALL    runtime·abort(SB)
+#endif
+
+has_cpuinfo:
        CMPL    BX, $0x756E6547  // "Genu"
        JNE     notintel
        CMPL    DX, $0x49656E69  // "ineI"
@@ -113,14 +205,51 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        CMPL    CX, $0x6C65746E  // "ntel"
        JNE     notintel
        MOVB    $1, runtime·isIntel(SB)
-       MOVB    $1, runtime·lfenceBeforeRdtsc(SB)
-notintel:
 
+notintel:
        // Load EAX=1 cpuid flags
        MOVL    $1, AX
        CPUID
        MOVL    AX, runtime·processorVersionInfo(SB)
 
+#ifdef NEED_FEATURES_CX
+       ANDL    $NEED_FEATURES_CX, CX
+       CMPL    CX, $NEED_FEATURES_CX
+       JNE     bad_cpu
+#endif
+
+#ifdef NEED_MAX_CPUID
+       MOVL    $0x80000000, AX
+       CPUID
+       CMPL    AX, $NEED_MAX_CPUID
+       JL      bad_cpu
+#endif
+
+#ifdef NEED_EXT_FEATURES_BX
+       MOVL    $7, AX
+       MOVL    $0, CX
+       CPUID
+       ANDL    $NEED_EXT_FEATURES_BX, BX
+       CMPL    BX, $NEED_EXT_FEATURES_BX
+       JNE     bad_cpu
+#endif
+
+#ifdef NEED_EXT_FEATURES_CX
+       MOVL    $0x80000001, AX
+       CPUID
+       ANDL    $NEED_EXT_FEATURES_CX, CX
+       CMPL    CX, $NEED_EXT_FEATURES_CX
+       JNE     bad_cpu
+#endif
+
+#ifdef NEED_OS_SUPPORT_AX
+       XORL    CX, CX
+       XGETBV
+       ANDL    $NEED_OS_SUPPORT_AX, AX
+       CMPL    AX, $NEED_OS_SUPPORT_AX
+       JNE     bad_cpu
+#endif
+
 nocpuinfo:
        // if there is an _cgo_init, call it.
        MOVQ    _cgo_init(SB), AX
@@ -667,22 +796,21 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        get_tls(CX)
-       MOVQ    g(CX), R8
-       CMPQ    R8, $0
-       JEQ     nosave
-       MOVQ    g_m(R8), R8
-       MOVQ    m_g0(R8), SI
        MOVQ    g(CX), DI
-       CMPQ    SI, DI
+       CMPQ    DI, $0
        JEQ     nosave
+       MOVQ    g_m(DI), R8
        MOVQ    m_gsignal(R8), SI
-       CMPQ    SI, DI
+       CMPQ    DI, SI
+       JEQ     nosave
+       MOVQ    m_g0(R8), SI
+       CMPQ    DI, SI
        JEQ     nosave
 
        // Switch to system stack.
-       MOVQ    m_g0(R8), SI
        CALL    gosave_systemstack_switch<>(SB)
        MOVQ    SI, g(CX)
        MOVQ    (g_sched+gobuf_sp)(SI), SP
@@ -929,18 +1057,30 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 
 // func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
-       CMPB    runtime·lfenceBeforeRdtsc(SB), $1
-       JNE     mfence
-       LFENCE
-       JMP     done
-mfence:
-       MFENCE
+       CMPB    internal∕cpu·X86+const_offsetX86HasRDTSCP(SB), $1
+       JNE     fences
+       // Instruction stream serializing RDTSCP is supported.
+       // RDTSCP is supported by Intel Nehalem (2008) and
+       // AMD K8 Rev. F (2006) and newer.
+       RDTSCP
 done:
-       RDTSC
        SHLQ    $32, DX
        ADDQ    DX, AX
        MOVQ    AX, ret+0(FP)
        RET
+fences:
+       // MFENCE is instruction stream serializing and flushes the
+       // store buffers on AMD. The serialization semantics of LFENCE on AMD
+       // are dependent on MSR C001_1029 and CPU generation.
+       // LFENCE on Intel does wait for all previous instructions to have executed.
+       // Intel recommends MFENCE;LFENCE in its manuals before RDTSC to have all
+       // previous instructions executed and all previous loads and stores to globally visible.
+       // Using MFENCE;LFENCE here aligns the serializing properties without
+       // runtime detection of CPU manufacturer.
+       MFENCE
+       LFENCE
+       RDTSC
+       JMP done
 
 // func memhash(p unsafe.Pointer, h, s uintptr) uintptr
 // hash function using AES hardware instructions
index a1164781d2eff652e8eafd1d523c44d329dd192e..b47184e36bc9801e1c2c2080b9a9ef629122304a 100644 (file)
@@ -556,7 +556,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOVW    g_m(g), R8
        MOVW    m_gsignal(R8), R3
        CMP     R3, g
index e51ce2f8316b4010b952f7b4e5f99eb7b1a2b31d..9e9d9314efc0b808badc0b27e1f55f30161453a5 100644 (file)
@@ -1027,7 +1027,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOVD    g_m(g), R8
        MOVD    m_gsignal(R8), R3
        CMP     R3, g
@@ -1382,12 +1383,16 @@ flush:
 // Defined as ABIInternal since the compiler generates ABIInternal
 // calls to it directly and it does not use the stack-based Go ABI.
 TEXT runtime·panicIndex<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R0, x+0(FP)
        MOVD    R1, y+8(FP)
+#endif
        JMP     runtime·goPanicIndex<ABIInternal>(SB)
 TEXT runtime·panicIndexU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R0, x+0(FP)
        MOVD    R1, y+8(FP)
+#endif
        JMP     runtime·goPanicIndexU<ABIInternal>(SB)
 TEXT runtime·panicSliceAlen<ABIInternal>(SB),NOSPLIT,$0-16
 #ifdef GOEXPERIMENT_regabiargs
@@ -1426,12 +1431,16 @@ TEXT runtime·panicSliceAcapU<ABIInternal>(SB),NOSPLIT,$0-16
 #endif
        JMP     runtime·goPanicSliceAcapU<ABIInternal>(SB)
 TEXT runtime·panicSliceB<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R0, x+0(FP)
        MOVD    R1, y+8(FP)
+#endif
        JMP     runtime·goPanicSliceB<ABIInternal>(SB)
 TEXT runtime·panicSliceBU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R0, x+0(FP)
        MOVD    R1, y+8(FP)
+#endif
        JMP     runtime·goPanicSliceBU<ABIInternal>(SB)
 TEXT runtime·panicSlice3Alen<ABIInternal>(SB),NOSPLIT,$0-16
 #ifdef GOEXPERIMENT_regabiargs
@@ -1488,12 +1497,16 @@ TEXT runtime·panicSlice3BU<ABIInternal>(SB),NOSPLIT,$0-16
 #endif
        JMP     runtime·goPanicSlice3BU<ABIInternal>(SB)
 TEXT runtime·panicSlice3C<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R0, x+0(FP)
        MOVD    R1, y+8(FP)
+#endif
        JMP     runtime·goPanicSlice3C<ABIInternal>(SB)
 TEXT runtime·panicSlice3CU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R0, x+0(FP)
        MOVD    R1, y+8(FP)
+#endif
        JMP     runtime·goPanicSlice3CU<ABIInternal>(SB)
 TEXT runtime·panicSliceConvert<ABIInternal>(SB),NOSPLIT,$0-16
 #ifdef GOEXPERIMENT_regabiargs
index b2e2384c3681f28bbc37e51bc46ed79066ebe280..e0e5cbb7048c918de43d2696f7d692d707a60329 100644 (file)
@@ -424,8 +424,11 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOVV    g_m(g), R5
+       MOVV    m_gsignal(R5), R6
+       BEQ     R6, g, g0
        MOVV    m_g0(R5), R6
        BEQ     R6, g, g0
 
index 87a1344e8f6de574193f56089fe0dc0ffe4d97c9..1b550719d17eb4b5e3ef5ff320a814783315a960 100644 (file)
@@ -413,8 +413,11 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOVW    g_m(g), R5
+       MOVW    m_gsignal(R5), R6
+       BEQ     R6, g, g0
        MOVW    m_g0(R5), R6
        BEQ     R6, g, g0
 
index 5dc96c594732ffc86899fb964914cc98e2a2cda5..0e7ef7b2b8fd7eba0c25fce6de60acc8be87a46e 100644 (file)
@@ -103,7 +103,7 @@ nocgo:
        MOVD    R0, 0(R0)
        RET
 
-DATA   runtime·mainPC+0(SB)/8,$runtime·main(SB)
+DATA   runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB)
 GLOBL  runtime·mainPC(SB),RODATA,$8
 
 TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
@@ -165,8 +165,14 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0
 // Switch to m->g0's stack, call fn(g).
 // Fn must never return. It should gogo(&g->sched)
 // to keep running g.
-TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8
+TEXT runtime·mcall<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-8
        // Save caller state in g->sched
+       // R11 should be safe across save_g??
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R3, R11
+#else
+       MOVD    fn+0(FP), R11
+#endif
        MOVD    R1, (g_sched+gobuf_sp)(g)
        MOVD    LR, R31
        MOVD    R31, (g_sched+gobuf_pc)(g)
@@ -180,10 +186,11 @@ TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8
        CMP     g, R3
        BNE     2(PC)
        BR      runtime·badmcall(SB)
-       MOVD    fn+0(FP), R11                   // context
        MOVD    0(R11), R12                     // code pointer
        MOVD    R12, CTR
        MOVD    (g_sched+gobuf_sp)(g), R1       // sp = m->g0->sched.sp
+       // Don't need to do anything special for regabiargs here
+       // R3 is g; stack is set anyway
        MOVDU   R3, -8(R1)
        MOVDU   R0, -8(R1)
        MOVDU   R0, -8(R1)
@@ -428,6 +435,8 @@ callfn: \
        BNE     2(PC)                           \
        MOVD    R0, 0(R0)                       \
 #endif                                         \
+       MOVD    regArgs+40(FP), R20;    \
+       BL      runtime·unspillArgs(SB);        \
        MOVD    (R11), R12;                     \
        MOVD    R12, CTR;                       \
        PCDATA  $PCDATA_StackMapIndex, $0;      \
@@ -436,6 +445,8 @@ callfn: \
        MOVD    24(R1), R2;                     \
 #endif                                         \
        /* copy return values back */           \
+       MOVD    regArgs+40(FP), R20;            \
+       BL      runtime·spillArgs(SB);                 \
        MOVD    stackArgsType+0(FP), R7;                \
        MOVD    stackArgs+16(FP), R3;                   \
        MOVWZ   stackArgsSize+24(FP), R4;                       \
@@ -452,11 +463,12 @@ callfn: \
 // to reflectcallmove. It does not follow the Go ABI; it expects its
 // arguments in registers.
 TEXT callRet<>(SB), NOSPLIT, $40-0
+       NO_LOCAL_POINTERS
        MOVD    R7, FIXED_FRAME+0(R1)
        MOVD    R3, FIXED_FRAME+8(R1)
        MOVD    R5, FIXED_FRAME+16(R1)
        MOVD    R4, FIXED_FRAME+24(R1)
-       MOVD    $0, FIXED_FRAME+32(R1)
+       MOVD    R20, FIXED_FRAME+32(R1)
        BL      runtime·reflectcallmove(SB)
        RET
 
@@ -541,9 +553,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
-       // Moreover, if it's called inside the signal handler, it must not switch
-       // to g0 as it can be in use by another syscall.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOVD    g_m(g), R8
        MOVD    m_gsignal(R8), R6
        CMP     R6, g
@@ -689,7 +700,10 @@ havem:
        MOVD    R5, FIXED_FRAME+0(R1)
        MOVD    R6, FIXED_FRAME+8(R1)
        MOVD    R7, FIXED_FRAME+16(R1)
-       BL      runtime·cgocallbackg(SB)
+
+       MOVD    $runtime·cgocallbackg(SB), R12
+       MOVD    R12, CTR
+       CALL    (CTR) // indirect call to bypass nosplit check. We're on a different stack now.
 
        // Restore g->sched (== m->curg->sched) from saved values.
        MOVD    0(R1), R5
@@ -775,15 +789,80 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-8
        MOVD    R3, ret+0(FP)
        RET
 
+#ifdef GOEXPERIMENT_regabireflect
+// spillArgs stores return values from registers to a *internal/abi.RegArgs in R20.
+TEXT runtime·spillArgs(SB),NOSPLIT,$0-0
+       MOVD    R3, 0(R20)
+       MOVD    R4, 8(R20)
+       MOVD    R5, 16(R20)
+       MOVD    R6, 24(R20)
+       MOVD    R7, 32(R20)
+       MOVD    R8, 40(R20)
+       MOVD    R9, 48(R20)
+       MOVD    R10, 56(R20)
+       MOVD    R14, 64(R20)
+       MOVD    R15, 72(R20)
+       MOVD    R16, 80(R20)
+       MOVD    R17, 88(R20)
+       FMOVD   F1, 96(R20)
+       FMOVD   F2, 104(R20)
+       FMOVD   F3, 112(R20)
+       FMOVD   F4, 120(R20)
+       FMOVD   F5, 128(R20)
+       FMOVD   F6, 136(R20)
+       FMOVD   F7, 144(R20)
+       FMOVD   F8, 152(R20)
+       FMOVD   F9, 160(R20)
+       FMOVD   F10, 168(R20)
+       FMOVD   F11, 176(R20)
+       FMOVD   F12, 184(R20)
+       RET
+
+// unspillArgs loads args into registers from a *internal/abi.RegArgs in R20.
+TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0
+       MOVD    0(R20), R3
+       MOVD    8(R20), R4
+       MOVD    16(R20), R5
+       MOVD    24(R20), R6
+       MOVD    32(R20), R7
+       MOVD    40(R20), R8
+       MOVD    48(R20), R9
+       MOVD    56(R20), R10
+       MOVD    64(R20), R14
+       MOVD    72(R20), R15
+       MOVD    80(R20), R16
+       MOVD    88(R20), R17
+       FMOVD   96(R20), F1
+       FMOVD   104(R20), F2
+       FMOVD   112(R20), F3
+       FMOVD   120(R20), F4
+       FMOVD   128(R20), F5
+       FMOVD   136(R20), F6
+       FMOVD   144(R20), F7
+       FMOVD   152(R20), F8
+       FMOVD   160(R20), F9
+       FMOVD   168(R20), F10
+       FMOVD   176(R20), F11
+       FMOVD   184(R20), F12
+       RET
+#else
+
+TEXT runtime·spillArgs(SB),NOSPLIT,$0-0
+        RET
+
+TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0
+        RET
+#endif
+
 // AES hashing not implemented for ppc64
-TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32
-       JMP     runtime·memhashFallback(SB)
-TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24
-       JMP     runtime·strhashFallback(SB)
-TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24
-       JMP     runtime·memhash32Fallback(SB)
-TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24
-       JMP     runtime·memhash64Fallback(SB)
+TEXT runtime·memhash<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-32
+       JMP     runtime·memhashFallback<ABIInternal>(SB)
+TEXT runtime·strhash<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
+       JMP     runtime·strhashFallback<ABIInternal>(SB)
+TEXT runtime·memhash32<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
+       JMP     runtime·memhash32Fallback<ABIInternal>(SB)
+TEXT runtime·memhash64<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
+       JMP     runtime·memhash64Fallback<ABIInternal>(SB)
 
 TEXT runtime·return0(SB), NOSPLIT, $0
        MOVW    $0, R3
@@ -861,7 +940,7 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1
 // It clobbers condition codes.
 // It does not clobber R0 through R17 (except special registers),
 // but may clobber any other register, *including* R31.
-TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$112
+TEXT runtime·gcWriteBarrier<ABIInternal>(SB),NOSPLIT,$112
        // The standard prologue clobbers R31.
        // We use R18 and R19 as scratch registers.
        MOVD    g_m(g), R18
@@ -930,71 +1009,138 @@ flush:
 // in the caller's stack frame. These stubs write the args into that stack space and
 // then tail call to the corresponding runtime handler.
 // The tail call makes these stubs disappear in backtraces.
-TEXT runtime·panicIndex(SB),NOSPLIT,$0-16
+TEXT runtime·panicIndex<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3, x+0(FP)
        MOVD    R4, y+8(FP)
-       JMP     runtime·goPanicIndex(SB)
-TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicIndex<ABIInternal>(SB)
+TEXT runtime·panicIndexU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3, x+0(FP)
        MOVD    R4, y+8(FP)
-       JMP     runtime·goPanicIndexU(SB)
-TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicIndexU<ABIInternal>(SB)
+TEXT runtime·panicSliceAlen<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R4, R3
+       MOVD    R5, R4
+#else
        MOVD    R4, x+0(FP)
        MOVD    R5, y+8(FP)
-       JMP     runtime·goPanicSliceAlen(SB)
-TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSliceAlen<ABIInternal>(SB)
+TEXT runtime·panicSliceAlenU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R4, R3
+       MOVD    R5, R4
+#else
        MOVD    R4, x+0(FP)
        MOVD    R5, y+8(FP)
-       JMP     runtime·goPanicSliceAlenU(SB)
-TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSliceAlenU<ABIInternal>(SB)
+TEXT runtime·panicSliceAcap<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R4, R3
+       MOVD    R5, R4
+#else
        MOVD    R4, x+0(FP)
        MOVD    R5, y+8(FP)
-       JMP     runtime·goPanicSliceAcap(SB)
-TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSliceAcap<ABIInternal>(SB)
+TEXT runtime·panicSliceAcapU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R4, R3
+       MOVD    R5, R4
+#else
        MOVD    R4, x+0(FP)
        MOVD    R5, y+8(FP)
-       JMP     runtime·goPanicSliceAcapU(SB)
-TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSliceAcapU<ABIInternal>(SB)
+TEXT runtime·panicSliceB<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3, x+0(FP)
        MOVD    R4, y+8(FP)
-       JMP     runtime·goPanicSliceB(SB)
-TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSliceB<ABIInternal>(SB)
+TEXT runtime·panicSliceBU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3, x+0(FP)
        MOVD    R4, y+8(FP)
-       JMP     runtime·goPanicSliceBU(SB)
-TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSliceBU<ABIInternal>(SB)
+TEXT runtime·panicSlice3Alen<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R5, R3
+       MOVD    R6, R4
+#else
        MOVD    R5, x+0(FP)
        MOVD    R6, y+8(FP)
-       JMP     runtime·goPanicSlice3Alen(SB)
-TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3Alen<ABIInternal>(SB)
+TEXT runtime·panicSlice3AlenU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R5, R3
+       MOVD    R6, R4
+#else
        MOVD    R5, x+0(FP)
        MOVD    R6, y+8(FP)
-       JMP     runtime·goPanicSlice3AlenU(SB)
-TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3AlenU<ABIInternal>(SB)
+TEXT runtime·panicSlice3Acap<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R5, R3
+       MOVD    R6, R4
+#else
        MOVD    R5, x+0(FP)
        MOVD    R6, y+8(FP)
-       JMP     runtime·goPanicSlice3Acap(SB)
-TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3Acap<ABIInternal>(SB)
+TEXT runtime·panicSlice3AcapU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R5, R3
+       MOVD    R6, R4
+#else
        MOVD    R5, x+0(FP)
        MOVD    R6, y+8(FP)
-       JMP     runtime·goPanicSlice3AcapU(SB)
-TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3AcapU<ABIInternal>(SB)
+TEXT runtime·panicSlice3B<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R4, R3
+       MOVD    R5, R4
+#else
        MOVD    R4, x+0(FP)
        MOVD    R5, y+8(FP)
-       JMP     runtime·goPanicSlice3B(SB)
-TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3B<ABIInternal>(SB)
+TEXT runtime·panicSlice3BU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R4, R3
+       MOVD    R5, R4
+#else
        MOVD    R4, x+0(FP)
        MOVD    R5, y+8(FP)
-       JMP     runtime·goPanicSlice3BU(SB)
-TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3BU<ABIInternal>(SB)
+TEXT runtime·panicSlice3C<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3, x+0(FP)
        MOVD    R4, y+8(FP)
-       JMP     runtime·goPanicSlice3C(SB)
-TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3C<ABIInternal>(SB)
+TEXT runtime·panicSlice3CU<ABIInternal>(SB),NOSPLIT,$0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    R3, x+0(FP)
        MOVD    R4, y+8(FP)
-       JMP     runtime·goPanicSlice3CU(SB)
-TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16
+#endif
+       JMP     runtime·goPanicSlice3CU<ABIInternal>(SB)
+TEXT runtime·panicSliceConvert<ABIInternal>(SB),NOSPLIT,$0-16
+#ifdef GOEXPERIMENT_regabiargs
+       MOVD    R5, R3
+       MOVD    R6, R4
+#else
        MOVD    R5, x+0(FP)
        MOVD    R6, y+8(FP)
-       JMP     runtime·goPanicSliceConvert(SB)
+#endif
+       JMP     runtime·goPanicSliceConvert<ABIInternal>(SB)
index 9927a817f7274a86761b711bce09b7b8b5282c6c..0e813189d4d21b7b56076efb1c55b93dde865f36 100644 (file)
@@ -81,7 +81,7 @@ TEXT setg_gcc<>(SB),NOSPLIT,$0-0
 
 // func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-8
-       RDTIME  A0
+       RDCYCLE A0
        MOV     A0, ret+0(FP)
        RET
 
@@ -310,8 +310,11 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOV     g_m(g), X6
+       MOV     m_gsignal(X6), X7
+       BEQ     X7, g, g0
        MOV     m_g0(X6), X7
        BEQ     X7, g, g0
 
@@ -628,10 +631,10 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1
 // The act of CALLing gcWriteBarrier will clobber RA (LR).
 // It does not clobber any other general-purpose registers,
 // but may clobber others (e.g., floating point registers).
-TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$216
+TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$208
        // Save the registers clobbered by the fast path.
-       MOV     A0, 25*8(X2)
-       MOV     A1, 26*8(X2)
+       MOV     A0, 24*8(X2)
+       MOV     A1, 25*8(X2)
        MOV     g_m(g), A0
        MOV     m_p(A0), A0
        MOV     (p_wbBuf+wbBuf_next)(A0), A1
@@ -647,8 +650,8 @@ TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$216
        // Is the buffer full?
        BEQ     A1, T6, flush
 ret:
-       MOV     25*8(X2), A0
-       MOV     26*8(X2), A1
+       MOV     24*8(X2), A0
+       MOV     25*8(X2), A1
        // Do the write.
        MOV     T1, (T0)
        RET
@@ -661,34 +664,34 @@ flush:
        // X0 is zero register
        // X1 is LR, saved by prologue
        // X2 is SP
-       MOV     X3, 3*8(X2)
+       // X3 is GP
        // X4 is TP
        // X5 is first arg to wbBufFlush (T0)
        // X6 is second arg to wbBufFlush (T1)
-       MOV     X7, 4*8(X2)
-       MOV     X8, 5*8(X2)
-       MOV     X9, 6*8(X2)
+       MOV     X7, 3*8(X2)
+       MOV     X8, 4*8(X2)
+       MOV     X9, 5*8(X2)
        // X10 already saved (A0)
        // X11 already saved (A1)
-       MOV     X12, 7*8(X2)
-       MOV     X13, 8*8(X2)
-       MOV     X14, 9*8(X2)
-       MOV     X15, 10*8(X2)
-       MOV     X16, 11*8(X2)
-       MOV     X17, 12*8(X2)
-       MOV     X18, 13*8(X2)
-       MOV     X19, 14*8(X2)
-       MOV     X20, 15*8(X2)
-       MOV     X21, 16*8(X2)
-       MOV     X22, 17*8(X2)
-       MOV     X23, 18*8(X2)
-       MOV     X24, 19*8(X2)
-       MOV     X25, 20*8(X2)
-       MOV     X26, 21*8(X2)
+       MOV     X12, 6*8(X2)
+       MOV     X13, 7*8(X2)
+       MOV     X14, 8*8(X2)
+       MOV     X15, 9*8(X2)
+       MOV     X16, 10*8(X2)
+       MOV     X17, 11*8(X2)
+       MOV     X18, 12*8(X2)
+       MOV     X19, 13*8(X2)
+       MOV     X20, 14*8(X2)
+       MOV     X21, 15*8(X2)
+       MOV     X22, 16*8(X2)
+       MOV     X23, 17*8(X2)
+       MOV     X24, 18*8(X2)
+       MOV     X25, 19*8(X2)
+       MOV     X26, 20*8(X2)
        // X27 is g.
-       MOV     X28, 22*8(X2)
-       MOV     X29, 23*8(X2)
-       MOV     X30, 24*8(X2)
+       MOV     X28, 21*8(X2)
+       MOV     X29, 22*8(X2)
+       MOV     X30, 23*8(X2)
        // X31 is tmp register.
 
        // This takes arguments T0 and T1.
@@ -696,28 +699,27 @@ flush:
 
        MOV     1*8(X2), T0
        MOV     2*8(X2), T1
-       MOV     3*8(X2), X3
-       MOV     4*8(X2), X7
-       MOV     5*8(X2), X8
-       MOV     6*8(X2), X9
-       MOV     7*8(X2), X12
-       MOV     8*8(X2), X13
-       MOV     9*8(X2), X14
-       MOV     10*8(X2), X15
-       MOV     11*8(X2), X16
-       MOV     12*8(X2), X17
-       MOV     13*8(X2), X18
-       MOV     14*8(X2), X19
-       MOV     15*8(X2), X20
-       MOV     16*8(X2), X21
-       MOV     17*8(X2), X22
-       MOV     18*8(X2), X23
-       MOV     19*8(X2), X24
-       MOV     20*8(X2), X25
-       MOV     21*8(X2), X26
-       MOV     22*8(X2), X28
-       MOV     23*8(X2), X29
-       MOV     24*8(X2), X30
+       MOV     3*8(X2), X7
+       MOV     4*8(X2), X8
+       MOV     5*8(X2), X9
+       MOV     6*8(X2), X12
+       MOV     7*8(X2), X13
+       MOV     8*8(X2), X14
+       MOV     9*8(X2), X15
+       MOV     10*8(X2), X16
+       MOV     11*8(X2), X17
+       MOV     12*8(X2), X18
+       MOV     13*8(X2), X19
+       MOV     14*8(X2), X20
+       MOV     15*8(X2), X21
+       MOV     16*8(X2), X22
+       MOV     17*8(X2), X23
+       MOV     18*8(X2), X24
+       MOV     19*8(X2), X25
+       MOV     20*8(X2), X26
+       MOV     21*8(X2), X28
+       MOV     22*8(X2), X29
+       MOV     23*8(X2), X30
 
        JMP     ret
 
index d4110d563f444efc1142eaba94b0f0c76b2dfab0..5894fe5783113e6717233aaf1a09afcfebdce4d1 100644 (file)
@@ -513,12 +513,15 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 
        // Figure out if we need to switch to m->g0 stack.
        // We get called to create new OS threads too, and those
-       // come in on the m->g0 stack already.
+       // come in on the m->g0 stack already. Or we might already
+       // be on the m->gsignal stack.
        MOVD    g_m(g), R6
-       MOVD    m_g0(R6), R6
-       CMPBEQ  R6, g, g0
+       MOVD    m_gsignal(R6), R7
+       CMPBEQ  R7, g, g0
+       MOVD    m_g0(R6), R7
+       CMPBEQ  R7, g, g0
        BL      gosave_systemstack_switch<>(SB)
-       MOVD    R6, g
+       MOVD    R7, g
        BL      runtime·save_g(SB)
        MOVD    (g_sched+gobuf_sp)(g), R15
 
index 3178f1a154cec36bafe578cb6379b2b452316454..5d473cab5ca482c1a16fc491caef8869e7a2717e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !solaris
-// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!solaris
 
 package runtime
 
index fcd1d36ca84f8060c22489e69701e32494dd3252..45151bf02bacbea6c09e2e5a72ff9b29a209d570 100644 (file)
@@ -14,7 +14,7 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
         * registers. Note that at procedure entry the first argument is at
         * 8(X2).
         */
-       ADD     $(-8*31), X2
+       ADD     $(-8*29), X2
        MOV     X10, (8*1)(X2) // fn unsafe.Pointer
        MOV     X11, (8*2)(X2) // a unsafe.Pointer
        MOV     X13, (8*3)(X2) // ctxt uintptr
@@ -30,21 +30,19 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
        MOV     X25, (8*13)(X2)
        MOV     X26, (8*14)(X2)
        MOV     g, (8*15)(X2)
-       MOV     X3, (8*16)(X2)
-       MOV     X4, (8*17)(X2)
-       MOV     X1, (8*18)(X2)
-       MOVD    F8, (8*19)(X2)
-       MOVD    F9, (8*20)(X2)
-       MOVD    F18, (8*21)(X2)
-       MOVD    F19, (8*22)(X2)
-       MOVD    F20, (8*23)(X2)
-       MOVD    F21, (8*24)(X2)
-       MOVD    F22, (8*25)(X2)
-       MOVD    F23, (8*26)(X2)
-       MOVD    F24, (8*27)(X2)
-       MOVD    F25, (8*28)(X2)
-       MOVD    F26, (8*29)(X2)
-       MOVD    F27, (8*30)(X2)
+       MOV     X1, (8*16)(X2)
+       MOVD    F8, (8*17)(X2)
+       MOVD    F9, (8*18)(X2)
+       MOVD    F18, (8*19)(X2)
+       MOVD    F19, (8*20)(X2)
+       MOVD    F20, (8*21)(X2)
+       MOVD    F21, (8*22)(X2)
+       MOVD    F22, (8*23)(X2)
+       MOVD    F23, (8*24)(X2)
+       MOVD    F24, (8*25)(X2)
+       MOVD    F25, (8*26)(X2)
+       MOVD    F26, (8*27)(X2)
+       MOVD    F27, (8*28)(X2)
 
        // Initialize Go ABI environment
        CALL    runtime·load_g(SB)
@@ -62,21 +60,19 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
        MOV     (8*13)(X2), X25
        MOV     (8*14)(X2), X26
        MOV     (8*15)(X2), g
-       MOV     (8*16)(X2), X3
-       MOV     (8*17)(X2), X4
-       MOV     (8*18)(X2), X1
-       MOVD    (8*19)(X2), F8
-       MOVD    (8*20)(X2), F9
-       MOVD    (8*21)(X2), F18
-       MOVD    (8*22)(X2), F19
-       MOVD    (8*23)(X2), F20
-       MOVD    (8*24)(X2), F21
-       MOVD    (8*25)(X2), F22
-       MOVD    (8*26)(X2), F23
-       MOVD    (8*27)(X2), F24
-       MOVD    (8*28)(X2), F25
-       MOVD    (8*29)(X2), F26
-       MOVD    (8*30)(X2), F27
-       ADD     $(8*31), X2
+       MOV     (8*16)(X2), X1
+       MOVD    (8*17)(X2), F8
+       MOVD    (8*18)(X2), F9
+       MOVD    (8*19)(X2), F18
+       MOVD    (8*20)(X2), F19
+       MOVD    (8*21)(X2), F20
+       MOVD    (8*22)(X2), F21
+       MOVD    (8*23)(X2), F22
+       MOVD    (8*24)(X2), F23
+       MOVD    (8*25)(X2), F24
+       MOVD    (8*26)(X2), F25
+       MOVD    (8*27)(X2), F26
+       MOVD    (8*28)(X2), F27
+       ADD     $(8*29), X2
 
        RET
index 7302c1eedfa64625d03e3eef41c35aef4605c882..dae31a8fcde16c79a3f9bc2f8bbbcf2068455b4f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || linux
-// +build darwin linux
 
 package cgo
 
index cfa6fe86e2f360e04bba3edc5037b57387c56af9..36d70e34e2d39f0d4eb4cea3221d1fe5c2d31cbb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly
-// +build dragonfly
 
 package cgo
 
index d56702ec704b2ac5e48805855d7556d6e1fab787..2d9f6245b5436096ae3105845c49b565c95d9ea1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd
-// +build freebsd
 
 package cgo
 
index dd283151f17055c1061f1e2e850e62534de489e6..fcf1e50740e855765a2ff471472e8e3fdca53cc5 100644 (file)
@@ -49,13 +49,13 @@ x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *ol
                sigemptyset(&act.sa_mask);
                for (i = 0; i < 8 * sizeof(goact->mask); i++) {
                        if (goact->mask & ((uint64_t)(1)<<i)) {
-                               sigaddset(&act.sa_mask, i+1);
+                               sigaddset(&act.sa_mask, (int)(i+1));
                        }
                }
-               act.sa_flags = goact->flags & ~SA_RESTORER;
+               act.sa_flags = (int)(goact->flags & ~(uint64_t)SA_RESTORER);
        }
 
-       ret = sigaction(signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
+       ret = sigaction((int)signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
        if (ret == -1) {
                // runtime.rt_sigaction expects _cgo_sigaction to return errno on error.
                _cgo_tsan_release();
@@ -70,11 +70,11 @@ x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *ol
                }
                oldgoact->mask = 0;
                for (i = 0; i < 8 * sizeof(oldgoact->mask); i++) {
-                       if (sigismember(&oldact.sa_mask, i+1) == 1) {
+                       if (sigismember(&oldact.sa_mask, (int)(i+1)) == 1) {
                                oldgoact->mask |= (uint64_t)(1)<<i;
                        }
                }
-               oldgoact->flags = oldact.sa_flags;
+               oldgoact->flags = (uint64_t)oldact.sa_flags;
        }
 
        _cgo_tsan_release();
index 070d531beeb5d7cb12464bbc40837b1d4e36a6ee..1d6fe03917b819de0d0806605eed83a1d742874e 100644 (file)
@@ -6,7 +6,6 @@
 // corresponding cgo->libc (nptl) wrappers for various system calls.
 
 //go:build linux
-// +build linux
 
 package cgo
 
index 347ae6b363f0023f69cc146afe688278d4fe7b89..eae0a9e7cc859d2339fd48bed0b299e991ca564b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (linux && amd64) || (linux && arm64)
-// +build linux,amd64 linux,arm64
 
 package cgo
 
index 7e17d1fcd257069849d372845ecd0747489fdb8f..8a8018b7a89b5c8dd47eeb48990b4db314a616d5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build netbsd
-// +build netbsd
 
 package cgo
 
index f6215613c33419caa3e4ac6eb54249c307e9ca2c..872d02e3345bf3d7e0f7c6cb03492eda477f5370 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd
-// +build openbsd
 
 package cgo
 
index e6e8040ae088c8dec9d3dfecc92ffc38664e034d..0f4780a945810819f27cdd31e538d894172f8cef 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package cgo
 
index 692fd2675f9475febed88480b615584c2d663fef..dc714f7ef4a3b08b06231a534591fa6b3c92a46e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le)
-// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le
 
 package cgo
 
index 17d26b4cc82f66569eed91fde308f41ec157b8c1..0cb25bdcdab3227b04b91fa0099dcbbfe9edaf5e 100644 (file)
@@ -5,7 +5,6 @@
 // Support for memory sanitizer. See runtime/cgo/mmap.go.
 
 //go:build (linux && amd64) || (linux && arm64)
-// +build linux,amd64 linux,arm64
 
 package runtime
 
index 4dc92ea3211b87d39863c0da10c684cfed8a1786..97b962e40f69f80afe3ade4afe123a64710c6607 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package runtime
 
index 6099d1b746f80a3803c9e21c2d3a19125168b18c..a2e12f0f0e272eb65ff97a340e74308cc4e49b1b 100644 (file)
@@ -5,7 +5,6 @@
 // Support for sanitizers. See runtime/cgo/sigaction.go.
 
 //go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le)
-// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le
 
 package runtime
 
@@ -28,7 +27,9 @@ func sigaction(sig uint32, new, old *sigactiont) {
        if msanenabled && new != nil {
                msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
        }
-
+       if asanenabled && new != nil {
+               asanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
+       }
        if _cgo_sigaction == nil || inForkedChild {
                sysSigaction(sig, new, old)
        } else {
@@ -80,6 +81,9 @@ func sigaction(sig uint32, new, old *sigactiont) {
        if msanenabled && old != nil {
                msanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
        }
+       if asanenabled && old != nil {
+               asanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
+       }
 }
 
 // callCgoSigaction calls the sigaction function in the runtime/cgo package
index 2f3c609907649b2e385e98ab03183a02efc56a0a..694b3e66cd519dd7170430a51775b994cccdfcc2 100644 (file)
@@ -291,6 +291,13 @@ func cgocallbackg1(fn, frame unsafe.Pointer, ctxt uintptr) {
                <-main_init_done
        }
 
+       // Check whether the profiler needs to be turned on or off; this route to
+       // run Go code does not use runtime.execute, so bypasses the check there.
+       hz := sched.profilehz
+       if gp.m.profilehz != hz {
+               setThreadCPUProfiler(hz)
+       }
+
        // Add entry to defer stack in case of panic.
        restore := true
        defer unwindm(&restore)
index d5dd101adbe051164a9f23f858dfd46d99f29c66..b3aea079c66a25bb92747e5f8191e12050d1df47 100644 (file)
@@ -55,3 +55,40 @@ func TestCheckPtr(t *testing.T) {
                })
        }
 }
+
+func TestCheckPtr2(t *testing.T) {
+       t.Parallel()
+       testenv.MustHaveGoRun(t)
+
+       exe, err := buildTestProg(t, "testprog", "-gcflags=all=-d=checkptr=2")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       testCases := []struct {
+               cmd  string
+               want string
+       }{
+               {"CheckPtrAlignmentNested", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
+       }
+
+       for _, tc := range testCases {
+               tc := tc
+               t.Run(tc.cmd, func(t *testing.T) {
+                       t.Parallel()
+                       got, err := testenv.CleanCmdEnv(exec.Command(exe, tc.cmd)).CombinedOutput()
+                       if err != nil {
+                               t.Log(err)
+                       }
+                       if tc.want == "" {
+                               if len(got) > 0 {
+                                       t.Errorf("output:\n%s\nwant no output", got)
+                               }
+                               return
+                       }
+                       if !strings.HasPrefix(string(got), tc.want) {
+                               t.Errorf("output:\n%s\n\nwant output starting with: %s", got, tc.want)
+                       }
+               })
+       }
+}
index 5104650c5d73e824ee1bc79b9a0db171d23b1002..bbe93c5bea2d7e46d752b25ebfca2e7b1640bdd6 100644 (file)
@@ -11,10 +11,10 @@ import (
 
 // Offsets into internal/cpu records for use in assembly.
 const (
-       offsetX86HasAVX  = unsafe.Offsetof(cpu.X86.HasAVX)
-       offsetX86HasAVX2 = unsafe.Offsetof(cpu.X86.HasAVX2)
-       offsetX86HasERMS = unsafe.Offsetof(cpu.X86.HasERMS)
-       offsetX86HasSSE2 = unsafe.Offsetof(cpu.X86.HasSSE2)
+       offsetX86HasAVX    = unsafe.Offsetof(cpu.X86.HasAVX)
+       offsetX86HasAVX2   = unsafe.Offsetof(cpu.X86.HasAVX2)
+       offsetX86HasERMS   = unsafe.Offsetof(cpu.X86.HasERMS)
+       offsetX86HasRDTSCP = unsafe.Offsetof(cpu.X86.HasRDTSCP)
 
        offsetARMHasIDIVA = unsafe.Offsetof(cpu.ARM.HasIDIVA)
 
index 7c926f4a2b88248e1fc3d6b2946b7b905553f991..2cf324033338d5d8699a32eabb8258be10493b4c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !arm && !arm64 && !mips64 && !mips64le && !mips && !mipsle && !wasm
-// +build !arm,!arm64,!mips64,!mips64le,!mips,!mipsle,!wasm
 
 package runtime
 
index 5729942cee3bfb36b0e0152059aa607155c23aef..e6d1742a384a63549e10a8cdb3437b9d96d2c4d7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build cgo
-// +build cgo
 
 package runtime_test
 
@@ -526,13 +525,38 @@ func TestCgoTracebackSigpanic(t *testing.T) {
        }
        t.Parallel()
        got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
+       t.Log(got)
        want := "runtime.sigpanic"
        if !strings.Contains(got, want) {
-               t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
+               t.Errorf("did not see %q in output", want)
        }
-       nowant := "unexpected return pc"
+       // No runtime errors like "runtime: unexpected return pc".
+       nowant := "runtime: "
        if strings.Contains(got, nowant) {
-               t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
+               t.Errorf("unexpectedly saw %q in output", nowant)
+       }
+}
+
+func TestCgoPanicCallback(t *testing.T) {
+       t.Parallel()
+       got := runTestProg(t, "testprogcgo", "PanicCallback")
+       t.Log(got)
+       want := "panic: runtime error: invalid memory address or nil pointer dereference"
+       if !strings.Contains(got, want) {
+               t.Errorf("did not see %q in output", want)
+       }
+       want = "panic_callback"
+       if !strings.Contains(got, want) {
+               t.Errorf("did not see %q in output", want)
+       }
+       want = "PanicCallback"
+       if !strings.Contains(got, want) {
+               t.Errorf("did not see %q in output", want)
+       }
+       // No runtime errors like "runtime: unexpected return pc".
+       nowant := "runtime: "
+       if strings.Contains(got, nowant) {
+               t.Errorf("did not see %q in output", want)
        }
 }
 
@@ -591,17 +615,54 @@ func TestSegv(t *testing.T) {
        }
 
        for _, test := range []string{"Segv", "SegvInCgo"} {
+               test := test
                t.Run(test, func(t *testing.T) {
                        t.Parallel()
                        got := runTestProg(t, "testprogcgo", test)
                        t.Log(got)
-                       if !strings.Contains(got, "SIGSEGV") {
-                               t.Errorf("expected crash from signal")
+                       want := "SIGSEGV"
+                       if !strings.Contains(got, want) {
+                               t.Errorf("did not see %q in output", want)
+                       }
+
+                       // No runtime errors like "runtime: unknown pc".
+                       switch runtime.GOOS {
+                       case "darwin", "illumos", "solaris":
+                               // TODO(golang.org/issue/49182): Skip, runtime
+                               // throws while attempting to generate
+                               // traceback.
+                       default:
+                               nowant := "runtime: "
+                               if strings.Contains(got, nowant) {
+                                       t.Errorf("unexpectedly saw %q in output", nowant)
+                               }
                        }
                })
        }
 }
 
+func TestAbortInCgo(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               // N.B. On Windows, C abort() causes the program to exit
+               // without going through the runtime at all.
+               t.Skipf("no signals on %s", runtime.GOOS)
+       }
+
+       t.Parallel()
+       got := runTestProg(t, "testprogcgo", "Abort")
+       t.Log(got)
+       want := "SIGABRT"
+       if !strings.Contains(got, want) {
+               t.Errorf("did not see %q in output", want)
+       }
+       // No runtime errors like "runtime: unknown pc".
+       nowant := "runtime: "
+       if strings.Contains(got, nowant) {
+               t.Errorf("did not see %q in output", want)
+       }
+}
+
 // TestEINTR tests that we handle EINTR correctly.
 // See issue #20400 and friends.
 func TestEINTR(t *testing.T) {
index 5f61476f217069a841cb0e3d4d62822d24fdeba0..73c1cd3101f0533a766d53944a347d2f71eb3bc4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows || plan9 || (js && wasm)
-// +build windows plan9 js,wasm
 
 package runtime_test
 
index 694cc3d138b73e42640b23f31785f8f67f005200..0d9d22aa49ff31b33885648b6a7ee95b5fa229ab 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime_test
 
index 82deefa200cdf7cf68d1af6fe7cd48534423d1ca..2703a0ce019d3f41f88caefd1fe95b0ff0e1a222 100644 (file)
@@ -61,3 +61,56 @@ func NumGoroutine() int {
 func debug_modinfo() string {
        return modinfo
 }
+
+// mayMoreStackPreempt is a maymorestack hook that forces a preemption
+// at every possible cooperative preemption point.
+//
+// This is valuable to apply to the runtime, which can be sensitive to
+// preemption points. To apply this to all preemption points in the
+// runtime and runtime-like code, use the following in bash or zsh:
+//
+//   X=(-{gc,asm}flags={runtime/...,reflect,sync}=-d=maymorestack=runtime.mayMoreStackPreempt) GOFLAGS=${X[@]}
+//
+// This must be deeply nosplit because it is called from a function
+// prologue before the stack is set up and because the compiler will
+// call it from any splittable prologue (leading to infinite
+// recursion).
+//
+// Ideally it should also use very little stack because the linker
+// doesn't currently account for this in nosplit stack depth checking.
+//
+//go:nosplit
+//
+// Ensure mayMoreStackPreempt can be called for all ABIs.
+//
+//go:linkname mayMoreStackPreempt
+func mayMoreStackPreempt() {
+       // Don't do anything on the g0 or gsignal stack.
+       g := getg()
+       if g == g.m.g0 || g == g.m.gsignal {
+               return
+       }
+       // Force a preemption, unless the stack is already poisoned.
+       if g.stackguard0 < stackPoisonMin {
+               g.stackguard0 = stackPreempt
+       }
+}
+
+// mayMoreStackMove is a maymorestack hook that forces stack movement
+// at every possible point.
+//
+// See mayMoreStackPreempt.
+//
+//go:nosplit
+//go:linkname mayMoreStackMove
+func mayMoreStackMove() {
+       // Don't do anything on the g0 or gsignal stack.
+       g := getg()
+       if g == g.m.g0 || g == g.m.gsignal {
+               return
+       }
+       // Force stack movement, unless the stack is already poisoned.
+       if g.stackguard0 < stackPoisonMin {
+               g.stackguard0 = stackForceMove
+       }
+}
index 0381bdcc53951c64b6277277467ca896c8863941..14b99f573549913ca145ffc93bcdcac292a2a242 100644 (file)
@@ -5,6 +5,9 @@
 package debug
 
 import (
+       "bytes"
+       "fmt"
+       "runtime"
        "strings"
 )
 
@@ -15,15 +18,32 @@ func modinfo() string
 // in the running binary. The information is available only
 // in binaries built with module support.
 func ReadBuildInfo() (info *BuildInfo, ok bool) {
-       return readBuildInfo(modinfo())
+       data := modinfo()
+       if len(data) < 32 {
+               return nil, false
+       }
+       data = data[16 : len(data)-16]
+       bi := &BuildInfo{}
+       if err := bi.UnmarshalText([]byte(data)); err != nil {
+               return nil, false
+       }
+
+       // The go version is stored separately from other build info, mostly for
+       // historical reasons. It is not part of the modinfo() string, and
+       // ParseBuildInfo does not recognize it. We inject it here to hide this
+       // awkwardness from the user.
+       bi.GoVersion = runtime.Version()
+
+       return bi, true
 }
 
-// BuildInfo represents the build information read from
-// the running binary.
+// BuildInfo represents the build information read from a Go binary.
 type BuildInfo struct {
-       Path string    // The main package path
-       Main Module    // The module containing the main package
-       Deps []*Module // Module dependencies
+       GoVersion string         // Version of Go that produced this binary.
+       Path      string         // The main package path
+       Main      Module         // The module containing the main package
+       Deps      []*Module      // Module dependencies
+       Settings  []BuildSetting // Other information about the build.
 }
 
 // Module represents a module.
@@ -34,81 +54,147 @@ type Module struct {
        Replace *Module // replaced by this module
 }
 
-func readBuildInfo(data string) (*BuildInfo, bool) {
-       if len(data) < 32 {
-               return nil, false
+// BuildSetting describes a setting that may be used to understand how the
+// binary was built. For example, VCS commit and dirty status is stored here.
+type BuildSetting struct {
+       // Key and Value describe the build setting. They must not contain tabs
+       // or newlines.
+       Key, Value string
+}
+
+func (bi *BuildInfo) MarshalText() ([]byte, error) {
+       buf := &bytes.Buffer{}
+       if bi.GoVersion != "" {
+               fmt.Fprintf(buf, "go\t%s\n", bi.GoVersion)
+       }
+       if bi.Path != "" {
+               fmt.Fprintf(buf, "path\t%s\n", bi.Path)
+       }
+       var formatMod func(string, Module)
+       formatMod = func(word string, m Module) {
+               buf.WriteString(word)
+               buf.WriteByte('\t')
+               buf.WriteString(m.Path)
+               mv := m.Version
+               if mv == "" {
+                       mv = "(devel)"
+               }
+               buf.WriteByte('\t')
+               buf.WriteString(mv)
+               if m.Replace == nil {
+                       buf.WriteByte('\t')
+                       buf.WriteString(m.Sum)
+               } else {
+                       buf.WriteByte('\n')
+                       formatMod("=>", *m.Replace)
+               }
+               buf.WriteByte('\n')
+       }
+       if bi.Main.Path != "" {
+               formatMod("mod", bi.Main)
+       }
+       for _, dep := range bi.Deps {
+               formatMod("dep", *dep)
+       }
+       for _, s := range bi.Settings {
+               if strings.ContainsAny(s.Key, "\n\t") || strings.ContainsAny(s.Value, "\n\t") {
+                       return nil, fmt.Errorf("build setting %q contains tab or newline", s.Key)
+               }
+               fmt.Fprintf(buf, "build\t%s\t%s\n", s.Key, s.Value)
        }
-       data = data[16 : len(data)-16]
 
-       const (
-               pathLine = "path\t"
-               modLine  = "mod\t"
-               depLine  = "dep\t"
-               repLine  = "=>\t"
+       return buf.Bytes(), nil
+}
+
+func (bi *BuildInfo) UnmarshalText(data []byte) (err error) {
+       *bi = BuildInfo{}
+       lineNum := 1
+       defer func() {
+               if err != nil {
+                       err = fmt.Errorf("could not parse Go build info: line %d: %w", lineNum, err)
+               }
+       }()
+
+       var (
+               pathLine  = []byte("path\t")
+               modLine   = []byte("mod\t")
+               depLine   = []byte("dep\t")
+               repLine   = []byte("=>\t")
+               buildLine = []byte("build\t")
+               newline   = []byte("\n")
+               tab       = []byte("\t")
        )
 
-       readEntryFirstLine := func(elem []string) (Module, bool) {
+       readModuleLine := func(elem [][]byte) (Module, error) {
                if len(elem) != 2 && len(elem) != 3 {
-                       return Module{}, false
+                       return Module{}, fmt.Errorf("expected 2 or 3 columns; got %d", len(elem))
                }
                sum := ""
                if len(elem) == 3 {
-                       sum = elem[2]
+                       sum = string(elem[2])
                }
                return Module{
-                       Path:    elem[0],
-                       Version: elem[1],
+                       Path:    string(elem[0]),
+                       Version: string(elem[1]),
                        Sum:     sum,
-               }, true
+               }, nil
        }
 
        var (
-               info = &BuildInfo{}
                last *Module
-               line string
+               line []byte
                ok   bool
        )
-       // Reverse of cmd/go/internal/modload.PackageBuildInfo
+       // Reverse of BuildInfo.String(), except for go version.
        for len(data) > 0 {
-               i := strings.IndexByte(data, '\n')
-               if i < 0 {
+               line, data, ok = bytes.Cut(data, newline)
+               if !ok {
                        break
                }
-               line, data = data[:i], data[i+1:]
                switch {
-               case strings.HasPrefix(line, pathLine):
+               case bytes.HasPrefix(line, pathLine):
                        elem := line[len(pathLine):]
-                       info.Path = elem
-               case strings.HasPrefix(line, modLine):
-                       elem := strings.Split(line[len(modLine):], "\t")
-                       last = &info.Main
-                       *last, ok = readEntryFirstLine(elem)
-                       if !ok {
-                               return nil, false
+                       bi.Path = string(elem)
+               case bytes.HasPrefix(line, modLine):
+                       elem := bytes.Split(line[len(modLine):], tab)
+                       last = &bi.Main
+                       *last, err = readModuleLine(elem)
+                       if err != nil {
+                               return err
                        }
-               case strings.HasPrefix(line, depLine):
-                       elem := strings.Split(line[len(depLine):], "\t")
+               case bytes.HasPrefix(line, depLine):
+                       elem := bytes.Split(line[len(depLine):], tab)
                        last = new(Module)
-                       info.Deps = append(info.Deps, last)
-                       *last, ok = readEntryFirstLine(elem)
-                       if !ok {
-                               return nil, false
+                       bi.Deps = append(bi.Deps, last)
+                       *last, err = readModuleLine(elem)
+                       if err != nil {
+                               return err
                        }
-               case strings.HasPrefix(line, repLine):
-                       elem := strings.Split(line[len(repLine):], "\t")
+               case bytes.HasPrefix(line, repLine):
+                       elem := bytes.Split(line[len(repLine):], tab)
                        if len(elem) != 3 {
-                               return nil, false
+                               return fmt.Errorf("expected 3 columns for replacement; got %d", len(elem))
                        }
                        if last == nil {
-                               return nil, false
+                               return fmt.Errorf("replacement with no module on previous line")
                        }
                        last.Replace = &Module{
-                               Path:    elem[0],
-                               Version: elem[1],
-                               Sum:     elem[2],
+                               Path:    string(elem[0]),
+                               Version: string(elem[1]),
+                               Sum:     string(elem[2]),
                        }
                        last = nil
+               case bytes.HasPrefix(line, buildLine):
+                       elem := bytes.Split(line[len(buildLine):], tab)
+                       if len(elem) != 2 {
+                               return fmt.Errorf("expected 2 columns for build setting; got %d", len(elem))
+                       }
+                       if len(elem[0]) == 0 {
+                               return fmt.Errorf("empty key")
+                       }
+                       bi.Settings = append(bi.Settings, BuildSetting{Key: string(elem[0]), Value: string(elem[1])})
                }
+               lineNum++
        }
-       return info, true
+       return nil
 }
index 65f9555f3761c55022fe2a4e8ddc7ebf58e1207e..ec5294ce4ce7662934c0d9063fd4a940cf6d8303 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build aix darwin dragonfly freebsd linux netbsd openbsd
 
 // TODO: test on Windows?
 
index f74383457f36765f07fb3ed9e8a41d461b37e16d..b5db7a55f1b261c34ddb62fe20eec21cb70e5de0 100644 (file)
@@ -10,7 +10,6 @@
 // point.
 
 //go:build amd64 && linux && !race
-// +build amd64,linux,!race
 
 package runtime_test
 
index ad66a18c26ce74bd9a1580d6090ae16a3ac72947..005a259f2831cdb56925a59acdfaad54bde44000 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64
-// +build amd64
 
 package runtime
 
@@ -78,7 +77,7 @@ func debugCallCheck(pc uintptr) string {
                }
 
                // Check that this isn't an unsafe-point.
-               if pc != f.entry {
+               if pc != f.entry() {
                        pc--
                }
                up := pcdatavalue(f, _PCDATA_UnsafePoint, pc, nil)
index 3ce3273f4def09707d447e42e79dea6ef1d6221c..588b54d1f5d8fe96d305f1a0be1179d0f483d887 100644 (file)
@@ -802,7 +802,7 @@ func printDebugLog() {
 // pc is a return PC that must first be converted to a call PC.
 func printDebugLogPC(pc uintptr, returnPC bool) {
        fn := findfunc(pc)
-       if returnPC && (!fn.valid() || pc > fn.entry) {
+       if returnPC && (!fn.valid() || pc > fn.entry()) {
                // TODO(austin): Don't back up if the previous frame
                // was a sigpanic.
                pc--
@@ -814,7 +814,7 @@ func printDebugLogPC(pc uintptr, returnPC bool) {
        } else {
                name := funcname(fn)
                file, line := funcline(fn, pc)
-               print(" [", name, "+", hex(pc-fn.entry),
+               print(" [", name, "+", hex(pc-fn.entry()),
                        " ", file, ":", line, "]")
        }
 }
index dd3815699929411a86170237417b1f4f6b6e0656..fa3be39c70f83449c279caa070bc07aaa6f718c4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !debuglog
-// +build !debuglog
 
 package runtime
 
index 2fcdbe70d14428e4f805f27b360a69e062661e90..b8150202251b36eeda9d16244e26da2aee0bab08 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build debuglog
-// +build debuglog
 
 package runtime
 
index fc961445975867b219812a9f6846790a5dc1996c..1d5745d60b5c6995c528d52ec8e5387d2dbaaeed 100644 (file)
@@ -438,3 +438,82 @@ func expect(t *testing.T, n int, err interface{}) {
                t.Fatalf("have %v, want %v", err, n)
        }
 }
+
+func TestIssue43920(t *testing.T) {
+       var steps int
+
+       defer func() {
+               expect(t, 1, recover())
+       }()
+       defer func() {
+               defer func() {
+                       defer func() {
+                               expect(t, 5, recover())
+                       }()
+                       defer panic(5)
+                       func() {
+                               panic(4)
+                       }()
+               }()
+               defer func() {
+                       expect(t, 3, recover())
+               }()
+               defer panic(3)
+       }()
+       func() {
+               defer step(t, &steps, 1)
+               panic(1)
+       }()
+}
+
+func step(t *testing.T, steps *int, want int) {
+       println("step", want)
+       *steps++
+       if *steps != want {
+               t.Fatalf("have %v, want %v", *steps, want)
+       }
+}
+
+func TestIssue43941(t *testing.T) {
+       var steps int = 7
+       defer func() {
+               step(t, &steps, 14)
+               expect(t, 4, recover())
+       }()
+       func() {
+               func() {
+                       defer func() {
+                               defer func() {
+                                       expect(t, 3, recover())
+                               }()
+                               defer panic(3)
+                               panic(2)
+                       }()
+                       defer func() {
+                               expect(t, 1, recover())
+                       }()
+                       defer panic(1)
+               }()
+               defer func() {}()
+               defer func() {}()
+               defer step(t, &steps, 10)
+               defer step(t, &steps, 9)
+               step(t, &steps, 8)
+       }()
+       func() {
+               defer step(t, &steps, 13)
+               defer step(t, &steps, 12)
+               func() {
+                       defer step(t, &steps, 11)
+                       panic(4)
+               }()
+
+               // Code below isn't executed,
+               // but removing it breaks the test case.
+               defer func() {}()
+               defer panic(-1)
+               defer step(t, &steps, -1)
+               defer step(t, &steps, -1)
+               defer func() {}()
+       }()
+}
index df9c05dd5ed14702dabc22ff20e849c55c5bbf02..709f19e599910d2f8035a9956ef422cbdfa6f375 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -cdefs
index d016db7d027cf624c1cabe9553b6554ddf13aef6..41ad73576f15af06b2ca6fed5f347459c0a4eaa0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
  * Input to cgo -cdefs
index 0a06aa2370725b4f8c354007a30bf673687200a3..99479aad06191ebb496c0bde0a5fa72c26c41f17 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -cdefs
index 1605002ea20b9dbd21602efc904178c8742ff945..b794cd5de8b2da354cdd988cdbc14850daa42cc4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs
index f84ff1160d0df517db666395640e55293c83a9e2..4e20c858411d9b344d9fb1032fda46a51b4f7941 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix
-// +build aix
 
 package runtime
 
index f6b6dd2c09e58a6529f7f95bda3deb9c3bb659b6..805735bd0eef8c68f705bd9ecdaa5bf6c6b94455 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index 2d41a97b5741b0630ed9027a93551d97cca31a84..59b81cf7136e24ba11bb42b7ec4e5f7813f60ca4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index aca2bf9001e82a296cffcaa0707edce29ddc7a58..47a2e4d1232537d1a3606c7c62c93f92662afb3b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index c258759549c8b96ace028097d6bc1c2431c1b820..9ba97c84596bd30d4e2eaa8110e5303c255d0561 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index 022ef19427e1885ff19d37145b0e368c2350e540..fa94e388f45bbdd35341a678b6592dc5a44da4c1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -cdefs
@@ -58,6 +57,9 @@ const (
        SA_ONSTACK = C.SA_ONSTACK
        SA_SIGINFO = C.SA_SIGINFO
 
+       SI_KERNEL = C.SI_KERNEL
+       SI_TIMER  = C.SI_TIMER
+
        SIGHUP    = C.SIGHUP
        SIGINT    = C.SIGINT
        SIGQUIT   = C.SIGQUIT
@@ -109,6 +111,10 @@ const (
        ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
        ITIMER_PROF    = C.ITIMER_PROF
 
+       CLOCK_THREAD_CPUTIME_ID = C.CLOCK_THREAD_CPUTIME_ID
+
+       SIGEV_THREAD_ID = C.SIGEV_THREAD_ID
+
        EPOLLIN       = C.POLLIN
        EPOLLOUT      = C.POLLOUT
        EPOLLERR      = C.POLLERR
@@ -126,5 +132,7 @@ type Timespec C.struct_timespec
 type Timeval C.struct_timeval
 type Sigaction C.struct_sigaction
 type Siginfo C.siginfo_t
+type Itimerspec C.struct_itimerspec
 type Itimerval C.struct_itimerval
+type Sigevent C.struct_sigevent
 type EpollEvent C.struct_epoll_event
index 64a0fbcaaaa5f0ae539f8af1cf6ba5bb18013190..24fb58bbf8db695eae5bf9c2bf0da4aae80c2c06 100644 (file)
@@ -3,6 +3,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -28,6 +30,9 @@ const (
        _SA_RESTORER = 0x4000000
        _SA_SIGINFO  = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -79,6 +84,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _O_RDONLY   = 0x0
        _O_NONBLOCK = 0x800
        _O_CLOEXEC  = 0x80000
@@ -159,7 +168,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -167,6 +176,13 @@ type siginfo struct {
        si_addr uint32
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
 type stackt struct {
        ss_sp    *byte
        ss_flags int32
@@ -212,11 +228,31 @@ type ucontext struct {
        uc_sigmask  uint32
 }
 
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events uint32
        data   [8]byte // to match amd64
index 1ae18a309bd70c6bb68d61f940b34a2827f050ed..36da22f8cedb78541dd89f4ea58d23f5831a8879 100644 (file)
@@ -3,6 +3,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -28,6 +30,9 @@ const (
        _SA_RESTORER = 0x4000000
        _SA_SIGINFO  = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -79,6 +84,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -121,7 +130,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -129,11 +138,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events uint32
        data   [8]byte // unaligned uintptr
index 5bc0916f8b66ca96e052d165797af86c34c2c2e1..13d06969e3dea42123ac2cccac491eb9f9f361b0 100644 (file)
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 // Constants
 const (
        _EINTR  = 0x4
@@ -29,6 +31,8 @@ const (
        _SA_ONSTACK     = 0x8000000
        _SA_RESTORER    = 0 // unused on ARM
        _SA_SIGINFO     = 0x4
+       _SI_KERNEL      = 0x80
+       _SI_TIMER       = -0x2
        _SIGHUP         = 0x1
        _SIGINT         = 0x2
        _SIGQUIT        = 0x3
@@ -79,6 +83,10 @@ const (
        _O_NONBLOCK     = 0x800
        _O_CLOEXEC      = 0x80000
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -153,12 +161,32 @@ func (tv *timeval) set_usec(x int32) {
        tv.tv_usec = x
 }
 
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
-type siginfo struct {
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -166,6 +194,13 @@ type siginfo struct {
        si_addr uint32
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
 type sigactiont struct {
        sa_handler  uintptr
        sa_flags    uint32
index 0690cd35b2e07e60f3a9eabcdda9578d73f73b36..f9ee9cbc35aea63a1b26993ecedcccea6ec70175 100644 (file)
@@ -3,6 +3,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -28,6 +30,9 @@ const (
        _SA_RESTORER = 0x0 // Only used on intel
        _SA_SIGINFO  = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -79,6 +84,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -121,7 +130,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -129,11 +138,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events uint32
        _pad   uint32
index 2cafad20cf98821c48004b51fccd6ef592b31de9..2601082ee1aef7e39323bf07316bd84c06dab18e 100644 (file)
@@ -3,11 +3,11 @@
 // license that can be found in the LICENSE file.
 
 //go:build (mips64 || mips64le) && linux
-// +build mips64 mips64le
-// +build linux
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -32,6 +32,9 @@ const (
        _SA_ONSTACK = 0x8000000
        _SA_SIGINFO = 0x8
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -83,6 +86,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -129,7 +136,7 @@ type sigactiont struct {
        sa_restorer uintptr
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_code  int32
        si_errno int32
@@ -138,11 +145,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events    uint32
        pad_cgo_0 [4]byte
index 3a8dfe2e99008171588e5c238789ba53253dfe91..37651ef7e4330ebdd7086446e826b4e436e6bdd0 100644 (file)
@@ -3,11 +3,11 @@
 // license that can be found in the LICENSE file.
 
 //go:build (mips || mipsle) && linux
-// +build mips mipsle
-// +build linux
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -32,6 +32,9 @@ const (
        _SA_ONSTACK = 0x8000000
        _SA_SIGINFO = 0x8
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -83,6 +86,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -124,7 +131,7 @@ type sigactiont struct {
        sa_restorer uintptr
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_code  int32
        si_errno int32
@@ -132,11 +139,38 @@ type siginfo struct {
        si_addr uint32
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events    uint32
        pad_cgo_0 [4]byte
index 90b1dc1ff9d84edc4143b8793331c992965e9720..c7aa7234c195551d588c33fe09f6493d1eed6703 100644 (file)
@@ -3,6 +3,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -27,6 +29,9 @@ const (
        _SA_ONSTACK = 0x8000000
        _SA_SIGINFO = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -78,6 +83,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -122,7 +131,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -130,11 +139,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events    uint32
        pad_cgo_0 [4]byte
index 90b1dc1ff9d84edc4143b8793331c992965e9720..c7aa7234c195551d588c33fe09f6493d1eed6703 100644 (file)
@@ -3,6 +3,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -27,6 +29,9 @@ const (
        _SA_ONSTACK = 0x8000000
        _SA_SIGINFO = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -78,6 +83,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -122,7 +131,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -130,11 +139,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events    uint32
        pad_cgo_0 [4]byte
index 60da0fae000775df74809ce0d0c3e97acf5cad64..332720a8c848d1d6f45ca23e930f196eb6a5bf81 100644 (file)
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -29,6 +31,9 @@ const (
        _SA_RESTORER = 0x0
        _SA_SIGINFO  = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -80,6 +85,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -119,7 +128,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -127,11 +136,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events    uint32
        pad_cgo_0 [4]byte
index fa289d531c074bbef57c54892d64c5082daa8889..740d8100c5dd449da5c6c5a43523cc7f598f5bef 100644 (file)
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 const (
        _EINTR  = 0x4
        _EAGAIN = 0xb
@@ -28,6 +30,9 @@ const (
        _SA_ONSTACK = 0x8000000
        _SA_SIGINFO = 0x4
 
+       _SI_KERNEL = 0x80
+       _SI_TIMER  = -0x2
+
        _SIGHUP    = 0x1
        _SIGINT    = 0x2
        _SIGQUIT   = 0x3
@@ -79,6 +84,10 @@ const (
        _ITIMER_VIRTUAL = 0x1
        _ITIMER_PROF    = 0x2
 
+       _CLOCK_THREAD_CPUTIME_ID = 0x3
+
+       _SIGEV_THREAD_ID = 0x4
+
        _EPOLLIN       = 0x1
        _EPOLLOUT      = 0x4
        _EPOLLERR      = 0x8
@@ -118,7 +127,7 @@ type sigactiont struct {
        sa_mask     uint64
 }
 
-type siginfo struct {
+type siginfoFields struct {
        si_signo int32
        si_errno int32
        si_code  int32
@@ -126,11 +135,38 @@ type siginfo struct {
        si_addr uint64
 }
 
+type siginfo struct {
+       siginfoFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte
+}
+
+type itimerspec struct {
+       it_interval timespec
+       it_value    timespec
+}
+
 type itimerval struct {
        it_interval timeval
        it_value    timeval
 }
 
+type sigeventFields struct {
+       value  uintptr
+       signo  int32
+       notify int32
+       // below here is a union; sigev_notify_thread_id is the only field we use
+       sigev_notify_thread_id int32
+}
+
+type sigevent struct {
+       sigeventFields
+
+       // Pad struct to the max size in the kernel.
+       _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte
+}
+
 type epollevent struct {
        events    uint32
        pad_cgo_0 [4]byte
index 755992d18e03591b9e5df75864045f9eb0a6438a..df8bc579f2556ab2e6d42fbfc21c98ac7ce9a2cb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index 03c9c2de59e5e6376068cadb8852d4bc44e0951d..2943ea3f13eebf78e4039b0c6b3812531abacede 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index 9fda1d7d22657269f7d046de9c69ab6be02a08e2..33d80ff53c0ccc5a0bccd99171f9d98b3d4cb078 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index e7f4f6cece7ac15f44a87016541a96e53267bab9..74b37527df66a6a0912008e43ed8861f64cf2bc5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index 8d323449d1c5d4330f0ce732b10be0e036f5bec6..ec7d82a33cf018e12316de8ad70c80c42e463680 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
@@ -26,6 +25,7 @@ package runtime
 #include <sys/signal.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pthread.h>
 #include <signal.h>
 */
 import "C"
index e644f9c6ddd5afc1a8cec2098b869286b60cf237..ec16c9dcce94afa5cd9b5d4a7d8daae5c124071c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index a0b38319a5ddcaf051211fdb5b19ad95cec59940..56e4b38c5e43842747ee534feee62acd349e27db 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo.
index d4e3b409d24b9d911e8f8ff332c6aec52a187427..eeecf13df14c1bf0a459e491694c1081a40f651f 100644 (file)
 
 #include "textflag.h"
 
-TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
-       MOVDU   R0, 8(R3)
+TEXT runtime·duffzero<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-0
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
+       MOVDU   R0, 8(R20)
        RET
 
-TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0
-       UNDEF
+TEXT runtime·duffcopy<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-0
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       MOVDU   8(R20), R5
+       MOVDU   R5, 8(R21)
+       RET
index 95517b2a958808e26e50d7768b7c8364aa10e6ae..44086c1d6341b47c8eca577db42b639231b5e1f2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows || plan9
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows plan9
 
 package runtime
 
index 5009003d27d7cbfed6a0dd7b6c65e317ab7f1a37..81f73925d58c2f6eb72803e2fc1e5afb2c72f7a2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 && linux && !goexperiment.regabiargs
-// +build amd64,linux,!goexperiment.regabiargs
 
 package runtime
 
index e1b72efd0f765ed6087eb6f9d0df3e47b27e2911..7d1ab6888e63e83fb3376fb0ae252a23567d360c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 && linux && goexperiment.regabiargs
-// +build amd64,linux,goexperiment.regabiargs
 
 package runtime
 
index a2cef02cf863becfca3d63d81323c89e057d1705..032a9b9725d9b260141926d3f3fb53ca65a67752 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 && linux
-// +build amd64,linux
 
 package runtime
 
index 34c970d6d2d337d065450a8a51647ab791e282fc..03157d8eed3e612c34ec6fd0222acf49233fa235 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux
-// +build dragonfly freebsd linux
 
 package runtime
 
index b7c901f238ff29479ef2f4c8fa3466e62540f0c2..dea94a934cef6665d72dff6cbfc1b02563f2874b 100644 (file)
@@ -8,11 +8,16 @@ package runtime
 
 import "unsafe"
 
+const SiginfoMaxSize = _si_max_size
+const SigeventMaxSize = _sigev_max_size
+
 var NewOSProc0 = newosproc0
 var Mincore = mincore
 var Add = add
 
 type EpollEvent epollevent
+type Siginfo siginfo
+type Sigevent sigevent
 
 func Epollctl(epfd, op, fd int32, ev unsafe.Pointer) int32 {
        return epollctl(epfd, op, fd, (*epollevent)(ev))
index bf4a81589916cc55d68d566a3157875cbf93eae1..f9c3229316a1fa2f83a7589763ce53aa57c1b512 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 // Export guts for testing.
 
index 26d8b7d185948aef22540176d5be6a0abc41961e..bdf39c60dfcf72c0577d4315b7e4aeb1d6a7d965 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime
 
index a0c6c0440d8d94447157f28f762bc1587ca7ab09..0583039982ebbc909af45356c4770f8311a1d5f2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin
-// +build aix darwin
 
 package runtime
 
index e7279564e3fcaee92453d3e76dca1d5122e4695e..5149252c83746395c2fde9287dbf93acd68d53f2 100644 (file)
@@ -198,7 +198,7 @@ func MemclrBytes(b []byte) {
        memclrNoHeapPointers(s.array, uintptr(s.len))
 }
 
-var HashLoad = &hashLoad
+const HashLoad = hashLoad
 
 // entry point for testing
 func GostringW(w []uint16) (s string) {
@@ -263,7 +263,7 @@ var ReadUnaligned64 = readUnaligned64
 func CountPagesInUse() (pagesInUse, counted uintptr) {
        stopTheWorld("CountPagesInUse")
 
-       pagesInUse = uintptr(mheap_.pagesInUse)
+       pagesInUse = uintptr(mheap_.pagesInUse.Load())
 
        for _, s := range mheap_.allspans {
                if s.state.get() == mSpanInUse {
@@ -1230,3 +1230,84 @@ func GCTestPointerClass(p unsafe.Pointer) string {
 }
 
 const Raceenabled = raceenabled
+
+const (
+       GCBackgroundUtilization = gcBackgroundUtilization
+       GCGoalUtilization       = gcGoalUtilization
+)
+
+type GCController struct {
+       gcControllerState
+}
+
+func NewGCController(gcPercent int) *GCController {
+       // Force the controller to escape. We're going to
+       // do 64-bit atomics on it, and if it gets stack-allocated
+       // on a 32-bit architecture, it may get allocated unaligned
+       // space.
+       g := escape(new(GCController)).(*GCController)
+       g.gcControllerState.test = true // Mark it as a test copy.
+       g.init(int32(gcPercent))
+       return g
+}
+
+func (c *GCController) StartCycle(stackSize, globalsSize uint64, scannableFrac float64, gomaxprocs int) {
+       c.scannableStackSize = stackSize
+       c.globalsScan = globalsSize
+       c.heapLive = c.trigger
+       c.heapScan += uint64(float64(c.trigger-c.heapMarked) * scannableFrac)
+       c.startCycle(0, gomaxprocs)
+}
+
+func (c *GCController) AssistWorkPerByte() float64 {
+       return c.assistWorkPerByte.Load()
+}
+
+func (c *GCController) HeapGoal() uint64 {
+       return c.heapGoal
+}
+
+func (c *GCController) HeapLive() uint64 {
+       return c.heapLive
+}
+
+func (c *GCController) HeapMarked() uint64 {
+       return c.heapMarked
+}
+
+func (c *GCController) Trigger() uint64 {
+       return c.trigger
+}
+
+type GCControllerReviseDelta struct {
+       HeapLive        int64
+       HeapScan        int64
+       HeapScanWork    int64
+       StackScanWork   int64
+       GlobalsScanWork int64
+}
+
+func (c *GCController) Revise(d GCControllerReviseDelta) {
+       c.heapLive += uint64(d.HeapLive)
+       c.heapScan += uint64(d.HeapScan)
+       c.heapScanWork.Add(d.HeapScanWork)
+       c.stackScanWork.Add(d.StackScanWork)
+       c.globalsScanWork.Add(d.GlobalsScanWork)
+       c.revise()
+}
+
+func (c *GCController) EndCycle(bytesMarked uint64, assistTime, elapsed int64, gomaxprocs int) {
+       c.assistTime = assistTime
+       triggerRatio := c.endCycle(elapsed, gomaxprocs, false)
+       c.resetLive(bytesMarked)
+       c.commit(triggerRatio)
+}
+
+var escapeSink interface{}
+
+//go:noinline
+func escape(x interface{}) interface{} {
+       escapeSink = x
+       escapeSink = nil
+       return x
+}
index 215e234286b1c025d720f64f3d79180983c29eee..9f046b95e043ba3a7896ad207921856eacffcfba 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime
 
index 536b398fd7a077802aa5a65a328237c049171afa..d9cf753463940c2f6c2bfc0c8dd3a9de56179411 100644 (file)
@@ -8,6 +8,8 @@ package runtime
 
 import "unsafe"
 
+const MaxArgs = maxArgs
+
 var (
        TestingWER              = &testingWER
        OsYield                 = osyield
index eca4062e68c17bb663e3cc0541664858c4627dbe..b2003ba54318ded5e5f835ebdfb80d56e2f8b307 100644 (file)
@@ -144,7 +144,7 @@ It is a comma-separated list of name=val pairs setting these named variables:
        because it also disables the conservative stack scanning used
        for asynchronously preempted goroutines.
 
-The net, net/http, and crypto/tls packages also refer to debugging variables in GODEBUG.
+The net and net/http packages also refer to debugging variables in GODEBUG.
 See the documentation for those packages for details.
 
 The GOMAXPROCS variable limits the number of operating system threads that
diff --git a/src/runtime/float_test.go b/src/runtime/float_test.go
new file mode 100644 (file)
index 0000000..b2aa43d
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2021 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 runtime_test
+
+import (
+       "testing"
+)
+
+func TestIssue48807(t *testing.T) {
+       for _, i := range []uint64{
+               0x8234508000000001, // from issue48807
+               1<<56 + 1<<32 + 1,
+       } {
+               got := float32(i)
+               dontwant := float32(float64(i))
+               if got == dontwant {
+                       // The test cases above should be uint64s such that
+                       // this equality doesn't hold. These examples trigger
+                       // the case where using an intermediate float64 doesn't work.
+                       t.Errorf("direct float32 conversion doesn't work: arg=%x got=%x dontwant=%x", i, got, dontwant)
+               }
+       }
+}
index 1002b181e4cf62c39f6962affa41bdf9ac53f53a..a454dcaa6977b6b7a90a7d1c4a3047b2b7d6b488 100644 (file)
@@ -11,6 +11,7 @@
 #define PCDATA_UnsafePoint 0
 #define PCDATA_StackMapIndex 1
 #define PCDATA_InlTreeIndex 2
+#define PCDATA_ArgLiveIndex 3
 
 #define FUNCDATA_ArgsPointerMaps 0 /* garbage collector blocks */
 #define FUNCDATA_LocalsPointerMaps 1
@@ -18,6 +19,7 @@
 #define FUNCDATA_InlTree 3
 #define FUNCDATA_OpenCodedDeferInfo 4 /* info for func with open-coded defers */
 #define FUNCDATA_ArgInfo 5
+#define FUNCDATA_ArgLiveInfo 6
 
 // Pseudo-assembly statements.
 
@@ -44,7 +46,7 @@
 
 // NO_LOCAL_POINTERS indicates that the assembly function stores
 // no pointers to heap objects in its local stack variables.
-#define NO_LOCAL_POINTERS      FUNCDATA $FUNCDATA_LocalsPointerMaps, runtime·no_pointers_stackmap(SB)
+#define NO_LOCAL_POINTERS      FUNCDATA $FUNCDATA_LocalsPointerMaps, no_pointers_stackmap(SB)
 
 // ArgsSizeUnknown is set in Func.argsize to mark all functions
 // whose argument size is unknown (C vararg functions, and
index 10a735327a7357b59e2a40946295c7668b0295e1..188d0c6525219649781c0806f8d756071615f402 100644 (file)
@@ -7,8 +7,6 @@
 // the test.
 
 //go:build (dragonfly || freebsd || linux) && !race
-// +build dragonfly freebsd linux
-// +build !race
 
 package runtime_test
 
index 0ec533153484ca953ed385453bf36829e69c1416..7b979afd55490096f0ab04183691d1e210a2b73c 100644 (file)
@@ -458,7 +458,7 @@ func benchSetType(b *testing.B, x interface{}) {
        v := reflect.ValueOf(x)
        t := v.Type()
        switch t.Kind() {
-       case reflect.Ptr:
+       case reflect.Pointer:
                b.SetBytes(int64(t.Elem().Size()))
        case reflect.Slice:
                b.SetBytes(int64(t.Elem().Size()) * int64(v.Len()))
index 7c22c76b875c37c630a1042c2b3dbf1e90b89059..0616c7dd050751eaab48674c8f49a667988b4a34 100644 (file)
@@ -6,7 +6,6 @@
 // wyhash: https://github.com/wangyi-fudan/wyhash/blob/ceb019b530e2c1c14d70b79bfa2bc49de7d95bc1/Modern%20Non-Cryptographic%20Hash%20Function%20and%20Pseudorandom%20Number%20Generator.pdf
 
 //go:build 386 || arm || mips || mipsle
-// +build 386 arm mips mipsle
 
 package runtime
 
index 5f7d00bf7f087af57d7f3b73a1509a56b2fa0022..f773eb929cd3bedd596f64d5cbc9283b62bd14d0 100644 (file)
@@ -6,7 +6,6 @@
 // wyhash: https://github.com/wangyi-fudan/wyhash
 
 //go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm
-// +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm
 
 package runtime
 
index 8fb30d95b9b1be80d880e8fec575632dfc6367da..871637a09e0e904046b65c0b55735fa0d82ebb4c 100644 (file)
@@ -259,7 +259,7 @@ func dumpframe(s *stkframe, arg unsafe.Pointer) bool {
        // Figure out what we can about our stack map
        pc := s.pc
        pcdata := int32(-1) // Use the entry map at function entry
-       if pc != f.entry {
+       if pc != f.entry() {
                pc--
                pcdata = pcdatavalue(f, _PCDATA_StackMapIndex, pc, nil)
        }
@@ -284,7 +284,7 @@ func dumpframe(s *stkframe, arg unsafe.Pointer) bool {
        dumpint(uint64(child.depth))                       // # of frames deep on the stack
        dumpint(uint64(uintptr(unsafe.Pointer(child.sp)))) // sp of child, or 0 if bottom of stack
        dumpmemrange(unsafe.Pointer(s.sp), s.fp-s.sp)      // frame contents
-       dumpint(uint64(f.entry))
+       dumpint(uint64(f.entry()))
        dumpint(uint64(s.pc))
        dumpint(uint64(s.continpc))
        name := funcname(f)
@@ -631,7 +631,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
                        dumpint(0)
                } else {
                        dumpstr(funcname(f))
-                       if i > 0 && pc > f.entry {
+                       if i > 0 && pc > f.entry() {
                                pc--
                        }
                        file, line := funcline(f, pc)
index 3d1d9d6ba18cf0183f3edb87fcc03ca5f2548275..e2bec1094819a7d3143db226ec2131bb8a56b90d 100644 (file)
@@ -325,6 +325,9 @@ func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {
        if msanenabled {
                msanread(v, t.size)
        }
+       if asanenabled {
+               asanread(v, t.size)
+       }
        x := mallocgc(t.size, t, true)
        typedmemmove(t, x, v)
        return x
@@ -337,6 +340,10 @@ func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer {
        if msanenabled {
                msanread(v, t.size)
        }
+       if asanenabled {
+               asanread(v, t.size)
+       }
+
        x := mallocgc(t.size, t, false)
        memmove(x, v, t.size)
        return x
index d4aed6b6717da97ab96463b58f7f15d95b8d4ea4..27a77ec37a90e8216ea0410451374b718cdc8df5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386
-// +build 386
 
 package atomic
 
index 2e9374ca269dd63a7a0c809f5d9ab245b5be19ea..e2539b6c7ec5e7f070ae7e48483c2ae4abdc7dcd 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm
-// +build arm
 
 package atomic
 
index dbb1796ec0941abc9820b53763f77b93565f088b..459fb9978db30afff6a0c5ea52798f9c385ee18b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64
-// +build arm64
 
 package atomic
 
index 5b407ebc7a5918006993978db2360a5f4570bd03..1e12b83801dba27180e78026adc2eb76ead3a088 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips64 || mips64le
-// +build mips64 mips64le
 
 package atomic
 
index 80cd65b33388ab4e432d2d85499045857eb65937..e552e5749528122aaafb4d62c448dc59ce6ad42b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips || mipsle
-// +build mips mipsle
 
 // Export some functions via linkname to assembly in sync/atomic.
 //go:linkname Xadd64
index 98101e3287823a0807a9bd5b204e82bf76a607c2..998d16e3f6862dcfae609432932ffe6dbf57cbe5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package atomic
 
diff --git a/src/runtime/internal/atomic/doc.go b/src/runtime/internal/atomic/doc.go
new file mode 100644 (file)
index 0000000..08e6b6c
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2021 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 atomic provides atomic operations, independent of sync/atomic,
+to the runtime.
+
+On most platforms, the compiler is aware of the functions defined
+in this package, and they're replaced with platform-specific intrinsics.
+On other platforms, generic implementations are made available.
+
+Unless otherwise noted, operations defined in this package are sequentially
+consistent across threads with respect to the values they manipulate. More
+specifically, operations that happen in a specific order on one thread,
+will always be observed to happen in exactly that order by another thread.
+*/
+package atomic
index e7544ba4484f079143149056cec80021843ef127..7df8d9c86329ee49a3abd1f069d66608cb4ebd6d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !wasm
-// +build !wasm
 
 package atomic
 
diff --git a/src/runtime/internal/atomic/types.go b/src/runtime/internal/atomic/types.go
new file mode 100644 (file)
index 0000000..1a240d7
--- /dev/null
@@ -0,0 +1,395 @@
+// Copyright 2021 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 atomic
+
+import "unsafe"
+
+// Int32 is an atomically accessed int32 value.
+//
+// An Int32 must not be copied.
+type Int32 struct {
+       noCopy noCopy
+       value  int32
+}
+
+// Load accesses and returns the value atomically.
+func (i *Int32) Load() int32 {
+       return Loadint32(&i.value)
+}
+
+// Store updates the value atomically.
+func (i *Int32) Store(value int32) {
+       Storeint32(&i.value, value)
+}
+
+// CompareAndSwap atomically compares i's value with old,
+// and if they're equal, swaps i's value with new.
+//
+// Returns true if the operation succeeded.
+func (i *Int32) CompareAndSwap(old, new int32) bool {
+       return Casint32(&i.value, old, new)
+}
+
+// Swap replaces i's value with new, returning
+// i's value before the replacement.
+func (i *Int32) Swap(new int32) int32 {
+       return Xchgint32(&i.value, new)
+}
+
+// Add adds delta to i atomically, returning
+// the new updated value.
+//
+// This operation wraps around in the usual
+// two's-complement way.
+func (i *Int32) Add(delta int32) int32 {
+       return Xaddint32(&i.value, delta)
+}
+
+// Int64 is an atomically accessed int64 value.
+//
+// An Int64 must not be copied.
+type Int64 struct {
+       noCopy noCopy
+       value  int64
+}
+
+// Load accesses and returns the value atomically.
+func (i *Int64) Load() int64 {
+       return Loadint64(&i.value)
+}
+
+// Store updates the value atomically.
+func (i *Int64) Store(value int64) {
+       Storeint64(&i.value, value)
+}
+
+// CompareAndSwap atomically compares i's value with old,
+// and if they're equal, swaps i's value with new.
+//
+// Returns true if the operation succeeded.
+func (i *Int64) CompareAndSwap(old, new int64) bool {
+       return Casint64(&i.value, old, new)
+}
+
+// Swap replaces i's value with new, returning
+// i's value before the replacement.
+func (i *Int64) Swap(new int64) int64 {
+       return Xchgint64(&i.value, new)
+}
+
+// Add adds delta to i atomically, returning
+// the new updated value.
+//
+// This operation wraps around in the usual
+// two's-complement way.
+func (i *Int64) Add(delta int64) int64 {
+       return Xaddint64(&i.value, delta)
+}
+
+// Uint8 is an atomically accessed uint8 value.
+//
+// A Uint8 must not be copied.
+type Uint8 struct {
+       noCopy noCopy
+       value  uint8
+}
+
+// Load accesses and returns the value atomically.
+func (u *Uint8) Load() uint8 {
+       return Load8(&u.value)
+}
+
+// Store updates the value atomically.
+func (u *Uint8) Store(value uint8) {
+       Store8(&u.value, value)
+}
+
+// And takes value and performs a bit-wise
+// "and" operation with the value of u, storing
+// the result into u.
+//
+// The full process is performed atomically.
+func (u *Uint8) And(value uint8) {
+       And8(&u.value, value)
+}
+
+// Or takes value and performs a bit-wise
+// "or" operation with the value of u, storing
+// the result into u.
+//
+// The full process is performed atomically.
+func (u *Uint8) Or(value uint8) {
+       Or8(&u.value, value)
+}
+
+// Uint32 is an atomically accessed uint32 value.
+//
+// A Uint32 must not be copied.
+type Uint32 struct {
+       noCopy noCopy
+       value  uint32
+}
+
+// Load accesses and returns the value atomically.
+func (u *Uint32) Load() uint32 {
+       return Load(&u.value)
+}
+
+// LoadAcquire is a partially unsynchronized version
+// of Load that relaxes ordering constraints. Other threads
+// may observe operations that precede this operation to
+// occur after it, but no operation that occurs after it
+// on this thread can be observed to occur before it.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uint32) LoadAcquire() uint32 {
+       return LoadAcq(&u.value)
+}
+
+// Store updates the value atomically.
+func (u *Uint32) Store(value uint32) {
+       Store(&u.value, value)
+}
+
+// StoreRelease is a partially unsynchronized version
+// of Store that relaxes ordering constraints. Other threads
+// may observe operations that occur after this operation to
+// precede it, but no operation that precedes it
+// on this thread can be observed to occur after it.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uint32) StoreRelease(value uint32) {
+       StoreRel(&u.value, value)
+}
+
+// CompareAndSwap atomically compares u's value with old,
+// and if they're equal, swaps u's value with new.
+//
+// Returns true if the operation succeeded.
+func (u *Uint32) CompareAndSwap(old, new uint32) bool {
+       return Cas(&u.value, old, new)
+}
+
+// CompareAndSwapRelease is a partially unsynchronized version
+// of Cas that relaxes ordering constraints. Other threads
+// may observe operations that occur after this operation to
+// precede it, but no operation that precedes it
+// on this thread can be observed to occur after it.
+//
+// Returns true if the operation succeeded.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uint32) CompareAndSwapRelease(old, new uint32) bool {
+       return CasRel(&u.value, old, new)
+}
+
+// Swap replaces u's value with new, returning
+// u's value before the replacement.
+func (u *Uint32) Swap(value uint32) uint32 {
+       return Xchg(&u.value, value)
+}
+
+// And takes value and performs a bit-wise
+// "and" operation with the value of u, storing
+// the result into u.
+//
+// The full process is performed atomically.
+func (u *Uint32) And(value uint32) {
+       And(&u.value, value)
+}
+
+// Or takes value and performs a bit-wise
+// "or" operation with the value of u, storing
+// the result into u.
+//
+// The full process is performed atomically.
+func (u *Uint32) Or(value uint32) {
+       Or(&u.value, value)
+}
+
+// Add adds delta to u atomically, returning
+// the new updated value.
+//
+// This operation wraps around in the usual
+// two's-complement way.
+func (u *Uint32) Add(delta int32) uint32 {
+       return Xadd(&u.value, delta)
+}
+
+// Uint64 is an atomically accessed uint64 value.
+//
+// A Uint64 must not be copied.
+type Uint64 struct {
+       noCopy noCopy
+       value  uint64
+}
+
+// Load accesses and returns the value atomically.
+func (u *Uint64) Load() uint64 {
+       return Load64(&u.value)
+}
+
+// Store updates the value atomically.
+func (u *Uint64) Store(value uint64) {
+       Store64(&u.value, value)
+}
+
+// CompareAndSwap atomically compares u's value with old,
+// and if they're equal, swaps u's value with new.
+//
+// Returns true if the operation succeeded.
+func (u *Uint64) CompareAndSwap(old, new uint64) bool {
+       return Cas64(&u.value, old, new)
+}
+
+// Swap replaces u's value with new, returning
+// u's value before the replacement.
+func (u *Uint64) Swap(value uint64) uint64 {
+       return Xchg64(&u.value, value)
+}
+
+// Add adds delta to u atomically, returning
+// the new updated value.
+//
+// This operation wraps around in the usual
+// two's-complement way.
+func (u *Uint64) Add(delta int64) uint64 {
+       return Xadd64(&u.value, delta)
+}
+
+// Uintptr is an atomically accessed uintptr value.
+//
+// A Uintptr must not be copied.
+type Uintptr struct {
+       noCopy noCopy
+       value  uintptr
+}
+
+// Load accesses and returns the value atomically.
+func (u *Uintptr) Load() uintptr {
+       return Loaduintptr(&u.value)
+}
+
+// LoadAcquire is a partially unsynchronized version
+// of Load that relaxes ordering constraints. Other threads
+// may observe operations that precede this operation to
+// occur after it, but no operation that occurs after it
+// on this thread can be observed to occur before it.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uintptr) LoadAcquire() uintptr {
+       return LoadAcquintptr(&u.value)
+}
+
+// Store updates the value atomically.
+func (u *Uintptr) Store(value uintptr) {
+       Storeuintptr(&u.value, value)
+}
+
+// StoreRelease is a partially unsynchronized version
+// of Store that relaxes ordering constraints. Other threads
+// may observe operations that occur after this operation to
+// precede it, but no operation that precedes it
+// on this thread can be observed to occur after it.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uintptr) StoreRelease(value uintptr) {
+       StoreReluintptr(&u.value, value)
+}
+
+// CompareAndSwap atomically compares u's value with old,
+// and if they're equal, swaps u's value with new.
+//
+// Returns true if the operation succeeded.
+func (u *Uintptr) CompareAndSwap(old, new uintptr) bool {
+       return Casuintptr(&u.value, old, new)
+}
+
+// Swap replaces u's value with new, returning
+// u's value before the replacement.
+func (u *Uintptr) Swap(value uintptr) uintptr {
+       return Xchguintptr(&u.value, value)
+}
+
+// Add adds delta to u atomically, returning
+// the new updated value.
+//
+// This operation wraps around in the usual
+// two's-complement way.
+func (u *Uintptr) Add(delta uintptr) uintptr {
+       return Xadduintptr(&u.value, delta)
+}
+
+// Float64 is an atomically accessed float64 value.
+//
+// A Float64 must not be copied.
+type Float64 struct {
+       u Uint64
+}
+
+// Load accesses and returns the value atomically.
+func (f *Float64) Load() float64 {
+       r := f.u.Load()
+       return *(*float64)(unsafe.Pointer(&r))
+}
+
+// Store updates the value atomically.
+func (f *Float64) Store(value float64) {
+       f.u.Store(*(*uint64)(unsafe.Pointer(&value)))
+}
+
+// UnsafePointer is an atomically accessed unsafe.Pointer value.
+//
+// Note that because of the atomicity guarantees, stores to values
+// of this type never trigger a write barrier, and the relevant
+// methods are suffixed with "NoWB" to indicate that explicitly.
+// As a result, this type should be used carefully, and sparingly,
+// mostly with values that do not live in the Go heap anyway.
+//
+// An UnsafePointer must not be copied.
+type UnsafePointer struct {
+       noCopy noCopy
+       value  unsafe.Pointer
+}
+
+// Load accesses and returns the value atomically.
+func (u *UnsafePointer) Load() unsafe.Pointer {
+       return Loadp(unsafe.Pointer(&u.value))
+}
+
+// StoreNoWB updates the value atomically.
+//
+// WARNING: As the name implies this operation does *not*
+// perform a write barrier on value, and so this operation may
+// hide pointers from the GC. Use with care and sparingly.
+// It is safe to use with values not found in the Go heap.
+func (u *UnsafePointer) StoreNoWB(value unsafe.Pointer) {
+       StorepNoWB(unsafe.Pointer(&u.value), value)
+}
+
+// CompareAndSwapNoWB atomically (with respect to other methods)
+// compares u's value with old, and if they're equal,
+// swaps u's value with new.
+//
+// Returns true if the operation succeeded.
+//
+// WARNING: As the name implies this operation does *not*
+// perform a write barrier on value, and so this operation may
+// hide pointers from the GC. Use with care and sparingly.
+// It is safe to use with values not found in the Go heap.
+func (u *UnsafePointer) CompareAndSwapNoWB(old, new unsafe.Pointer) bool {
+       return Casp1(&u.value, old, new)
+}
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://golang.org/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock()   {}
+func (*noCopy) Unlock() {}
diff --git a/src/runtime/internal/atomic/types_64bit.go b/src/runtime/internal/atomic/types_64bit.go
new file mode 100644 (file)
index 0000000..43c1ba2
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 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:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm
+
+package atomic
+
+// LoadAcquire is a partially unsynchronized version
+// of Load that relaxes ordering constraints. Other threads
+// may observe operations that precede this operation to
+// occur after it, but no operation that occurs after it
+// on this thread can be observed to occur before it.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uint64) LoadAcquire() uint64 {
+       return LoadAcq64(&u.value)
+}
+
+// StoreRelease is a partially unsynchronized version
+// of Store that relaxes ordering constraints. Other threads
+// may observe operations that occur after this operation to
+// precede it, but no operation that precedes it
+// on this thread can be observed to occur after it.
+//
+// WARNING: Use sparingly and with great care.
+func (u *Uint64) StoreRelease(value uint64) {
+       StoreRel64(&u.value, value)
+}
index e76d8dd064616a2866047dbb40c0408c40d70eb1..5af49011e9e65549e10829b6358617a0c6b20172 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !386
-// +build !386
 
 // TODO finish intrinsifying 386, deadcode the assembly, remove build tags, merge w/ intrinsics_common
 // TODO replace all uses of CtzXX with TrailingZerosXX; they are the same.
index 818d75ecc53ee6e8d5b2dd0639125b7966da7f75..48d9759ca9c54c77074cd98a8506fb3b24230b70 100644 (file)
@@ -141,3 +141,18 @@ func TrailingZeros8(x uint8) int {
 func Len8(x uint8) int {
        return int(len8tab[x])
 }
+
+// Prefetch prefetches data from memory addr to cache
+//
+// AMD64: Produce PREFETCHT0 instruction
+//
+// ARM64: Produce PRFM instruction with PLDL1KEEP option
+func Prefetch(addr uintptr) {}
+
+// PrefetchStreamed prefetches data from memory addr, with a hint that this data is being streamed.
+// That is, it is likely to be accessed very soon, but only once. If possible, this will avoid polluting the cache.
+//
+// AMD64: Produce PREFETCHNTA instruction
+//
+// ARM64: Produce PRFM instruction with PLDL1STRM option
+func PrefetchStreamed(addr uintptr) {}
index bf1494d48aac7b787cdf381d7ba70c6f04876be5..a020652f7604b39c40798983b66fcfd03e210f9a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386
-// +build 386
 
 package sys
 
index c00f0965bd63b1f40e46e40bca929a7979079363..405923cc34e7425d8cfed647b0762c3471fd6131 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || arm || mips || mipsle
-// +build 386 arm mips mipsle
 
 package runtime
 
index 4812dd1156572437938a16ad9c78ab96b5dce9a7..3f0e48089774a7ae561f47ac69758558bf93598d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x || wasm
-// +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm
 
 package runtime
 
index 578bce04149baab781e738fa2779a14ec5d6ec6a..e7b3cdc46a9ea8b4c9c908dcbdf3154eb9d4568c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build libfuzzer
-// +build libfuzzer
 
 package runtime
 
index e4c8d01941d196d46ad670d66396ab8ee85f05fe..575df7a1d57086db73da1af1da4cd94237a663af 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux
-// +build dragonfly freebsd linux
 
 package runtime
 
index 0ca3512baf3c8313542cfe214057ef11772e917c..80ee50da3513cf71541e358392e0358c250ea323 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package runtime
 
index 7a6af28b561399aa45913e034db07202033ce1da..db36df1f375b377c54627df90786c0e8be91b0e1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || netbsd || openbsd || plan9 || solaris || windows
-// +build aix darwin netbsd openbsd plan9 solaris windows
 
 package runtime
 
index f3d2c009145766c448a9a71a5ca3d4c0cd1f6c96..daa45b542dd330d918a7f2594d89829032b57e50 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !goexperiment.staticlockranking
-// +build !goexperiment.staticlockranking
 
 package runtime
 
index fc8d2dc8d1179fd1813561ff0a6283550b7a0bfe..3c8c367c19fbb53700e3023e903f63b17b2703be 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build goexperiment.staticlockranking
-// +build goexperiment.staticlockranking
 
 package runtime
 
index f8d5d48a28d7c8f7c1e35ebc013f93a166bbb42b..e267e2df23193f61997dfdab1167553881a37247 100644 (file)
@@ -908,6 +908,14 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
        if size == 0 {
                return unsafe.Pointer(&zerobase)
        }
+       userSize := size
+       if asanenabled {
+               // Refer to ASAN runtime library, the malloc() function allocates extra memory,
+               // the redzone, around the user requested memory region. And the redzones are marked
+               // as unaddressable. We perform the same operations in Go to detect the overflows or
+               // underflows.
+               size += computeRZlog(size)
+       }
 
        if debug.malloc {
                if debug.sbrk != 0 {
@@ -971,8 +979,8 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
        mp.mallocing = 1
 
        shouldhelpgc := false
-       dataSize := size
-       c := getMCache()
+       dataSize := userSize
+       c := getMCache(mp)
        if c == nil {
                throw("mallocgc called without a P or outside bootstrapping")
        }
@@ -980,8 +988,8 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
        var x unsafe.Pointer
        noscan := typ == nil || typ.ptrdata == 0
        // In some cases block zeroing can profitably (for latency reduction purposes)
-       // be delayed till preemption is possible; isZeroed tracks that state.
-       isZeroed := true
+       // be delayed till preemption is possible; delayedZeroing tracks that state.
+       delayedZeroing := false
        if size <= maxSmallSize {
                if noscan && size < maxTinySize {
                        // Tiny allocator.
@@ -1079,11 +1087,23 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
                shouldhelpgc = true
                // For large allocations, keep track of zeroed state so that
                // bulk zeroing can be happen later in a preemptible context.
-               span, isZeroed = c.allocLarge(size, needzero && !noscan, noscan)
+               span = c.allocLarge(size, noscan)
                span.freeindex = 1
                span.allocCount = 1
-               x = unsafe.Pointer(span.base())
                size = span.elemsize
+               x = unsafe.Pointer(span.base())
+               if needzero && span.needzero != 0 {
+                       if noscan {
+                               delayedZeroing = true
+                       } else {
+                               memclrNoHeapPointers(x, size)
+                               // We've in theory cleared almost the whole span here,
+                               // and could take the extra step of actually clearing
+                               // the whole thing. However, don't. Any GC bits for the
+                               // uncleared parts will be zero, and it's just going to
+                               // be needzero = 1 once freed anyway.
+                       }
+               }
        }
 
        var scanSize uintptr
@@ -1126,6 +1146,17 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
                msanmalloc(x, size)
        }
 
+       if asanenabled {
+               // We should only read/write the memory with the size asked by the user.
+               // The rest of the allocated memory should be poisoned, so that we can report
+               // errors when accessing poisoned memory.
+               // The allocated memory is larger than required userSize, it will also include
+               // redzone and some other padding bytes.
+               rzBeg := unsafe.Add(x, userSize)
+               asanpoison(rzBeg, size-userSize)
+               asanunpoison(x, userSize)
+       }
+
        if rate := MemProfileRate; rate > 0 {
                // Note cache c only valid while m acquired; see #47302
                if rate != 1 && size < c.nextSample {
@@ -1139,7 +1170,10 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 
        // Pointerfree data can be zeroed late in a context where preemption can occur.
        // x will keep the memory alive.
-       if !isZeroed && needzero {
+       if delayedZeroing {
+               if !noscan {
+                       throw("delayed zeroing on data that may contain pointers")
+               }
                memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302
        }
 
@@ -1247,7 +1281,7 @@ func reflect_unsafe_NewArray(typ *_type, n int) unsafe.Pointer {
 }
 
 func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
-       c := getMCache()
+       c := getMCache(mp)
        if c == nil {
                throw("profilealloc called without a P or outside bootstrapping")
        }
@@ -1301,7 +1335,7 @@ func fastexprand(mean int) int32 {
        // x = -log_e(q) * mean
        // x = log_2(q) * (-log_e(2)) * mean    ; Using log_2 for efficiency
        const randomBitCount = 26
-       q := fastrand()%(1<<randomBitCount) + 1
+       q := fastrandn(1<<randomBitCount) + 1
        qlog := fastlog2(float64(q)) - randomBitCount
        if qlog > 0 {
                qlog = 0
@@ -1319,7 +1353,7 @@ func nextSampleNoFP() uintptr {
                rate = 0x3fffffff
        }
        if rate != 0 {
-               return uintptr(fastrand() % uint32(2*rate))
+               return uintptr(fastrandn(uint32(2 * rate)))
        }
        return 0
 }
@@ -1499,3 +1533,26 @@ type notInHeap struct{}
 func (p *notInHeap) add(bytes uintptr) *notInHeap {
        return (*notInHeap)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + bytes))
 }
+
+// computeRZlog computes the size of the redzone.
+// Refer to the implementation of the compiler-rt.
+func computeRZlog(userSize uintptr) uintptr {
+       switch {
+       case userSize <= (64 - 16):
+               return 16 << 0
+       case userSize <= (128 - 32):
+               return 16 << 1
+       case userSize <= (512 - 64):
+               return 16 << 2
+       case userSize <= (4096 - 128):
+               return 16 << 3
+       case userSize <= (1<<14)-256:
+               return 16 << 4
+       case userSize <= (1<<15)-512:
+               return 16 << 5
+       case userSize <= (1<<16)-1024:
+               return 16 << 6
+       default:
+               return 16 << 7
+       }
+}
index 0cad1a354de3dec000c6b7fde8d3462be216e841..e91b25eaec501512170ebe101e3d70aa291b970e 100644 (file)
@@ -160,8 +160,8 @@ type bmap struct {
 }
 
 // A hash iteration structure.
-// If you modify hiter, also change cmd/compile/internal/reflectdata/reflect.go to indicate
-// the layout of this structure.
+// If you modify hiter, also change cmd/compile/internal/reflectdata/reflect.go
+// and reflect/value.go to match the layout of this structure.
 type hiter struct {
        key         unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/compile/internal/walk/range.go).
        elem        unsafe.Pointer // Must be in second position (see cmd/compile/internal/walk/range.go).
@@ -402,6 +402,9 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        if msanenabled && h != nil {
                msanread(key, t.key.size)
        }
+       if asanenabled && h != nil {
+               asanread(key, t.key.size)
+       }
        if h == nil || h.count == 0 {
                if t.hashMightPanic() {
                        t.hasher(key, 0) // see issue 23734
@@ -460,6 +463,9 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
        if msanenabled && h != nil {
                msanread(key, t.key.size)
        }
+       if asanenabled && h != nil {
+               asanread(key, t.key.size)
+       }
        if h == nil || h.count == 0 {
                if t.hashMightPanic() {
                        t.hasher(key, 0) // see issue 23734
@@ -582,6 +588,9 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        if msanenabled {
                msanread(key, t.key.size)
        }
+       if asanenabled {
+               asanread(key, t.key.size)
+       }
        if h.flags&hashWriting != 0 {
                throw("concurrent map writes")
        }
@@ -693,6 +702,9 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
        if msanenabled && h != nil {
                msanread(key, t.key.size)
        }
+       if asanenabled && h != nil {
+               asanread(key, t.key.size)
+       }
        if h == nil || h.count == 0 {
                if t.hashMightPanic() {
                        t.hasher(key, 0) // see issue 23734
@@ -806,6 +818,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
                racereadpc(unsafe.Pointer(h), callerpc, abi.FuncPCABIInternal(mapiterinit))
        }
 
+       it.t = t
        if h == nil || h.count == 0 {
                return
        }
@@ -813,7 +826,6 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
        if unsafe.Sizeof(hiter{})/goarch.PtrSize != 12 {
                throw("hash_iter size incorrect") // see cmd/compile/internal/reflectdata/reflect.go
        }
-       it.t = t
        it.h = h
 
        // grab snapshot of bucket state
@@ -1324,22 +1336,41 @@ func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
        return elem
 }
 
+//go:linkname reflect_mapaccess_faststr reflect.mapaccess_faststr
+func reflect_mapaccess_faststr(t *maptype, h *hmap, key string) unsafe.Pointer {
+       elem, ok := mapaccess2_faststr(t, h, key)
+       if !ok {
+               // reflect wants nil for a missing element
+               elem = nil
+       }
+       return elem
+}
+
 //go:linkname reflect_mapassign reflect.mapassign
 func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, elem unsafe.Pointer) {
        p := mapassign(t, h, key)
        typedmemmove(t.elem, p, elem)
 }
 
+//go:linkname reflect_mapassign_faststr reflect.mapassign_faststr
+func reflect_mapassign_faststr(t *maptype, h *hmap, key string, elem unsafe.Pointer) {
+       p := mapassign_faststr(t, h, key)
+       typedmemmove(t.elem, p, elem)
+}
+
 //go:linkname reflect_mapdelete reflect.mapdelete
 func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
        mapdelete(t, h, key)
 }
 
+//go:linkname reflect_mapdelete_faststr reflect.mapdelete_faststr
+func reflect_mapdelete_faststr(t *maptype, h *hmap, key string) {
+       mapdelete_faststr(t, h, key)
+}
+
 //go:linkname reflect_mapiterinit reflect.mapiterinit
-func reflect_mapiterinit(t *maptype, h *hmap) *hiter {
-       it := new(hiter)
+func reflect_mapiterinit(t *maptype, h *hmap, it *hiter) {
        mapiterinit(t, h, it)
-       return it
 }
 
 //go:linkname reflect_mapiternext reflect.mapiternext
index 24556b4093c32e44e8c2ab8e79e4a20422194bd0..f78cad5a776f4657f584fc622e09e7b55ee0cd63 100644 (file)
@@ -473,7 +473,7 @@ func TestMapNanGrowIterator(t *testing.T) {
        nan := math.NaN()
        const nBuckets = 16
        // To fill nBuckets buckets takes LOAD * nBuckets keys.
-       nKeys := int(nBuckets * *runtime.HashLoad)
+       nKeys := int(nBuckets * runtime.HashLoad)
 
        // Get map to full point with nan keys.
        for i := 0; i < nKeys; i++ {
index 3fd1cca42cc2f2c0e4b808b56ee6ca4617fee92b..0f8b2af5faea408c23266415104d9b4e3b0fb6e4 100644 (file)
@@ -184,6 +184,10 @@ func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
                msanwrite(dst, typ.size)
                msanread(src, typ.size)
        }
+       if asanenabled {
+               asanwrite(dst, typ.size)
+               asanread(src, typ.size)
+       }
        typedmemmove(typ, dst, src)
 }
 
@@ -262,6 +266,10 @@ func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe
                msanwrite(dstPtr, uintptr(n)*typ.size)
                msanread(srcPtr, uintptr(n)*typ.size)
        }
+       if asanenabled {
+               asanwrite(dstPtr, uintptr(n)*typ.size)
+               asanread(srcPtr, uintptr(n)*typ.size)
+       }
 
        if writeBarrier.cgo {
                cgoCheckSliceCopy(typ, dstPtr, srcPtr, n)
index 9363409e361c11dfce0b03061fc4f11bcd5de8c3..3330ddd62ef1c63555b13849d774e8e2c3586c16 100644 (file)
@@ -417,6 +417,15 @@ func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex ui
        return
 }
 
+// verifyNotInHeapPtr reports whether converting the not-in-heap pointer into a unsafe.Pointer is ok.
+//go:linkname reflect_verifyNotInHeapPtr reflect.verifyNotInHeapPtr
+func reflect_verifyNotInHeapPtr(p uintptr) bool {
+       // Conversion to a pointer is ok as long as findObject above does not call badPointer.
+       // Since we're already promised that p doesn't point into the heap, just disallow heap
+       // pointers and the special clobbered pointer.
+       return spanOf(p) == nil && p != clobberdeadPtr
+}
+
 // next returns the heapBits describing the next pointer-sized word in memory.
 // That is, if h describes address p, h.next() describes p+ptrSize.
 // Note that next does not modify h. The caller must record the result.
@@ -974,7 +983,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
        // machine instructions.
 
        outOfPlace := false
-       if arenaIndex(x+size-1) != arenaIdx(h.arena) || (doubleCheck && fastrand()%2 == 0) {
+       if arenaIndex(x+size-1) != arenaIdx(h.arena) || (doubleCheck && fastrandn(2) == 0) {
                // This object spans heap arenas, so the bitmap may be
                // discontiguous. Unroll it into the object instead
                // and then copy it out.
index a9e959109abaab7f4e624fe7fcc857f7572efcff..86a8958b9dc66347b227e360e84d84f158fcf0cd 100644 (file)
@@ -122,9 +122,9 @@ func freemcache(c *mcache) {
 //
 // Returns nil if we're not bootstrapping or we don't have a P. The caller's
 // P must not change, so we must be in a non-preemptible state.
-func getMCache() *mcache {
+func getMCache(mp *m) *mcache {
        // Grab the mcache, since that's where stats live.
-       pp := getg().m.p.ptr()
+       pp := mp.p.ptr()
        var c *mcache
        if pp == nil {
                // We will be called without a P while bootstrapping,
@@ -184,32 +184,18 @@ func (c *mcache) refill(spc spanClass) {
        }
        memstats.heapStats.release()
 
-       // Update gcController.heapLive with the same assumption.
-       usedBytes := uintptr(s.allocCount) * s.elemsize
-       atomic.Xadd64(&gcController.heapLive, int64(s.npages*pageSize)-int64(usedBytes))
-
+       // Update heapLive with the same assumption.
        // While we're here, flush scanAlloc, since we have to call
        // revise anyway.
-       atomic.Xadd64(&gcController.heapScan, int64(c.scanAlloc))
+       usedBytes := uintptr(s.allocCount) * s.elemsize
+       gcController.update(int64(s.npages*pageSize)-int64(usedBytes), int64(c.scanAlloc))
        c.scanAlloc = 0
 
-       if trace.enabled {
-               // gcController.heapLive changed.
-               traceHeapAlloc()
-       }
-       if gcBlackenEnabled != 0 {
-               // gcController.heapLive and heapScan changed.
-               gcController.revise()
-       }
-
        c.alloc[spc] = s
 }
 
 // allocLarge allocates a span for a large object.
-// The boolean result indicates whether the span is known-zeroed.
-// If it did not need to be zeroed, it may not have been zeroed;
-// but if it came directly from the OS, it is already zeroed.
-func (c *mcache) allocLarge(size uintptr, needzero bool, noscan bool) (*mspan, bool) {
+func (c *mcache) allocLarge(size uintptr, noscan bool) *mspan {
        if size+_PageSize < size {
                throw("out of memory")
        }
@@ -224,7 +210,7 @@ func (c *mcache) allocLarge(size uintptr, needzero bool, noscan bool) (*mspan, b
        deductSweepCredit(npages*_PageSize, npages)
 
        spc := makeSpanClass(0, noscan)
-       s, isZeroed := mheap_.alloc(npages, spc, needzero)
+       s := mheap_.alloc(npages, spc)
        if s == nil {
                throw("out of memory")
        }
@@ -233,30 +219,24 @@ func (c *mcache) allocLarge(size uintptr, needzero bool, noscan bool) (*mspan, b
        atomic.Xadduintptr(&stats.largeAllocCount, 1)
        memstats.heapStats.release()
 
-       // Update gcController.heapLive and revise pacing if needed.
-       atomic.Xadd64(&gcController.heapLive, int64(npages*pageSize))
-       if trace.enabled {
-               // Trace that a heap alloc occurred because gcController.heapLive changed.
-               traceHeapAlloc()
-       }
-       if gcBlackenEnabled != 0 {
-               gcController.revise()
-       }
+       // Update heapLive.
+       gcController.update(int64(s.npages*pageSize), 0)
 
        // Put the large span in the mcentral swept list so that it's
        // visible to the background sweeper.
        mheap_.central[spc].mcentral.fullSwept(mheap_.sweepgen).push(s)
        s.limit = s.base() + size
        heapBitsForAddr(s.base()).initSpan(s)
-       return s, isZeroed
+       return s
 }
 
 func (c *mcache) releaseAll() {
        // Take this opportunity to flush scanAlloc.
-       atomic.Xadd64(&gcController.heapScan, int64(c.scanAlloc))
+       scanAlloc := int64(c.scanAlloc)
        c.scanAlloc = 0
 
        sg := mheap_.sweepgen
+       dHeapLive := int64(0)
        for i := range c.alloc {
                s := c.alloc[i]
                if s != &emptymspan {
@@ -273,7 +253,7 @@ func (c *mcache) releaseAll() {
                                // gcController.heapLive was totally recomputed since
                                // caching this span, so we don't do this for
                                // stale spans.
-                               atomic.Xadd64(&gcController.heapLive, -int64(n)*int64(s.elemsize))
+                               dHeapLive -= int64(n) * int64(s.elemsize)
                        }
                        // Release the span to the mcentral.
                        mheap_.central[i].mcentral.uncacheSpan(s)
@@ -290,10 +270,8 @@ func (c *mcache) releaseAll() {
        c.tinyAllocs = 0
        memstats.heapStats.release()
 
-       // Updated heapScan and possible gcController.heapLive.
-       if gcBlackenEnabled != 0 {
-               gcController.revise()
-       }
+       // Updated heapScan and heapLive.
+       gcController.update(dHeapLive, scanAlloc)
 }
 
 // prepareForSweep flushes c if the system has entered a new sweep phase
index 6013c94c69808a9d728b9e4d67c9db1fa16dc91f..e4bdf3507170e7eefdadac422c238db139e039a5 100644 (file)
@@ -102,56 +102,59 @@ func (c *mcentral) cacheSpan() *mspan {
        spanBudget := 100
 
        var s *mspan
-       sl := newSweepLocker()
-       sg := sl.sweepGen
+       var sl sweepLocker
 
        // Try partial swept spans first.
+       sg := mheap_.sweepgen
        if s = c.partialSwept(sg).pop(); s != nil {
                goto havespan
        }
 
-       // Now try partial unswept spans.
-       for ; spanBudget >= 0; spanBudget-- {
-               s = c.partialUnswept(sg).pop()
-               if s == nil {
-                       break
-               }
-               if s, ok := sl.tryAcquire(s); ok {
-                       // We got ownership of the span, so let's sweep it and use it.
-                       s.sweep(true)
-                       sl.dispose()
-                       goto havespan
-               }
-               // We failed to get ownership of the span, which means it's being or
-               // has been swept by an asynchronous sweeper that just couldn't remove it
-               // from the unswept list. That sweeper took ownership of the span and
-               // responsibility for either freeing it to the heap or putting it on the
-               // right swept list. Either way, we should just ignore it (and it's unsafe
-               // for us to do anything else).
-       }
-       // Now try full unswept spans, sweeping them and putting them into the
-       // right list if we fail to get a span.
-       for ; spanBudget >= 0; spanBudget-- {
-               s = c.fullUnswept(sg).pop()
-               if s == nil {
-                       break
-               }
-               if s, ok := sl.tryAcquire(s); ok {
-                       // We got ownership of the span, so let's sweep it.
-                       s.sweep(true)
-                       // Check if there's any free space.
-                       freeIndex := s.nextFreeIndex()
-                       if freeIndex != s.nelems {
-                               s.freeindex = freeIndex
-                               sl.dispose()
+       sl = sweep.active.begin()
+       if sl.valid {
+               // Now try partial unswept spans.
+               for ; spanBudget >= 0; spanBudget-- {
+                       s = c.partialUnswept(sg).pop()
+                       if s == nil {
+                               break
+                       }
+                       if s, ok := sl.tryAcquire(s); ok {
+                               // We got ownership of the span, so let's sweep it and use it.
+                               s.sweep(true)
+                               sweep.active.end(sl)
                                goto havespan
                        }
-                       // Add it to the swept list, because sweeping didn't give us any free space.
-                       c.fullSwept(sg).push(s.mspan)
+                       // We failed to get ownership of the span, which means it's being or
+                       // has been swept by an asynchronous sweeper that just couldn't remove it
+                       // from the unswept list. That sweeper took ownership of the span and
+                       // responsibility for either freeing it to the heap or putting it on the
+                       // right swept list. Either way, we should just ignore it (and it's unsafe
+                       // for us to do anything else).
+               }
+               // Now try full unswept spans, sweeping them and putting them into the
+               // right list if we fail to get a span.
+               for ; spanBudget >= 0; spanBudget-- {
+                       s = c.fullUnswept(sg).pop()
+                       if s == nil {
+                               break
+                       }
+                       if s, ok := sl.tryAcquire(s); ok {
+                               // We got ownership of the span, so let's sweep it.
+                               s.sweep(true)
+                               // Check if there's any free space.
+                               freeIndex := s.nextFreeIndex()
+                               if freeIndex != s.nelems {
+                                       s.freeindex = freeIndex
+                                       sweep.active.end(sl)
+                                       goto havespan
+                               }
+                               // Add it to the swept list, because sweeping didn't give us any free space.
+                               c.fullSwept(sg).push(s.mspan)
+                       }
+                       // See comment for partial unswept spans.
                }
-               // See comment for partial unswept spans.
+               sweep.active.end(sl)
        }
-       sl.dispose()
        if trace.enabled {
                traceGCSweepDone()
                traceDone = true
@@ -238,7 +241,7 @@ func (c *mcentral) grow() *mspan {
        npages := uintptr(class_to_allocnpages[c.spanclass.sizeclass()])
        size := uintptr(class_to_size[c.spanclass.sizeclass()])
 
-       s, _ := mheap_.alloc(npages, c.spanclass, true)
+       s := mheap_.alloc(npages, c.spanclass)
        if s == nil {
                return nil
        }
index dcbb9a1d51ee5222cc902776e54f54c909b66e02..b1525717921d1d588d27a7a9e73ee71bce95d283 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || netbsd || openbsd || solaris
-// +build dragonfly freebsd netbsd openbsd solaris
 
 package runtime
 
index fe940360c0e19a06243325d49bc0073477a842c3..4ca486ac4b74a41447fd3ba60d06c7f8162fc146 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package runtime
 
index 046c3441198bf5e4c44b29fe524e8e50d9ca17ca..2627792ced076a308a9410204dbbe51a8f0f8c6d 100644 (file)
@@ -30,8 +30,9 @@ tail:
        JBE     _5through8
        CMPL    BX, $16
        JBE     _9through16
-       CMPB    internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE     nosse2
+#ifdef GO386_softfloat
+       JMP     nosse2
+#endif
        PXOR    X0, X0
        CMPL    BX, $32
        JBE     _17through32
index 65639322b2a1cbb3872e16c530e4b35f8a0a36eb..91aa417ca2af76c57f3bedefb70b8f44a11e7172 100644 (file)
 // See memclrNoHeapPointers Go doc for important implementation constraints.
 
 // func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
-TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT|NOFRAME, $0-16
+TEXT runtime·memclrNoHeapPointers<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD ptr+0(FP), R3
        MOVD n+8(FP), R4
+#endif
 
        // Determine if there are doublewords to clear
 check:
index 1a43a1f724d7330f001c7fc5636356216ae8812c..389ef8847712e0d8adf982b9e20171118233ec73 100644 (file)
@@ -55,8 +55,9 @@ tail:
        JBE     move_5through8
        CMPL    BX, $16
        JBE     move_9through16
-       CMPB    internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE     nosse2
+#ifdef GO386_softfloat
+       JMP     nosse2
+#endif
        CMPL    BX, $32
        JBE     move_17through32
        CMPL    BX, $64
index fd16ad8129b3013010ffec54806304a3fc0949f8..b36b23f8ef3d29c6726e8426f2e096464ffa1cff 100644 (file)
 // number of 32 byte chunks
 #define QWORDS R10
 
-TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24
+TEXT runtime·memmove<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-24
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    to+0(FP), TGT
        MOVD    from+8(FP), SRC
        MOVD    n+16(FP), LEN
+#endif
 
        // Determine if there are doublewords to
        // copy so a more efficient move can be done
index 293c16b38b1bc1ebc5eb7802757d7bcaf92b5e60..b701a09b40a9471ab9b04c9742d7fddc11630aee 100644 (file)
@@ -30,7 +30,8 @@ type fixalloc struct {
        arg    unsafe.Pointer
        list   *mlink
        chunk  uintptr // use uintptr instead of unsafe.Pointer to avoid write barriers
-       nchunk uint32
+       nchunk uint32  // bytes remaining in current chunk
+       nalloc uint32  // size of new chunks in bytes
        inuse  uintptr // in-use bytes now
        stat   *sysMemStat
        zero   bool // zero allocations
@@ -50,12 +51,20 @@ type mlink struct {
 // Initialize f to allocate objects of the given size,
 // using the allocator to obtain chunks of memory.
 func (f *fixalloc) init(size uintptr, first func(arg, p unsafe.Pointer), arg unsafe.Pointer, stat *sysMemStat) {
+       if size > _FixAllocChunk {
+               throw("runtime: fixalloc size too large")
+       }
+       if min := unsafe.Sizeof(mlink{}); size < min {
+               size = min
+       }
+
        f.size = size
        f.first = first
        f.arg = arg
        f.list = nil
        f.chunk = 0
        f.nchunk = 0
+       f.nalloc = uint32(_FixAllocChunk / size * size) // Round _FixAllocChunk down to an exact multiple of size to eliminate tail waste
        f.inuse = 0
        f.stat = stat
        f.zero = true
@@ -77,8 +86,8 @@ func (f *fixalloc) alloc() unsafe.Pointer {
                return v
        }
        if uintptr(f.nchunk) < f.size {
-               f.chunk = uintptr(persistentalloc(_FixAllocChunk, 0, f.stat))
-               f.nchunk = _FixAllocChunk
+               f.chunk = uintptr(persistentalloc(uintptr(f.nalloc), 0, f.stat))
+               f.nchunk = f.nalloc
        }
 
        v := unsafe.Pointer(f.chunk)
index 34b5b482a355b634d2f2b9b85d120ca4981afd9e..96f4157b59864751da8b3ac5b798541dcbb43222 100644 (file)
@@ -154,7 +154,7 @@ func gcinit() {
                throw("size of Workbuf is suboptimal")
        }
        // No sweep on the first cycle.
-       mheap_.sweepDrained = 1
+       sweep.active.state.Store(sweepDrainedMask)
 
        // Initialize GC pacer state.
        // Use the environment variable GOGC for the initial gcPercent value.
@@ -545,7 +545,7 @@ func (t gcTrigger) test() bool {
                // own write.
                return gcController.heapLive >= gcController.trigger
        case gcTriggerTime:
-               if gcController.gcPercent < 0 {
+               if atomic.Loadint32(&gcController.gcPercent) < 0 {
                        return false
                }
                lastgc := int64(atomic.Load64(&memstats.last_gc_nanotime))
@@ -661,7 +661,9 @@ func gcStart(trigger gcTrigger) {
 
        work.cycles++
 
-       gcController.startCycle()
+       // Assists and workers can start the moment we start
+       // the world.
+       gcController.startCycle(now, int(gomaxprocs))
        work.heapGoal = gcController.heapGoal
 
        // In STW mode, disable scheduling of user Gs. This may also
@@ -704,10 +706,6 @@ func gcStart(trigger gcTrigger) {
        // mutators.
        atomic.Store(&gcBlackenEnabled, 1)
 
-       // Assists and workers can start the moment we start
-       // the world.
-       gcController.markStartTime = now
-
        // In STW mode, we could block the instant systemstack
        // returns, so make sure we're not preemptible.
        mp = acquirem()
@@ -891,7 +889,7 @@ top:
        // endCycle depends on all gcWork cache stats being flushed.
        // The termination algorithm above ensured that up to
        // allocations since the ragged barrier.
-       nextTriggerRatio := gcController.endCycle(work.userForced)
+       nextTriggerRatio := gcController.endCycle(now, int(gomaxprocs), work.userForced)
 
        // Perform mark termination. This will restart the world.
        gcMarkTermination(nextTriggerRatio)
@@ -965,12 +963,13 @@ func gcMarkTermination(nextTriggerRatio float64) {
                throw("gc done but gcphase != _GCoff")
        }
 
-       // Record heapGoal and heap_inuse for scavenger.
-       gcController.lastHeapGoal = gcController.heapGoal
+       // Record heap_inuse for scavenger.
        memstats.last_heap_inuse = memstats.heap_inuse
 
        // Update GC trigger and pacing for the next cycle.
        gcController.commit(nextTriggerRatio)
+       gcPaceSweeper(gcController.trigger)
+       gcPaceScavenger(gcController.heapGoal, gcController.lastHeapGoal)
 
        // Update timing memstats
        now := nanotime()
@@ -1021,8 +1020,10 @@ func gcMarkTermination(nextTriggerRatio float64) {
        // Those aren't tracked in any sweep lists, so we need to
        // count them against sweep completion until we ensure all
        // those spans have been forced out.
-       sl := newSweepLocker()
-       sl.blockCompletion()
+       sl := sweep.active.begin()
+       if !sl.valid {
+               throw("failed to set sweep barrier")
+       }
 
        systemstack(func() { startTheWorldWithSema(true) })
 
@@ -1049,7 +1050,7 @@ func gcMarkTermination(nextTriggerRatio float64) {
        })
        // Now that we've swept stale spans in mcaches, they don't
        // count against unswept spans.
-       sl.dispose()
+       sweep.active.end(sl)
 
        // Print gctrace before dropping worldsema. As soon as we drop
        // worldsema another cycle could start and smash the stats
@@ -1083,6 +1084,8 @@ func gcMarkTermination(nextTriggerRatio float64) {
                print(" ms cpu, ",
                        work.heap0>>20, "->", work.heap1>>20, "->", work.heap2>>20, " MB, ",
                        work.heapGoal>>20, " MB goal, ",
+                       gcController.stackScan>>20, " MB stacks, ",
+                       gcController.globalsScan>>20, " MB globals, ",
                        work.maxprocs, " P")
                if work.userForced {
                        print(" (forced)")
@@ -1287,15 +1290,9 @@ func gcBgMarkWorker() {
 
                // Account for time.
                duration := nanotime() - startTime
-               switch pp.gcMarkWorkerMode {
-               case gcMarkWorkerDedicatedMode:
-                       atomic.Xaddint64(&gcController.dedicatedMarkTime, duration)
-                       atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, 1)
-               case gcMarkWorkerFractionalMode:
-                       atomic.Xaddint64(&gcController.fractionalMarkTime, duration)
+               gcController.logWorkTime(pp.gcMarkWorkerMode, duration)
+               if pp.gcMarkWorkerMode == gcMarkWorkerFractionalMode {
                        atomic.Xaddint64(&pp.gcFractionalMarkTime, duration)
-               case gcMarkWorkerIdleMode:
-                       atomic.Xaddint64(&gcController.idleMarkTime, duration)
                }
 
                // Was this the last worker and did we run out
@@ -1415,30 +1412,22 @@ func gcMark(startTime int64) {
                gcw.dispose()
        }
 
-       // Update the marked heap stat.
-       gcController.heapMarked = work.bytesMarked
-
        // Flush scanAlloc from each mcache since we're about to modify
        // heapScan directly. If we were to flush this later, then scanAlloc
        // might have incorrect information.
+       //
+       // Note that it's not important to retain this information; we know
+       // exactly what heapScan is at this point via scanWork.
        for _, p := range allp {
                c := p.mcache
                if c == nil {
                        continue
                }
-               gcController.heapScan += uint64(c.scanAlloc)
                c.scanAlloc = 0
        }
 
-       // Update other GC heap size stats. This must happen after
-       // cachestats (which flushes local statistics to these) and
-       // flushallmcaches (which modifies gcController.heapLive).
-       gcController.heapLive = work.bytesMarked
-       gcController.heapScan = uint64(gcController.scanWork)
-
-       if trace.enabled {
-               traceHeapAlloc()
-       }
+       // Reset controller state.
+       gcController.resetLive(work.bytesMarked)
 }
 
 // gcSweep must be called on the system stack because it acquires the heap
@@ -1456,11 +1445,11 @@ func gcSweep(mode gcMode) {
 
        lock(&mheap_.lock)
        mheap_.sweepgen += 2
-       mheap_.sweepDrained = 0
-       mheap_.pagesSwept = 0
+       sweep.active.reset()
+       mheap_.pagesSwept.Store(0)
        mheap_.sweepArenas = mheap_.allArenas
-       mheap_.reclaimIndex = 0
-       mheap_.reclaimCredit = 0
+       mheap_.reclaimIndex.Store(0)
+       mheap_.reclaimCredit.Store(0)
        unlock(&mheap_.lock)
 
        sweep.centralIndex.clear()
index 874d9107209c0448368a1b90e5f2a0d9249b1b87..a5129bd1ee489f55f81eebf633b5bf6cc801a7aa 100644 (file)
@@ -8,7 +8,9 @@ package runtime
 
 import (
        "internal/goarch"
+       "internal/goexperiment"
        "runtime/internal/atomic"
+       "runtime/internal/sys"
        "unsafe"
 )
 
@@ -150,20 +152,28 @@ var oneptrmask = [...]uint8{1}
 //
 // Preemption must be disabled (because this uses a gcWork).
 //
+// Returns the amount of GC work credit produced by the operation.
+// If flushBgCredit is true, then that credit is also flushed
+// to the background credit pool.
+//
 // nowritebarrier is only advisory here.
 //
 //go:nowritebarrier
-func markroot(gcw *gcWork, i uint32) {
+func markroot(gcw *gcWork, i uint32, flushBgCredit bool) int64 {
        // Note: if you add a case here, please also update heapdump.go:dumproots.
+       var workDone int64
+       var workCounter *atomic.Int64
        switch {
        case work.baseData <= i && i < work.baseBSS:
+               workCounter = &gcController.globalsScanWork
                for _, datap := range activeModules() {
-                       markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, gcw, int(i-work.baseData))
+                       workDone += markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, gcw, int(i-work.baseData))
                }
 
        case work.baseBSS <= i && i < work.baseSpans:
+               workCounter = &gcController.globalsScanWork
                for _, datap := range activeModules() {
-                       markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, gcw, int(i-work.baseBSS))
+                       workDone += markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, gcw, int(i-work.baseBSS))
                }
 
        case i == fixedRootFinalizers:
@@ -183,6 +193,7 @@ func markroot(gcw *gcWork, i uint32) {
 
        default:
                // the rest is scanning goroutine stacks
+               workCounter = &gcController.stackScanWork
                var gp *g
                if work.baseStacks <= i && i < work.baseEnd {
                        // N.B. Atomic read of allglen in gcMarkRootPrepare
@@ -229,7 +240,7 @@ func markroot(gcw *gcWork, i uint32) {
                        if gp.gcscandone {
                                throw("g already scanned")
                        }
-                       scanstack(gp, gcw)
+                       workDone += scanstack(gp, gcw)
                        gp.gcscandone = true
                        resumeG(stopped)
 
@@ -238,13 +249,24 @@ func markroot(gcw *gcWork, i uint32) {
                        }
                })
        }
+       if goexperiment.PacerRedesign {
+               if workCounter != nil && workDone != 0 {
+                       workCounter.Add(workDone)
+                       if flushBgCredit {
+                               gcFlushBgCredit(workDone)
+                       }
+               }
+       }
+       return workDone
 }
 
 // markrootBlock scans the shard'th shard of the block of memory [b0,
 // b0+n0), with the given pointer mask.
 //
+// Returns the amount of work done.
+//
 //go:nowritebarrier
-func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) {
+func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) int64 {
        if rootBlockBytes%(8*goarch.PtrSize) != 0 {
                // This is necessary to pick byte offsets in ptrmask0.
                throw("rootBlockBytes must be a multiple of 8*ptrSize")
@@ -255,7 +277,7 @@ func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) {
        // These tests are written to avoid any possible overflow.
        off := uintptr(shard) * rootBlockBytes
        if off >= n0 {
-               return
+               return 0
        }
        b := b0 + off
        ptrmask := (*uint8)(add(unsafe.Pointer(ptrmask0), uintptr(shard)*(rootBlockBytes/(8*goarch.PtrSize))))
@@ -266,6 +288,7 @@ func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) {
 
        // Scan this shard.
        scanblock(b, n, ptrmask, gcw, nil)
+       return int64(n)
 }
 
 // markrootFreeGStacks frees stacks of dead Gs.
@@ -399,8 +422,8 @@ retry:
        // balance positive. When the required amount of work is low,
        // we over-assist to build up credit for future allocations
        // and amortize the cost of assisting.
-       assistWorkPerByte := float64frombits(atomic.Load64(&gcController.assistWorkPerByte))
-       assistBytesPerWork := float64frombits(atomic.Load64(&gcController.assistBytesPerWork))
+       assistWorkPerByte := gcController.assistWorkPerByte.Load()
+       assistBytesPerWork := gcController.assistBytesPerWork.Load()
        debtBytes := -gp.gcAssistBytes
        scanWork := int64(assistWorkPerByte * float64(debtBytes))
        if scanWork < gcOverAssistWork {
@@ -544,7 +567,7 @@ func gcAssistAlloc1(gp *g, scanWork int64) {
        // this scan work counts for. The "1+" is a poor man's
        // round-up, to ensure this adds credit even if
        // assistBytesPerWork is very low.
-       assistBytesPerWork := float64frombits(atomic.Load64(&gcController.assistBytesPerWork))
+       assistBytesPerWork := gcController.assistBytesPerWork.Load()
        gp.gcAssistBytes += 1 + int64(assistBytesPerWork*float64(workDone))
 
        // If this is the last worker and we ran out of work,
@@ -586,8 +609,6 @@ func gcWakeAllAssists() {
 //
 // gcParkAssist reports whether the assist is now satisfied. If it
 // returns false, the caller must retry the assist.
-//
-//go:nowritebarrier
 func gcParkAssist() bool {
        lock(&work.assistQueue.lock)
        // If the GC cycle finished while we were getting the lock,
@@ -639,7 +660,7 @@ func gcFlushBgCredit(scanWork int64) {
                return
        }
 
-       assistBytesPerWork := float64frombits(atomic.Load64(&gcController.assistBytesPerWork))
+       assistBytesPerWork := gcController.assistBytesPerWork.Load()
        scanBytes := int64(float64(scanWork) * assistBytesPerWork)
 
        lock(&work.assistQueue.lock)
@@ -673,7 +694,7 @@ func gcFlushBgCredit(scanWork int64) {
 
        if scanBytes > 0 {
                // Convert from scan bytes back to work.
-               assistWorkPerByte := float64frombits(atomic.Load64(&gcController.assistWorkPerByte))
+               assistWorkPerByte := gcController.assistWorkPerByte.Load()
                scanWork = int64(float64(scanBytes) * assistWorkPerByte)
                atomic.Xaddint64(&gcController.bgScanCredit, scanWork)
        }
@@ -682,6 +703,13 @@ func gcFlushBgCredit(scanWork int64) {
 
 // scanstack scans gp's stack, greying all pointers found on the stack.
 //
+// For goexperiment.PacerRedesign:
+// Returns the amount of scan work performed, but doesn't update
+// gcController.stackScanWork or flush any credit. Any background credit produced
+// by this function should be flushed by its caller. scanstack itself can't
+// safely flush because it may result in trying to wake up a goroutine that
+// was just scanned, resulting in a self-deadlock.
+//
 // scanstack will also shrink the stack if it is safe to do so. If it
 // is not, it schedules a stack shrink for the next synchronous safe
 // point.
@@ -691,7 +719,7 @@ func gcFlushBgCredit(scanWork int64) {
 //
 //go:nowritebarrier
 //go:systemstack
-func scanstack(gp *g, gcw *gcWork) {
+func scanstack(gp *g, gcw *gcWork) int64 {
        if readgstatus(gp)&_Gscan == 0 {
                print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n")
                throw("scanstack - bad status")
@@ -702,7 +730,7 @@ func scanstack(gp *g, gcw *gcWork) {
                print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
                throw("mark - bad status")
        case _Gdead:
-               return
+               return 0
        case _Grunning:
                print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
                throw("scanstack: goroutine not stopped")
@@ -714,6 +742,15 @@ func scanstack(gp *g, gcw *gcWork) {
                throw("can't scan our own stack")
        }
 
+       // stackSize is the amount of work we'll be reporting.
+       //
+       // We report the total stack size, more than we scan,
+       // because this number needs to line up with gcControllerState's
+       // stackScan and scannableStackSize fields.
+       //
+       // See the documentation on those fields for more information.
+       stackSize := gp.stack.hi - gp.stack.lo
+
        if isShrinkStackSafe(gp) {
                // Shrink the stack if not much of it is being used.
                shrinkstack(gp)
@@ -804,7 +841,7 @@ func scanstack(gp *g, gcw *gcWork) {
                        println()
                        printunlock()
                }
-               gcdata := r.gcdata
+               gcdata := r.gcdata()
                var s *mspan
                if r.useGCProg() {
                        // This path is pretty unlikely, an object large enough
@@ -853,6 +890,7 @@ func scanstack(gp *g, gcw *gcWork) {
        if state.buf != nil || state.cbuf != nil || state.freeBuf != nil {
                throw("remaining pointer buffers")
        }
+       return int64(stackSize)
 }
 
 // Scan a stack frame: local variables and function arguments/results.
@@ -924,7 +962,8 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) {
                // varp is 0 for defers, where there are no locals.
                // In that case, there can't be a pointer to its args, either.
                // (And all args would be scanned above anyway.)
-               for i, obj := range objs {
+               for i := range objs {
+                       obj := &objs[i]
                        off := obj.off
                        base := frame.varp // locals base pointer
                        if off >= 0 {
@@ -938,7 +977,7 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) {
                        if stackTraceDebug {
                                println("stkobj at", hex(ptr), "of size", obj.size)
                        }
-                       state.addObject(ptr, &objs[i])
+                       state.addObject(ptr, obj)
                }
        }
 }
@@ -984,7 +1023,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
        flushBgCredit := flags&gcDrainFlushBgCredit != 0
        idle := flags&gcDrainIdle != 0
 
-       initScanWork := gcw.scanWork
+       initScanWork := gcw.heapScanWork
 
        // checkWork is the scan work before performing the next
        // self-preempt check.
@@ -1007,7 +1046,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
                        if job >= work.markrootJobs {
                                break
                        }
-                       markroot(gcw, job)
+                       markroot(gcw, job, flushBgCredit)
                        if check != nil && check() {
                                goto done
                        }
@@ -1046,14 +1085,14 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
                // Flush background scan work credit to the global
                // account if we've accumulated enough locally so
                // mutator assists can draw on it.
-               if gcw.scanWork >= gcCreditSlack {
-                       atomic.Xaddint64(&gcController.scanWork, gcw.scanWork)
+               if gcw.heapScanWork >= gcCreditSlack {
+                       gcController.heapScanWork.Add(gcw.heapScanWork)
                        if flushBgCredit {
-                               gcFlushBgCredit(gcw.scanWork - initScanWork)
+                               gcFlushBgCredit(gcw.heapScanWork - initScanWork)
                                initScanWork = 0
                        }
-                       checkWork -= gcw.scanWork
-                       gcw.scanWork = 0
+                       checkWork -= gcw.heapScanWork
+                       gcw.heapScanWork = 0
 
                        if checkWork <= 0 {
                                checkWork += drainCheckThreshold
@@ -1066,12 +1105,12 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
 
 done:
        // Flush remaining scan work credit.
-       if gcw.scanWork > 0 {
-               atomic.Xaddint64(&gcController.scanWork, gcw.scanWork)
+       if gcw.heapScanWork > 0 {
+               gcController.heapScanWork.Add(gcw.heapScanWork)
                if flushBgCredit {
-                       gcFlushBgCredit(gcw.scanWork - initScanWork)
+                       gcFlushBgCredit(gcw.heapScanWork - initScanWork)
                }
-               gcw.scanWork = 0
+               gcw.heapScanWork = 0
        }
 }
 
@@ -1095,20 +1134,15 @@ func gcDrainN(gcw *gcWork, scanWork int64) int64 {
 
        // There may already be scan work on the gcw, which we don't
        // want to claim was done by this call.
-       workFlushed := -gcw.scanWork
+       workFlushed := -gcw.heapScanWork
 
        gp := getg().m.curg
-       for !gp.preempt && workFlushed+gcw.scanWork < scanWork {
+       for !gp.preempt && workFlushed+gcw.heapScanWork < scanWork {
                // See gcDrain comment.
                if work.full == 0 {
                        gcw.balance()
                }
 
-               // This might be a good place to add prefetch code...
-               // if(wbuf.nobj > 4) {
-               //         PREFETCH(wbuf->obj[wbuf.nobj - 3];
-               //  }
-               //
                b := gcw.tryGetFast()
                if b == 0 {
                        b = gcw.tryGet()
@@ -1122,26 +1156,27 @@ func gcDrainN(gcw *gcWork, scanWork int64) int64 {
 
                if b == 0 {
                        // Try to do a root job.
-                       //
-                       // TODO: Assists should get credit for this
-                       // work.
                        if work.markrootNext < work.markrootJobs {
                                job := atomic.Xadd(&work.markrootNext, +1) - 1
                                if job < work.markrootJobs {
-                                       markroot(gcw, job)
+                                       work := markroot(gcw, job, false)
+                                       if goexperiment.PacerRedesign {
+                                               workFlushed += work
+                                       }
                                        continue
                                }
                        }
                        // No heap or root jobs.
                        break
                }
+
                scanobject(b, gcw)
 
                // Flush background scan work credit.
-               if gcw.scanWork >= gcCreditSlack {
-                       atomic.Xaddint64(&gcController.scanWork, gcw.scanWork)
-                       workFlushed += gcw.scanWork
-                       gcw.scanWork = 0
+               if gcw.heapScanWork >= gcCreditSlack {
+                       gcController.heapScanWork.Add(gcw.heapScanWork)
+                       workFlushed += gcw.heapScanWork
+                       gcw.heapScanWork = 0
                }
        }
 
@@ -1149,14 +1184,14 @@ func gcDrainN(gcw *gcWork, scanWork int64) int64 {
        // here because this never flushes to bgScanCredit and
        // gcw.dispose will flush any remaining work to scanWork.
 
-       return workFlushed + gcw.scanWork
+       return workFlushed + gcw.heapScanWork
 }
 
 // scanblock scans b as scanobject would, but using an explicit
 // pointer bitmap instead of the heap bitmap.
 //
 // This is used to scan non-heap roots, so it does not update
-// gcw.bytesMarked or gcw.scanWork.
+// gcw.bytesMarked or gcw.heapScanWork.
 //
 // If stk != nil, possible stack pointers are also reported to stk.putPtr.
 //go:nowritebarrier
@@ -1199,6 +1234,12 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork, stk *stackScanState)
 //
 //go:nowritebarrier
 func scanobject(b uintptr, gcw *gcWork) {
+       // Prefetch object before we scan it.
+       //
+       // This will overlap fetching the beginning of the object with initial
+       // setup before we start scanning the object.
+       sys.Prefetch(b)
+
        // Find the bits for b and the size of the object at b.
        //
        // b is either the beginning of an object, in which case this
@@ -1280,7 +1321,7 @@ func scanobject(b uintptr, gcw *gcWork) {
                }
        }
        gcw.bytesMarked += uint64(n)
-       gcw.scanWork += int64(i)
+       gcw.heapScanWork += int64(i)
 }
 
 // scanConservative scans block [b, b+n) conservatively, treating any
@@ -1437,12 +1478,12 @@ func greyobject(obj, base, off uintptr, span *mspan, gcw *gcWork, objIndex uintp
                }
        }
 
-       // Queue the obj for scanning. The PREFETCH(obj) logic has been removed but
-       // seems like a nice optimization that can be added back in.
-       // There needs to be time between the PREFETCH and the use.
-       // Previously we put the obj in an 8 element buffer that is drained at a rate
-       // to give the PREFETCH time to do its work.
-       // Use of PREFETCHNTA might be more appropriate than PREFETCH
+       // We're adding obj to P's local workbuf, so it's likely
+       // this object will be processed soon by the same P.
+       // Even if the workbuf gets flushed, there will likely still be
+       // some benefit on platforms with inclusive shared caches.
+       sys.Prefetch(obj)
+       // Queue the obj for scanning.
        if !gcw.putFast(obj) {
                gcw.put(obj)
        }
@@ -1519,7 +1560,19 @@ func gcmarknewobject(span *mspan, obj, size, scanSize uintptr) {
 
        gcw := &getg().m.p.ptr().gcw
        gcw.bytesMarked += uint64(size)
-       gcw.scanWork += int64(scanSize)
+       if !goexperiment.PacerRedesign {
+               // The old pacer counts newly allocated memory toward
+               // heapScanWork because heapScan is continuously updated
+               // throughout the GC cyle with newly allocated memory. However,
+               // these objects are never actually scanned, so we need
+               // to account for them in heapScanWork here, "faking" their work.
+               // Otherwise the pacer will think it's always behind, potentially
+               // by a large margin.
+               //
+               // The new pacer doesn't care about this because it ceases to updated
+               // heapScan once a GC cycle starts, effectively snapshotting it.
+               gcw.heapScanWork += int64(scanSize)
+       }
 }
 
 // gcMarkTinyAllocs greys all active tiny alloc blocks.
index 9338359de7d7719151489d47329ab9c4286ba8a0..230e78b000d544e38cf461d67493882eee5e37c6 100644 (file)
@@ -6,6 +6,7 @@ package runtime
 
 import (
        "internal/cpu"
+       "internal/goexperiment"
        "runtime/internal/atomic"
        "unsafe"
 )
@@ -13,7 +14,8 @@ import (
 const (
        // gcGoalUtilization is the goal CPU utilization for
        // marking as a fraction of GOMAXPROCS.
-       gcGoalUtilization = 0.30
+       gcGoalUtilization = goexperiment.PacerRedesignInt*gcBackgroundUtilization +
+               (1-goexperiment.PacerRedesignInt)*(gcBackgroundUtilization+0.05)
 
        // gcBackgroundUtilization is the fixed CPU utilization for background
        // marking. It must be <= gcGoalUtilization. The difference between
@@ -26,10 +28,15 @@ const (
        // better control CPU and heap growth. However, the larger the gap,
        // the more mutator assists are expected to happen, which impact
        // mutator latency.
+       //
+       // If goexperiment.PacerRedesign, the trigger feedback controller
+       // is replaced with an estimate of the mark/cons ratio that doesn't
+       // have the same saturation issues, so this is set equal to
+       // gcGoalUtilization.
        gcBackgroundUtilization = 0.25
 
        // gcCreditSlack is the amount of scan work credit that can
-       // accumulate locally before updating gcController.scanWork and,
+       // accumulate locally before updating gcController.heapScanWork and,
        // optionally, gcController.bgScanCredit. Lower values give a more
        // accurate assist ratio and make it more likely that assists will
        // successfully steal background credit. Higher values reduce memory
@@ -46,7 +53,12 @@ const (
        gcOverAssistWork = 64 << 10
 
        // defaultHeapMinimum is the value of heapMinimum for GOGC==100.
-       defaultHeapMinimum = 4 << 20
+       defaultHeapMinimum = goexperiment.PacerRedesignInt*(512<<10) +
+               (1-goexperiment.PacerRedesignInt)*(4<<20)
+
+       // scannableStackSizeSlack is the bytes of stack space allocated or freed
+       // that can accumulate on a P before updating gcController.stackSize.
+       scannableStackSizeSlack = 8 << 10
 )
 
 func init() {
@@ -73,6 +85,10 @@ var gcController gcControllerState
 
 type gcControllerState struct {
        // Initialized from $GOGC. GOGC=off means no GC.
+       //
+       // Updated atomically with mheap_.lock held or during a STW.
+       // Safe to read atomically at any time, or non-atomically with
+       // mheap_.lock or STW.
        gcPercent int32
 
        _ uint32 // padding so following 64-bit values are 8-byte aligned
@@ -100,6 +116,8 @@ type gcControllerState struct {
        // during mark termination for the next cycle's trigger.
        //
        // Protected by mheap_.lock or a STW.
+       //
+       // Used if !goexperiment.PacerRedesign.
        triggerRatio float64
 
        // trigger is the heap size that triggers marking.
@@ -114,6 +132,31 @@ type gcControllerState struct {
        // Protected by mheap_.lock or a STW.
        trigger uint64
 
+       // consMark is the estimated per-CPU consMark ratio for the application.
+       //
+       // It represents the ratio between the application's allocation
+       // rate, as bytes allocated per CPU-time, and the GC's scan rate,
+       // as bytes scanned per CPU-time.
+       // The units of this ratio are (B / cpu-ns) / (B / cpu-ns).
+       //
+       // At a high level, this value is computed as the bytes of memory
+       // allocated (cons) per unit of scan work completed (mark) in a GC
+       // cycle, divided by the CPU time spent on each activity.
+       //
+       // Updated at the end of each GC cycle, in endCycle.
+       //
+       // For goexperiment.PacerRedesign.
+       consMark float64
+
+       // consMarkController holds the state for the mark-cons ratio
+       // estimation over time.
+       //
+       // Its purpose is to smooth out noisiness in the computation of
+       // consMark; see consMark for details.
+       //
+       // For goexperiment.PacerRedesign.
+       consMarkController piController
+
        // heapGoal is the goal heapLive for when next GC ends.
        // Set to ^uint64(0) if disabled.
        //
@@ -156,28 +199,73 @@ type gcControllerState struct {
        // is the live heap (as counted by heapLive), but omitting
        // no-scan objects and no-scan tails of objects.
        //
-       // Whenever this is updated, call this gcControllerState's
-       // revise() method.
+       // For !goexperiment.PacerRedesign: Whenever this is updated,
+       // call this gcControllerState's revise() method. It is read
+       // and written atomically or with the world stopped.
        //
-       // Read and written atomically or with the world stopped.
+       // For goexperiment.PacerRedesign: This value is fixed at the
+       // start of a GC cycle, so during a GC cycle it is safe to
+       // read without atomics, and it represents the maximum scannable
+       // heap.
        heapScan uint64
 
+       // lastHeapScan is the number of bytes of heap that were scanned
+       // last GC cycle. It is the same as heapMarked, but only
+       // includes the "scannable" parts of objects.
+       //
+       // Updated when the world is stopped.
+       lastHeapScan uint64
+
+       // stackScan is a snapshot of scannableStackSize taken at each GC
+       // STW pause and is used in pacing decisions.
+       //
+       // Updated only while the world is stopped.
+       stackScan uint64
+
+       // scannableStackSize is the amount of allocated goroutine stack space in
+       // use by goroutines.
+       //
+       // This number tracks allocated goroutine stack space rather than used
+       // goroutine stack space (i.e. what is actually scanned) because used
+       // goroutine stack space is much harder to measure cheaply. By using
+       // allocated space, we make an overestimate; this is OK, it's better
+       // to conservatively overcount than undercount.
+       //
+       // Read and updated atomically.
+       scannableStackSize uint64
+
+       // globalsScan is the total amount of global variable space
+       // that is scannable.
+       //
+       // Read and updated atomically.
+       globalsScan uint64
+
        // heapMarked is the number of bytes marked by the previous
        // GC. After mark termination, heapLive == heapMarked, but
        // unlike heapLive, heapMarked does not change until the
        // next mark termination.
        heapMarked uint64
 
-       // scanWork is the total scan work performed this cycle. This
-       // is updated atomically during the cycle. Updates occur in
-       // bounded batches, since it is both written and read
-       // throughout the cycle. At the end of the cycle, this is how
+       // heapScanWork is the total heap scan work performed this cycle.
+       // stackScanWork is the total stack scan work performed this cycle.
+       // globalsScanWork is the total globals scan work performed this cycle.
+       //
+       // These are updated atomically during the cycle. Updates occur in
+       // bounded batches, since they are both written and read
+       // throughout the cycle. At the end of the cycle, heapScanWork is how
        // much of the retained heap is scannable.
        //
-       // Currently this is the bytes of heap scanned. For most uses,
-       // this is an opaque unit of work, but for estimation the
-       // definition is important.
-       scanWork int64
+       // Currently these are measured in bytes. For most uses, this is an
+       // opaque unit of work, but for estimation the definition is important.
+       //
+       // Note that stackScanWork includes all allocated space, not just the
+       // size of the stack itself, mirroring stackSize.
+       //
+       // For !goexperiment.PacerRedesign, stackScanWork and globalsScanWork
+       // are always zero.
+       heapScanWork    atomic.Int64
+       stackScanWork   atomic.Int64
+       globalsScanWork atomic.Int64
 
        // bgScanCredit is the scan work credit accumulated by the
        // concurrent background scan. This credit is accumulated by
@@ -222,24 +310,14 @@ type gcControllerState struct {
        // bytes that should be performed by mutator assists. This is
        // computed at the beginning of each cycle and updated every
        // time heapScan is updated.
-       //
-       // Stored as a uint64, but it's actually a float64. Use
-       // float64frombits to get the value.
-       //
-       // Read and written atomically.
-       assistWorkPerByte uint64
+       assistWorkPerByte atomic.Float64
 
        // assistBytesPerWork is 1/assistWorkPerByte.
        //
-       // Stored as a uint64, but it's actually a float64. Use
-       // float64frombits to get the value.
-       //
-       // Read and written atomically.
-       //
        // Note that because this is read and written independently
        // from assistWorkPerByte users may notice a skew between
        // the two values, and such a state should be safe.
-       assistBytesPerWork uint64
+       assistBytesPerWork atomic.Float64
 
        // fractionalUtilizationGoal is the fraction of wall clock
        // time that should be spent in the fractional mark worker on
@@ -253,19 +331,48 @@ type gcControllerState struct {
        // If this is zero, no fractional workers are needed.
        fractionalUtilizationGoal float64
 
+       // test indicates that this is a test-only copy of gcControllerState.
+       test bool
+
        _ cpu.CacheLinePad
 }
 
 func (c *gcControllerState) init(gcPercent int32) {
        c.heapMinimum = defaultHeapMinimum
 
-       // Set a reasonable initial GC trigger.
-       c.triggerRatio = 7 / 8.0
+       if goexperiment.PacerRedesign {
+               c.consMarkController = piController{
+                       // Tuned first via the Ziegler-Nichols process in simulation,
+                       // then the integral time was manually tuned against real-world
+                       // applications to deal with noisiness in the measured cons/mark
+                       // ratio.
+                       kp: 0.9,
+                       ti: 4.0,
+
+                       // An update is done once per GC cycle.
+                       period: 1,
+
+                       // Set a high reset time in GC cycles.
+                       // This is inversely proportional to the rate at which we
+                       // accumulate error from clipping. By making this very high
+                       // we make the accumulation slow. In general, clipping is
+                       // OK in our situation, hence the choice.
+                       //
+                       // Tune this if we get unintended effects from clipping for
+                       // a long time.
+                       tt:  1000,
+                       min: -1000,
+                       max: 1000,
+               }
+       } else {
+               // Set a reasonable initial GC trigger.
+               c.triggerRatio = 7 / 8.0
 
-       // Fake a heapMarked value so it looks like a trigger at
-       // heapMinimum is the appropriate growth from heapMarked.
-       // This will go into computing the initial GC goal.
-       c.heapMarked = uint64(float64(c.heapMinimum) / (1 + c.triggerRatio))
+               // Fake a heapMarked value so it looks like a trigger at
+               // heapMinimum is the appropriate growth from heapMarked.
+               // This will go into computing the initial GC goal.
+               c.heapMarked = uint64(float64(c.heapMinimum) / (1 + c.triggerRatio))
+       }
 
        // This will also compute and set the GC trigger and goal.
        c.setGCPercent(gcPercent)
@@ -274,13 +381,17 @@ func (c *gcControllerState) init(gcPercent int32) {
 // startCycle resets the GC controller's state and computes estimates
 // for a new GC cycle. The caller must hold worldsema and the world
 // must be stopped.
-func (c *gcControllerState) startCycle() {
-       c.scanWork = 0
+func (c *gcControllerState) startCycle(markStartTime int64, procs int) {
+       c.heapScanWork.Store(0)
+       c.stackScanWork.Store(0)
+       c.globalsScanWork.Store(0)
        c.bgScanCredit = 0
        c.assistTime = 0
        c.dedicatedMarkTime = 0
        c.fractionalMarkTime = 0
        c.idleMarkTime = 0
+       c.markStartTime = markStartTime
+       c.stackScan = atomic.Load64(&c.scannableStackSize)
 
        // Ensure that the heap goal is at least a little larger than
        // the current live heap size. This may not be the case if GC
@@ -289,8 +400,14 @@ func (c *gcControllerState) startCycle() {
        // GOGC. Assist is proportional to this distance, so enforce a
        // minimum distance, even if it means going over the GOGC goal
        // by a tiny bit.
-       if c.heapGoal < c.heapLive+1024*1024 {
-               c.heapGoal = c.heapLive + 1024*1024
+       if goexperiment.PacerRedesign {
+               if c.heapGoal < c.heapLive+64<<10 {
+                       c.heapGoal = c.heapLive + 64<<10
+               }
+       } else {
+               if c.heapGoal < c.heapLive+1<<20 {
+                       c.heapGoal = c.heapLive + 1<<20
+               }
        }
 
        // Compute the background mark utilization goal. In general,
@@ -298,7 +415,7 @@ func (c *gcControllerState) startCycle() {
        // dedicated workers so that the utilization is closest to
        // 25%. For small GOMAXPROCS, this would introduce too much
        // error, so we add fractional workers in that case.
-       totalUtilizationGoal := float64(gomaxprocs) * gcBackgroundUtilization
+       totalUtilizationGoal := float64(procs) * gcBackgroundUtilization
        c.dedicatedMarkWorkersNeeded = int64(totalUtilizationGoal + 0.5)
        utilError := float64(c.dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1
        const maxUtilError = 0.3
@@ -311,14 +428,14 @@ func (c *gcControllerState) startCycle() {
                        // Too many dedicated workers.
                        c.dedicatedMarkWorkersNeeded--
                }
-               c.fractionalUtilizationGoal = (totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded)) / float64(gomaxprocs)
+               c.fractionalUtilizationGoal = (totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded)) / float64(procs)
        } else {
                c.fractionalUtilizationGoal = 0
        }
 
        // In STW mode, we just want dedicated workers.
        if debug.gcstoptheworld > 0 {
-               c.dedicatedMarkWorkersNeeded = int64(gomaxprocs)
+               c.dedicatedMarkWorkersNeeded = int64(procs)
                c.fractionalUtilizationGoal = 0
        }
 
@@ -333,7 +450,7 @@ func (c *gcControllerState) startCycle() {
        c.revise()
 
        if debug.gcpacertrace > 0 {
-               assistRatio := float64frombits(atomic.Load64(&c.assistWorkPerByte))
+               assistRatio := c.assistWorkPerByte.Load()
                print("pacer: assist ratio=", assistRatio,
                        " (scan ", gcController.heapScan>>20, " MB in ",
                        work.initialHeapLive>>20, "->",
@@ -365,7 +482,7 @@ func (c *gcControllerState) startCycle() {
 // is when assists are enabled and the necessary statistics are
 // available).
 func (c *gcControllerState) revise() {
-       gcPercent := c.gcPercent
+       gcPercent := atomic.Loadint32(&c.gcPercent)
        if gcPercent < 0 {
                // If GC is disabled but we're running a forced GC,
                // act like GOGC is huge for the below calculations.
@@ -373,32 +490,80 @@ func (c *gcControllerState) revise() {
        }
        live := atomic.Load64(&c.heapLive)
        scan := atomic.Load64(&c.heapScan)
-       work := atomic.Loadint64(&c.scanWork)
+       work := c.heapScanWork.Load() + c.stackScanWork.Load() + c.globalsScanWork.Load()
 
        // Assume we're under the soft goal. Pace GC to complete at
        // heapGoal assuming the heap is in steady-state.
        heapGoal := int64(atomic.Load64(&c.heapGoal))
 
-       // Compute the expected scan work remaining.
-       //
-       // This is estimated based on the expected
-       // steady-state scannable heap. For example, with
-       // GOGC=100, only half of the scannable heap is
-       // expected to be live, so that's what we target.
-       //
-       // (This is a float calculation to avoid overflowing on
-       // 100*heapScan.)
-       scanWorkExpected := int64(float64(scan) * 100 / float64(100+gcPercent))
-
-       if int64(live) > heapGoal || work > scanWorkExpected {
-               // We're past the soft goal, or we've already done more scan
-               // work than we expected. Pace GC so that in the worst case it
-               // will complete by the hard goal.
-               const maxOvershoot = 1.1
-               heapGoal = int64(float64(heapGoal) * maxOvershoot)
-
-               // Compute the upper bound on the scan work remaining.
-               scanWorkExpected = int64(scan)
+       var scanWorkExpected int64
+       if goexperiment.PacerRedesign {
+               // The expected scan work is computed as the amount of bytes scanned last
+               // GC cycle, plus our estimate of stacks and globals work for this cycle.
+               scanWorkExpected = int64(c.lastHeapScan + c.stackScan + c.globalsScan)
+
+               // maxScanWork is a worst-case estimate of the amount of scan work that
+               // needs to be performed in this GC cycle. Specifically, it represents
+               // the case where *all* scannable memory turns out to be live.
+               maxScanWork := int64(scan + c.stackScan + c.globalsScan)
+               if work > scanWorkExpected {
+                       // We've already done more scan work than expected. Because our expectation
+                       // is based on a steady-state scannable heap size, we assume this means our
+                       // heap is growing. Compute a new heap goal that takes our existing runway
+                       // computed for scanWorkExpected and extrapolates it to maxScanWork, the worst-case
+                       // scan work. This keeps our assist ratio stable if the heap continues to grow.
+                       //
+                       // The effect of this mechanism is that assists stay flat in the face of heap
+                       // growths. It's OK to use more memory this cycle to scan all the live heap,
+                       // because the next GC cycle is inevitably going to use *at least* that much
+                       // memory anyway.
+                       extHeapGoal := int64(float64(heapGoal-int64(c.trigger))/float64(scanWorkExpected)*float64(maxScanWork)) + int64(c.trigger)
+                       scanWorkExpected = maxScanWork
+
+                       // hardGoal is a hard limit on the amount that we're willing to push back the
+                       // heap goal, and that's twice the heap goal (i.e. if GOGC=100 and the heap and/or
+                       // stacks and/or globals grow to twice their size, this limits the current GC cycle's
+                       // growth to 4x the original live heap's size).
+                       //
+                       // This maintains the invariant that we use no more memory than the next GC cycle
+                       // will anyway.
+                       hardGoal := int64((1.0 + float64(gcPercent)/100.0) * float64(heapGoal))
+                       if extHeapGoal > hardGoal {
+                               extHeapGoal = hardGoal
+                       }
+                       heapGoal = extHeapGoal
+               }
+               if int64(live) > heapGoal {
+                       // We're already past our heap goal, even the extrapolated one.
+                       // Leave ourselves some extra runway, so in the worst case we
+                       // finish by that point.
+                       const maxOvershoot = 1.1
+                       heapGoal = int64(float64(heapGoal) * maxOvershoot)
+
+                       // Compute the upper bound on the scan work remaining.
+                       scanWorkExpected = maxScanWork
+               }
+       } else {
+               // Compute the expected scan work remaining.
+               //
+               // This is estimated based on the expected
+               // steady-state scannable heap. For example, with
+               // GOGC=100, only half of the scannable heap is
+               // expected to be live, so that's what we target.
+               //
+               // (This is a float calculation to avoid overflowing on
+               // 100*heapScan.)
+               scanWorkExpected = int64(float64(scan) * 100 / float64(100+gcPercent))
+               if int64(live) > heapGoal || work > scanWorkExpected {
+                       // We're past the soft goal, or we've already done more scan
+                       // work than we expected. Pace GC so that in the worst case it
+                       // will complete by the hard goal.
+                       const maxOvershoot = 1.1
+                       heapGoal = int64(float64(heapGoal) * maxOvershoot)
+
+                       // Compute the upper bound on the scan work remaining.
+                       scanWorkExpected = int64(scan)
+               }
        }
 
        // Compute the remaining scan work estimate.
@@ -439,14 +604,95 @@ func (c *gcControllerState) revise() {
        // cycle.
        assistWorkPerByte := float64(scanWorkRemaining) / float64(heapRemaining)
        assistBytesPerWork := float64(heapRemaining) / float64(scanWorkRemaining)
-       atomic.Store64(&c.assistWorkPerByte, float64bits(assistWorkPerByte))
-       atomic.Store64(&c.assistBytesPerWork, float64bits(assistBytesPerWork))
+       c.assistWorkPerByte.Store(assistWorkPerByte)
+       c.assistBytesPerWork.Store(assistBytesPerWork)
 }
 
-// endCycle computes the trigger ratio for the next cycle.
+// endCycle computes the trigger ratio (!goexperiment.PacerRedesign)
+// or the consMark estimate (goexperiment.PacerRedesign) for the next cycle.
+// Returns the trigger ratio if application, or 0 (goexperiment.PacerRedesign).
 // userForced indicates whether the current GC cycle was forced
 // by the application.
-func (c *gcControllerState) endCycle(userForced bool) float64 {
+func (c *gcControllerState) endCycle(now int64, procs int, userForced bool) float64 {
+       // Record last heap goal for the scavenger.
+       // We'll be updating the heap goal soon.
+       gcController.lastHeapGoal = gcController.heapGoal
+
+       // Compute the duration of time for which assists were turned on.
+       assistDuration := now - c.markStartTime
+
+       // Assume background mark hit its utilization goal.
+       utilization := gcBackgroundUtilization
+       // Add assist utilization; avoid divide by zero.
+       if assistDuration > 0 {
+               utilization += float64(c.assistTime) / float64(assistDuration*int64(procs))
+       }
+
+       if goexperiment.PacerRedesign {
+               if c.heapLive <= c.trigger {
+                       // Shouldn't happen, but let's be very safe about this in case the
+                       // GC is somehow extremely short.
+                       //
+                       // In this case though, the only reasonable value for c.heapLive-c.trigger
+                       // would be 0, which isn't really all that useful, i.e. the GC was so short
+                       // that it didn't matter.
+                       //
+                       // Ignore this case and don't update anything.
+                       return 0
+               }
+               idleUtilization := 0.0
+               if assistDuration > 0 {
+                       idleUtilization = float64(c.idleMarkTime) / float64(assistDuration*int64(procs))
+               }
+               // Determine the cons/mark ratio.
+               //
+               // The units we want for the numerator and denominator are both B / cpu-ns.
+               // We get this by taking the bytes allocated or scanned, and divide by the amount of
+               // CPU time it took for those operations. For allocations, that CPU time is
+               //
+               //    assistDuration * procs * (1 - utilization)
+               //
+               // Where utilization includes just background GC workers and assists. It does *not*
+               // include idle GC work time, because in theory the mutator is free to take that at
+               // any point.
+               //
+               // For scanning, that CPU time is
+               //
+               //    assistDuration * procs * (utilization + idleUtilization)
+               //
+               // In this case, we *include* idle utilization, because that is additional CPU time that the
+               // the GC had available to it.
+               //
+               // In effect, idle GC time is sort of double-counted here, but it's very weird compared
+               // to other kinds of GC work, because of how fluid it is. Namely, because the mutator is
+               // *always* free to take it.
+               //
+               // So this calculation is really:
+               //     (heapLive-trigger) / (assistDuration * procs * (1-utilization)) /
+               //         (scanWork) / (assistDuration * procs * (utilization+idleUtilization)
+               //
+               // Note that because we only care about the ratio, assistDuration and procs cancel out.
+               scanWork := c.heapScanWork.Load() + c.stackScanWork.Load() + c.globalsScanWork.Load()
+               currentConsMark := (float64(c.heapLive-c.trigger) * (utilization + idleUtilization)) /
+                       (float64(scanWork) * (1 - utilization))
+
+               // Update cons/mark controller.
+               oldConsMark := c.consMark
+               c.consMark = c.consMarkController.next(c.consMark, currentConsMark)
+
+               if debug.gcpacertrace > 0 {
+                       printlock()
+                       print("pacer: ", int(utilization*100), "% CPU (", int(gcGoalUtilization*100), " exp.) for ")
+                       print(c.heapScanWork.Load(), "+", c.stackScanWork.Load(), "+", c.globalsScanWork.Load(), " B work (", c.lastHeapScan+c.stackScan+c.globalsScan, " B exp.) ")
+                       print("in ", c.trigger, " B -> ", c.heapLive, " B (∆goal ", int64(c.heapLive)-int64(c.heapGoal), ", cons/mark ", oldConsMark, ")")
+                       println()
+                       printunlock()
+               }
+               return 0
+       }
+
+       // !goexperiment.PacerRedesign below.
+
        if userForced {
                // Forced GC means this cycle didn't start at the
                // trigger, so where it finished isn't good
@@ -473,15 +719,6 @@ func (c *gcControllerState) endCycle(userForced bool) float64 {
        // heap growth is the error.
        goalGrowthRatio := c.effectiveGrowthRatio()
        actualGrowthRatio := float64(c.heapLive)/float64(c.heapMarked) - 1
-       assistDuration := nanotime() - c.markStartTime
-
-       // Assume background mark hit its utilization goal.
-       utilization := gcBackgroundUtilization
-       // Add assist utilization; avoid divide by zero.
-       if assistDuration > 0 {
-               utilization += float64(c.assistTime) / float64(assistDuration*int64(gomaxprocs))
-       }
-
        triggerError := goalGrowthRatio - c.triggerRatio - utilization/gcGoalUtilization*(actualGrowthRatio-c.triggerRatio)
 
        // Finally, we adjust the trigger for next time by this error,
@@ -500,7 +737,7 @@ func (c *gcControllerState) endCycle(userForced bool) float64 {
                H_g := int64(float64(H_m_prev) * (1 + h_g))
                u_a := utilization
                u_g := gcGoalUtilization
-               W_a := c.scanWork
+               W_a := c.heapScanWork.Load()
                print("pacer: H_m_prev=", H_m_prev,
                        " h_t=", h_t, " H_T=", H_T,
                        " h_a=", h_a, " H_a=", H_a,
@@ -636,9 +873,82 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
        return gp
 }
 
-// commit sets the trigger ratio and updates everything
-// derived from it: the absolute trigger, the heap goal, mark pacing,
-// and sweep pacing.
+// resetLive sets up the controller state for the next mark phase after the end
+// of the previous one. Must be called after endCycle and before commit, before
+// the world is started.
+//
+// The world must be stopped.
+func (c *gcControllerState) resetLive(bytesMarked uint64) {
+       c.heapMarked = bytesMarked
+       c.heapLive = bytesMarked
+       c.heapScan = uint64(c.heapScanWork.Load())
+       c.lastHeapScan = uint64(c.heapScanWork.Load())
+
+       // heapLive was updated, so emit a trace event.
+       if trace.enabled {
+               traceHeapAlloc()
+       }
+}
+
+// logWorkTime updates mark work accounting in the controller by a duration of
+// work in nanoseconds.
+//
+// Safe to execute at any time.
+func (c *gcControllerState) logWorkTime(mode gcMarkWorkerMode, duration int64) {
+       switch mode {
+       case gcMarkWorkerDedicatedMode:
+               atomic.Xaddint64(&c.dedicatedMarkTime, duration)
+               atomic.Xaddint64(&c.dedicatedMarkWorkersNeeded, 1)
+       case gcMarkWorkerFractionalMode:
+               atomic.Xaddint64(&c.fractionalMarkTime, duration)
+       case gcMarkWorkerIdleMode:
+               atomic.Xaddint64(&c.idleMarkTime, duration)
+       default:
+               throw("logWorkTime: unknown mark worker mode")
+       }
+}
+
+func (c *gcControllerState) update(dHeapLive, dHeapScan int64) {
+       if dHeapLive != 0 {
+               atomic.Xadd64(&gcController.heapLive, dHeapLive)
+               if trace.enabled {
+                       // gcController.heapLive changed.
+                       traceHeapAlloc()
+               }
+       }
+       // Only update heapScan in the new pacer redesign if we're not
+       // currently in a GC.
+       if !goexperiment.PacerRedesign || gcBlackenEnabled == 0 {
+               if dHeapScan != 0 {
+                       atomic.Xadd64(&gcController.heapScan, dHeapScan)
+               }
+       }
+       if gcBlackenEnabled != 0 {
+               // gcController.heapLive and heapScan changed.
+               c.revise()
+       }
+}
+
+func (c *gcControllerState) addScannableStack(pp *p, amount int64) {
+       if pp == nil {
+               atomic.Xadd64(&c.scannableStackSize, amount)
+               return
+       }
+       pp.scannableStackSizeDelta += amount
+       if pp.scannableStackSizeDelta >= scannableStackSizeSlack || pp.scannableStackSizeDelta <= -scannableStackSizeSlack {
+               atomic.Xadd64(&c.scannableStackSize, pp.scannableStackSizeDelta)
+               pp.scannableStackSizeDelta = 0
+       }
+}
+
+func (c *gcControllerState) addGlobals(amount int64) {
+       atomic.Xadd64(&c.globalsScan, amount)
+}
+
+// commit recomputes all pacing parameters from scratch, namely
+// absolute trigger, the heap goal, mark pacing, and sweep pacing.
+//
+// If goexperiment.PacerRedesign is true, triggerRatio is ignored.
 //
 // This can be called any time. If GC is the in the middle of a
 // concurrent phase, it will adjust the pacing of that phase.
@@ -648,8 +958,134 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
 //
 // mheap_.lock must be held or the world must be stopped.
 func (c *gcControllerState) commit(triggerRatio float64) {
-       assertWorldStoppedOrLockHeld(&mheap_.lock)
+       if !c.test {
+               assertWorldStoppedOrLockHeld(&mheap_.lock)
+       }
+
+       if !goexperiment.PacerRedesign {
+               c.oldCommit(triggerRatio)
+               return
+       }
+
+       // Compute the next GC goal, which is when the allocated heap
+       // has grown by GOGC/100 over where it started the last cycle,
+       // plus additional runway for non-heap sources of GC work.
+       goal := ^uint64(0)
+       if c.gcPercent >= 0 {
+               goal = c.heapMarked + (c.heapMarked+atomic.Load64(&c.stackScan)+atomic.Load64(&c.globalsScan))*uint64(c.gcPercent)/100
+       }
+
+       // Don't trigger below the minimum heap size.
+       minTrigger := c.heapMinimum
+       if !isSweepDone() {
+               // Concurrent sweep happens in the heap growth
+               // from gcController.heapLive to trigger, so ensure
+               // that concurrent sweep has some heap growth
+               // in which to perform sweeping before we
+               // start the next GC cycle.
+               sweepMin := atomic.Load64(&c.heapLive) + sweepMinHeapDistance
+               if sweepMin > minTrigger {
+                       minTrigger = sweepMin
+               }
+       }
+
+       // If we let the trigger go too low, then if the application
+       // is allocating very rapidly we might end up in a situation
+       // where we're allocating black during a nearly always-on GC.
+       // The result of this is a growing heap and ultimately an
+       // increase in RSS. By capping us at a point >0, we're essentially
+       // saying that we're OK using more CPU during the GC to prevent
+       // this growth in RSS.
+       //
+       // The current constant was chosen empirically: given a sufficiently
+       // fast/scalable allocator with 48 Ps that could drive the trigger ratio
+       // to <0.05, this constant causes applications to retain the same peak
+       // RSS compared to not having this allocator.
+       if triggerBound := uint64(0.7*float64(goal-c.heapMarked)) + c.heapMarked; minTrigger < triggerBound {
+               minTrigger = triggerBound
+       }
+
+       // For small heaps, set the max trigger point at 95% of the heap goal.
+       // This ensures we always have *some* headroom when the GC actually starts.
+       // For larger heaps, set the max trigger point at the goal, minus the
+       // minimum heap size.
+       // This choice follows from the fact that the minimum heap size is chosen
+       // to reflect the costs of a GC with no work to do. With a large heap but
+       // very little scan work to perform, this gives us exactly as much runway
+       // as we would need, in the worst case.
+       maxRunway := uint64(0.95 * float64(goal-c.heapMarked))
+       if largeHeapMaxRunway := goal - c.heapMinimum; goal > c.heapMinimum && maxRunway < largeHeapMaxRunway {
+               maxRunway = largeHeapMaxRunway
+       }
+       maxTrigger := maxRunway + c.heapMarked
+       if maxTrigger < minTrigger {
+               maxTrigger = minTrigger
+       }
+
+       // Compute the trigger by using our estimate of the cons/mark ratio.
+       //
+       // The idea is to take our expected scan work, and multiply it by
+       // the cons/mark ratio to determine how long it'll take to complete
+       // that scan work in terms of bytes allocated. This gives us our GC's
+       // runway.
+       //
+       // However, the cons/mark ratio is a ratio of rates per CPU-second, but
+       // here we care about the relative rates for some division of CPU
+       // resources among the mutator and the GC.
+       //
+       // To summarize, we have B / cpu-ns, and we want B / ns. We get that
+       // by multiplying by our desired division of CPU resources. We choose
+       // to express CPU resources as GOMAPROCS*fraction. Note that because
+       // we're working with a ratio here, we can omit the number of CPU cores,
+       // because they'll appear in the numerator and denominator and cancel out.
+       // As a result, this is basically just "weighing" the cons/mark ratio by
+       // our desired division of resources.
+       //
+       // Furthermore, by setting the trigger so that CPU resources are divided
+       // this way, assuming that the cons/mark ratio is correct, we make that
+       // division a reality.
+       var trigger uint64
+       runway := uint64((c.consMark * (1 - gcGoalUtilization) / (gcGoalUtilization)) * float64(c.lastHeapScan+c.stackScan+c.globalsScan))
+       if runway > goal {
+               trigger = minTrigger
+       } else {
+               trigger = goal - runway
+       }
+       if trigger < minTrigger {
+               trigger = minTrigger
+       }
+       if trigger > maxTrigger {
+               trigger = maxTrigger
+       }
+       if trigger > goal {
+               goal = trigger
+       }
+
+       // Commit to the trigger and goal.
+       c.trigger = trigger
+       atomic.Store64(&c.heapGoal, goal)
+       if trace.enabled {
+               traceHeapGoal()
+       }
+
+       // Update mark pacing.
+       if gcphase != _GCoff {
+               c.revise()
+       }
+}
 
+// oldCommit sets the trigger ratio and updates everything
+// derived from it: the absolute trigger, the heap goal, mark pacing,
+// and sweep pacing.
+//
+// This can be called any time. If GC is the in the middle of a
+// concurrent phase, it will adjust the pacing of that phase.
+//
+// This depends on gcPercent, gcController.heapMarked, and
+// gcController.heapLive. These must be up to date.
+//
+// For !goexperiment.PacerRedesign.
+func (c *gcControllerState) oldCommit(triggerRatio float64) {
        // Compute the next GC goal, which is when the allocated heap
        // has grown by GOGC/100 over the heap marked by the last
        // cycle.
@@ -741,42 +1177,6 @@ func (c *gcControllerState) commit(triggerRatio float64) {
        if gcphase != _GCoff {
                c.revise()
        }
-
-       // Update sweep pacing.
-       if isSweepDone() {
-               mheap_.sweepPagesPerByte = 0
-       } else {
-               // Concurrent sweep needs to sweep all of the in-use
-               // pages by the time the allocated heap reaches the GC
-               // trigger. Compute the ratio of in-use pages to sweep
-               // per byte allocated, accounting for the fact that
-               // some might already be swept.
-               heapLiveBasis := atomic.Load64(&c.heapLive)
-               heapDistance := int64(trigger) - int64(heapLiveBasis)
-               // Add a little margin so rounding errors and
-               // concurrent sweep are less likely to leave pages
-               // unswept when GC starts.
-               heapDistance -= 1024 * 1024
-               if heapDistance < _PageSize {
-                       // Avoid setting the sweep ratio extremely high
-                       heapDistance = _PageSize
-               }
-               pagesSwept := atomic.Load64(&mheap_.pagesSwept)
-               pagesInUse := atomic.Load64(&mheap_.pagesInUse)
-               sweepDistancePages := int64(pagesInUse) - int64(pagesSwept)
-               if sweepDistancePages <= 0 {
-                       mheap_.sweepPagesPerByte = 0
-               } else {
-                       mheap_.sweepPagesPerByte = float64(sweepDistancePages) / float64(heapDistance)
-                       mheap_.sweepHeapLiveBasis = heapLiveBasis
-                       // Write pagesSweptBasis last, since this
-                       // signals concurrent sweeps to recompute
-                       // their debt.
-                       atomic.Store64(&mheap_.pagesSweptBasis, pagesSwept)
-               }
-       }
-
-       gcPaceScavenger()
 }
 
 // effectiveGrowthRatio returns the current effective heap growth
@@ -789,7 +1189,9 @@ func (c *gcControllerState) commit(triggerRatio float64) {
 //
 // mheap_.lock must be held or the world must be stopped.
 func (c *gcControllerState) effectiveGrowthRatio() float64 {
-       assertWorldStoppedOrLockHeld(&mheap_.lock)
+       if !c.test {
+               assertWorldStoppedOrLockHeld(&mheap_.lock)
+       }
 
        egogc := float64(atomic.Load64(&c.heapGoal)-c.heapMarked) / float64(c.heapMarked)
        if egogc < 0 {
@@ -802,15 +1204,20 @@ func (c *gcControllerState) effectiveGrowthRatio() float64 {
 // setGCPercent updates gcPercent and all related pacer state.
 // Returns the old value of gcPercent.
 //
+// Calls gcControllerState.commit.
+//
 // The world must be stopped, or mheap_.lock must be held.
 func (c *gcControllerState) setGCPercent(in int32) int32 {
-       assertWorldStoppedOrLockHeld(&mheap_.lock)
+       if !c.test {
+               assertWorldStoppedOrLockHeld(&mheap_.lock)
+       }
 
        out := c.gcPercent
        if in < 0 {
                in = -1
        }
-       c.gcPercent = in
+       // Write it atomically so readers like revise() can read it safely.
+       atomic.Storeint32(&c.gcPercent, in)
        c.heapMinimum = defaultHeapMinimum * uint64(c.gcPercent) / 100
        // Update pacing in response to gcPercent change.
        c.commit(c.triggerRatio)
@@ -824,6 +1231,8 @@ func setGCPercent(in int32) (out int32) {
        systemstack(func() {
                lock(&mheap_.lock)
                out = gcController.setGCPercent(in)
+               gcPaceSweeper(gcController.trigger)
+               gcPaceScavenger(gcController.heapGoal, gcController.lastHeapGoal)
                unlock(&mheap_.lock)
        })
 
@@ -846,3 +1255,38 @@ func readGOGC() int32 {
        }
        return 100
 }
+
+type piController struct {
+       kp float64 // Proportional constant.
+       ti float64 // Integral time constant.
+       tt float64 // Reset time in GC cyles.
+
+       // Period in GC cycles between updates.
+       period float64
+
+       min, max float64 // Output boundaries.
+
+       // PI controller state.
+
+       errIntegral float64 // Integral of the error from t=0 to now.
+}
+
+func (c *piController) next(input, setpoint float64) float64 {
+       // Compute the raw output value.
+       prop := c.kp * (setpoint - input)
+       rawOutput := prop + c.errIntegral
+
+       // Clamp rawOutput into output.
+       output := rawOutput
+       if output < c.min {
+               output = c.min
+       } else if output > c.max {
+               output = c.max
+       }
+
+       // Update the controller's state.
+       if c.ti != 0 && c.tt != 0 {
+               c.errIntegral += (c.kp*c.period/c.ti)*(setpoint-input) + (c.period/c.tt)*(output-rawOutput)
+       }
+       return output
+}
diff --git a/src/runtime/mgcpacer_test.go b/src/runtime/mgcpacer_test.go
new file mode 100644 (file)
index 0000000..9ec0e51
--- /dev/null
@@ -0,0 +1,717 @@
+// Copyright 2021 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 runtime_test
+
+import (
+       "fmt"
+       "internal/goexperiment"
+       "math"
+       "math/rand"
+       . "runtime"
+       "testing"
+       "time"
+)
+
+func TestGcPacer(t *testing.T) {
+       t.Parallel()
+
+       const initialHeapBytes = 256 << 10
+       for _, e := range []*gcExecTest{
+               {
+                       // The most basic test case: a steady-state heap.
+                       // Growth to an O(MiB) heap, then constant heap size, alloc/scan rates.
+                       name:          "Steady",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     constant(33.0),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if n >= 25 {
+                                       if goexperiment.PacerRedesign {
+                                               // For the pacer redesign, assert something even stronger: at this alloc/scan rate,
+                                               // it should be extremely close to the goal utilization.
+                                               assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, GCGoalUtilization, 0.005)
+                                       }
+
+                                       // Make sure the pacer settles into a non-degenerate state in at least 25 GC cycles.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.005)
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                               }
+                       },
+               },
+               {
+                       // Same as the steady-state case, but lots of stacks to scan relative to the heap size.
+                       name:          "SteadyBigStacks",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     constant(132.0),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(2048).sum(ramp(128<<20, 8)),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               // Check the same conditions as the steady-state case, except the old pacer can't
+                               // really handle this well, so don't check the goal ratio for it.
+                               n := len(c)
+                               if n >= 25 {
+                                       if goexperiment.PacerRedesign {
+                                               // For the pacer redesign, assert something even stronger: at this alloc/scan rate,
+                                               // it should be extremely close to the goal utilization.
+                                               assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, GCGoalUtilization, 0.005)
+                                               assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                                       }
+
+                                       // Make sure the pacer settles into a non-degenerate state in at least 25 GC cycles.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.005)
+                               }
+                       },
+               },
+               {
+                       // Same as the steady-state case, but lots of globals to scan relative to the heap size.
+                       name:          "SteadyBigGlobals",
+                       gcPercent:     100,
+                       globalsBytes:  128 << 20,
+                       nCores:        8,
+                       allocRate:     constant(132.0),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               // Check the same conditions as the steady-state case, except the old pacer can't
+                               // really handle this well, so don't check the goal ratio for it.
+                               n := len(c)
+                               if n >= 25 {
+                                       if goexperiment.PacerRedesign {
+                                               // For the pacer redesign, assert something even stronger: at this alloc/scan rate,
+                                               // it should be extremely close to the goal utilization.
+                                               assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, GCGoalUtilization, 0.005)
+                                               assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                                       }
+
+                                       // Make sure the pacer settles into a non-degenerate state in at least 25 GC cycles.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.005)
+                               }
+                       },
+               },
+               {
+                       // This tests the GC pacer's response to a small change in allocation rate.
+                       name:          "StepAlloc",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     constant(33.0).sum(ramp(66.0, 1).delay(50)),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        100,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if (n >= 25 && n < 50) || n >= 75 {
+                                       // Make sure the pacer settles into a non-degenerate state in at least 25 GC cycles
+                                       // and then is able to settle again after a significant jump in allocation rate.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.005)
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                               }
+                       },
+               },
+               {
+                       // This tests the GC pacer's response to a large change in allocation rate.
+                       name:          "HeavyStepAlloc",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     constant(33).sum(ramp(330, 1).delay(50)),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        100,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if (n >= 25 && n < 50) || n >= 75 {
+                                       // Make sure the pacer settles into a non-degenerate state in at least 25 GC cycles
+                                       // and then is able to settle again after a significant jump in allocation rate.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.005)
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                               }
+                       },
+               },
+               {
+                       // This tests the GC pacer's response to a change in the fraction of the scannable heap.
+                       name:          "StepScannableFrac",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     constant(128.0),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(0.2).sum(unit(0.5).delay(50)),
+                       stackBytes:    constant(8192),
+                       length:        100,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if (n >= 25 && n < 50) || n >= 75 {
+                                       // Make sure the pacer settles into a non-degenerate state in at least 25 GC cycles
+                                       // and then is able to settle again after a significant jump in allocation rate.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.005)
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                               }
+                       },
+               },
+               {
+                       // Tests the pacer for a high GOGC value with a large heap growth happening
+                       // in the middle. The purpose of the large heap growth is to check if GC
+                       // utilization ends up sensitive
+                       name:          "HighGOGC",
+                       gcPercent:     1500,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     random(7, 0x53).offset(165),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12), random(0.01, 0x1), unit(14).delay(25)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if goexperiment.PacerRedesign && n > 12 {
+                                       if n == 26 {
+                                               // In the 26th cycle there's a heap growth. Overshoot is expected to maintain
+                                               // a stable utilization, but we should *never* overshoot more than GOGC of
+                                               // the next cycle.
+                                               assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.90, 15)
+                                       } else {
+                                               // Give a wider goal range here. With such a high GOGC value we're going to be
+                                               // forced to undershoot.
+                                               //
+                                               // TODO(mknyszek): Instead of placing a 0.95 limit on the trigger, make the limit
+                                               // based on absolute bytes, that's based somewhat in how the minimum heap size
+                                               // is determined.
+                                               assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.90, 1.05)
+                                       }
+
+                                       // Ensure utilization remains stable despite a growth in live heap size
+                                       // at GC #25. This test fails prior to the GC pacer redesign.
+                                       //
+                                       // Because GOGC is so large, we should also be really close to the goal utilization.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, GCGoalUtilization, GCGoalUtilization+0.03)
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.03)
+                               }
+                       },
+               },
+               {
+                       // This test makes sure that in the face of a varying (in this case, oscillating) allocation
+                       // rate, the pacer does a reasonably good job of staying abreast of the changes.
+                       name:          "OscAlloc",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     oscillate(13, 0, 8).offset(67),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if n > 12 {
+                                       // After the 12th GC, the heap will stop growing. Now, just make sure that:
+                                       // 1. Utilization isn't varying _too_ much, and
+                                       // 2. The pacer is mostly keeping up with the goal.
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                                       if goexperiment.PacerRedesign {
+                                               assertInRange(t, "GC utilization", c[n-1].gcUtilization, 0.25, 0.3)
+                                       } else {
+                                               // The old pacer is messier here, and needs a lot more tolerance.
+                                               assertInRange(t, "GC utilization", c[n-1].gcUtilization, 0.25, 0.4)
+                                       }
+                               }
+                       },
+               },
+               {
+                       // This test is the same as OscAlloc, but instead of oscillating, the allocation rate is jittery.
+                       name:          "JitterAlloc",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     random(13, 0xf).offset(132),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12), random(0.01, 0xe)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if n > 12 {
+                                       // After the 12th GC, the heap will stop growing. Now, just make sure that:
+                                       // 1. Utilization isn't varying _too_ much, and
+                                       // 2. The pacer is mostly keeping up with the goal.
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                                       if goexperiment.PacerRedesign {
+                                               assertInRange(t, "GC utilization", c[n-1].gcUtilization, 0.25, 0.3)
+                                       } else {
+                                               // The old pacer is messier here, and needs a lot more tolerance.
+                                               assertInRange(t, "GC utilization", c[n-1].gcUtilization, 0.25, 0.4)
+                                       }
+                               }
+                       },
+               },
+               {
+                       // This test is the same as JitterAlloc, but with a much higher allocation rate.
+                       // The jitter is proportionally the same.
+                       name:          "HeavyJitterAlloc",
+                       gcPercent:     100,
+                       globalsBytes:  32 << 10,
+                       nCores:        8,
+                       allocRate:     random(33.0, 0x0).offset(330),
+                       scanRate:      constant(1024.0),
+                       growthRate:    constant(2.0).sum(ramp(-1.0, 12), random(0.01, 0x152)),
+                       scannableFrac: constant(1.0),
+                       stackBytes:    constant(8192),
+                       length:        50,
+                       checker: func(t *testing.T, c []gcCycleResult) {
+                               n := len(c)
+                               if n > 13 {
+                                       // After the 12th GC, the heap will stop growing. Now, just make sure that:
+                                       // 1. Utilization isn't varying _too_ much, and
+                                       // 2. The pacer is mostly keeping up with the goal.
+                                       // We start at the 13th here because we want to use the 12th as a reference.
+                                       assertInRange(t, "goal ratio", c[n-1].goalRatio(), 0.95, 1.05)
+                                       // Unlike the other tests, GC utilization here will vary more and tend higher.
+                                       // Just make sure it's not going too crazy.
+                                       assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[n-2].gcUtilization, 0.05)
+                                       if goexperiment.PacerRedesign {
+                                               assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[11].gcUtilization, 0.05)
+                                       } else {
+                                               // The old pacer is messier here, and needs a little more tolerance.
+                                               assertInEpsilon(t, "GC utilization", c[n-1].gcUtilization, c[11].gcUtilization, 0.07)
+                                       }
+                               }
+                       },
+               },
+               // TODO(mknyszek): Write a test that exercises the pacer's hard goal.
+               // This is difficult in the idealized model this testing framework places
+               // the pacer in, because the calculated overshoot is directly proportional
+               // to the runway for the case of the expected work.
+               // However, it is still possible to trigger this case if something exceptional
+               // happens between calls to revise; the framework just doesn't support this yet.
+       } {
+               e := e
+               t.Run(e.name, func(t *testing.T) {
+                       t.Parallel()
+
+                       c := NewGCController(e.gcPercent)
+                       var bytesAllocatedBlackLast int64
+                       results := make([]gcCycleResult, 0, e.length)
+                       for i := 0; i < e.length; i++ {
+                               cycle := e.next()
+                               c.StartCycle(cycle.stackBytes, e.globalsBytes, cycle.scannableFrac, e.nCores)
+
+                               // Update pacer incrementally as we complete scan work.
+                               const (
+                                       revisePeriod = 500 * time.Microsecond
+                                       rateConv     = 1024 * float64(revisePeriod) / float64(time.Millisecond)
+                               )
+                               var nextHeapMarked int64
+                               if i == 0 {
+                                       nextHeapMarked = initialHeapBytes
+                               } else {
+                                       nextHeapMarked = int64(float64(int64(c.HeapMarked())-bytesAllocatedBlackLast) * cycle.growthRate)
+                               }
+                               globalsScanWorkLeft := int64(e.globalsBytes)
+                               stackScanWorkLeft := int64(cycle.stackBytes)
+                               heapScanWorkLeft := int64(float64(nextHeapMarked) * cycle.scannableFrac)
+                               doWork := func(work int64) (int64, int64, int64) {
+                                       var deltas [3]int64
+
+                                       // Do globals work first, then stacks, then heap.
+                                       for i, workLeft := range []*int64{&globalsScanWorkLeft, &stackScanWorkLeft, &heapScanWorkLeft} {
+                                               if *workLeft == 0 {
+                                                       continue
+                                               }
+                                               if *workLeft > work {
+                                                       deltas[i] += work
+                                                       *workLeft -= work
+                                                       work = 0
+                                                       break
+                                               } else {
+                                                       deltas[i] += *workLeft
+                                                       work -= *workLeft
+                                                       *workLeft = 0
+                                               }
+                                       }
+                                       return deltas[0], deltas[1], deltas[2]
+                               }
+                               var (
+                                       gcDuration          int64
+                                       assistTime          int64
+                                       bytesAllocatedBlack int64
+                               )
+                               for heapScanWorkLeft+stackScanWorkLeft+globalsScanWorkLeft > 0 {
+                                       // Simulate GC assist pacing.
+                                       //
+                                       // Note that this is an idealized view of the GC assist pacing
+                                       // mechanism.
+
+                                       // From the assist ratio and the alloc and scan rates, we can idealize what
+                                       // the GC CPU utilization looks like.
+                                       //
+                                       // We start with assistRatio = (bytes of scan work) / (bytes of runway) (by definition).
+                                       //
+                                       // Over revisePeriod, we can also calculate how many bytes are scanned and
+                                       // allocated, given some GC CPU utilization u:
+                                       //
+                                       //     bytesScanned   = scanRate  * rateConv * nCores * u
+                                       //     bytesAllocated = allocRate * rateConv * nCores * (1 - u)
+                                       //
+                                       // During revisePeriod, assistRatio is kept constant, and GC assists kick in to
+                                       // maintain it. Specifically, they act to prevent too many bytes being allocated
+                                       // compared to how many bytes are scanned. It directly defines the ratio of
+                                       // bytesScanned to bytesAllocated over this period, hence:
+                                       //
+                                       //     assistRatio = bytesScanned / bytesAllocated
+                                       //
+                                       // From this, we can solve for utilization, because everything else has already
+                                       // been determined:
+                                       //
+                                       //     assistRatio = (scanRate * rateConv * nCores * u) / (allocRate * rateConv * nCores * (1 - u))
+                                       //     assistRatio = (scanRate * u) / (allocRate * (1 - u))
+                                       //     assistRatio * allocRate * (1-u) = scanRate * u
+                                       //     assistRatio * allocRate - assistRatio * allocRate * u = scanRate * u
+                                       //     assistRatio * allocRate = assistRatio * allocRate * u + scanRate * u
+                                       //     assistRatio * allocRate = (assistRatio * allocRate + scanRate) * u
+                                       //     u = (assistRatio * allocRate) / (assistRatio * allocRate + scanRate)
+                                       //
+                                       // Note that this may give a utilization that is _less_ than GCBackgroundUtilization,
+                                       // which isn't possible in practice because of dedicated workers. Thus, this case
+                                       // must be interpreted as GC assists not kicking in at all, and just round up. All
+                                       // downstream values will then have this accounted for.
+                                       assistRatio := c.AssistWorkPerByte()
+                                       utilization := assistRatio * cycle.allocRate / (assistRatio*cycle.allocRate + cycle.scanRate)
+                                       if utilization < GCBackgroundUtilization {
+                                               utilization = GCBackgroundUtilization
+                                       }
+
+                                       // Knowing the utilization, calculate bytesScanned and bytesAllocated.
+                                       bytesScanned := int64(cycle.scanRate * rateConv * float64(e.nCores) * utilization)
+                                       bytesAllocated := int64(cycle.allocRate * rateConv * float64(e.nCores) * (1 - utilization))
+
+                                       // Subtract work from our model.
+                                       globalsScanned, stackScanned, heapScanned := doWork(bytesScanned)
+
+                                       // doWork may not use all of bytesScanned.
+                                       // In this case, the GC actually ends sometime in this period.
+                                       // Let's figure out when, exactly, and adjust bytesAllocated too.
+                                       actualElapsed := revisePeriod
+                                       actualAllocated := bytesAllocated
+                                       if actualScanned := globalsScanned + stackScanned + heapScanned; actualScanned < bytesScanned {
+                                               // actualScanned = scanRate * rateConv * (t / revisePeriod) * nCores * u
+                                               // => t = actualScanned * revisePeriod / (scanRate * rateConv * nCores * u)
+                                               actualElapsed = time.Duration(float64(actualScanned) * float64(revisePeriod) / (cycle.scanRate * rateConv * float64(e.nCores) * utilization))
+                                               actualAllocated = int64(cycle.allocRate * rateConv * float64(actualElapsed) / float64(revisePeriod) * float64(e.nCores) * (1 - utilization))
+                                       }
+
+                                       // Ask the pacer to revise.
+                                       c.Revise(GCControllerReviseDelta{
+                                               HeapLive:        actualAllocated,
+                                               HeapScan:        int64(float64(actualAllocated) * cycle.scannableFrac),
+                                               HeapScanWork:    heapScanned,
+                                               StackScanWork:   stackScanned,
+                                               GlobalsScanWork: globalsScanned,
+                                       })
+
+                                       // Accumulate variables.
+                                       assistTime += int64(float64(actualElapsed) * float64(e.nCores) * (utilization - GCBackgroundUtilization))
+                                       gcDuration += int64(actualElapsed)
+                                       bytesAllocatedBlack += actualAllocated
+                               }
+
+                               // Put together the results, log them, and concatenate them.
+                               result := gcCycleResult{
+                                       cycle:         i + 1,
+                                       heapLive:      c.HeapMarked(),
+                                       heapScannable: int64(float64(int64(c.HeapMarked())-bytesAllocatedBlackLast) * cycle.scannableFrac),
+                                       heapTrigger:   c.Trigger(),
+                                       heapPeak:      c.HeapLive(),
+                                       heapGoal:      c.HeapGoal(),
+                                       gcUtilization: float64(assistTime)/(float64(gcDuration)*float64(e.nCores)) + GCBackgroundUtilization,
+                               }
+                               t.Log("GC", result.String())
+                               results = append(results, result)
+
+                               // Run the checker for this test.
+                               e.check(t, results)
+
+                               c.EndCycle(uint64(nextHeapMarked+bytesAllocatedBlack), assistTime, gcDuration, e.nCores)
+
+                               bytesAllocatedBlackLast = bytesAllocatedBlack
+                       }
+               })
+       }
+}
+
+type gcExecTest struct {
+       name string
+
+       gcPercent    int
+       globalsBytes uint64
+       nCores       int
+
+       allocRate     float64Stream // > 0, KiB / cpu-ms
+       scanRate      float64Stream // > 0, KiB / cpu-ms
+       growthRate    float64Stream // > 0
+       scannableFrac float64Stream // Clamped to [0, 1]
+       stackBytes    float64Stream // Multiple of 2048.
+       length        int
+
+       checker func(*testing.T, []gcCycleResult)
+}
+
+// minRate is an arbitrary minimum for allocRate, scanRate, and growthRate.
+// These values just cannot be zero.
+const minRate = 0.0001
+
+func (e *gcExecTest) next() gcCycle {
+       return gcCycle{
+               allocRate:     e.allocRate.min(minRate)(),
+               scanRate:      e.scanRate.min(minRate)(),
+               growthRate:    e.growthRate.min(minRate)(),
+               scannableFrac: e.scannableFrac.limit(0, 1)(),
+               stackBytes:    uint64(e.stackBytes.quantize(2048).min(0)()),
+       }
+}
+
+func (e *gcExecTest) check(t *testing.T, results []gcCycleResult) {
+       t.Helper()
+
+       // Do some basic general checks first.
+       n := len(results)
+       switch n {
+       case 0:
+               t.Fatal("no results passed to check")
+               return
+       case 1:
+               if results[0].cycle != 1 {
+                       t.Error("first cycle has incorrect number")
+               }
+       default:
+               if results[n-1].cycle != results[n-2].cycle+1 {
+                       t.Error("cycle numbers out of order")
+               }
+       }
+       if u := results[n-1].gcUtilization; u < 0 || u > 1 {
+               t.Fatal("GC utilization not within acceptable bounds")
+       }
+       if s := results[n-1].heapScannable; s < 0 {
+               t.Fatal("heapScannable is negative")
+       }
+       if e.checker == nil {
+               t.Fatal("test-specific checker is missing")
+       }
+
+       // Run the test-specific checker.
+       e.checker(t, results)
+}
+
+type gcCycle struct {
+       allocRate     float64
+       scanRate      float64
+       growthRate    float64
+       scannableFrac float64
+       stackBytes    uint64
+}
+
+type gcCycleResult struct {
+       cycle int
+
+       // These come directly from the pacer, so uint64.
+       heapLive    uint64
+       heapTrigger uint64
+       heapGoal    uint64
+       heapPeak    uint64
+
+       // These are produced by the simulation, so int64 and
+       // float64 are more appropriate, so that we can check for
+       // bad states in the simulation.
+       heapScannable int64
+       gcUtilization float64
+}
+
+func (r *gcCycleResult) goalRatio() float64 {
+       return float64(r.heapPeak) / float64(r.heapGoal)
+}
+
+func (r *gcCycleResult) String() string {
+       return fmt.Sprintf("%d %2.1f%% %d->%d->%d (goal: %d)", r.cycle, r.gcUtilization*100, r.heapLive, r.heapTrigger, r.heapPeak, r.heapGoal)
+}
+
+func assertInEpsilon(t *testing.T, name string, a, b, epsilon float64) {
+       t.Helper()
+       assertInRange(t, name, a, b-epsilon, b+epsilon)
+}
+
+func assertInRange(t *testing.T, name string, a, min, max float64) {
+       t.Helper()
+       if a < min || a > max {
+               t.Errorf("%s not in range (%f, %f): %f", name, min, max, a)
+       }
+}
+
+// float64Stream is a function that generates an infinite stream of
+// float64 values when called repeatedly.
+type float64Stream func() float64
+
+// constant returns a stream that generates the value c.
+func constant(c float64) float64Stream {
+       return func() float64 {
+               return c
+       }
+}
+
+// unit returns a stream that generates a single peak with
+// amplitude amp, followed by zeroes.
+//
+// In another manner of speaking, this is the Kronecker delta.
+func unit(amp float64) float64Stream {
+       dropped := false
+       return func() float64 {
+               if dropped {
+                       return 0
+               }
+               dropped = true
+               return amp
+       }
+}
+
+// oscillate returns a stream that oscillates sinusoidally
+// with the given amplitude, phase, and period.
+func oscillate(amp, phase float64, period int) float64Stream {
+       var cycle int
+       return func() float64 {
+               p := float64(cycle)/float64(period)*2*math.Pi + phase
+               cycle++
+               if cycle == period {
+                       cycle = 0
+               }
+               return math.Sin(p) * amp
+       }
+}
+
+// ramp returns a stream that moves from zero to height
+// over the course of length steps.
+func ramp(height float64, length int) float64Stream {
+       var cycle int
+       return func() float64 {
+               h := height * float64(cycle) / float64(length)
+               if cycle < length {
+                       cycle++
+               }
+               return h
+       }
+}
+
+// random returns a stream that generates random numbers
+// between -amp and amp.
+func random(amp float64, seed int64) float64Stream {
+       r := rand.New(rand.NewSource(seed))
+       return func() float64 {
+               return ((r.Float64() - 0.5) * 2) * amp
+       }
+}
+
+// delay returns a new stream which is a buffered version
+// of f: it returns zero for cycles steps, followed by f.
+func (f float64Stream) delay(cycles int) float64Stream {
+       zeroes := 0
+       return func() float64 {
+               if zeroes < cycles {
+                       zeroes++
+                       return 0
+               }
+               return f()
+       }
+}
+
+// scale returns a new stream that is f, but attenuated by a
+// constant factor.
+func (f float64Stream) scale(amt float64) float64Stream {
+       return func() float64 {
+               return f() * amt
+       }
+}
+
+// offset returns a new stream that is f but offset by amt
+// at each step.
+func (f float64Stream) offset(amt float64) float64Stream {
+       return func() float64 {
+               old := f()
+               return old + amt
+       }
+}
+
+// sum returns a new stream that is the sum of all input streams
+// at each step.
+func (f float64Stream) sum(fs ...float64Stream) float64Stream {
+       return func() float64 {
+               sum := f()
+               for _, s := range fs {
+                       sum += s()
+               }
+               return sum
+       }
+}
+
+// quantize returns a new stream that rounds f to a multiple
+// of mult at each step.
+func (f float64Stream) quantize(mult float64) float64Stream {
+       return func() float64 {
+               r := f() / mult
+               if r < 0 {
+                       return math.Ceil(r) * mult
+               }
+               return math.Floor(r) * mult
+       }
+}
+
+// min returns a new stream that replaces all values produced
+// by f lower than min with min.
+func (f float64Stream) min(min float64) float64Stream {
+       return func() float64 {
+               return math.Max(min, f())
+       }
+}
+
+// max returns a new stream that replaces all values produced
+// by f higher than max with max.
+func (f float64Stream) max(max float64) float64Stream {
+       return func() float64 {
+               return math.Min(max, f())
+       }
+}
+
+// limit returns a new stream that replaces all values produced
+// by f lower than min with min and higher than max with max.
+func (f float64Stream) limit(min, max float64) float64Stream {
+       return func() float64 {
+               v := f()
+               if v < min {
+                       v = min
+               } else if v > max {
+                       v = max
+               }
+               return v
+       }
+}
index 2bb19985db0353aa181f9c40a0e08c6c831fcdeb..4edeb8739e7e3d9009cbc026f527e21a9406b9f2 100644 (file)
@@ -105,7 +105,8 @@ func heapRetained() uint64 {
 }
 
 // gcPaceScavenger updates the scavenger's pacing, particularly
-// its rate and RSS goal.
+// its rate and RSS goal. For this, it requires the current heapGoal,
+// and the heapGoal for the previous GC cycle.
 //
 // The RSS goal is based on the current heap goal with a small overhead
 // to accommodate non-determinism in the allocator.
@@ -113,18 +114,22 @@ func heapRetained() uint64 {
 // The pacing is based on scavengePageRate, which applies to both regular and
 // huge pages. See that constant for more information.
 //
+// Must be called whenever GC pacing is updated.
+//
 // mheap_.lock must be held or the world must be stopped.
-func gcPaceScavenger() {
+func gcPaceScavenger(heapGoal, lastHeapGoal uint64) {
+       assertWorldStoppedOrLockHeld(&mheap_.lock)
+
        // If we're called before the first GC completed, disable scavenging.
        // We never scavenge before the 2nd GC cycle anyway (we don't have enough
        // information about the heap yet) so this is fine, and avoids a fault
        // or garbage data later.
-       if gcController.lastHeapGoal == 0 {
-               mheap_.scavengeGoal = ^uint64(0)
+       if lastHeapGoal == 0 {
+               atomic.Store64(&mheap_.scavengeGoal, ^uint64(0))
                return
        }
        // Compute our scavenging goal.
-       goalRatio := float64(atomic.Load64(&gcController.heapGoal)) / float64(gcController.lastHeapGoal)
+       goalRatio := float64(heapGoal) / float64(lastHeapGoal)
        retainedGoal := uint64(float64(memstats.last_heap_inuse) * goalRatio)
        // Add retainExtraPercent overhead to retainedGoal. This calculation
        // looks strange but the purpose is to arrive at an integer division
@@ -152,10 +157,10 @@ func gcPaceScavenger() {
        // the background scavenger. We disable the background scavenger if there's
        // less than one physical page of work to do because it's not worth it.
        if retainedNow <= retainedGoal || retainedNow-retainedGoal < uint64(physPageSize) {
-               mheap_.scavengeGoal = ^uint64(0)
+               atomic.Store64(&mheap_.scavengeGoal, ^uint64(0))
                return
        }
-       mheap_.scavengeGoal = retainedGoal
+       atomic.Store64(&mheap_.scavengeGoal, retainedGoal)
 }
 
 // Sleep/wait state of the background scavenger.
@@ -294,7 +299,7 @@ func bgscavenge(c chan int) {
                        lock(&mheap_.lock)
 
                        // If background scavenging is disabled or if there's no work to do just park.
-                       retained, goal := heapRetained(), mheap_.scavengeGoal
+                       retained, goal := heapRetained(), atomic.Load64(&mheap_.scavengeGoal)
                        if retained <= goal {
                                unlock(&mheap_.lock)
                                return
index 1812644623b2f2eb2ffb09217491c969a117deaf..fdbec30cf121d88f792e49059e98cd4f61fd521d 100644 (file)
@@ -41,6 +41,10 @@ type sweepdata struct {
        nbgsweep    uint32
        npausesweep uint32
 
+       // active tracks outstanding sweepers and the sweep
+       // termination condition.
+       active activeSweep
+
        // centralIndex is the current unswept span class.
        // It represents an index into the mcentral span
        // sets. Accessed and updated via its load and
@@ -116,6 +120,108 @@ func (h *mheap) nextSpanForSweep() *mspan {
        return nil
 }
 
+const sweepDrainedMask = 1 << 31
+
+// activeSweep is a type that captures whether sweeping
+// is done, and whether there are any outstanding sweepers.
+//
+// Every potential sweeper must call begin() before they look
+// for work, and end() after they've finished sweeping.
+type activeSweep struct {
+       // state is divided into two parts.
+       //
+       // The top bit (masked by sweepDrainedMask) is a boolean
+       // value indicating whether all the sweep work has been
+       // drained from the queue.
+       //
+       // The rest of the bits are a counter, indicating the
+       // number of outstanding concurrent sweepers.
+       state atomic.Uint32
+}
+
+// begin registers a new sweeper. Returns a sweepLocker
+// for acquiring spans for sweeping. Any outstanding sweeper blocks
+// sweep termination.
+//
+// If the sweepLocker is invalid, the caller can be sure that all
+// outstanding sweep work has been drained, so there is nothing left
+// to sweep. Note that there may be sweepers currently running, so
+// this does not indicate that all sweeping has completed.
+//
+// Even if the sweepLocker is invalid, its sweepGen is always valid.
+func (a *activeSweep) begin() sweepLocker {
+       for {
+               state := a.state.Load()
+               if state&sweepDrainedMask != 0 {
+                       return sweepLocker{mheap_.sweepgen, false}
+               }
+               if a.state.CompareAndSwap(state, state+1) {
+                       return sweepLocker{mheap_.sweepgen, true}
+               }
+       }
+}
+
+// end deregisters a sweeper. Must be called once for each time
+// begin is called if the sweepLocker is valid.
+func (a *activeSweep) end(sl sweepLocker) {
+       if sl.sweepGen != mheap_.sweepgen {
+               throw("sweeper left outstanding across sweep generations")
+       }
+       for {
+               state := a.state.Load()
+               if (state&^sweepDrainedMask)-1 >= sweepDrainedMask {
+                       throw("mismatched begin/end of activeSweep")
+               }
+               if a.state.CompareAndSwap(state, state-1) {
+                       if state != sweepDrainedMask {
+                               return
+                       }
+                       if debug.gcpacertrace > 0 {
+                               print("pacer: sweep done at heap size ", gcController.heapLive>>20, "MB; allocated ", (gcController.heapLive-mheap_.sweepHeapLiveBasis)>>20, "MB during sweep; swept ", mheap_.pagesSwept.Load(), " pages at ", mheap_.sweepPagesPerByte, " pages/byte\n")
+                       }
+                       return
+               }
+       }
+}
+
+// markDrained marks the active sweep cycle as having drained
+// all remaining work. This is safe to be called concurrently
+// with all other methods of activeSweep, though may race.
+//
+// Returns true if this call was the one that actually performed
+// the mark.
+func (a *activeSweep) markDrained() bool {
+       for {
+               state := a.state.Load()
+               if state&sweepDrainedMask != 0 {
+                       return false
+               }
+               if a.state.CompareAndSwap(state, state|sweepDrainedMask) {
+                       return true
+               }
+       }
+}
+
+// sweepers returns the current number of active sweepers.
+func (a *activeSweep) sweepers() uint32 {
+       return a.state.Load() &^ sweepDrainedMask
+}
+
+// isDone returns true if all sweep work has been drained and no more
+// outstanding sweepers exist. That is, when the sweep phase is
+// completely done.
+func (a *activeSweep) isDone() bool {
+       return a.state.Load() == sweepDrainedMask
+}
+
+// reset sets up the activeSweep for the next sweep cycle.
+//
+// The world must be stopped.
+func (a *activeSweep) reset() {
+       assertWorldStopped()
+       a.state.Store(0)
+}
+
 // finishsweep_m ensures that all spans are swept.
 //
 // The world must be stopped. This ensures there are no sweeps in
@@ -134,6 +240,15 @@ func finishsweep_m() {
                sweep.npausesweep++
        }
 
+       // Make sure there aren't any outstanding sweepers left.
+       // At this point, with the world stopped, it means one of two
+       // things. Either we were able to preempt a sweeper, or that
+       // a sweeper didn't call sweep.active.end when it should have.
+       // Both cases indicate a bug, so throw.
+       if sweep.active.sweepers() != 0 {
+               throw("active sweepers found at start of mark phase")
+       }
+
        // Reset all the unswept buffers, which should be empty.
        // Do this in sweep termination as opposed to mark termination
        // so that we can catch unswept spans and reclaim blocks as
@@ -183,15 +298,11 @@ func bgsweep(c chan int) {
        }
 }
 
-// sweepLocker acquires sweep ownership of spans and blocks sweep
-// completion.
+// sweepLocker acquires sweep ownership of spans.
 type sweepLocker struct {
        // sweepGen is the sweep generation of the heap.
        sweepGen uint32
-       // blocking indicates that this tracker is blocking sweep
-       // completion, usually as a result of acquiring sweep
-       // ownership of at least one span.
-       blocking bool
+       valid    bool
 }
 
 // sweepLocked represents sweep ownership of a span.
@@ -199,22 +310,16 @@ type sweepLocked struct {
        *mspan
 }
 
-func newSweepLocker() sweepLocker {
-       return sweepLocker{
-               sweepGen: mheap_.sweepgen,
-       }
-}
-
 // tryAcquire attempts to acquire sweep ownership of span s. If it
 // successfully acquires ownership, it blocks sweep completion.
 func (l *sweepLocker) tryAcquire(s *mspan) (sweepLocked, bool) {
+       if !l.valid {
+               throw("use of invalid sweepLocker")
+       }
        // Check before attempting to CAS.
        if atomic.Load(&s.sweepgen) != l.sweepGen-2 {
                return sweepLocked{}, false
        }
-       // Add ourselves to sweepers before potentially taking
-       // ownership.
-       l.blockCompletion()
        // Attempt to acquire sweep ownership of s.
        if !atomic.Cas(&s.sweepgen, l.sweepGen-2, l.sweepGen-1) {
                return sweepLocked{}, false
@@ -222,48 +327,22 @@ func (l *sweepLocker) tryAcquire(s *mspan) (sweepLocked, bool) {
        return sweepLocked{s}, true
 }
 
-// blockCompletion blocks sweep completion without acquiring any
-// specific spans.
-func (l *sweepLocker) blockCompletion() {
-       if !l.blocking {
-               atomic.Xadd(&mheap_.sweepers, +1)
-               l.blocking = true
-       }
-}
-
-func (l *sweepLocker) dispose() {
-       if !l.blocking {
-               return
-       }
-       // Decrement the number of active sweepers and if this is the
-       // last one, mark sweep as complete.
-       l.blocking = false
-       if atomic.Xadd(&mheap_.sweepers, -1) == 0 && atomic.Load(&mheap_.sweepDrained) != 0 {
-               l.sweepIsDone()
-       }
-}
-
-func (l *sweepLocker) sweepIsDone() {
-       if debug.gcpacertrace > 0 {
-               print("pacer: sweep done at heap size ", gcController.heapLive>>20, "MB; allocated ", (gcController.heapLive-mheap_.sweepHeapLiveBasis)>>20, "MB during sweep; swept ", mheap_.pagesSwept, " pages at ", mheap_.sweepPagesPerByte, " pages/byte\n")
-       }
-}
-
 // sweepone sweeps some unswept heap span and returns the number of pages returned
 // to the heap, or ^uintptr(0) if there was nothing to sweep.
 func sweepone() uintptr {
-       _g_ := getg()
+       gp := getg()
 
-       // increment locks to ensure that the goroutine is not preempted
+       // Increment locks to ensure that the goroutine is not preempted
        // in the middle of sweep thus leaving the span in an inconsistent state for next GC
-       _g_.m.locks++
-       if atomic.Load(&mheap_.sweepDrained) != 0 {
-               _g_.m.locks--
-               return ^uintptr(0)
-       }
+       gp.m.locks++
+
        // TODO(austin): sweepone is almost always called in a loop;
        // lift the sweepLocker into its callers.
-       sl := newSweepLocker()
+       sl := sweep.active.begin()
+       if !sl.valid {
+               gp.m.locks--
+               return ^uintptr(0)
+       }
 
        // Find a span to sweep.
        npages := ^uintptr(0)
@@ -271,7 +350,7 @@ func sweepone() uintptr {
        for {
                s := mheap_.nextSpanForSweep()
                if s == nil {
-                       noMoreWork = atomic.Cas(&mheap_.sweepDrained, 0, 1)
+                       noMoreWork = sweep.active.markDrained()
                        break
                }
                if state := s.state.get(); state != mSpanInUse {
@@ -291,7 +370,7 @@ func sweepone() uintptr {
                                // Whole span was freed. Count it toward the
                                // page reclaimer credit since these pages can
                                // now be used for span allocation.
-                               atomic.Xadduintptr(&mheap_.reclaimCredit, npages)
+                               mheap_.reclaimCredit.Add(npages)
                        } else {
                                // Span is still in-use, so this returned no
                                // pages to the heap and the span needs to
@@ -301,8 +380,7 @@ func sweepone() uintptr {
                        break
                }
        }
-
-       sl.dispose()
+       sweep.active.end(sl)
 
        if noMoreWork {
                // The sweep list is empty. There may still be
@@ -331,7 +409,7 @@ func sweepone() uintptr {
                readyForScavenger()
        }
 
-       _g_.m.locks--
+       gp.m.locks--
        return npages
 }
 
@@ -342,10 +420,7 @@ func sweepone() uintptr {
 // GC runs; to prevent that the caller must be non-preemptible or must
 // somehow block GC progress.
 func isSweepDone() bool {
-       // Check that all spans have at least begun sweeping and there
-       // are no active sweepers. If both are true, then all spans
-       // have finished sweeping.
-       return atomic.Load(&mheap_.sweepDrained) != 0 && atomic.Load(&mheap_.sweepers) == 0
+       return sweep.active.isDone()
 }
 
 // Returns only when span s has been swept.
@@ -359,16 +434,23 @@ func (s *mspan) ensureSwept() {
                throw("mspan.ensureSwept: m is not locked")
        }
 
-       sl := newSweepLocker()
-       // The caller must be sure that the span is a mSpanInUse span.
-       if s, ok := sl.tryAcquire(s); ok {
-               s.sweep(false)
-               sl.dispose()
-               return
+       // If this operation fails, then that means that there are
+       // no more spans to be swept. In this case, either s has already
+       // been swept, or is about to be acquired for sweeping and swept.
+       sl := sweep.active.begin()
+       if sl.valid {
+               // The caller must be sure that the span is a mSpanInUse span.
+               if s, ok := sl.tryAcquire(s); ok {
+                       s.sweep(false)
+                       sweep.active.end(sl)
+                       return
+               }
+               sweep.active.end(sl)
        }
-       sl.dispose()
 
-       // unfortunate condition, and we don't have efficient means to wait
+       // Unfortunately we can't sweep the span ourselves. Somebody else
+       // got to it first. We don't have efficient means to wait, but that's
+       // OK, it will be swept fairly soon.
        for {
                spangen := atomic.Load(&s.sweepgen)
                if spangen == sl.sweepGen || spangen == sl.sweepGen+3 {
@@ -408,7 +490,7 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
                traceGCSweepSpan(s.npages * _PageSize)
        }
 
-       atomic.Xadd64(&mheap_.pagesSwept, int64(s.npages))
+       mheap_.pagesSwept.Add(int64(s.npages))
 
        spc := s.spanclass
        size := s.elemsize
@@ -481,7 +563,7 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
                spanHasNoSpecials(s)
        }
 
-       if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled {
+       if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled || asanenabled {
                // Find all newly freed objects. This doesn't have to
                // efficient; allocfreetrace has massive overhead.
                mbits := s.markBitsForBase()
@@ -501,6 +583,9 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
                                if msanenabled {
                                        msanfree(unsafe.Pointer(x), size)
                                }
+                               if asanenabled {
+                                       asanpoison(unsafe.Pointer(x), size)
+                               }
                        }
                        mbits.advance()
                        abits.advance()
@@ -719,17 +804,17 @@ func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) {
        }
 
 retry:
-       sweptBasis := atomic.Load64(&mheap_.pagesSweptBasis)
+       sweptBasis := mheap_.pagesSweptBasis.Load()
 
        // Fix debt if necessary.
        newHeapLive := uintptr(atomic.Load64(&gcController.heapLive)-mheap_.sweepHeapLiveBasis) + spanBytes
        pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages)
-       for pagesTarget > int64(atomic.Load64(&mheap_.pagesSwept)-sweptBasis) {
+       for pagesTarget > int64(mheap_.pagesSwept.Load()-sweptBasis) {
                if sweepone() == ^uintptr(0) {
                        mheap_.sweepPagesPerByte = 0
                        break
                }
-               if atomic.Load64(&mheap_.pagesSweptBasis) != sweptBasis {
+               if mheap_.pagesSweptBasis.Load() != sweptBasis {
                        // Sweep pacing changed. Recompute debt.
                        goto retry
                }
@@ -748,3 +833,46 @@ func clobberfree(x unsafe.Pointer, size uintptr) {
                *(*uint32)(add(x, i)) = 0xdeadbeef
        }
 }
+
+// gcPaceSweeper updates the sweeper's pacing parameters.
+//
+// Must be called whenever the GC's pacing is updated.
+//
+// The world must be stopped, or mheap_.lock must be held.
+func gcPaceSweeper(trigger uint64) {
+       assertWorldStoppedOrLockHeld(&mheap_.lock)
+
+       // Update sweep pacing.
+       if isSweepDone() {
+               mheap_.sweepPagesPerByte = 0
+       } else {
+               // Concurrent sweep needs to sweep all of the in-use
+               // pages by the time the allocated heap reaches the GC
+               // trigger. Compute the ratio of in-use pages to sweep
+               // per byte allocated, accounting for the fact that
+               // some might already be swept.
+               heapLiveBasis := atomic.Load64(&gcController.heapLive)
+               heapDistance := int64(trigger) - int64(heapLiveBasis)
+               // Add a little margin so rounding errors and
+               // concurrent sweep are less likely to leave pages
+               // unswept when GC starts.
+               heapDistance -= 1024 * 1024
+               if heapDistance < _PageSize {
+                       // Avoid setting the sweep ratio extremely high
+                       heapDistance = _PageSize
+               }
+               pagesSwept := mheap_.pagesSwept.Load()
+               pagesInUse := mheap_.pagesInUse.Load()
+               sweepDistancePages := int64(pagesInUse) - int64(pagesSwept)
+               if sweepDistancePages <= 0 {
+                       mheap_.sweepPagesPerByte = 0
+               } else {
+                       mheap_.sweepPagesPerByte = float64(sweepDistancePages) / float64(heapDistance)
+                       mheap_.sweepHeapLiveBasis = heapLiveBasis
+                       // Write pagesSweptBasis last, since this
+                       // signals concurrent sweeps to recompute
+                       // their debt.
+                       mheap_.pagesSweptBasis.Store(pagesSwept)
+               }
+       }
+}
index 8787d93d873508b36ebd597b417b1e08dec91b67..9c3f7fd223a943716dbab8549f1d638696fe6d74 100644 (file)
@@ -77,9 +77,10 @@ type gcWork struct {
        // into work.bytesMarked by dispose.
        bytesMarked uint64
 
-       // Scan work performed on this gcWork. This is aggregated into
+       // Heap scan work performed on this gcWork. This is aggregated into
        // gcController by dispose and may also be flushed by callers.
-       scanWork int64
+       // Other types of scan work are flushed immediately.
+       heapScanWork int64
 
        // flushedWork indicates that a non-empty work buffer was
        // flushed to the global work list since the last gcMarkDone
@@ -274,9 +275,9 @@ func (w *gcWork) dispose() {
                atomic.Xadd64(&work.bytesMarked, int64(w.bytesMarked))
                w.bytesMarked = 0
        }
-       if w.scanWork != 0 {
-               atomic.Xaddint64(&gcController.scanWork, w.scanWork)
-               w.scanWork = 0
+       if w.heapScanWork != 0 {
+               gcController.heapScanWork.Add(w.heapScanWork)
+               w.heapScanWork = 0
        }
 }
 
index b78f752ded6b618cd25417446d07e3f1bf16e69b..f2f6e7f4cf7f154d4f5dc561ce4defbd0f334a10 100644 (file)
@@ -65,9 +65,7 @@ type mheap struct {
        lock  mutex
        pages pageAlloc // page allocation data structure
 
-       sweepgen     uint32 // sweep generation, see comment in mspan; written during STW
-       sweepDrained uint32 // all spans are swept or are being swept
-       sweepers     uint32 // number of active sweepone calls
+       sweepgen uint32 // sweep generation, see comment in mspan; written during STW
 
        // allspans is a slice of all mspans ever created. Each mspan
        // appears exactly once.
@@ -96,23 +94,25 @@ type mheap struct {
        // any given time, the system is at (gcController.heapLive,
        // pagesSwept) in this space.
        //
-       // It's important that the line pass through a point we
-       // control rather than simply starting at a (0,0) origin
+       // It is important that the line pass through a point we
+       // control rather than simply starting at a 0,0 origin
        // because that lets us adjust sweep pacing at any time while
        // accounting for current progress. If we could only adjust
        // the slope, it would create a discontinuity in debt if any
        // progress has already been made.
-       pagesInUse         uint64  // pages of spans in stats mSpanInUse; updated atomically
-       pagesSwept         uint64  // pages swept this cycle; updated atomically
-       pagesSweptBasis    uint64  // pagesSwept to use as the origin of the sweep ratio; updated atomically
-       sweepHeapLiveBasis uint64  // value of gcController.heapLive to use as the origin of sweep ratio; written with lock, read without
-       sweepPagesPerByte  float64 // proportional sweep ratio; written with lock, read without
+       pagesInUse         atomic.Uint64 // pages of spans in stats mSpanInUse
+       pagesSwept         atomic.Uint64 // pages swept this cycle
+       pagesSweptBasis    atomic.Uint64 // pagesSwept to use as the origin of the sweep ratio
+       sweepHeapLiveBasis uint64        // value of gcController.heapLive to use as the origin of sweep ratio; written with lock, read without
+       sweepPagesPerByte  float64       // proportional sweep ratio; written with lock, read without
        // TODO(austin): pagesInUse should be a uintptr, but the 386
        // compiler can't 8-byte align fields.
 
        // scavengeGoal is the amount of total retained heap memory (measured by
        // heapRetained) that the runtime will try to maintain by returning memory
        // to the OS.
+       //
+       // Accessed atomically.
        scavengeGoal uint64
 
        // Page reclaimer state
@@ -123,16 +123,13 @@ type mheap struct {
        //
        // If this is >= 1<<63, the page reclaimer is done scanning
        // the page marks.
-       //
-       // This is accessed atomically.
-       reclaimIndex uint64
+       reclaimIndex atomic.Uint64
+
        // reclaimCredit is spare credit for extra pages swept. Since
        // the page reclaimer works in large chunks, it may reclaim
        // more than requested. Any spare pages released go to this
        // credit pool.
-       //
-       // This is accessed atomically.
-       reclaimCredit uintptr
+       reclaimCredit atomic.Uintptr
 
        // arenas is the heap arena map. It points to the metadata for
        // the heap for every arena frame of the entire usable virtual
@@ -739,7 +736,7 @@ func (h *mheap) reclaim(npage uintptr) {
        // batching heap frees.
 
        // Bail early if there's no more reclaim work.
-       if atomic.Load64(&h.reclaimIndex) >= 1<<63 {
+       if h.reclaimIndex.Load() >= 1<<63 {
                return
        }
 
@@ -756,23 +753,23 @@ func (h *mheap) reclaim(npage uintptr) {
        locked := false
        for npage > 0 {
                // Pull from accumulated credit first.
-               if credit := atomic.Loaduintptr(&h.reclaimCredit); credit > 0 {
+               if credit := h.reclaimCredit.Load(); credit > 0 {
                        take := credit
                        if take > npage {
                                // Take only what we need.
                                take = npage
                        }
-                       if atomic.Casuintptr(&h.reclaimCredit, credit, credit-take) {
+                       if h.reclaimCredit.CompareAndSwap(credit, credit-take) {
                                npage -= take
                        }
                        continue
                }
 
                // Claim a chunk of work.
-               idx := uintptr(atomic.Xadd64(&h.reclaimIndex, pagesPerReclaimerChunk) - pagesPerReclaimerChunk)
+               idx := uintptr(h.reclaimIndex.Add(pagesPerReclaimerChunk) - pagesPerReclaimerChunk)
                if idx/pagesPerArena >= uintptr(len(arenas)) {
                        // Page reclaiming is done.
-                       atomic.Store64(&h.reclaimIndex, 1<<63)
+                       h.reclaimIndex.Store(1 << 63)
                        break
                }
 
@@ -788,7 +785,7 @@ func (h *mheap) reclaim(npage uintptr) {
                        npage -= nfound
                } else {
                        // Put spare pages toward global credit.
-                       atomic.Xadduintptr(&h.reclaimCredit, nfound-npage)
+                       h.reclaimCredit.Add(nfound - npage)
                        npage = 0
                }
        }
@@ -818,7 +815,10 @@ func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr {
 
        n0 := n
        var nFreed uintptr
-       sl := newSweepLocker()
+       sl := sweep.active.begin()
+       if !sl.valid {
+               return 0
+       }
        for n > 0 {
                ai := arenas[pageIdx/pagesPerArena]
                ha := h.arenas[ai.l1()][ai.l2()]
@@ -864,7 +864,7 @@ func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr {
                pageIdx += uintptr(len(inUse) * 8)
                n -= uintptr(len(inUse) * 8)
        }
-       sl.dispose()
+       sweep.active.end(sl)
        if trace.enabled {
                unlock(&h.lock)
                // Account for pages scanned but not reclaimed.
@@ -896,10 +896,9 @@ func (s spanAllocType) manual() bool {
 //
 // spanclass indicates the span's size class and scannability.
 //
-// If needzero is true, the memory for the returned span will be zeroed.
-// The boolean returned indicates whether the returned span contains zeroes,
-// either because this was requested, or because it was already zeroed.
-func (h *mheap) alloc(npages uintptr, spanclass spanClass, needzero bool) (*mspan, bool) {
+// Returns a span that has been fully initialized. span.needzero indicates
+// whether the span has been zeroed. Note that it may not be.
+func (h *mheap) alloc(npages uintptr, spanclass spanClass) *mspan {
        // Don't do any operations that lock the heap on the G stack.
        // It might trigger stack growth, and the stack growth code needs
        // to be able to allocate heap.
@@ -912,17 +911,7 @@ func (h *mheap) alloc(npages uintptr, spanclass spanClass, needzero bool) (*mspa
                }
                s = h.allocSpan(npages, spanAllocHeap, spanclass)
        })
-
-       if s == nil {
-               return nil, false
-       }
-       isZeroed := s.needzero == 0
-       if needzero && !isZeroed {
-               memclrNoHeapPointers(unsafe.Pointer(s.base()), s.npages<<_PageShift)
-               isZeroed = true
-       }
-       s.needzero = 0
-       return s, isZeroed
+       return s
 }
 
 // allocManual allocates a manually-managed span of npage pages.
@@ -1011,7 +1000,7 @@ func (h *mheap) allocNeedsZero(base, npage uintptr) (needZero bool) {
                                break
                        }
                        zeroedBase = atomic.Loaduintptr(&ha.zeroedBase)
-                       // Sanity check zeroedBase.
+                       // Double check basic conditions of zeroedBase.
                        if zeroedBase <= arenaLimit && zeroedBase > arenaBase {
                                // The zeroedBase moved into the space we were trying to
                                // claim. That's very bad, and indicates someone allocated
@@ -1311,7 +1300,7 @@ HaveSpan:
                atomic.Or8(&arena.pageInUse[pageIdx], pageMask)
 
                // Update related page sweeper stats.
-               atomic.Xadd64(&h.pagesInUse, int64(npages))
+               h.pagesInUse.Add(int64(npages))
        }
 
        // Make sure the newly allocated span will be observed
@@ -1412,9 +1401,10 @@ func (h *mheap) grow(npage uintptr) bool {
        // By scavenging inline we deal with the failure to allocate out of
        // memory fragments by scavenging the memory fragments that are least
        // likely to be re-used.
-       if retained := heapRetained(); retained+uint64(totalGrowth) > h.scavengeGoal {
+       scavengeGoal := atomic.Load64(&h.scavengeGoal)
+       if retained := heapRetained(); retained+uint64(totalGrowth) > scavengeGoal {
                todo := totalGrowth
-               if overage := uintptr(retained + uint64(totalGrowth) - h.scavengeGoal); todo > overage {
+               if overage := uintptr(retained + uint64(totalGrowth) - scavengeGoal); todo > overage {
                        todo = overage
                }
                h.pages.scavenge(todo, false)
@@ -1432,6 +1422,12 @@ func (h *mheap) freeSpan(s *mspan) {
                        bytes := s.npages << _PageShift
                        msanfree(base, bytes)
                }
+               if asanenabled {
+                       // Tell asan that this entire span is no longer in use.
+                       base := unsafe.Pointer(s.base())
+                       bytes := s.npages << _PageShift
+                       asanpoison(base, bytes)
+               }
                h.freeSpanLocked(s, spanAllocHeap)
                unlock(&h.lock)
        })
@@ -1468,7 +1464,7 @@ func (h *mheap) freeSpanLocked(s *mspan, typ spanAllocType) {
                        print("mheap.freeSpanLocked - span ", s, " ptr ", hex(s.base()), " allocCount ", s.allocCount, " sweepgen ", s.sweepgen, "/", h.sweepgen, "\n")
                        throw("mheap.freeSpanLocked - invalid free")
                }
-               atomic.Xadd64(&h.pagesInUse, -int64(s.npages))
+               h.pagesInUse.Add(-int64(s.npages))
 
                // Clear in-use bit in arena page bitmap.
                arena, pageIdx, pageMask := pageIndexOf(s.base())
index f03674509238b0505ef4f7ee9ad93e7085821597..e8a85702c6088bdd1fc0ff746189f10e2e984fe8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // runtime·duffzero is a Duff's device for zeroing memory.
 // The compiler jumps to computed addresses within
@@ -180,7 +179,6 @@ func copyARM64(w io.Writer) {
 func tagsPPC64x(w io.Writer) {
        fmt.Fprintln(w)
        fmt.Fprintln(w, "//go:build ppc64 || ppc64le")
-       fmt.Fprintln(w, "// +build ppc64 ppc64le")
        fmt.Fprintln(w)
 }
 
@@ -188,23 +186,26 @@ func zeroPPC64x(w io.Writer) {
        // R0: always zero
        // R3 (aka REGRT1): ptr to memory to be zeroed - 8
        // On return, R3 points to the last zeroed dword.
-       fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT|NOFRAME, $0-0")
+       fmt.Fprintln(w, "TEXT runtime·duffzero<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-0")
        for i := 0; i < 128; i++ {
-               fmt.Fprintln(w, "\tMOVDU\tR0, 8(R3)")
+               fmt.Fprintln(w, "\tMOVDU\tR0, 8(R20)")
        }
        fmt.Fprintln(w, "\tRET")
 }
 
 func copyPPC64x(w io.Writer) {
        // duffcopy is not used on PPC64.
-       fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT|NOFRAME, $0-0")
-       fmt.Fprintln(w, "\tUNDEF")
+       fmt.Fprintln(w, "TEXT runtime·duffcopy<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-0")
+       for i := 0; i < 128; i++ {
+               fmt.Fprintln(w, "\tMOVDU\t8(R20), R5")
+               fmt.Fprintln(w, "\tMOVDU\tR5, 8(R21)")
+       }
+       fmt.Fprintln(w, "\tRET")
 }
 
 func tagsMIPS64x(w io.Writer) {
        fmt.Fprintln(w)
        fmt.Fprintln(w, "//go:build mips64 || mips64le")
-       fmt.Fprintln(w, "// +build mips64 mips64le")
        fmt.Fprintln(w)
 }
 
index 8d78a3923a094be383eaebbbce64d519c579c45a..a55f54751c91bc4ada7a7c434f4d506d5fc389d2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // fastlog2Table contains log2 approximations for 5 binary digits.
 // This is used to implement fastlog2, which is used for heap sampling.
index f2b90307cab1ea05755c7f657796ee7e33a93d40..e8c23d485abe8fc0f1bc94336d164e1e11305a3f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // mkpreempt generates the asyncPreempt functions for each
 // architecture.
@@ -124,7 +123,6 @@ func header(arch string) {
        if beLe[arch] {
                base := arch[:len(arch)-1]
                fmt.Fprintf(out, "//go:build %s || %sle\n", base, base)
-               fmt.Fprintf(out, "// +build %s %sle\n\n", base, base)
        }
        fmt.Fprintf(out, "#include \"go_asm.h\"\n")
        fmt.Fprintf(out, "#include \"textflag.h\"\n\n")
@@ -200,6 +198,8 @@ func gen386() {
                l.add("MOVL", reg, 4)
        }
 
+       softfloat := "GO386_softfloat"
+
        // Save SSE state only if supported.
        lSSE := layout{stack: l.stack, sp: "SP"}
        for i := 0; i < 8; i++ {
@@ -209,13 +209,13 @@ func gen386() {
        p("ADJSP $%d", lSSE.stack)
        p("NOP SP")
        l.save()
-       p("CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1\nJNE nosse")
+       p("#ifndef %s", softfloat)
        lSSE.save()
-       label("nosse:")
+       p("#endif")
        p("CALL ·asyncPreempt2(SB)")
-       p("CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1\nJNE nosse2")
+       p("#ifndef %s", softfloat)
        lSSE.restore()
-       label("nosse2:")
+       p("#endif")
        l.restore()
        p("ADJSP $%d", -lSSE.stack)
 
@@ -504,12 +504,12 @@ func genPPC64() {
 }
 
 func genRISCV64() {
-       // X0 (zero), X1 (LR), X2 (SP), X4 (TP), X27 (g), X31 (TMP) are special.
+       // X0 (zero), X1 (LR), X2 (SP), X3 (GP), X4 (TP), X27 (g), X31 (TMP) are special.
        var l = layout{sp: "X2", stack: 8}
 
-       // Add integer registers (X3, X5-X26, X28-30).
-       for i := 3; i < 31; i++ {
-               if i == 4 || i == 27 {
+       // Add integer registers (X5-X26, X28-30).
+       for i := 5; i < 31; i++ {
+               if i == 27 {
                        continue
                }
                reg := fmt.Sprintf("X%d", i)
index b1b10e9e0230a9976968a4b7cf84a9ee2d746eda..64ed84432923081e04e2be0ee429cb612b80154c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Generate tables for small malloc size classes.
 //
index 7460eb31046fa895127156e2f68c11e593a5ef7a..3280a62e8dd9e43806c12dfeefc22af261205493 100644 (file)
@@ -3,15 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !js && (!linux || !amd64) && (!linux || !arm64) && !openbsd && !plan9 && !solaris && !windows
-// +build !aix
-// +build !darwin
-// +build !js
-// +build !linux !amd64
-// +build !linux !arm64
-// +build !openbsd
-// +build !plan9
-// +build !solaris
-// +build !windows
 
 package runtime
 
index 071f1fc27499cf9f9c043c80c2049f10b1e0c568..862882cd82472388ec93aa6662c2c4d9b1662e33 100644 (file)
@@ -155,7 +155,7 @@ func addrsToSummaryRange(level int, base, limit uintptr) (lo int, hi int) {
        // upper-bound. Note that the exclusive upper bound may be within a
        // summary at this level, meaning if we just do the obvious computation
        // hi will end up being an inclusive upper bound. Unfortunately, just
-       // adding 1 to that is too broad since we might be on the very edge of
+       // adding 1 to that is too broad since we might be on the very edge
        // 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.
index fceb4e7a187b7a6d3a0ff060da84ea92a02e8277..1d863f2fdaa7c8117319257fcc1aef9912d574d6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || arm || mips || mipsle || wasm || (ios && arm64)
-// +build 386 arm mips mipsle wasm ios,arm64
 
 // wasm is a treated as a 32-bit architecture for the purposes of the page
 // allocator, even though it has 64-bit pointers. This is because any wasm
index 16577346a7fbe2c30742875f56b4c6b6d4cac0af..782628c91d05b211cd54be48bb6cc7a8bb780c71 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || (!ios && arm64) || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x
-// +build amd64 !ios,arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x
 
 // See mpagealloc_32bit.go for why ios/arm64 is excluded here.
 
index 4b5c66d8d6e14f1fd158e17b27acee91e553217a..7206e2dbdb763a0df7278660d2ef3ec6dcae6273 100644 (file)
@@ -123,9 +123,10 @@ func (p *pageAlloc) allocToCache() pageCache {
        }
        c := pageCache{}
        ci := chunkIndex(p.searchAddr.addr()) // chunk index
+       var chunk *pallocData
        if p.summary[len(p.summary)-1][ci] != 0 {
                // Fast path: there's free pages at or near the searchAddr address.
-               chunk := p.chunkOf(ci)
+               chunk = p.chunkOf(ci)
                j, _ := chunk.find(1, chunkPageIndex(p.searchAddr.addr()))
                if j == ^uint(0) {
                        throw("bad summary data")
@@ -146,7 +147,7 @@ func (p *pageAlloc) allocToCache() pageCache {
                        return pageCache{}
                }
                ci := chunkIndex(addr)
-               chunk := p.chunkOf(ci)
+               chunk = p.chunkOf(ci)
                c = pageCache{
                        base:  alignDown(addr, 64*pageSize),
                        cache: ^chunk.pages64(chunkPageIndex(addr)),
@@ -154,8 +155,11 @@ func (p *pageAlloc) allocToCache() pageCache {
                }
        }
 
-       // Set the bits as allocated and clear the scavenged bits.
-       p.allocRange(c.base, pageCachePages)
+       // Set the page bits as allocated and clear the scavenged bits, but
+       // be careful to only set and clear the relevant bits.
+       cpi := chunkPageIndex(c.base)
+       chunk.allocPages64(cpi, c.cache)
+       chunk.scavenged.clearBlock64(cpi, c.cache&c.scav /* free and scavenged */)
 
        // Update as an allocation, but note that it's not contiguous.
        p.update(c.base, pageCachePages, false, true)
index 2ed0c0aa6a0ba82da5c78a1601514120840b5b0b..69084f9a84f71854b53a2383cfca69dc087bbe82 100644 (file)
@@ -261,17 +261,18 @@ func TestPageAllocAllocToCache(t *testing.T) {
                t.Skip("skipping because virtual memory is limited; see #36210")
        }
        type test struct {
-               before map[ChunkIdx][]BitRange
-               scav   map[ChunkIdx][]BitRange
-               hits   []PageCache // expected base addresses and patterns
-               after  map[ChunkIdx][]BitRange
+               beforeAlloc map[ChunkIdx][]BitRange
+               beforeScav  map[ChunkIdx][]BitRange
+               hits        []PageCache // expected base addresses and patterns
+               afterAlloc  map[ChunkIdx][]BitRange
+               afterScav   map[ChunkIdx][]BitRange
        }
        tests := map[string]test{
                "AllFree": {
-                       before: map[ChunkIdx][]BitRange{
+                       beforeAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {},
                        },
-                       scav: map[ChunkIdx][]BitRange{
+                       beforeScav: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{1, 1}, {64, 64}},
                        },
                        hits: []PageCache{
@@ -280,17 +281,17 @@ func TestPageAllocAllocToCache(t *testing.T) {
                                NewPageCache(PageBase(BaseChunkIdx, 128), ^uint64(0), 0),
                                NewPageCache(PageBase(BaseChunkIdx, 192), ^uint64(0), 0),
                        },
-                       after: map[ChunkIdx][]BitRange{
+                       afterAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{0, 256}},
                        },
                },
                "ManyArena": {
-                       before: map[ChunkIdx][]BitRange{
+                       beforeAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:     {{0, PallocChunkPages}},
                                BaseChunkIdx + 1: {{0, PallocChunkPages}},
                                BaseChunkIdx + 2: {{0, PallocChunkPages - 64}},
                        },
-                       scav: map[ChunkIdx][]BitRange{
+                       beforeScav: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:     {{0, PallocChunkPages}},
                                BaseChunkIdx + 1: {{0, PallocChunkPages}},
                                BaseChunkIdx + 2: {},
@@ -298,46 +299,50 @@ func TestPageAllocAllocToCache(t *testing.T) {
                        hits: []PageCache{
                                NewPageCache(PageBase(BaseChunkIdx+2, PallocChunkPages-64), ^uint64(0), 0),
                        },
-                       after: map[ChunkIdx][]BitRange{
+                       afterAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:     {{0, PallocChunkPages}},
                                BaseChunkIdx + 1: {{0, PallocChunkPages}},
                                BaseChunkIdx + 2: {{0, PallocChunkPages}},
                        },
                },
                "NotContiguous": {
-                       before: map[ChunkIdx][]BitRange{
+                       beforeAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:        {{0, PallocChunkPages}},
                                BaseChunkIdx + 0xff: {{0, 0}},
                        },
-                       scav: map[ChunkIdx][]BitRange{
+                       beforeScav: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:        {{0, PallocChunkPages}},
                                BaseChunkIdx + 0xff: {{31, 67}},
                        },
                        hits: []PageCache{
                                NewPageCache(PageBase(BaseChunkIdx+0xff, 0), ^uint64(0), ((uint64(1)<<33)-1)<<31),
                        },
-                       after: map[ChunkIdx][]BitRange{
+                       afterAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:        {{0, PallocChunkPages}},
                                BaseChunkIdx + 0xff: {{0, 64}},
                        },
+                       afterScav: map[ChunkIdx][]BitRange{
+                               BaseChunkIdx:        {{0, PallocChunkPages}},
+                               BaseChunkIdx + 0xff: {{64, 34}},
+                       },
                },
                "First": {
-                       before: map[ChunkIdx][]BitRange{
+                       beforeAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{0, 32}, {33, 31}, {96, 32}},
                        },
-                       scav: map[ChunkIdx][]BitRange{
+                       beforeScav: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{1, 4}, {31, 5}, {66, 2}},
                        },
                        hits: []PageCache{
                                NewPageCache(PageBase(BaseChunkIdx, 0), 1<<32, 1<<32),
                                NewPageCache(PageBase(BaseChunkIdx, 64), (uint64(1)<<32)-1, 0x3<<2),
                        },
-                       after: map[ChunkIdx][]BitRange{
+                       afterAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{0, 128}},
                        },
                },
                "Fail": {
-                       before: map[ChunkIdx][]BitRange{
+                       beforeAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{0, PallocChunkPages}},
                        },
                        hits: []PageCache{
@@ -345,10 +350,27 @@ func TestPageAllocAllocToCache(t *testing.T) {
                                NewPageCache(0, 0, 0),
                                NewPageCache(0, 0, 0),
                        },
-                       after: map[ChunkIdx][]BitRange{
+                       afterAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx: {{0, PallocChunkPages}},
                        },
                },
+               "RetainScavBits": {
+                       beforeAlloc: map[ChunkIdx][]BitRange{
+                               BaseChunkIdx: {{0, 1}, {10, 2}},
+                       },
+                       beforeScav: map[ChunkIdx][]BitRange{
+                               BaseChunkIdx: {{0, 4}, {11, 1}},
+                       },
+                       hits: []PageCache{
+                               NewPageCache(PageBase(BaseChunkIdx, 0), ^uint64(0x1|(0x3<<10)), 0x7<<1),
+                       },
+                       afterAlloc: map[ChunkIdx][]BitRange{
+                               BaseChunkIdx: {{0, 64}},
+                       },
+                       afterScav: map[ChunkIdx][]BitRange{
+                               BaseChunkIdx: {{0, 1}, {11, 1}},
+                       },
+               },
        }
        if PageAlloc64Bit != 0 {
                const chunkIdxBigJump = 0x100000 // chunk index offset which translates to O(TiB)
@@ -359,11 +381,11 @@ func TestPageAllocAllocToCache(t *testing.T) {
                sumsPerPhysPage := ChunkIdx(PhysPageSize / PallocSumBytes)
                baseChunkIdx := BaseChunkIdx &^ (sumsPerPhysPage - 1)
                tests["DiscontiguousMappedSumBoundary"] = test{
-                       before: map[ChunkIdx][]BitRange{
+                       beforeAlloc: map[ChunkIdx][]BitRange{
                                baseChunkIdx + sumsPerPhysPage - 1: {{0, PallocChunkPages - 1}},
                                baseChunkIdx + chunkIdxBigJump:     {{1, PallocChunkPages - 1}},
                        },
-                       scav: map[ChunkIdx][]BitRange{
+                       beforeScav: map[ChunkIdx][]BitRange{
                                baseChunkIdx + sumsPerPhysPage - 1: {},
                                baseChunkIdx + chunkIdxBigJump:     {},
                        },
@@ -372,7 +394,7 @@ func TestPageAllocAllocToCache(t *testing.T) {
                                NewPageCache(PageBase(baseChunkIdx+chunkIdxBigJump, 0), 1, 0),
                                NewPageCache(0, 0, 0),
                        },
-                       after: map[ChunkIdx][]BitRange{
+                       afterAlloc: map[ChunkIdx][]BitRange{
                                baseChunkIdx + sumsPerPhysPage - 1: {{0, PallocChunkPages}},
                                baseChunkIdx + chunkIdxBigJump:     {{0, PallocChunkPages}},
                        },
@@ -381,7 +403,7 @@ func TestPageAllocAllocToCache(t *testing.T) {
        for name, v := range tests {
                v := v
                t.Run(name, func(t *testing.T) {
-                       b := NewPageAlloc(v.before, v.scav)
+                       b := NewPageAlloc(v.beforeAlloc, v.beforeScav)
                        defer FreePageAlloc(b)
 
                        for _, expect := range v.hits {
@@ -390,7 +412,7 @@ func TestPageAllocAllocToCache(t *testing.T) {
                                        return
                                }
                        }
-                       want := NewPageAlloc(v.after, v.scav)
+                       want := NewPageAlloc(v.afterAlloc, v.afterScav)
                        defer FreePageAlloc(want)
 
                        checkPageAlloc(t, want, b)
index ff112300c37365ac962bccc560623c5642b0db63..f63164becd392b2c8b0f0ffda8dfe817ac80e376 100644 (file)
@@ -57,6 +57,12 @@ func (b *pageBits) setAll() {
        }
 }
 
+// setBlock64 sets the 64-bit aligned block of bits containing the i'th bit that
+// are set in v.
+func (b *pageBits) setBlock64(i uint, v uint64) {
+       b[i/64] |= v
+}
+
 // clear clears bit i of pageBits.
 func (b *pageBits) clear(i uint) {
        b[i/64] &^= 1 << (i % 64)
@@ -93,6 +99,12 @@ func (b *pageBits) clearAll() {
        }
 }
 
+// clearBlock64 clears the 64-bit aligned block of bits containing the i'th bit that
+// are set in v.
+func (b *pageBits) clearBlock64(i uint, v uint64) {
+       b[i/64] &^= v
+}
+
 // popcntRange counts the number of set bits in the
 // range [i, i+n).
 func (b *pageBits) popcntRange(i, n uint) (s uint) {
@@ -367,6 +379,12 @@ func (b *pallocBits) pages64(i uint) uint64 {
        return (*pageBits)(b).block64(i)
 }
 
+// allocPages64 allocates a 64-bit block of 64 pages aligned to 64 pages according
+// to the bits set in alloc. The block set is the one containing the i'th page.
+func (b *pallocBits) allocPages64(i uint, alloc uint64) {
+       (*pageBits)(b).setBlock64(i, alloc)
+}
+
 // findBitRange64 returns the bit index of the first set of
 // n consecutive 1 bits. If no consecutive set of 1 bits of
 // size n may be found in c, then it returns an integer >= 64.
index 0ba415ba5acbe9c74808c3241cc3a6c4ee51c2ab..b4de8f53a919f801b60cd4ac7b550f7aa2cb1770 100644 (file)
@@ -142,7 +142,7 @@ var (
        mbuckets  *bucket // memory profile buckets
        bbuckets  *bucket // blocking profile buckets
        xbuckets  *bucket // mutex profile buckets
-       buckhash  *[179999]*bucket
+       buckhash  *[buckHashSize]*bucket
        bucketmem uintptr
 
        mProf struct {
@@ -627,6 +627,9 @@ func record(r *MemProfileRecord, b *bucket) {
        if msanenabled {
                msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
        }
+       if asanenabled {
+               asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
+       }
        copy(r.Stack0[:], b.stk())
        for i := int(b.nstk); i < len(r.Stack0); i++ {
                r.Stack0[i] = 0
@@ -680,6 +683,9 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
                        if msanenabled {
                                msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
                        }
+                       if asanenabled {
+                               asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
+                       }
                        i := copy(r.Stack0[:], b.stk())
                        for ; i < len(r.Stack0); i++ {
                                r.Stack0[i] = 0
index 25aaf94e26cec2a46c4672b9bcc612a7ee96bd3d..902a1e9e744b3d4ed38fc53b55a610d61e58e31b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build msan
-// +build msan
 
 package runtime
 
index 9908a8ec22170fdf7782407e25247b909a25c56c..f1bf4e1065cf96c2fc40c8a51afb3f29c252e8d0 100644 (file)
@@ -3,9 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build msan && linux && (amd64 || arm64)
-// +build msan
-// +build linux
-// +build amd64 arm64
 
 package msan
 
index b1096a6750e5d249dc132c92acf755ed7fe7fcce..2f5fd2d98216e542040e3bdab59c9084bd9037ab 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !msan
-// +build !msan
 
 // Dummy MSan support API, used when not built with -msan.
 
index 076a722eb73eba50eef9eb4a3a7ed4e501c51da5..a9c8987438defec3b430b7657db746d16dbf3de9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || solaris
-// +build aix darwin solaris
 
 package runtime_test
 
index 6d5e4ff0215a082f70556fe607981e82ef2c9a8d..97607fa2cf7a1bca191c01b10bc2072a73ff2f6c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package runtime_test
 
index b17257e9ec3649ba4cf5eebe671f5897648d5e88..408e1ec410fec434b125060d6470fe597d71b01a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin
-// +build aix darwin
 
 package runtime
 
index f22b2b591fd592806ba7b4df5de67222464a51a2..6a555bcd9970d9640780ee6984d0fe92cddb8d06 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime
 
index 1d6a9b525c8850e29074bba7b931a650433cb1dd..36342cfde832aa3150bbf97d4dbfbb24df47b0f0 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime_test
 
index 6c26fdbbeb8765baed5574f329d5a0e97642c40f..f60e62dec718b8f3343e1bdd1e342f133929ec08 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
 
 package runtime
 
@@ -78,6 +77,7 @@ type pollDesc struct {
        // pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO readiness notification)
        // proceed w/o taking the lock. So closing, everr, rg, rd, wg and wd are manipulated
        // in a lock-free way by all operations.
+       // TODO(golang.org/issue/49008): audit these lock-free fields for continued correctness.
        // NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
        // that will blow up when GC starts moving objects.
        lock    mutex // protects the following fields
@@ -86,11 +86,11 @@ type pollDesc struct {
        everr   bool      // marks event scanning error happened
        user    uint32    // user settable cookie
        rseq    uintptr   // protects from stale read timers
-       rg      uintptr   // pdReady, pdWait, G waiting for read or nil
+       rg      uintptr   // pdReady, pdWait, G waiting for read or nil. Accessed atomically.
        rt      timer     // read deadline timer (set if rt.f != nil)
        rd      int64     // read deadline
        wseq    uintptr   // protects from stale write timers
-       wg      uintptr   // pdReady, pdWait, G waiting for write or nil
+       wg      uintptr   // pdReady, pdWait, G waiting for write or nil. Accessed atomically.
        wt      timer     // write deadline timer
        wd      int64     // write deadline
        self    *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
@@ -147,20 +147,22 @@ func poll_runtime_isPollServerDescriptor(fd uintptr) bool {
 func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
        pd := pollcache.alloc()
        lock(&pd.lock)
-       if pd.wg != 0 && pd.wg != pdReady {
+       wg := atomic.Loaduintptr(&pd.wg)
+       if wg != 0 && wg != pdReady {
                throw("runtime: blocked write on free polldesc")
        }
-       if pd.rg != 0 && pd.rg != pdReady {
+       rg := atomic.Loaduintptr(&pd.rg)
+       if rg != 0 && rg != pdReady {
                throw("runtime: blocked read on free polldesc")
        }
        pd.fd = fd
        pd.closing = false
        pd.everr = false
        pd.rseq++
-       pd.rg = 0
+       atomic.Storeuintptr(&pd.rg, 0)
        pd.rd = 0
        pd.wseq++
-       pd.wg = 0
+       atomic.Storeuintptr(&pd.wg, 0)
        pd.wd = 0
        pd.self = pd
        unlock(&pd.lock)
@@ -178,10 +180,12 @@ func poll_runtime_pollClose(pd *pollDesc) {
        if !pd.closing {
                throw("runtime: close polldesc w/o unblock")
        }
-       if pd.wg != 0 && pd.wg != pdReady {
+       wg := atomic.Loaduintptr(&pd.wg)
+       if wg != 0 && wg != pdReady {
                throw("runtime: blocked write on closing polldesc")
        }
-       if pd.rg != 0 && pd.rg != pdReady {
+       rg := atomic.Loaduintptr(&pd.rg)
+       if rg != 0 && rg != pdReady {
                throw("runtime: blocked read on closing polldesc")
        }
        netpollclose(pd.fd)
@@ -205,9 +209,9 @@ func poll_runtime_pollReset(pd *pollDesc, mode int) int {
                return errcode
        }
        if mode == 'r' {
-               pd.rg = 0
+               atomic.Storeuintptr(&pd.rg, 0)
        } else if mode == 'w' {
-               pd.wg = 0
+               atomic.Storeuintptr(&pd.wg, 0)
        }
        return pollNoError
 }
@@ -417,6 +421,8 @@ func netpollgoready(gp *g, traceskip int) {
 
 // returns true if IO is ready, or false if timedout or closed
 // waitio - wait only for completed IO, ignore errors
+// Concurrent calls to netpollblock in the same mode are forbidden, as pollDesc
+// can hold only a single waiting goroutine for each mode.
 func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
        gpp := &pd.rg
        if mode == 'w' {
@@ -425,23 +431,25 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 
        // set the gpp semaphore to pdWait
        for {
-               old := *gpp
-               if old == pdReady {
-                       *gpp = 0
+               // Consume notification if already ready.
+               if atomic.Casuintptr(gpp, pdReady, 0) {
                        return true
                }
-               if old != 0 {
-                       throw("runtime: double wait")
-               }
                if atomic.Casuintptr(gpp, 0, pdWait) {
                        break
                }
+
+               // Double check that this isn't corrupt; otherwise we'd loop
+               // forever.
+               if v := atomic.Loaduintptr(gpp); v != pdReady && v != 0 {
+                       throw("runtime: double wait")
+               }
        }
 
        // need to recheck error states after setting gpp to pdWait
        // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
        // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
-       if waitio || netpollcheckerr(pd, mode) == 0 {
+       if waitio || netpollcheckerr(pd, mode) == pollNoError {
                gopark(netpollblockcommit, unsafe.Pointer(gpp), waitReasonIOWait, traceEvGoBlockNet, 5)
        }
        // be careful to not lose concurrent pdReady notification
@@ -459,7 +467,7 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
        }
 
        for {
-               old := *gpp
+               old := atomic.Loaduintptr(gpp)
                if old == pdReady {
                        return nil
                }
index 371ac59f8e2ec06327069c328fb77d5ddf2e3627..e0fb877d50858ba869df51e3e3205fc2dee8ef86 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package runtime
 
index 8366f289144cf4f377d6e7ed94271d3caadca56c..de1dcae7acf8123e8a1dc0fe3ab2634a6d289960 100644 (file)
@@ -6,7 +6,6 @@
 // Should never be used, because wasm/js network connections do not honor "SetNonblock".
 
 //go:build js && wasm
-// +build js,wasm
 
 package runtime
 
index 80d1b0cf18a17a9ab786599d91c44fb59f69db99..2f7f2848d296a6ee2c3fc035452cfe2d3297314c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 package runtime
 
index 33ab8eba58cc48a36f81763b8559f67b26b9a858..d0a63bca866f66680cd80ac2c762a693ab0d9f1d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package runtime
 
index b199aa633c12708c1361bc9c9af5e3c110e7b622..b188a2e88b7c8c24077a2f1dd75d5813697a07f8 100644 (file)
@@ -4,7 +4,6 @@
 
 // The file contains tests that cannot run under race detector for some reason.
 //go:build !race
-// +build !race
 
 package runtime_test
 
index 9ad5dde3829924d338010a2e7df96b70a8784d3f..d49f2ec0dfd9187e2b9a27db1c6590f975c9bcf7 100644 (file)
@@ -4,7 +4,6 @@
 
 // The file contains tests that cannot run under race detector for some reason.
 //go:build !race
-// +build !race
 
 package runtime_test
 
index 84194a3050d6c99d32ce41246e43280b6b785f20..2e946656d018955b3690830316ee6b26c66386aa 100644 (file)
@@ -289,6 +289,19 @@ func sigdelset(mask *sigset, i int) {
 func (c *sigctxt) fixsigcode(sig uint32) {
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 //go:nosplit
 func semacreate(mp *m) {
        if mp.waitsema != 0 {
@@ -316,20 +329,20 @@ func semacreate(mp *m) {
 
 //go:nosplit
 func semasleep(ns int64) int32 {
-       _m_ := getg().m
+       mp := getg().m
        if ns >= 0 {
-               _m_.ts.tv_sec = ns / 1000000000
-               _m_.ts.tv_nsec = ns % 1000000000
-
-               _m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
-               _m_.libcall.n = 2
-               _m_.scratch = mscratch{}
-               _m_.scratch.v[0] = _m_.waitsema
-               _m_.scratch.v[1] = uintptr(unsafe.Pointer(&_m_.ts))
-               _m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
-               asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&_m_.libcall))
-               if *_m_.perrno != 0 {
-                       if *_m_.perrno == _ETIMEDOUT || *_m_.perrno == _EAGAIN || *_m_.perrno == _EINTR {
+               mp.ts.tv_sec = ns / 1000000000
+               mp.ts.tv_nsec = ns % 1000000000
+
+               mp.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
+               mp.libcall.n = 2
+               mp.scratch = mscratch{}
+               mp.scratch.v[0] = mp.waitsema
+               mp.scratch.v[1] = uintptr(unsafe.Pointer(&mp.ts))
+               mp.libcall.args = uintptr(unsafe.Pointer(&mp.scratch))
+               asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&mp.libcall))
+               if *mp.perrno != 0 {
+                       if *mp.perrno == _ETIMEDOUT || *mp.perrno == _EAGAIN || *mp.perrno == _EINTR {
                                return -1
                        }
                        throw("sem_reltimedwait_np")
@@ -337,16 +350,16 @@ func semasleep(ns int64) int32 {
                return 0
        }
        for {
-               _m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
-               _m_.libcall.n = 1
-               _m_.scratch = mscratch{}
-               _m_.scratch.v[0] = _m_.waitsema
-               _m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
-               asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&_m_.libcall))
-               if _m_.libcall.r1 == 0 {
+               mp.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
+               mp.libcall.n = 1
+               mp.scratch = mscratch{}
+               mp.scratch.v[0] = mp.waitsema
+               mp.libcall.args = uintptr(unsafe.Pointer(&mp.scratch))
+               asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&mp.libcall))
+               if mp.libcall.r1 == 0 {
                        break
                }
-               if *_m_.perrno == _EINTR {
+               if *mp.perrno == _EINTR {
                        continue
                }
                throw("sem_wait")
index 478dde2fc3ff4c1d8527c83a50fd86f19d8cbbb0..aeff593d50b39e5f6845d0c61ab6af2b55d16647 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix
-// +build aix
 
 package runtime
 
@@ -49,7 +48,7 @@ func semacreate(mp *m) {
 
 //go:nosplit
 func semasleep(ns int64) int32 {
-       _m_ := getg().m
+       mp := getg().m
        if ns >= 0 {
                var ts timespec
 
@@ -63,17 +62,17 @@ func semasleep(ns int64) int32 {
                        ts.tv_nsec -= 1e9
                }
 
-               if r, err := sem_timedwait((*semt)(unsafe.Pointer(_m_.waitsema)), &ts); r != 0 {
+               if r, err := sem_timedwait((*semt)(unsafe.Pointer(mp.waitsema)), &ts); r != 0 {
                        if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
                                return -1
                        }
-                       println("sem_timedwait err ", err, " ts.tv_sec ", ts.tv_sec, " ts.tv_nsec ", ts.tv_nsec, " ns ", ns, " id ", _m_.id)
+                       println("sem_timedwait err ", err, " ts.tv_sec ", ts.tv_sec, " ts.tv_nsec ", ts.tv_nsec, " ns ", ns, " id ", mp.id)
                        throw("sem_timedwait")
                }
                return 0
        }
        for {
-               r1, err := sem_wait((*semt)(unsafe.Pointer(_m_.waitsema)))
+               r1, err := sem_wait((*semt)(unsafe.Pointer(mp.waitsema)))
                if r1 == 0 {
                        break
                }
@@ -323,6 +322,19 @@ func sigdelset(mask *sigset, i int) {
        (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 const (
        _CLOCK_REALTIME  = 9
        _CLOCK_MONOTONIC = 10
index ca61f20e8ac43c0d57c282c6f2f0c9cab98f8776..0f0eb6c6fdcfa609b7dc753f8ea5a526d2d1d27b 100644 (file)
@@ -425,6 +425,19 @@ func sigdelset(mask *sigset, i int) {
        *mask &^= 1 << (uint32(i) - 1)
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 //go:linkname executablePath os.executablePath
 var executablePath string
 
index 191a560667c9cf9a2329543830d2c8855d8fee8c..cba2e42ab052d056e4e057f3d82e6059cbad0961 100644 (file)
@@ -268,6 +268,19 @@ func sigdelset(mask *sigset, i int) {
 func (c *sigctxt) fixsigcode(sig uint32) {
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 func sysargs(argc int32, argv **byte) {
        n := argc + 1
 
index 5a8121a420f208fea16c4aa345380fc63afabc63..c63b0e3d69dc0609d1ca425ff0ec2cfd7b4d2630 100644 (file)
@@ -380,6 +380,19 @@ func sigdelset(mask *sigset, i int) {
 func (c *sigctxt) fixsigcode(sig uint32) {
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 func sysargs(argc int32, argv **byte) {
        n := argc + 1
 
index 7e266dc27e2c62a34b74b35a5be352fdaf5e89c1..3eaedf0b8b99a805a732a1799d305edada6c4ea1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd && !amd64
-// +build freebsd,!amd64
 
 package runtime
 
index 8fe0cb6718f14d2f62577146058f35115e8e8e50..1d9452bda5fc33b5650a225a97e977bdb56fcfe8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd && !arm
-// +build freebsd,!arm
 
 package runtime
 
index 52b64e76027648239fe16ed75a6a95334bc82f2e..9ed916705bc517e906f1f1618fc0e58ae3492277 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package runtime
 
index 88c16f7163959007231c680e8d6e3d334af116af..32a1e1b4f7d9bc7c22e53d1a767b741c9e697dd5 100644 (file)
@@ -7,10 +7,21 @@ package runtime
 import (
        "internal/abi"
        "internal/goarch"
+       "runtime/internal/atomic"
        "unsafe"
 )
 
-type mOS struct{}
+type mOS struct {
+       // profileTimer holds the ID of the POSIX interval timer for profiling CPU
+       // usage on this thread.
+       //
+       // It is valid when the profileTimerValid field is non-zero. A thread
+       // creates and manages its own timer, and these fields are read and written
+       // only by this thread. But because some of the reads on profileTimerValid
+       // are in signal handling code, access to that field uses atomic operations.
+       profileTimer      int32
+       profileTimerValid uint32
+}
 
 //go:noescape
 func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
@@ -395,6 +406,15 @@ func sigaltstack(new, old *stackt)
 //go:noescape
 func setitimer(mode int32, new, old *itimerval)
 
+//go:noescape
+func timer_create(clockid int32, sevp *sigevent, timerid *int32) int32
+
+//go:noescape
+func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32
+
+//go:noescape
+func timer_delete(timerid int32) int32
+
 //go:noescape
 func rtsigprocmask(how int32, new, old *sigset, size int32)
 
@@ -420,6 +440,11 @@ func pipe() (r, w int32, errno int32)
 func pipe2(flags int32) (r, w int32, errno int32)
 func setNonblock(fd int32)
 
+const (
+       _si_max_size    = 128
+       _sigev_max_size = 64
+)
+
 //go:nosplit
 //go:nowritebarrierrec
 func setsig(i uint32, fn uintptr) {
@@ -508,3 +533,134 @@ func tgkill(tgid, tid, sig int)
 func signalM(mp *m, sig int) {
        tgkill(getpid(), int(mp.procid), sig)
 }
+
+// go118UseTimerCreateProfiler enables the per-thread CPU profiler.
+const go118UseTimerCreateProfiler = true
+
+// validSIGPROF compares this signal delivery's code against the signal sources
+// that the profiler uses, returning whether the delivery should be processed.
+// To be processed, a signal delivery from a known profiling mechanism should
+// correspond to the best profiling mechanism available to this thread. Signals
+// from other sources are always considered valid.
+//
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       code := int32(c.sigcode())
+       setitimer := code == _SI_KERNEL
+       timer_create := code == _SI_TIMER
+
+       if !(setitimer || timer_create) {
+               // The signal doesn't correspond to a profiling mechanism that the
+               // runtime enables itself. There's no reason to process it, but there's
+               // no reason to ignore it either.
+               return true
+       }
+
+       if mp == nil {
+               // Since we don't have an M, we can't check if there's an active
+               // per-thread timer for this thread. We don't know how long this thread
+               // has been around, and if it happened to interact with the Go scheduler
+               // at a time when profiling was active (causing it to have a per-thread
+               // timer). But it may have never interacted with the Go scheduler, or
+               // never while profiling was active. To avoid double-counting, process
+               // only signals from setitimer.
+               //
+               // When a custom cgo traceback function has been registered (on
+               // platforms that support runtime.SetCgoTraceback), SIGPROF signals
+               // delivered to a thread that cannot find a matching M do this check in
+               // the assembly implementations of runtime.cgoSigtramp.
+               return setitimer
+       }
+
+       // Having an M means the thread interacts with the Go scheduler, and we can
+       // check whether there's an active per-thread timer for this thread.
+       if atomic.Load(&mp.profileTimerValid) != 0 {
+               // If this M has its own per-thread CPU profiling interval timer, we
+               // should track the SIGPROF signals that come from that timer (for
+               // accurate reporting of its CPU usage; see issue 35057) and ignore any
+               // that it gets from the process-wide setitimer (to not over-count its
+               // CPU consumption).
+               return timer_create
+       }
+
+       // No active per-thread timer means the only valid profiler is setitimer.
+       return setitimer
+}
+
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       mp := getg().m
+       mp.profilehz = hz
+
+       if !go118UseTimerCreateProfiler {
+               return
+       }
+
+       // destroy any active timer
+       if atomic.Load(&mp.profileTimerValid) != 0 {
+               timerid := mp.profileTimer
+               atomic.Store(&mp.profileTimerValid, 0)
+               mp.profileTimer = 0
+
+               ret := timer_delete(timerid)
+               if ret != 0 {
+                       print("runtime: failed to disable profiling timer; timer_delete(", timerid, ") errno=", -ret, "\n")
+                       throw("timer_delete")
+               }
+       }
+
+       if hz == 0 {
+               // If the goal was to disable profiling for this thread, then the job's done.
+               return
+       }
+
+       // The period of the timer should be 1/Hz. For every "1/Hz" of additional
+       // work, the user should expect one additional sample in the profile.
+       //
+       // But to scale down to very small amounts of application work, to observe
+       // even CPU usage of "one tenth" of the requested period, set the initial
+       // timing delay in a different way: So that "one tenth" of a period of CPU
+       // spend shows up as a 10% chance of one sample (for an expected value of
+       // 0.1 samples), and so that "two and six tenths" periods of CPU spend show
+       // up as a 60% chance of 3 samples and a 40% chance of 2 samples (for an
+       // expected value of 2.6). Set the initial delay to a value in the unifom
+       // random distribution between 0 and the desired period. And because "0"
+       // means "disable timer", add 1 so the half-open interval [0,period) turns
+       // into (0,period].
+       //
+       // Otherwise, this would show up as a bias away from short-lived threads and
+       // from threads that are only occasionally active: for example, when the
+       // garbage collector runs on a mostly-idle system, the additional threads it
+       // activates may do a couple milliseconds of GC-related work and nothing
+       // else in the few seconds that the profiler observes.
+       spec := new(itimerspec)
+       spec.it_value.setNsec(1 + int64(fastrandn(uint32(1e9/hz))))
+       spec.it_interval.setNsec(1e9 / int64(hz))
+
+       var timerid int32
+       var sevp sigevent
+       sevp.notify = _SIGEV_THREAD_ID
+       sevp.signo = _SIGPROF
+       sevp.sigev_notify_thread_id = int32(mp.procid)
+       ret := timer_create(_CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid)
+       if ret != 0 {
+               // If we cannot create a timer for this M, leave profileTimerValid false
+               // to fall back to the process-wide setitimer profiler.
+               return
+       }
+
+       ret = timer_settime(timerid, 0, spec, nil)
+       if ret != 0 {
+               print("runtime: failed to configure profiling timer; timer_settime(", timerid,
+                       ", 0, {interval: {",
+                       spec.it_interval.tv_sec, "s + ", spec.it_interval.tv_nsec, "ns} value: {",
+                       spec.it_value.tv_sec, "s + ", spec.it_value.tv_nsec, "ns}}, nil) errno=", -ret, "\n")
+               throw("timer_settime")
+       }
+
+       mp.profileTimer = timerid
+       atomic.Store(&mp.profileTimerValid, 1)
+}
index 5260f22f57396b44468b699cf849b254884963a9..2daa56fce75e533b8546f9dd75603bc5d8137243 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build arm64
-// +build arm64
 
 package runtime
 
index 498d7cec6d8e4502f01c91c992516d7939460071..537515fcf25a8f166a4e043a828f3348d2af9c4d 100644 (file)
@@ -5,8 +5,6 @@
 // The standard Linux sigset type on big-endian 64-bit machines.
 
 //go:build linux && (ppc64 || s390x)
-// +build linux
-// +build ppc64 s390x
 
 package runtime
 
index fe1973dbde6ce06a3bd359d3e53a4edbd9f30acc..bed9e66e156e2c72e1cd30f71b40fb790343908d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !mips && !mipsle && !mips64 && !mips64le && !s390x && !ppc64 && linux
-// +build !mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,linux
 
 package runtime
 
index bd76442dbd843219bff013e64d5662436bb002f3..188db0103481d769d0c96d57b59a3bcad4fdc64c 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips64 || mips64le)
-// +build linux
-// +build mips64 mips64le
 
 package runtime
 
index ef8b3f7d4348230ad17663105c3966880661044d..73016f81d91b7c8beb375870f63acf2f2bb84448 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips || mipsle)
-// +build linux
-// +build mips mipsle
 
 package runtime
 
index 59b5aacaebc318a142d4e8cc0bcdcf143c5ac66e..7b84f713d64c3bcf6e1e2ddf4cec81b3ec66d928 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && !arm && !arm64 && !mips && !mipsle && !mips64 && !mips64le && !s390x && !ppc64 && !ppc64le
-// +build linux,!arm,!arm64,!mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,!ppc64le
 
 package runtime
 
index 8104f63627f7486b462adbac1c9f8f8cddf48c9c..b06716dc6a1c7e1e568800ecaddfcb0c8e0138db 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build linux && !386 && !amd64 && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le
-// +build linux,!386,!amd64,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le
+//go:build linux && !386 && !amd64 && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !riscv64
 
 package runtime
 
index c093d2ec0f593013d479a8c8f10fe958b4940d12..25d7ccc0356c1659ec7e464f88bee6c8d6d3d9a2 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (ppc64 || ppc64le)
-// +build linux
-// +build ppc64 ppc64le
 
 package runtime
 
index 5667774d82f055569923a94cef5f1081660a4339..c88f61fa2e99e681fe93838ae20e53ab67369af5 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (386 || amd64)
-// +build linux
-// +build 386 amd64
 
 package runtime
 
index 2c20ee21734435c97ad985ee72738bebff187817..cd9508c7063f94218ff5259cb006a598b52cc944 100644 (file)
@@ -101,6 +101,9 @@ var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)
 
 // From NetBSD's <sys/sysctl.h>
 const (
+       _CTL_KERN   = 1
+       _KERN_OSREV = 3
+
        _CTL_HW        = 6
        _HW_NCPU       = 3
        _HW_PAGESIZE   = 7
@@ -138,6 +141,13 @@ func getPageSize() uintptr {
        return 0
 }
 
+func getOSRev() int {
+       if osrev, ok := sysctlInt([]uint32{_CTL_KERN, _KERN_OSREV}); ok {
+               return int(osrev)
+       }
+       return 0
+}
+
 //go:nosplit
 func semacreate(mp *m) {
 }
@@ -252,6 +262,7 @@ func osinit() {
        if physPageSize == 0 {
                physPageSize = getPageSize()
        }
+       needSysmonWorkaround = getOSRev() < 902000000 // NetBSD 9.2
 }
 
 var urandom_dev = []byte("/dev/urandom\x00")
@@ -360,6 +371,19 @@ func sigdelset(mask *sigset, i int) {
 func (c *sigctxt) fixsigcode(sig uint32) {
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 func sysargs(argc int32, argv **byte) {
        n := argc + 1
 
index 6134b6c02f20683f7f1d35e37e1e0e8a08c4485b..a5775961e8fa876ff437b80df538ceecb3ee3175 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !openbsd
-// +build !openbsd
 
 package runtime
 
index 3829683c807186b38ae75c84bccb22a641658ac4..0c72500674f72e1bbb48b22dbcbb0ee915ff7c3b 100644 (file)
@@ -5,7 +5,6 @@
 // Solaris code that doesn't also apply to illumos.
 
 //go:build !illumos
-// +build !illumos
 
 package runtime
 
index 54f36c6ebff7a4aebfd3c2a4a2b164043e00a58c..2d0e71de53b5ee3c1851608843df511d52e6149c 100644 (file)
@@ -233,6 +233,19 @@ func sigdelset(mask *sigset, i int) {
 func (c *sigctxt) fixsigcode(sig uint32) {
 }
 
+func setProcessCPUProfiler(hz int32) {
+       setProcessCPUProfilerTimer(hz)
+}
+
+func setThreadCPUProfiler(hz int32) {
+       setThreadCPUProfilerHz(hz)
+}
+
+//go:nosplit
+func validSIGPROF(mp *m, c *sigctxt) bool {
+       return true
+}
+
 var haveMapStack = false
 
 func osStackAlloc(s *mspan) {
index 981e49827fbd99a09181a86e02e5c1b5c7f28365..ff21eccb4b5759d0f31cbe9df243964023fb5564 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && !mips64
-// +build openbsd,!mips64
 
 package runtime
 
index 1ddee1864e415150ef9eca6b48699c5c564b30a9..8128c20453b8242629d0a996a2605a9f6d32c1c7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && mips64
-// +build openbsd,mips64
 
 package runtime
 
index c20ee8300e3001a8771133b6d73c2b5ad38fade0..d32894ba6a38b29d70afd6ad4f777237c2aaf684 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && mips64
-// +build openbsd,mips64
 
 package runtime
 
index af1997131feba964e06521a75f99ae5a2d8d0486..99542fb2de161786d8974b17fb96d3476205b99e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && mips64
-// +build openbsd,mips64
 
 package runtime
 
index 648239fb366a15b6f96d53af2cb76e3867ebc871..0e17e75e3e68b7eeb8b7dba553b8fb428805aebd 100644 (file)
@@ -40,6 +40,7 @@ const (
 //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
 //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
 //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
+//go:cgo_import_dynamic runtime._RaiseException RaiseException%4 "kernel32.dll"
 //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
 //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
 //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll"
@@ -93,6 +94,7 @@ var (
        _PostQueuedCompletionStatus,
        _QueryPerformanceCounter,
        _QueryPerformanceFrequency,
+       _RaiseException,
        _ResumeThread,
        _SetConsoleCtrlHandler,
        _SetErrorMode,
@@ -120,6 +122,7 @@ var (
        _AddVectoredContinueHandler,
        _LoadLibraryExA,
        _LoadLibraryExW,
+       _WerSetFlags,
        _ stdFunction
 
        // Use RtlGenRandom to generate cryptographically random data.
@@ -254,6 +257,7 @@ func loadOptionalSyscalls() {
        _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
        _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
        _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
+       _WerSetFlags = windowsFindfunc(k32, []byte("WerSetFlags\000"))
        useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
 
        var advapi32dll = []byte("advapi32.dll\000")
index e4bdceb32f1a68d4730846980e441eab6e886dfb..eec69dfdc67f5d6b0d633188921b769c534ec406 100644 (file)
@@ -560,14 +560,28 @@ func printpanics(p *_panic) {
        print("\n")
 }
 
-// addOneOpenDeferFrame scans the stack for the first frame (if any) with
-// open-coded defers and if it finds one, adds a single record to the defer chain
-// for that frame. If sp is non-nil, it starts the stack scan from the frame
-// specified by sp. If sp is nil, it uses the sp from the current defer record
-// (which has just been finished). Hence, it continues the stack scan from the
-// frame of the defer that just finished. It skips any frame that already has an
-// open-coded _defer record, which would have been created from a previous
-// (unrecovered) panic.
+// addOneOpenDeferFrame scans the stack (in gentraceback order, from inner frames to
+// outer frames) for the first frame (if any) with open-coded defers. If it finds
+// one, it adds a single entry to the defer chain for that frame. The entry added
+// represents all the defers in the associated open defer frame, and is sorted in
+// order with respect to any non-open-coded defers.
+//
+// addOneOpenDeferFrame stops (possibly without adding a new entry) if it encounters
+// an in-progress open defer entry. An in-progress open defer entry means there has
+// been a new panic because of a defer in the associated frame. addOneOpenDeferFrame
+// does not add an open defer entry past a started entry, because that started entry
+// still needs to finished, and addOneOpenDeferFrame will be called when that started
+// entry is completed. The defer removal loop in gopanic() similarly stops at an
+// in-progress defer entry. Together, addOneOpenDeferFrame and the defer removal loop
+// ensure the invariant that there is no open defer entry further up the stack than
+// an in-progress defer, and also that the defer removal loop is guaranteed to remove
+// all not-in-progress open defer entries from the defer chain.
+//
+// If sp is non-nil, addOneOpenDeferFrame starts the stack scan from the frame
+// specified by sp. If sp is nil, it uses the sp from the current defer record (which
+// has just been finished). Hence, it continues the stack scan from the frame of the
+// defer that just finished. It skips any frame that already has a (not-in-progress)
+// open-coded _defer record in the defer chain.
 //
 // Note: All entries of the defer chain (including this new open-coded entry) have
 // their pointers (including sp) adjusted properly if the stack moves while
@@ -608,6 +622,16 @@ func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) {
                                                if !d.openDefer {
                                                        throw("duplicated defer entry")
                                                }
+                                               // Don't add any record past an
+                                               // in-progress defer entry. We don't
+                                               // need it, and more importantly, we
+                                               // want to keep the invariant that
+                                               // there is no open defer entry
+                                               // passed an in-progress entry (see
+                                               // header comment).
+                                               if d.started {
+                                                       return false
+                                               }
                                                return true
                                        }
                                        prev = d
@@ -626,7 +650,7 @@ func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) {
                                // deferreturn that runs any remaining
                                // defers and then returns from the
                                // function.
-                               d1.pc = frame.fn.entry + uintptr(frame.fn.deferreturn)
+                               d1.pc = frame.fn.entry() + uintptr(frame.fn.deferreturn)
                                d1.varp = frame.varp
                                d1.fd = fd
                                // Save the SP/PC associated with current frame,
@@ -849,12 +873,15 @@ func gopanic(e interface{}) {
                        }
                        atomic.Xadd(&runningPanicDefers, -1)
 
-                       // Remove any remaining non-started, open-coded
-                       // defer entries after a recover, since the
-                       // corresponding defers will be executed normally
-                       // (inline). Any such entry will become stale once
-                       // we run the corresponding defers inline and exit
-                       // the associated stack frame.
+                       // After a recover, remove any remaining non-started,
+                       // open-coded defer entries, since the corresponding defers
+                       // will be executed normally (inline). Any such entry will
+                       // become stale once we run the corresponding defers inline
+                       // and exit the associated stack frame. We only remove up to
+                       // the first started (in-progress) open defer entry, not
+                       // including the current frame, since any higher entries will
+                       // be from a higher panic in progress, and will still be
+                       // needed.
                        d := gp._defer
                        var prev *_defer
                        if !done {
@@ -975,6 +1002,11 @@ var runningPanicDefers uint32
 // panicking is incremented and decremented atomically.
 var panicking uint32
 
+// tracebackprinted is zero before gopanic() prints the traceback. After
+// traceback is printed, it sets to 1 so that the subsequent exception handler
+// won't print the traceback again.
+var tracebackprinted uint32
+
 // paniclk is held while printing the panic information and stack trace,
 // so that two concurrent panics don't overlap their output.
 var paniclk mutex
@@ -1018,6 +1050,9 @@ func fatalthrow() {
                startpanic_m()
 
                if dopanic_m(gp, pc, sp) {
+                       // At this point, traceback has already been printed.
+                       // Set tracebackprinted to 1 to avoid printing traceback again
+                       tracebackprinted = 1
                        // crash uses a decent amount of nosplit stack and we're already
                        // low on stack in throw, so crash on the system stack (unlike
                        // fatalpanic).
@@ -1059,6 +1094,9 @@ func fatalpanic(msgs *_panic) {
        })
 
        if docrash {
+               // At this point, traceback has already been printed.
+               // Set tracebackprinted to 1 to avoid printing traceback again
+               tracebackprinted = 1
                // By crashing outside the above systemstack call, debuggers
                // will not be confused when generating a backtrace.
                // Function crash is marked nosplit to avoid stack growth.
@@ -1190,22 +1228,22 @@ func canpanic(gp *g) bool {
        // Note also that g->m can change at preemption, so m can go stale
        // if this function ever makes a function call.
        _g_ := getg()
-       _m_ := _g_.m
+       mp := _g_.m
 
        // Is it okay for gp to panic instead of crashing the program?
        // Yes, as long as it is running Go code, not runtime code,
        // and not stuck in a system call.
-       if gp == nil || gp != _m_.curg {
+       if gp == nil || gp != mp.curg {
                return false
        }
-       if _m_.locks != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
+       if mp.locks != 0 || mp.mallocing != 0 || mp.throwing != 0 || mp.preemptoff != "" || mp.dying != 0 {
                return false
        }
        status := readgstatus(gp)
        if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
                return false
        }
-       if GOOS == "windows" && _m_.libcallsp != 0 {
+       if GOOS == "windows" && mp.libcallsp != 0 {
                return false
        }
        return true
index acbdd1ff458d6210d96a08c3b564d72a2b39b023..fa3f2bf2f8bdf12f8a4d0af251425e84083b9782 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build 386 || arm || mips || mipsle
-// +build 386 arm mips mipsle
 
 package runtime
 
index cd7fc5f8489a988a52affb35d62aec12353f7f81..f37854f915cfca7a516926cd16dbdb2aaffbad3e 100644 (file)
@@ -96,7 +96,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, errstr s
 func pluginftabverify(md *moduledata) {
        badtable := false
        for i := 0; i < len(md.ftab); i++ {
-               entry := md.ftab[i].entry
+               entry := md.textAddr(md.ftab[i].entryoff)
                if md.minpc <= entry && entry <= md.maxpc {
                        continue
                }
@@ -112,7 +112,7 @@ func pluginftabverify(md *moduledata) {
                f2 := findfunc(entry)
                if f2.valid() {
                        name2 = funcname(f2)
-                       entry2 = f2.entry
+                       entry2 = f2.entry()
                }
                badtable = true
                println("ftab entry", hex(entry), "/", hex(entry2), ": ",
index b4680fbdee99ecb6c79a32e6e591745ec2664175..ab8341d32f681cab67a78b53c138a1dce35c11a7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package pprof
 
@@ -86,17 +85,6 @@ func TestMemoryProfiler(t *testing.T) {
 
        runtime.GC() // materialize stats
 
-       // TODO(mknyszek): Fix #45315 and remove this extra call.
-       //
-       // Unfortunately, it's possible for the sweep termination condition
-       // to flap, so with just one runtime.GC call, a freed object could be
-       // missed, leading this test to fail. A second call reduces the chance
-       // of this happening to zero, because sweeping actually has to finish
-       // to move on to the next GC, during which nothing will happen.
-       //
-       // See #46500 for more details.
-       runtime.GC()
-
        memoryProfilerRun++
 
        tests := []struct {
@@ -105,31 +93,31 @@ func TestMemoryProfiler(t *testing.T) {
        }{{
                stk: []string{"runtime/pprof.allocatePersistent1K", "runtime/pprof.TestMemoryProfiler"},
                legacy: fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#      0x[0-9,a-f]+    runtime/pprof\.allocatePersistent1K\+0x[0-9,a-f]+       .*/runtime/pprof/mprof_test\.go:48
-#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:83
+#      0x[0-9,a-f]+    runtime/pprof\.allocatePersistent1K\+0x[0-9,a-f]+       .*/runtime/pprof/mprof_test\.go:47
+#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:82
 `, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun),
        }, {
                stk: []string{"runtime/pprof.allocateTransient1M", "runtime/pprof.TestMemoryProfiler"},
                legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#      0x[0-9,a-f]+    runtime/pprof\.allocateTransient1M\+0x[0-9,a-f]+        .*/runtime/pprof/mprof_test.go:25
-#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:80
+#      0x[0-9,a-f]+    runtime/pprof\.allocateTransient1M\+0x[0-9,a-f]+        .*/runtime/pprof/mprof_test.go:24
+#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:79
 `, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
        }, {
                stk: []string{"runtime/pprof.allocateTransient2M", "runtime/pprof.TestMemoryProfiler"},
                legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#      0x[0-9,a-f]+    runtime/pprof\.allocateTransient2M\+0x[0-9,a-f]+        .*/runtime/pprof/mprof_test.go:31
-#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:81
+#      0x[0-9,a-f]+    runtime/pprof\.allocateTransient2M\+0x[0-9,a-f]+        .*/runtime/pprof/mprof_test.go:30
+#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:80
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
        }, {
                stk: []string{"runtime/pprof.allocateTransient2MInline", "runtime/pprof.TestMemoryProfiler"},
                legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#      0x[0-9,a-f]+    runtime/pprof\.allocateTransient2MInline\+0x[0-9,a-f]+  .*/runtime/pprof/mprof_test.go:35
-#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:82
+#      0x[0-9,a-f]+    runtime/pprof\.allocateTransient2MInline\+0x[0-9,a-f]+  .*/runtime/pprof/mprof_test.go:34
+#      0x[0-9,a-f]+    runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:81
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
        }, {
                stk: []string{"runtime/pprof.allocateReflectTransient"},
                legacy: fmt.Sprintf(`0: 0 \[%v: %v\] @( 0x[0-9,a-f]+)+
-#      0x[0-9,a-f]+    runtime/pprof\.allocateReflectTransient\+0x[0-9,a-f]+   .*/runtime/pprof/mprof_test.go:56
+#      0x[0-9,a-f]+    runtime/pprof\.allocateReflectTransient\+0x[0-9,a-f]+   .*/runtime/pprof/mprof_test.go:55
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
        }}
 
index e175dd380cfb62d51f2a48a8baa83a642a977c79..cbc5176cfa063b3b09e52ebfb7150fb714798922 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !darwin && !linux
-// +build !darwin,!linux
 
 package pprof
 
index 269f21bc2f93c520d7b280af186318ad2a431627..46263fedd965da6d97598d81527ed1475ce1b3e7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || linux
-// +build darwin linux
 
 package pprof
 
index e0d32a0f54aa7d42bdaf6813a43c852d83e7f3b2..417d5034a6e2bed949b90dee7669230bb23e018a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 package pprof
 
@@ -21,6 +20,7 @@ import (
        "os/exec"
        "regexp"
        "runtime"
+       "runtime/debug"
        "strings"
        "sync"
        "sync/atomic"
@@ -79,6 +79,10 @@ func cpuHog2(x int) int {
        return foo
 }
 
+func cpuHog3(x int) int {
+       return cpuHog0(x, 1e5)
+}
+
 // Return a list of functions that we don't want to ever appear in CPU
 // profiles. For gccgo, that list includes the sigprof handler itself.
 func avoidFunctions() []string {
@@ -107,6 +111,101 @@ func TestCPUProfileMultithreaded(t *testing.T) {
        })
 }
 
+func TestCPUProfileMultithreadMagnitude(t *testing.T) {
+       if runtime.GOOS != "linux" {
+               t.Skip("issue 35057 is only confirmed on Linux")
+       }
+
+       // Run a workload in a single goroutine, then run copies of the same
+       // workload in several goroutines. For both the serial and parallel cases,
+       // the CPU time the process measures with its own profiler should match the
+       // total CPU usage that the OS reports.
+       //
+       // We could also check that increases in parallelism (GOMAXPROCS) lead to a
+       // linear increase in the CPU usage reported by both the OS and the
+       // profiler, but without a guarantee of exclusive access to CPU resources
+       // that is likely to be a flaky test.
+
+       // Require the smaller value to be within 10%, or 40% in short mode.
+       maxDiff := 0.10
+       if testing.Short() {
+               maxDiff = 0.40
+       }
+
+       parallelism := runtime.GOMAXPROCS(0)
+
+       // This test compares the process's total CPU time against the CPU
+       // profiler's view of time spent in direct execution of user code.
+       // Background work, especially from the garbage collector, adds noise to
+       // that measurement. Disable automatic triggering of the GC, and then
+       // request a complete GC cycle (up through sweep termination).
+       defer debug.SetGCPercent(debug.SetGCPercent(-1))
+       runtime.GC()
+
+       var cpuTime1, cpuTimeN time.Duration
+       p := testCPUProfile(t, stackContains, []string{"runtime/pprof.cpuHog1", "runtime/pprof.cpuHog3"}, avoidFunctions(), func(dur time.Duration) {
+               cpuTime1 = diffCPUTime(t, func() {
+                       // Consume CPU in one goroutine
+                       cpuHogger(cpuHog1, &salt1, dur)
+               })
+
+               cpuTimeN = diffCPUTime(t, func() {
+                       // Next, consume CPU in several goroutines
+                       var wg sync.WaitGroup
+                       var once sync.Once
+                       for i := 0; i < parallelism; i++ {
+                               wg.Add(1)
+                               go func() {
+                                       defer wg.Done()
+                                       var salt = 0
+                                       cpuHogger(cpuHog3, &salt, dur)
+                                       once.Do(func() { salt1 = salt })
+                               }()
+                       }
+                       wg.Wait()
+               })
+       })
+
+       for i, unit := range []string{"count", "nanoseconds"} {
+               if have, want := p.SampleType[i].Unit, unit; have != want {
+                       t.Errorf("pN SampleType[%d]; %q != %q", i, have, want)
+               }
+       }
+
+       var value1, valueN time.Duration
+       for _, sample := range p.Sample {
+               if stackContains("runtime/pprof.cpuHog1", uintptr(sample.Value[0]), sample.Location, sample.Label) {
+                       value1 += time.Duration(sample.Value[1]) * time.Nanosecond
+               }
+               if stackContains("runtime/pprof.cpuHog3", uintptr(sample.Value[0]), sample.Location, sample.Label) {
+                       valueN += time.Duration(sample.Value[1]) * time.Nanosecond
+               }
+       }
+
+       compare := func(a, b time.Duration, maxDiff float64) func(*testing.T) {
+               return func(t *testing.T) {
+                       t.Logf("compare %s vs %s", a, b)
+                       if a <= 0 || b <= 0 {
+                               t.Errorf("Expected both time reports to be positive")
+                               return
+                       }
+
+                       if a < b {
+                               a, b = b, a
+                       }
+
+                       diff := float64(a-b) / float64(a)
+                       if diff > maxDiff {
+                               t.Errorf("CPU usage reports are too different (limit -%.1f%%, got -%.1f%%)", maxDiff*100, diff*100)
+                       }
+               }
+       }
+
+       // check that the OS's perspective matches what the Go runtime measures
+       t.Run("serial execution OS vs pprof", compare(cpuTime1, value1, maxDiff))
+       t.Run("parallel execution OS vs pprof", compare(cpuTimeN, valueN, maxDiff))
+}
+
 // containsInlinedCall reports whether the function body for the function f is
 // known to contain an inlined function call within the first maxBytes bytes.
 func containsInlinedCall(f interface{}, maxBytes int) bool {
@@ -350,6 +449,16 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, avoid []stri
        return nil
 }
 
+var diffCPUTimeImpl func(f func()) time.Duration
+
+func diffCPUTime(t *testing.T, f func()) time.Duration {
+       if fn := diffCPUTimeImpl; fn != nil {
+               return fn(f)
+       }
+       t.Fatalf("cannot measure CPU time on GOOS=%s GOARCH=%s", runtime.GOOS, runtime.GOARCH)
+       return 0
+}
+
 func contains(slice []string, s string) bool {
        for i := range slice {
                if slice[i] == s {
@@ -1133,11 +1242,10 @@ func TestGoroutineCounts(t *testing.T) {
 
 func containsInOrder(s string, all ...string) bool {
        for _, t := range all {
-               i := strings.Index(s, t)
-               if i < 0 {
+               var ok bool
+               if _, s, ok = strings.Cut(s, t); !ok {
                        return false
                }
-               s = s[i+len(t):]
        }
        return true
 }
@@ -1217,18 +1325,18 @@ func TestEmptyCallStack(t *testing.T) {
 // stackContainsLabeled takes a spec like funcname;key=value and matches if the stack has that key
 // and value and has funcname somewhere in the stack.
 func stackContainsLabeled(spec string, count uintptr, stk []*profile.Location, labels map[string][]string) bool {
-       semi := strings.Index(spec, ";")
-       if semi == -1 {
+       base, kv, ok := strings.Cut(spec, ";")
+       if !ok {
                panic("no semicolon in key/value spec")
        }
-       kv := strings.SplitN(spec[semi+1:], "=", 2)
-       if len(kv) != 2 {
+       k, v, ok := strings.Cut(kv, "=")
+       if !ok {
                panic("missing = in key/value spec")
        }
-       if !contains(labels[kv[0]], kv[1]) {
+       if !contains(labels[k], v) {
                return false
        }
-       return stackContains(spec[:semi], count, stk, labels)
+       return stackContains(base, count, stk, labels)
 }
 
 func TestCPUProfileLabel(t *testing.T) {
@@ -1544,3 +1652,38 @@ func TestTryAdd(t *testing.T) {
                })
        }
 }
+
+func TestTimeVDSO(t *testing.T) {
+       // Test that time functions have the right stack trace. In particular,
+       // it shouldn't be recursive.
+
+       if runtime.GOOS == "android" {
+               // Flaky on Android, issue 48655. VDSO may not be enabled.
+               testenv.SkipFlaky(t, 48655)
+       }
+
+       p := testCPUProfile(t, stackContains, []string{"time.now"}, avoidFunctions(), func(dur time.Duration) {
+               t0 := time.Now()
+               for {
+                       t := time.Now()
+                       if t.Sub(t0) >= dur {
+                               return
+                       }
+               }
+       })
+
+       // Check for recursive time.now sample.
+       for _, sample := range p.Sample {
+               var seenNow bool
+               for _, loc := range sample.Location {
+                       for _, line := range loc.Line {
+                               if line.Function.Name == "time.now" {
+                                       if seenNow {
+                                               t.Fatalf("unexpected recursive time.now")
+                                       }
+                                       seenNow = true
+                               }
+                       }
+               }
+       }
+}
index 686251395663f32358e39bc283513c13effedb34..54e7a80183e072be1e6061943965ae14c8b002c0 100644 (file)
@@ -13,6 +13,7 @@ import (
        "os"
        "runtime"
        "strconv"
+       "strings"
        "time"
        "unsafe"
 )
@@ -581,6 +582,9 @@ func (b *profileBuilder) readMapping() {
        }
 }
 
+var space = []byte(" ")
+var newline = []byte("\n")
+
 func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file, buildID string)) {
        // $ cat /proc/self/maps
        // 00400000-0040b000 r-xp 00000000 fc:01 787766                             /bin/cat
@@ -607,37 +611,24 @@ func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file,
        // next removes and returns the next field in the line.
        // It also removes from line any spaces following the field.
        next := func() []byte {
-               j := bytes.IndexByte(line, ' ')
-               if j < 0 {
-                       f := line
-                       line = nil
-                       return f
-               }
-               f := line[:j]
-               line = line[j+1:]
-               for len(line) > 0 && line[0] == ' ' {
-                       line = line[1:]
-               }
+               var f []byte
+               f, line, _ = bytes.Cut(line, space)
+               line = bytes.TrimLeft(line, " ")
                return f
        }
 
        for len(data) > 0 {
-               i := bytes.IndexByte(data, '\n')
-               if i < 0 {
-                       line, data = data, nil
-               } else {
-                       line, data = data[:i], data[i+1:]
-               }
+               line, data, _ = bytes.Cut(data, newline)
                addr := next()
-               i = bytes.IndexByte(addr, '-')
-               if i < 0 {
+               loStr, hiStr, ok := strings.Cut(string(addr), "-")
+               if !ok {
                        continue
                }
-               lo, err := strconv.ParseUint(string(addr[:i]), 16, 64)
+               lo, err := strconv.ParseUint(loStr, 16, 64)
                if err != nil {
                        continue
                }
-               hi, err := strconv.ParseUint(string(addr[i+1:]), 16, 64)
+               hi, err := strconv.ParseUint(hiStr, 16, 64)
                if err != nil {
                        continue
                }
index d052b9fa421d699c660020b62a4764119e873e15..4a9749a83f2e85633adbd19dc6eff74b7cfaffce 100644 (file)
@@ -274,11 +274,10 @@ func TestProcSelfMaps(t *testing.T) {
 
        f := func(t *testing.T, input string) {
                for tx, tt := range strings.Split(input, "\n\n") {
-                       i := strings.Index(tt, "->\n")
-                       if i < 0 {
+                       in, out, ok := strings.Cut(tt, "->\n")
+                       if !ok {
                                t.Fatal("malformed test case")
                        }
-                       in, out := tt[:i], tt[i+len("->\n"):]
                        if len(out) > 0 && out[len(out)-1] != '\n' {
                                out += "\n"
                        }
diff --git a/src/runtime/pprof/rusage_test.go b/src/runtime/pprof/rusage_test.go
new file mode 100644 (file)
index 0000000..b0d651e
--- /dev/null
@@ -0,0 +1,39 @@
+// 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.
+
+//go:build darwin || freebsd || linux || netbsd || openbsd
+
+package pprof
+
+import (
+       "syscall"
+       "time"
+)
+
+func init() {
+       diffCPUTimeImpl = diffCPUTimeRUsage
+}
+
+func diffCPUTimeRUsage(f func()) time.Duration {
+       ok := true
+       var before, after syscall.Rusage
+
+       err := syscall.Getrusage(syscall.RUSAGE_SELF, &before)
+       if err != nil {
+               ok = false
+       }
+
+       f()
+
+       err = syscall.Getrusage(syscall.RUSAGE_SELF, &after)
+       if err != nil {
+               ok = false
+       }
+
+       if !ok {
+               return 0
+       }
+
+       return time.Duration((after.Utime.Nano() + after.Stime.Nano()) - (before.Utime.Nano() + before.Stime.Nano()))
+}
index a38ab793986bd21ab13a8759f8ce5e52b21c7d2b..da24f5042c0707eb9e7611196904843e0c8177e7 100644 (file)
@@ -56,7 +56,6 @@ import (
        "internal/abi"
        "internal/goarch"
        "runtime/internal/atomic"
-       "unsafe"
 )
 
 type suspendGState struct {
@@ -399,18 +398,15 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) {
                return false, 0
        }
        up, startpc := pcdatavalue2(f, _PCDATA_UnsafePoint, pc)
-       if up != _PCDATA_UnsafePointSafe {
+       if up == _PCDATA_UnsafePointUnsafe {
                // Unsafe-point marked by compiler. This includes
                // atomic sequences (e.g., write barrier) and nosplit
                // functions (except at calls).
                return false, 0
        }
-       if fd := funcdata(f, _FUNCDATA_LocalsPointerMaps); fd == nil || fd == unsafe.Pointer(&no_pointers_stackmap) {
-               // This is assembly code. Don't assume it's
-               // well-formed. We identify assembly code by
-               // checking that it has either no stack map, or
-               // no_pointers_stackmap, which is the stack map
-               // for ones marked as NO_LOCAL_POINTERS.
+       if fd := funcdata(f, _FUNCDATA_LocalsPointerMaps); fd == nil || f.flag&funcFlag_ASM != 0 {
+               // This is assembly code. Don't assume it's well-formed.
+               // TODO: Empirically we still need the fd == nil check. Why?
                //
                // TODO: Are there cases that are safe but don't have a
                // locals pointer map, like empty frame functions?
@@ -451,9 +447,7 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) {
                return true, startpc
        case _PCDATA_RestartAtEntry:
                // Restart from the function entry at resumption.
-               return true, f.entry
+               return true, f.entry()
        }
        return true, pc
 }
-
-var no_pointers_stackmap uint64 // defined in assembly, for NO_LOCAL_POINTERS macro
index c3a5fa1f361cfb28c653c27c2f764b54031c7aaf..d57bc3d37c061e17d6f5fed474d3005057ad8851 100644 (file)
@@ -14,8 +14,7 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
        MOVL BP, 16(SP)
        MOVL SI, 20(SP)
        MOVL DI, 24(SP)
-       CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE nosse
+       #ifndef GO386_softfloat
        MOVUPS X0, 28(SP)
        MOVUPS X1, 44(SP)
        MOVUPS X2, 60(SP)
@@ -24,10 +23,9 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
        MOVUPS X5, 108(SP)
        MOVUPS X6, 124(SP)
        MOVUPS X7, 140(SP)
-nosse:
+       #endif
        CALL ·asyncPreempt2(SB)
-       CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
-       JNE nosse2
+       #ifndef GO386_softfloat
        MOVUPS 140(SP), X7
        MOVUPS 124(SP), X6
        MOVUPS 108(SP), X5
@@ -36,7 +34,7 @@ nosse:
        MOVUPS 60(SP), X2
        MOVUPS 44(SP), X1
        MOVUPS 28(SP), X0
-nosse2:
+       #endif
        MOVL 24(SP), DI
        MOVL 20(SP), SI
        MOVL 16(SP), BP
index 365e86a611a4daa8c56ff827b7ceed5c2ce5887e..d6a2408cb7cd2edb30f6df876abf60c8fd0e523e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows
-// +build !windows
 
 package runtime
 
index eb68dcba2b96d137171d58c0a9b36b7f433fa387..56df6c30e07e44b8a95321c2c11b18314d01b65c 100644 (file)
 #include "textflag.h"
 
 TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
-       MOV X1, -472(X2)
-       ADD $-472, X2
-       MOV X3, 8(X2)
-       MOV X5, 16(X2)
-       MOV X6, 24(X2)
-       MOV X7, 32(X2)
-       MOV X8, 40(X2)
-       MOV X9, 48(X2)
-       MOV X10, 56(X2)
-       MOV X11, 64(X2)
-       MOV X12, 72(X2)
-       MOV X13, 80(X2)
-       MOV X14, 88(X2)
-       MOV X15, 96(X2)
-       MOV X16, 104(X2)
-       MOV X17, 112(X2)
-       MOV X18, 120(X2)
-       MOV X19, 128(X2)
-       MOV X20, 136(X2)
-       MOV X21, 144(X2)
-       MOV X22, 152(X2)
-       MOV X23, 160(X2)
-       MOV X24, 168(X2)
-       MOV X25, 176(X2)
-       MOV X26, 184(X2)
-       MOV X28, 192(X2)
-       MOV X29, 200(X2)
-       MOV X30, 208(X2)
-       MOVD F0, 216(X2)
-       MOVD F1, 224(X2)
-       MOVD F2, 232(X2)
-       MOVD F3, 240(X2)
-       MOVD F4, 248(X2)
-       MOVD F5, 256(X2)
-       MOVD F6, 264(X2)
-       MOVD F7, 272(X2)
-       MOVD F8, 280(X2)
-       MOVD F9, 288(X2)
-       MOVD F10, 296(X2)
-       MOVD F11, 304(X2)
-       MOVD F12, 312(X2)
-       MOVD F13, 320(X2)
-       MOVD F14, 328(X2)
-       MOVD F15, 336(X2)
-       MOVD F16, 344(X2)
-       MOVD F17, 352(X2)
-       MOVD F18, 360(X2)
-       MOVD F19, 368(X2)
-       MOVD F20, 376(X2)
-       MOVD F21, 384(X2)
-       MOVD F22, 392(X2)
-       MOVD F23, 400(X2)
-       MOVD F24, 408(X2)
-       MOVD F25, 416(X2)
-       MOVD F26, 424(X2)
-       MOVD F27, 432(X2)
-       MOVD F28, 440(X2)
-       MOVD F29, 448(X2)
-       MOVD F30, 456(X2)
-       MOVD F31, 464(X2)
+       MOV X1, -464(X2)
+       ADD $-464, X2
+       MOV X5, 8(X2)
+       MOV X6, 16(X2)
+       MOV X7, 24(X2)
+       MOV X8, 32(X2)
+       MOV X9, 40(X2)
+       MOV X10, 48(X2)
+       MOV X11, 56(X2)
+       MOV X12, 64(X2)
+       MOV X13, 72(X2)
+       MOV X14, 80(X2)
+       MOV X15, 88(X2)
+       MOV X16, 96(X2)
+       MOV X17, 104(X2)
+       MOV X18, 112(X2)
+       MOV X19, 120(X2)
+       MOV X20, 128(X2)
+       MOV X21, 136(X2)
+       MOV X22, 144(X2)
+       MOV X23, 152(X2)
+       MOV X24, 160(X2)
+       MOV X25, 168(X2)
+       MOV X26, 176(X2)
+       MOV X28, 184(X2)
+       MOV X29, 192(X2)
+       MOV X30, 200(X2)
+       MOVD F0, 208(X2)
+       MOVD F1, 216(X2)
+       MOVD F2, 224(X2)
+       MOVD F3, 232(X2)
+       MOVD F4, 240(X2)
+       MOVD F5, 248(X2)
+       MOVD F6, 256(X2)
+       MOVD F7, 264(X2)
+       MOVD F8, 272(X2)
+       MOVD F9, 280(X2)
+       MOVD F10, 288(X2)
+       MOVD F11, 296(X2)
+       MOVD F12, 304(X2)
+       MOVD F13, 312(X2)
+       MOVD F14, 320(X2)
+       MOVD F15, 328(X2)
+       MOVD F16, 336(X2)
+       MOVD F17, 344(X2)
+       MOVD F18, 352(X2)
+       MOVD F19, 360(X2)
+       MOVD F20, 368(X2)
+       MOVD F21, 376(X2)
+       MOVD F22, 384(X2)
+       MOVD F23, 392(X2)
+       MOVD F24, 400(X2)
+       MOVD F25, 408(X2)
+       MOVD F26, 416(X2)
+       MOVD F27, 424(X2)
+       MOVD F28, 432(X2)
+       MOVD F29, 440(X2)
+       MOVD F30, 448(X2)
+       MOVD F31, 456(X2)
        CALL ·asyncPreempt2(SB)
-       MOVD 464(X2), F31
-       MOVD 456(X2), F30
-       MOVD 448(X2), F29
-       MOVD 440(X2), F28
-       MOVD 432(X2), F27
-       MOVD 424(X2), F26
-       MOVD 416(X2), F25
-       MOVD 408(X2), F24
-       MOVD 400(X2), F23
-       MOVD 392(X2), F22
-       MOVD 384(X2), F21
-       MOVD 376(X2), F20
-       MOVD 368(X2), F19
-       MOVD 360(X2), F18
-       MOVD 352(X2), F17
-       MOVD 344(X2), F16
-       MOVD 336(X2), F15
-       MOVD 328(X2), F14
-       MOVD 320(X2), F13
-       MOVD 312(X2), F12
-       MOVD 304(X2), F11
-       MOVD 296(X2), F10
-       MOVD 288(X2), F9
-       MOVD 280(X2), F8
-       MOVD 272(X2), F7
-       MOVD 264(X2), F6
-       MOVD 256(X2), F5
-       MOVD 248(X2), F4
-       MOVD 240(X2), F3
-       MOVD 232(X2), F2
-       MOVD 224(X2), F1
-       MOVD 216(X2), F0
-       MOV 208(X2), X30
-       MOV 200(X2), X29
-       MOV 192(X2), X28
-       MOV 184(X2), X26
-       MOV 176(X2), X25
-       MOV 168(X2), X24
-       MOV 160(X2), X23
-       MOV 152(X2), X22
-       MOV 144(X2), X21
-       MOV 136(X2), X20
-       MOV 128(X2), X19
-       MOV 120(X2), X18
-       MOV 112(X2), X17
-       MOV 104(X2), X16
-       MOV 96(X2), X15
-       MOV 88(X2), X14
-       MOV 80(X2), X13
-       MOV 72(X2), X12
-       MOV 64(X2), X11
-       MOV 56(X2), X10
-       MOV 48(X2), X9
-       MOV 40(X2), X8
-       MOV 32(X2), X7
-       MOV 24(X2), X6
-       MOV 16(X2), X5
-       MOV 8(X2), X3
-       MOV 472(X2), X1
+       MOVD 456(X2), F31
+       MOVD 448(X2), F30
+       MOVD 440(X2), F29
+       MOVD 432(X2), F28
+       MOVD 424(X2), F27
+       MOVD 416(X2), F26
+       MOVD 408(X2), F25
+       MOVD 400(X2), F24
+       MOVD 392(X2), F23
+       MOVD 384(X2), F22
+       MOVD 376(X2), F21
+       MOVD 368(X2), F20
+       MOVD 360(X2), F19
+       MOVD 352(X2), F18
+       MOVD 344(X2), F17
+       MOVD 336(X2), F16
+       MOVD 328(X2), F15
+       MOVD 320(X2), F14
+       MOVD 312(X2), F13
+       MOVD 304(X2), F12
+       MOVD 296(X2), F11
+       MOVD 288(X2), F10
+       MOVD 280(X2), F9
+       MOVD 272(X2), F8
+       MOVD 264(X2), F7
+       MOVD 256(X2), F6
+       MOVD 248(X2), F5
+       MOVD 240(X2), F4
+       MOVD 232(X2), F3
+       MOVD 224(X2), F2
+       MOVD 216(X2), F1
+       MOVD 208(X2), F0
+       MOV 200(X2), X30
+       MOV 192(X2), X29
+       MOV 184(X2), X28
+       MOV 176(X2), X26
+       MOV 168(X2), X25
+       MOV 160(X2), X24
+       MOV 152(X2), X23
+       MOV 144(X2), X22
+       MOV 136(X2), X21
+       MOV 128(X2), X20
+       MOV 120(X2), X19
+       MOV 112(X2), X18
+       MOV 104(X2), X17
+       MOV 96(X2), X16
+       MOV 88(X2), X15
+       MOV 80(X2), X14
+       MOV 72(X2), X13
+       MOV 64(X2), X12
+       MOV 56(X2), X11
+       MOV 48(X2), X10
+       MOV 40(X2), X9
+       MOV 32(X2), X8
+       MOV 24(X2), X7
+       MOV 16(X2), X6
+       MOV 8(X2), X5
+       MOV 464(X2), X1
        MOV (X2), X31
-       ADD $480, X2
+       ADD $472, X2
        JMP (X31)
index 59a91203b9ff9cad9e665833d5a8e362bda68f5b..b2a642bb862f00a049757bb5d2cbf0616f9fd255 100644 (file)
@@ -293,7 +293,7 @@ func hexdumpWords(p, end uintptr, mark func(uintptr) byte) {
                // Can we symbolize val?
                fn := findfunc(val)
                if fn.valid() {
-                       print("<", funcname(fn), "+", hex(val-fn.entry), "> ")
+                       print("<", funcname(fn), "+", hex(val-fn.entry()), "> ")
                }
        }
        minhexdigits = 0
index cde1a115830faacba3c71ba2c75184849457feb1..bf5fa8e4fc267ee336073433dd2c755c5b996d90 100644 (file)
@@ -622,13 +622,18 @@ func cpuinit() {
 
        // Support cpu feature variables are used in code generated by the compiler
        // to guard execution of instructions that can not be assumed to be always supported.
-       x86HasPOPCNT = cpu.X86.HasPOPCNT
-       x86HasSSE41 = cpu.X86.HasSSE41
-       x86HasFMA = cpu.X86.HasFMA
+       switch GOARCH {
+       case "386", "amd64":
+               x86HasPOPCNT = cpu.X86.HasPOPCNT
+               x86HasSSE41 = cpu.X86.HasSSE41
+               x86HasFMA = cpu.X86.HasFMA
 
-       armHasVFPv4 = cpu.ARM.HasVFPv4
+       case "arm":
+               armHasVFPv4 = cpu.ARM.HasVFPv4
 
-       arm64HasATOMICS = cpu.ARM64.HasATOMICS
+       case "arm64":
+               arm64HasATOMICS = cpu.ARM64.HasATOMICS
+       }
 }
 
 // The bootstrap sequence is:
@@ -675,13 +680,14 @@ func schedinit() {
        moduledataverify()
        stackinit()
        mallocinit()
+       cpuinit()      // must run before alginit
+       alginit()      // maps, hash, fastrand must not be used before this call
        fastrandinit() // must run before mcommoninit
        mcommoninit(_g_.m, -1)
-       cpuinit()       // must run before alginit
-       alginit()       // maps must not be used before this call
        modulesinit()   // provides activeModules
        typelinksinit() // uses maps, activeModules
        itabsinit()     // uses activeModules
+       stkobjinit()    // must run before GC starts
 
        sigsave(&_g_.m.sigmask)
        initSigmask = _g_.m.sigmask
@@ -782,11 +788,8 @@ func mcommoninit(mp *m, id int64) {
                mp.id = mReserveID()
        }
 
-       mp.fastrand[0] = uint32(int64Hash(uint64(mp.id), fastrandseed))
-       mp.fastrand[1] = uint32(int64Hash(uint64(cputicks()), ^fastrandseed))
-       if mp.fastrand[0]|mp.fastrand[1] == 0 {
-               mp.fastrand[1] = 1
-       }
+       // cputicks is not very random in startup virtual machine
+       mp.fastrand = uint64(int64Hash(uint64(mp.id), fastrandseed^uintptr(cputicks())))
 
        mpreinit(mp)
        if mp.gsignal != nil {
@@ -2230,6 +2233,9 @@ func newm1(mp *m) {
                if msanenabled {
                        msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
                }
+               if asanenabled {
+                       asanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
+               }
                execLock.rlock() // Prevent process clone.
                asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
                execLock.runlock()
@@ -3620,8 +3626,10 @@ func goexit1() {
 // goexit continuation on g0.
 func goexit0(gp *g) {
        _g_ := getg()
+       _p_ := _g_.m.p.ptr()
 
        casgstatus(gp, _Grunning, _Gdead)
+       gcController.addScannableStack(_p_, -int64(gp.stack.hi-gp.stack.lo))
        if isSystemGoroutine(gp, false) {
                atomic.Xadd(&sched.ngsys, -1)
        }
@@ -3643,7 +3651,7 @@ func goexit0(gp *g) {
                // Flush assist credit to the global pool. This gives
                // better information to pacing if the application is
                // rapidly creating an exiting goroutines.
-               assistWorkPerByte := float64frombits(atomic.Load64(&gcController.assistWorkPerByte))
+               assistWorkPerByte := gcController.assistWorkPerByte.Load()
                scanCredit := int64(assistWorkPerByte * float64(gp.gcAssistBytes))
                atomic.Xaddint64(&gcController.bgScanCredit, scanCredit)
                gp.gcAssistBytes = 0
@@ -3652,7 +3660,7 @@ func goexit0(gp *g) {
        dropg()
 
        if GOARCH == "wasm" { // no threads yet on wasm
-               gfput(_g_.m.p.ptr(), gp)
+               gfput(_p_, gp)
                schedule() // never returns
        }
 
@@ -3660,7 +3668,7 @@ func goexit0(gp *g) {
                print("invalid m->lockedInt = ", _g_.m.lockedInt, "\n")
                throw("internal lockOSThread error")
        }
-       gfput(_g_.m.p.ptr(), gp)
+       gfput(_p_, gp)
        if locked {
                // The goroutine may have locked this thread because
                // it put it in an unusual kernel state. Kill it
@@ -4289,6 +4297,7 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g {
                newg.tracking = true
        }
        casgstatus(newg, _Gdead, _Grunnable)
+       gcController.addScannableStack(_p_, int64(newg.stack.hi-newg.stack.lo))
 
        if _p_.goidcache == _p_.goidcacheend {
                // Sched.goidgen is the last allocated id,
@@ -4429,6 +4438,9 @@ retry:
                if msanenabled {
                        msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
                }
+               if asanenabled {
+                       asanunpoison(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
+               }
        }
        return gp
 }
@@ -4642,6 +4654,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
        getg().m.mallocing++
 
        var stk [maxCPUProfStack]uintptr
+       flags := uint(_TraceJumpStack)
        n := 0
        if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
                cgoOff := 0
@@ -4659,12 +4672,12 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
                }
 
                // Collect Go stack that leads to the cgo call.
-               n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[cgoOff], len(stk)-cgoOff, nil, nil, 0)
+               n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[cgoOff], len(stk)-cgoOff, nil, nil, flags)
                if n > 0 {
                        n += cgoOff
                }
        } else {
-               n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|_TraceJumpStack)
+               n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|flags)
        }
 
        if n <= 0 {
@@ -4674,10 +4687,10 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
                if usesLibcall() && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
                        // Libcall, i.e. runtime syscall on windows.
                        // Collect Go stack that leads to the call.
-                       n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, 0)
+                       n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, flags)
                }
                if n == 0 && mp != nil && mp.vdsoSP != 0 {
-                       n = gentraceback(mp.vdsoPC, mp.vdsoSP, 0, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|_TraceJumpStack)
+                       n = gentraceback(mp.vdsoPC, mp.vdsoSP, 0, gp, 0, &stk[0], len(stk), nil, nil, flags)
                }
                if n == 0 {
                        // If all of the above has failed, account it against abstract "System" or "GC".
@@ -4703,45 +4716,6 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
        getg().m.mallocing--
 }
 
-// If the signal handler receives a SIGPROF signal on a non-Go thread,
-// it tries to collect a traceback into sigprofCallers.
-// sigprofCallersUse is set to non-zero while sigprofCallers holds a traceback.
-var sigprofCallers cgoCallers
-var sigprofCallersUse uint32
-
-// sigprofNonGo is called if we receive a SIGPROF signal on a non-Go thread,
-// and the signal handler collected a stack trace in sigprofCallers.
-// When this is called, sigprofCallersUse will be non-zero.
-// g is nil, and what we can do is very limited.
-//go:nosplit
-//go:nowritebarrierrec
-func sigprofNonGo() {
-       if prof.hz != 0 {
-               n := 0
-               for n < len(sigprofCallers) && sigprofCallers[n] != 0 {
-                       n++
-               }
-               cpuprof.addNonGo(sigprofCallers[:n])
-       }
-
-       atomic.Store(&sigprofCallersUse, 0)
-}
-
-// sigprofNonGoPC is called when a profiling signal arrived on a
-// non-Go thread and we have a single PC value, not a stack trace.
-// g is nil, and what we can do is very limited.
-//go:nosplit
-//go:nowritebarrierrec
-func sigprofNonGoPC(pc uintptr) {
-       if prof.hz != 0 {
-               stk := []uintptr{
-                       pc,
-                       abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum,
-               }
-               cpuprof.addNonGo(stk)
-       }
-}
-
 // setcpuprofilerate sets the CPU profiling rate to hz times per second.
 // If hz <= 0, setcpuprofilerate turns off CPU profiling.
 func setcpuprofilerate(hz int32) {
@@ -5229,6 +5203,10 @@ func checkdead() {
 // This is a variable for testing purposes. It normally doesn't change.
 var forcegcperiod int64 = 2 * 60 * 1e9
 
+// needSysmonWorkaround is true if the workaround for
+// golang.org/issue/42515 is needed on NetBSD.
+var needSysmonWorkaround bool = false
+
 // Always runs without a P, so write barriers are not allowed.
 //
 //go:nowritebarrierrec
@@ -5337,7 +5315,7 @@ func sysmon() {
                        }
                }
                mDoFixup()
-               if GOOS == "netbsd" {
+               if GOOS == "netbsd" && needSysmonWorkaround {
                        // netpoll is responsible for waiting for timer
                        // expiration, so we typically don't have to worry
                        // about starting an M to service timers. (Note that
@@ -5872,7 +5850,7 @@ const randomizeScheduler = raceenabled
 // If the run queue is full, runnext puts g on the global queue.
 // Executed only by the owner P.
 func runqput(_p_ *p, gp *g, next bool) {
-       if randomizeScheduler && next && fastrand()%2 == 0 {
+       if randomizeScheduler && next && fastrandn(2) == 0 {
                next = false
        }
 
@@ -5985,14 +5963,12 @@ func runqputbatch(pp *p, q *gQueue, qsize int) {
 // Executed only by the owner P.
 func runqget(_p_ *p) (gp *g, inheritTime bool) {
        // If there's a runnext, it's the next G to run.
-       for {
-               next := _p_.runnext
-               if next == 0 {
-                       break
-               }
-               if _p_.runnext.cas(next, 0) {
-                       return next.ptr(), true
-               }
+       next := _p_.runnext
+       // If the runnext is non-0 and the CAS fails, it could only have been stolen by another P,
+       // because other Ps can race to set runnext to 0, but only the current P can set it to non-0.
+       // Hence, there's no need to retry this CAS if it falls.
+       if next != 0 && _p_.runnext.cas(next, 0) {
+               return next.ptr(), true
        }
 
        for {
@@ -6157,7 +6133,7 @@ func (q *gQueue) pushBack(gp *g) {
        q.tail.set(gp)
 }
 
-// pushBackAll adds all Gs in l2 to the tail of q. After this q2 must
+// pushBackAll adds all Gs in q2 to the tail of q. After this q2 must
 // not be used.
 func (q *gQueue) pushBackAll(q2 gQueue) {
        if q2.tail == 0 {
index 7eaa9d2b721dbdb08093ae7f2631bff4b7c71e4d..e019923bb5c67109f0fad3f6d0bd6dd219d50426 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race
-// +build race
 
 package runtime
 
index 63fcd847dc7e6c3100e62270f5d6b54cc424b669..46cdfcd0e98b65d7825ccbfd46fdba46fc58083f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race
-// +build race
 
 package race_test
 
index 84050e877111818583a9ac4d074989418a7ef2a5..63fa83ff146c922e78a1b8a9e71e7c31c7e6cdf1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (race && linux && amd64) || (race && freebsd && amd64) || (race && netbsd && amd64) || (race && darwin && amd64) || (race && windows && amd64) || (race && linux && ppc64le) || (race && linux && arm64) || (race && darwin && arm64) || (race && openbsd && amd64)
-// +build race,linux,amd64 race,freebsd,amd64 race,netbsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le race,linux,arm64 race,darwin,arm64 race,openbsd,amd64
 
 package race
 
index 9c0d48d6bda6c589cb6961f70f7b11704ac0c591..e8a2d0fd8c91c44e0c9b3aa100b97280e21a02e8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && race
-// +build linux,race
 
 package race_test
 
index 8c880b857007a1157a66131fa07dadd8d943e694..1677e139865cddeba725e538a9cf236694625919 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race
-// +build race
 
 // This program is used to verify the race detector
 // by running the tests and parsing their output.
index acd6e47f9827645b6b82d56694382f9bf33e621b..6cc0730589f33b37aa6a00699237d2df635f3a4b 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race && (darwin || freebsd || linux)
-// +build race
-// +build darwin freebsd linux
 
 package race_test
 
index e490d766dd05ddb91880abf05b0421a3fdc9f2d2..143b483f97f8903c3e76c38843c9730bbbd0ec67 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build windows && race
-// +build windows,race
 
 package race_test
 
index e904ebd20d8c1c699407e374404acaff217aedb2..9fe83ea11d35e5acb03aa199f9e62e9e57179a82 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race
-// +build race
 
 package race_test
 
index f5095737a4f632e97770c953094c3ac4ae17f236..2f1a91cab1d9c12b5d7b02481f77b1e512217c2c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race
-// +build race
 
 package race
 
index f11f8456a0fd4a95ae6417ac813fba6c112ca03e..dd59005564273abc0749742c99bd3bdb8151d495 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build race
-// +build race
 
 package race_test
 
index 0e431b8103e060323b4080a096aa59451335cf28..f36d4387c74fe2bd46178982f00d4fe9ab322df6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !race
-// +build !race
 
 // Dummy race detection API, used when not built with -race.
 
index 963e57099c9c4c3b0ca283fe6172b79a5e00cc7b..625c81a255bcc148b397ad4623e1b52ca4bbb073 100644 (file)
 
 // func runtime·RaceRead(addr uintptr)
 // Called from instrumented Go code
-TEXT   runtime·raceread(SB), NOSPLIT, $0-8
+TEXT   runtime·raceread<ABIInternal>(SB), NOSPLIT, $0-8
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    addr+0(FP), R4
+#else
+       MOVD    R3, R4
+#endif
        MOVD    LR, R5 // caller of this?
        // void __tsan_read(ThreadState *thr, void *addr, void *pc);
        MOVD    $__tsan_read(SB), R8
@@ -64,8 +68,12 @@ TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
 
 // func runtime·RaceWrite(addr uintptr)
 // Called from instrumented Go code
-TEXT   runtime·racewrite(SB), NOSPLIT, $0-8
+TEXT   runtime·racewrite<ABIInternal>(SB), NOSPLIT, $0-8
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    addr+0(FP), R4
+#else
+       MOVD    R3, R4
+#endif
        MOVD    LR, R5 // caller has set LR via BL inst
        // void __tsan_write(ThreadState *thr, void *addr, void *pc);
        MOVD    $__tsan_write(SB), R8
@@ -85,9 +93,14 @@ TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
 
 // func runtime·RaceReadRange(addr, size uintptr)
 // Called from instrumented Go code.
-TEXT   runtime·racereadrange(SB), NOSPLIT, $0-16
+TEXT   runtime·racereadrange<ABIInternal>(SB), NOSPLIT, $0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    addr+0(FP), R4
        MOVD    size+8(FP), R5
+#else
+       MOVD    R4, R5
+       MOVD    R3, R4
+#endif
        MOVD    LR, R6
        // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
        MOVD    $__tsan_read_range(SB), R8
@@ -108,9 +121,14 @@ TEXT    runtime·RaceReadRange(SB), NOSPLIT, $0-16
 
 // func runtime·RaceWriteRange(addr, size uintptr)
 // Called from instrumented Go code.
-TEXT   runtime·racewriterange(SB), NOSPLIT, $0-16
+TEXT   runtime·racewriterange<ABIInternal>(SB), NOSPLIT, $0-16
+#ifndef GOEXPERIMENT_regabiargs
        MOVD    addr+0(FP), R4
        MOVD    size+8(FP), R5
+#else
+       MOVD    R4, R5
+       MOVD    R3, R4
+#endif
        MOVD    LR, R6
        // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
        MOVD    $__tsan_write_range(SB), R8
index 5b92879c20bc5ce3dba3b9063349c527e235bbc2..e507702fc10e83a94b4205b6540ebd3b699cfb3e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !windows
-// +build !windows
 
 package runtime
 
index f31f7f75e5153e3645fc2f85df6ad48fd6ab0c6d..d6b8ac85dca6468065b71d11e831fca5c1722356 100644 (file)
@@ -9,6 +9,104 @@ TEXT _rt0_riscv64_linux(SB),NOSPLIT|NOFRAME,$0
        ADD     $8, X2, A1      // argv
        JMP     main(SB)
 
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_riscv64_linux_lib(SB),NOSPLIT,$224
+       // Preserve callee-save registers, along with X1 (LR).
+       MOV     X1, (8*3)(X2)
+       MOV     X8, (8*4)(X2)
+       MOV     X9, (8*5)(X2)
+       MOV     X18, (8*6)(X2)
+       MOV     X19, (8*7)(X2)
+       MOV     X20, (8*8)(X2)
+       MOV     X21, (8*9)(X2)
+       MOV     X22, (8*10)(X2)
+       MOV     X23, (8*11)(X2)
+       MOV     X24, (8*12)(X2)
+       MOV     X25, (8*13)(X2)
+       MOV     X26, (8*14)(X2)
+       MOV     g, (8*15)(X2)
+       MOVD    F8, (8*16)(X2)
+       MOVD    F9, (8*17)(X2)
+       MOVD    F18, (8*18)(X2)
+       MOVD    F19, (8*19)(X2)
+       MOVD    F20, (8*20)(X2)
+       MOVD    F21, (8*21)(X2)
+       MOVD    F22, (8*22)(X2)
+       MOVD    F23, (8*23)(X2)
+       MOVD    F24, (8*24)(X2)
+       MOVD    F25, (8*25)(X2)
+       MOVD    F26, (8*26)(X2)
+       MOVD    F27, (8*27)(X2)
+
+       // Initialize g as nil in case of using g later e.g. sigaction in cgo_sigaction.go
+       MOV     X0, g
+
+       MOV     A0, _rt0_riscv64_linux_lib_argc<>(SB)
+       MOV     A1, _rt0_riscv64_linux_lib_argv<>(SB)
+
+       // Synchronous initialization.
+       MOV     $runtime·libpreinit(SB), T0
+       JALR    RA, T0
+
+       // Create a new thread to do the runtime initialization and return.
+       MOV     _cgo_sys_thread_create(SB), T0
+       BEQZ    T0, nocgo
+       MOV     $_rt0_riscv64_linux_lib_go(SB), A0
+       MOV     $0, A1
+       JALR    RA, T0
+       JMP     restore
+
+nocgo:
+       MOV     $0x800000, A0                     // stacksize = 8192KB
+       MOV     $_rt0_riscv64_linux_lib_go(SB), A1
+       MOV     A0, 8(X2)
+       MOV     A1, 16(X2)
+       MOV     $runtime·newosproc0(SB), T0
+       JALR    RA, T0
+
+restore:
+       // Restore callee-save registers, along with X1 (LR).
+       MOV     (8*3)(X2), X1
+       MOV     (8*4)(X2), X8
+       MOV     (8*5)(X2), X9
+       MOV     (8*6)(X2), X18
+       MOV     (8*7)(X2), X19
+       MOV     (8*8)(X2), X20
+       MOV     (8*9)(X2), X21
+       MOV     (8*10)(X2), X22
+       MOV     (8*11)(X2), X23
+       MOV     (8*12)(X2), X24
+       MOV     (8*13)(X2), X25
+       MOV     (8*14)(X2), X26
+       MOV     (8*15)(X2), g
+       MOVD    (8*16)(X2), F8
+       MOVD    (8*17)(X2), F9
+       MOVD    (8*18)(X2), F18
+       MOVD    (8*19)(X2), F19
+       MOVD    (8*20)(X2), F20
+       MOVD    (8*21)(X2), F21
+       MOVD    (8*22)(X2), F22
+       MOVD    (8*23)(X2), F23
+       MOVD    (8*24)(X2), F24
+       MOVD    (8*25)(X2), F25
+       MOVD    (8*26)(X2), F26
+       MOVD    (8*27)(X2), F27
+
+       RET
+
+TEXT _rt0_riscv64_linux_lib_go(SB),NOSPLIT,$0
+       MOV     _rt0_riscv64_linux_lib_argc<>(SB), A0
+       MOV     _rt0_riscv64_linux_lib_argv<>(SB), A1
+       MOV     $runtime·rt0_go(SB), T0
+       JALR    ZERO, T0
+
+DATA _rt0_riscv64_linux_lib_argc<>(SB)/8, $0
+GLOBL _rt0_riscv64_linux_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_riscv64_linux_lib_argv<>(SB)/8, $0
+GLOBL _rt0_riscv64_linux_lib_argv<>(SB),NOPTR, $8
+
+
 TEXT main(SB),NOSPLIT|NOFRAME,$0
        MOV     $runtime·rt0_go(SB), T0
        JALR    ZERO, T0
index 8d96dfb6094ae077734592528db84afcc36d1feb..5bb605cc37b567abfd90457b24be15718fb27b6a 100644 (file)
@@ -219,6 +219,9 @@ class ChanTypePrinter:
                        yield ('[{0}]'.format(i), (ptr + j).dereference())
 
 
+def paramtypematch(t, pattern):
+       return t.code == gdb.TYPE_CODE_TYPEDEF and str(t).startswith(".param") and pattern.match(str(t.target()))
+
 #
 #  Register all the *Printer classes above.
 #
@@ -228,6 +231,8 @@ def makematcher(klass):
                try:
                        if klass.pattern.match(str(val.type)):
                                return klass(val)
+                       elif paramtypematch(val.type, klass.pattern):
+                               return klass(val.cast(val.type.target()))
                except Exception:
                        pass
        return matcher
@@ -387,7 +392,7 @@ class GoLenFunc(gdb.Function):
        def invoke(self, obj):
                typename = str(obj.type)
                for klass, fld in self.how:
-                       if klass.pattern.match(typename):
+                       if klass.pattern.match(typename) or paramtypematch(obj.type, klass.pattern):
                                return obj[fld]
 
 
@@ -402,7 +407,7 @@ class GoCapFunc(gdb.Function):
        def invoke(self, obj):
                typename = str(obj.type)
                for klass, fld in self.how:
-                       if klass.pattern.match(typename):
+                       if klass.pattern.match(typename) or paramtypematch(obj.type, klass.pattern):
                                return obj[fld]
 
 
index 8c76a9123c69ef7ec7f57fe9beebfa8cdbc8631b..4a0f489c2f8b04de0f172f8a8372feda5a9556f4 100644 (file)
@@ -267,7 +267,7 @@ func testGdbPython(t *testing.T, cgo bool) {
                t.Fatalf("gdb exited with error: %v", err)
        }
 
-       firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
+       firstLine, _, _ := bytes.Cut(got, []byte("\n"))
        if string(firstLine) != "Loading Go Runtime support." {
                // This can happen when using all.bash with
                // GOROOT_FINAL set, because the tests are run before
index e4e9ee50b805eb7900abd4b0203decb8abe8c426..bfd857e8d5a2468be7de3d039dd13fe54b523ce1 100644 (file)
@@ -538,7 +538,7 @@ type m struct {
        printlock     int8
        incgo         bool   // m is executing a cgo call
        freeWait      uint32 // if == 0, safe to free g0 and delete m (atomic)
-       fastrand      [2]uint32
+       fastrand      uint64
        needextram    bool
        traceback     uint8
        ncgocall      uint64      // number of cgo calls in total
@@ -734,6 +734,12 @@ type p struct {
        // Race context used while executing timer functions.
        timerRaceCtx uintptr
 
+       // scannableStackSizeDelta accumulates the amount of stack space held by
+       // live goroutines (i.e. those eligible for stack scanning).
+       // Flushed to gcController.scannableStackSize once scannableStackSizeSlack
+       // or -scannableStackSizeSlack is reached.
+       scannableStackSizeDelta int64
+
        // preempt is set to indicate that this P should be enter the
        // scheduler ASAP (regardless of what G is running on it).
        preempt bool
@@ -858,8 +864,8 @@ const (
 // Keep in sync with linker (../cmd/link/internal/ld/pcln.go:/pclntab)
 // and with package debug/gosym and with symtab.go in package runtime.
 type _func struct {
-       entry   uintptr // start pc
-       nameoff int32   // function name
+       entryoff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
+       nameoff  int32  // function name
 
        args        int32  // in/out args size
        deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
@@ -879,8 +885,8 @@ type _func struct {
 // A *Func can be either a *_func or a *funcinl, and they are distinguished
 // by the first uintptr.
 type funcinl struct {
-       zero  uintptr // set to 0 to distinguish from _func
-       entry uintptr // entry of the real (the "outermost") frame.
+       ones  uint32  // set to ^0 to distinguish from _func
+       entry uintptr // entry of the real (the "outermost") frame
        name  string
        file  string
        line  int
@@ -1128,7 +1134,6 @@ var (
        // Set on startup in asm_{386,amd64}.s
        processorVersionInfo uint32
        isIntel              bool
-       lfenceBeforeRdtsc    bool
 
        goarm uint8 // set by cmd/link on arm systems
 )
index cd59368cb2af4311ee0bca69cd64aade889350f9..a753aeea583d66e549faa192421f9134d5febc20 100644 (file)
@@ -61,3 +61,14 @@ func TestEpollctlErrorSign(t *testing.T) {
                t.Errorf("epollctl = %v, want %v", v, -EBADF)
        }
 }
+
+func TestKernelStructSize(t *testing.T) {
+       // Check that the Go definitions of structures exchanged with the kernel are
+       // the same size as what the kernel defines.
+       if have, want := unsafe.Sizeof(Siginfo{}), uintptr(SiginfoMaxSize); have != want {
+               t.Errorf("Go's siginfo struct is %d bytes long; kernel expects %d", have, want)
+       }
+       if have, want := unsafe.Sizeof(Sigevent{}), uintptr(SigeventMaxSize); have != want {
+               t.Errorf("Go's sigevent struct is %d bytes long; kernel expects %d", have, want)
+       }
+}
index f71f8afa5746aeb115bf233a3d238de8ee61ec06..9323c093557da405d35b45b569210d64f749cd1f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime_test
 
index 0251c676e6df6b171c38752a4e2f9671a29bc2be..642a9462803a998d8ecaf13a8af46d0dce508b0c 100644 (file)
@@ -7,7 +7,6 @@
 // and Close(-1) is nearly universally fast.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || plan9
-// +build aix darwin dragonfly freebsd linux netbsd openbsd plan9
 
 package runtime_test
 
index ee1f95ffa9ed304fa82aaf562356ea6b10110eea..e18b2f14c08cc1b3b5bf838dca6899a3975cea00 100644 (file)
@@ -406,6 +406,13 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
                        msanwrite(cas.elem, c.elemtype.size)
                }
        }
+       if asanenabled {
+               if casi < nsends {
+                       asanread(cas.elem, c.elemtype.size)
+               } else if cas.elem != nil {
+                       asanwrite(cas.elem, c.elemtype.size)
+               }
+       }
 
        selunlock(scases, lockorder)
        goto retc
@@ -421,6 +428,9 @@ bufrecv:
        if msanenabled && cas.elem != nil {
                msanwrite(cas.elem, c.elemtype.size)
        }
+       if asanenabled && cas.elem != nil {
+               asanwrite(cas.elem, c.elemtype.size)
+       }
        recvOK = true
        qp = chanbuf(c, c.recvx)
        if cas.elem != nil {
@@ -444,6 +454,9 @@ bufsend:
        if msanenabled {
                msanread(cas.elem, c.elemtype.size)
        }
+       if asanenabled {
+               asanread(cas.elem, c.elemtype.size)
+       }
        typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
        c.sendx++
        if c.sendx == c.dataqsiz {
@@ -482,6 +495,9 @@ send:
        if msanenabled {
                msanread(cas.elem, c.elemtype.size)
        }
+       if asanenabled {
+               asanread(cas.elem, c.elemtype.size)
+       }
        send(c, sg, cas.elem, func() { selunlock(scases, lockorder) }, 2)
        if debugSelect {
                print("syncsend: cas0=", cas0, " c=", c, "\n")
index 905e932b7d857efb1643e9fc314b7693a1222a45..cf4ef1820849a425a6b066ce37888b98e123f17e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !plan9 && !windows && !js
-// +build !plan9,!windows,!js
 
 package runtime_test
 
index 30050efcc78a022bead6ffa9961a9b425a7fe29b..05f44f65dbcd5614499fd1a0e2393ffdb0bc213b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (linux && !amd64 && !arm64 && !ppc64le) || (freebsd && !amd64)
-// +build linux,!amd64,!arm64,!ppc64le freebsd,!amd64
 
 package runtime
 
index 69a59e6dcff2a9e60ce336a1513b9b4afac5d7b2..aa66032caa361a163cbb8d04eecf9f2c0c531ad3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package runtime
 
index 5999d9dc3d01d407d4999eaa191a2fff0ffbf79c..c6cb91a0a25731e06804ef9552f3d3219ae1852f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix
-// +build aix
 
 package runtime
 
index 20490cffbf5174f08503296fef6d36ac0606bbfd..67a21950d715b37f33a0924fc5dfcb43eb1b3652 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 && (darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris)
-// +build amd64
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime
 
index a0780788f809fc7a04fa7ca5d173cdea1325f89f..fff302f4d4b92b9cfac520b7660ea8c4a1a11ab3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package runtime
 
index 9d4a8b8a99d54e6516418b84e44d8d7908b0d9d5..771585a8f9b392e58c9dda4cd4968c2c8ebba60a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || freebsd || linux || netbsd || openbsd
-// +build darwin freebsd linux netbsd openbsd
 
 package runtime
 
index e62d6a93fd2fe9a0a1079ba9623560a138f251d8..9c2a286001660308f566c0fa72997df63df9197b 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips64 || mips64le)
-// +build linux
-// +build mips64 mips64le
 
 package runtime
 
index f3969c5aac4a7468fd275ca2ea6617c36a9664ce..f11bfc9b3a2c79072f6d57a8d5b84fd8e60fc1c4 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips || mipsle)
-// +build linux
-// +build mips mipsle
 
 package runtime
 
index d2eeb39eadd39c66a1b75576097e0c485f896fd7..31754289ece3674ec3d0dfd6c5ae3ec1d775a102 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (ppc64 || ppc64le)
-// +build linux
-// +build ppc64 ppc64le
 
 package runtime
 
index 87dfa724c4758e7c75b0b60fe21411288ecf4ea5..cee1bf7a1b23dcd1d566fe77138c9d343120c592 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (linux || openbsd) && (mips64 || mips64le)
-// +build linux openbsd
-// +build mips64 mips64le
 
 package runtime
 
index 5067799bd6bd75368eac70205db44a38b906849d..ba92655152e84b2dc791892d6da9228f8669e8f6 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips || mipsle)
-// +build linux
-// +build mips mipsle
 
 package runtime
 
index 8a39d59957695ce14af2624fb51cf3b2ef8f2d19..bdd354026cb0ad04c8eb61b78692cf4ed3d7a3c4 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (aix || linux) && (ppc64 || ppc64le)
-// +build aix linux
-// +build ppc64 ppc64le
 
 package runtime
 
index 8a24e4e36a9977f2c91ac982f0c6dc6a2ed693d3..5eeb227aa05862f92a801865e464f785f4d281f3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && riscv64
-// +build linux,riscv64
 
 package runtime
 
index 8117582855db02d55e1b874a4f71630427f8ed30..dbcbfc67bca3af97ba65e694faf66fd4b3941979 100644 (file)
@@ -3,13 +3,13 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package runtime
 
 import (
        "internal/abi"
        "runtime/internal/atomic"
+       "runtime/internal/sys"
        "unsafe"
 )
 
@@ -167,8 +167,8 @@ func sigInstallGoHandler(sig uint32) bool {
        }
 
        // When built using c-archive or c-shared, only install signal
-       // handlers for synchronous signals and SIGPIPE.
-       if (isarchive || islibrary) && t.flags&_SigPanic == 0 && sig != _SIGPIPE {
+       // handlers for synchronous signals and SIGPIPE and sigPreempt.
+       if (isarchive || islibrary) && t.flags&_SigPanic == 0 && sig != _SIGPIPE && sig != sigPreempt {
                return false
        }
 
@@ -263,11 +263,11 @@ func clearSignalHandlers() {
        }
 }
 
-// setProcessCPUProfiler is called when the profiling timer changes.
-// It is called with prof.lock held. hz is the new timer, and is 0 if
+// setProcessCPUProfilerTimer is called when the profiling timer changes.
+// It is called with prof.signalLock held. hz is the new timer, and is 0 if
 // profiling is being disabled. Enable or disable the signal as
 // required for -buildmode=c-archive.
-func setProcessCPUProfiler(hz int32) {
+func setProcessCPUProfilerTimer(hz int32) {
        if hz != 0 {
                // Enable the Go signal handler if not enabled.
                if atomic.Cas(&handlingSig[_SIGPROF], 0, 1) {
@@ -309,10 +309,10 @@ func setProcessCPUProfiler(hz int32) {
        }
 }
 
-// setThreadCPUProfiler makes any thread-specific changes required to
+// setThreadCPUProfilerHz makes any thread-specific changes required to
 // implement profiling at a rate of hz.
-// No changes required on Unix systems.
-func setThreadCPUProfiler(hz int32) {
+// No changes required on Unix systems when using setitimer.
+func setThreadCPUProfilerHz(hz int32) {
        getg().m.profilehz = hz
 }
 
@@ -383,7 +383,7 @@ func preemptM(mp *m) {
 //go:nosplit
 func sigFetchG(c *sigctxt) *g {
        switch GOARCH {
-       case "arm", "arm64", "ppc64", "ppc64le":
+       case "arm", "arm64", "ppc64", "ppc64le", "riscv64":
                if !iscgo && inVDSOPage(c.sigpc()) {
                        // When using cgo, we save the g on TLS and load it from there
                        // in sigtramp. Just use that.
@@ -423,7 +423,11 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
        setg(g)
        if g == nil {
                if sig == _SIGPROF {
-                       sigprofNonGoPC(c.sigpc())
+                       // Some platforms (Linux) have per-thread timers, which we use in
+                       // combination with the process-wide timer. Avoid double-counting.
+                       if validSIGPROF(nil, c) {
+                               sigprofNonGoPC(c.sigpc())
+                       }
                        return
                }
                if sig == sigPreempt && preemptMSupported && debug.asyncpreemptoff == 0 {
@@ -465,6 +469,56 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
        }
 }
 
+// If the signal handler receives a SIGPROF signal on a non-Go thread,
+// it tries to collect a traceback into sigprofCallers.
+// sigprofCallersUse is set to non-zero while sigprofCallers holds a traceback.
+var sigprofCallers cgoCallers
+var sigprofCallersUse uint32
+
+// sigprofNonGo is called if we receive a SIGPROF signal on a non-Go thread,
+// and the signal handler collected a stack trace in sigprofCallers.
+// When this is called, sigprofCallersUse will be non-zero.
+// g is nil, and what we can do is very limited.
+//
+// It is called from the signal handling functions written in assembly code that
+// are active for cgo programs, cgoSigtramp and sigprofNonGoWrapper, which have
+// not verified that the SIGPROF delivery corresponds to the best available
+// profiling source for this thread.
+//
+//go:nosplit
+//go:nowritebarrierrec
+func sigprofNonGo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+       if prof.hz != 0 {
+               c := &sigctxt{info, ctx}
+               // Some platforms (Linux) have per-thread timers, which we use in
+               // combination with the process-wide timer. Avoid double-counting.
+               if validSIGPROF(nil, c) {
+                       n := 0
+                       for n < len(sigprofCallers) && sigprofCallers[n] != 0 {
+                               n++
+                       }
+                       cpuprof.addNonGo(sigprofCallers[:n])
+               }
+       }
+
+       atomic.Store(&sigprofCallersUse, 0)
+}
+
+// sigprofNonGoPC is called when a profiling signal arrived on a
+// non-Go thread and we have a single PC value, not a stack trace.
+// g is nil, and what we can do is very limited.
+//go:nosplit
+//go:nowritebarrierrec
+func sigprofNonGoPC(pc uintptr) {
+       if prof.hz != 0 {
+               stk := []uintptr{
+                       pc,
+                       abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum,
+               }
+               cpuprof.addNonGo(stk)
+       }
+}
+
 // adjustSignalStack adjusts the current stack guard based on the
 // stack pointer that is actually in use while handling a signal.
 // We do this in case some non-Go code called sigaltstack.
@@ -540,7 +594,12 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
        c := &sigctxt{info, ctxt}
 
        if sig == _SIGPROF {
-               sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
+               mp := _g_.m
+               // Some platforms (Linux) have per-thread timers, which we use in
+               // combination with the process-wide timer. Avoid double-counting.
+               if validSIGPROF(mp, c) {
+                       sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, mp)
+               }
                return
        }
 
@@ -628,9 +687,11 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
        }
 
        print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
-       if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+       if _g_.m.incgo && gp == _g_.m.g0 && _g_.m.curg != nil {
                print("signal arrived during cgo execution\n")
-               gp = _g_.m.lockedg.ptr()
+               // Switch to curg so that we get a traceback of the Go code
+               // leading up to the cgocall, which switched from curg to g0.
+               gp = _g_.m.curg
        }
        if sig == _SIGILL || sig == _SIGFPE {
                // It would be nice to know how long the instruction is.
index 3fe352ef575bb780a2705292c905c5798390e1e1..b036f3c965bb894f2c9f3acc0892ccb610ac8bf6 100644 (file)
@@ -22,6 +22,38 @@ func disableWER() {
        stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
 }
 
+// isWin7 returns true on Windows 7. Otherwise it returns false.
+//
+//go:nosplit
+func isWin7() bool {
+       var maj, min, build uint32
+       stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build)))
+       return maj < 6 || (maj == 6 && min <= 1)
+}
+
+// enableWERNoUI re-enables Windows error reporting without fault reporting UI.
+//
+// This is marked nosplit since it is used during crash.
+//
+//go:nosplit
+func enableWERNoUI() bool {
+       if _WerSetFlags == nil {
+               return false
+       }
+
+       // Disable Fault reporting UI
+       const (
+               WER_FAULT_REPORTING_NO_UI = 0x0020
+       )
+       if stdcall1(_WerSetFlags, WER_FAULT_REPORTING_NO_UI) != 0 {
+               return false
+       }
+
+       // re-enable Windows Error Reporting
+       stdcall1(_SetErrorMode, 0)
+       return true
+}
+
 // in sys_windows_386.s and sys_windows_amd64.s
 func exceptiontramp()
 func firstcontinuetramp()
@@ -108,6 +140,7 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
                // Don't go through any more of the Windows handler chain.
                // Crash now.
                winthrow(info, r, gp)
+               exit(2)
        }
 
        // After this point, it is safe to grow the stack.
@@ -196,6 +229,20 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
        }
 
        winthrow(info, r, gp)
+
+       _, _, docrash := gotraceback()
+       if docrash {
+               // Windows 7 apears to ignore WER_FAULT_REPORTING_NO_UI
+               // WerSetFlags API flag. So do not call enableWERNoUI
+               // on Windows 7.
+               if !isWin7() {
+                       // trigger crash dump creation
+                       if enableWERNoUI() {
+                               return _EXCEPTION_CONTINUE_SEARCH
+                       }
+               }
+       }
+       exit(2)
        return 0 // not reached
 }
 
@@ -203,11 +250,6 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
 func winthrow(info *exceptionrecord, r *context, gp *g) {
        _g_ := getg()
 
-       if panicking != 0 { // traceback already printed
-               exit(2)
-       }
-       panicking = 1
-
        // In case we're handling a g0 stack overflow, blow away the
        // g0 stack bounds so we have room to print the traceback. If
        // this somehow overflows the stack, the OS will trap it.
@@ -218,29 +260,27 @@ func winthrow(info *exceptionrecord, r *context, gp *g) {
        print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
 
        print("PC=", hex(r.ip()), "\n")
-       if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+       if _g_.m.incgo && gp == _g_.m.g0 && _g_.m.curg != nil {
                if iscgo {
                        print("signal arrived during external code execution\n")
                }
-               gp = _g_.m.lockedg.ptr()
+               gp = _g_.m.curg
        }
        print("\n")
 
        _g_.m.throwing = 1
        _g_.m.caughtsig.set(gp)
 
-       level, _, docrash := gotraceback()
+       level, _, _ := gotraceback()
        if level > 0 {
-               tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
-               tracebackothers(gp)
+               // only print traceback when it hasn't been printed
+               if tracebackprinted == 0 {
+                       tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
+                       tracebackothers(gp)
+                       tracebackprinted = 1
+               }
                dumpregs(r)
        }
-
-       if docrash {
-               crash()
-       }
-
-       exit(2)
 }
 
 func sigpanic() {
@@ -312,14 +352,17 @@ func signame(sig uint32) string {
 
 //go:nosplit
 func crash() {
-       // TODO: This routine should do whatever is needed
-       // to make the Windows program abort/crash as it
-       // would if Go was not intercepting signals.
-       // On Unix the routine would remove the custom signal
-       // handler and then raise a signal (like SIGABRT).
-       // Something like that should happen here.
-       // It's okay to leave this empty for now: if crash returns
-       // the ordinary exit-after-panic happens.
+       // When GOTRACEBACK==crash, raise the same exception
+       // from kernel32.dll, so that Windows gets a chance
+       // to handle the exception by creating a crash dump.
+
+       // Get the Exception code that caused the crash
+       gp := getg()
+       exceptionCode := gp.sig
+
+       // RaiseException() here will not be handled in exceptionhandler()
+       // because it comes from kernel32.dll
+       stdcall4(_RaiseException, uintptr(unsafe.Pointer(&exceptionCode)), 0, 0, 0)
 }
 
 // gsignalStack is unused on Windows.
index 1b7cb9d4c453aeb930fbe11a5403205a1b643ace..7c88ab573eab2ad033a5d087f2736e30b4664e2a 100644 (file)
@@ -1,5 +1,4 @@
 //go:build windows
-// +build windows
 
 package runtime_test
 
index 6c91fb3fb3538c7202451ffd2960c2c3fb9fb40e..7b84a0ef65742d211baeebcd6d22f6f8e13814b4 100644 (file)
@@ -29,7 +29,6 @@
 // nor deadlocks.
 
 //go:build !plan9
-// +build !plan9
 
 package runtime
 
index e23446bea47b776bf48189390f2906f3a24f0176..fb1a517fa5733078880642f5baf3d2566a6484e8 100644 (file)
@@ -8,7 +8,6 @@
 // those functions. These functions will never be called.
 
 //go:build !darwin && !plan9
-// +build !darwin,!plan9
 
 package runtime
 
index dc1debddab3c4f4d90a4187dc15cfdc4999fa8ec..fe93bbafb5988ae65990f9452882296f05882f59 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !mips && !mipsle && !mips64 && !mips64le && linux
-// +build !mips,!mipsle,!mips64,!mips64le,linux
 
 package runtime
 
index af9c7e56eb907c48785b7ae2f715ea9e51cab00c..295ced5bbbbe48b6910da6135a9b39f6ef265bc4 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (mips || mipsle || mips64 || mips64le) && linux
-// +build mips mipsle mips64 mips64le
-// +build linux
 
 package runtime
 
index e8267be885df1670ed24265c8e5a890709f72a3b..ac0b7d5fefc51e95b77fe4764f0b5225c18413c2 100644 (file)
@@ -76,6 +76,9 @@ func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsaf
        if msanenabled {
                msanread(from, copymem)
        }
+       if asanenabled {
+               asanread(from, copymem)
+       }
 
        memmove(to, from, copymem)
 
@@ -115,16 +118,15 @@ func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
 }
 
 func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
-       if len == 0 {
-               return
-       }
-
-       if ptr == nil {
-               panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
+       if len < 0 {
+               panicunsafeslicelen()
        }
 
        mem, overflow := math.MulUintptr(et.size, uintptr(len))
-       if overflow || mem > maxAlloc || len < 0 {
+       if overflow || mem > -uintptr(ptr) {
+               if ptr == nil {
+                       panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
+               }
                panicunsafeslicelen()
        }
 }
@@ -169,6 +171,9 @@ func growslice(et *_type, old slice, cap int) slice {
        if msanenabled {
                msanread(old.array, uintptr(old.len*int(et.size)))
        }
+       if asanenabled {
+               asanread(old.array, uintptr(old.len*int(et.size)))
+       }
 
        if cap < old.cap {
                panic(errorString("growslice: cap out of range"))
@@ -185,13 +190,17 @@ func growslice(et *_type, old slice, cap int) slice {
        if cap > doublecap {
                newcap = cap
        } else {
-               if old.cap < 1024 {
+               const threshold = 256
+               if old.cap < threshold {
                        newcap = doublecap
                } else {
                        // Check 0 < newcap to detect overflow
                        // and prevent an infinite loop.
                        for 0 < newcap && newcap < cap {
-                               newcap += newcap / 4
+                               // Transition from growing 2x for small slices
+                               // to growing 1.25x for large slices. This formula
+                               // gives a smooth-ish transition between the two.
+                               newcap += (newcap + 3*threshold) / 4
                        }
                        // Set newcap to the requested cap when
                        // the newcap calculation overflowed.
@@ -308,6 +317,10 @@ func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen
                msanread(fromPtr, size)
                msanwrite(toPtr, size)
        }
+       if asanenabled {
+               asanread(fromPtr, size)
+               asanwrite(toPtr, size)
+       }
 
        if size == 1 { // common case worth about 2x to do here
                // TODO: is this still worth it with new memmove impl?
index 084aa132d9c6bd2636b6a58a452798264544e37b..42ef0092970b3e2525b65fa1c4cf5559d51b44d7 100644 (file)
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Software IEEE754 64-bit floating point.
-// Only referred to (and thus linked in) by arm port
+// Only referred to (and thus linked in) by softfloat targets
 // and by tests in this directory.
 
 package runtime
@@ -414,6 +414,25 @@ func fintto64(val int64) (f uint64) {
        }
        return fpack64(fs, mant, int(mantbits64), 0)
 }
+func fintto32(val int64) (f uint32) {
+       fs := uint64(val) & (1 << 63)
+       mant := uint64(val)
+       if fs != 0 {
+               mant = -mant
+       }
+       // Reduce mantissa size until it fits into a uint32.
+       // Keep track of the bits we throw away, and if any are
+       // nonzero or them into the lowest bit.
+       exp := int(mantbits32)
+       var trunc uint32
+       for mant >= 1<<32 {
+               trunc |= uint32(mant) & 1
+               mant >>= 1
+               exp++
+       }
+
+       return fpack32(uint32(fs>>32), uint32(mant), exp, trunc)
+}
 
 // 64x64 -> 128 multiply.
 // adapted from hacker's delight.
@@ -493,6 +512,7 @@ func fmul32(x, y uint32) uint32 {
 }
 
 func fdiv32(x, y uint32) uint32 {
+       // TODO: are there double-rounding problems here? See issue 48807.
        return f64to32(fdiv64(f32to64(x), f32to64(y)))
 }
 
@@ -527,7 +547,7 @@ func fge64(x, y uint64) bool {
 }
 
 func fint32to32(x int32) uint32 {
-       return f64to32(fintto64(int64(x)))
+       return fintto32(int64(x))
 }
 
 func fint32to64(x int32) uint64 {
@@ -535,7 +555,7 @@ func fint32to64(x int32) uint64 {
 }
 
 func fint64to32(x int64) uint32 {
-       return f64to32(fintto64(x))
+       return fintto32(x)
 }
 
 func fint64to64(x int64) uint64 {
@@ -595,5 +615,13 @@ func fuint64to64(x uint64) uint64 {
 }
 
 func fuint64to32(x uint64) uint32 {
-       return f64to32(fuint64to64(x))
+       if int64(x) >= 0 {
+               return fint64to32(int64(x))
+       }
+       // See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat
+       y := x & 1
+       z := x >> 1
+       z = z | y
+       r := fint64to32(int64(z))
+       return fadd32(r, r)
 }
index 54ad66dca2d202697926af9ea5d75729336868bf..7d9ae1e9d24dc3f7a9d03a63991772d1d6cef1af 100644 (file)
@@ -144,6 +144,9 @@ const (
        // Force a stack movement. Used for debugging.
        // 0xfffffeed in hex.
        stackForceMove = uintptrMask & -275
+
+       // stackPoisonMin is the lowest allowed stack poison value.
+       stackPoisonMin = uintptrMask & -4096
 )
 
 // Global pool of spans that have free stacks.
@@ -424,6 +427,9 @@ func stackalloc(n uint32) stack {
        if msanenabled {
                msanmalloc(v, uintptr(n))
        }
+       if asanenabled {
+               asanunpoison(v, uintptr(n))
+       }
        if stackDebug >= 1 {
                print("  allocated ", v, "\n")
        }
@@ -461,6 +467,9 @@ func stackfree(stk stack) {
        if msanenabled {
                msanfree(v, n)
        }
+       if asanenabled {
+               asanpoison(v, n)
+       }
        if n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
                order := uint8(0)
                n2 := n
@@ -691,7 +700,8 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
        // Adjust pointers in all stack objects (whether they are live or not).
        // See comments in mgcmark.go:scanframeworker.
        if frame.varp != 0 {
-               for _, obj := range objs {
+               for i := range objs {
+                       obj := &objs[i]
                        off := obj.off
                        base := frame.varp // locals base pointer
                        if off >= 0 {
@@ -705,7 +715,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
                                continue
                        }
                        ptrdata := obj.ptrdata()
-                       gcdata := obj.gcdata
+                       gcdata := obj.gcdata()
                        var s *mspan
                        if obj.useGCProg() {
                                // See comments in mgcmark.go:scanstack
@@ -851,6 +861,11 @@ func copystack(gp *g, newsize uintptr) {
                throw("nil stackbase")
        }
        used := old.hi - gp.sched.sp
+       // Add just the difference to gcController.addScannableStack.
+       // g0 stacks never move, so this will never account for them.
+       // It's also fine if we have no P, addScannableStack can deal with
+       // that case.
+       gcController.addScannableStack(getg().m.p.ptr(), int64(newsize)-int64(old.hi-old.lo))
 
        // allocate new stack
        new := stackalloc(uint32(newsize))
@@ -966,7 +981,7 @@ func newstack() {
                f := findfunc(gp.sched.pc)
                if f.valid() {
                        pcname = funcname(f)
-                       pcoff = gp.sched.pc - f.entry
+                       pcoff = gp.sched.pc - f.entry()
                }
                print("runtime: newstack at ", pcname, "+", hex(pcoff),
                        " sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
@@ -1198,7 +1213,6 @@ func shrinkstack(gp *g) {
 
 // freeStackSpans frees unused stack spans at the end of GC.
 func freeStackSpans() {
-
        // Scan stack pools for empty stack spans.
        for order := range stackpool {
                lock(&stackpool[order].item.mu)
@@ -1241,7 +1255,7 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args
 
        f := frame.fn
        pcdata := int32(-1)
-       if targetpc != f.entry {
+       if targetpc != f.entry() {
                // Back up to the CALL. If we're at the function entry
                // point, we want to use the entry map (-1), even if
                // the first instruction of the function changes the
@@ -1317,12 +1331,12 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args
        }
 
        // stack objects.
-       if (GOARCH == "amd64" || GOARCH == "arm64") && unsafe.Sizeof(abi.RegArgs{}) > 0 && frame.argmap != nil {
+       if (GOARCH == "amd64" || GOARCH == "arm64" || GOARCH == "ppc64" || GOARCH == "ppc64le") && unsafe.Sizeof(abi.RegArgs{}) > 0 && frame.argmap != nil {
                // argmap is set when the function is reflect.makeFuncStub or reflect.methodValueCall.
                // We don't actually use argmap in this case, but we need to fake the stack object
                // record for these frames which contain an internal/abi.RegArgs at a hard-coded offset.
                // This offset matches the assembly code on amd64 and arm64.
-               objs = methodValueCallFrameObjs
+               objs = methodValueCallFrameObjs[:]
        } else {
                p := funcdata(f, _FUNCDATA_StackObjects)
                if p != nil {
@@ -1340,23 +1354,33 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args
        return
 }
 
-var (
-       abiRegArgsEface          interface{} = abi.RegArgs{}
-       abiRegArgsType           *_type      = efaceOf(&abiRegArgsEface)._type
-       methodValueCallFrameObjs             = []stackObjectRecord{
-               {
-                       off:      -int32(alignUp(abiRegArgsType.size, 8)), // It's always the highest address local.
-                       size:     int32(abiRegArgsType.size),
-                       _ptrdata: int32(abiRegArgsType.ptrdata),
-                       gcdata:   abiRegArgsType.gcdata,
-               },
-       }
-)
+var methodValueCallFrameObjs [1]stackObjectRecord // initialized in stackobjectinit
 
-func init() {
+func stkobjinit() {
+       var abiRegArgsEface interface{} = abi.RegArgs{}
+       abiRegArgsType := efaceOf(&abiRegArgsEface)._type
        if abiRegArgsType.kind&kindGCProg != 0 {
                throw("abiRegArgsType needs GC Prog, update methodValueCallFrameObjs")
        }
+       // Set methodValueCallFrameObjs[0].gcdataoff so that
+       // stackObjectRecord.gcdata() will work correctly with it.
+       ptr := uintptr(unsafe.Pointer(&methodValueCallFrameObjs[0]))
+       var mod *moduledata
+       for datap := &firstmoduledata; datap != nil; datap = datap.next {
+               if datap.gofunc <= ptr && ptr < datap.end {
+                       mod = datap
+                       break
+               }
+       }
+       if mod == nil {
+               throw("methodValueCallFrameObjs is not in a module")
+       }
+       methodValueCallFrameObjs[0] = stackObjectRecord{
+               off:       -int32(alignUp(abiRegArgsType.size, 8)), // It's always the highest address local.
+               size:      int32(abiRegArgsType.size),
+               _ptrdata:  int32(abiRegArgsType.ptrdata),
+               gcdataoff: uint32(uintptr(unsafe.Pointer(abiRegArgsType.gcdata)) - mod.rodata),
+       }
 }
 
 // A stackObjectRecord is generated by the compiler for each stack object in a stack frame.
@@ -1365,10 +1389,10 @@ type stackObjectRecord struct {
        // offset in frame
        // if negative, offset from varp
        // if non-negative, offset from argp
-       off      int32
-       size     int32
-       _ptrdata int32 // ptrdata, or -ptrdata is GC prog is used
-       gcdata   *byte // pointer map or GC prog of the type
+       off       int32
+       size      int32
+       _ptrdata  int32  // ptrdata, or -ptrdata is GC prog is used
+       gcdataoff uint32 // offset to gcdata from moduledata.rodata
 }
 
 func (r *stackObjectRecord) useGCProg() bool {
@@ -1383,6 +1407,23 @@ func (r *stackObjectRecord) ptrdata() uintptr {
        return uintptr(x)
 }
 
+// gcdata returns pointer map or GC prog of the type.
+func (r *stackObjectRecord) gcdata() *byte {
+       ptr := uintptr(unsafe.Pointer(r))
+       var mod *moduledata
+       for datap := &firstmoduledata; datap != nil; datap = datap.next {
+               if datap.gofunc <= ptr && ptr < datap.end {
+                       mod = datap
+                       break
+               }
+       }
+       // If you get a panic here due to a nil mod,
+       // you may have made a copy of a stackObjectRecord.
+       // You must use the original pointer.
+       res := mod.rodata + uintptr(r.gcdataoff)
+       return (*byte)(unsafe.Pointer(res))
+}
+
 // This is exported as ABI0 via linkname so obj can call it.
 //
 //go:nosplit
index 43fc5cac55fba1911ff313bcec98f5ee3f0e4166..3f02243a1ea5371a2b0eb43aca9cb814ad0801a8 100644 (file)
@@ -585,6 +585,34 @@ func count21(n int) int { return 1 + count22(n-1) }
 func count22(n int) int { return 1 + count23(n-1) }
 func count23(n int) int { return 1 + count1(n-1) }
 
+type stkobjT struct {
+       p *stkobjT
+       x int64
+       y [20]int // consume some stack
+}
+
+// Sum creates a linked list of stkobjTs.
+func Sum(n int64, p *stkobjT) {
+       if n == 0 {
+               return
+       }
+       s := stkobjT{p: p, x: n}
+       Sum(n-1, &s)
+       p.x += s.x
+}
+
+func BenchmarkStackCopyWithStkobj(b *testing.B) {
+       c := make(chan bool)
+       for i := 0; i < b.N; i++ {
+               go func() {
+                       var s stkobjT
+                       Sum(100000, &s)
+                       c <- true
+               }()
+               <-c
+       }
+}
+
 type structWithMethod struct{}
 
 func (s structWithMethod) caller() string {
index d6990dab9aa66e46dbf889bafb95449b7b5574b5..980a9866e669516540bb41773c6852043baf481b 100644 (file)
@@ -94,6 +94,9 @@ func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
        if msanenabled {
                msanread(unsafe.Pointer(ptr), uintptr(n))
        }
+       if asanenabled {
+               asanread(unsafe.Pointer(ptr), uintptr(n))
+       }
        if n == 1 {
                p := unsafe.Pointer(&staticuint64s[*ptr])
                if goarch.BigEndian {
@@ -158,6 +161,9 @@ func slicebytetostringtmp(ptr *byte, n int) (str string) {
        if msanenabled && n > 0 {
                msanread(unsafe.Pointer(ptr), uintptr(n))
        }
+       if asanenabled && n > 0 {
+               asanread(unsafe.Pointer(ptr), uintptr(n))
+       }
        stringStructOf(&str).str = unsafe.Pointer(ptr)
        stringStructOf(&str).len = n
        return
@@ -209,6 +215,9 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
        if msanenabled && len(a) > 0 {
                msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
        }
+       if asanenabled && len(a) > 0 {
+               asanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
+       }
        var dum [4]byte
        size1 := 0
        for _, r := range a {
index 8a520d7839e31e4fc7180f5e38b88be015c778e7..ad78363bb67b1184a51eb75be1efff5f489c979a 100644 (file)
@@ -8,6 +8,7 @@ import (
        "internal/abi"
        "internal/goarch"
        "internal/goexperiment"
+       "runtime/internal/math"
        "unsafe"
 )
 
@@ -119,20 +120,32 @@ func reflect_memmove(to, from unsafe.Pointer, n uintptr) {
 }
 
 // exported value for testing
-var hashLoad = float32(loadFactorNum) / float32(loadFactorDen)
+const hashLoad = float32(loadFactorNum) / float32(loadFactorDen)
 
 //go:nosplit
 func fastrand() uint32 {
        mp := getg().m
+       // Implement wyrand: https://github.com/wangyi-fudan/wyhash
+       // Only the platform that math.Mul64 can be lowered
+       // by the compiler should be in this list.
+       if goarch.IsAmd64|goarch.IsArm64|goarch.IsPpc64|
+               goarch.IsPpc64le|goarch.IsMips64|goarch.IsMips64le|
+               goarch.IsS390x|goarch.IsRiscv64 == 1 {
+               mp.fastrand += 0xa0761d6478bd642f
+               hi, lo := math.Mul64(mp.fastrand, mp.fastrand^0xe7037ed1a0b428db)
+               return uint32(hi ^ lo)
+       }
+
        // Implement xorshift64+: 2 32-bit xorshift sequences added together.
        // Shift triplet [17,7,16] was calculated as indicated in Marsaglia's
        // Xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
        // This generator passes the SmallCrush suite, part of TestU01 framework:
        // http://simul.iro.umontreal.ca/testu01/tu01.html
-       s1, s0 := mp.fastrand[0], mp.fastrand[1]
+       t := (*[2]uint32)(unsafe.Pointer(&mp.fastrand))
+       s1, s0 := t[0], t[1]
        s1 ^= s1 << 17
        s1 = s1 ^ s0 ^ s1>>7 ^ s0>>16
-       mp.fastrand[0], mp.fastrand[1] = s0, s1
+       t[0], t[1] = s0, s1
        return s0 + s1
 }
 
@@ -143,8 +156,8 @@ func fastrandn(n uint32) uint32 {
        return uint32(uint64(fastrand()) * uint64(n) >> 32)
 }
 
-//go:linkname sync_fastrand sync.fastrand
-func sync_fastrand() uint32 { return fastrand() }
+//go:linkname sync_fastrandn sync.fastrandn
+func sync_fastrandn(n uint32) uint32 { return fastrandn(n) }
 
 //go:linkname net_fastrand net.fastrand
 func net_fastrand() uint32 { return fastrand() }
index 525b324c8163bd29ad5485ea53bda1397f5a22f6..9aa965454d991a4fda9dd84c786d65f5d9f94f8d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !js && !openbsd && !plan9 && !solaris && !windows
-// +build !aix,!darwin,!js,!openbsd,!plan9,!solaris,!windows
 
 package runtime
 
index b895be4c707519940dc354a892cc69f37b63ea45..891663b1109b1981bb664d3d284c9ea8ac347937 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !freebsd && !openbsd && !plan9 && !solaris
-// +build !aix,!darwin,!freebsd,!openbsd,!plan9,!solaris
 
 package runtime
 
index ba267009ca11f8b5e86d1b4871f1b51316be7017..06c14e21601d65c5aac0d5fee111af9fd7a97eb2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package runtime
 
index 05a4d0d38d5f87d0d9312958f06b93eab6d1896e..a9ddfc02568caeeac512a481ec15f39bcea98fb7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips64 || mips64le
-// +build mips64 mips64le
 
 package runtime
 
index 9bffb35b67e9200e41ba154baa1a04199875af73..d48f9b88e82ecfb9203082255d1a4cead272a9f1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips || mipsle
-// +build mips mipsle
 
 package runtime
 
index f9b98595fc4403a2ea796a7728cdfc42248bf335..1a06d7cc1d6dc05027be682cf4676eecb013159b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !linux
-// +build !linux
 
 package runtime
 
index f692947109abbb6445d9065934b6be2d885e0efb..07127629d19f6839280c251ab1231e7f876abda7 100644 (file)
@@ -3,14 +3,9 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package runtime
 
-// Called from assembly only; declared for go vet.
-func load_g()
-func save_g()
-func reginit()
-
+// This is needed for vet
 //go:noescape
 func callCgoSigaction(sig uintptr, new, old *sigactiont) int32
similarity index 59%
rename from src/runtime/stubs_ppc64le.go
rename to src/runtime/stubs_ppc64x.go
index 5b733136e3b57a5722f85ac57b8eb4500bf348a6..95e43a5162adb430bcb7aa183f5041b1f6ef16e4 100644 (file)
@@ -2,9 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build ppc64le || ppc64
+
 package runtime
 
 // Called from assembly only; declared for go vet.
 func load_g()
 func save_g()
 func reginit()
+
+// Spills/loads arguments in registers to/from an internal/abi.RegArgs
+// respectively. Does not follow the Go ABI.
+func spillArgs()
+func unspillArgs()
index d08aa0b320470506aa2ef42ba2f3ceecd58783d4..3237a6b708611c222de3d13aa1b427103260051c 100644 (file)
@@ -206,7 +206,7 @@ func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
                }
                lastFuncID = inltree[ix].funcID
                // Back up to an instruction in the "caller".
-               tracepc = f.entry + uintptr(inltree[ix].parentPc)
+               tracepc = f.entry() + uintptr(inltree[ix].parentPc)
                pc = tracepc + 1
        }
 
@@ -272,8 +272,26 @@ func (f *Func) raw() *_func {
 }
 
 func (f *Func) funcInfo() funcInfo {
-       fn := f.raw()
-       return funcInfo{fn, findmoduledatap(fn.entry)}
+       return f.raw().funcInfo()
+}
+
+func (f *_func) funcInfo() funcInfo {
+       // Find the module containing fn. fn is located in the pclntable.
+       // The unsafe.Pointer to uintptr conversions and arithmetic
+       // are safe because we are working with module addresses.
+       ptr := uintptr(unsafe.Pointer(f))
+       var mod *moduledata
+       for datap := &firstmoduledata; datap != nil; datap = datap.next {
+               if len(datap.pclntable) == 0 {
+                       continue
+               }
+               base := uintptr(unsafe.Pointer(&datap.pclntable[0]))
+               if base <= ptr && ptr < base+uintptr(len(datap.pclntable)) {
+                       mod = datap
+                       break
+               }
+       }
+       return funcInfo{f, mod}
 }
 
 // PCDATA and FUNCDATA table indexes.
@@ -283,6 +301,7 @@ const (
        _PCDATA_UnsafePoint   = 0
        _PCDATA_StackMapIndex = 1
        _PCDATA_InlTreeIndex  = 2
+       _PCDATA_ArgLiveIndex  = 3
 
        _FUNCDATA_ArgsPointerMaps    = 0
        _FUNCDATA_LocalsPointerMaps  = 1
@@ -290,6 +309,7 @@ const (
        _FUNCDATA_InlTree            = 3
        _FUNCDATA_OpenCodedDeferInfo = 4
        _FUNCDATA_ArgInfo            = 5
+       _FUNCDATA_ArgLiveInfo        = 6
 
        _ArgsSizeUnknown = -0x80000000
 )
@@ -365,20 +385,24 @@ const (
        // to be an incomplete unwinding of the stack. In certain contexts
        // (in particular garbage collector stack scans) that is a fatal error.
        funcFlag_SPWRITE
+
+       // ASM indicates that a function was implemented in assembly.
+       funcFlag_ASM
 )
 
 // pcHeader holds data used by the pclntab lookups.
 type pcHeader struct {
-       magic          uint32  // 0xFFFFFFFA
+       magic          uint32  // 0xFFFFFFF0
        pad1, pad2     uint8   // 0,0
        minLC          uint8   // min instruction size
        ptrSize        uint8   // size of a ptr in bytes
        nfunc          int     // number of functions in the module
-       nfiles         uint    // number of entries in the file tab.
+       nfiles         uint    // number of entries in the file tab
+       textStart      uintptr // base for function entry PC offsets in this module, equal to moduledata.text
        funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
        cuOffset       uintptr // offset to the cutab variable from pcHeader
        filetabOffset  uintptr // offset to the filetab variable from pcHeader
-       pctabOffset    uintptr // offset to the pctab varible from pcHeader
+       pctabOffset    uintptr // offset to the pctab variable from pcHeader
        pclnOffset     uintptr // offset to the pclntab variable from pcHeader
 }
 
@@ -405,6 +429,8 @@ type moduledata struct {
        noptrbss, enoptrbss   uintptr
        end, gcdata, gcbss    uintptr
        types, etypes         uintptr
+       rodata                uintptr
+       gofunc                uintptr // go.func.*
 
        textsectmap []textsect
        typelinks   []int32 // offsets from types
@@ -503,8 +529,11 @@ func modulesinit() {
                }
                *modules = append(*modules, md)
                if md.gcdatamask == (bitvector{}) {
-                       md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), md.edata-md.data)
-                       md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
+                       scanDataSize := md.edata - md.data
+                       md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize)
+                       scanBSSSize := md.ebss - md.bss
+                       md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize)
+                       gcController.addGlobals(int64(scanDataSize + scanBSSSize))
                }
        }
 
@@ -529,15 +558,15 @@ func modulesinit() {
 }
 
 type functab struct {
-       entry   uintptr
-       funcoff uintptr
+       entryoff uint32 // relative to runtime.text
+       funcoff  uint32
 }
 
 // Mapping information for secondary text sections
 
 type textsect struct {
        vaddr    uintptr // prelinked section vaddr
-       length   uintptr // section length
+       end      uintptr // vaddr + section length
        baseaddr uintptr // relocated section address
 }
 
@@ -568,33 +597,28 @@ const debugPcln = false
 func moduledataverify1(datap *moduledata) {
        // Check that the pclntab's format is valid.
        hdr := datap.pcHeader
-       if hdr.magic != 0xfffffffa || hdr.pad1 != 0 || hdr.pad2 != 0 || hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize {
-               print("runtime: function symbol table header:", hex(hdr.magic), hex(hdr.pad1), hex(hdr.pad2), hex(hdr.minLC), hex(hdr.ptrSize))
-               if datap.pluginpath != "" {
-                       print(", plugin:", datap.pluginpath)
-               }
-               println()
-               throw("invalid function symbol table\n")
+       if hdr.magic != 0xfffffff0 || hdr.pad1 != 0 || hdr.pad2 != 0 ||
+               hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize || hdr.textStart != datap.text {
+               println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2,
+                       "minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pcHeader.textStart=", hex(hdr.textStart),
+                       "text=", hex(datap.text), "pluginpath=", datap.pluginpath)
+               throw("invalid function symbol table")
        }
 
        // ftab is lookup table for function by program counter.
        nftab := len(datap.ftab) - 1
        for i := 0; i < nftab; i++ {
                // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
-               if datap.ftab[i].entry > datap.ftab[i+1].entry {
+               if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff {
                        f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
                        f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
                        f2name := "end"
                        if i+1 < nftab {
                                f2name = funcname(f2)
                        }
-                       print("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
-                       if datap.pluginpath != "" {
-                               print(", plugin:", datap.pluginpath)
-                       }
-                       println()
+                       println("function symbol table not sorted by PC offset:", hex(datap.ftab[i].entryoff), funcname(f1), ">", hex(datap.ftab[i+1].entryoff), f2name, ", plugin:", datap.pluginpath)
                        for j := 0; j <= i; j++ {
-                               print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
+                               println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}))
                        }
                        if GOOS == "aix" && isarchive {
                                println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
@@ -603,8 +627,10 @@ func moduledataverify1(datap *moduledata) {
                }
        }
 
-       if datap.minpc != datap.ftab[0].entry ||
-               datap.maxpc != datap.ftab[nftab].entry {
+       min := datap.textAddr(datap.ftab[0].entryoff)
+       max := datap.textAddr(datap.ftab[nftab].entryoff)
+       if datap.minpc != min || datap.maxpc != max {
+               println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max))
                throw("minpc or maxpc invalid")
        }
 
@@ -616,6 +642,69 @@ func moduledataverify1(datap *moduledata) {
        }
 }
 
+// textAddr returns md.text + off, with special handling for multiple text sections.
+// off is a (virtual) offset computed at internal linking time,
+// before the external linker adjusts the sections' base addresses.
+//
+// The text, or instruction stream is generated as one large buffer.
+// The off (offset) for a function is its offset within this buffer.
+// If the total text size gets too large, there can be issues on platforms like ppc64
+// if the target of calls are too far for the call instruction.
+// To resolve the large text issue, the text is split into multiple text sections
+// to allow the linker to generate long calls when necessary.
+// When this happens, the vaddr for each text section is set to its offset within the text.
+// Each function's offset is compared against the section vaddrs and ends to determine the containing section.
+// Then the section relative offset is added to the section's
+// relocated baseaddr to compute the function address.
+//
+// It is nosplit because it is part of the findfunc implementation.
+//go:nosplit
+func (md *moduledata) textAddr(off32 uint32) uintptr {
+       off := uintptr(off32)
+       res := md.text + off
+       if len(md.textsectmap) > 1 {
+               for i, sect := range md.textsectmap {
+                       // For the last section, include the end address (etext), as it is included in the functab.
+                       if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) {
+                               res = sect.baseaddr + off - sect.vaddr
+                               break
+                       }
+               }
+               if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory
+                       println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext))
+                       throw("runtime: text offset out of range")
+               }
+       }
+       return res
+}
+
+// textOff is the opposite of textAddr. It converts a PC to a (virtual) offset
+// to md.text, and returns if the PC is in any Go text section.
+//
+// It is nosplit because it is part of the findfunc implementation.
+//go:nosplit
+func (md *moduledata) textOff(pc uintptr) (uint32, bool) {
+       res := uint32(pc - md.text)
+       if len(md.textsectmap) > 1 {
+               for i, sect := range md.textsectmap {
+                       if sect.baseaddr > pc {
+                               // pc is not in any section.
+                               return 0, false
+                       }
+                       end := sect.baseaddr + (sect.end - sect.vaddr)
+                       // For the last section, include the end address (etext), as it is included in the functab.
+                       if i == len(md.textsectmap) {
+                               end++
+                       }
+                       if pc < end {
+                               res = uint32(pc - sect.baseaddr + sect.vaddr)
+                               break
+                       }
+               }
+       }
+       return res, true
+}
+
 // FuncForPC returns a *Func describing the function that contains the
 // given program counter address, or else nil.
 //
@@ -637,7 +726,8 @@ func FuncForPC(pc uintptr) *Func {
                        name := funcnameFromNameoff(f, inltree[ix].func_)
                        file, line := funcline(f, pc)
                        fi := &funcinl{
-                               entry: f.entry, // entry of the real (the outermost) function.
+                               ones:  ^uint32(0),
+                               entry: f.entry(), // entry of the real (the outermost) function.
                                name:  name,
                                file:  file,
                                line:  int(line),
@@ -654,7 +744,7 @@ func (f *Func) Name() string {
                return ""
        }
        fn := f.raw()
-       if fn.entry == 0 { // inlined version
+       if fn.isInlined() { // inlined version
                fi := (*funcinl)(unsafe.Pointer(fn))
                return fi.name
        }
@@ -664,11 +754,11 @@ func (f *Func) Name() string {
 // Entry returns the entry address of the function.
 func (f *Func) Entry() uintptr {
        fn := f.raw()
-       if fn.entry == 0 { // inlined version
+       if fn.isInlined() { // inlined version
                fi := (*funcinl)(unsafe.Pointer(fn))
                return fi.entry
        }
-       return fn.entry
+       return fn.funcInfo().entry()
 }
 
 // FileLine returns the file name and line number of the
@@ -677,7 +767,7 @@ func (f *Func) Entry() uintptr {
 // counter within f.
 func (f *Func) FileLine(pc uintptr) (file string, line int) {
        fn := f.raw()
-       if fn.entry == 0 { // inlined version
+       if fn.isInlined() { // inlined version
                fi := (*funcinl)(unsafe.Pointer(fn))
                return fi.file, fi.line
        }
@@ -715,6 +805,16 @@ func (f funcInfo) _Func() *Func {
        return (*Func)(unsafe.Pointer(f._func))
 }
 
+// isInlined reports whether f should be re-interpreted as a *funcinl.
+func (f *_func) isInlined() bool {
+       return f.entryoff == ^uint32(0) // see comment for funcinl.ones
+}
+
+// entry returns the entry PC for f.
+func (f funcInfo) entry() uintptr {
+       return f.datap.textAddr(f.entryoff)
+}
+
 // findfunc looks up function metadata for a PC.
 //
 // It is nosplit because it's part of the isgoexception
@@ -728,44 +828,24 @@ func findfunc(pc uintptr) funcInfo {
        }
        const nsub = uintptr(len(findfuncbucket{}.subbuckets))
 
-       x := pc - datap.minpc
+       pcOff, ok := datap.textOff(pc)
+       if !ok {
+               return funcInfo{}
+       }
+
+       x := uintptr(pcOff) + datap.text - datap.minpc // TODO: are datap.text and datap.minpc always equal?
        b := x / pcbucketsize
        i := x % pcbucketsize / (pcbucketsize / nsub)
 
        ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
        idx := ffb.idx + uint32(ffb.subbuckets[i])
 
-       // If the idx is beyond the end of the ftab, set it to the end of the table and search backward.
-       // This situation can occur if multiple text sections are generated to handle large text sections
-       // and the linker has inserted jump tables between them.
-
-       if idx >= uint32(len(datap.ftab)) {
-               idx = uint32(len(datap.ftab) - 1)
+       // Find the ftab entry.
+       for datap.ftab[idx+1].entryoff <= pcOff {
+               idx++
        }
-       if pc < datap.ftab[idx].entry {
-               // With multiple text sections, the idx might reference a function address that
-               // is higher than the pc being searched, so search backward until the matching address is found.
 
-               for datap.ftab[idx].entry > pc && idx > 0 {
-                       idx--
-               }
-               if idx == 0 {
-                       throw("findfunc: bad findfunctab entry idx")
-               }
-       } else {
-               // linear search to find func with pc >= entry.
-               for datap.ftab[idx+1].entry <= pc {
-                       idx++
-               }
-       }
        funcoff := datap.ftab[idx].funcoff
-       if funcoff == ^uintptr(0) {
-               // With multiple text sections, there may be functions inserted by the external
-               // linker that are not known by Go. This means there may be holes in the PC
-               // range covered by the func table. The invalid funcoff value indicates a hole.
-               // See also cmd/link/internal/ld/pcln.go:pclntab
-               return funcInfo{}
-       }
        return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
 }
 
@@ -819,19 +899,19 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, cache *pcvalueCache, stri
 
        if !f.valid() {
                if strict && panicking == 0 {
-                       print("runtime: no module data for ", hex(f.entry), "\n")
+                       println("runtime: no module data for", hex(f.entry()))
                        throw("no module data")
                }
                return -1, 0
        }
        datap := f.datap
        p := datap.pctab[off:]
-       pc := f.entry
+       pc := f.entry()
        prevpc := pc
        val := int32(-1)
        for {
                var ok bool
-               p, ok = step(p, &pc, &val, pc == f.entry)
+               p, ok = step(p, &pc, &val, pc == f.entry())
                if !ok {
                        break
                }
@@ -845,7 +925,7 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, cache *pcvalueCache, stri
                        if cache != nil {
                                x := pcvalueCacheKey(targetpc)
                                e := &cache.entries[x]
-                               ci := fastrand() % uint32(len(cache.entries[x]))
+                               ci := fastrandn(uint32(len(cache.entries[x])))
                                e[ci] = e[0]
                                e[0] = pcvalueCacheEnt{
                                        targetpc: targetpc,
@@ -868,11 +948,11 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, cache *pcvalueCache, stri
        print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
 
        p = datap.pctab[off:]
-       pc = f.entry
+       pc = f.entry()
        val = -1
        for {
                var ok bool
-               p, ok = step(p, &pc, &val, pc == f.entry)
+               p, ok = step(p, &pc, &val, pc == f.entry())
                if !ok {
                        break
                }
@@ -955,8 +1035,9 @@ func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
 
 func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
        x, _ := pcvalue(f, f.pcsp, targetpc, cache, true)
-       if x&(goarch.PtrSize-1) != 0 {
-               print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
+       if debugPcln && x&(goarch.PtrSize-1) != 0 {
+               print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
+               throw("bad spdelta")
        }
        return x
 }
@@ -965,12 +1046,12 @@ func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
 func funcMaxSPDelta(f funcInfo) int32 {
        datap := f.datap
        p := datap.pctab[f.pcsp:]
-       pc := f.entry
+       pc := f.entry()
        val := int32(-1)
        max := int32(0)
        for {
                var ok bool
-               p, ok = step(p, &pc, &val, pc == f.entry)
+               p, ok = step(p, &pc, &val, pc == f.entry())
                if !ok {
                        return max
                }
@@ -1009,18 +1090,24 @@ func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
        return pcvalue(f, pcdatastart(f, table), targetpc, nil, true)
 }
 
+// funcdata returns a pointer to the ith funcdata for f.
+// funcdata should be kept in sync with cmd/link:writeFuncs.
 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
        if i < 0 || i >= f.nfuncdata {
                return nil
        }
-       p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
-       if goarch.PtrSize == 8 && uintptr(p)&4 != 0 {
-               if uintptr(unsafe.Pointer(f._func))&4 != 0 {
-                       println("runtime: misaligned func", f._func)
-               }
-               p = add(p, 4)
+       base := f.datap.gofunc // load gofunc address early so that we calculate during cache misses
+       p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
+       off := *(*uint32)(unsafe.Pointer(p))
+       // Return off == ^uint32(0) ? 0 : f.datap.gofunc + uintptr(off), but without branches.
+       // The compiler calculates mask on most architectures using conditional assignment.
+       var mask uintptr
+       if off == ^uint32(0) {
+               mask = 1
        }
-       return *(*unsafe.Pointer)(add(p, uintptr(i)*goarch.PtrSize))
+       mask--
+       raw := base + uintptr(off)
+       return unsafe.Pointer(raw & mask)
 }
 
 // step advances to the next pc, value pair in the encoded table.
index ffa07c7f3a9f8dca3ab1323bdfe6cbd5269a2c39..99ff0d4420b1caa9a246cc98368109533a89ee7d 100644 (file)
@@ -250,3 +250,35 @@ func TestFunctionAlignmentTraceback(t *testing.T) {
                t.Errorf("frames.Next() got %+v want %+v", frame.Func, f)
        }
 }
+
+func BenchmarkFunc(b *testing.B) {
+       pc, _, _, ok := runtime.Caller(0)
+       if !ok {
+               b.Fatal("failed to look up PC")
+       }
+       f := runtime.FuncForPC(pc)
+       b.Run("Name", func(b *testing.B) {
+               for i := 0; i < b.N; i++ {
+                       name := f.Name()
+                       if name != "runtime_test.BenchmarkFunc" {
+                               b.Fatalf("unexpected name %q", name)
+                       }
+               }
+       })
+       b.Run("Entry", func(b *testing.B) {
+               for i := 0; i < b.N; i++ {
+                       pc := f.Entry()
+                       if pc == 0 {
+                               b.Fatal("zero PC")
+                       }
+               }
+       })
+       b.Run("FileLine", func(b *testing.B) {
+               for i := 0; i < b.N; i++ {
+                       file, line := f.FileLine(pc)
+                       if !strings.HasSuffix(file, "symtab_test.go") || line == 0 {
+                               b.Fatalf("unexpected file/line %q:%d", file, line)
+                       }
+               }
+       })
+}
index 3bd027f98242f06d189643af0af0c3e8a1931b6c..5d89cda8e68901a668fec3e3b7bb7f30e21b3e57 100644 (file)
@@ -230,6 +230,23 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
        POP_REGS_HOST_TO_ABI0()
        RET
 
+// Called using C ABI.
+TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$0
+       // Transition from C ABI to Go ABI.
+       PUSH_REGS_HOST_TO_ABI0()
+
+       // Call into the Go signal handler
+       NOP     SP              // disable vet stack checking
+       ADJSP   $24
+       MOVL    DI, 0(SP)       // sig
+       MOVQ    SI, 8(SP)       // info
+       MOVQ    DX, 16(SP)      // ctx
+       CALL    ·sigprofNonGo(SB)
+       ADJSP   $-24
+
+       POP_REGS_HOST_TO_ABI0()
+       RET
+
 // Used instead of sigtramp in programs that use cgo.
 // Arguments from kernel are in DI, SI, DX.
 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
@@ -297,12 +314,12 @@ sigtrampnog:
        JNZ     sigtramp  // Skip stack trace if already locked.
 
        // Jump to the traceback function in runtime/cgo.
-       // It will call back to sigprofNonGo, which will ignore the
-       // arguments passed in registers.
+       // It will call back to sigprofNonGo, via sigprofNonGoWrapper, to convert
+       // the arguments to the Go calling convention.
        // First three arguments to traceback function are in registers already.
        MOVQ    runtime·cgoTraceback(SB), CX
        MOVQ    $runtime·sigprofCallers(SB), R8
-       MOVQ    $runtime·sigprofNonGo(SB), R9
+       MOVQ    $runtime·sigprofNonGoWrapper<>(SB), R9
        MOVQ    _cgo_callers(SB), AX
        JMP     AX
 
index 71a60cae65c23668ba2638592566a96b2e383914..165e97c60d735881ea3797df151f5c3aa79f9409 100644 (file)
@@ -255,6 +255,23 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
         POP_REGS_HOST_TO_ABI0()
        RET
 
+// Called using C ABI.
+TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$0
+       // Transition from C ABI to Go ABI.
+       PUSH_REGS_HOST_TO_ABI0()
+
+       // Call into the Go signal handler
+       NOP     SP              // disable vet stack checking
+       ADJSP   $24
+       MOVL    DI, 0(SP)       // sig
+       MOVQ    SI, 8(SP)       // info
+       MOVQ    DX, 16(SP)      // ctx
+       CALL    ·sigprofNonGo(SB)
+       ADJSP   $-24
+
+       POP_REGS_HOST_TO_ABI0()
+       RET
+
 // Used instead of sigtramp in programs that use cgo.
 // Arguments from kernel are in DI, SI, DX.
 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
@@ -322,12 +339,12 @@ sigtrampnog:
        JNZ     sigtramp  // Skip stack trace if already locked.
 
        // Jump to the traceback function in runtime/cgo.
-       // It will call back to sigprofNonGo, which will ignore the
-       // arguments passed in registers.
+       // It will call back to sigprofNonGo, via sigprofNonGoWrapper, to convert
+       // the arguments to the Go calling convention.
        // First three arguments to traceback function are in registers already.
        MOVQ    runtime·cgoTraceback(SB), CX
        MOVQ    $runtime·sigprofCallers(SB), R8
-       MOVQ    $runtime·sigprofNonGo(SB), R9
+       MOVQ    $runtime·sigprofNonGoWrapper<>(SB), R9
        MOVQ    _cgo_callers(SB), AX
        JMP     AX
 
index b1a9f8b5365709d2862057877815ff4056cb942c..7012b4167e969f0065c93df970f22a88fe487fc6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || (openbsd && !mips64)
-// +build darwin openbsd,!mips64
 
 package runtime
 
index 3ae5a9099f096aaa01f10b676dc41bad1437f7dc..6df812234c3f9cf4591a83375a2dc39b4745662f 100644 (file)
@@ -56,6 +56,9 @@
 #define SYS_epoll_create       254
 #define SYS_epoll_ctl          255
 #define SYS_epoll_wait         256
+#define SYS_timer_create       259
+#define SYS_timer_settime      260
+#define SYS_timer_delete       263
 #define SYS_clock_gettime      265
 #define SYS_tgkill             270
 #define SYS_epoll_create1      329
@@ -210,6 +213,32 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0-12
        INVOKE_SYSCALL
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-16
+       MOVL    $SYS_timer_create, AX
+       MOVL    clockid+0(FP), BX
+       MOVL    sevp+4(FP), CX
+       MOVL    timerid+8(FP), DX
+       INVOKE_SYSCALL
+       MOVL    AX, ret+12(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
+       MOVL    $SYS_timer_settime, AX
+       MOVL    timerid+0(FP), BX
+       MOVL    flags+4(FP), CX
+       MOVL    new+8(FP), DX
+       MOVL    old+12(FP), SI
+       INVOKE_SYSCALL
+       MOVL    AX, ret+16(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
+       MOVL    $SYS_timer_delete, AX
+       MOVL    timerid+0(FP), BX
+       INVOKE_SYSCALL
+       MOVL    AX, ret+4(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT,$0-16
        MOVL    $SYS_mincore, AX
        MOVL    addr+0(FP), BX
index 64ddc2354e6959f0ecb5b5adc502548026c1ee80..f0e58e11db36ec56ed0bf2de730f198a64cec0a3 100644 (file)
@@ -41,6 +41,9 @@
 #define SYS_futex              202
 #define SYS_sched_getaffinity  204
 #define SYS_epoll_create       213
+#define SYS_timer_create       222
+#define SYS_timer_settime      223
+#define SYS_timer_delete       226
 #define SYS_clock_gettime      228
 #define SYS_exit_group         231
 #define SYS_epoll_ctl          233
@@ -195,6 +198,32 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0-24
        SYSCALL
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-28
+       MOVL    clockid+0(FP), DI
+       MOVQ    sevp+8(FP), SI
+       MOVQ    timerid+16(FP), DX
+       MOVL    $SYS_timer_create, AX
+       SYSCALL
+       MOVL    AX, ret+24(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
+       MOVL    timerid+0(FP), DI
+       MOVL    flags+4(FP), SI
+       MOVQ    new+8(FP), DX
+       MOVQ    old+16(FP), R10
+       MOVL    $SYS_timer_settime, AX
+       SYSCALL
+       MOVL    AX, ret+24(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
+       MOVL    timerid+0(FP), DI
+       MOVL    $SYS_timer_delete, AX
+       SYSCALL
+       MOVL    AX, ret+8(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT,$0-28
        MOVQ    addr+0(FP), DI
        MOVQ    n+8(FP), SI
@@ -335,6 +364,23 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
         POP_REGS_HOST_TO_ABI0()
        RET
 
+// Called using C ABI.
+TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$0
+       // Transition from C ABI to Go ABI.
+       PUSH_REGS_HOST_TO_ABI0()
+
+       // Call into the Go signal handler
+       NOP     SP              // disable vet stack checking
+       ADJSP   $24
+       MOVL    DI, 0(SP)       // sig
+       MOVQ    SI, 8(SP)       // info
+       MOVQ    DX, 16(SP)      // ctx
+       CALL    ·sigprofNonGo(SB)
+       ADJSP   $-24
+
+       POP_REGS_HOST_TO_ABI0()
+       RET
+
 // Used instead of sigtramp in programs that use cgo.
 // Arguments from kernel are in DI, SI, DX.
 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
@@ -402,12 +448,12 @@ sigtrampnog:
        JNZ     sigtramp  // Skip stack trace if already locked.
 
        // Jump to the traceback function in runtime/cgo.
-       // It will call back to sigprofNonGo, which will ignore the
-       // arguments passed in registers.
+       // It will call back to sigprofNonGo, via sigprofNonGoWrapper, to convert
+       // the arguments to the Go calling convention.
        // First three arguments to traceback function are in registers already.
        MOVQ    runtime·cgoTraceback(SB), CX
        MOVQ    $runtime·sigprofCallers(SB), R8
-       MOVQ    $runtime·sigprofNonGo(SB), R9
+       MOVQ    $runtime·sigprofNonGoWrapper<>(SB), R9
        MOVQ    _cgo_callers(SB), AX
        JMP     AX
 
index 02a5d4a6427402cdc0981364caf157bcd82d77a0..65935de99f66f4c617d47c75323f23cfb4a045de 100644 (file)
@@ -45,6 +45,9 @@
 #define SYS_epoll_create (SYS_BASE + 250)
 #define SYS_epoll_ctl (SYS_BASE + 251)
 #define SYS_epoll_wait (SYS_BASE + 252)
+#define SYS_timer_create (SYS_BASE + 257)
+#define SYS_timer_settime (SYS_BASE + 258)
+#define SYS_timer_delete (SYS_BASE + 261)
 #define SYS_epoll_create1 (SYS_BASE + 357)
 #define SYS_pipe2 (SYS_BASE + 359)
 #define SYS_fcntl (SYS_BASE + 55)
@@ -233,6 +236,32 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0
        SWI     $0
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-16
+       MOVW    clockid+0(FP), R0
+       MOVW    sevp+4(FP), R1
+       MOVW    timerid+8(FP), R2
+       MOVW    $SYS_timer_create, R7
+       SWI     $0
+       MOVW    R0, ret+12(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
+       MOVW    timerid+0(FP), R0
+       MOVW    flags+4(FP), R1
+       MOVW    new+8(FP), R2
+       MOVW    old+12(FP), R3
+       MOVW    $SYS_timer_settime, R7
+       SWI     $0
+       MOVW    R0, ret+16(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
+       MOVW    timerid+0(FP), R0
+       MOVW    $SYS_timer_delete, R7
+       SWI     $0
+       MOVW    R0, ret+4(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT,$0
        MOVW    addr+0(FP), R0
        MOVW    n+4(FP), R1
@@ -259,8 +288,9 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
        MOVW    R1, 4(R13)
        MOVW    R2, 8(R13)
 
+       MOVW    $ret-4(FP), R2 // caller's SP
        MOVW    LR, m_vdsoPC(R5)
-       MOVW    R13, m_vdsoSP(R5)
+       MOVW    R2, m_vdsoSP(R5)
 
        MOVW    m_curg(R5), R0
 
@@ -330,6 +360,7 @@ finish:
        MOVW    R1, m_vdsoPC(R5)
 
        MOVW    R0, sec_lo+0(FP)
+       MOVW    $0, R1
        MOVW    R1, sec_hi+4(FP)
        MOVW    R2, nsec+8(FP)
        RET
@@ -351,8 +382,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$8-8
        MOVW    R1, 4(R13)
        MOVW    R2, 8(R13)
 
+       MOVW    $ret-4(FP), R2 // caller's SP
        MOVW    LR, m_vdsoPC(R5)
-       MOVW    R13, m_vdsoSP(R5)
+       MOVW    R2, m_vdsoSP(R5)
 
        MOVW    m_curg(R5), R0
 
index 69ac16027800f3df0e61100b3278ee6357ed9f82..1276c077d701f2c8bf894d780a79d8938d05268e 100644 (file)
@@ -49,6 +49,9 @@
 #define SYS_socket             198
 #define SYS_connect            203
 #define SYS_brk                        214
+#define SYS_timer_create       107
+#define SYS_timer_settime      110
+#define SYS_timer_delete       111
 
 TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
        MOVW    code+0(FP), R0
@@ -197,6 +200,32 @@ TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
        SVC
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-28
+       MOVW    clockid+0(FP), R0
+       MOVD    sevp+8(FP), R1
+       MOVD    timerid+16(FP), R2
+       MOVD    $SYS_timer_create, R8
+       SVC
+       MOVW    R0, ret+24(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
+       MOVW    timerid+0(FP), R0
+       MOVW    flags+4(FP), R1
+       MOVD    new+8(FP), R2
+       MOVD    old+16(FP), R3
+       MOVD    $SYS_timer_settime, R8
+       SVC
+       MOVW    R0, ret+24(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
+       MOVW    timerid+0(FP), R0
+       MOVD    $SYS_timer_delete, R8
+       SVC
+       MOVW    R0, ret+8(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
        MOVD    addr+0(FP), R0
        MOVD    n+8(FP), R1
@@ -221,8 +250,9 @@ TEXT runtime·walltime(SB),NOSPLIT,$24-12
        MOVD    R2, 8(RSP)
        MOVD    R3, 16(RSP)
 
+       MOVD    $ret-8(FP), R2 // caller's SP
        MOVD    LR, m_vdsoPC(R21)
-       MOVD    R20, m_vdsoSP(R21)
+       MOVD    R2, m_vdsoSP(R21)
 
        MOVD    m_curg(R21), R0
        CMP     g, R0
@@ -304,8 +334,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$24-8
        MOVD    R2, 8(RSP)
        MOVD    R3, 16(RSP)
 
+       MOVD    $ret-8(FP), R2 // caller's SP
        MOVD    LR, m_vdsoPC(R21)
-       MOVD    R20, m_vdsoSP(R21)
+       MOVD    R2, m_vdsoSP(R21)
 
        MOVD    m_curg(R21), R0
        CMP     g, R0
index e18d29144563fed07dfecfcb859c5f1257de0782..08e44d671b8bd675fdb1393a764090dcb51b1dba 100644 (file)
@@ -41,6 +41,9 @@
 #define SYS_exit_group         5205
 #define SYS_epoll_create       5207
 #define SYS_epoll_ctl          5208
+#define SYS_timer_create       5216
+#define SYS_timer_settime      5217
+#define SYS_timer_delete       5220
 #define SYS_tgkill             5225
 #define SYS_openat             5247
 #define SYS_epoll_pwait                5272
@@ -204,6 +207,32 @@ TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
        SYSCALL
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-28
+       MOVW    clockid+0(FP), R4
+       MOVV    sevp+8(FP), R5
+       MOVV    timerid+16(FP), R6
+       MOVV    $SYS_timer_create, R2
+       SYSCALL
+       MOVW    R2, ret+24(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
+       MOVW    timerid+0(FP), R4
+       MOVW    flags+4(FP), R5
+       MOVV    new+8(FP), R6
+       MOVV    old+16(FP), R7
+       MOVV    $SYS_timer_settime, R2
+       SYSCALL
+       MOVW    R2, ret+24(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
+       MOVW    timerid+0(FP), R4
+       MOVV    $SYS_timer_delete, R2
+       SYSCALL
+       MOVW    R2, ret+8(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
        MOVV    addr+0(FP), R4
        MOVV    n+8(FP), R5
@@ -229,8 +258,9 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12
        MOVV    R2, 8(R29)
        MOVV    R3, 16(R29)
 
+       MOVV    $ret-8(FP), R2 // caller's SP
        MOVV    R31, m_vdsoPC(R17)
-       MOVV    R29, m_vdsoSP(R17)
+       MOVV    R2, m_vdsoSP(R17)
 
        MOVV    m_curg(R17), R4
        MOVV    g, R5
@@ -298,8 +328,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$16-8
        MOVV    R2, 8(R29)
        MOVV    R3, 16(R29)
 
+       MOVV    $ret-8(FP), R2 // caller's SP
        MOVV    R31, m_vdsoPC(R17)
-       MOVV    R29, m_vdsoSP(R17)
+       MOVV    R2, m_vdsoSP(R17)
 
        MOVV    m_curg(R17), R4
        MOVV    g, R5
index b3970be9cf8f746a0f6cf2e2eb5bf212009b68be..c82843189946416118b9d2129b0b97c9e9fac9b8 100644 (file)
@@ -43,6 +43,9 @@
 #define SYS_epoll_create       4248
 #define SYS_epoll_ctl          4249
 #define SYS_epoll_wait         4250
+#define SYS_timer_create       4257
+#define SYS_timer_settime      4258
+#define SYS_timer_delete       4261
 #define SYS_clock_gettime      4263
 #define SYS_tgkill             4266
 #define SYS_epoll_create1      4326
@@ -209,6 +212,32 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0-12
        SYSCALL
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-16
+       MOVW    clockid+0(FP), R4
+       MOVW    sevp+4(FP), R5
+       MOVW    timerid+8(FP), R6
+       MOVW    $SYS_timer_create, R2
+       SYSCALL
+       MOVW    R2, ret+12(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-20
+       MOVW    timerid+0(FP), R4
+       MOVW    flags+4(FP), R5
+       MOVW    new+8(FP), R6
+       MOVW    old+12(FP), R7
+       MOVW    $SYS_timer_settime, R2
+       SYSCALL
+       MOVW    R2, ret+16(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-8
+       MOVW    timerid+0(FP), R4
+       MOVW    $SYS_timer_delete, R2
+       SYSCALL
+       MOVW    R2, ret+4(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT,$0-16
        MOVW    addr+0(FP), R4
        MOVW    n+4(FP), R5
index 005fa4d2b4d002acfb2a946ff72b2369580ae08a..9347afaf19086b4d189375f698b67d3efe8ed5c8 100644 (file)
@@ -44,6 +44,9 @@
 #define SYS_epoll_create       236
 #define SYS_epoll_ctl          237
 #define SYS_epoll_wait         238
+#define SYS_timer_create       240
+#define SYS_timer_settime      241
+#define SYS_timer_delete       244
 #define SYS_clock_gettime      246
 #define SYS_tgkill             250
 #define SYS_epoll_create1      315
@@ -176,6 +179,29 @@ TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
        SYSCALL $SYS_setitimer
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT,$0-28
+       MOVW    clockid+0(FP), R3
+       MOVD    sevp+8(FP), R4
+       MOVD    timerid+16(FP), R5
+       SYSCALL $SYS_timer_create
+       MOVW    R3, ret+24(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
+       MOVW    timerid+0(FP), R3
+       MOVW    flags+4(FP), R4
+       MOVD    new+8(FP), R5
+       MOVD    old+16(FP), R6
+       SYSCALL $SYS_timer_settime
+       MOVW    R3, ret+24(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
+       MOVW    timerid+0(FP), R3
+       SYSCALL $SYS_timer_delete
+       MOVW    R3, ret+8(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
        MOVD    addr+0(FP), R3
        MOVD    n+8(FP), R4
@@ -205,8 +231,9 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12
        MOVD    R5, 40(R1)
 
        MOVD    LR, R14
+       MOVD    $ret-FIXED_FRAME(FP), R5 // caller's SP
        MOVD    R14, m_vdsoPC(R21)
-       MOVD    R15, m_vdsoSP(R21)
+       MOVD    R5, m_vdsoSP(R21)
 
        MOVD    m_curg(R21), R6
        CMP     g, R6
@@ -297,9 +324,10 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$16-8
        MOVD    R4, 32(R1)
        MOVD    R5, 40(R1)
 
-       MOVD    LR, R14         // R14 is unchanged by C code
+       MOVD    LR, R14                         // R14 is unchanged by C code
+       MOVD    $ret-FIXED_FRAME(FP), R5        // caller's SP
        MOVD    R14, m_vdsoPC(R21)
-       MOVD    R15, m_vdsoSP(R21)
+       MOVD    R5, m_vdsoSP(R21)
 
        MOVD    m_curg(R21), R6
        CMP     g, R6
@@ -715,6 +743,9 @@ TEXT cgoSigtramp<>(SB),NOSPLIT,$0
 TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$0
        // We're coming from C code, set up essential register, then call sigprofNonGo.
        CALL    runtime·reginit(SB)
+       MOVW    R3, FIXED_FRAME+0(R1)   // sig
+       MOVD    R4, FIXED_FRAME+8(R1)   // info
+       MOVD    R5, FIXED_FRAME+16(R1)  // ctx
        CALL    runtime·sigprofNonGo(SB)
        RET
 
index 2389f1cc182489971fb050fcc9209fbbd470e474..a3da46d1362fbcd615ff4378cbc229b302d6e644 100644 (file)
@@ -10,6 +10,8 @@
 #include "go_asm.h"
 
 #define AT_FDCWD -100
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 1
 
 #define SYS_brk                        214
 #define SYS_clock_gettime      113
@@ -25,7 +27,6 @@
 #define SYS_fcntl              25
 #define SYS_futex              98
 #define SYS_getpid             172
-#define SYS_getrlimit          163
 #define SYS_gettid             178
 #define SYS_gettimeofday       169
 #define SYS_kill               129
@@ -47,6 +48,9 @@
 #define SYS_sigaltstack                132
 #define SYS_socket             198
 #define SYS_tgkill             131
+#define SYS_timer_create       107
+#define SYS_timer_delete       111
+#define SYS_timer_settime      110
 #define SYS_tkill              130
 #define SYS_write              64
 
@@ -132,15 +136,6 @@ TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
        MOVW    A0, errno+16(FP)
        RET
 
-// func getrlimit(kind int32, limit unsafe.Pointer) int32
-TEXT runtime·getrlimit(SB),NOSPLIT|NOFRAME,$0-20
-       MOVW    kind+0(FP), A0
-       MOV     limit+8(FP), A1
-       MOV     $SYS_getrlimit, A7
-       ECALL
-       MOVW    A0, ret+16(FP)
-       RET
-
 // func usleep(usec uint32)
 TEXT runtime·usleep(SB),NOSPLIT,$24-4
        MOVWU   usec+0(FP), A0
@@ -209,6 +204,35 @@ TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
        ECALL
        RET
 
+// func timer_create(clockid int32, sevp *sigevent, timerid *int32) int32
+TEXT runtime·timer_create(SB),NOSPLIT,$0-28
+       MOVW    clockid+0(FP), A0
+       MOV     sevp+8(FP), A1
+       MOV     timerid+16(FP), A2
+       MOV     $SYS_timer_create, A7
+       ECALL
+       MOVW    A0, ret+24(FP)
+       RET
+
+// func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32
+TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
+       MOVW    timerid+0(FP), A0
+       MOVW    flags+4(FP), A1
+       MOV     new+8(FP), A2
+       MOV     old+16(FP), A3
+       MOV     $SYS_timer_settime, A7
+       ECALL
+       MOVW    A0, ret+24(FP)
+       RET
+
+// func timer_delete(timerid int32) int32
+TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
+       MOVW    timerid+0(FP), A0
+       MOV     $SYS_timer_delete, A7
+       ECALL
+       MOVW    A0, ret+8(FP)
+       RET
+
 // func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
 TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
        MOV     addr+0(FP), A0
@@ -220,8 +244,68 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
        RET
 
 // func walltime() (sec int64, nsec int32)
-TEXT runtime·walltime(SB),NOSPLIT,$24-12
-       MOV     $0, A0 // CLOCK_REALTIME
+TEXT runtime·walltime(SB),NOSPLIT,$40-12
+       MOV     $CLOCK_REALTIME, A0
+
+       MOV     runtime·vdsoClockgettimeSym(SB), A7
+       BEQZ    A7, fallback
+       MOV     X2, S2 // S2,S3,S4 is unchanged by C code
+       MOV     g_m(g), S3 // S3 = m
+
+       // Save the old values on stack for reentrant
+       MOV     m_vdsoPC(S3), T0
+       MOV     T0, 24(X2)
+       MOV     m_vdsoSP(S3), T0
+       MOV     T0, 32(X2)
+
+       MOV     RA, m_vdsoPC(S3)
+       MOV     $ret-8(FP), T1 // caller's SP
+       MOV     T1, m_vdsoSP(S3)
+
+       MOV     m_curg(S3), T1
+       BNE     g, T1, noswitch
+
+       MOV     m_g0(S3), T1
+       MOV     (g_sched+gobuf_sp)(T1), X2
+
+noswitch:
+       ADDI    $-24, X2 // Space for result
+       ANDI    $~7, X2 // Align for C code
+       MOV     $8(X2), A1
+
+       // Store g on gsignal's stack, see sys_linux_arm64.s for detail
+       MOVBU   runtime·iscgo(SB), S4
+       BNEZ    S4, nosaveg
+       MOV     m_gsignal(S3), S4 // g.m.gsignal
+       BEQZ    S4, nosaveg
+       BEQ     g, S4, nosaveg
+       MOV     (g_stack+stack_lo)(S4), S4 // g.m.gsignal.stack.lo
+       MOV     g, (S4)
+
+       JALR    RA, A7
+
+       MOV     ZERO, (S4)
+       JMP     finish
+
+nosaveg:
+       JALR    RA, A7
+
+finish:
+       MOV     8(X2), T0       // sec
+       MOV     16(X2), T1      // nsec
+
+       MOV     S2, X2  // restore stack
+       MOV     24(X2), A2
+       MOV     A2, m_vdsoPC(S3)
+
+       MOV     32(X2), A3
+       MOV     A3, m_vdsoSP(S3)
+
+       MOV     T0, sec+0(FP)
+       MOVW    T1, nsec+8(FP)
+       RET
+
+fallback:
        MOV     $8(X2), A1
        MOV     $SYS_clock_gettime, A7
        ECALL
@@ -232,13 +316,62 @@ TEXT runtime·walltime(SB),NOSPLIT,$24-12
        RET
 
 // func nanotime1() int64
-TEXT runtime·nanotime1(SB),NOSPLIT,$24-8
-       MOV     $1, A0 // CLOCK_MONOTONIC
+TEXT runtime·nanotime1(SB),NOSPLIT,$40-8
+       MOV     $CLOCK_MONOTONIC, A0
+
+       MOV     runtime·vdsoClockgettimeSym(SB), A7
+       BEQZ    A7, fallback
+
+       MOV     X2, S2 // S2 = RSP, S2 is unchanged by C code
+       MOV     g_m(g), S3 // S3 = m
+       // Save the old values on stack for reentrant
+       MOV     m_vdsoPC(S3), T0
+       MOV     T0, 24(X2)
+       MOV     m_vdsoSP(S3), T0
+       MOV     T0, 32(X2)
+
+       MOV     RA, m_vdsoPC(S3)
+       MOV     $ret-8(FP), T0 // caller's SP
+       MOV     T0, m_vdsoSP(S3)
+
+       MOV     m_curg(S3), T1
+       BNE     g, T1, noswitch
+
+       MOV     m_g0(S3), T1
+       MOV     (g_sched+gobuf_sp)(T1), X2
+
+noswitch:
+       ADDI    $-24, X2 // Space for result
+       ANDI    $~7, X2 // Align for C code
        MOV     $8(X2), A1
-       MOV     $SYS_clock_gettime, A7
-       ECALL
+
+       // Store g on gsignal's stack, see sys_linux_arm64.s for detail
+       MOVBU   runtime·iscgo(SB), S4
+       BNEZ    S4, nosaveg
+       MOV     m_gsignal(S3), S4 // g.m.gsignal
+       BEQZ    S4, nosaveg
+       BEQ     g, S4, nosaveg
+       MOV     (g_stack+stack_lo)(S4), S4 // g.m.gsignal.stack.lo
+       MOV     g, (S4)
+
+       JALR    RA, A7
+
+       MOV     ZERO, (S4)
+       JMP     finish
+
+nosaveg:
+       JALR    RA, A7
+
+finish:
        MOV     8(X2), T0       // sec
        MOV     16(X2), T1      // nsec
+       // restore stack
+       MOV     S2, X2
+       MOV     24(X2), T2
+       MOV     T2, m_vdsoPC(S3)
+
+       MOV     32(X2), T2
+       MOV     T2, m_vdsoSP(S3)
        // sec is in T0, nsec in T1
        // return nsec in T0
        MOV     $1000000000, T2
@@ -247,6 +380,18 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$24-8
        MOV     T0, ret+0(FP)
        RET
 
+fallback:
+       MOV     $8(X2), A1
+       MOV     $SYS_clock_gettime, A7
+       ECALL
+       MOV     8(X2), T0       // sec
+       MOV     16(X2), T1      // nsec
+       MOV     $1000000000, T2
+       MUL     T2, T0
+       ADD     T1, T0
+       MOV     T0, ret+0(FP)
+       RET
+
 // func rtsigprocmask(how int32, new, old *sigset, size int32)
 TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
        MOVW    how+0(FP), A0
index 916dfada8d58e68d6f91d5097d53d80d3b76bacb..886add8b543b3c927db0e362f535a1c90ec6d1cb 100644 (file)
@@ -39,6 +39,9 @@
 #define SYS_epoll_create        249
 #define SYS_epoll_ctl           250
 #define SYS_epoll_wait          251
+#define SYS_timer_create        254
+#define SYS_timer_settime       255
+#define SYS_timer_delete        258
 #define SYS_clock_gettime       260
 #define SYS_pipe2              325
 #define SYS_epoll_create1       327
@@ -185,6 +188,32 @@ TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
        SYSCALL
        RET
 
+TEXT runtime·timer_create(SB),NOSPLIT|NOFRAME,$0-28
+       MOVW    clockid+0(FP), R2
+       MOVD    sevp+8(FP), R3
+       MOVD    timerid+16(FP), R4
+       MOVW    $SYS_timer_create, R1
+       SYSCALL
+       MOVW    R2, ret+24(FP)
+       RET
+
+TEXT runtime·timer_settime(SB),NOSPLIT|NOFRAME,$0-28
+       MOVW    timerid+0(FP), R2
+       MOVW    flags+4(FP), R3
+       MOVD    new+8(FP), R4
+       MOVD    old+16(FP), R5
+       MOVW    $SYS_timer_settime, R1
+       SYSCALL
+       MOVW    R2, ret+24(FP)
+       RET
+
+TEXT runtime·timer_delete(SB),NOSPLIT|NOFRAME,$0-12
+       MOVW    timerid+0(FP), R2
+       MOVW    $SYS_timer_delete, R1
+       SYSCALL
+       MOVW    R2, ret+8(FP)
+       RET
+
 TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
        MOVD    addr+0(FP), R2
        MOVD    n+8(FP), R3
index 842a4a7084ffe6303cd7fa6f1fda7bd2c781ebc4..b71538409c6fcf38ecc8f3b94dbee1dceb946417 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips64 || mips64le
-// +build mips64 mips64le
 
 package runtime
 
index 2038eb7d794f9a7b27534b2c9654b319d8fb482d..b60135f9649d449a083cac512b723dfcf2684994 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build mips || mipsle
-// +build mips mipsle
 
 package runtime
 
index 66821b1f76b06dfe7bee306c66d3cb7cbbd05a06..653f1c999f0ad936843163d6fb01c7d9c99f0476 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !ppc64 && !ppc64le
-// +build !ppc64,!ppc64le
 
 package runtime
 
index 15888619b1790b6aaf8d40717416778850e9d5cc..9f3a25fcf80daa3893ff561f7721617444b909f7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && !mips64
-// +build openbsd,!mips64
 
 package runtime
 
index b4e9f54538e02ee14e16ea242307980c275c796c..4b80f60226aa6db1576c6809b0cec76ee25cb260 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && !mips64
-// +build openbsd,!mips64
 
 package runtime
 
index 190ee4716a6c5ab69d8050ce6183a1f14c759e49..7024cfa86d22fd5b72a72989e405a61e4a02138e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && !mips64
-// +build openbsd,!mips64
 
 package runtime
 
@@ -199,7 +198,9 @@ func sigaction_trampoline()
 //go:nosplit
 //go:cgo_unsafe_args
 func sigprocmask(how uint32, new *sigset, old *sigset) {
-       libcCall(unsafe.Pointer(abi.FuncPCABI0(sigprocmask_trampoline)), unsafe.Pointer(&how))
+       // sigprocmask is called from sigsave, which is called from needm.
+       // As such, we have to be able to run with no g here.
+       asmcgocall_no_g(unsafe.Pointer(abi.FuncPCABI0(sigprocmask_trampoline)), unsafe.Pointer(&how))
 }
 func sigprocmask_trampoline()
 
index a917ebde6108a99be3df2374bcbf8a9248a0111c..269bf86f10de43ca22e0f868d777492f556adafd 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && !mips64
-// +build openbsd,!mips64
 
 package runtime
 
index 39fc4c68e4ce969632c34ec14a650ec3b97ca9d7..638300dfb935481b786d84beeaa4716a1cf01536 100644 (file)
@@ -94,7 +94,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
        MOVQ    0(SP), AX
 
        // generated code for
-       //      func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
+       //      func f(x uint64) (uint64, uint64) { return x/1000000000, x%1000000000 }
        // adapted to reduce duplication
        MOVQ    AX, CX
        MOVQ    $1360296554856532783, AX
index 69bd99fa09e11de792dc517de2de61bb75992557..56c5c9575e550371827abf5a60f99adf598356eb 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ppc64 || ppc64le
-// +build ppc64 ppc64le
 
 package runtime
 
index 6cc5bba2b7378b4dd76d53965bc88a1b2c1ca505..1467b4d57bf01b9d7ef50c80f3dac851094a287e 100644 (file)
@@ -8,10 +8,6 @@
 #include "time_windows.h"
 #include "cgo/abi_amd64.h"
 
-// maxargs should be divisible by 2, as Windows stack
-// must be kept 16-byte aligned on syscall entry.
-#define maxargs 18
-
 // void runtime·asmstdcall(void *c);
 TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
        // asmcgocall will put first argument into CX.
@@ -24,14 +20,14 @@ TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
        MOVQ    0x30(GS), DI
        MOVL    $0, 0x68(DI)
 
-       SUBQ    $(maxargs*8), SP        // room for args
+       SUBQ    $(const_maxArgs*8), SP  // room for args
 
        // Fast version, do not store args on the stack.
        CMPL    CX, $4
        JLE     loadregs
 
        // Check we have enough room for args.
-       CMPL    CX, $maxargs
+       CMPL    CX, $const_maxArgs
        JLE     2(PC)
        INT     $3                      // not enough room -> crash
 
@@ -59,7 +55,7 @@ loadregs:
        // Call stdcall function.
        CALL    AX
 
-       ADDQ    $(maxargs*8), SP
+       ADDQ    $(const_maxArgs*8), SP
 
        // Return result.
        POPQ    CX
@@ -348,16 +344,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
        CMPB    runtime·useQPCTime(SB), $0
        JNE     useQPC
        MOVQ    $_INTERRUPT_TIME, DI
-loop:
-       MOVL    time_hi1(DI), AX
-       MOVL    time_lo(DI), BX
-       MOVL    time_hi2(DI), CX
-       CMPL    AX, CX
-       JNE     loop
-       SHLQ    $32, CX
-       ORQ     BX, CX
-       IMULQ   $100, CX
-       MOVQ    CX, ret+0(FP)
+       MOVQ    time_lo(DI), AX
+       IMULQ   $100, AX
+       MOVQ    AX, ret+0(FP)
        RET
 useQPC:
        JMP     runtime·nanotimeQPC(SB)
index c9e96cb6522a1536f76977cc1a9b3facfa77543a..e5b1b7e9f358f21e6684e2a4dc468a4729b2fb62 100644 (file)
@@ -350,7 +350,9 @@ TEXT runtime·nanotime1(SB),NOSPLIT|NOFRAME,$0-8
        MOVW    $_INTERRUPT_TIME, R3
 loop:
        MOVW    time_hi1(R3), R1
+       DMB     MB_ISH
        MOVW    time_lo(R3), R0
+       DMB     MB_ISH
        MOVW    time_hi2(R3), R2
        CMP     R1, R2
        BNE     loop
index 44145c53fb7ee8e0822fef94b64af6b7fcd55253..87f8f0d2183a22d1beaa4988383f3284ca5e3767 100644 (file)
@@ -415,15 +415,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT|NOFRAME,$0-8
        CMP     $0, R0
        BNE     useQPC
        MOVD    $_INTERRUPT_TIME, R3
-loop:
-       MOVWU   time_hi1(R3), R1
-       MOVWU   time_lo(R3), R0
-       MOVWU   time_hi2(R3), R2
-       CMP     R1, R2
-       BNE     loop
-
-       // wintime = R1:R0, multiply by 100
-       ORR     R1<<32, R0
+       MOVD    time_lo(R3), R0
        MOVD    $100, R1
        MUL     R1, R0
        MOVD    R0, ret+0(FP)
index 856c73a2f6c84625a3b62dfbbfe35009cb380ccf..9fb36c2a661d5c3d9c2505e1aeb950d905f19a33 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 || 386
-// +build amd64 386
 
 package runtime
 
index e872d74e97fc6cded5ffcdaa02f58c1181578223..da181f2a8d416ad9aeacc0de4974da17f23881ff 100644 (file)
@@ -468,84 +468,69 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint
 
 //go:linkname syscall_Syscall syscall.Syscall
 //go:nosplit
-//go:cgo_unsafe_args
 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
-       lockOSThread()
-       defer unlockOSThread()
-       c := &getg().m.syscall
-       c.fn = fn
-       c.n = nargs
-       c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-       cgocall(asmstdcallAddr, unsafe.Pointer(c))
-       return c.r1, c.r2, c.err
+       return syscall_SyscallN(fn, a1, a2, a3)
 }
 
 //go:linkname syscall_Syscall6 syscall.Syscall6
 //go:nosplit
-//go:cgo_unsafe_args
 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
-       lockOSThread()
-       defer unlockOSThread()
-       c := &getg().m.syscall
-       c.fn = fn
-       c.n = nargs
-       c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-       cgocall(asmstdcallAddr, unsafe.Pointer(c))
-       return c.r1, c.r2, c.err
+       return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6)
 }
 
 //go:linkname syscall_Syscall9 syscall.Syscall9
 //go:nosplit
-//go:cgo_unsafe_args
 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
-       lockOSThread()
-       c := &getg().m.syscall
-       c.fn = fn
-       c.n = nargs
-       c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-       cgocall(asmstdcallAddr, unsafe.Pointer(c))
-       unlockOSThread()
-       return c.r1, c.r2, c.err
+       return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9)
 }
 
 //go:linkname syscall_Syscall12 syscall.Syscall12
 //go:nosplit
-//go:cgo_unsafe_args
 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
-       lockOSThread()
-       c := &getg().m.syscall
-       c.fn = fn
-       c.n = nargs
-       c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-       cgocall(asmstdcallAddr, unsafe.Pointer(c))
-       unlockOSThread()
-       return c.r1, c.r2, c.err
+       return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
 }
 
 //go:linkname syscall_Syscall15 syscall.Syscall15
 //go:nosplit
-//go:cgo_unsafe_args
 func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
-       lockOSThread()
-       c := &getg().m.syscall
-       c.fn = fn
-       c.n = nargs
-       c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-       cgocall(asmstdcallAddr, unsafe.Pointer(c))
-       unlockOSThread()
-       return c.r1, c.r2, c.err
+       return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
 }
 
 //go:linkname syscall_Syscall18 syscall.Syscall18
 //go:nosplit
-//go:cgo_unsafe_args
 func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) {
+       return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
+}
+
+// maxArgs should be divisible by 2, as Windows stack
+// must be kept 16-byte aligned on syscall entry.
+//
+// Although it only permits maximum 42 parameters, it
+// is arguably large enough.
+const maxArgs = 42
+
+//go:linkname syscall_SyscallN syscall.SyscallN
+//go:nosplit
+func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
+       nargs := len(args)
+
+       // asmstdcall expects it can access the first 4 arguments
+       // to load them into registers.
+       var tmp [4]uintptr
+       switch {
+       case nargs < 4:
+               copy(tmp[:], args)
+               args = tmp[:]
+       case nargs > maxArgs:
+               panic("runtime: SyscallN has too many arguments")
+       }
+
        lockOSThread()
+       defer unlockOSThread()
        c := &getg().m.syscall
-       c.fn = fn
-       c.n = nargs
-       c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+       c.fn = trap
+       c.n = uintptr(nargs)
+       c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
        cgocall(asmstdcallAddr, unsafe.Pointer(c))
-       unlockOSThread()
        return c.r1, c.r2, c.err
 }
index e3f772ac4bb9457a5ed94ff944cfc466b67afca2..65f74b32fb75f8b87a8e5323c878bc66987610f5 100644 (file)
@@ -759,7 +759,7 @@ uintptr_t cfunc(callback f, uintptr_t n) {
        }
 }
 
-func TestSyscall18(t *testing.T) {
+func TestSyscallN(t *testing.T) {
        if _, err := exec.LookPath("gcc"); err != nil {
                t.Skip("skipping test: gcc is missing")
        }
@@ -767,40 +767,51 @@ func TestSyscall18(t *testing.T) {
                t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
        }
 
-       const src = `
-#include <stdint.h>
-#include <windows.h>
+       for arglen := 0; arglen <= runtime.MaxArgs; arglen++ {
+               arglen := arglen
+               t.Run(fmt.Sprintf("arg-%d", arglen), func(t *testing.T) {
+                       args := make([]string, arglen)
+                       rets := make([]string, arglen+1)
+                       params := make([]uintptr, arglen)
+                       for i := range args {
+                               args[i] = fmt.Sprintf("int a%d", i)
+                               rets[i] = fmt.Sprintf("(a%d == %d)", i, i)
+                               params[i] = uintptr(i)
+                       }
+                       rets[arglen] = "1" // for arglen == 0
 
-int cfunc(     int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9,
-                       int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18) {
-       return 1;
-}
-`
-       tmpdir := t.TempDir()
+                       src := fmt.Sprintf(`
+               #include <stdint.h>
+               #include <windows.h>
+               int cfunc(%s) { return %s; }`, strings.Join(args, ", "), strings.Join(rets, " && "))
 
-       srcname := "mydll.c"
-       err := os.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0)
-       if err != nil {
-               t.Fatal(err)
-       }
-       outname := "mydll.dll"
-       cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname)
-       cmd.Dir = tmpdir
-       out, err := cmd.CombinedOutput()
-       if err != nil {
-               t.Fatalf("failed to build dll: %v - %v", err, string(out))
-       }
-       dllpath := filepath.Join(tmpdir, outname)
+                       tmpdir := t.TempDir()
 
-       dll := syscall.MustLoadDLL(dllpath)
-       defer dll.Release()
+                       srcname := "mydll.c"
+                       err := os.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       outname := "mydll.dll"
+                       cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname)
+                       cmd.Dir = tmpdir
+                       out, err := cmd.CombinedOutput()
+                       if err != nil {
+                               t.Fatalf("failed to build dll: %v\n%s", err, out)
+                       }
+                       dllpath := filepath.Join(tmpdir, outname)
 
-       proc := dll.MustFindProc("cfunc")
+                       dll := syscall.MustLoadDLL(dllpath)
+                       defer dll.Release()
 
-       // proc.Call() will call Syscall18() internally.
-       r, _, err := proc.Call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
-       if r != 1 {
-               t.Errorf("got %d want 1 (err=%v)", r, err)
+                       proc := dll.MustFindProc("cfunc")
+
+                       // proc.Call() will call SyscallN() internally.
+                       r, _, err := proc.Call(params...)
+                       if r != 1 {
+                               t.Errorf("got %d want 1 (err=%v)", r, err)
+                       }
+               })
        }
 }
 
index 9c5561396e5d43b335c3b270201025809c307f1c..b27e5f74f868f3db8c31d60d745feac20f085cc8 100644 (file)
@@ -20,6 +20,7 @@ func init() {
        register("CheckPtrSmall", CheckPtrSmall)
        register("CheckPtrSliceOK", CheckPtrSliceOK)
        register("CheckPtrSliceFail", CheckPtrSliceFail)
+       register("CheckPtrAlignmentNested", CheckPtrAlignmentNested)
 }
 
 func CheckPtrAlignmentNoPtr() {
@@ -96,3 +97,10 @@ func CheckPtrSliceFail() {
        sink2 = p
        sink2 = unsafe.Slice(p, 100)
 }
+
+func CheckPtrAlignmentNested() {
+       s := make([]int8, 100)
+       p := unsafe.Pointer(&s[0])
+       n := 9
+       _ = ((*[10]int8)(unsafe.Pointer((*[10]int64)(unsafe.Pointer(&p)))))[:n:n]
+}
index aff36ec702b0660ce2b5d4597cea9c093f13fc50..7209f67959a0a293705c36a147bd1a8be900774d 100644 (file)
@@ -85,19 +85,18 @@ func getList() ([]string, error) {
        if err != nil {
                return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err)
        }
-       pos := bytes.IndexRune(output, '\n')
-       if pos == -1 {
+       output, _, ok := bytes.Cut(output, []byte("\n"))
+       if !ok {
                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 {
+       _, cpus, ok := bytes.Cut(output, []byte(":"))
+       if !ok {
                return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output)
        }
 
        var list []string
-       for _, val := range bytes.Split(output[pos+1:], []byte(",")) {
+       for _, val := range bytes.Split(cpus, []byte(",")) {
                index := string(bytes.TrimSpace(val))
                if len(index) == 0 {
                        continue
index 0ee402c4bdc60837db2f12d20c53d001f9a51f5c..1d0d00bab7d4ae48cc8fd81d7bd33e9e90e3debe 100644 (file)
@@ -33,30 +33,27 @@ func printStack() {
        for {
                n := runtime.Stack(buf, true)
                if n < len(buf) {
-                       tb := string(buf[:n])
+                       all := string(buf[:n])
+                       var saved string
 
                        // Delete any ignored goroutines, if present.
-                       pos := 0
-                       for pos < len(tb) {
-                               next := pos + strings.Index(tb[pos:], "\n\n")
-                               if next < pos {
-                                       next = len(tb)
-                               } else {
-                                       next += len("\n\n")
-                               }
+                       for all != "" {
+                               var g string
+                               g, all, _ = strings.Cut(all, "\n\n")
 
-                               if strings.HasPrefix(tb[pos:], "goroutine ") {
-                                       id := tb[pos+len("goroutine "):]
-                                       id = id[:strings.IndexByte(id, ' ')]
+                               if strings.HasPrefix(g, "goroutine ") {
+                                       id, _, _ := strings.Cut(strings.TrimPrefix(g, "goroutine "), " ")
                                        if ignoreGoroutines[id] {
-                                               tb = tb[:pos] + tb[next:]
-                                               next = pos
+                                               continue
                                        }
                                }
-                               pos = next
+                               if saved != "" {
+                                       saved += "\n\n"
+                               }
+                               saved += g
                        }
 
-                       fmt.Print(tb)
+                       fmt.Print(saved)
                        return
                }
                buf = make([]byte, 2*len(buf))
@@ -89,11 +86,10 @@ func recurseThenCallGo(w chan struct{}, frames int, goroutines int, main bool) {
 func goroutineID() string {
        buf := make([]byte, 128)
        runtime.Stack(buf, false)
-       const prefix = "goroutine "
-       if !bytes.HasPrefix(buf, []byte(prefix)) {
+       prefix := []byte("goroutine ")
+       if !bytes.HasPrefix(buf, prefix) {
                panic(fmt.Sprintf("expected %q at beginning of traceback:\n%s", prefix, buf))
        }
-       buf = buf[len(prefix):]
-       n := bytes.IndexByte(buf, ' ')
-       return string(buf[:n])
+       id, _, _ := bytes.Cut(bytes.TrimPrefix(buf, prefix), []byte(" "))
+       return string(id)
 }
diff --git a/src/runtime/testdata/testprogcgo/panic.c b/src/runtime/testdata/testprogcgo/panic.c
new file mode 100644 (file)
index 0000000..deb5ed5
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+extern void panic_callback();
+
+void call_callback(void) {
+       panic_callback();
+}
diff --git a/src/runtime/testdata/testprogcgo/panic.go b/src/runtime/testdata/testprogcgo/panic.go
new file mode 100644 (file)
index 0000000..57ac895
--- /dev/null
@@ -0,0 +1,23 @@
+package main
+
+// This program will crash.
+// We want to test unwinding from a cgo callback.
+
+/*
+void call_callback(void);
+*/
+import "C"
+
+func init() {
+       register("PanicCallback", PanicCallback)
+}
+
+//export panic_callback
+func panic_callback() {
+       var i *int
+       *i = 42
+}
+
+func PanicCallback() {
+       C.call_callback()
+}
diff --git a/src/runtime/testdata/testprogcgo/sigthrow.go b/src/runtime/testdata/testprogcgo/sigthrow.go
new file mode 100644 (file)
index 0000000..665e3b0
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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
+
+// This program will abort.
+
+/*
+#include <stdlib.h>
+*/
+import "C"
+
+func init() {
+       register("Abort", Abort)
+}
+
+func Abort() {
+       C.abort()
+}
index ad267c336564f68c78e65d4236421710eb568f8a..46e9a8c2abb7e1aaac49d4f2feff57d322defc5a 100644 (file)
@@ -367,9 +367,9 @@ func deltimer(t *timer) bool {
 
 // dodeltimer removes timer i from the current P's heap.
 // We are locked on the P when this is called.
-// It reports whether it saw no problems due to races.
+// It returns the smallest changed index in pp.timers.
 // The caller must have locked the timers for pp.
-func dodeltimer(pp *p, i int) {
+func dodeltimer(pp *p, i int) int {
        if t := pp.timers[i]; t.pp.ptr() != pp {
                throw("dodeltimer: wrong P")
        } else {
@@ -381,16 +381,18 @@ func dodeltimer(pp *p, i int) {
        }
        pp.timers[last] = nil
        pp.timers = pp.timers[:last]
+       smallestChanged := i
        if i != last {
                // Moving to i may have moved the last timer to a new parent,
                // so sift up to preserve the heap guarantee.
-               siftupTimer(pp.timers, i)
+               smallestChanged = siftupTimer(pp.timers, i)
                siftdownTimer(pp.timers, i)
        }
        if i == 0 {
                updateTimer0When(pp)
        }
        atomic.Xadd(&pp.numTimers, -1)
+       return smallestChanged
 }
 
 // dodeltimer0 removes timer 0 from the current P's heap.
@@ -675,13 +677,14 @@ func adjusttimers(pp *p, now int64) {
                switch s := atomic.Load(&t.status); s {
                case timerDeleted:
                        if atomic.Cas(&t.status, s, timerRemoving) {
-                               dodeltimer(pp, i)
+                               changed := dodeltimer(pp, i)
                                if !atomic.Cas(&t.status, timerRemoving, timerRemoved) {
                                        badTimer()
                                }
                                atomic.Xadd(&pp.deletedTimers, -1)
-                               // Look at this heap position again.
-                               i--
+                               // Go back to the earliest changed heap entry.
+                               // "- 1" because the loop will add 1.
+                               i = changed - 1
                        }
                case timerModifiedEarlier, timerModifiedLater:
                        if atomic.Cas(&t.status, s, timerMoving) {
@@ -691,10 +694,11 @@ func adjusttimers(pp *p, now int64) {
                                // We don't add it back yet because the
                                // heap manipulation could cause our
                                // loop to skip some other timer.
-                               dodeltimer(pp, i)
+                               changed := dodeltimer(pp, i)
                                moved = append(moved, t)
-                               // Look at this heap position again.
-                               i--
+                               // Go back to the earliest changed heap entry.
+                               // "- 1" because the loop will add 1.
+                               i = changed - 1
                        }
                case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving:
                        badTimer()
@@ -1044,7 +1048,10 @@ func timeSleepUntil() (int64, *p) {
 // "panic holding locks" message. Instead, we panic while not
 // holding a lock.
 
-func siftupTimer(t []*timer, i int) {
+// siftupTimer puts the timer at position i in the right place
+// in the heap by moving it up toward the top of the heap.
+// It returns the smallest changed index.
+func siftupTimer(t []*timer, i int) int {
        if i >= len(t) {
                badTimer()
        }
@@ -1064,8 +1071,11 @@ func siftupTimer(t []*timer, i int) {
        if tmp != t[i] {
                t[i] = tmp
        }
+       return i
 }
 
+// siftdownTimer puts the timer at position i in the right place
+// in the heap by moving it down toward the bottom of the heap.
 func siftdownTimer(t []*timer, i int) {
        n := len(t)
        if i >= n {
index c790faba3d6b75744b7a9afdba58e2c22183ede0..107f6be335a2df132122a994cdd0b20ac7722b06 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build faketime && !windows
-// +build faketime,!windows
 
 // Faketime isn't currently supported on Windows. This would require
 // modifying syscall.Write to call syscall.faketimeWrite,
index c88e92bd0cab904074c0890a4f9f662509310cb0..67cfdd8fdffb8b5530c70a37f2b0e8d7b716fef0 100644 (file)
 #define SYS_clock_gettime      228
 
 // func time.now() (sec int64, nsec int32, mono int64)
-TEXT time·now(SB),NOSPLIT,$16-24
+TEXT time·now<ABIInternal>(SB),NOSPLIT,$16-24
        MOVQ    SP, R12 // Save old SP; R12 unchanged by C code.
 
        MOVQ    g_m(R14), BX // BX unchanged by C code.
 
-       // Store CLOCK_REALTIME results directly to return space.
-       LEAQ    sec+0(FP), SI
-
        // Set vdsoPC and vdsoSP for SIGPROF traceback.
        // Save the old values on stack and restore them on exit,
        // so this function is reentrant.
@@ -28,9 +25,10 @@ TEXT time·now(SB),NOSPLIT,$16-24
        MOVQ    CX, 0(SP)
        MOVQ    DX, 8(SP)
 
-       MOVQ    -8(SI), CX      // Sets CX to function return address.
+       LEAQ    sec+0(FP), DX
+       MOVQ    -8(DX), CX      // Sets CX to function return address.
        MOVQ    CX, m_vdsoPC(BX)
-       MOVQ    SI, m_vdsoSP(BX)
+       MOVQ    DX, m_vdsoSP(BX)
 
        CMPQ    R14, m_curg(BX) // Only switch if on curg.
        JNE     noswitch
@@ -39,10 +37,11 @@ TEXT time·now(SB),NOSPLIT,$16-24
        MOVQ    (g_sched+gobuf_sp)(DX), SP      // Set SP to g0 stack
 
 noswitch:
-       SUBQ    $16, SP         // Space for monotonic time results
+       SUBQ    $32, SP         // Space for two time results
        ANDQ    $~15, SP        // Align for C code
 
        MOVL    $0, DI // CLOCK_REALTIME
+       LEAQ    16(SP), SI
        MOVQ    runtime·vdsoClockgettimeSym(SB), AX
        CMPQ    AX, $0
        JEQ     fallback
@@ -54,25 +53,27 @@ noswitch:
        CALL    AX
 
 ret:
-       MOVQ    0(SP), AX       // sec
-       MOVQ    8(SP), DX       // nsec
+       MOVQ    16(SP), AX      // realtime sec
+       MOVQ    24(SP), DI      // realtime nsec (moved to BX below)
+       MOVQ    0(SP), CX       // monotonic sec
+       IMULQ   $1000000000, CX
+       MOVQ    8(SP), DX       // monotonic nsec
 
        MOVQ    R12, SP         // Restore real SP
+
        // Restore vdsoPC, vdsoSP
        // We don't worry about being signaled between the two stores.
        // If we are not in a signal handler, we'll restore vdsoSP to 0,
        // and no one will care about vdsoPC. If we are in a signal handler,
        // we cannot receive another signal.
-       MOVQ    8(SP), CX
-       MOVQ    CX, m_vdsoSP(BX)
-       MOVQ    0(SP), CX
-       MOVQ    CX, m_vdsoPC(BX)
+       MOVQ    8(SP), SI
+       MOVQ    SI, m_vdsoSP(BX)
+       MOVQ    0(SP), SI
+       MOVQ    SI, m_vdsoPC(BX)
 
-       // sec is in AX, nsec in DX
-       // return nsec in AX
-       IMULQ   $1000000000, AX
-       ADDQ    DX, AX
-       MOVQ    AX, mono+16(FP)
+       // set result registers; AX is already correct
+       MOVQ    DI, BX
+       ADDQ    DX, CX
        RET
 
 fallback:
index 5a4ceaf43d280ceacd4fec036405316ae0f32ea1..70a2102b22e84c2f43c904a1bb302823220363c3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !faketime
-// +build !faketime
 
 package runtime
 
@@ -20,9 +19,14 @@ func nanotime() int64 {
        return nanotime1()
 }
 
+var overrideWrite func(fd uintptr, p unsafe.Pointer, n int32) int32
+
 // write must be nosplit on Windows (see write1)
 //
 //go:nosplit
 func write(fd uintptr, p unsafe.Pointer, n int32) int32 {
+       if overrideWrite != nil {
+               return overrideWrite(fd, noescape(p), n)
+       }
        return write1(fd, p, n)
 }
index cd16fd163bb42963272f07fa512ed95a21fd33b7..7c2e65c328b82a1d8b8468e1271033b2a04eb661 100644 (file)
@@ -9,6 +9,7 @@
 // http://web.archive.org/web/20210411000829/https://wrkhpi.wordpress.com/2007/08/09/getting-os-information-the-kuser_shared_data-structure/
 
 // Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
+// Or, on 64-bit, just read lo:hi1 all at once atomically.
 #define _INTERRUPT_TIME 0x7ffe0008
 #define _SYSTEM_TIME 0x7ffe0014
 #define time_lo 0
index 93ab960b067cd5a810d27effdb31cf84712792bd..70f6a008cddcec563802d8fcbf927b2ff959e70a 100644 (file)
 TEXT time·now(SB),NOSPLIT,$0-24
        CMPB    runtime·useQPCTime(SB), $0
        JNE     useQPC
+
        MOVQ    $_INTERRUPT_TIME, DI
-loop:
-       MOVL    time_hi1(DI), AX
-       MOVL    time_lo(DI), BX
-       MOVL    time_hi2(DI), CX
-       CMPL    AX, CX
-       JNE     loop
-       SHLQ    $32, AX
-       ORQ     BX, AX
+       MOVQ    time_lo(DI), AX
        IMULQ   $100, AX
        MOVQ    AX, mono+16(FP)
 
        MOVQ    $_SYSTEM_TIME, DI
-wall:
-       MOVL    time_hi1(DI), AX
-       MOVL    time_lo(DI), BX
-       MOVL    time_hi2(DI), CX
-       CMPL    AX, CX
-       JNE     wall
-       SHLQ    $32, AX
-       ORQ     BX, AX
+       MOVQ    time_lo(DI), AX
        MOVQ    $116444736000000000, DI
        SUBQ    DI, AX
        IMULQ   $100, AX
 
        // generated code for
-       //      func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
+       //      func f(x uint64) (uint64, uint64) { return x/1000000000, x%1000000000 }
        // adapted to reduce duplication
        MOVQ    AX, CX
        MOVQ    $1360296554856532783, AX
index 7c763b66edd2f6b4716f67bc5987a2f5e69ab915..6552d75ff1ce5355bcfb3fab1bacbb2c9fd3cb83 100644 (file)
@@ -17,7 +17,9 @@ TEXT time·now(SB),NOSPLIT|NOFRAME,$0-20
        MOVW    $_INTERRUPT_TIME, R3
 loop:
        MOVW    time_hi1(R3), R1
+       DMB     MB_ISH
        MOVW    time_lo(R3), R0
+       DMB     MB_ISH
        MOVW    time_hi2(R3), R2
        CMP     R1, R2
        BNE     loop
@@ -34,7 +36,9 @@ loop:
        MOVW    $_SYSTEM_TIME, R3
 wall:
        MOVW    time_hi1(R3), R1
+       DMB     MB_ISH
        MOVW    time_lo(R3), R0
+       DMB     MB_ISH
        MOVW    time_hi2(R3), R2
        CMP     R1, R2
        BNE     wall
index ef52ce4c99441eb02c5c00a933e9d0be44fffc88..ef5b84847379fb217cd0f8db136ae7a992827413 100644 (file)
@@ -13,34 +13,18 @@ TEXT time·now(SB),NOSPLIT|NOFRAME,$0-24
        MOVB    runtime·useQPCTime(SB), R0
        CMP     $0, R0
        BNE     useQPC
-       MOVD    $_INTERRUPT_TIME, R3
-loop:
-       MOVWU   time_hi1(R3), R1
-       MOVWU   time_lo(R3), R0
-       MOVWU   time_hi2(R3), R2
-       CMP     R1, R2
-       BNE     loop
 
-       // wintime = R1:R0, multiply by 100
-       ORR     R1<<32, R0
+       MOVD    $_INTERRUPT_TIME, R3
+       MOVD    time_lo(R3), R0
        MOVD    $100, R1
        MUL     R1, R0
        MOVD    R0, mono+16(FP)
 
        MOVD    $_SYSTEM_TIME, R3
-wall:
-       MOVWU   time_hi1(R3), R1
-       MOVWU   time_lo(R3), R0
-       MOVWU   time_hi2(R3), R2
-       CMP     R1, R2
-       BNE     wall
-
-       // w = R1:R0 in 100ns units
+       MOVD    time_lo(R3), R0
        // convert to Unix epoch (but still 100ns units)
        #define delta 116444736000000000
-       ORR     R1<<32, R0
        SUB     $delta, R0
-
        // Convert to nSec
        MOVD    $100, R1
        MUL     R1, R0
@@ -48,17 +32,14 @@ wall:
        // Code stolen from compiler output for:
        //
        //      var x uint64
-       //      func f() (sec uint64, nsec uint32) { return x / 1000000000, uint32(x % 100000000) }
+       //      func f() (sec uint64, nsec uint32) { return x / 1000000000, uint32(x % 1000000000) }
        //
        LSR     $1, R0, R1
        MOVD    $-8543223759426509416, R2
-       UMULH   R2, R1, R1
+       UMULH   R1, R2, R1
        LSR     $28, R1, R1
        MOVD    R1, sec+0(FP)
-       MOVD    $-6067343680855748867, R1
-       UMULH   R0, R1, R1
-       LSR     $26, R1, R1
-       MOVD    $100000000, R2
+       MOVD    $1000000000, R2
        MSUB    R1, R0, R2, R0
        MOVW    R0, nsec+8(FP)
        RET
index 468ff8a0d33dcdbcdd2c0c6c37c23101e59fa8ca..0421388686a253fa4e19dd6d1ccf55f22f56886c 100644 (file)
@@ -5,8 +5,6 @@
 // Declarations for operating systems implementing time.now directly in assembly.
 
 //go:build !faketime && (windows || (linux && amd64))
-// +build !faketime
-// +build windows linux,amd64
 
 package runtime
 
index 6f16c70b8160b18a0d1131230914c6a63a5ea88a..1d2926b43dc3d4c2447ba3af6961249c7f29b318 100644 (file)
@@ -6,9 +6,6 @@
 // indirectly, in terms of walltime and nanotime assembly.
 
 //go:build !faketime && !windows && !(linux && amd64)
-// +build !faketime
-// +build !windows
-// +build !linux !amd64
 
 package runtime
 
index 800a2a94e0a0d8b757f350d81fe17aa9fe0beb2d..b9a5cc6345ee2d393882bc18ed9f4d37c0c90e88 100644 (file)
@@ -3,13 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !aix && !darwin && !freebsd && !openbsd && !solaris && !windows && !(linux && amd64)
-// +build !aix
-// +build !darwin
-// +build !freebsd
-// +build !openbsd
-// +build !solaris
-// +build !windows
-// +build !linux !amd64
 
 package runtime
 
index 22b550b76114b642029be87b0771af4feac8a4a4..397919aeba23635de78464a453de036d84a39ea9 100644 (file)
@@ -15,7 +15,7 @@ TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0-0
        BEQ     X0, X31, nocgo
 
        MOV     runtime·tls_g(SB), X31
-       ADD     X4, X31         // add offset to thread pointer (X4)
+       ADD     TP, X31         // add offset to thread pointer (X4)
        MOV     g, (X31)
 
 nocgo:
@@ -23,7 +23,7 @@ nocgo:
 
 TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0
        MOV     runtime·tls_g(SB), X31
-       ADD     X4, X31         // add offset to thread pointer (X4)
+       ADD     TP, X31         // add offset to thread pointer (X4)
        MOV     (X31), g
        RET
 
index 95dafd007c130cc44e14f495e4be00447dd64a7f..7bdfc6b89a614986cd4dc027612f7a46edfe1c7d 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (windows && !amd64) || !windows
-// +build windows,!amd64 !windows
 
 package runtime
 
index 00544e4283c620310c1ee3b53664750d34787713..5b14a5f553922526b1667c71e067cddec43dbbfc 100644 (file)
@@ -551,8 +551,15 @@ func traceEventLocked(extraBytes int, mp *m, pid int32, bufp *traceBufPtr, ev by
                bufp.set(buf)
        }
 
+       // NOTE: ticks might be same after tick division, although the real cputicks is
+       // linear growth.
        ticks := uint64(cputicks()) / traceTickDiv
        tickDiff := ticks - buf.lastTicks
+       if tickDiff == 0 {
+               ticks = buf.lastTicks + 1
+               tickDiff = 1
+       }
+
        buf.lastTicks = ticks
        narg := byte(len(args))
        if skip >= 0 {
@@ -653,6 +660,9 @@ func traceFlush(buf traceBufPtr, pid int32) traceBufPtr {
 
        // initialize the buffer for a new batch
        ticks := uint64(cputicks()) / traceTickDiv
+       if ticks == bufp.lastTicks {
+               ticks = bufp.lastTicks + 1
+       }
        bufp.lastTicks = ticks
        bufp.byte(traceEvBatch | 1<<traceArgCountShift)
        bufp.varint(uint64(pid))
index addfa6faac828f191781f3d0df5c81c25b55fe5b..36627a6735960b13167701be20cd2ede615b8409 100644 (file)
@@ -297,7 +297,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                frame.continpc = frame.pc
                if waspanic {
                        if frame.fn.deferreturn != 0 {
-                               frame.continpc = frame.fn.entry + uintptr(frame.fn.deferreturn) + 1
+                               frame.continpc = frame.fn.entry() + uintptr(frame.fn.deferreturn) + 1
                                // Note: this may perhaps keep return variables alive longer than
                                // strictly necessary, as we are using "function has a defer statement"
                                // as a proxy for "function actually deferred something". It seems
@@ -333,7 +333,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                        // See issue 34123.
                        // The pc can be at function entry when the frame is initialized without
                        // actually running code, like runtime.mstart.
-                       if (n == 0 && flags&_TraceTrap != 0) || waspanic || pc == f.entry {
+                       if (n == 0 && flags&_TraceTrap != 0) || waspanic || pc == f.entry() {
                                pc++
                        } else {
                                tracepc--
@@ -357,7 +357,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                        }
                                        lastFuncID = inltree[ix].funcID
                                        // Back up to an instruction in the "caller".
-                                       tracepc = frame.fn.entry + uintptr(inltree[ix].parentPc)
+                                       tracepc = frame.fn.entry() + uintptr(inltree[ix].parentPc)
                                        pc = tracepc + 1
                                }
                        }
@@ -384,7 +384,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 
                        // backup to CALL instruction to read inlining info (same logic as below)
                        tracepc := frame.pc
-                       if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
+                       if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry() && !waspanic {
                                tracepc--
                        }
                        // If there is inlining info, print the inner frames.
@@ -412,7 +412,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                        }
                                        lastFuncID = inltree[ix].funcID
                                        // Back up to an instruction in the "caller".
-                                       tracepc = frame.fn.entry + uintptr(inltree[ix].parentPc)
+                                       tracepc = frame.fn.entry() + uintptr(inltree[ix].parentPc)
                                }
                        }
                        if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp, nprint == 0, f.funcID, lastFuncID) {
@@ -427,11 +427,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                }
                                print(name, "(")
                                argp := unsafe.Pointer(frame.argp)
-                               printArgs(f, argp)
+                               printArgs(f, argp, tracepc)
                                print(")\n")
                                print("\t", file, ":", line)
-                               if frame.pc > f.entry {
-                                       print(" +", hex(frame.pc-f.entry))
+                               if frame.pc > f.entry() {
+                                       print(" +", hex(frame.pc-f.entry()))
                                }
                                if gp.m != nil && gp.m.throwing > 0 && gp == gp.m.curg || level >= 2 {
                                        print(" fp=", hex(frame.fp), " sp=", hex(frame.sp), " pc=", hex(frame.pc))
@@ -540,7 +540,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 }
 
 // printArgs prints function arguments in traceback.
-func printArgs(f funcInfo, argp unsafe.Pointer) {
+func printArgs(f funcInfo, argp unsafe.Pointer, pc uintptr) {
        // The "instruction" of argument printing is encoded in _FUNCDATA_ArgInfo.
        // See cmd/compile/internal/ssagen.emitArgInfo for the description of the
        // encoding.
@@ -564,9 +564,27 @@ func printArgs(f funcInfo, argp unsafe.Pointer) {
                return
        }
 
-       print1 := func(off, sz uint8) {
+       liveInfo := funcdata(f, _FUNCDATA_ArgLiveInfo)
+       liveIdx := pcdatavalue(f, _PCDATA_ArgLiveIndex, pc, nil)
+       startOffset := uint8(0xff) // smallest offset that needs liveness info (slots with a lower offset is always live)
+       if liveInfo != nil {
+               startOffset = *(*uint8)(liveInfo)
+       }
+
+       isLive := func(off, slotIdx uint8) bool {
+               if liveInfo == nil || liveIdx <= 0 {
+                       return true // no liveness info, always live
+               }
+               if off < startOffset {
+                       return true
+               }
+               bits := *(*uint8)(add(liveInfo, uintptr(liveIdx)+uintptr(slotIdx/8)))
+               return bits&(1<<(slotIdx%8)) != 0
+       }
+
+       print1 := func(off, sz, slotIdx uint8) {
                x := readUnaligned64(add(argp, uintptr(off)))
-               // mask out irrelavant bits
+               // mask out irrelevant bits
                if sz < 8 {
                        shift := 64 - sz*8
                        if goarch.BigEndian {
@@ -576,6 +594,9 @@ func printArgs(f funcInfo, argp unsafe.Pointer) {
                        }
                }
                print(hex(x))
+               if !isLive(off, slotIdx) {
+                       print("?")
+               }
        }
 
        start := true
@@ -585,6 +606,7 @@ func printArgs(f funcInfo, argp unsafe.Pointer) {
                }
        }
        pi := 0
+       slotIdx := uint8(0) // register arg spill slot index
 printloop:
        for {
                o := p[pi]
@@ -609,7 +631,10 @@ printloop:
                        printcomma()
                        sz := p[pi]
                        pi++
-                       print1(o, sz)
+                       print1(o, sz, slotIdx)
+                       if o >= startOffset {
+                               slotIdx++
+                       }
                }
                start = false
        }
@@ -668,7 +693,7 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
                                // in the return values.
                                retValid = *(*bool)(unsafe.Pointer(arg0 + 4*goarch.PtrSize))
                        }
-                       if mv.fn != f.entry {
+                       if mv.fn != f.entry() {
                                print("runtime: confused by ", funcname(f), "\n")
                                throw("reflect mismatch")
                        }
@@ -728,13 +753,13 @@ func printcreatedby(gp *g) {
 func printcreatedby1(f funcInfo, pc uintptr) {
        print("created by ", funcname(f), "\n")
        tracepc := pc // back up to CALL instruction for funcline.
-       if pc > f.entry {
+       if pc > f.entry() {
                tracepc -= sys.PCQuantum
        }
        file, line := funcline(f, tracepc)
        print("\t", file, ":", line)
-       if pc > f.entry {
-               print(" +", hex(pc-f.entry))
+       if pc > f.entry() {
+               print(" +", hex(pc-f.entry()))
        }
        print("\n")
 }
@@ -777,16 +802,23 @@ func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
                printCgoTraceback(&cgoCallers)
        }
 
-       var n int
        if readgstatus(gp)&^_Gscan == _Gsyscall {
                // Override registers if blocked in system call.
                pc = gp.syscallpc
                sp = gp.syscallsp
                flags &^= _TraceTrap
        }
+       if gp.m != nil && gp.m.vdsoSP != 0 {
+               // Override registers if running in VDSO. This comes after the
+               // _Gsyscall check to cover VDSO calls after entersyscall.
+               pc = gp.m.vdsoPC
+               sp = gp.m.vdsoSP
+               flags &^= _TraceTrap
+       }
+
        // Print traceback. By default, omits runtime frames.
        // If that means we print nothing at all, repeat forcing all frames printed.
-       n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags)
+       n := gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags)
        if n == 0 && (flags&_TraceRuntimeFrames) == 0 {
                n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags|_TraceRuntimeFrames)
        }
@@ -842,8 +874,8 @@ func printAncestorTracebackFuncInfo(f funcInfo, pc uintptr) {
        }
        print(name, "(...)\n")
        print("\t", file, ":", line)
-       if pc > f.entry {
-               print(" +", hex(pc-f.entry))
+       if pc > f.entry() {
+               print(" +", hex(pc-f.entry()))
        }
        print("\n")
 }
@@ -1358,6 +1390,9 @@ func callCgoSymbolizer(arg *cgoSymbolizerArg) {
        if msanenabled {
                msanwrite(unsafe.Pointer(arg), unsafe.Sizeof(cgoSymbolizerArg{}))
        }
+       if asanenabled {
+               asanwrite(unsafe.Pointer(arg), unsafe.Sizeof(cgoSymbolizerArg{}))
+       }
        call(cgoSymbolizer, noescape(unsafe.Pointer(arg)))
 }
 
@@ -1380,5 +1415,8 @@ func cgoContextPCs(ctxt uintptr, buf []uintptr) {
        if msanenabled {
                msanwrite(unsafe.Pointer(&arg), unsafe.Sizeof(arg))
        }
+       if asanenabled {
+               asanwrite(unsafe.Pointer(&arg), unsafe.Sizeof(arg))
+       }
        call(cgoTraceback, noescape(unsafe.Pointer(&arg)))
 }
index 83b86a7e909acd3095f3a1c2c4f4c392823c6da6..0333b85c56c75287e762241b8cb48ca57f111e66 100644 (file)
@@ -6,13 +6,29 @@ package runtime_test
 
 import (
        "bytes"
+       "internal/goexperiment"
+       "internal/testenv"
        "runtime"
+       "strings"
        "testing"
 )
 
 var testTracebackArgsBuf [1000]byte
 
 func TestTracebackArgs(t *testing.T) {
+       if *flagQuick {
+               t.Skip("-quick")
+       }
+       optimized := !strings.HasSuffix(testenv.Builder(), "-noopt")
+       abiSel := func(x, y string) string {
+               // select expected output based on ABI
+               // In noopt build we always spill arguments so the output is the same as stack ABI.
+               if optimized && goexperiment.RegabiArgs {
+                       return x
+               }
+               return y
+       }
+
        tests := []struct {
                fn     func() int
                expect string
@@ -105,6 +121,52 @@ func TestTracebackArgs(t *testing.T) {
                        func() int { return testTracebackArgs8d(testArgsType8d{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}, 12}) },
                        "testTracebackArgs8d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}, ...})",
                },
+
+               // Register argument liveness.
+               // 1, 3 are used and live, 2, 4 are dead (in register ABI).
+               // Address-taken (7) and stack ({5, 6}) args are always live.
+               {
+                       func() int {
+                               poisonStack() // poison arg area to make output deterministic
+                               return testTracebackArgs9(1, 2, 3, 4, [2]int{5, 6}, 7)
+                       },
+                       abiSel(
+                               "testTracebackArgs9(0x1, 0xffffffff?, 0x3, 0xff?, {0x5, 0x6}, 0x7)",
+                               "testTracebackArgs9(0x1, 0x2, 0x3, 0x4, {0x5, 0x6}, 0x7)"),
+               },
+               // No live.
+               // (Note: this assume at least 5 int registers if register ABI is used.)
+               {
+                       func() int {
+                               poisonStack() // poison arg area to make output deterministic
+                               return testTracebackArgs10(1, 2, 3, 4, 5)
+                       },
+                       abiSel(
+                               "testTracebackArgs10(0xffffffff?, 0xffffffff?, 0xffffffff?, 0xffffffff?, 0xffffffff?)",
+                               "testTracebackArgs10(0x1, 0x2, 0x3, 0x4, 0x5)"),
+               },
+               // Conditional spills.
+               // Spill in conditional, not executed.
+               {
+                       func() int {
+                               poisonStack() // poison arg area to make output deterministic
+                               return testTracebackArgs11a(1, 2, 3)
+                       },
+                       abiSel(
+                               "testTracebackArgs11a(0xffffffff?, 0xffffffff?, 0xffffffff?)",
+                               "testTracebackArgs11a(0x1, 0x2, 0x3)"),
+               },
+               // 2 spills in conditional, not executed; 3 spills in conditional, executed, but not statically known.
+               // So print 0x3?.
+               {
+                       func() int {
+                               poisonStack() // poison arg area to make output deterministic
+                               return testTracebackArgs11b(1, 2, 3, 4)
+                       },
+                       abiSel(
+                               "testTracebackArgs11b(0xffffffff?, 0xffffffff?, 0x3?, 0x4)",
+                               "testTracebackArgs11b(0x1, 0x2, 0x3, 0x4)"),
+               },
        }
        for _, test := range tests {
                n := test.fn()
@@ -290,3 +352,62 @@ func testTracebackArgs8d(a testArgsType8d) int {
        }
        return n
 }
+
+//go:noinline
+func testTracebackArgs9(a int64, b int32, c int16, d int8, x [2]int, y int) int {
+       if a < 0 {
+               println(&y) // take address, make y live, even if no longer used at traceback
+       }
+       n := runtime.Stack(testTracebackArgsBuf[:], false)
+       if a < 0 {
+               // use half of in-reg args to keep them alive, the other half are dead
+               return int(a) + int(c)
+       }
+       return n
+}
+
+//go:noinline
+func testTracebackArgs10(a, b, c, d, e int32) int {
+       // no use of any args
+       return runtime.Stack(testTracebackArgsBuf[:], false)
+}
+
+// norace to avoid race instrumentation changing spill locations.
+//
+//go:norace
+//go:noinline
+func testTracebackArgs11a(a, b, c int32) int {
+       if a < 0 {
+               println(a, b, c) // spill in a conditional, may not execute
+       }
+       if b < 0 {
+               return int(a + b + c)
+       }
+       return runtime.Stack(testTracebackArgsBuf[:], false)
+}
+
+// norace to avoid race instrumentation changing spill locations.
+//
+//go:norace
+//go:noinline
+func testTracebackArgs11b(a, b, c, d int32) int {
+       var x int32
+       if a < 0 {
+               print() // spill b in a conditional
+               x = b
+       } else {
+               print() // spill c in a conditional
+               x = c
+       }
+       if d < 0 { // d is always needed
+               return int(x + d)
+       }
+       return runtime.Stack(testTracebackArgsBuf[:], false)
+}
+
+// Poison the arg area with deterministic values.
+//
+//go:noinline
+func poisonStack() [20]int {
+       return [20]int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
+}
index ad01d5095e5088ad8d99d007452316b810cb2c98..da471478973b01b8d707bcfee1797edf14625136 100644 (file)
@@ -288,34 +288,7 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
                }
                return res
        }
-       res := uintptr(0)
-
-       // The text, or instruction stream is generated as one large buffer.  The off (offset) for a method is
-       // its offset within this buffer.  If the total text size gets too large, there can be issues on platforms like ppc64 if
-       // the target of calls are too far for the call instruction.  To resolve the large text issue, the text is split
-       // into multiple text sections to allow the linker to generate long calls when necessary.  When this happens, the vaddr
-       // for each text section is set to its offset within the text.  Each method's offset is compared against the section
-       // vaddrs and sizes to determine the containing section.  Then the section relative offset is added to the section's
-       // relocated baseaddr to compute the method addess.
-
-       if len(md.textsectmap) > 1 {
-               for i := range md.textsectmap {
-                       sectaddr := md.textsectmap[i].vaddr
-                       sectlen := md.textsectmap[i].length
-                       if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen {
-                               res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
-                               break
-                       }
-               }
-       } else {
-               // single text section
-               res = md.text + uintptr(off)
-       }
-
-       if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory
-               println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
-               throw("runtime: text offset out of range")
-       }
+       res := md.textAddr(uint32(off))
        return unsafe.Pointer(res)
 }
 
index 456173b0f51c147de0fc8bf8ea912c081de10652..1b8afbedf45792444a7e8a9fe16b76ef8dbd22c0 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (386 || arm)
-// +build linux
-// +build 386 arm
 
 package runtime
 
index 9923bd46971e5f2bc971c3cd448e5bfc7ccc19c1..d46d6f8c34da7599191832ab451830b18031763d 100644 (file)
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build linux && (amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le)
-// +build linux
-// +build amd64 arm64 mips64 mips64le ppc64 ppc64le
+//go:build linux && (amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64)
 
 package runtime
 
index 7ca7b2810bf0de4920f35cec583e14061dcd9452..0fe21cf647044689327ebcec71a80df8d8c16564 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd
-// +build freebsd
 
 package runtime
 
index 23a5a8c322707a3b94201d47db6c86f0e3841a60..5324a3d4cb3206390a33826cf72839e174a6c92c 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd && (386 || amd64)
-// +build freebsd
-// +build 386 amd64
 
 package runtime
 
index c66fbf821669fd6425e3739c07b1df0b9643c0a3..618bd39b42b0f79a82cba8632d758e8dd142729c 100644 (file)
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build (linux && !386 && !amd64 && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le) || !linux
-// +build linux,!386,!amd64,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le !linux
+//go:build (linux && !386 && !amd64 && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !riscv64) || !linux
 
 package runtime
 
index ae211f96b1b058c2766c923b3001b395682d9f57..cff2000767f598dc9d2140b622e94c49b98b715d 100644 (file)
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build linux && (386 || amd64 || arm || arm64 || mips64 || mips64le || ppc64 || ppc64le)
-// +build linux
-// +build 386 amd64 arm arm64 mips64 mips64le ppc64 ppc64le
+//go:build linux && (386 || amd64 || arm || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64)
 
 package runtime
 
index 395ddbba69a730aab8872b3e6e2a6c810c0910ce..1444f8e5246aec9e8ee33f093b77915c5742cee1 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips64 || mips64le)
-// +build linux
-// +build mips64 mips64le
 
 package runtime
 
index b741dbfcdc527d9f9a55fdb37c36acdb110c0cb9..09c8d9d20ed8a87d4218e606fa115467a15609ab 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (ppc64 || ppc64le)
-// +build linux
-// +build ppc64 ppc64le
 
 package runtime
 
diff --git a/src/runtime/vdso_linux_riscv64.go b/src/runtime/vdso_linux_riscv64.go
new file mode 100644 (file)
index 0000000..f427124
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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 runtime
+
+const (
+       // vdsoArrayMax is the byte-size of a maximally sized array on this architecture.
+       // See cmd/compile/internal/riscv64/galign.go arch.MAXWIDTH initialization.
+       vdsoArrayMax = 1<<50 - 1
+)
+
+// key and version at man 7 vdso : riscv
+var vdsoLinuxVersion = vdsoVersionKey{"LINUX_4.15", 0xae77f75}
+
+var vdsoSymbolKeys = []vdsoSymbolKey{
+       {"__vdso_clock_gettime", 0xd35ec75, 0x6e43a318, &vdsoClockgettimeSym},
+}
+
+// initialize to fall back to syscall
+var vdsoClockgettimeSym uintptr = 0
index cf631bdcca7d245c749f4ccb76c48b1b50ee37c1..1dcb125aef548dc862330a60c8c9b9b450da4101 100644 (file)
@@ -24,7 +24,6 @@
 // THE SOFTWARE.
 
 //go:build arm || 386 || mips || mipsle
-// +build arm 386 mips mipsle
 
 package runtime
 
@@ -59,6 +58,36 @@ func uint64tofloat64(y uint64) float64 {
        return d
 }
 
+func int64tofloat32(y int64) float32 {
+       if y < 0 {
+               return -uint64tofloat32(-uint64(y))
+       }
+       return uint64tofloat32(uint64(y))
+}
+
+func uint64tofloat32(y uint64) float32 {
+       // divide into top 18, mid 23, and bottom 23 bits.
+       // (23-bit integers fit into a float32 without loss.)
+       top := uint32(y >> 46)
+       mid := uint32(y >> 23 & (1<<23 - 1))
+       bot := uint32(y & (1<<23 - 1))
+       if top == 0 {
+               return float32(mid)*(1<<23) + float32(bot)
+       }
+       if bot != 0 {
+               // Top is not zero, so the bits in bot
+               // won't make it into the final mantissa.
+               // In fact, the bottom bit of mid won't
+               // make it into the mantissa either.
+               // We only need to make sure that if top+mid
+               // is about to round down in a round-to-even
+               // scenario, and bot is not zero, we make it
+               // round up instead.
+               mid |= 1
+       }
+       return float32(top)*(1<<46) + float32(mid)*(1<<23)
+}
+
 func _d2v(y *uint64, d float64) {
        x := *(*uint64)(unsafe.Pointer(&d))
 
index 73f1e567cecf948558a87ab15bff97a83ee36955..442a98470837b84a7b0b5c1971ccce6d5eccaa3a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // Generate Windows callback assembly file.
 
@@ -23,7 +22,6 @@ func genasm386Amd64() {
        buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
 
 //go:build 386 || amd64
-// +build 386 amd64
 
 // runtime·callbackasm is called by external code to
 // execute Go implemented callback function. It is not
index a4656fd72810d7b8d9a30695a732a5cdd11918aa..81ae872e9c035d7f75783b3cfd2eed7d887004dc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !android
-// +build !android
 
 package runtime
 
index 39dd9c4a581539376c5421ce88728e690fa01955..fd73958c97d29eb174e19044c714ed0e31b75f1e 100644 (file)
@@ -28,15 +28,14 @@ func pow2(i int) float64 {
 // Wrapper around strconv.ParseFloat(x, 64).  Handles dddddp+ddd (binary exponent)
 // itself, passes the rest on to strconv.ParseFloat.
 func myatof64(s string) (f float64, ok bool) {
-       a := strings.SplitN(s, "p", 2)
-       if len(a) == 2 {
-               n, err := strconv.ParseInt(a[0], 10, 64)
+       if mant, exp, ok := strings.Cut(s, "p"); ok {
+               n, err := strconv.ParseInt(mant, 10, 64)
                if err != nil {
                        return 0, false
                }
-               e, err1 := strconv.Atoi(a[1])
+               e, err1 := strconv.Atoi(exp)
                if err1 != nil {
-                       println("bad e", a[1])
+                       println("bad e", exp)
                        return 0, false
                }
                v := float64(n)
@@ -72,16 +71,15 @@ func myatof64(s string) (f float64, ok bool) {
 // Wrapper around strconv.ParseFloat(x, 32).  Handles dddddp+ddd (binary exponent)
 // itself, passes the rest on to strconv.ParseFloat.
 func myatof32(s string) (f float32, ok bool) {
-       a := strings.SplitN(s, "p", 2)
-       if len(a) == 2 {
-               n, err := strconv.Atoi(a[0])
+       if mant, exp, ok := strings.Cut(s, "p"); ok {
+               n, err := strconv.Atoi(mant)
                if err != nil {
-                       println("bad n", a[0])
+                       println("bad n", mant)
                        return 0, false
                }
-               e, err1 := strconv.Atoi(a[1])
+               e, err1 := strconv.Atoi(exp)
                if err1 != nil {
-                       println("bad p", a[1])
+                       println("bad p", exp)
                        return 0, false
                }
                return float32(float64(n) * pow2(e)), true
index 1c61288b9ffa8ebaa7b7d294bc9d238700e7da3a..f2e74bed1779400c87820a9dbc9c127fdd0a9a4f 100644 (file)
@@ -291,7 +291,7 @@ func ryuFtoaShortest(d *decimalSlice, mant uint64, exp int, flt *floatInfo) {
        // Is it allowed to use 'du' as a result?
        // It is always allowed when it is truncated, but also
        // if it is exact and the original binary mantissa is even
-       // When disallowed, we can substract 1.
+       // When disallowed, we can subtract 1.
        uok := !du0 || fracu > 0
        if du0 && fracu == 0 {
                uok = mant&1 == 0
index b3bbb1612b9f634e930fc169bc329e87d1c8858d..d2814b92da795b77ceb1a4757748cf7d25ca6ea2 100644 (file)
@@ -103,7 +103,7 @@ func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bo
                        buf = append(buf, `\x`...)
                        buf = append(buf, lowerhex[byte(r)>>4])
                        buf = append(buf, lowerhex[byte(r)&0xF])
-               case r > utf8.MaxRune:
+               case !utf8.ValidRune(r):
                        r = 0xFFFD
                        fallthrough
                case r < 0x10000:
@@ -322,7 +322,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string,
                        value = v
                        break
                }
-               if v > utf8.MaxRune {
+               if !utf8.ValidRune(v) {
                        err = ErrSyntax
                        return
                }
index 4750be27408a65dfd4c2f51864abda3862d60250..81fc8f79e147499f14798d1831bb8d61d6b55ce2 100644 (file)
@@ -131,6 +131,7 @@ var quoterunetests = []quoteRuneTest{
        {'\\', `'\\'`, `'\\'`, `'\\'`},
        {0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`},
        {0x263a, `'☺'`, `'\u263a'`, `'☺'`},
+       {0xdead, `'�'`, `'\ufffd'`, `'�'`},
        {0xfffd, `'�'`, `'\ufffd'`, `'�'`},
        {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`},
        {0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`},
@@ -305,6 +306,8 @@ var misquoted = []string{
        "\"\n\"",
        "\"\\n\n\"",
        "'\n'",
+       `"\udead"`,
+       `"\ud83d\ude4f"`,
 }
 
 func TestUnquote(t *testing.T) {
diff --git a/src/strings/clone.go b/src/strings/clone.go
new file mode 100644 (file)
index 0000000..edd1497
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2021 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 strings
+
+import (
+       "unsafe"
+)
+
+// Clone returns a fresh copy of s.
+// It guarantees to make a copy of s into a new allocation,
+// which can be important when retaining only a small substring
+// of a much larger string. Using Clone can help such programs
+// use less memory. Of course, since using Clone makes a copy,
+// overuse of Clone can make programs use more memory.
+// Clone should typically be used only rarely, and only when
+// profiling indicates that it is needed.
+// For strings of length zero the string "" will be returned
+// and no allocation is made.
+func Clone(s string) string {
+       if len(s) == 0 {
+               return ""
+       }
+       b := make([]byte, len(s))
+       copy(b, s)
+       return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/src/strings/clone_test.go b/src/strings/clone_test.go
new file mode 100644 (file)
index 0000000..a9ba8ad
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2021 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 strings_test
+
+import (
+       "reflect"
+       "strings"
+       "testing"
+       "unsafe"
+)
+
+var emptyString string
+
+func TestClone(t *testing.T) {
+       var cloneTests = []string{
+               "",
+               strings.Clone(""),
+               strings.Repeat("a", 42)[:0],
+               "short",
+               strings.Repeat("a", 42),
+       }
+       for _, input := range cloneTests {
+               clone := strings.Clone(input)
+               if clone != input {
+                       t.Errorf("Clone(%q) = %q; want %q", input, clone, input)
+               }
+
+               inputHeader := (*reflect.StringHeader)(unsafe.Pointer(&input))
+               cloneHeader := (*reflect.StringHeader)(unsafe.Pointer(&clone))
+               if len(input) != 0 && cloneHeader.Data == inputHeader.Data {
+                       t.Errorf("Clone(%q) return value should not reference inputs backing memory.", input)
+               }
+
+               emptyHeader := (*reflect.StringHeader)(unsafe.Pointer(&emptyString))
+               if len(input) == 0 && cloneHeader.Data != emptyHeader.Data {
+                       t.Errorf("Clone(%#v) return value should be equal to empty string.", inputHeader)
+               }
+       }
+}
+
+func BenchmarkClone(b *testing.B) {
+       var str = strings.Repeat("a", 42)
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               stringSink = strings.Clone(str)
+       }
+}
index 1fe6b8d89a3f94439a80ed2aa68456be4cba241b..2bd4a243db2f83ca77d4f41eeea12e16c7174329 100644 (file)
@@ -5,7 +5,7 @@
 package strings
 
 // Compare returns an integer comparing two strings lexicographically.
-// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
+// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
 //
 // Compare is included only for symmetry with package bytes.
 // It is usually clearer and always faster to use the built-in
index 375f9cac6502e89a0124315a04c1700b8cbd13ae..94aa167f90900c57be37a90d484455f88c7e5468 100644 (file)
@@ -10,17 +10,15 @@ import (
        "unicode"
 )
 
-func ExampleFields() {
-       fmt.Printf("Fields are: %q", strings.Fields("  foo bar  baz   "))
-       // Output: Fields are: ["foo" "bar" "baz"]
-}
-
-func ExampleFieldsFunc() {
-       f := func(c rune) bool {
-               return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+func ExampleBuilder() {
+       var b strings.Builder
+       for i := 3; i >= 1; i-- {
+               fmt.Fprintf(&b, "%d...", i)
        }
-       fmt.Printf("Fields are: %q", strings.FieldsFunc("  foo1;bar2,baz3...", f))
-       // Output: Fields are: ["foo1" "bar2" "baz3"]
+       b.WriteString("ignition")
+       fmt.Println(b.String())
+
+       // Output: 3...2...1...ignition
 }
 
 func ExampleCompare() {
@@ -79,11 +77,40 @@ func ExampleCount() {
        // 5
 }
 
+func ExampleCut() {
+       show := func(s, sep string) {
+               before, after, found := strings.Cut(s, sep)
+               fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
+       }
+       show("Gopher", "Go")
+       show("Gopher", "ph")
+       show("Gopher", "er")
+       show("Gopher", "Badger")
+       // Output:
+       // Cut("Gopher", "Go") = "", "pher", true
+       // Cut("Gopher", "ph") = "Go", "er", true
+       // Cut("Gopher", "er") = "Goph", "", true
+       // Cut("Gopher", "Badger") = "Gopher", "", false
+}
+
 func ExampleEqualFold() {
        fmt.Println(strings.EqualFold("Go", "go"))
        // Output: true
 }
 
+func ExampleFields() {
+       fmt.Printf("Fields are: %q", strings.Fields("  foo bar  baz   "))
+       // Output: Fields are: ["foo" "bar" "baz"]
+}
+
+func ExampleFieldsFunc() {
+       f := func(c rune) bool {
+               return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+       }
+       fmt.Printf("Fields are: %q", strings.FieldsFunc("  foo1;bar2,baz3...", f))
+       // Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
 func ExampleHasPrefix() {
        fmt.Println(strings.HasPrefix("Gopher", "Go"))
        fmt.Println(strings.HasPrefix("Gopher", "C"))
@@ -370,14 +397,3 @@ func ExampleTrimRightFunc() {
        }))
        // Output: ¡¡¡Hello, Gophers
 }
-
-func ExampleBuilder() {
-       var b strings.Builder
-       for i := 3; i >= 1; i-- {
-               fmt.Fprintf(&b, "%d...", i)
-       }
-       b.WriteString("ignition")
-       fmt.Println(b.String())
-
-       // Output: 3...2...1...ignition
-}
index e28d42887930b9d852bdd2129c28f4ebf3bd8c8b..ee728bb22b655259247ad7b871ae9983b28fac72 100644 (file)
@@ -387,7 +387,7 @@ func makeSingleStringReplacer(pattern string, value string) *singleStringReplace
 }
 
 func (r *singleStringReplacer) Replace(s string) string {
-       var buf []byte
+       var buf Builder
        i, matched := 0, false
        for {
                match := r.finder.next(s[i:])
@@ -395,15 +395,16 @@ func (r *singleStringReplacer) Replace(s string) string {
                        break
                }
                matched = true
-               buf = append(buf, s[i:i+match]...)
-               buf = append(buf, r.value...)
+               buf.Grow(match + len(r.value))
+               buf.WriteString(s[i : i+match])
+               buf.WriteString(r.value)
                i += match + len(r.finder.pattern)
        }
        if !matched {
                return s
        }
-       buf = append(buf, s[i:]...)
-       return string(buf)
+       buf.WriteString(s[i:])
+       return buf.String()
 }
 
 func (r *singleStringReplacer) WriteString(w io.Writer, s string) (n int, err error) {
index b429735feadf9d26d29c22d52440f9eb5a749d7f..bc734048c3fc2223cf57b2bdf9f739d1dcb62e19 100644 (file)
@@ -797,6 +797,8 @@ func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
 // most-significant bit of the highest word, map to the full range of all
 // 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
 // ensuring that any non-ASCII character will be reported as not in the set.
+// This allocates a total of 32 bytes even though the upper half
+// is unused to avoid bounds checks in asciiSet.contains.
 type asciiSet [8]uint32
 
 // makeASCIISet creates a set of ASCII characters and reports whether all
@@ -807,28 +809,14 @@ func makeASCIISet(chars string) (as asciiSet, ok bool) {
                if c >= utf8.RuneSelf {
                        return as, false
                }
-               as[c>>5] |= 1 << uint(c&31)
+               as[c/32] |= 1 << (c % 32)
        }
        return as, true
 }
 
 // contains reports whether c is inside the set.
 func (as *asciiSet) contains(c byte) bool {
-       return (as[c>>5] & (1 << uint(c&31))) != 0
-}
-
-func makeCutsetFunc(cutset string) func(rune) bool {
-       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
-               return func(r rune) bool {
-                       return r == rune(cutset[0])
-               }
-       }
-       if as, isASCII := makeASCIISet(cutset); isASCII {
-               return func(r rune) bool {
-                       return r < utf8.RuneSelf && as.contains(byte(r))
-               }
-       }
-       return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
+       return (as[c/32] & (1 << (c % 32))) != 0
 }
 
 // Trim returns a slice of the string s with all leading and
@@ -837,7 +825,13 @@ func Trim(s, cutset string) string {
        if s == "" || cutset == "" {
                return s
        }
-       return TrimFunc(s, makeCutsetFunc(cutset))
+       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+               return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
+       }
+       if as, ok := makeASCIISet(cutset); ok {
+               return trimLeftASCII(trimRightASCII(s, &as), &as)
+       }
+       return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)
 }
 
 // TrimLeft returns a slice of the string s with all leading
@@ -848,7 +842,44 @@ func TrimLeft(s, cutset string) string {
        if s == "" || cutset == "" {
                return s
        }
-       return TrimLeftFunc(s, makeCutsetFunc(cutset))
+       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+               return trimLeftByte(s, cutset[0])
+       }
+       if as, ok := makeASCIISet(cutset); ok {
+               return trimLeftASCII(s, &as)
+       }
+       return trimLeftUnicode(s, cutset)
+}
+
+func trimLeftByte(s string, c byte) string {
+       for len(s) > 0 && s[0] == c {
+               s = s[1:]
+       }
+       return s
+}
+
+func trimLeftASCII(s string, as *asciiSet) string {
+       for len(s) > 0 {
+               if !as.contains(s[0]) {
+                       break
+               }
+               s = s[1:]
+       }
+       return s
+}
+
+func trimLeftUnicode(s, cutset string) string {
+       for len(s) > 0 {
+               r, n := rune(s[0]), 1
+               if r >= utf8.RuneSelf {
+                       r, n = utf8.DecodeRuneInString(s)
+               }
+               if !ContainsRune(cutset, r) {
+                       break
+               }
+               s = s[n:]
+       }
+       return s
 }
 
 // TrimRight returns a slice of the string s, with all trailing
@@ -859,7 +890,44 @@ func TrimRight(s, cutset string) string {
        if s == "" || cutset == "" {
                return s
        }
-       return TrimRightFunc(s, makeCutsetFunc(cutset))
+       if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+               return trimRightByte(s, cutset[0])
+       }
+       if as, ok := makeASCIISet(cutset); ok {
+               return trimRightASCII(s, &as)
+       }
+       return trimRightUnicode(s, cutset)
+}
+
+func trimRightByte(s string, c byte) string {
+       for len(s) > 0 && s[len(s)-1] == c {
+               s = s[:len(s)-1]
+       }
+       return s
+}
+
+func trimRightASCII(s string, as *asciiSet) string {
+       for len(s) > 0 {
+               if !as.contains(s[len(s)-1]) {
+                       break
+               }
+               s = s[:len(s)-1]
+       }
+       return s
+}
+
+func trimRightUnicode(s, cutset string) string {
+       for len(s) > 0 {
+               r, n := rune(s[len(s)-1]), 1
+               if r >= utf8.RuneSelf {
+                       r, n = utf8.DecodeLastRuneInString(s)
+               }
+               if !ContainsRune(cutset, r) {
+                       break
+               }
+               s = s[:len(s)-n]
+       }
+       return s
 }
 
 // TrimSpace returns a slice of the string s, with all leading
@@ -1100,3 +1168,14 @@ func Index(s, substr string) int {
        }
        return -1
 }
+
+// Cut slices s around the first instance of sep,
+// returning the text before and after sep.
+// The found result reports whether sep appears in s.
+// If sep does not appear in s, cut returns s, "", false.
+func Cut(s, sep string) (before, after string, found bool) {
+       if i := Index(s, sep); i >= 0 {
+               return s[:i], s[i+len(sep):], true
+       }
+       return s, "", false
+}
index 09e5b27cc3857a6a98a0ef0b19cd05f1e9d536da..0f30ca738e6754728fe28fe66e4ed046d08afe89 100644 (file)
@@ -808,7 +808,9 @@ var trimTests = []struct {
        {"TrimLeft", "abba", "ab", ""},
        {"TrimRight", "abba", "ab", ""},
        {"TrimLeft", "abba", "a", "bba"},
+       {"TrimLeft", "abba", "b", "abba"},
        {"TrimRight", "abba", "a", "abb"},
+       {"TrimRight", "abba", "b", "abba"},
        {"Trim", "<tag>", "<>", "tag"},
        {"Trim", "* listitem", " *", "listitem"},
        {"Trim", `"quote"`, `"`, "quote"},
@@ -1577,7 +1579,30 @@ var CountTests = []struct {
 func TestCount(t *testing.T) {
        for _, tt := range CountTests {
                if num := Count(tt.s, tt.sep); num != tt.num {
-                       t.Errorf("Count(\"%s\", \"%s\") = %d, want %d", tt.s, tt.sep, num, tt.num)
+                       t.Errorf("Count(%q, %q) = %d, want %d", tt.s, tt.sep, num, tt.num)
+               }
+       }
+}
+
+var cutTests = []struct {
+       s, sep        string
+       before, after string
+       found         bool
+}{
+       {"abc", "b", "a", "c", true},
+       {"abc", "a", "", "bc", true},
+       {"abc", "c", "ab", "", true},
+       {"abc", "abc", "", "", true},
+       {"abc", "", "", "abc", true},
+       {"abc", "d", "abc", "", false},
+       {"", "d", "", "", false},
+       {"", "", "", "", true},
+}
+
+func TestCut(t *testing.T) {
+       for _, tt := range cutTests {
+               if before, after, found := Cut(tt.s, tt.sep); before != tt.before || after != tt.after || found != tt.found {
+                       t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found)
                }
        }
 }
@@ -1860,6 +1885,13 @@ func BenchmarkTrimASCII(b *testing.B) {
        }
 }
 
+func BenchmarkTrimByte(b *testing.B) {
+       x := "  the quick brown fox   "
+       for i := 0; i < b.N; i++ {
+               Trim(x, " ")
+       }
+}
+
 func BenchmarkIndexPeriodic(b *testing.B) {
        key := "aa"
        for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
index eadc962f70634b12feac91930b44198ae1bb8be8..4b8c2a58f34b446e1bf991a1b822f2c769475177 100644 (file)
@@ -7,6 +7,7 @@ package atomic_test
 import (
        "fmt"
        "runtime"
+       "runtime/debug"
        "strings"
        . "sync/atomic"
        "testing"
@@ -1196,6 +1197,11 @@ func TestHammerStoreLoad(t *testing.T) {
        }
        const procs = 8
        defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
+       // Disable the GC because hammerStoreLoadPointer invokes
+       // write barriers on values that aren't real pointers.
+       defer debug.SetGCPercent(debug.SetGCPercent(-1))
+       // Ensure any in-progress GC is finished.
+       runtime.GC()
        for _, tt := range tests {
                c := make(chan int)
                var val uint64
index 3500cd22f4e74e7991d4f9cfca1ea6856695b722..af6295de91e19ef858f943c31a79427a8cad7122 100644 (file)
@@ -28,7 +28,7 @@ type ifaceWords struct {
 func (v *Value) Load() (val interface{}) {
        vp := (*ifaceWords)(unsafe.Pointer(v))
        typ := LoadPointer(&vp.typ)
-       if typ == nil || uintptr(typ) == ^uintptr(0) {
+       if typ == nil || typ == unsafe.Pointer(&firstStoreInProgress) {
                // First store not yet completed.
                return nil
        }
@@ -39,6 +39,8 @@ func (v *Value) Load() (val interface{}) {
        return
 }
 
+var firstStoreInProgress byte
+
 // Store sets the value of the Value to x.
 // All calls to Store for a given Value must use values of the same concrete type.
 // Store of an inconsistent type panics, as does Store(nil).
@@ -53,10 +55,9 @@ func (v *Value) Store(val interface{}) {
                if typ == nil {
                        // Attempt to start first store.
                        // Disable preemption so that other goroutines can use
-                       // active spin wait to wait for completion; and so that
-                       // GC does not see the fake type accidentally.
+                       // active spin wait to wait for completion.
                        runtime_procPin()
-                       if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
+                       if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {
                                runtime_procUnpin()
                                continue
                        }
@@ -66,7 +67,7 @@ func (v *Value) Store(val interface{}) {
                        runtime_procUnpin()
                        return
                }
-               if uintptr(typ) == ^uintptr(0) {
+               if typ == unsafe.Pointer(&firstStoreInProgress) {
                        // First store in progress. Wait.
                        // Since we disable preemption around the first store,
                        // we can wait with active spinning.
index bdd3af6fedaa4bb25b7cb6b2990a5aa171209612..f009a68cf21f25427d2bcca48194fa0f33233ac2 100644 (file)
@@ -22,7 +22,7 @@ func ExampleWaitGroup() {
        var urls = []string{
                "http://www.golang.org/",
                "http://www.google.com/",
-               "http://www.somestupidname.com/",
+               "http://www.example.com/",
        }
        for _, url := range urls {
                // Increment the WaitGroup counter.
index 3028552f743d1fce5e916244b1e141c83079ee0f..9dd04d947017f15d8a3663353e71c9322000a700 100644 (file)
@@ -81,6 +81,21 @@ func (m *Mutex) Lock() {
        m.lockSlow()
 }
 
+// TryLock tries to lock m and reports whether it succeeded.
+//
+// Note that while correct uses of TryLock do exist, they are rare,
+// and use of TryLock is often a sign of a deeper problem
+// in a particular use of mutexes.
+func (m *Mutex) TryLock() bool {
+       if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
+               if race.Enabled {
+                       race.Acquire(unsafe.Pointer(m))
+               }
+               return true
+       }
+       return false
+}
+
 func (m *Mutex) lockSlow() {
        var waitStartTime int64
        starving := false
index 98c1bf2a5f9bc2fb7386c7eafd5b58907ae0a56e..cca0986a30975ebd9c51cf37d97037b43b666dae 100644 (file)
@@ -60,6 +60,12 @@ func BenchmarkContendedSemaphore(b *testing.B) {
 
 func HammerMutex(m *Mutex, loops int, cdone chan bool) {
        for i := 0; i < loops; i++ {
+               if i%3 == 0 {
+                       if m.TryLock() {
+                               m.Unlock()
+                       }
+                       continue
+               }
                m.Lock()
                m.Unlock()
        }
@@ -71,7 +77,19 @@ func TestMutex(t *testing.T) {
                t.Logf("got mutexrate %d expected 0", n)
        }
        defer runtime.SetMutexProfileFraction(0)
+
        m := new(Mutex)
+
+       m.Lock()
+       if m.TryLock() {
+               t.Fatalf("TryLock succeeded with mutex locked")
+       }
+       m.Unlock()
+       if !m.TryLock() {
+               t.Fatalf("TryLock failed with mutex unlocked")
+       }
+       m.Unlock()
+
        c := make(chan bool)
        for i := 0; i < 10; i++ {
                go HammerMutex(m, 1000, c)
index 1ae70127ac24ec137906c7c87dfc28e6ab02d413..9802f29d6f6d5ecb36d9b69b6230d220bad2d51c 100644 (file)
@@ -71,7 +71,7 @@ type poolLocal struct {
 }
 
 // from runtime
-func fastrand() uint32
+func fastrandn(n uint32) uint32
 
 var poolRaceHash [128]uint64
 
@@ -92,7 +92,7 @@ func (p *Pool) Put(x interface{}) {
                return
        }
        if race.Enabled {
-               if fastrand()%4 == 0 {
+               if fastrandn(4) == 0 {
                        // Randomly drop x on floor.
                        return
                }
index 65666daab48e66fb3522ccd1bac095e893b4dca7..d991621624ca781e4db92aac5fee070c6c20a292 100644 (file)
@@ -4,7 +4,6 @@
 
 // Pool is no-op under race detector, so all these tests do not work.
 //go:build !race
-// +build !race
 
 package sync_test
 
@@ -271,6 +270,26 @@ func BenchmarkPoolOverflow(b *testing.B) {
        })
 }
 
+// Simulate object starvation in order to force Ps to steal objects
+// from other Ps.
+func BenchmarkPoolStarvation(b *testing.B) {
+       var p Pool
+       count := 100
+       // Reduce number of putted objects by 33 %. It creates objects starvation
+       // that force P-local storage to steal objects from other Ps.
+       countStarved := count - int(float32(count)*0.33)
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       for b := 0; b < countStarved; b++ {
+                               p.Put(1)
+                       }
+                       for b := 0; b < count; b++ {
+                               p.Get()
+                       }
+               }
+       })
+}
+
 var globalSink interface{}
 
 func BenchmarkPoolSTW(b *testing.B) {
index c4b44893f0e7659f197834b804fd967c6f888560..9b7e9922fba0b0b401b80e4c5b897ddc85e6a5d8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !goexperiment.staticlockranking
-// +build !goexperiment.staticlockranking
 
 package sync
 
index e91fdb6c1ff46d95036740f6a7dea6cfaa2eec48..cdb1af41c69a85eccc05e7be1387dd4d8683b1e5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build goexperiment.staticlockranking
-// +build goexperiment.staticlockranking
 
 package sync
 
index 3012b5548e4147d8f6495d84363bb7161c2f9779..f0d4c9771a04907e9bb0c64586a9d49d71871b80 100644 (file)
@@ -68,6 +68,34 @@ func (rw *RWMutex) RLock() {
        }
 }
 
+// TryRLock tries to lock rw for reading and reports whether it succeeded.
+//
+// Note that while correct uses of TryRLock do exist, they are rare,
+// and use of TryRLock is often a sign of a deeper problem
+// in a particular use of mutexes.
+func (rw *RWMutex) TryRLock() bool {
+       if race.Enabled {
+               _ = rw.w.state
+               race.Disable()
+       }
+       for {
+               c := atomic.LoadInt32(&rw.readerCount)
+               if c < 0 {
+                       if race.Enabled {
+                               race.Enable()
+                       }
+                       return false
+               }
+               if atomic.CompareAndSwapInt32(&rw.readerCount, c, c+1) {
+                       if race.Enabled {
+                               race.Enable()
+                               race.Acquire(unsafe.Pointer(&rw.readerSem))
+                       }
+                       return true
+               }
+       }
+}
+
 // RUnlock undoes a single RLock call;
 // it does not affect other simultaneous readers.
 // It is a run-time error if rw is not locked for reading
@@ -122,6 +150,37 @@ func (rw *RWMutex) Lock() {
        }
 }
 
+// TryLock tries to lock rw for writing and reports whether it succeeded.
+//
+// Note that while correct uses of TryLock do exist, they are rare,
+// and use of TryLock is often a sign of a deeper problem
+// in a particular use of mutexes.
+func (rw *RWMutex) TryLock() bool {
+       if race.Enabled {
+               _ = rw.w.state
+               race.Disable()
+       }
+       if !rw.w.TryLock() {
+               if race.Enabled {
+                       race.Enable()
+               }
+               return false
+       }
+       if !atomic.CompareAndSwapInt32(&rw.readerCount, 0, -rwmutexMaxReaders) {
+               rw.w.Unlock()
+               if race.Enabled {
+                       race.Enable()
+               }
+               return false
+       }
+       if race.Enabled {
+               race.Enable()
+               race.Acquire(unsafe.Pointer(&rw.readerSem))
+               race.Acquire(unsafe.Pointer(&rw.writerSem))
+       }
+       return true
+}
+
 // Unlock unlocks rw for writing. It is a run-time error if rw is
 // not locked for writing on entry to Unlock.
 //
index c98e69fd07d7457b55a2fcfb9c5c875a8a8af05e..dfbdd9bbeef706afd38ef510019187f824f527ab 100644 (file)
@@ -108,6 +108,34 @@ func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
 }
 
 func TestRWMutex(t *testing.T) {
+       var m RWMutex
+
+       m.Lock()
+       if m.TryLock() {
+               t.Fatalf("TryLock succeeded with mutex locked")
+       }
+       if m.TryRLock() {
+               t.Fatalf("TryRLock succeeded with mutex locked")
+       }
+       m.Unlock()
+
+       if !m.TryLock() {
+               t.Fatalf("TryLock failed with mutex unlocked")
+       }
+       m.Unlock()
+
+       if !m.TryRLock() {
+               t.Fatalf("TryRLock failed with mutex unlocked")
+       }
+       if !m.TryRLock() {
+               t.Fatalf("TryRLock failed with mutex rlocked")
+       }
+       if m.TryLock() {
+               t.Fatalf("TryLock succeeded with mutex rlocked")
+       }
+       m.RUnlock()
+       m.RUnlock()
+
        defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
        n := 1000
        if testing.Short() {
index e81a493dea21d5a8053c6c899e1808ae7b88cecc..9c6662d04be08f6eedbb62db97b1dfef82bfcf66 100644 (file)
@@ -22,18 +22,24 @@ type WaitGroup struct {
 
        // 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
        // 64-bit atomic operations require 64-bit alignment, but 32-bit
-       // compilers do not ensure it. So we allocate 12 bytes and then use
-       // the aligned 8 bytes in them as state, and the other 4 as storage
-       // for the sema.
-       state1 [3]uint32
+       // compilers only guarantee that 64-bit fields are 32-bit aligned.
+       // For this reason on 32 bit architectures we need to check in state()
+       // if state1 is aligned or not, and dynamically "swap" the field order if
+       // needed.
+       state1 uint64
+       state2 uint32
 }
 
-// state returns pointers to the state and sema fields stored within wg.state1.
+// state returns pointers to the state and sema fields stored within wg.state*.
 func (wg *WaitGroup) state() (statep *uint64, semap *uint32) {
-       if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
-               return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2]
+       if unsafe.Alignof(wg.state1) == 8 || uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
+               // state1 is 64-bit aligned: nothing to do.
+               return &wg.state1, &wg.state2
        } else {
-               return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0]
+               // state1 is 32-bit aligned but not 64-bit aligned: this means that
+               // (&state1)+4 is 64-bit aligned.
+               state := (*[3]uint32)(unsafe.Pointer(&wg.state1))
+               return (*uint64)(unsafe.Pointer(&state[1])), &state[0]
        }
 }
 
index c569e0faa2ebf21950dd7442bf7de9c869a3ec1c..4ded218d2d8d0c27e9efe6953f69d83e79b1ac67 100644 (file)
@@ -5,8 +5,6 @@
 package sync_test
 
 import (
-       "internal/race"
-       "runtime"
        . "sync"
        "sync/atomic"
        "testing"
@@ -48,12 +46,6 @@ func TestWaitGroup(t *testing.T) {
        }
 }
 
-func knownRacy(t *testing.T) {
-       if race.Enabled {
-               t.Skip("skipping known-racy test under the race detector")
-       }
-}
-
 func TestWaitGroupMisuse(t *testing.T) {
        defer func() {
                err := recover()
@@ -68,124 +60,6 @@ func TestWaitGroupMisuse(t *testing.T) {
        t.Fatal("Should panic")
 }
 
-// pollUntilEqual blocks until v, loaded atomically, is
-// equal to the target.
-func pollUntilEqual(v *uint32, target uint32) {
-       for {
-               for i := 0; i < 1e3; i++ {
-                       if atomic.LoadUint32(v) == target {
-                               return
-                       }
-               }
-               // yield to avoid deadlock with the garbage collector
-               // see issue #20072
-               runtime.Gosched()
-       }
-}
-
-func TestWaitGroupMisuse2(t *testing.T) {
-       knownRacy(t)
-       if runtime.NumCPU() <= 4 {
-               t.Skip("NumCPU<=4, skipping: this test requires parallelism")
-       }
-       defer func() {
-               err := recover()
-               if err != "sync: negative WaitGroup counter" &&
-                       err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
-                       err != "sync: WaitGroup is reused before previous Wait has returned" {
-                       t.Fatalf("Unexpected panic: %#v", err)
-               }
-       }()
-       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-       done := make(chan interface{}, 2)
-       // The detection is opportunistic, so we want it to panic
-       // at least in one run out of a million.
-       for i := 0; i < 1e6; i++ {
-               var wg WaitGroup
-               var here uint32
-               wg.Add(1)
-               go func() {
-                       defer func() {
-                               done <- recover()
-                       }()
-                       atomic.AddUint32(&here, 1)
-                       pollUntilEqual(&here, 3)
-                       wg.Wait()
-               }()
-               go func() {
-                       defer func() {
-                               done <- recover()
-                       }()
-                       atomic.AddUint32(&here, 1)
-                       pollUntilEqual(&here, 3)
-                       wg.Add(1) // This is the bad guy.
-                       wg.Done()
-               }()
-               atomic.AddUint32(&here, 1)
-               pollUntilEqual(&here, 3)
-               wg.Done()
-               for j := 0; j < 2; j++ {
-                       if err := <-done; err != nil {
-                               panic(err)
-                       }
-               }
-       }
-       t.Fatal("Should panic")
-}
-
-func TestWaitGroupMisuse3(t *testing.T) {
-       knownRacy(t)
-       if runtime.NumCPU() <= 1 {
-               t.Skip("NumCPU==1, skipping: this test requires parallelism")
-       }
-       defer func() {
-               err := recover()
-               if err != "sync: negative WaitGroup counter" &&
-                       err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
-                       err != "sync: WaitGroup is reused before previous Wait has returned" {
-                       t.Fatalf("Unexpected panic: %#v", err)
-               }
-       }()
-       defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-       done := make(chan interface{}, 3)
-       // The detection is opportunistically, so we want it to panic
-       // at least in one run out of a million.
-       for i := 0; i < 1e6; i++ {
-               var wg WaitGroup
-               wg.Add(1)
-               go func() {
-                       defer func() {
-                               done <- recover()
-                       }()
-                       wg.Done()
-               }()
-               go func() {
-                       defer func() {
-                               done <- recover()
-                       }()
-                       wg.Wait()
-                       // Start reusing the wg before waiting for the Wait below to return.
-                       wg.Add(1)
-                       go func() {
-                               wg.Done()
-                       }()
-                       wg.Wait()
-               }()
-               go func() {
-                       defer func() {
-                               done <- recover()
-                       }()
-                       wg.Wait()
-               }()
-               for j := 0; j < 3; j++ {
-                       if err := <-done; err != nil {
-                               panic(err)
-                       }
-               }
-       }
-       t.Fatal("Should panic")
-}
-
 func TestWaitGroupRace(t *testing.T) {
        // Run this test for about 1ms.
        for i := 0; i < 1000; i++ {
diff --git a/src/syscall/asan.go b/src/syscall/asan.go
new file mode 100644 (file)
index 0000000..3199130
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 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:build asan
+// +build asan
+
+package syscall
+
+import (
+       "runtime"
+       "unsafe"
+)
+
+const asanenabled = true
+
+func asanRead(addr unsafe.Pointer, len int) {
+       runtime.ASanRead(addr, len)
+}
+
+func asanWrite(addr unsafe.Pointer, len int) {
+       runtime.ASanWrite(addr, len)
+}
diff --git a/src/syscall/asan0.go b/src/syscall/asan0.go
new file mode 100644 (file)
index 0000000..7b69f4a
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+//go:build !asan
+// +build !asan
+
+package syscall
+
+import (
+       "unsafe"
+)
+
+const asanenabled = false
+
+func asanRead(addr unsafe.Pointer, len int) {
+}
+
+func asanWrite(addr unsafe.Pointer, len int) {
+}
index 452d4cf14b6b13b52c55ef235d6ea1b2b0b60f9f..735c0788950db27593a88be7591ae40d3c0f15f9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || netbsd || openbsd
-// +build dragonfly freebsd netbsd openbsd
 
 // Berkeley packet filter for BSD variants
 
index c1a8b516e81a408c6313afa7c7d47caf835a789c..1ee56fc3401cee4edb3bd9886ded6e4e132fe0ba 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package syscall_test
 
index 9e1222e81c6dfccaa2aa056b0ec70f643fac76b6..237ea79ad621ce172de924cfb30e54e7d46530d9 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package syscall
 
index 71b445ba9b533b49022a80cea9b88aba4298d750..6570bf92179d51738d3c3ac7291a0d6bb57748ee 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package syscall_test
 
index 16210ca5b58a53d1cd26bec6374b3b17818feb7f..34b481d6e63543c1cf08cf1ea0d2ec664b66781a 100644 (file)
@@ -5,7 +5,6 @@
 package syscall
 
 import (
-       "internal/itoa"
        "internal/syscall/windows/sysdll"
        "sync"
        "sync/atomic"
@@ -25,12 +24,25 @@ func (e *DLLError) Unwrap() error { return e.Err }
 
 // Implemented in ../runtime/syscall_windows.go.
 
+// Deprecated: Use SyscallN instead.
 func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+
+// Deprecated: Use SyscallN instead.
 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
+// Deprecated: Use SyscallN instead.
 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+
+// Deprecated: Use SyscallN instead.
 func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
+
+// Deprecated: Use SyscallN instead.
 func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
+
+// Deprecated: Use SyscallN instead.
 func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno)
+
+func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
 func loadlibrary(filename *uint16) (handle uintptr, err Errno)
 func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
@@ -160,8 +172,7 @@ func (p *Proc) Addr() uintptr {
 
 //go:uintptrescapes
 
-// Call executes procedure p with arguments a. It will panic if more than 18 arguments
-// are supplied.
+// Call executes procedure p with arguments a.
 //
 // 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
@@ -175,49 +186,8 @@ func (p *Proc) Addr() uintptr {
 // 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:
-               return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
-       case 1:
-               return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
-       case 2:
-               return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
-       case 3:
-               return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
-       case 4:
-               return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
-       case 5:
-               return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
-       case 6:
-               return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
-       case 7:
-               return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
-       case 8:
-               return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
-       case 9:
-               return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
-       case 10:
-               return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
-       case 11:
-               return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
-       case 12:
-               return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
-       case 13:
-               return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
-       case 14:
-               return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
-       case 15:
-               return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
-       case 16:
-               return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], 0, 0)
-       case 17:
-               return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], 0)
-       case 18:
-               return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17])
-       default:
-               panic("Call " + p.Name + " with too many arguments " + itoa.Itoa(len(a)) + ".")
-       }
+func (p *Proc) Call(a ...uintptr) (uintptr, uintptr, error) {
+       return SyscallN(p.Addr(), a...)
 }
 
 // A LazyDLL implements access to a single DLL.
index dc0947fa6e84b3b3fd109f6bb08a1aab80e3e70a..8e3874eb8630740901c8f77b05a88a3145a5c0d3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 //
 //go:build ppc64 || s390x || mips || mips64
-// +build ppc64 s390x mips mips64
 
 package syscall
 
index a894445f73cb518b12e56dfef71026c47eb931a7..edfb6cf164ab32be691e3b869a95bdbd09ad1c05 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 //
 //go:build 386 || amd64 || arm || arm64 || ppc64le || mips64le || mipsle || riscv64 || wasm
-// +build 386 amd64 arm arm64 ppc64le mips64le mipsle riscv64 wasm
 
 package syscall
 
index 022ef6ed7342c6f0c5508d05677deda6e64d3918..521967c79f52e47fc83119e763548d1e680faaa4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || plan9
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris plan9
 
 // Unix environment variables.
 
index 17c7ac0664a0a878deb4bad32b6f0a796f250aeb..f2d54a40bd196903fe5403a47deee90492e0e2ea 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix
-// +build aix
 
 package syscall
 
index 709066e809baa5306884ba03978ef933a899de2a..148f5a91aa00e842697195db71f284bc8d545868 100644 (file)
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build dragonfly || freebsd || netbsd || (openbsd && mips64)
-// +build dragonfly freebsd netbsd openbsd,mips64
+//go:build dragonfly || netbsd || (openbsd && mips64)
 
 package syscall
 
 import (
+       "runtime"
        "unsafe"
 )
 
@@ -181,11 +181,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
        // Pass 1: look for fd[i] < i and move those up above len(fd)
        // so that pass 2 won't stomp on an fd it needs later.
        if pipe < nextfd {
-               _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
-               if err1 != 0 {
-                       goto childerror
+               switch runtime.GOOS {
+               case "netbsd":
+                       _, _, err1 = RawSyscall(_SYS_DUP3, uintptr(pipe), uintptr(nextfd), O_CLOEXEC)
+                       if err1 != 0 {
+                               goto childerror
+                       }
+               default:
+                       _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
+                       if err1 != 0 {
+                               goto childerror
+                       }
+                       RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                }
-               RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                pipe = nextfd
                nextfd++
        }
@@ -194,11 +202,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                        if nextfd == pipe { // don't stomp on pipe
                                nextfd++
                        }
-                       _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
-                       if err1 != 0 {
-                               goto childerror
+                       switch runtime.GOOS {
+                       case "netbsd":
+                               _, _, err1 = RawSyscall(_SYS_DUP3, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC)
+                               if err1 != 0 {
+                                       goto childerror
+                               }
+                       default:
+                               _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
+                               if err1 != 0 {
+                                       goto childerror
+                               }
+                               RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                        }
-                       RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                        fd[i] = nextfd
                        nextfd++
                }
diff --git a/src/syscall/exec_freebsd.go b/src/syscall/exec_freebsd.go
new file mode 100644 (file)
index 0000000..90793fe
--- /dev/null
@@ -0,0 +1,297 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+       "runtime"
+       "unsafe"
+)
+
+type SysProcAttr struct {
+       Chroot     string      // Chroot.
+       Credential *Credential // Credential.
+       Ptrace     bool        // Enable tracing.
+       Setsid     bool        // Create session.
+       // Setpgid sets the process group ID of the child to Pgid,
+       // or, if Pgid == 0, to the new child's process ID.
+       Setpgid bool
+       // Setctty sets the controlling terminal of the child to
+       // file descriptor Ctty. Ctty must be a descriptor number
+       // in the child process: an index into ProcAttr.Files.
+       // This is only meaningful if Setsid is true.
+       Setctty bool
+       Noctty  bool // Detach fd 0 from controlling terminal
+       Ctty    int  // Controlling TTY fd
+       // Foreground places the child process group in the foreground.
+       // This implies Setpgid. The Ctty field must be set to
+       // the descriptor of the controlling TTY.
+       // Unlike Setctty, in this case Ctty must be a descriptor
+       // number in the parent process.
+       Foreground bool
+       Pgid       int    // Child's process group ID if Setpgid.
+       Pdeathsig  Signal // Signal that the process will get when its parent dies (Linux and FreeBSD only)
+}
+
+const (
+       _P_PID = 0
+
+       _PROC_PDEATHSIG_CTL = 11
+)
+
+// Implemented in runtime package.
+func runtime_BeforeFork()
+func runtime_AfterFork()
+func runtime_AfterForkInChild()
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno error to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+// For the same reason compiler does not race instrument it.
+// The calls to RawSyscall are okay because they are assembly
+// functions that do not grow the stack.
+//go:norace
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+       // Declare all variables at top in case any
+       // declarations require heap allocation (e.g., err1).
+       var (
+               r1     uintptr
+               err1   Errno
+               nextfd int
+               i      int
+       )
+
+       // Record parent PID so child can test if it has died.
+       ppid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+
+       // guard against side effects of shuffling fds below.
+       // Make sure that nextfd is beyond any currently open files so
+       // that we can't run the risk of overwriting any of them.
+       fd := make([]int, len(attr.Files))
+       nextfd = len(attr.Files)
+       for i, ufd := range attr.Files {
+               if nextfd < int(ufd) {
+                       nextfd = int(ufd)
+               }
+               fd[i] = int(ufd)
+       }
+       nextfd++
+
+       // About to call fork.
+       // No more allocation or calls of non-assembly functions.
+       runtime_BeforeFork()
+       r1, _, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
+       if err1 != 0 {
+               runtime_AfterFork()
+               return 0, err1
+       }
+
+       if r1 != 0 {
+               // parent; return PID
+               runtime_AfterFork()
+               return int(r1), 0
+       }
+
+       // Fork succeeded, now in child.
+
+       // Enable tracing if requested.
+       if sys.Ptrace {
+               _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Session ID
+       if sys.Setsid {
+               _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Set process group
+       if sys.Setpgid || sys.Foreground {
+               // Place child in process group.
+               _, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       if sys.Foreground {
+               // This should really be pid_t, however _C_int (aka int32) is
+               // generally equivalent.
+               pgrp := _C_int(sys.Pgid)
+               if pgrp == 0 {
+                       r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
+                       if err1 != 0 {
+                               goto childerror
+                       }
+
+                       pgrp = _C_int(r1)
+               }
+
+               // Place process group in foreground.
+               _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Restore the signal mask. We do this after TIOCSPGRP to avoid
+       // having the kernel send a SIGTTOU signal to the process group.
+       runtime_AfterForkInChild()
+
+       // Chroot
+       if chroot != nil {
+               _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // User and groups
+       if cred := sys.Credential; cred != nil {
+               ngroups := uintptr(len(cred.Groups))
+               groups := uintptr(0)
+               if ngroups > 0 {
+                       groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+               }
+               if !cred.NoSetGroups {
+                       _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+                       if err1 != 0 {
+                               goto childerror
+                       }
+               }
+               _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+               _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Chdir
+       if dir != nil {
+               _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Parent death signal
+       if sys.Pdeathsig != 0 {
+               switch runtime.GOARCH {
+               case "386", "arm":
+                       _, _, err1 = RawSyscall6(SYS_PROCCTL, _P_PID, 0, 0, _PROC_PDEATHSIG_CTL, uintptr(unsafe.Pointer(&sys.Pdeathsig)), 0)
+               default:
+                       _, _, err1 = RawSyscall6(SYS_PROCCTL, _P_PID, 0, _PROC_PDEATHSIG_CTL, uintptr(unsafe.Pointer(&sys.Pdeathsig)), 0, 0)
+               }
+               if err1 != 0 {
+                       goto childerror
+               }
+
+               // Signal self if parent is already dead. This might cause a
+               // duplicate signal in rare cases, but it won't matter when
+               // using SIGKILL.
+               r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
+               if r1 != ppid {
+                       pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+                       _, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+                       if err1 != 0 {
+                               goto childerror
+                       }
+               }
+       }
+
+       // Pass 1: look for fd[i] < i and move those up above len(fd)
+       // so that pass 2 won't stomp on an fd it needs later.
+       if pipe < nextfd {
+               _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(pipe), F_DUP2FD_CLOEXEC, uintptr(nextfd))
+               if err1 != 0 {
+                       goto childerror
+               }
+               pipe = nextfd
+               nextfd++
+       }
+       for i = 0; i < len(fd); i++ {
+               if fd[i] >= 0 && fd[i] < int(i) {
+                       if nextfd == pipe { // don't stomp on pipe
+                               nextfd++
+                       }
+                       _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_DUP2FD_CLOEXEC, uintptr(nextfd))
+                       if err1 != 0 {
+                               goto childerror
+                       }
+                       fd[i] = nextfd
+                       nextfd++
+               }
+       }
+
+       // Pass 2: dup fd[i] down onto i.
+       for i = 0; i < len(fd); i++ {
+               if fd[i] == -1 {
+                       RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+                       continue
+               }
+               if fd[i] == int(i) {
+                       // dup2(i, i) won't clear close-on-exec flag on Linux,
+                       // probably not elsewhere either.
+                       _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
+                       if err1 != 0 {
+                               goto childerror
+                       }
+                       continue
+               }
+               // The new fd is created NOT close-on-exec,
+               // which is exactly what we want.
+               _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // By convention, we don't close-on-exec the fds we are
+       // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+       // Programs that know they inherit fds >= 3 will need
+       // to set them close-on-exec.
+       for i = len(fd); i < 3; i++ {
+               RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+       }
+
+       // Detach fd 0 from tty
+       if sys.Noctty {
+               _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Set the controlling TTY to Ctty
+       if sys.Setctty {
+               _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
+               if err1 != 0 {
+                       goto childerror
+               }
+       }
+
+       // Time to exec.
+       _, _, err1 = RawSyscall(SYS_EXECVE,
+               uintptr(unsafe.Pointer(argv0)),
+               uintptr(unsafe.Pointer(&argv[0])),
+               uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+       // send error code on pipe
+       RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+       for {
+               RawSyscall(SYS_EXIT, 253, 0, 0)
+       }
+}
index 8a84954051a1dc42526fe78e85004d158aac5738..c8549c496444e47e6e659e0948bb339c7bae37b6 100644 (file)
@@ -3,13 +3,13 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || solaris
-// +build aix solaris
 
 // This file handles forkAndExecInChild function for OS using libc syscall like AIX or Solaris.
 
 package syscall
 
 import (
+       "runtime"
        "unsafe"
 )
 
@@ -197,11 +197,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
        // Pass 1: look for fd[i] < i and move those up above len(fd)
        // so that pass 2 won't stomp on an fd it needs later.
        if pipe < nextfd {
-               _, err1 = dup2child(uintptr(pipe), uintptr(nextfd))
+               switch runtime.GOOS {
+               case "illumos":
+                       _, err1 = fcntl1(uintptr(pipe), _F_DUP2FD_CLOEXEC, uintptr(nextfd))
+               default:
+                       _, err1 = dup2child(uintptr(pipe), uintptr(nextfd))
+                       if err1 != 0 {
+                               goto childerror
+                       }
+                       _, err1 = fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+               }
                if err1 != 0 {
                        goto childerror
                }
-               fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                pipe = nextfd
                nextfd++
        }
@@ -210,11 +218,16 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
                        if nextfd == pipe { // don't stomp on pipe
                                nextfd++
                        }
-                       _, err1 = dup2child(uintptr(fd[i]), uintptr(nextfd))
-                       if err1 != 0 {
-                               goto childerror
+                       switch runtime.GOOS {
+                       case "illumos":
+                               _, err1 = fcntl1(uintptr(fd[i]), _F_DUP2FD_CLOEXEC, uintptr(nextfd))
+                       default:
+                               _, err1 = dup2child(uintptr(fd[i]), uintptr(nextfd))
+                               if err1 != 0 {
+                                       goto childerror
+                               }
+                               _, err1 = fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                        }
-                       _, err1 = fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
                        if err1 != 0 {
                                goto childerror
                        }
index b999754c2e81bf33c15accea3ab169841af96284..b05f053bbf3fa75cac478f50955454f624f521de 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || (openbsd && !mips64)
-// +build darwin openbsd,!mips64
 
 package syscall
 
@@ -117,14 +116,15 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
        }
 
        if sys.Foreground {
-               pgrp := sys.Pgid
+               // This should really be pid_t, however _C_int (aka int32) is
+               // generally equivalent.
+               pgrp := _C_int(sys.Pgid)
                if pgrp == 0 {
                        r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_getpid_trampoline), 0, 0, 0)
                        if err1 != 0 {
                                goto childerror
                        }
-
-                       pgrp = int(r1)
+                       pgrp = _C_int(r1)
                }
 
                // Place process group in foreground.
index ccc0e39e30bda23cb5f7093b750c6562af14bc40..0f0dee8ea5a90cfba5620dcece364b0349ee2ef7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package syscall
 
@@ -46,7 +45,7 @@ type SysProcAttr struct {
        // number in the parent process.
        Foreground   bool
        Pgid         int            // Child's process group ID if Setpgid.
-       Pdeathsig    Signal         // Signal that the process will get when its parent dies (Linux only)
+       Pdeathsig    Signal         // Signal that the process will get when its parent dies (Linux and FreeBSD only)
        Cloneflags   uintptr        // Flags for clone calls (Linux only)
        Unshareflags uintptr        // Flags for unshare calls (Linux only)
        UidMappings  []SysProcIDMap // User ID mappings for user namespaces.
@@ -448,13 +447,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
        // so that pass 2 won't stomp on an fd it needs later.
        if pipe < nextfd {
                _, _, err1 = RawSyscall(SYS_DUP3, uintptr(pipe), uintptr(nextfd), O_CLOEXEC)
-               if _SYS_dup != SYS_DUP3 && err1 == ENOSYS {
-                       _, _, err1 = RawSyscall(_SYS_dup, uintptr(pipe), uintptr(nextfd), 0)
-                       if err1 != 0 {
-                               goto childerror
-                       }
-                       RawSyscall(fcntl64Syscall, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
-               } else if err1 != 0 {
+               if err1 != 0 {
                        goto childerror
                }
                pipe = nextfd
@@ -466,13 +459,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
                                nextfd++
                        }
                        _, _, err1 = RawSyscall(SYS_DUP3, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC)
-                       if _SYS_dup != SYS_DUP3 && err1 == ENOSYS {
-                               _, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(nextfd), 0)
-                               if err1 != 0 {
-                                       goto childerror
-                               }
-                               RawSyscall(fcntl64Syscall, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
-                       } else if err1 != 0 {
+                       if err1 != 0 {
                                goto childerror
                        }
                        fd[i] = nextfd
@@ -497,7 +484,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
                }
                // The new fd is created NOT close-on-exec,
                // which is exactly what we want.
-               _, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(i), 0)
+               _, _, err1 = RawSyscall(SYS_DUP3, uintptr(fd[i]), uintptr(i), 0)
                if err1 != 0 {
                        goto childerror
                }
@@ -553,19 +540,7 @@ childerror:
 
 // Try to open a pipe with O_CLOEXEC set on both file descriptors.
 func forkExecPipe(p []int) (err error) {
-       err = Pipe2(p, O_CLOEXEC)
-       // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it
-       // might not be implemented.
-       if err == ENOSYS {
-               if err = Pipe(p); err != nil {
-                       return
-               }
-               if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil {
-                       return
-               }
-               _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
-       }
-       return
+       return Pipe2(p, O_CLOEXEC)
 }
 
 func formatIDMappings(idMap []SysProcIDMap) []byte {
index 85b59ad00d94650368e0305ba62b507c0b8824b0..80440ca4d6612703e179c0ec1aa5ffc2672aadca 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux
-// +build linux
 
 package syscall_test
 
@@ -111,14 +110,6 @@ func checkUserNS(t *testing.T) {
                        t.Skip("kernel doesn't support user namespaces")
                }
        }
-
-       // When running under the Go continuous build, skip tests for
-       // now when under Kubernetes. (where things are root but not quite)
-       // Both of these are our own environment variables.
-       // See Issue 12815.
-       if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
-               t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
-       }
 }
 
 func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
@@ -201,14 +192,6 @@ func TestUnshare(t *testing.T) {
                t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
        }
 
-       // When running under the Go continuous build, skip tests for
-       // now when under Kubernetes. (where things are root but not quite)
-       // Both of these are our own environment variables.
-       // See Issue 12815.
-       if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
-               t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
-       }
-
        path := "/proc/net/dev"
        if _, err := os.Stat(path); err != nil {
                if os.IsNotExist(err) {
@@ -526,9 +509,7 @@ func mustSupportAmbientCaps(t *testing.T) {
                buf[i] = byte(b)
        }
        ver := string(buf[:])
-       if i := strings.Index(ver, "\x00"); i != -1 {
-               ver = ver[:i]
-       }
+       ver, _, _ = strings.Cut(ver, "\x00")
        if strings.HasPrefix(ver, "2.") ||
                strings.HasPrefix(ver, "3.") ||
                strings.HasPrefix(ver, "4.1.") ||
diff --git a/src/syscall/exec_pdeathsig_test.go b/src/syscall/exec_pdeathsig_test.go
new file mode 100644 (file)
index 0000000..96ae27b
--- /dev/null
@@ -0,0 +1,134 @@
+// 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.
+
+//go:build freebsd || linux
+
+package syscall_test
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "os"
+       "os/exec"
+       "os/signal"
+       "path/filepath"
+       "syscall"
+       "testing"
+       "time"
+)
+
+func TestDeathSignal(t *testing.T) {
+       if os.Getuid() != 0 {
+               t.Skip("skipping root only test")
+       }
+
+       // Copy the test binary to a location that a non-root user can read/execute
+       // after we drop privileges
+       tempDir, err := os.MkdirTemp("", "TestDeathSignal")
+       if err != nil {
+               t.Fatalf("cannot create temporary directory: %v", err)
+       }
+       defer os.RemoveAll(tempDir)
+       os.Chmod(tempDir, 0755)
+
+       tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
+
+       src, err := os.Open(os.Args[0])
+       if err != nil {
+               t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
+       }
+       defer src.Close()
+
+       dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+       if err != nil {
+               t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
+       }
+       if _, err := io.Copy(dst, src); err != nil {
+               t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
+       }
+       err = dst.Close()
+       if err != nil {
+               t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
+       }
+
+       cmd := exec.Command(tmpBinary)
+       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)
+       }
+       chldStdout, err := cmd.StdoutPipe()
+       if err != nil {
+               t.Fatalf("failed to create new stdout pipe: %v", err)
+       }
+       cmd.Stderr = os.Stderr
+
+       err = cmd.Start()
+       defer cmd.Wait()
+       if err != nil {
+               t.Fatalf("failed to start first child process: %v", err)
+       }
+
+       chldPipe := bufio.NewReader(chldStdout)
+
+       if got, err := chldPipe.ReadString('\n'); got == "start\n" {
+               syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
+
+               go func() {
+                       time.Sleep(5 * time.Second)
+                       chldStdin.Close()
+               }()
+
+               want := "ok\n"
+               if got, err = chldPipe.ReadString('\n'); got != want {
+                       t.Fatalf("expected %q, received %q, %v", want, got, err)
+               }
+       } else {
+               t.Fatalf("did not receive start from child, received %q, %v", got, err)
+       }
+}
+
+func deathSignalParent() {
+       cmd := exec.Command(os.Args[0])
+       cmd.Env = append(os.Environ(),
+               "GO_DEATHSIG_PARENT=",
+               "GO_DEATHSIG_CHILD=1",
+       )
+       cmd.Stdin = os.Stdin
+       cmd.Stdout = os.Stdout
+       attrs := syscall.SysProcAttr{
+               Pdeathsig: syscall.SIGUSR1,
+               // UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
+               // unused on Ubuntu
+               Credential: &syscall.Credential{Uid: 99, Gid: 99},
+       }
+       cmd.SysProcAttr = &attrs
+
+       err := cmd.Start()
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err)
+               os.Exit(1)
+       }
+       cmd.Wait()
+       os.Exit(0)
+}
+
+func deathSignalChild() {
+       c := make(chan os.Signal, 1)
+       signal.Notify(c, syscall.SIGUSR1)
+       go func() {
+               <-c
+               fmt.Println("ok")
+               os.Exit(0)
+       }()
+       fmt.Println("start")
+
+       buf := make([]byte, 32)
+       os.Stdin.Read(buf)
+
+       // We expected to be signaled before stdin closed
+       fmt.Println("not ok")
+       os.Exit(1)
+}
index f54fc8385d59200e6933d4dfcc49e7d07e6a37c3..90e5349bf458db4eeb5996888081dcc1bc63aabd 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build solaris
-// +build solaris
 
 package syscall
 
index 54b18dccd73e266e680d9a5e3250be18ce08ead4..64eb5ed9f047a80c5c2414572484fec131892421 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 // Fork, exec, wait, etc.
 
index 866671ba2aca759a4c959f8695c775acdc5c71e8..b7ae77552bac68e9b68d22996cebc0e26a858a7b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package syscall_test
 
@@ -14,7 +13,6 @@ import (
        "os"
        "os/exec"
        "os/signal"
-       "runtime"
        "syscall"
        "testing"
        "time"
@@ -328,7 +326,6 @@ func TestExecHelper(t *testing.T) {
        // We don't have to worry about restoring these values.
        // We are in a child process that only runs this test,
        // and we are going to call syscall.Exec anyhow.
-       runtime.GOMAXPROCS(50)
        os.Setenv("GO_WANT_HELPER_PROCESS", "3")
 
        stop := time.Now().Add(time.Second)
index 18d15028c3d3bba9812e58ea0555f618f6e5a07c..9d10d6a51271f62c2b7daa86db0c774dff5084b6 100644 (file)
@@ -390,8 +390,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
        }
        fd = fd[:j]
 
+       willInheritHandles := len(fd) > 0 && !sys.NoInheritHandles
+
        // Do not accidentally inherit more than these handles.
-       if len(fd) > 0 {
+       if willInheritHandles {
                err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil)
                if err != nil {
                        return 0, 0, err
@@ -401,9 +403,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
        pi := new(ProcessInformation)
        flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT
        if sys.Token != 0 {
-               err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
+               err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
        } else {
-               err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
+               err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi)
        }
        if err != nil {
                return 0, 0, err
index 2d2c67673d7887fc0b81c04bb12ee99445efd316..2f678d25664bc3283b8977a756be939559c57615 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || linux || netbsd || openbsd
-// +build dragonfly freebsd linux netbsd openbsd
 
 package syscall
 
index 3b43b6aeded16e928baba8bcb46874e2c89ad4eb..8cb8f16153a9be79e86c823f608b778a56b8f6be 100644 (file)
@@ -1,5 +1,4 @@
 //go:build linux || freebsd || openbsd || netbsd || dragonfly
-// +build linux freebsd openbsd netbsd dragonfly
 
 // Copyright 2014 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index 2f3277497cd577946fba274ee5b53aaa01782b14..76a09fc47e3fa823e4d4b8cf7f126fb5961f0cd1 100644 (file)
@@ -6,7 +6,6 @@
 // internal/syscall/unix/fcntl_linux_32bit.go.
 
 //go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle)
-// +build linux,386 linux,arm linux,mips linux,mipsle
 
 package syscall
 
index 79cbdf4150f5354fb3ccb913019ded8a656ace5e..6f7d29ce67aea1597649d08e1eeed3f4506531ed 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || solaris
-// +build aix darwin solaris
 
 package syscall
 
index e57240c156157a033e4211157049c467c17b84b6..312244c0d8ab0c604b917c0b72c4652ebe58ef1f 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build dragonfly || freebsd || netbsd || openbsd
-// +build dragonfly freebsd netbsd openbsd
 
 package syscall
 
index 0170516201473f85afc8e7ecc49a92ba65194b91..84a554e8b9128ee541d0d90c7585aa4a0a5344d8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package syscall
 
index 814e656649b8eda0ae780ce63ddbafc682a9205b..ddd8208c15483766dfae78dde39d6cdce13fd6e5 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || freebsd || netbsd || openbsd
-// +build darwin freebsd netbsd openbsd
 
 package syscall_test
 
index 4bd9c5d595eb72a8a186de52d2beaf80e9aa7b9d..fb61daea7cea00f4732496c8a0a344e73ccbe345 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package js
 
index ab23e5fbfc0cce35a8821c6de43ef36bbaf90157..77fb9e66ca91f2d62be29984627bec1e642da0f3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package js
 
@@ -15,8 +14,6 @@ var (
        nextFuncID uint32 = 1
 )
 
-var _ Wrapper = Func{} // Func must implement Wrapper
-
 // Func is a wrapped Go function to be called by JavaScript.
 type Func struct {
        Value // the JavaScript function that invokes the Go function
index d805d6916644d7d0c0dde33d1706bf87e72d064a..d80d5d63de2a5ab9ecfb1ebff8c8aeff07b4ccab 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 // Package js gives access to the WebAssembly host environment when using the js/wasm architecture.
 // Its API is based on JavaScript semantics.
@@ -28,12 +27,6 @@ type ref uint64
 // nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above).
 const nanHead = 0x7FF80000
 
-// Wrapper is implemented by types that are backed by a JavaScript value.
-type Wrapper interface {
-       // JSValue returns a JavaScript value associated with an object.
-       JSValue() Value
-}
-
 // Value represents a JavaScript value. The zero value is the JavaScript value "undefined".
 // Values can be checked for equality with the Equal method.
 type Value struct {
@@ -51,11 +44,6 @@ const (
        typeFlagFunction
 )
 
-// JSValue implements Wrapper interface.
-func (v Value) JSValue() Value {
-       return v
-}
-
 func makeValue(r ref) Value {
        var gcPtr *ref
        typeFlag := (r >> 32) & 7
@@ -162,10 +150,10 @@ func Global() Value {
 // Panics if x is not one of the expected types.
 func ValueOf(x interface{}) Value {
        switch x := x.(type) {
-       case Value: // should precede Wrapper to avoid a loop
+       case Value:
                return x
-       case Wrapper:
-               return x.JSValue()
+       case Func:
+               return x.Value
        case nil:
                return valueNull
        case bool:
index 8088a897f60716ffb2f439f177fc7fa4372b99ce..fa8c782459c42c4a4da15012af31fa2b7a69e99c 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 // To run these tests:
 //
index e0ec46681d14a5ed20f10e713461089d05a4ebae..dce61f322c08e3184aaa69cf87e9c7b2b4847a16 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // mkasm.go generates assembly trampolines to call library routines from Go.
 // This program must be run after mksyscall.pl.
index 94e8d92eff86c0e03df88125c1848f2d6f9f266f..4f81b81b57e528891f211ebd5aee7ea3b2f23157 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // mkpost processes the output of cgo -godefs to
 // modify the generated types. It is used to clean up
index d8e8a713c554ccea104e077e77aed836381d1c4a..39517bc7f141e9690aa760c8b6f9b74659684fa6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // mksyscall_windows wraps golang.org/x/sys/windows/mkwinsyscall.
 package main
index e3909f1afb05fd9449b62a70cb28b35ce606c8b8..3e9c08d67d38fb6ffc11bd67e054991adb294641 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build aix darwin dragonfly freebsd linux netbsd openbsd
 
 package syscall_test
 
index 89fb75f03c9d965614b59b18c57bf3c8dd122922..89c580799fc858ca591b47f7fd79b02d5863bfa8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build msan
-// +build msan
 
 package syscall
 
index 85097025a0bdbec1e49eb1b32ed46838dd3ab7a6..fba8a5f716ed263dea2172bbb155e154509ff2c6 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !msan
-// +build !msan
 
 package syscall
 
index ed462025bbc88c1d3f5e4972e51320ba1c726b25..253ab22dd90c71e85277ba4fd64ad77ea02db582 100644 (file)
@@ -6,7 +6,6 @@
 // This file only exists to make the compiler happy.
 
 //go:build js && wasm
-// +build js,wasm
 
 package syscall
 
index 0937ff797ad4dcd3ae3323a8a71e1d75c6775d7a..2d810705bf1bcd38f162bf5a639244619af6a163 100644 (file)
@@ -55,14 +55,22 @@ func NetlinkRIB(proto, family int) ([]byte, error) {
                return nil, err
        }
        defer Close(s)
-       lsa := &SockaddrNetlink{Family: AF_NETLINK}
-       if err := Bind(s, lsa); err != nil {
+       sa := &SockaddrNetlink{Family: AF_NETLINK}
+       if err := Bind(s, sa); err != nil {
                return nil, err
        }
        wb := newNetlinkRouteRequest(proto, 1, family)
-       if err := Sendto(s, wb, 0, lsa); err != nil {
+       if err := Sendto(s, wb, 0, sa); err != nil {
                return nil, err
        }
+       lsa, err := Getsockname(s)
+       if err != nil {
+               return nil, err
+       }
+       lsanl, ok := lsa.(*SockaddrNetlink)
+       if !ok {
+               return nil, EINVAL
+       }
        var tab []byte
        rbNew := make([]byte, Getpagesize())
 done:
@@ -82,16 +90,7 @@ done:
                        return nil, err
                }
                for _, m := range msgs {
-                       lsa, err := Getsockname(s)
-                       if err != nil {
-                               return nil, err
-                       }
-                       switch v := lsa.(type) {
-                       case *SockaddrNetlink:
-                               if m.Header.Seq != 1 || m.Header.Pid != v.Pid {
-                                       return nil, EINVAL
-                               }
-                       default:
+                       if m.Header.Seq != 1 || m.Header.Pid != lsanl.Pid {
                                return nil, EINVAL
                        }
                        if m.Header.Type == NLMSG_DONE {
index b968c7c7f3a910de8b1c942e7d60c531386f832c..519e451c73ff94a5f27e8f6d29330823253fc941 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !ios
-// +build !ios
 
 package syscall
 
index 5209d1e0dd16057e3c3e84b1987f078fc42a63b3..fa8d0007154997b549453df1ebd3c008ac762f7a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ios
-// +build ios
 
 package syscall
 
index e9321a4e645596167f68a26436478dc64914b975..8e47ff888e935856f7635e4515085caca99dafc4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 package syscall
 
index 412833a37cb2d5a05f33b41c0c68669eb066e8ce..c70f0bb0d3c16f89af0fc9f42fc5aab3252c0567 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (freebsd && 386) || (freebsd && arm)
-// +build freebsd,386 freebsd,arm
 
 package syscall
 
index 5300bed47173852ac5d7f0f822fb5f32ac739f99..9febdfaf3540b297b86421c1f3b5062bb14a199a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build (freebsd && amd64) || (freebsd && arm64)
-// +build freebsd,amd64 freebsd,arm64
 
 package syscall
 
index 64897fe43c6408e18522da062b8ca9ab45ae9acf..6920f33987cd607231bc7916ac9a8c21a0891687 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (386 || arm)
-// +build linux
-// +build 386 arm
 
 package syscall
 
index 3b36f66fa2639d355bc3c0e01208a45147570839..c995d258eb93dd2e94c024ff71679a5ce3a4ea2a 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && !386 && !arm
-// +build linux,!386,!arm
 
 package syscall
 
index 99913b9a88bdc0063ccb78cdad00a5b5c53d988b..a3dcf818da7e8ece79d4d37938168679fca50aa1 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 // Socket control messages
 
index bd8dcfa34cf7efbb37466cf7da25b0e153118e96..845bd9df9909706db00bce26b4b2b9be74529b47 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin freebsd linux netbsd openbsd solaris
 
 package syscall
 
index 9c6afba442e2f2adf2227fb05845af8aeee9ddc4..0f5101999ff9687d8ed71e9339cb835ee9f3206f 100644 (file)
@@ -31,6 +31,8 @@ const (
        F_DUPFD_CLOEXEC = 0
        // AF_LOCAL doesn't exist on AIX
        AF_LOCAL = AF_UNIX
+
+       _F_DUP2FD_CLOEXEC = 0
 )
 
 func (ts *StTimespec_t) Unix() (sec int64, nsec int64) {
@@ -253,9 +255,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
 }
 
@@ -268,9 +268,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
        sa.raw.Scope_id = sa.ZoneId
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
 }
 
@@ -323,10 +321,9 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
        return
 }
 
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
        var msg Msghdr
-       var rsa RawSockaddrAny
-       msg.Name = (*byte)(unsafe.Pointer(&rsa))
+       msg.Name = (*byte)(unsafe.Pointer(rsa))
        msg.Namelen = uint32(SizeofSockaddrAny)
        var iov Iovec
        if len(p) > 0 {
@@ -355,27 +352,10 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
        }
        oobn = int(msg.Controllen)
        recvflags = int(msg.Flags)
-       // source address is only specified if the socket is unconnected
-       if rsa.Addr.Family != AF_UNSPEC {
-               from, err = anyToSockaddr(&rsa)
-       }
-       return
-}
-
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
-       _, err = SendmsgN(fd, p, oob, to, flags)
        return
 }
 
-func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
-       var ptr unsafe.Pointer
-       var salen _Socklen
-       if to != nil {
-               ptr, salen, err = to.sockaddr()
-               if err != nil {
-                       return 0, err
-               }
-       }
+func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
        var msg Msghdr
        msg.Name = (*byte)(unsafe.Pointer(ptr))
        msg.Namelen = uint32(salen)
@@ -441,9 +421,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa := new(SockaddrInet4)
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
 
        case AF_INET6:
@@ -451,9 +429,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa := new(SockaddrInet6)
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
        }
        return nil, EAFNOSUPPORT
index 595e705856ec3f407f3c77fe974e155736b298a9..5e636d5258046296d17ecdedd347a904631de3d3 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || netbsd || openbsd
-// +build darwin dragonfly freebsd netbsd openbsd
 
 // BSD system call wrappers shared by *BSD based systems
 // including OS X (Darwin) and FreeBSD.  Like the other
@@ -168,9 +167,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
 }
 
@@ -184,9 +181,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
        sa.raw.Scope_id = sa.ZoneId
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
 }
 
@@ -215,9 +210,7 @@ func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
        sa.raw.Nlen = sa.Nlen
        sa.raw.Alen = sa.Alen
        sa.raw.Slen = sa.Slen
-       for i := 0; i < len(sa.raw.Data); i++ {
-               sa.raw.Data[i] = sa.Data[i]
-       }
+       sa.raw.Data = sa.Data
        return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
 }
 
@@ -233,9 +226,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa.Nlen = pp.Nlen
                sa.Alen = pp.Alen
                sa.Slen = pp.Slen
-               for i := 0; i < len(sa.Data); i++ {
-                       sa.Data[i] = pp.Data[i]
-               }
+               sa.Data = pp.Data
                return sa, nil
 
        case AF_UNIX:
@@ -267,9 +258,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa := new(SockaddrInet4)
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
 
        case AF_INET6:
@@ -278,9 +267,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
                sa.ZoneId = pp.Scope_id
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
        }
        return nil, EAFNOSUPPORT
@@ -371,10 +358,9 @@ func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
 //sys   sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
 //sys  recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
 
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
        var msg Msghdr
-       var rsa RawSockaddrAny
-       msg.Name = (*byte)(unsafe.Pointer(&rsa))
+       msg.Name = (*byte)(unsafe.Pointer(rsa))
        msg.Namelen = uint32(SizeofSockaddrAny)
        var iov Iovec
        if len(p) > 0 {
@@ -398,29 +384,12 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
        }
        oobn = int(msg.Controllen)
        recvflags = int(msg.Flags)
-       // source address is only specified if the socket is unconnected
-       if rsa.Addr.Family != AF_UNSPEC {
-               from, err = anyToSockaddr(&rsa)
-       }
        return
 }
 
 //sys  sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
 
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
-       _, err = SendmsgN(fd, p, oob, to, flags)
-       return
-}
-
-func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
-       var ptr unsafe.Pointer
-       var salen _Socklen
-       if to != nil {
-               ptr, salen, err = to.sockaddr()
-               if err != nil {
-                       return 0, err
-               }
-       }
+func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
        var msg Msghdr
        msg.Name = (*byte)(unsafe.Pointer(ptr))
        msg.Namelen = uint32(salen)
@@ -524,12 +493,7 @@ func UtimesNano(path string, ts []Timespec) error {
        if len(ts) != 2 {
                return EINVAL
        }
-       // Darwin setattrlist can set nanosecond timestamps
-       err := setattrlistTimes(path, ts)
-       if err != ENOSYS {
-               return err
-       }
-       err = utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+       err := utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
        if err != ENOSYS {
                return err
        }
index 2d8a8cbfe6125bfe2fe3d3323e72368ad42c76a9..98fab1d3963c8dd9e4ad1871d4829deb94983ccc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || openbsd
-// +build darwin dragonfly freebsd openbsd
 
 package syscall_test
 
index a4fe4f1962bb7e096ff2c17461f775150dbf2455..5bb34e300c5f5f18330cc980479353a7aecaa842 100644 (file)
@@ -72,22 +72,6 @@ func direntNamlen(buf []byte) (uint64, bool) {
 func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
 func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
 
-const (
-       attrBitMapCount = 5
-       attrCmnModtime  = 0x00000400
-       attrCmnAcctime  = 0x00001000
-)
-
-type attrList struct {
-       bitmapCount uint16
-       _           uint16
-       CommonAttr  uint32
-       VolAttr     uint32
-       DirAttr     uint32
-       FileAttr    uint32
-       Forkattr    uint32
-}
-
 //sysnb pipe(p *[2]int32) (err error)
 
 func Pipe(p []int) (err error) {
@@ -120,42 +104,7 @@ func libc_getfsstat_trampoline()
 
 //go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib"
 
-func setattrlistTimes(path string, times []Timespec) error {
-       _p0, err := BytePtrFromString(path)
-       if err != nil {
-               return err
-       }
-
-       var attrList attrList
-       attrList.bitmapCount = attrBitMapCount
-       attrList.CommonAttr = attrCmnModtime | attrCmnAcctime
-
-       // order is mtime, atime: the opposite of Chtimes
-       attributes := [2]Timespec{times[1], times[0]}
-       const options = 0
-       _, _, e1 := syscall6(
-               abi.FuncPCABI0(libc_setattrlist_trampoline),
-               uintptr(unsafe.Pointer(_p0)),
-               uintptr(unsafe.Pointer(&attrList)),
-               uintptr(unsafe.Pointer(&attributes)),
-               uintptr(unsafe.Sizeof(attributes)),
-               uintptr(options),
-               0,
-       )
-       if e1 != 0 {
-               return e1
-       }
-       return nil
-}
-
-func libc_setattrlist_trampoline()
-
-//go:cgo_import_dynamic libc_setattrlist setattrlist "/usr/lib/libSystem.B.dylib"
-
-func utimensat(dirfd int, path string, times *[2]Timespec, flag int) error {
-       // Darwin doesn't support SYS_UTIMENSAT
-       return ENOSYS
-}
+//sys  utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
 
 /*
  * Wrapped
index b01a4ada67525e356195c6a1314a70bdeff50098..cc92c4a93edc9c50c70119b147ec020a0e23bf61 100644 (file)
@@ -17,6 +17,8 @@ import (
        "unsafe"
 )
 
+const _SYS_DUP3 = 0
+
 // See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h
 var (
        osreldateOnce sync.Once
@@ -156,11 +158,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
-       // used on Darwin for UtimesNano
-       return ENOSYS
-}
-
 /*
  * Exposed directly
  */
diff --git a/src/syscall/syscall_dup2_linux.go b/src/syscall/syscall_dup2_linux.go
deleted file mode 100644 (file)
index 351a96e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-
-//go:build !android && (386 || amd64 || arm || mips || mipsle || mips64 || mips64le || ppc64 || ppc64le || s390x)
-// +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
deleted file mode 100644 (file)
index 66ec67b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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.
-
-//go:build android || arm64 || riscv64
-// +build android arm64 riscv64
-
-package syscall
-
-const _SYS_dup = SYS_DUP3
index 7c7b89aab9030aa91683b372267d96bb49166217..6f44b25cb9a415e546c81f5007188596c4d65541 100644 (file)
@@ -176,11 +176,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
-       // used on Darwin for UtimesNano
-       return ENOSYS
-}
-
 func Stat(path string, st *Stat_t) (err error) {
        var oldStat stat_freebsd11_t
        if supportsABI(_ino64First) {
index 89c7959d0c43ac3e81b0e9d70722fe8c48dc43fe..f04b12b6d3ca4df1c5749cb8d970ecb5e035ccd4 100644 (file)
@@ -3,12 +3,12 @@
 // license that can be found in the LICENSE file.
 
 //go:build freebsd
-// +build freebsd
 
 package syscall_test
 
 import (
        "fmt"
+       "os"
        "syscall"
        "testing"
        "unsafe"
@@ -53,3 +53,13 @@ func TestConvertFromDirent11(t *testing.T) {
                }
        }
 }
+
+func TestMain(m *testing.M) {
+       if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
+               deathSignalParent()
+       } else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
+               deathSignalChild()
+       }
+
+       os.Exit(m.Run())
+}
index ef95fe58f7c58cd70ead9ba6429b3af5f02b083d..de6b1600484a8d2e28589f353f32adee89869c86 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 // Illumos system calls not present on Solaris.
 
index ed70d622842da2c45106474f14ca0a95388eb442..cd9549906360b1b71bea8fc34d2b7875b52ab502 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package syscall
 
index dfce3d0a4bac336618108e00b7ef0927afbb7029..c0022996412665fea08ad66939edd5ee5a008346 100644 (file)
@@ -161,6 +161,23 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
        return openat(dirfd, path, flags|O_LARGEFILE, mode)
 }
 
+func Pipe(p []int) error {
+       return Pipe2(p, 0)
+}
+
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) error {
+       if len(p) != 2 {
+               return EINVAL
+       }
+       var pp [2]_C_int
+       err := pipe2(&pp, flags)
+       p[0] = int(pp[0])
+       p[1] = int(pp[1])
+       return err
+}
+
 //sys  readlinkat(dirfd int, path string, buf []byte) (n int, err error)
 
 func Readlink(path string, buf []byte) (n int, err error) {
@@ -204,18 +221,7 @@ func UtimesNano(path string, ts []Timespec) (err error) {
        if len(ts) != 2 {
                return EINVAL
        }
-       err = utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
-       if err != ENOSYS {
-               return err
-       }
-       // If the utimensat syscall isn't available (utimensat was added to Linux
-       // in 2.6.22, Released, 8 July 2007) then fall back to utimes
-       var tv [2]Timeval
-       for i := 0; i < 2; i++ {
-               tv[i].Sec = ts[i].Sec
-               tv[i].Usec = ts[i].Nsec / 1000
-       }
-       return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+       return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
 }
 
 func Futimesat(dirfd int, path string, tv []Timeval) (err error) {
@@ -387,9 +393,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
 }
 
@@ -402,9 +406,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
        sa.raw.Scope_id = sa.ZoneId
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
 }
 
@@ -455,9 +457,7 @@ func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) {
        sa.raw.Hatype = sa.Hatype
        sa.raw.Pkttype = sa.Pkttype
        sa.raw.Halen = sa.Halen
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil
 }
 
@@ -496,9 +496,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa.Hatype = pp.Hatype
                sa.Pkttype = pp.Pkttype
                sa.Halen = pp.Halen
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
 
        case AF_UNIX:
@@ -531,9 +529,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa := new(SockaddrInet4)
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
 
        case AF_INET6:
@@ -542,9 +538,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
                sa.ZoneId = pp.Scope_id
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
        }
        return nil, EAFNOSUPPORT
@@ -553,11 +547,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
 func Accept(fd int) (nfd int, sa Sockaddr, err error) {
        var rsa RawSockaddrAny
        var len _Socklen = SizeofSockaddrAny
-       // Try accept4 first for Android, then try accept for kernel older than 2.6.28
        nfd, err = accept4(fd, &rsa, &len, 0)
-       if err == ENOSYS {
-               nfd, err = accept(fd, &rsa, &len)
-       }
        if err != nil {
                return
        }
@@ -648,10 +638,9 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
        return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
 }
 
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
        var msg Msghdr
-       var rsa RawSockaddrAny
-       msg.Name = (*byte)(unsafe.Pointer(&rsa))
+       msg.Name = (*byte)(unsafe.Pointer(rsa))
        msg.Namelen = uint32(SizeofSockaddrAny)
        var iov Iovec
        if len(p) > 0 {
@@ -682,28 +671,10 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
        }
        oobn = int(msg.Controllen)
        recvflags = int(msg.Flags)
-       // source address is only specified if the socket is unconnected
-       if rsa.Addr.Family != AF_UNSPEC {
-               from, err = anyToSockaddr(&rsa)
-       }
        return
 }
 
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
-       _, err = SendmsgN(fd, p, oob, to, flags)
-       return
-}
-
-func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
-       var ptr unsafe.Pointer
-       var salen _Socklen
-       if to != nil {
-               var err error
-               ptr, salen, err = to.sockaddr()
-               if err != nil {
-                       return 0, err
-               }
-       }
+func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
        var msg Msghdr
        msg.Name = (*byte)(ptr)
        msg.Namelen = uint32(salen)
index 0db037470d438761c4c290d27384aafe43c7eda2..98442055d80ea7c5c6837c5891bb6e7726c88722 100644 (file)
@@ -22,32 +22,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: int32(sec), Usec: int32(usec)}
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 // 64-bit file system and 32-bit uid calls
 // (386 default is 32-bit file system and 16-bit uid).
 //sys  Dup2(oldfd int, newfd int) (err error)
index 5df3f796d1677785114bad853ae8479e8fee83b6..04acd063fa69e407184f67a8394e088732f43f4f 100644 (file)
@@ -110,32 +110,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-//sysnb        pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe(&pp)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func (r *PtraceRegs) PC() uint64 { return r.Rip }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
index e887cf788f3ae20cab1ee83a502ff054f1383d97..f2f342e7ed25ed485ec12a187308f82825c3d516 100644 (file)
@@ -22,36 +22,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: int32(sec), Usec: int32(usec)}
 }
 
-//sysnb pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       // Try pipe2 first for Android O, then try pipe for kernel 2.6.23.
-       err = pipe2(&pp, 0)
-       if err == ENOSYS {
-               err = pipe(&pp)
-       }
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 // Underlying system call writes to newoffset via pointer.
 // Implemented in assembly to avoid allocation.
 func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
index f575c84c930c2d0a884893289a285a939a0b4b07..990e732f359f0404654bd076cdcc9aee9482359f 100644 (file)
@@ -42,7 +42,6 @@ func EpollCreate(size int) (fd int, err error) {
 //sys  Setfsgid(gid int) (err error)
 //sys  Setfsuid(uid int) (err error)
 //sysnb        setrlimit(resource int, rlim *Rlimit) (err error)
-//sysnb        Setreuid(ruid int, euid int) (err error)
 //sys  Shutdown(fd int, how int) (err error)
 //sys  Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
 
@@ -146,30 +145,6 @@ func utimes(path string, tv *[2]Timeval) (err error) {
        return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 // Getrlimit prefers the prlimit64 system call. See issue 38604.
 func Getrlimit(resource int, rlim *Rlimit) error {
        err := prlimit(0, resource, nil, rlim)
index 5feb03e915adf0021f5060b2fa6e5b88d9b973b7..7c9dd80614a451c96b37106f6f5bd73b38f4b80c 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips64 || mips64le)
-// +build linux
-// +build mips64 mips64le
 
 package syscall
 
@@ -103,30 +101,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func Ioperm(from int, num int, on int) (err error) {
        return ENOSYS
 }
index 39104d71d84520f8fe6dd3bb17d8944635354318..741eeb14bbb67b7c5d717b94d9d5fbf21f1a3338 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (mips || mipsle)
-// +build linux
-// +build mips mipsle
 
 package syscall
 
@@ -112,29 +110,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: int32(sec), Usec: int32(usec)}
 }
 
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe() (p1 int, p2 int, err error)
-
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       p[0], p[1], err = pipe()
-       return
-}
-
 //sys  mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
 
 func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
index 495ae29757cac649b2a3b9cb754a0be19d1ff1e2..cc1b72e0e79cca158dfcd7559191c3b0e9a5661a 100644 (file)
@@ -3,8 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build linux && (ppc64 || ppc64le)
-// +build linux
-// +build ppc64 ppc64le
 
 package syscall
 
@@ -82,30 +80,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func (r *PtraceRegs) PC() uint64 { return r.Nip }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Nip = pc }
index 2a0fe64d258617a8dc147d17d55cc8d205e0905b..bcb89c6e9aca20b63d42246ff7cb3bc5f2faa3b0 100644 (file)
@@ -149,30 +149,6 @@ func utimes(path string, tv *[2]Timeval) (err error) {
        return utimensat(_AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 func (r *PtraceRegs) PC() uint64 { return r.Pc }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc }
index 0f6f6277bbfda2b02aab58268b77ce9b796c2097..123664f5b2b98acf760310c11eef871eb10b3fdb 100644 (file)
@@ -74,30 +74,6 @@ func setTimeval(sec, usec int64) Timeval {
        return Timeval{Sec: sec, Usec: usec}
 }
 
-func Pipe(p []int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, 0)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-       if len(p) != 2 {
-               return EINVAL
-       }
-       var pp [2]_C_int
-       err = pipe2(&pp, flags)
-       p[0] = int(pp[0])
-       p[1] = int(pp[1])
-       return
-}
-
 // Linux on s390x uses the old mmap interface, which requires arguments to be passed in a struct.
 // mmap2 also requires arguments to be passed in a struct; it is currently not exposed in <asm/unistd.h>.
 func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
index 442dc9f10eb87f17b8b1f7d560011c8329fb44cf..8d828be0153348feeb9014d1a9894e3de1d17d16 100644 (file)
@@ -5,13 +5,11 @@
 package syscall_test
 
 import (
-       "bufio"
        "fmt"
        "io"
        "io/fs"
        "os"
        "os/exec"
-       "os/signal"
        "path/filepath"
        "runtime"
        "sort"
@@ -19,7 +17,6 @@ import (
        "strings"
        "syscall"
        "testing"
-       "time"
        "unsafe"
 )
 
@@ -153,120 +150,6 @@ func TestMain(m *testing.M) {
        os.Exit(m.Run())
 }
 
-func TestLinuxDeathSignal(t *testing.T) {
-       if os.Getuid() != 0 {
-               t.Skip("skipping root only test")
-       }
-
-       // Copy the test binary to a location that a non-root user can read/execute
-       // after we drop privileges
-       tempDir, err := os.MkdirTemp("", "TestDeathSignal")
-       if err != nil {
-               t.Fatalf("cannot create temporary directory: %v", err)
-       }
-       defer os.RemoveAll(tempDir)
-       os.Chmod(tempDir, 0755)
-
-       tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
-
-       src, err := os.Open(os.Args[0])
-       if err != nil {
-               t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
-       }
-       defer src.Close()
-
-       dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
-       if err != nil {
-               t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
-       }
-       if _, err := io.Copy(dst, src); err != nil {
-               t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
-       }
-       err = dst.Close()
-       if err != nil {
-               t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
-       }
-
-       cmd := exec.Command(tmpBinary)
-       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)
-       }
-       chldStdout, err := cmd.StdoutPipe()
-       if err != nil {
-               t.Fatalf("failed to create new stdout pipe: %v", err)
-       }
-       cmd.Stderr = os.Stderr
-
-       err = cmd.Start()
-       defer cmd.Wait()
-       if err != nil {
-               t.Fatalf("failed to start first child process: %v", err)
-       }
-
-       chldPipe := bufio.NewReader(chldStdout)
-
-       if got, err := chldPipe.ReadString('\n'); got == "start\n" {
-               syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
-
-               go func() {
-                       time.Sleep(5 * time.Second)
-                       chldStdin.Close()
-               }()
-
-               want := "ok\n"
-               if got, err = chldPipe.ReadString('\n'); got != want {
-                       t.Fatalf("expected %q, received %q, %v", want, got, err)
-               }
-       } else {
-               t.Fatalf("did not receive start from child, received %q, %v", got, err)
-       }
-}
-
-func deathSignalParent() {
-       cmd := exec.Command(os.Args[0])
-       cmd.Env = append(os.Environ(),
-               "GO_DEATHSIG_PARENT=",
-               "GO_DEATHSIG_CHILD=1",
-       )
-       cmd.Stdin = os.Stdin
-       cmd.Stdout = os.Stdout
-       attrs := syscall.SysProcAttr{
-               Pdeathsig: syscall.SIGUSR1,
-               // UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
-               // unused on Ubuntu
-               Credential: &syscall.Credential{Uid: 99, Gid: 99},
-       }
-       cmd.SysProcAttr = &attrs
-
-       err := cmd.Start()
-       if err != nil {
-               fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err)
-               os.Exit(1)
-       }
-       cmd.Wait()
-       os.Exit(0)
-}
-
-func deathSignalChild() {
-       c := make(chan os.Signal, 1)
-       signal.Notify(c, syscall.SIGUSR1)
-       go func() {
-               <-c
-               fmt.Println("ok")
-               os.Exit(0)
-       }()
-       fmt.Println("start")
-
-       buf := make([]byte, 32)
-       os.Stdin.Read(buf)
-
-       // We expected to be signaled before stdin closed
-       fmt.Println("not ok")
-       os.Exit(1)
-}
-
 func TestParseNetlinkMessage(t *testing.T) {
        for i, b := range [][]byte{
                {103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3,
index fc13b706b5da3c621f87177263e62984d433ea53..cebef10be885949b984ddd1462f70479cb3fa21c 100644 (file)
@@ -14,6 +14,8 @@ package syscall
 
 import "unsafe"
 
+const _SYS_DUP3 = SYS_DUP3
+
 type SockaddrDatalink struct {
        Len    uint8
        Family uint8
@@ -146,11 +148,6 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
        return -1, ENOSYS
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
-       // used on Darwin for UtimesNano
-       return ENOSYS
-}
-
 /*
  * Exposed directly
  */
index 5a5ba5a51b07b7d7f908b74a2831c2ab57c338c7..195cf8617ca70f6e02eb13afa6be7685a70995a2 100644 (file)
@@ -121,11 +121,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
        return
 }
 
-func setattrlistTimes(path string, times []Timespec) error {
-       // used on Darwin for UtimesNano
-       return ENOSYS
-}
-
 /*
  * Exposed directly
  */
index 15870ce1ee1523289608e02f9a98f82b2a1c81be..bddeda637a9815741058e9249b7a8b9ecdd38000 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && mips64
-// +build openbsd,mips64
 
 package syscall
 
index e67ee4e571c264eae8e1aea91d042666cab6c623..15b68fd0fcf51c780738f12ee73b00526f1c36ac 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build openbsd && !mips64
-// +build openbsd,!mips64
 
 package syscall
 
index b259dc69755b7d9cd3a4f74c00ed624590386dac..e8ae2e9911bafa336ce75b93eeff422602366088 100644 (file)
@@ -4,6 +4,8 @@
 
 package syscall
 
+const _SYS_DUP3 = 0
+
 func setTimespec(sec, nsec int64) Timespec {
        return Timespec{Sec: sec, Nsec: nsec}
 }
index 45729d9e8e9698b187aced0e53eb75f79d0bd54c..5b128de77954574f1f29eb324d78a57ad3593139 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd linux netbsd openbsd
 
 package syscall_test
 
index daa4b88a71d6fcb6d9d03c3048006d52fd9c135f..5f12f229c4c78622d078a3afc66c0b80fc53841e 100644 (file)
@@ -14,6 +14,8 @@ package syscall
 
 import "unsafe"
 
+const _F_DUP2FD_CLOEXEC = F_DUP2FD_CLOEXEC
+
 // Implemented in asm_solaris_amd64.s.
 func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
 func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
@@ -67,9 +69,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
 }
 
@@ -82,9 +82,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
        sa.raw.Scope_id = sa.ZoneId
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
 }
 
@@ -302,9 +300,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                sa := new(SockaddrInet4)
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
 
        case AF_INET6:
@@ -313,9 +309,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
                sa.ZoneId = pp.Scope_id
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
        }
        return nil, EAFNOSUPPORT
@@ -338,10 +332,9 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
        return
 }
 
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
        var msg Msghdr
-       var rsa RawSockaddrAny
-       msg.Name = (*byte)(unsafe.Pointer(&rsa))
+       msg.Name = (*byte)(unsafe.Pointer(rsa))
        msg.Namelen = uint32(SizeofSockaddrAny)
        var iov Iovec
        if len(p) > 0 {
@@ -364,29 +357,12 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
                return
        }
        oobn = int(msg.Accrightslen)
-       // source address is only specified if the socket is unconnected
-       if rsa.Addr.Family != AF_UNSPEC {
-               from, err = anyToSockaddr(&rsa)
-       }
-       return
-}
-
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
-       _, err = SendmsgN(fd, p, oob, to, flags)
        return
 }
 
 //sys  sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
 
-func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
-       var ptr unsafe.Pointer
-       var salen _Socklen
-       if to != nil {
-               ptr, salen, err = to.sockaddr()
-               if err != nil {
-                       return 0, err
-               }
-       }
+func sendmsgN(fd int, p, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
        var msg Msghdr
        msg.Name = (*byte)(unsafe.Pointer(ptr))
        msg.Namelen = uint32(salen)
index 5b405b99b4f23744bb35f308ab1b8b015d3994ee..5ee938115d4941a2467abe2b45d4da14693f1770 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package syscall
 
@@ -198,6 +197,9 @@ func Read(fd int, p []byte) (n int, err error) {
        if msanenabled && n > 0 {
                msanWrite(unsafe.Pointer(&p[0]), n)
        }
+       if asanenabled && n > 0 {
+               asanWrite(unsafe.Pointer(&p[0]), n)
+       }
        return
 }
 
@@ -219,6 +221,9 @@ func Write(fd int, p []byte) (n int, err error) {
        if msanenabled && n > 0 {
                msanRead(unsafe.Pointer(&p[0]), n)
        }
+       if asanenabled && n > 0 {
+               asanRead(unsafe.Pointer(&p[0]), n)
+       }
        return
 }
 
@@ -292,6 +297,119 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
        return
 }
 
+func recvfromInet4(fd int, p []byte, flags int, from *SockaddrInet4) (n int, err error) {
+       var rsa RawSockaddrAny
+       var socklen _Socklen = SizeofSockaddrAny
+       if n, err = recvfrom(fd, p, flags, &rsa, &socklen); err != nil {
+               return
+       }
+       pp := (*RawSockaddrInet4)(unsafe.Pointer(&rsa))
+       port := (*[2]byte)(unsafe.Pointer(&pp.Port))
+       from.Port = int(port[0])<<8 + int(port[1])
+       from.Addr = pp.Addr
+       return
+}
+
+func recvfromInet6(fd int, p []byte, flags int, from *SockaddrInet6) (n int, err error) {
+       var rsa RawSockaddrAny
+       var socklen _Socklen = SizeofSockaddrAny
+       if n, err = recvfrom(fd, p, flags, &rsa, &socklen); err != nil {
+               return
+       }
+       pp := (*RawSockaddrInet6)(unsafe.Pointer(&rsa))
+       port := (*[2]byte)(unsafe.Pointer(&pp.Port))
+       from.Port = int(port[0])<<8 + int(port[1])
+       from.ZoneId = pp.Scope_id
+       from.Addr = pp.Addr
+       return
+}
+
+func recvmsgInet4(fd int, p, oob []byte, flags int, from *SockaddrInet4) (n, oobn int, recvflags int, err error) {
+       var rsa RawSockaddrAny
+       n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa)
+       if err != nil {
+               return
+       }
+       pp := (*RawSockaddrInet4)(unsafe.Pointer(&rsa))
+       port := (*[2]byte)(unsafe.Pointer(&pp.Port))
+       from.Port = int(port[0])<<8 + int(port[1])
+       from.Addr = pp.Addr
+       return
+}
+
+func recvmsgInet6(fd int, p, oob []byte, flags int, from *SockaddrInet6) (n, oobn int, recvflags int, err error) {
+       var rsa RawSockaddrAny
+       n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa)
+       if err != nil {
+               return
+       }
+       pp := (*RawSockaddrInet6)(unsafe.Pointer(&rsa))
+       port := (*[2]byte)(unsafe.Pointer(&pp.Port))
+       from.Port = int(port[0])<<8 + int(port[1])
+       from.ZoneId = pp.Scope_id
+       from.Addr = pp.Addr
+       return
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+       var rsa RawSockaddrAny
+       n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa)
+       // source address is only specified if the socket is unconnected
+       if rsa.Addr.Family != AF_UNSPEC {
+               from, err = anyToSockaddr(&rsa)
+       }
+       return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+       _, err = SendmsgN(fd, p, oob, to, flags)
+       return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+       var ptr unsafe.Pointer
+       var salen _Socklen
+       if to != nil {
+               ptr, salen, err = to.sockaddr()
+               if err != nil {
+                       return 0, err
+               }
+       }
+       return sendmsgN(fd, p, oob, ptr, salen, flags)
+}
+
+func sendmsgNInet4(fd int, p, oob []byte, to *SockaddrInet4, flags int) (n int, err error) {
+       ptr, salen, err := to.sockaddr()
+       if err != nil {
+               return 0, err
+       }
+       return sendmsgN(fd, p, oob, ptr, salen, flags)
+}
+
+func sendmsgNInet6(fd int, p, oob []byte, to *SockaddrInet6, flags int) (n int, err error) {
+       ptr, salen, err := to.sockaddr()
+       if err != nil {
+               return 0, err
+       }
+       return sendmsgN(fd, p, oob, ptr, salen, flags)
+}
+
+func sendtoInet4(fd int, p []byte, flags int, to *SockaddrInet4) (err error) {
+       ptr, n, err := to.sockaddr()
+       if err != nil {
+               return err
+       }
+       return sendto(fd, p, flags, ptr, n)
+}
+
+func sendtoInet6(fd int, p []byte, flags int, to *SockaddrInet6) (err error) {
+       ptr, n, err := to.sockaddr()
+       if err != nil {
+               return err
+       }
+       return sendto(fd, p, flags, ptr, n)
+}
+
 func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
        ptr, n, err := to.sockaddr()
        if err != nil {
index af0bc856ee8f9dc3c092492ae093591d4b9f003f..e4af0ba4a595f67bd975ded647205310fc228bdf 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package syscall_test
 
@@ -85,16 +84,24 @@ func TestFcntlFlock(t *testing.T) {
                if err != nil {
                        t.Fatalf("Open failed: %v", err)
                }
-               defer syscall.Close(fd)
-               if err := syscall.Ftruncate(fd, 1<<20); err != nil {
+               // f takes ownership of fd, and will close it.
+               //
+               // N.B. This defer is also necessary to keep f alive
+               // while we use its fd, preventing its finalizer from
+               // executing.
+               f := os.NewFile(uintptr(fd), name)
+               defer f.Close()
+
+               if err := syscall.Ftruncate(int(f.Fd()), 1<<20); err != nil {
                        t.Fatalf("Ftruncate(1<<20) failed: %v", err)
                }
-               if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil {
+               if err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &flock); err != nil {
                        t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err)
                }
+
                cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$")
                cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
-               cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)}
+               cmd.ExtraFiles = []*os.File{f}
                out, err := cmd.CombinedOutput()
                if len(out) > 0 || err != nil {
                        t.Fatalf("child process: %q, %v", out, err)
@@ -252,6 +259,10 @@ func passFDChild() {
                fmt.Printf("TempFile: %v", err)
                return
        }
+       // N.B. This defer is also necessary to keep f alive
+       // while we use its fd, preventing its finalizer from
+       // executing.
+       defer f.Close()
 
        f.Write([]byte("Hello from child process!\n"))
        f.Seek(0, io.SeekStart)
index 660179ae9e8cf32ddccb2e09b3ac45dbf136f860..ecb1eeecf68c755ec533461d5ff63ffce98536c6 100644 (file)
@@ -279,7 +279,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys  RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
 //sys  RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
 //sys  RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
-//sys  RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
+//sys  regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
 //sys  RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
 //sys  getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
 //sys  GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
@@ -394,6 +394,9 @@ func Read(fd Handle, p []byte) (n int, err error) {
        if msanenabled && done > 0 {
                msanWrite(unsafe.Pointer(&p[0]), int(done))
        }
+       if asanenabled && done > 0 {
+               asanWrite(unsafe.Pointer(&p[0]), int(done))
+       }
        return int(done), nil
 }
 
@@ -412,6 +415,9 @@ func Write(fd Handle, p []byte) (n int, err error) {
        if msanenabled && done > 0 {
                msanRead(unsafe.Pointer(&p[0]), int(done))
        }
+       if asanenabled && done > 0 {
+               asanRead(unsafe.Pointer(&p[0]), int(done))
+       }
        return int(done), nil
 }
 
@@ -738,9 +744,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
        p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
 }
 
@@ -760,9 +764,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
        p[0] = byte(sa.Port >> 8)
        p[1] = byte(sa.Port)
        sa.raw.Scope_id = sa.ZoneId
-       for i := 0; i < len(sa.Addr); i++ {
-               sa.raw.Addr[i] = sa.Addr[i]
-       }
+       sa.raw.Addr = sa.Addr
        return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
 }
 
@@ -835,9 +837,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
                sa := new(SockaddrInet4)
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
 
        case AF_INET6:
@@ -846,9 +846,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
                p := (*[2]byte)(unsafe.Pointer(&pp.Port))
                sa.Port = int(p[0])<<8 + int(p[1])
                sa.ZoneId = pp.Scope_id
-               for i := 0; i < len(sa.Addr); i++ {
-                       sa.Addr[i] = pp.Addr[i]
-               }
+               sa.Addr = pp.Addr
                return sa, nil
        }
        return nil, EAFNOSUPPORT
@@ -924,6 +922,38 @@ func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
        return err
 }
 
+func wsaSendtoInet4(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *SockaddrInet4, overlapped *Overlapped, croutine *byte) (err error) {
+       rsa, len, err := to.sockaddr()
+       if err != nil {
+               return err
+       }
+       r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+       if r1 == socket_error {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return err
+}
+
+func wsaSendtoInet6(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *SockaddrInet6, overlapped *Overlapped, croutine *byte) (err error) {
+       rsa, len, err := to.sockaddr()
+       if err != nil {
+               return err
+       }
+       r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(rsa)), uintptr(len), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+       if r1 == socket_error {
+               if e1 != 0 {
+                       err = errnoErr(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return err
+}
+
 func LoadGetAddrInfo() error {
        return procGetAddrInfoW.Find()
 }
@@ -1271,3 +1301,31 @@ func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LI
        }
        return al, nil
 }
+
+// RegEnumKeyEx enumerates the subkeys of an open registry key.
+// Each call retrieves information about one subkey. name is
+// a buffer that should be large enough to hold the name of the
+// subkey plus a null terminating character. nameLen is its
+// length. On return, nameLen will contain the actual length of the
+// subkey.
+//
+// Should name not be large enough to hold the subkey, this function
+// will return ERROR_MORE_DATA, and must be called again with an
+// appropriately sized buffer.
+//
+// reserved must be nil. class and classLen behave like name and nameLen
+// but for the class of the subkey, except that they are optional.
+// lastWriteTime, if not nil, will be populated with the time the subkey
+// was last written.
+//
+// The caller must enumerate all subkeys in order. That is
+// RegEnumKeyEx must be called with index starting at 0, incrementing
+// the index until the function returns ERROR_NO_MORE_ITEMS, or with
+// the index of the last subkey (obtainable from RegQueryInfoKey),
+// decrementing until index 0 is enumerated.
+//
+// Successive calls to this API must happen on the same OS thread,
+// so call runtime.LockOSThread before calling this function.
+func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+       return regEnumKeyEx(key, index, name, nameLen, reserved, class, classLen, lastWriteTime)
+}
index 64d958415d8f8be750a355e1cc40b258270a7070..78a1e71a016e308e51b3ee7760de690570f512af 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package syscall
 
index cf88aeb921a1621891a01258995357db53022df4..b60fe60b03c403155ae6a4ef8b8c4780ae635d6b 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build faketime
-// +build faketime
 
 package syscall
 
index 5eaa2daabd3f0537d95b5f759c78e05d4a866d2c..231875d8c3c92c9824712a9504cf855fd2133c19 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !faketime
-// +build !faketime
 
 package syscall
 
index e4f3d50f56b68bb23bcea2db498d89b475f968aa..7cf4be45b126634d34fbb6b8024a89229f0b5b96 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package syscall
 
index 6588d690eabd68a088ea95191eb4f4bd0eec3dc7..9e05af90ee5bca0a7e12b57c5a5284f2b6b49953 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index c2a32c0782edaec711eea9b173e047482766c56b..c9404aaf1bebda0113347f0d46f1d0c35ca31817 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index 9f8d5bc3ddc06e5a75899d29c316ab6eb255c6b1..33420c4a92434da27290d84b5f0147928777be99 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index d7414117036779dcd7e96997eca38346d7ef2cdb..83bc7dc49979a9f35d1d179401323cdbdf6e7813 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index 254e3e7cfeddb4ba6f67941d8c78d5539227df5d..22c172f1f7d9882725677f0806c7857268497095 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build illumos
-// +build illumos
 
 // Illumos consts not present on Solaris. These are added manually rather than
 // auto-generated by mkerror.sh
index bf76be978bce1f6e309ae7ca0b12a71433e64e9b..23a76edd902dd289a13384a69726a2a38d35f6ad 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index 0bd25ea3c953d82796c364c5bf18527e95c6caec..e53e8c9386f5a7919d6c97221967f7f0cea22f30 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index 8b41cdca230bf5b525e275a9dd0e41a60761b81f..bfe6e9f592f5ae60f442ccf4f6f1029d55ab30d4 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index 179f7914817e85ecbf5974a3e9fdd29f33957b60..2f56bc06010261f5b327bdc54a2ad6987e3d3ca7 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 /*
 Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
index 0b9897284c4d447af040193172dab90a29d5db57..ecbe89c5473a7cb2dcf482ccf2a360b4b4c81bf6 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && darwin
-// +build amd64,darwin
 
 package syscall
 
index 5f210fd1c40b2a1878db0078695bb6738402fbea..fa7cb845c316896000d52bca5c124e76edfc8c9b 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build arm64 && darwin
-// +build arm64,darwin
 
 package syscall
 
index 35e2a52d253b6daafc0d20c80a6603af74c5caed..bca2f50c9695da591b3f54861f483425591176d9 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && dragonfly
-// +build amd64,dragonfly
 
 package syscall
 
index aec26ad7785c8ff630c7f0c421b0ba74d6f62ec5..b1441e76a3c77d39453a4abc4fd77f8375ff75b1 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m32 _const.go
 
 //go:build 386 && freebsd
-// +build 386,freebsd
 
 package syscall
 
index d6d13e4155865c5127c9849eb46e7e978e9db77f..3aed004986d0bec029344c5ace1048294adb37e1 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && freebsd
-// +build amd64,freebsd
 
 package syscall
 
index 15c714fad810731547b6ada3eed9f90ee18a2b07..e1f91ff86cb7ec288919c2bafd74213a566ba2d6 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- _const.go
 
 //go:build arm && freebsd
-// +build arm,freebsd
 
 package syscall
 
index b20ce7d82319e218eeb683269bf560bc63b0ffaf..d0cb6c8ac751bab068a6d963c19b3c65d9c91675 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build freebsd && arm64
-// +build freebsd,arm64
 
 // Code generated by cmd/cgo -godefs; DO NOT EDIT.
 // cgo -godefs -- -m64 _const.go
index fb64932ad620945d8c3ab0c82c38793c5ac36503..5e4c867bc90a102b7e809c564f4c8fa6dd3cfdfe 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m32 _const.go
 
 //go:build 386 && linux
-// +build 386,linux
 
 package syscall
 
index 3a92bcdbb46b1e939787f25ebcd915da5cbc18e9..3ff6e498e78df093c45134730ae0e3d9b9aa3c81 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && linux
-// +build amd64,linux
 
 package syscall
 
index e013d8e7fd682fde0b041f9c37d2e11dad46ff02..35825cc9fb4b1287b1deb795c886aa7e2807dae2 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- _const.go
 
 //go:build arm && linux
-// +build arm,linux
 
 package syscall
 
index 1a4d33e3fd5cc95949e0ca057acecee74bd350a7..444b8816d56490692eabe63c34e36279a262103d 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- _const.go
 
 //go:build arm64 && linux
-// +build arm64,linux
 
 package syscall
 
index 1dda43be70fc259a2ba873d0afe45df1ef93ce5c..dd439acc5823497b60535569c059d4ebff888a29 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build ppc64 && linux
-// +build ppc64,linux
 
 package syscall
 
index 6d56f1c99817c25d1666e5aad9a27f758308a269..b71cb0b4e7ead7e09c66f17aee5b465f6cf3a818 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build ppc64le && linux
-// +build ppc64le,linux
 
 package syscall
 
index 934e9ef073abf72f977ee0a0ef50ae7763047208..b2fcb65782e98cb580b61cd37798adf5a435dfd9 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m32 _const.go
 
 //go:build 386 && netbsd
-// +build 386,netbsd
 
 package syscall
 
index 0f5ad61a9f29a859f6f0b880448b909cb2dd2747..dc52c3ca573ec863aee220bfb8ec3ca81181d5bd 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && netbsd
-// +build amd64,netbsd
 
 package syscall
 
index 9d8678750d4cca58417b93091c49512f02f4ab0f..3137e18a2471f54b0778b68b42132e3884f4799a 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -marm _const.go
 
 //go:build arm && netbsd
-// +build arm,netbsd
 
 package syscall
 
index 7adb72f7edd622bfe9805359f7cb4edd3d4da43e..cc1b0088c9ab95655cfbe65f95202f3129c2450b 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build arm64 && netbsd
-// +build arm64,netbsd
 
 package syscall
 
index a8457c6edfe8b6cde64cf49d3302b2d049c7e99e..d17ecb96e50c5d3898b9d818ea34dde0d6963683 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m32 _const.go
 
 //go:build 386 && openbsd
-// +build 386,openbsd
 
 package syscall
 
index eb19537a2ac9ed6104cd1e7368721edaa76315c2..4904e7614f3d185d98bf7dfb172dab319b67db82 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && openbsd
-// +build amd64,openbsd
 
 package syscall
 
index 89a4e6d89a54b56f04bf2d15aa719b48c7269fd4..76ac9173a93f2ae1ee77744184899155d08264ab 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- _const.go
 
 //go:build arm && openbsd
-// +build arm,openbsd
 
 package syscall
 
index b7dee696029654eea3992e4e3cd4a42233cbdb09..fb25dacee43f8d88655528d3b9721273cd01772b 100644 (file)
@@ -5,7 +5,6 @@
 // cgo -godefs -- -m64 _const.go
 
 //go:build amd64 && solaris
-// +build amd64,solaris
 
 package syscall
 
index 134ae41165bd76cd33afecea1d65c2b1f2bdc6ff..94f1b4371c5724bee5b75b0d37e669a0f435c615 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build aix && ppc64
-// +build aix,ppc64
 
 package syscall
 
index 07a519d7d65fa92463e100d88b037abf71cd67c6..0ccdaf2d0eea6d2613201cd72d1951bcbaca527a 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build darwin && amd64
-// +build darwin,amd64
 
 package syscall
 
@@ -345,6 +344,25 @@ func libc_pipe_trampoline()
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       _, _, e1 := syscall6(abi.FuncPCABI0(libc_utimensat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func libc_utimensat_trampoline()
+
+//go:cgo_import_dynamic libc_utimensat utimensat "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func kill(pid int, signum int, posix int) (err error) {
        _, _, e1 := syscall(abi.FuncPCABI0(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix))
        if e1 != 0 {
index 492f94785548754bc70c6db0c60ba87217f5a959..563083d441a17c7600c4265e4104adc9498bc60b 100644 (file)
@@ -3,8 +3,6 @@
 #include "textflag.h"
 TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_getfsstat(SB)
-TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0
-       JMP     libc_setattrlist(SB)
 TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_fdopendir(SB)
 TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0
@@ -53,6 +51,8 @@ TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_fcntl(SB)
 TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_pipe(SB)
+TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0
+       JMP     libc_utimensat(SB)
 TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_kill(SB)
 TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0
index 5ae096730eae21ee5858b4ab9b7f4d594935a03c..09bf34bb3c55e4fd8aecaac90af61fb16c18a96c 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build darwin && arm64
-// +build darwin,arm64
 
 package syscall
 
@@ -345,6 +344,25 @@ func libc_pipe_trampoline()
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       _, _, e1 := syscall6(abi.FuncPCABI0(libc_utimensat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+func libc_utimensat_trampoline()
+
+//go:cgo_import_dynamic libc_utimensat utimensat "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func kill(pid int, signum int, posix int) (err error) {
        _, _, e1 := syscall(abi.FuncPCABI0(libc_kill_trampoline), uintptr(pid), uintptr(signum), uintptr(posix))
        if e1 != 0 {
index b606c6e49e35bba658ee8f19eb432debeb6fd820..0567a42fa337985c3b5d0115cf27299c9ebe04d4 100644 (file)
@@ -3,8 +3,6 @@
 #include "textflag.h"
 TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_getfsstat(SB)
-TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0
-       JMP     libc_setattrlist(SB)
 TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_fdopendir(SB)
 TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0
@@ -53,6 +51,8 @@ TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_fcntl(SB)
 TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_pipe(SB)
+TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0
+       JMP     libc_utimensat(SB)
 TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_kill(SB)
 TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0
index aa327c001095362fa7fd81f9716e28c51d78aeb8..5d5576d76ff64608d701aa5cee06a2f4323af85d 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build dragonfly && amd64
-// +build dragonfly,amd64
 
 package syscall
 
index 7137d66f0b232f710cf5d4e9a861c9215df042ad..ed0eb9fa15e68802b9e0e662f06f98b983f8f554 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build freebsd && 386
-// +build freebsd,386
 
 package syscall
 
index d721dafde28b7acd47838618ce5886b728833ab8..e291a5675688c56b21471d71046613a1b039e4bf 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build freebsd && amd64
-// +build freebsd,amd64
 
 package syscall
 
index d9dbea921a141194ababeb30feab15497e85b3cf..7dd856fd970946c62507a7611dd65dcbbcece17f 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build freebsd && arm
-// +build freebsd,arm
 
 package syscall
 
index a24f0115e2ce09595bec7818eb704443f3a24de7..229a9a22387bd7c324d349c5fa5d827fb831180e 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build freebsd && arm64
-// +build freebsd,arm64
 
 package syscall
 
index ac822d6f7a435dde180689e7f217f90e1c972cd8..c385dd3ca140098e6fe63d85159de34a230d77e7 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && 386
-// +build linux,386
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1048,26 +1057,6 @@ func Munlockall() (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Dup2(oldfd int, newfd int) (err error) {
        _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
        if e1 != 0 {
index ed37fa8decaa08bb6d3f6416ba623176654424d8..2059271324f7fee4da4a765b711c49c9b460d862 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && amd64
-// +build linux,amd64
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1644,23 +1653,3 @@ func utimes(path string, times *[2]Timeval) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index 213aaf3bac40a18ab11647ee6e3ebbb16c3dbf81..50498c6eb6792acb8f7e87ccb455e33e66cc62f3 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && arm
-// +build linux,arm
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1048,26 +1057,6 @@ func Munlockall() (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
        r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
        fd = int(r0)
index e2f9c0fd9b06e2cd0d60fbdb8dc8ce6170698001..6714123f9c7f7a367c79fb6af9f1af8e796e7900 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && arm64
-// +build linux,arm64
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1555,16 +1564,6 @@ func Gettimeofday(tv *Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func ppoll(fds *pollFd, nfds int, timeout *Timespec, sigmask *sigset_t) (n int, err error) {
        r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0)
        n = int(r0)
index 617c2f54663309179f6182694c4102734bdbf887..c6f4878ff7ba139b11d2b72bdf15fcf17f4602ed 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && mips
-// +build linux,mips
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1646,28 +1655,6 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe() (p1 int, p2 int, err error) {
-       r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
-       p1 = int(r0)
-       p2 = int(r1)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
        r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
        xaddr = uintptr(r0)
index 793d4b98846a4e7691c946eb3af2ab7b6d93d5e1..5187c28ebb6050c8fb5e20c91afb9981999541a4 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && mips64
-// +build linux,mips64
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1642,16 +1651,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func fstat(fd int, st *stat_t) (err error) {
        _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(st)), 0)
        if e1 != 0 {
index 54e1760bda6d081a01cf174d439962273e1a14ce..f3dacfeedaff9316b569431464d39ad3722e7aa4 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && mips64le
-// +build linux,mips64le
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1642,16 +1651,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func fstat(fd int, st *stat_t) (err error) {
        _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(st)), 0)
        if e1 != 0 {
index ba7e2118c04e5769079a61229255a798b2ac247f..fbc543709fc163fef73e18d76320abf78e03a4df 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && mipsle
-// +build linux,mipsle
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1646,28 +1655,6 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe() (p1 int, p2 int, err error) {
-       r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
-       p1 = int(r0)
-       p2 = int(r1)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
        r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
        xaddr = uintptr(r0)
index c3437722e02f50c49e40ebdb05a9b4d486eedc11..b71dca2b371e611a29ea287d4392112ac9b44cac 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && ppc64
-// +build linux,ppc64
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1703,16 +1712,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func syncFileRange2(fd int, flags int, off int64, n int64) (err error) {
        _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off), uintptr(n), 0, 0)
        if e1 != 0 {
index acc34a76d2b6315a3f864773c5131191445531b2..193fbbc5418ecf2a49c8a62cf5afdb61999025fc 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && ppc64le
-// +build linux,ppc64le
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1703,16 +1712,6 @@ func utimes(path string, times *[2]Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func syncFileRange2(fd int, flags int, off int64, n int64) (err error) {
        _, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(flags), uintptr(off), uintptr(n), 0, 0)
        if e1 != 0 {
index d662d780db9d8fd8c3eda1de74b5816c0e548922..33b1e9b4312a6cdb7348b4b6a783ca6dfd0fb22d 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && riscv64
-// +build linux,riscv64
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1555,16 +1564,6 @@ func Gettimeofday(tv *Timeval) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func ppoll(fds *pollFd, nfds int, timeout *Timespec, sigmask *sigset_t) (n int, err error) {
        r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0)
        n = int(r0)
index 20f8c61366ca1eef8721a36a00c523a5351b9fc8..2ab78c71bfe39d1085dc90e7610d495abfca405d 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build linux && s390x
-// +build linux,s390x
 
 package syscall
 
@@ -76,6 +75,16 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func pipe2(p *[2]_C_int, flags int) (err error) {
+       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
        var _p0 *byte
        _p0, err = BytePtrFromString(path)
@@ -1490,13 +1499,3 @@ func utimes(path string, times *[2]Timeval) (err error) {
        }
        return
 }
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe2(p *[2]_C_int, flags int) (err error) {
-       _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-       if e1 != 0 {
-               err = errnoErr(e1)
-       }
-       return
-}
index 07ff5fba5f6a511feb5b368cbc06571fdc10d5ef..408318181af20c32446111d2933d643dc0f26d7f 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build netbsd && 386
-// +build netbsd,386
 
 package syscall
 
index ffb4e059a4b5aa64781b50448bd5c465c1a268cb..2039cf6d0ea80f318d113a7966a22f55e2800f51 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build netbsd && amd64
-// +build netbsd,amd64
 
 package syscall
 
index 37df77e5e8cbbf1dd7eb68c6b1b7423284fe83bc..3c287ea223d1e80e35acbce97633546469be5651 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build netbsd && arm
-// +build netbsd,arm
 
 package syscall
 
index c5eb57a2269d6ff73eea66f5d7b9a636ae6201bc..1d40db9e6b632d541117fac2d0d91a437f4fb330 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build netbsd && arm64
-// +build netbsd,arm64
 
 package syscall
 
index 1ff5c95fa19855498cde553ddbfba410e33e4e51..5f95d7a9c6dbcec0bb9faaa38e7230cf972624c5 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build openbsd && 386
-// +build openbsd,386
 
 package syscall
 
index 85cb195739f2966b04f4084ba716210220f2957c..189bf887e6223fd29f665da34b292968f7513994 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build openbsd && amd64
-// +build openbsd,amd64
 
 package syscall
 
index 04a2fadccddde263cc040a910b2799b1aa310535..c7513a3ac9af4c754ea2c0f02b5177c499d76d23 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build openbsd && arm
-// +build openbsd,arm
 
 package syscall
 
index fa35905d1bcf9cb259f11aafdd7ca9d6e4c74bc6..293b70360021896c2d9a17a50af2367674d6ed42 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build openbsd && arm64
-// +build openbsd,arm64
 
 package syscall
 
index 70fd1474fd3f9b88e9f3cdd3f5b16edd7134b832..51904b5e29dc1ad1b5e85af65b177e86aca92dbf 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build openbsd && mips64
-// +build openbsd,mips64
 
 package syscall
 
index 8b7727b3435e88d4fc0824b31bc0d343e2303632..32fa0f0eb6e2b7d98071184bd5753f37df3d1799 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build plan9 && 386
-// +build plan9,386
 
 package syscall
 
index bed9108ea6e2d5e242a73e07a30443db5d2a538d..b3337ce8110c977f58e0dffca0d96f6e5641a39d 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build plan9 && amd64
-// +build plan9,amd64
 
 package syscall
 
index 7bbcf9b4b795065e600d47168d3ece2d579bd8cd..3705566fa3a4895a41694f77a5f9e40a690848aa 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build plan9 && arm
-// +build plan9,arm
 
 package syscall
 
index 9b37dc09506f2860c011fbea13d65a62ecdf18cf..2d8cdfd280b807a0dd337ba2feab818eaad93934 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build solaris && amd64
-// +build solaris,amd64
 
 package syscall
 
index 7bfff16be6ac325fa9a406f98b76aa0542b39948..2d6f34e059d75bec84413d7249548a714f3edaeb 100644 (file)
@@ -305,7 +305,7 @@ func RegCloseKey(key Handle) (regerrno error) {
        return
 }
 
-func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+func regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
        r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
        if r0 != 0 {
                regerrno = Errno(r0)
index f66f7d2715feba2ce0dc68f9e45157fb26bf6df3..08e003f2926448046e5a0f0ff76f814fc8262a28 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build amd64 && darwin
-// +build amd64,darwin
 
 package syscall
 
index 6fa146368aff59ca847f7c520b1b0e468c4bdd35..71309bb4d6f7f83fb645b899a23f46f15e9e9a33 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm64 && darwin
-// +build arm64,darwin
 
 package syscall
 
index e8996db0f8dd580f016d94d5c50e29d168a3e7ef..03d4b06a09b40145b747dab7dd26f98c481f7ce2 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build amd64 && dragonfly
-// +build amd64,dragonfly
 
 package syscall
 
index 1ed7e3ee8d3e3d7c70107ae5afa6b0395d0b350f..355b2ec3039cda704df92ebc33a717bf874ec651 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build 386 && freebsd
-// +build 386,freebsd
 
 package syscall
 
index d72dbc944a1b74e1d2c706c1a6f9135154b5053b..84c821c955f9e1956fbfcccf90d37a31fc242480 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build amd64 && freebsd
-// +build amd64,freebsd
 
 package syscall
 
index 4f4dc4db7959e32e887f35e44341c30aa1a64d96..785e7875f40d2986eb474523be6a21518e0dc393 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm && freebsd
-// +build arm,freebsd
 
 package syscall
 
index ab1a05258e7e95fa0e050703b28848091e1ebe12..7144a8abed126c460c8b7fb36fb987e69d1c0eeb 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm64 && freebsd
-// +build arm64,freebsd
 
 package syscall
 
index 792f43550e99f59a254745d60fc05da41c14a6e8..4966d2a94714e89d4634275c25d3bdfd281d7cf3 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build 386 && linux
-// +build 386,linux
 
 package syscall
 
index 9ea18d6111398c86976162a94af975bbe941d4cd..576c7c36a6b7eb70cf0e3b311f428fdc097b35bb 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build amd64 && linux
-// +build amd64,linux
 
 package syscall
 
index ccae9c15e32249b5cbb62f05a19b9037ac48d896..b0da97c64bc32d6848fa0a27a438e8fd4b595486 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm && linux
-// +build arm,linux
 
 package syscall
 
index 17c54a2c833bf4fcff45d7fd9c884691b0edc368..0136d9440b897a9a2b762cb8cd07e6362a632e9a 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm64 && linux
-// +build arm64,linux
 
 package syscall
 
index a0d37ff1f2701354c9baa4c1dbe4828fec695c76..cc964c23e2eef022236ffe12a5db01663529d8ec 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build ppc64 && linux
-// +build ppc64,linux
 
 package syscall
 
index f8f82d20432359617871f620222b5a229bc5213e..57bfb7795f23418fc95d0ebbcfe056129f4c5c56 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build ppc64le && linux
-// +build ppc64le,linux
 
 package syscall
 
index fd0c32995142f826538f02638e0ed3cd0e6552d3..5696c4befebc897d49127e2f511e34e87116be75 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build 386 && netbsd
-// +build 386,netbsd
 
 package syscall
 
index 03f2cd3bd328e7a5fb5fe2a98c193e5a22aad6ea..9fb85cddbaf858168fe7006444a34b6b6a7e7926 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build amd64 && netbsd
-// +build amd64,netbsd
 
 package syscall
 
index 7b356e7102c06b3af3c72a105ec0f161e49b484d..e0e8994641ab71b19569f06597e2218411d739ea 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm && netbsd
-// +build arm,netbsd
 
 package syscall
 
index 3f57ec4d894e09d01956c200369ce6c4f9062aa9..9653364dae9411283badfca0d44cd56804c63359 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm64 && netbsd
-// +build arm64,netbsd
 
 package syscall
 
index b289886d6c61fc8710677ee881dacc0ba772d9bc..3b12639bd739930a8ac4b2e95092d94a3be56135 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build 386 && openbsd
-// +build 386,openbsd
 
 package syscall
 
index 8cf2b68dcd3abe18c6b7b4f6b37c05af7ae9cd11..bce309dc5d94dbd79550032fadf0173db8c52473 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build amd64 && openbsd
-// +build amd64,openbsd
 
 package syscall
 
index cc33773a05833901c36ac0294832a450f3ac2996..05aed70762df58a68116c3f122c4ef28196ed32f 100644 (file)
@@ -2,7 +2,6 @@
 // Code generated by the command above; DO NOT EDIT.
 
 //go:build arm && openbsd
-// +build arm,openbsd
 
 package syscall
 
index 23c9c715b5215c1ac807496c24f1dc016a1290c2..ea244e535ec42ad2f1d433f05afe67e7525ae000 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build amd64 && solaris
-// +build amd64,solaris
 
 package syscall
 
index 8feacc47ab5142754766f8df8aff93e38ce7b18e..551edc702578d18cc10307b193d1ee6fbc85560f 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_darwin.go
 
 //go:build amd64 && darwin
-// +build amd64,darwin
 
 package syscall
 
index 8079d22429b4500e23e7e30c5e51f1f03b8d73bb..46f78a97eb2950c937850757144a37f327e0bf75 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_darwin.go
 
 //go:build arm64 && darwin
-// +build arm64,darwin
 
 package syscall
 
index a51e0038bb9bda3278b36ef995991f355c6a6c59..ec519b72ec15841fe1235b6a67c5966ddfbe644e 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_dragonfly.go
 
 //go:build amd64 && dragonfly
-// +build amd64,dragonfly
 
 package syscall
 
index 173972688387bf12da427087c0a77c0897ec36fa..e1946dece8d3f2d3dddb857d4d9eba7eb10977c6 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_freebsd.go | go run mkpost.go
 
 //go:build 386 && freebsd
-// +build 386,freebsd
 
 package syscall
 
index 0457d8e995918784465b0228151f55fed4f95909..a718345d799b949b4683e1f95a7807e5072ea603 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_freebsd.go | go run mkpost.go
 
 //go:build amd64 && freebsd
-// +build amd64,freebsd
 
 package syscall
 
index 29c8380d898784c348689090b86d90ade1c9a1f9..9c5a0667132a9911a568ef3c5d5fcc1560a359d6 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs -- -fsigned-char types_freebsd.go
 
 //go:build arm && freebsd
-// +build arm,freebsd
 
 package syscall
 
index 6472db00809a51972811ffb3658f508217971372..3ccd9fc0dd7962247e9d81db35823f101fbd53a1 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_freebsd.go | go run mkpost.go
 
 //go:build arm64 && freebsd
-// +build arm64,freebsd
 
 package syscall
 
index 251a0c0b4ad249be800e35b96b432d15dd4ba57c..a45511e84760855810ed4f7ddc4d987f1bf31e36 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_linux.go
 
 //go:build 386 && linux
-// +build 386,linux
 
 package syscall
 
index 34c953fc8bf45ae9ee7f4ff90e3cfa8cd58f5308..1bab13bf431ece2f79c01710b5d3206b41daa361 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_linux.go
 
 //go:build amd64 && linux
-// +build amd64,linux
 
 package syscall
 
index 4de656b491e74a6283fbfed3ca29dd680a743b28..a4d61bd19bbe88000d55cdcfe605498cb828980a 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_linux.go
 
 //go:build arm && linux
-// +build arm,linux
 
 package syscall
 
index bed9cb08515eb014b933edfe5ad8b178f6eb57e6..1e469c36d2eddb6b19992e6edbd1ee8f437b1316 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs -- -fsigned-char types_linux.go
 
 //go:build arm64 && linux
-// +build arm64,linux
 
 package syscall
 
index 355533fb27cb4730c170e9c75b6785ebabdb1262..c830cee966bf86d9e14a126da6c85709b8d5a100 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_linux.go
 
 //go:build ppc64 && linux
-// +build ppc64,linux
 
 package syscall
 
index 94e12c742c8033e4a9e11d9e66b8351987277f9f..770ddc9fe9a23bdfb0fadfa0cabbd60a9dd21084 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_linux.go
 
 //go:build ppc64le && linux
-// +build ppc64le,linux
 
 package syscall
 
index 321460f45aa386047a84aac6f8777f57331ab360..74eaa4a15034b0b7593684944b5155dda475903f 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_netbsd.go
 
 //go:build 386 && netbsd
-// +build 386,netbsd
 
 package syscall
 
index 370d7172634361212d3e7ec55c357df3e5789dfc..fc28fc9bb8f77f36cbad371d982de26aa9a6b15c 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_netbsd.go
 
 //go:build amd64 && netbsd
-// +build amd64,netbsd
 
 package syscall
 
index 557c6345339c080fb6ac4e8b79cc7ae1441e8ec3..1f885048dd65f7461a4cde811439679024f5b26d 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_netbsd.go
 
 //go:build arm && netbsd
-// +build arm,netbsd
 
 package syscall
 
index 19f36903412e76d3b635aa1555e4ba36a7629f64..cac74693d756a87789ad34f83504d0ea544cfaa6 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_netbsd.go
 
 //go:build arm64 && netbsd
-// +build arm64,netbsd
 
 package syscall
 
index 222c6c7e46520b2abf78e7f255afe21b66573a70..f9ba685e25269dbe21168cb827ae46f7c6c0c6f0 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_openbsd.go
 
 //go:build 386 && openbsd
-// +build 386,openbsd
 
 package syscall
 
index 644ee9b3dfbe7192051b9a50957140323fe81768..889b9551ae9024572f3ec7e0fc410450994d1288 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_openbsd.go
 
 //go:build amd64 && openbsd
-// +build amd64,openbsd
 
 package syscall
 
index 64e16b494350738844ca4334d944922034360285..d486cd002f967bf715f7ea7e94f694b52186b9d5 100644 (file)
@@ -2,7 +2,6 @@
 // cgo -godefs types_solaris.go
 
 //go:build amd64 && solaris
-// +build amd64,solaris
 
 package syscall
 
index 15b4426c5a544cbc081bde34d7647bd3eb6f9365..d8ec217f66c628e0950a6223dd0a67e12625f8a0 100644 (file)
@@ -32,35 +32,36 @@ var (
        matchBenchmarks *string
        benchmarkMemory *bool
 
-       benchTime = benchTimeFlag{d: 1 * time.Second} // changed during test of testing package
+       benchTime = durationOrCountFlag{d: 1 * time.Second} // changed during test of testing package
 )
 
-type benchTimeFlag struct {
-       d time.Duration
-       n int
+type durationOrCountFlag struct {
+       d         time.Duration
+       n         int
+       allowZero bool
 }
 
-func (f *benchTimeFlag) String() string {
+func (f *durationOrCountFlag) String() string {
        if f.n > 0 {
                return fmt.Sprintf("%dx", f.n)
        }
-       return time.Duration(f.d).String()
+       return f.d.String()
 }
 
-func (f *benchTimeFlag) Set(s string) error {
+func (f *durationOrCountFlag) Set(s string) error {
        if strings.HasSuffix(s, "x") {
                n, err := strconv.ParseInt(s[:len(s)-1], 10, 0)
-               if err != nil || n <= 0 {
+               if err != nil || n < 0 || (!f.allowZero && n == 0) {
                        return fmt.Errorf("invalid count")
                }
-               *f = benchTimeFlag{n: int(n)}
+               *f = durationOrCountFlag{n: int(n)}
                return nil
        }
        d, err := time.ParseDuration(s)
-       if err != nil || d <= 0 {
+       if err != nil || d < 0 || (!f.allowZero && d == 0) {
                return fmt.Errorf("invalid duration")
        }
-       *f = benchTimeFlag{d: d}
+       *f = durationOrCountFlag{d: d}
        return nil
 }
 
@@ -98,7 +99,7 @@ type B struct {
        previousN        int           // number of iterations in the previous run
        previousDuration time.Duration // total duration of the previous run
        benchFunc        func(b *B)
-       benchTime        benchTimeFlag
+       benchTime        durationOrCountFlag
        bytes            int64
        missingBytes     bool // one of the subbenchmarks does not have bytes set.
        timerOn          bool
@@ -298,7 +299,12 @@ func (b *B) launch() {
 
        // Run the benchmark for at least the specified amount of time.
        if b.benchTime.n > 0 {
-               b.runN(b.benchTime.n)
+               // We already ran a single iteration in run1.
+               // If -benchtime=1x was requested, use that result.
+               // See https://golang.org/issue/32051.
+               if b.benchTime.n > 1 {
+                       b.runN(b.benchTime.n)
+               }
        } else {
                d := b.benchTime.d
                for n := int64(1); !b.failed && b.duration < d && n < 1e9; {
index 9fef2f4696ec7944acc891eb3c69e86a3f376139..056ef133fac928e173c26ce8d34d7ab5f18b064e 100644 (file)
@@ -66,7 +66,9 @@ func (fsys MapFS) Open(name string) (fs.File, error) {
                for fname, f := range fsys {
                        i := strings.Index(fname, "/")
                        if i < 0 {
-                               list = append(list, mapFileInfo{fname, f})
+                               if fname != "." {
+                                       list = append(list, mapFileInfo{fname, f})
+                               }
                        } else {
                                need[fname[:i]] = true
                        }
index 2abedd67351fc4d4b258225c7ec79d5d02764fad..c8d29283b28989c942ac9b00d51c1311717876fa 100644 (file)
@@ -5,6 +5,9 @@
 package fstest
 
 import (
+       "fmt"
+       "io/fs"
+       "strings"
        "testing"
 )
 
@@ -17,3 +20,28 @@ func TestMapFS(t *testing.T) {
                t.Fatal(err)
        }
 }
+
+func TestMapFSChmodDot(t *testing.T) {
+       m := MapFS{
+               "a/b.txt": &MapFile{Mode: 0666},
+               ".":       &MapFile{Mode: 0777 | fs.ModeDir},
+       }
+       buf := new(strings.Builder)
+       fs.WalkDir(m, ".", func(path string, d fs.DirEntry, err error) error {
+               fi, err := d.Info()
+               if err != nil {
+                       return err
+               }
+               fmt.Fprintf(buf, "%s: %v\n", path, fi.Mode())
+               return nil
+       })
+       want := `
+.: drwxrwxrwx
+a: d---------
+a/b.txt: -rw-rw-rw-
+`[1:]
+       got := buf.String()
+       if want != got {
+               t.Errorf("MapFS modes want:\n%s\ngot:\n%s\n", want, got)
+       }
+}
diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go
new file mode 100644 (file)
index 0000000..1066516
--- /dev/null
@@ -0,0 +1,700 @@
+// 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 testing
+
+import (
+       "bytes"
+       "errors"
+       "flag"
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
+       "reflect"
+       "runtime"
+       "sync/atomic"
+       "time"
+)
+
+func initFuzzFlags() {
+       matchFuzz = flag.String("test.fuzz", "", "run the fuzz target matching `regexp`")
+       flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely")
+       flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a crash")
+       fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored")
+       isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values")
+}
+
+var (
+       matchFuzz        *string
+       fuzzDuration     durationOrCountFlag
+       minimizeDuration = durationOrCountFlag{d: 60 * time.Second, allowZero: true}
+       fuzzCacheDir     *string
+       isFuzzWorker     *bool
+
+       // corpusDir is the parent directory of the target's seed corpus within
+       // the package.
+       corpusDir = "testdata/fuzz"
+)
+
+// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an internal error.
+// This distinguishes internal errors from uncontrolled panics and other crashes.
+// Keep in sync with internal/fuzz.workerExitCode.
+const fuzzWorkerExitCode = 70
+
+// InternalFuzzTarget is an internal type but exported because it is cross-package;
+// it is part of the implementation of the "go test" command.
+type InternalFuzzTarget struct {
+       Name string
+       Fn   func(f *F)
+}
+
+// F is a type passed to fuzz targets.
+//
+// A fuzz target may add seed corpus entries using F.Add or by storing files in
+// the testdata/fuzz/<FuzzTargetName> directory. The fuzz target must then
+// call F.Fuzz once to provide a fuzz function. See the testing package
+// documentation for an example, and see the F.Fuzz and F.Add method
+// documentation for details.
+//
+// *F methods can only be called before (*F).Fuzz. Once inside the function
+// passed to (*F).Fuzz, only (*T) methods can be used. The only *F methods that
+// are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name.
+type F struct {
+       common
+       fuzzContext *fuzzContext
+       testContext *testContext
+
+       // inFuzzFn is true when the fuzz function is running. Most F methods cannot
+       // be called when inFuzzFn is true.
+       inFuzzFn bool
+
+       // corpus is a set of seed corpus entries, added with F.Add and loaded
+       // from testdata.
+       corpus []corpusEntry
+
+       result     fuzzResult
+       fuzzCalled bool
+}
+
+var _ TB = (*F)(nil)
+
+// corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry.
+// We use a type alias because we don't want to export this type, and we can't
+// import internal/fuzz from testing.
+type corpusEntry = struct {
+       Parent     string
+       Path       string
+       Data       []byte
+       Values     []interface{}
+       Generation int
+       IsSeed     bool
+}
+
+// Helper marks the calling function as a test helper function.
+// When printing file and line information, that function will be skipped.
+// Helper may be called simultaneously from multiple goroutines.
+func (f *F) Helper() {
+       if f.inFuzzFn {
+               panic("testing: f.Helper was called inside the f.Fuzz function, use t.Helper instead")
+       }
+
+       // common.Helper is inlined here.
+       // If we called it, it would mark F.Helper as the helper
+       // instead of the caller.
+       f.mu.Lock()
+       defer f.mu.Unlock()
+       if f.helperPCs == nil {
+               f.helperPCs = make(map[uintptr]struct{})
+       }
+       // repeating code from callerName here to save walking a stack frame
+       var pc [1]uintptr
+       n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper
+       if n == 0 {
+               panic("testing: zero callers found")
+       }
+       if _, found := f.helperPCs[pc[0]]; !found {
+               f.helperPCs[pc[0]] = struct{}{}
+               f.helperNames = nil // map will be recreated next time it is needed
+       }
+}
+
+// Fail marks the function as having failed but continues execution.
+func (f *F) Fail() {
+       // (*F).Fail may be called by (*T).Fail, which we should allow. However, we
+       // shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function.
+       if f.inFuzzFn {
+               panic("testing: f.Fail was called inside the f.Fuzz function, use t.Fail instead")
+       }
+       f.common.Helper()
+       f.common.Fail()
+}
+
+// Skipped reports whether the test was skipped.
+func (f *F) Skipped() bool {
+       // (*F).Skipped may be called by tRunner, which we should allow. However, we
+       // shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function.
+       if f.inFuzzFn {
+               panic("testing: f.Skipped was called inside the f.Fuzz function, use t.Skipped instead")
+       }
+       f.common.Helper()
+       return f.common.Skipped()
+}
+
+// Add will add the arguments to the seed corpus for the fuzz target. This will
+// be a no-op if called after or within the Fuzz function. The args must match
+// those in the Fuzz function.
+func (f *F) Add(args ...interface{}) {
+       var values []interface{}
+       for i := range args {
+               if t := reflect.TypeOf(args[i]); !supportedTypes[t] {
+                       panic(fmt.Sprintf("testing: unsupported type to Add %v", t))
+               }
+               values = append(values, args[i])
+       }
+       f.corpus = append(f.corpus, corpusEntry{Values: values, IsSeed: true, Path: fmt.Sprintf("seed#%d", len(f.corpus))})
+}
+
+// supportedTypes represents all of the supported types which can be fuzzed.
+var supportedTypes = map[reflect.Type]bool{
+       reflect.TypeOf(([]byte)("")):  true,
+       reflect.TypeOf((string)("")):  true,
+       reflect.TypeOf((bool)(false)): true,
+       reflect.TypeOf((byte)(0)):     true,
+       reflect.TypeOf((rune)(0)):     true,
+       reflect.TypeOf((float32)(0)):  true,
+       reflect.TypeOf((float64)(0)):  true,
+       reflect.TypeOf((int)(0)):      true,
+       reflect.TypeOf((int8)(0)):     true,
+       reflect.TypeOf((int16)(0)):    true,
+       reflect.TypeOf((int32)(0)):    true,
+       reflect.TypeOf((int64)(0)):    true,
+       reflect.TypeOf((uint)(0)):     true,
+       reflect.TypeOf((uint8)(0)):    true,
+       reflect.TypeOf((uint16)(0)):   true,
+       reflect.TypeOf((uint32)(0)):   true,
+       reflect.TypeOf((uint64)(0)):   true,
+}
+
+// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of
+// arguments, those arguments will be added to the seed corpus.
+//
+// ff must be a function with no return value whose first argument is *T and
+// whose remaining arguments are the types to be fuzzed.
+// For example:
+//
+//     f.Fuzz(func(t *testing.T, b []byte, i int) { ... })
+//
+// The following types are allowed: []byte, string, bool, byte, rune, float32,
+// float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64.
+// More types may be supported in the future.
+//
+// ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use
+// the corresponding *T method instead. The only *F methods that are allowed in
+// the (*F).Fuzz function are (*F).Failed and (*F).Name.
+//
+// This function sould be fast and deterministic, and its behavior should not
+// depend on shared state. No mutatable input arguments, or pointers to them,
+// should be retained between executions of the fuzz function, as the memory
+// backing them may be mutated during a subsequent invocation. ff must not
+// modify the underlying data of the arguments provided by the fuzzing engine.
+//
+// When fuzzing, F.Fuzz does not return until a problem is found, time runs out
+// (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz
+// should be called exactly once, unless F.Skip or F.Fail is called beforehand.
+func (f *F) Fuzz(ff interface{}) {
+       if f.fuzzCalled {
+               panic("testing: F.Fuzz called more than once")
+       }
+       f.fuzzCalled = true
+       if f.failed {
+               return
+       }
+       f.Helper()
+
+       // ff should be in the form func(*testing.T, ...interface{})
+       fn := reflect.ValueOf(ff)
+       fnType := fn.Type()
+       if fnType.Kind() != reflect.Func {
+               panic("testing: F.Fuzz must receive a function")
+       }
+       if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) {
+               panic("testing: F.Fuzz function must receive at least two arguments, where the first argument is a *T")
+       }
+
+       // Save the types of the function to compare against the corpus.
+       var types []reflect.Type
+       for i := 1; i < fnType.NumIn(); i++ {
+               t := fnType.In(i)
+               if !supportedTypes[t] {
+                       panic(fmt.Sprintf("testing: unsupported type for fuzzing %v", t))
+               }
+               types = append(types, t)
+       }
+
+       // Load the testdata seed corpus. Check types of entries in the testdata
+       // corpus and entries declared with F.Add.
+       //
+       // Don't load the seed corpus if this is a worker process; we won't use it.
+       if f.fuzzContext.mode != fuzzWorker {
+               for _, c := range f.corpus {
+                       if err := f.fuzzContext.deps.CheckCorpus(c.Values, types); err != nil {
+                               // TODO(#48302): Report the source location of the F.Add call.
+                               f.Fatal(err)
+                       }
+               }
+
+               // Load seed corpus
+               c, err := f.fuzzContext.deps.ReadCorpus(filepath.Join(corpusDir, f.name), types)
+               if err != nil {
+                       f.Fatal(err)
+               }
+               for i := range c {
+                       c[i].IsSeed = true // these are all seed corpus values
+                       if f.fuzzContext.mode == fuzzCoordinator {
+                               // If this is the coordinator process, zero the values, since we don't need
+                               // to hold onto them.
+                               c[i].Values = nil
+                       }
+               }
+
+               f.corpus = append(f.corpus, c...)
+       }
+
+       // run calls fn on a given input, as a subtest with its own T.
+       // run is analogous to T.Run. The test filtering and cleanup works similarly.
+       // fn is called in its own goroutine.
+       run := func(captureOut io.Writer, e corpusEntry) (ok bool) {
+               if e.Values == nil {
+                       // The corpusEntry must have non-nil Values in order to run the
+                       // test. If Values is nil, it is a bug in our code.
+                       panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Path))
+               }
+               if shouldFailFast() {
+                       return true
+               }
+               testName := f.name
+               if e.Path != "" {
+                       testName = fmt.Sprintf("%s/%s", testName, filepath.Base(e.Path))
+               }
+               if f.testContext.isFuzzing {
+                       // Don't preserve subtest names while fuzzing. If fn calls T.Run,
+                       // there will be a very large number of subtests with duplicate names,
+                       // which will use a large amount of memory. The subtest names aren't
+                       // useful since there's no way to re-run them deterministically.
+                       f.testContext.match.clearSubNames()
+               }
+
+               // Record the stack trace at the point of this call so that if the subtest
+               // function - which runs in a separate stack - is marked as a helper, we can
+               // continue walking the stack into the parent test.
+               var pc [maxStackLen]uintptr
+               n := runtime.Callers(2, pc[:])
+               t := &T{
+                       common: common{
+                               barrier: make(chan bool),
+                               signal:  make(chan bool),
+                               name:    testName,
+                               parent:  &f.common,
+                               level:   f.level + 1,
+                               creator: pc[:n],
+                               chatty:  f.chatty,
+                       },
+                       context: f.testContext,
+               }
+               if captureOut != nil {
+                       // t.parent aliases f.common.
+                       t.parent.w = captureOut
+               }
+               t.w = indenter{&t.common}
+               if t.chatty != nil {
+                       // TODO(#48132): adjust this to work with test2json.
+                       t.chatty.Updatef(t.name, "=== RUN   %s\n", t.name)
+               }
+               f.common.inFuzzFn, f.inFuzzFn = true, true
+               go tRunner(t, func(t *T) {
+                       args := []reflect.Value{reflect.ValueOf(t)}
+                       for _, v := range e.Values {
+                               args = append(args, reflect.ValueOf(v))
+                       }
+                       // Before reseting the current coverage, defer the snapshot so that we
+                       // make sure it is called right before the tRunner function exits,
+                       // regardless of whether it was executed cleanly, panicked, or if the
+                       // fuzzFn called t.Fatal.
+                       defer f.fuzzContext.deps.SnapshotCoverage()
+                       f.fuzzContext.deps.ResetCoverage()
+                       fn.Call(args)
+               })
+               <-t.signal
+               f.common.inFuzzFn, f.inFuzzFn = false, false
+               return !t.Failed()
+       }
+
+       switch f.fuzzContext.mode {
+       case fuzzCoordinator:
+               // Fuzzing is enabled, and this is the test process started by 'go test'.
+               // Act as the coordinator process, and coordinate workers to perform the
+               // actual fuzzing.
+               corpusTargetDir := filepath.Join(corpusDir, f.name)
+               cacheTargetDir := filepath.Join(*fuzzCacheDir, f.name)
+               err := f.fuzzContext.deps.CoordinateFuzzing(
+                       fuzzDuration.d,
+                       int64(fuzzDuration.n),
+                       minimizeDuration.d,
+                       int64(minimizeDuration.n),
+                       *parallel,
+                       f.corpus,
+                       types,
+                       corpusTargetDir,
+                       cacheTargetDir)
+               if err != nil {
+                       f.result = fuzzResult{Error: err}
+                       f.Fail()
+                       fmt.Fprintf(f.w, "%v\n", err)
+                       if crashErr, ok := err.(fuzzCrashError); ok {
+                               crashPath := crashErr.CrashPath()
+                               fmt.Fprintf(f.w, "Crash written to %s\n", crashPath)
+                               testName := filepath.Base(crashPath)
+                               fmt.Fprintf(f.w, "To re-run:\ngo test %s -run=%s/%s\n", f.fuzzContext.deps.ImportPath(), f.name, testName)
+                       }
+               }
+               // TODO(jayconrod,katiehockman): Aggregate statistics across workers
+               // and add to FuzzResult (ie. time taken, num iterations)
+
+       case fuzzWorker:
+               // Fuzzing is enabled, and this is a worker process. Follow instructions
+               // from the coordinator.
+               if err := f.fuzzContext.deps.RunFuzzWorker(func(e corpusEntry) error {
+                       // Don't write to f.w (which points to Stdout) if running from a
+                       // fuzz worker. This would become very verbose, particularly during
+                       // minimization. Return the error instead, and let the caller deal
+                       // with the output.
+                       var buf bytes.Buffer
+                       if ok := run(&buf, e); !ok {
+                               return errors.New(buf.String())
+                       }
+                       return nil
+               }); err != nil {
+                       // Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz.
+                       // The worker will exit with fuzzWorkerExitCode, indicating this is a failure
+                       // (and 'go test' should exit non-zero) but a crasher should not be recorded.
+                       f.Errorf("communicating with fuzzing coordinator: %v", err)
+               }
+
+       default:
+               // Fuzzing is not enabled, or will be done later. Only run the seed
+               // corpus now.
+               for _, e := range f.corpus {
+                       name := fmt.Sprintf("%s/%s", f.name, filepath.Base(e.Path))
+                       if _, ok, _ := f.testContext.match.fullName(nil, name); ok {
+                               run(f.w, e)
+                       }
+               }
+       }
+}
+
+func (f *F) report() {
+       if *isFuzzWorker || f.parent == nil {
+               return
+       }
+       dstr := fmtDuration(f.duration)
+       format := "--- %s: %s (%s)\n"
+       if f.Failed() {
+               f.flushToParent(f.name, format, "FAIL", f.name, dstr)
+       } else if f.chatty != nil {
+               if f.Skipped() {
+                       f.flushToParent(f.name, format, "SKIP", f.name, dstr)
+               } else {
+                       f.flushToParent(f.name, format, "PASS", f.name, dstr)
+               }
+       }
+}
+
+// fuzzResult contains the results of a fuzz run.
+type fuzzResult struct {
+       N     int           // The number of iterations.
+       T     time.Duration // The total time taken.
+       Error error         // Error is the error from the crash
+}
+
+func (r fuzzResult) String() string {
+       s := ""
+       if r.Error == nil {
+               return s
+       }
+       s = fmt.Sprintf("%s", r.Error.Error())
+       return s
+}
+
+// fuzzCrashError is satisfied by a crash detected within the fuzz function.
+// These errors are written to the seed corpus and can be re-run with 'go test'.
+// Errors within the fuzzing framework (like I/O errors between coordinator
+// and worker processes) don't satisfy this interface.
+type fuzzCrashError interface {
+       error
+       Unwrap() error
+
+       // CrashPath returns the path of the subtest that corresponds to the saved
+       // crash input file in the seed corpus. The test can be re-run with go test
+       // -run=$target/$name $target is the fuzz target name, and $name is the
+       // filepath.Base of the string returned here.
+       CrashPath() string
+}
+
+// fuzzContext holds fields common to all fuzz targets.
+type fuzzContext struct {
+       deps testDeps
+       mode fuzzMode
+}
+
+type fuzzMode uint8
+
+const (
+       seedCorpusOnly fuzzMode = iota
+       fuzzCoordinator
+       fuzzWorker
+)
+
+// runFuzzTargets runs the fuzz targets matching the pattern for -run. This will
+// only run the f.Fuzz function for each seed corpus without using the fuzzing
+// engine to generate or mutate inputs.
+func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline time.Time) (ran, ok bool) {
+       ok = true
+       if len(fuzzTargets) == 0 || *isFuzzWorker {
+               return ran, ok
+       }
+       m := newMatcher(deps.MatchString, *match, "-test.run")
+       tctx := newTestContext(*parallel, m)
+       tctx.deadline = deadline
+       var mFuzz *matcher
+       if *matchFuzz != "" {
+               mFuzz = newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz")
+       }
+       fctx := &fuzzContext{deps: deps, mode: seedCorpusOnly}
+       root := common{w: os.Stdout} // gather output in one place
+       if Verbose() {
+               root.chatty = newChattyPrinter(root.w)
+       }
+       for _, ft := range fuzzTargets {
+               if shouldFailFast() {
+                       break
+               }
+               testName, matched, _ := tctx.match.fullName(nil, ft.Name)
+               if !matched {
+                       continue
+               }
+               if mFuzz != nil {
+                       if _, fuzzMatched, _ := mFuzz.fullName(nil, ft.Name); fuzzMatched {
+                               // If this target will be fuzzed, then don't run the seed corpus
+                               // right now. That will happen later.
+                               continue
+                       }
+               }
+               f := &F{
+                       common: common{
+                               signal:  make(chan bool),
+                               barrier: make(chan bool),
+                               name:    testName,
+                               parent:  &root,
+                               level:   root.level + 1,
+                               chatty:  root.chatty,
+                       },
+                       testContext: tctx,
+                       fuzzContext: fctx,
+               }
+               f.w = indenter{&f.common}
+               if f.chatty != nil {
+                       // TODO(#48132): adjust this to work with test2json.
+                       f.chatty.Updatef(f.name, "=== RUN   %s\n", f.name)
+               }
+
+               go fRunner(f, ft.Fn)
+               <-f.signal
+       }
+       return root.ran, !root.Failed()
+}
+
+// runFuzzing runs the fuzz target matching the pattern for -fuzz. Only one such
+// fuzz target must match. This will run the fuzzing engine to generate and
+// mutate new inputs against the f.Fuzz function.
+//
+// If fuzzing is disabled (-test.fuzz is not set), runFuzzing
+// returns immediately.
+func runFuzzing(deps testDeps, fuzzTargets []InternalFuzzTarget) (ok bool) {
+       // TODO(katiehockman,jayconrod): Should we do something special to make sure
+       // we don't print f.Log statements again with runFuzzing, since we already
+       // would have printed them when we ran runFuzzTargets (ie. seed corpus run)?
+       if len(fuzzTargets) == 0 || *matchFuzz == "" {
+               return true
+       }
+       m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz")
+       tctx := newTestContext(1, m)
+       tctx.isFuzzing = true
+       fctx := &fuzzContext{
+               deps: deps,
+       }
+       root := common{w: os.Stdout}
+       if *isFuzzWorker {
+               root.w = io.Discard
+               fctx.mode = fuzzWorker
+       } else {
+               fctx.mode = fuzzCoordinator
+       }
+       if Verbose() && !*isFuzzWorker {
+               root.chatty = newChattyPrinter(root.w)
+       }
+       var target *InternalFuzzTarget
+       var targetName string
+       var matched []string
+       for i := range fuzzTargets {
+               name, ok, _ := tctx.match.fullName(nil, fuzzTargets[i].Name)
+               if !ok {
+                       continue
+               }
+               matched = append(matched, name)
+               target = &fuzzTargets[i]
+               targetName = name
+       }
+       if len(matched) == 0 {
+               fmt.Fprintln(os.Stderr, "testing: warning: no targets to fuzz")
+               return true
+       }
+       if len(matched) > 1 {
+               fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one target: %v\n", matched)
+               return false
+       }
+
+       f := &F{
+               common: common{
+                       signal:  make(chan bool),
+                       barrier: nil, // T.Parallel has no effect when fuzzing.
+                       name:    targetName,
+                       parent:  &root,
+                       level:   root.level + 1,
+                       chatty:  root.chatty,
+               },
+               fuzzContext: fctx,
+               testContext: tctx,
+       }
+       f.w = indenter{&f.common}
+       if f.chatty != nil {
+               // TODO(#48132): adjust this to work with test2json.
+               f.chatty.Updatef(f.name, "=== FUZZ  %s\n", f.name)
+       }
+       go fRunner(f, target.Fn)
+       <-f.signal
+       return !f.failed
+}
+
+// fRunner wraps a call to a fuzz target and ensures that cleanup functions are
+// called and status flags are set. fRunner should be called in its own
+// goroutine. To wait for its completion, receive from f.signal.
+//
+// fRunner is analogous to tRunner, which wraps subtests started with T.Run.
+// Tests and fuzz targets work a little differently, so for now, these functions
+// aren't consolidated. In particular, because there are no F.Run and F.Parallel
+// methods, i.e., no fuzz sub-targets or parallel fuzz targets, a few
+// simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is
+// called.
+func fRunner(f *F, fn func(*F)) {
+       // When this goroutine is done, either because runtime.Goexit was called,
+       // a panic started, or fn returned normally, record the duration and send
+       // t.signal, indicating the fuzz target is done.
+       defer func() {
+               // Detect whether the fuzz target panicked or called runtime.Goexit without
+               // calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly replacing a
+               // nil panic value). Nothing should recover after fRunner unwinds, so this
+               // should crash the process and print stack. Unfortunately, recovering here
+               // adds stack frames, but the location of the original panic should still be
+               // clear.
+               if f.Failed() {
+                       atomic.AddUint32(&numFailed, 1)
+               }
+               err := recover()
+               if err == nil {
+                       f.mu.RLock()
+                       fuzzNotCalled := !f.fuzzCalled && !f.skipped && !f.failed
+                       if !f.finished && !f.skipped && !f.failed {
+                               err = errNilPanicOrGoexit
+                       }
+                       f.mu.RUnlock()
+                       if fuzzNotCalled && err == nil {
+                               f.Error("returned without calling F.Fuzz, F.Fail, or F.Skip")
+                       }
+               }
+
+               // Use a deferred call to ensure that we report that the test is
+               // complete even if a cleanup function calls F.FailNow. See issue 41355.
+               didPanic := false
+               defer func() {
+                       if !didPanic {
+                               // Only report that the test is complete if it doesn't panic,
+                               // as otherwise the test binary can exit before the panic is
+                               // reported to the user. See issue 41479.
+                               f.signal <- true
+                       }
+               }()
+
+               // If we recovered a panic or inappropriate runtime.Goexit, fail the test,
+               // flush the output log up to the root, then panic.
+               doPanic := func(err interface{}) {
+                       f.Fail()
+                       if r := f.runCleanup(recoverAndReturnPanic); r != nil {
+                               f.Logf("cleanup panicked with %v", r)
+                       }
+                       for root := &f.common; root.parent != nil; root = root.parent {
+                               root.mu.Lock()
+                               root.duration += time.Since(root.start)
+                               d := root.duration
+                               root.mu.Unlock()
+                               root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
+                       }
+                       didPanic = true
+                       panic(err)
+               }
+               if err != nil {
+                       doPanic(err)
+               }
+
+               // No panic or inappropriate Goexit.
+               f.duration += time.Since(f.start)
+
+               if len(f.sub) > 0 {
+                       // Unblock inputs that called T.Parallel while running the seed corpus.
+                       // This only affects fuzz targets run as normal tests.
+                       // While fuzzing, T.Parallel has no effect, so f.sub is empty, and this
+                       // branch is not taken. f.barrier is nil in that case.
+                       close(f.barrier)
+                       // Wait for the subtests to complete.
+                       for _, sub := range f.sub {
+                               <-sub.signal
+                       }
+                       cleanupStart := time.Now()
+                       err := f.runCleanup(recoverAndReturnPanic)
+                       f.duration += time.Since(cleanupStart)
+                       if err != nil {
+                               doPanic(err)
+                       }
+               }
+
+               // Report after all subtests have finished.
+               f.report()
+               f.done = true
+               f.setRan()
+       }()
+       defer func() {
+               if len(f.sub) == 0 {
+                       f.runCleanup(normalPanic)
+               }
+       }()
+
+       f.start = time.Now()
+       fn(f)
+
+       // Code beyond this point will not be executed when FailNow or SkipNow
+       // is invoked.
+       f.mu.Lock()
+       f.finished = true
+       f.mu.Unlock()
+}
index b27fd62ee8f7182c5c1709f60a1e62908ce051cf..6175410f18a7c276f456c70f7848d7343b1ec52f 100644 (file)
@@ -33,6 +33,9 @@ helperfuncs_test.go:45: 5
 helperfuncs_test.go:21: 6
 helperfuncs_test.go:44: 7
 helperfuncs_test.go:56: 8
+--- FAIL: Test/sub2 (?s)
+helperfuncs_test.go:71: 11
+helperfuncs_test.go:75: recover 12
 helperfuncs_test.go:64: 9
 helperfuncs_test.go:60: 10
 `
@@ -71,38 +74,6 @@ func TestTBHelperParallel(t *T) {
        }
 }
 
-func TestTBHelperLineNumer(t *T) {
-       var buf bytes.Buffer
-       ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
-       t1 := &T{
-               common: common{
-                       signal: make(chan bool),
-                       w:      &buf,
-               },
-               context: ctx,
-       }
-       t1.Run("Test", func(t *T) {
-               helperA := func(t *T) {
-                       t.Helper()
-                       t.Run("subtest", func(t *T) {
-                               t.Helper()
-                               t.Fatal("fatal error message")
-                       })
-               }
-               helperA(t)
-       })
-
-       want := "helper_test.go:92: fatal error message"
-       got := ""
-       lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
-       if len(lines) > 0 {
-               got = strings.TrimSpace(lines[len(lines)-1])
-       }
-       if got != want {
-               t.Errorf("got output:\n\n%v\nwant:\n\n%v", got, want)
-       }
-}
-
 type noopWriter int
 
 func (nw *noopWriter) Write(b []byte) (int, error) { return len(b), nil }
index df0476ed7323de68fe7a7d8e6dba0aa93658c33f..272b33c0e5095ba2712324749821867e133c2c40 100644 (file)
@@ -65,6 +65,14 @@ func testHelper(t *T) {
                t.Helper()
                t.Error("9")
        })
+
+       // Check that helper-ness propagates up through subtests
+       // to helpers above. See https://golang.org/issue/44887.
+       helperSubCallingHelper(t, "11")
+
+       // Check that helper-ness propagates up through panic/recover.
+       // See https://golang.org/issue/31154.
+       recoverHelper(t, "12")
 }
 
 func parallelTestHelper(t *T) {
@@ -78,3 +86,27 @@ func parallelTestHelper(t *T) {
        }
        wg.Wait()
 }
+
+func helperSubCallingHelper(t *T, msg string) {
+       t.Helper()
+       t.Run("sub2", func(t *T) {
+               t.Helper()
+               t.Fatal(msg)
+       })
+}
+
+func recoverHelper(t *T, msg string) {
+       t.Helper()
+       defer func() {
+               t.Helper()
+               if err := recover(); err != nil {
+                       t.Errorf("recover %s", err)
+               }
+       }()
+       doPanic(t, msg)
+}
+
+func doPanic(t *T, msg string) {
+       t.Helper()
+       panic(msg)
+}
index 3608d332946e2ebee0558a35c35c7930a65e923a..c612355a0070bbbf713e821e64cffca4eea0423c 100644 (file)
@@ -12,12 +12,18 @@ package testdeps
 
 import (
        "bufio"
+       "context"
+       "internal/fuzz"
        "internal/testlog"
        "io"
+       "os"
+       "os/signal"
+       "reflect"
        "regexp"
        "runtime/pprof"
        "strings"
        "sync"
+       "time"
 )
 
 // TestDeps is an implementation of the testing.testDeps interface,
@@ -126,3 +132,68 @@ func (TestDeps) StopTestLog() error {
 func (TestDeps) SetPanicOnExit0(v bool) {
        testlog.SetPanicOnExit0(v)
 }
+
+func (TestDeps) CoordinateFuzzing(
+       timeout time.Duration,
+       limit int64,
+       minimizeTimeout time.Duration,
+       minimizeLimit int64,
+       parallel int,
+       seed []fuzz.CorpusEntry,
+       types []reflect.Type,
+       corpusDir,
+       cacheDir string) (err error) {
+       // Fuzzing may be interrupted with a timeout or if the user presses ^C.
+       // In either case, we'll stop worker processes gracefully and save
+       // crashers and interesting values.
+       ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+       defer cancel()
+       err = fuzz.CoordinateFuzzing(ctx, fuzz.CoordinateFuzzingOpts{
+               Log:             os.Stderr,
+               Timeout:         timeout,
+               Limit:           limit,
+               MinimizeTimeout: minimizeTimeout,
+               MinimizeLimit:   minimizeLimit,
+               Parallel:        parallel,
+               Seed:            seed,
+               Types:           types,
+               CorpusDir:       corpusDir,
+               CacheDir:        cacheDir,
+       })
+       if err == ctx.Err() {
+               return nil
+       }
+       return err
+}
+
+func (TestDeps) RunFuzzWorker(fn func(fuzz.CorpusEntry) error) error {
+       // Worker processes may or may not receive a signal when the user presses ^C
+       // On POSIX operating systems, a signal sent to a process group is delivered
+       // to all processes in that group. This is not the case on Windows.
+       // If the worker is interrupted, return quickly and without error.
+       // If only the coordinator process is interrupted, it tells each worker
+       // process to stop by closing its "fuzz_in" pipe.
+       ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+       defer cancel()
+       err := fuzz.RunFuzzWorker(ctx, fn)
+       if err == ctx.Err() {
+               return nil
+       }
+       return err
+}
+
+func (TestDeps) ReadCorpus(dir string, types []reflect.Type) ([]fuzz.CorpusEntry, error) {
+       return fuzz.ReadCorpus(dir, types)
+}
+
+func (TestDeps) CheckCorpus(vals []interface{}, types []reflect.Type) error {
+       return fuzz.CheckCorpus(vals, types)
+}
+
+func (TestDeps) ResetCoverage() {
+       fuzz.ResetCoverage()
+}
+
+func (TestDeps) SnapshotCoverage() {
+       fuzz.SnapshotCoverage()
+}
index b18c6e7f389ac64bfa10056ac958f69c50003eb9..d530f70c2676c61c2b43ec56aff204f67e20fcea 100644 (file)
@@ -14,36 +14,52 @@ import (
 
 // matcher sanitizes, uniques, and filters names of subtests and subbenchmarks.
 type matcher struct {
-       filter    []string
+       filter    filterMatch
        matchFunc func(pat, str string) (bool, error)
 
-       mu       sync.Mutex
-       subNames map[string]int64
+       mu sync.Mutex
+
+       // subNames is used to deduplicate subtest names.
+       // Each key is the subtest name joined to the deduplicated name of the parent test.
+       // Each value is the count of the number of occurrences of the given subtest name
+       // already seen.
+       subNames map[string]int32
+}
+
+type filterMatch interface {
+       // matches checks the name against the receiver's pattern strings using the
+       // given match function.
+       matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool)
+
+       // verify checks that the receiver's pattern strings are valid filters by
+       // calling the given match function.
+       verify(name string, matchString func(pat, str string) (bool, error)) error
 }
 
+// simpleMatch matches a test name if all of the pattern strings match in
+// sequence.
+type simpleMatch []string
+
+// alternationMatch matches a test name if one of the alternations match.
+type alternationMatch []filterMatch
+
 // TODO: fix test_main to avoid race and improve caching, also allowing to
 // eliminate this Mutex.
 var matchMutex sync.Mutex
 
 func newMatcher(matchString func(pat, str string) (bool, error), patterns, name string) *matcher {
-       var filter []string
+       var impl filterMatch
        if patterns != "" {
-               filter = splitRegexp(patterns)
-               for i, s := range filter {
-                       filter[i] = rewrite(s)
-               }
-               // Verify filters before doing any processing.
-               for i, s := range filter {
-                       if _, err := matchString(s, "non-empty"); err != nil {
-                               fmt.Fprintf(os.Stderr, "testing: invalid regexp for element %d of %s (%q): %s\n", i, name, s, err)
-                               os.Exit(1)
-                       }
+               impl = splitRegexp(patterns)
+               if err := impl.verify(name, matchString); err != nil {
+                       fmt.Fprintf(os.Stderr, "testing: invalid regexp for %s\n", err)
+                       os.Exit(1)
                }
        }
        return &matcher{
-               filter:    filter,
+               filter:    impl,
                matchFunc: matchString,
-               subNames:  map[string]int64{},
+               subNames:  map[string]int32{},
        }
 }
 
@@ -60,22 +76,74 @@ func (m *matcher) fullName(c *common, subname string) (name string, ok, partial
        matchMutex.Lock()
        defer matchMutex.Unlock()
 
+       if m.filter == nil {
+               return name, true, false
+       }
+
        // We check the full array of paths each time to allow for the case that
        // a pattern contains a '/'.
        elem := strings.Split(name, "/")
-       for i, s := range elem {
-               if i >= len(m.filter) {
+       ok, partial = m.filter.matches(elem, m.matchFunc)
+       return name, ok, partial
+}
+
+// clearSubNames clears the matcher's internal state, potentially freeing
+// memory. After this is called, T.Name may return the same strings as it did
+// for earlier subtests.
+func (m *matcher) clearSubNames() {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+       for key := range m.subNames {
+               delete(m.subNames, key)
+       }
+}
+
+func (m simpleMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) {
+       for i, s := range name {
+               if i >= len(m) {
                        break
                }
-               if ok, _ := m.matchFunc(m.filter[i], s); !ok {
-                       return name, false, false
+               if ok, _ := matchString(m[i], s); !ok {
+                       return false, false
+               }
+       }
+       return true, len(name) < len(m)
+}
+
+func (m simpleMatch) verify(name string, matchString func(pat, str string) (bool, error)) error {
+       for i, s := range m {
+               m[i] = rewrite(s)
+       }
+       // Verify filters before doing any processing.
+       for i, s := range m {
+               if _, err := matchString(s, "non-empty"); err != nil {
+                       return fmt.Errorf("element %d of %s (%q): %s", i, name, s, err)
+               }
+       }
+       return nil
+}
+
+func (m alternationMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) {
+       for _, m := range m {
+               if ok, partial = m.matches(name, matchString); ok {
+                       return ok, partial
+               }
+       }
+       return false, false
+}
+
+func (m alternationMatch) verify(name string, matchString func(pat, str string) (bool, error)) error {
+       for i, m := range m {
+               if err := m.verify(name, matchString); err != nil {
+                       return fmt.Errorf("alternation %d of %s", i, err)
                }
        }
-       return name, true, len(elem) < len(m.filter)
+       return nil
 }
 
-func splitRegexp(s string) []string {
-       a := make([]string, 0, strings.Count(s, "/"))
+func splitRegexp(s string) filterMatch {
+       a := make(simpleMatch, 0, strings.Count(s, "/"))
+       b := make(alternationMatch, 0, strings.Count(s, "|"))
        cs := 0
        cp := 0
        for i := 0; i < len(s); {
@@ -103,31 +171,88 @@ func splitRegexp(s string) []string {
                                i = 0
                                continue
                        }
+               case '|':
+                       if cs == 0 && cp == 0 {
+                               a = append(a, s[:i])
+                               s = s[i+1:]
+                               i = 0
+                               b = append(b, a)
+                               a = make(simpleMatch, 0, len(a))
+                               continue
+                       }
                }
                i++
        }
-       return append(a, s)
+
+       a = append(a, s)
+       if len(b) == 0 {
+               return a
+       }
+       return append(b, a)
 }
 
 // unique creates a unique name for the given parent and subname by affixing it
 // with one or more counts, if necessary.
 func (m *matcher) unique(parent, subname string) string {
-       name := fmt.Sprintf("%s/%s", parent, subname)
-       empty := subname == ""
+       base := parent + "/" + subname
+
        for {
-               next, exists := m.subNames[name]
-               if !empty && !exists {
-                       m.subNames[name] = 1 // next count is 1
-                       return name
+               n := m.subNames[base]
+               if n < 0 {
+                       panic("subtest count overflow")
                }
-               // Name was already used. We increment with the count and append a
-               // string with the count.
-               m.subNames[name] = next + 1
+               m.subNames[base] = n + 1
+
+               if n == 0 && subname != "" {
+                       prefix, nn := parseSubtestNumber(base)
+                       if len(prefix) < len(base) && nn < m.subNames[prefix] {
+                               // This test is explicitly named like "parent/subname#NN",
+                               // and #NN was already used for the NNth occurrence of "parent/subname".
+                               // Loop to add a disambiguating suffix.
+                               continue
+                       }
+                       return base
+               }
+
+               name := fmt.Sprintf("%s#%02d", base, n)
+               if m.subNames[name] != 0 {
+                       // This is the nth occurrence of base, but the name "parent/subname#NN"
+                       // collides with the first occurrence of a subtest *explicitly* named
+                       // "parent/subname#NN". Try the next number.
+                       continue
+               }
+
+               return name
+       }
+}
+
+// parseSubtestNumber splits a subtest name into a "#%02d"-formatted int32
+// suffix (if present), and a prefix preceding that suffix (always).
+func parseSubtestNumber(s string) (prefix string, nn int32) {
+       i := strings.LastIndex(s, "#")
+       if i < 0 {
+               return s, 0
+       }
+
+       prefix, suffix := s[:i], s[i+1:]
+       if len(suffix) < 2 || (len(suffix) > 2 && suffix[0] == '0') {
+               // Even if suffix is numeric, it is not a possible output of a "%02" format
+               // string: it has either too few digits or too many leading zeroes.
+               return s, 0
+       }
+       if suffix == "00" {
+               if !strings.HasSuffix(prefix, "/") {
+                       // We only use "#00" as a suffix for subtests named with the empty
+                       // string — it isn't a valid suffix if the subtest name is non-empty.
+                       return s, 0
+               }
+       }
 
-               // Add a count to guarantee uniqueness.
-               name = fmt.Sprintf("%s#%02d", name, next)
-               empty = false
+       n, err := strconv.ParseInt(suffix, 10, 32)
+       if err != nil || n < 0 {
+               return s, 0
        }
+       return prefix, int32(n)
 }
 
 // rewrite rewrites a subname to having only printable characters and no white
index 8c09dc660fb1a42b164ae8977ba87b8b61b3f294..206ac0b651f4082c3b45380468894341873a0125 100644 (file)
@@ -5,8 +5,10 @@
 package testing
 
 import (
+       "fmt"
        "reflect"
        "regexp"
+       "strings"
        "unicode"
 )
 
@@ -25,10 +27,11 @@ func TestIsSpace(t *T) {
 }
 
 func TestSplitRegexp(t *T) {
-       res := func(s ...string) []string { return s }
+       res := func(s ...string) filterMatch { return simpleMatch(s) }
+       alt := func(m ...filterMatch) filterMatch { return alternationMatch(m) }
        testCases := []struct {
                pattern string
-               result  []string
+               result  filterMatch
        }{
                // Correct patterns
                // If a regexp pattern is correct, all split regexps need to be correct
@@ -49,6 +52,8 @@ func TestSplitRegexp(t *T) {
                {`([)/][(])`, res(`([)/][(])`)},
                {"[(]/[)]", res("[(]", "[)]")},
 
+               {"A/B|C/D", alt(res("A", "B"), res("C", "D"))},
+
                // Faulty patterns
                // Errors in original should produce at least one faulty regexp in results.
                {")/", res(")/")},
@@ -71,10 +76,8 @@ func TestSplitRegexp(t *T) {
                // needs to have an error as well.
                if _, err := regexp.Compile(tc.pattern); err != nil {
                        ok := true
-                       for _, re := range a {
-                               if _, err := regexp.Compile(re); err != nil {
-                                       ok = false
-                               }
+                       if err := a.verify("", regexp.MatchString); err != nil {
+                               ok = false
                        }
                        if ok {
                                t.Errorf("%s: expected error in any of %q", tc.pattern, a)
@@ -113,6 +116,10 @@ func TestMatcher(t *T) {
                {"TestFoo/", "TestBar", "x", false, false},
                {"TestFoo/bar/baz", "TestBar", "x/bar/baz", false, false},
 
+               {"A/B|C/D", "TestA", "B", true, false},
+               {"A/B|C/D", "TestC", "D", true, false},
+               {"A/B|C/D", "TestA", "C", false, false},
+
                // subtests only
                {"", "TestFoo", "x", true, false},
                {"/", "TestFoo", "x", true, false},
@@ -142,45 +149,90 @@ func TestMatcher(t *T) {
        }
 }
 
+var namingTestCases = []struct{ name, want string }{
+       // Uniqueness
+       {"", "x/#00"},
+       {"", "x/#01"},
+       {"#0", "x/#0"},      // Doesn't conflict with #00 because the number of digits differs.
+       {"#00", "x/#00#01"}, // Conflicts with implicit #00 (used above), so add a suffix.
+       {"#", "x/#"},
+       {"#", "x/##01"},
+
+       {"t", "x/t"},
+       {"t", "x/t#01"},
+       {"t", "x/t#02"},
+       {"t#00", "x/t#00"}, // Explicit "#00" doesn't conflict with the unsuffixed first subtest.
+
+       {"a#01", "x/a#01"},    // user has subtest with this name.
+       {"a", "x/a"},          // doesn't conflict with this name.
+       {"a", "x/a#02"},       // This string is claimed now, so resume
+       {"a", "x/a#03"},       // with counting.
+       {"a#02", "x/a#02#01"}, // We already used a#02 once, so add a suffix.
+
+       {"b#00", "x/b#00"},
+       {"b", "x/b"}, // Implicit 0 doesn't conflict with explicit "#00".
+       {"b", "x/b#01"},
+       {"b#9223372036854775807", "x/b#9223372036854775807"}, // MaxInt64
+       {"b", "x/b#02"},
+       {"b", "x/b#03"},
+
+       // Sanitizing
+       {"A:1 B:2", "x/A:1_B:2"},
+       {"s\t\r\u00a0", "x/s___"},
+       {"\x01", `x/\x01`},
+       {"\U0010ffff", `x/\U0010ffff`},
+}
+
 func TestNaming(t *T) {
        m := newMatcher(regexp.MatchString, "", "")
-
        parent := &common{name: "x", level: 1} // top-level test.
 
-       // Rig the matcher with some preloaded values.
-       m.subNames["x/b"] = 1000
+       for i, tc := range namingTestCases {
+               if got, _, _ := m.fullName(parent, tc.name); got != tc.want {
+                       t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
+               }
+       }
+}
 
-       testCases := []struct {
-               name, want string
-       }{
-               // Uniqueness
-               {"", "x/#00"},
-               {"", "x/#01"},
-
-               {"t", "x/t"},
-               {"t", "x/t#01"},
-               {"t", "x/t#02"},
-
-               {"a#01", "x/a#01"}, // user has subtest with this name.
-               {"a", "x/a"},       // doesn't conflict with this name.
-               {"a", "x/a#01#01"}, // conflict, add disambiguating string.
-               {"a", "x/a#02"},    // This string is claimed now, so resume
-               {"a", "x/a#03"},    // with counting.
-               {"a#02", "x/a#02#01"},
-
-               {"b", "x/b#1000"}, // rigged, see above
-               {"b", "x/b#1001"},
-
-               // // Sanitizing
-               {"A:1 B:2", "x/A:1_B:2"},
-               {"s\t\r\u00a0", "x/s___"},
-               {"\x01", `x/\x01`},
-               {"\U0010ffff", `x/\U0010ffff`},
+func FuzzNaming(f *F) {
+       for _, tc := range namingTestCases {
+               f.Add(tc.name)
+       }
+       parent := &common{name: "x", level: 1}
+       var m *matcher
+       var seen map[string]string
+       reset := func() {
+               m = newMatcher(regexp.MatchString, "", "")
+               seen = make(map[string]string)
        }
+       reset()
 
-       for i, tc := range testCases {
-               if got, _, _ := m.fullName(parent, tc.name); got != tc.want {
-                       t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
+       f.Fuzz(func(t *T, subname string) {
+               if len(subname) > 10 {
+                       // Long names attract the OOM killer.
+                       t.Skip()
                }
+               name := m.unique(parent.name, subname)
+               if !strings.Contains(name, "/"+subname) {
+                       t.Errorf("name %q does not contain subname %q", name, subname)
+               }
+               if prev, ok := seen[name]; ok {
+                       t.Errorf("name %q generated by both %q and %q", name, prev, subname)
+               }
+               if len(seen) > 1e6 {
+                       // Free up memory.
+                       reset()
+               }
+               seen[name] = subname
+       })
+}
+
+// GoString returns a string that is more readable than the default, which makes
+// it easier to read test errors.
+func (m alternationMatch) GoString() string {
+       s := make([]string, len(m))
+       for i, m := range m {
+               s[i] = fmt.Sprintf("%#v", m)
        }
+       return fmt.Sprintf("(%s)", strings.Join(s, " | "))
 }
index c01647ecf0c911cdffbebe601975455dd94f6953..777338bb37de5b23882de2e951133fde8d5598f8 100644 (file)
@@ -113,7 +113,7 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value,
                        }
                        v.SetMapIndex(key, value)
                }
-       case reflect.Ptr:
+       case reflect.Pointer:
                if rand.Intn(size) == 0 {
                        v.Set(reflect.Zero(concrete)) // Generate nil pointer.
                } else {
index d9e342d4951edd62ec5f1537f076b7d38846fb82..e7eab1e50efd7956decdcd9074d6663d2521f3b8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build !js
-// +build !js
 
 // TODO(@musiol, @odeke-em): re-unify this entire file back into
 // example.go when js/wasm gets an os.Pipe implementation
index d914633ba91889b975e9f764aaed56f9e9c0d90c..adef9511fb56f8700e9517f35c0f910e76a80367 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js
-// +build js
 
 package testing
 
index 6c7d83aac2c036af89e65de2a1f35f44243f52a7..6a5add6f4e89f5f259d8b94ad962ffd955f612d2 100644 (file)
@@ -480,9 +480,10 @@ func TestTRun(t *T) {
                        buf := &bytes.Buffer{}
                        root := &T{
                                common: common{
-                                       signal: make(chan bool),
-                                       name:   "Test",
-                                       w:      buf,
+                                       signal:  make(chan bool),
+                                       barrier: make(chan bool),
+                                       name:    "Test",
+                                       w:       buf,
                                },
                                context: ctx,
                        }
@@ -669,7 +670,7 @@ func TestBRun(t *T) {
                                        w:      buf,
                                },
                                benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
-                               benchTime: benchTimeFlag{d: 1 * time.Microsecond},
+                               benchTime: durationOrCountFlag{d: 1 * time.Microsecond},
                        }
                        if tc.chatty {
                                root.chatty = newChattyPrinter(root.w)
index a19238d31e23fa5f308f97230a4f774be9785c91..2ad2266e2d0781b1a5b24f51840984800dda242f 100644 (file)
@@ -34,7 +34,7 @@
 // its -bench flag is provided. Benchmarks are run sequentially.
 //
 // For a description of the testing flags, see
-// https://golang.org/cmd/go/#hdr-Testing_flags
+// https://golang.org/cmd/go/#hdr-Testing_flags.
 //
 // A sample benchmark function looks like this:
 //     func BenchmarkRandInt(b *testing.B) {
 //         })
 //     }
 //
+// A detailed specification of the benchmark results format is given
+// in https://golang.org/design/14313-benchmark-format.
+//
+// There are standard tools for working with benchmark results at
+// https://golang.org/x/perf/cmd.
+// In particular, https://golang.org/x/perf/cmd/benchstat performs
+// statistically robust A/B comparisons.
+//
 // Examples
 //
 // The package also runs and verifies example code. Example functions may
 // example function, at least one other function, type, variable, or constant
 // declaration, and no test or benchmark functions.
 //
+// Fuzzing
+//
+// 'go test' and the testing package support fuzzing, a testing technique where
+// a function is called with randomly generated inputs to find bugs not
+// anticipated by unit tests.
+//
+// A fuzz target is a function that declares a set of "seed" inputs by calling
+// F.Add, then provides a fuzz function by calling F.Fuzz. A fuzz target has
+// the form:
+//
+//     func FuzzXxx(*testing.F)
+//
+// For example:
+//
+//     func FuzzHex(f *testing.F) {
+//       for _, seed := range [][]byte{{}, {0}, {9}, {0xa}, {0xf}, {1, 2, 3, 4}} {
+//         f.Add(seed)
+//       }
+//       f.Fuzz(func(t *testing.T, in []byte) {
+//         enc := hex.EncodeToString(in)
+//         out, err := hex.DecodeString(enc)
+//         if err != nil {
+//           t.Fatalf("%v: decode: %v", in, err)
+//         }
+//         if !bytes.Equal(in, out) {
+//           t.Fatalf("%v: not equal after round trip: %v", in, out)
+//         }
+//       })
+//     }
+//
+// Seed inputs may be registered by calling F.Add or by storing files in the
+// directory testdata/fuzz/<Name> (where <Name> is the name of the fuzz target)
+// within the package containing the fuzz target. Seed inputs are optional, but
+// the fuzzing engine may find bugs more efficiently when provided with a set
+// of small seed inputs with good code coverage.
+//
+// The fuzz function provided to F.Fuzz must accept a *testing.T parameter,
+// followed by one or more parameters for random inputs. The types of arguments
+// passed to F.Add must be identical to the types of these parameters. The fuzz
+// function may signal that it's found a problem the same way tests do: by
+// calling T.Fail (or any method that calls it like T.Error or T.Fatal) or by
+// panicking.
+//
+// When fuzzing is enabled (by setting the -fuzz flag to a regular expression
+// that matches a specific fuzz target), the fuzz function is called with
+// arguments generated by repeatedly making random changes to the seed inputs.
+// On supported platforms, 'go test' compiles the test executable with fuzzing
+// coverage instrumentation. The fuzzing engine uses that instrumentation to
+// find and cache inputs that expand coverage, increasing the liklihood of
+// finding bugs. If the fuzz function finds a problem, the fuzzing engine writes
+// the inputs that caused the problem to a file in the directory
+// testdata/fuzz/<Name> within the package directory. This file later serves as
+// a seed input. If the file can't be written at that location (for example,
+// because the directory is read-only), the fuzzing engine writes the file to
+// the fuzz cache directory within the build cache instead.
+//
+// When fuzzing is disabled, the fuzz function is called with the seed inputs
+// registered with F.Add and seed inputs from testdata/fuzz/<Name>. In this
+// mode, the fuzz target acts much like a regular test, with subtests started
+// with F.Fuzz instead of T.Run.
+//
+// TODO(#48255): write and link to documentation that will be helpful to users
+// who are unfamiliar with fuzzing.
+//
 // Skipping
 //
 // Tests or benchmarks may be skipped at run time with a call to
 //         ...
 //     }
 //
+// The Skip method of *T can be used in a fuzz target if the input is invalid,
+// but should not be considered a crash. For example:
+//
+//     func FuzzJSONMarshalling(f *testing.F) {
+//         f.Fuzz(func(t *testing.T, b []byte) {
+//             var v interface{}
+//             if err := json.Unmarshal(b, &v); err != nil {
+//                 t.Skip()
+//             }
+//             if _, err := json.Marshal(v); err != nil {
+//                 t.Error("Marshal: %v", err)
+//             }
+//         })
+//     }
+//
 // Subtests and Sub-benchmarks
 //
 // The Run methods of T and B allow defining subtests and sub-benchmarks,
 // of the top-level test and the sequence of names passed to Run, separated by
 // slashes, with an optional trailing sequence number for disambiguation.
 //
-// The argument to the -run and -bench command-line flags is an unanchored regular
+// The argument to the -run, -bench, and -fuzz command-line flags is an unanchored regular
 // expression that matches the test's name. For tests with multiple slash-separated
 // elements, such as subtests, the argument is itself slash-separated, with
 // expressions matching each name element in turn. Because it is unanchored, an
 // empty expression matches any string.
 // For example, using "matching" to mean "whose name contains":
 //
-//     go test -run ''      # Run all tests.
-//     go test -run Foo     # Run top-level tests matching "Foo", such as "TestFooBar".
-//     go test -run Foo/A=  # For top-level tests matching "Foo", run subtests matching "A=".
-//     go test -run /A=1    # For all top-level tests, run subtests matching "A=1".
+//     go test -run ''        # Run all tests.
+//     go test -run Foo       # Run top-level tests matching "Foo", such as "TestFooBar".
+//     go test -run Foo/A=    # For top-level tests matching "Foo", run subtests matching "A=".
+//     go test -run /A=1      # For all top-level tests, run subtests matching "A=1".
+//     go test -fuzz FuzzFoo  # Fuzz the target matching "FuzzFoo"
+//
+// The -run argument can also be used to run a specific value in the seed
+// corpus, for debugging. For example:
+//     go test -run=FuzzFoo/9ddb952d9814
+//
+// The -fuzz and -run flags can both be set, in order to fuzz a target but
+// skip the execution of all other tests.
 //
 // Subtests can also be used to control parallelism. A parent test will only
 // complete once all of its subtests complete. In this example, all tests are
@@ -246,6 +341,7 @@ import (
        "io"
        "math/rand"
        "os"
+       "reflect"
        "runtime"
        "runtime/debug"
        "runtime/trace"
@@ -307,6 +403,7 @@ func Init() {
        shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks")
 
        initBenchmarkFlags()
+       initFuzzFlags()
 }
 
 var (
@@ -403,6 +500,7 @@ type common struct {
        cleanupName string               // Name of the cleanup function.
        cleanupPc   []uintptr            // The stack trace at the point where Cleanup was called.
        finished    bool                 // Test function has completed.
+       inFuzzFn    bool                 // Whether the fuzz function, if this is one, is running.
 
        chatty     *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set.
        bench      bool           // Whether the current test is a benchmark.
@@ -416,7 +514,7 @@ type common struct {
        name     string    // Name of test or benchmark.
        start    time.Time // Time test or benchmark started
        duration time.Duration
-       barrier  chan bool // To signal parallel subtests they may start.
+       barrier  chan bool // To signal parallel subtests they may start. Nil when T.Parallel is not present (B) or not usable (when fuzzing).
        signal   chan bool // To signal a test is done.
        sub      []*T      // Queue of subtests to be run in parallel.
 
@@ -458,6 +556,12 @@ func Verbose() bool {
        return *chatty
 }
 
+func (c *common) checkFuzzFn(name string) {
+       if c.inFuzzFn {
+               panic(fmt.Sprintf("testing: f.%s was called inside the f.Fuzz function, use t.%s instead", name, name))
+       }
+}
+
 // frameSkip searches, starting after skip frames, for the first caller frame
 // in a function not marked as a helper and returns that frame.
 // The search stops if it finds a tRunner function that
@@ -483,6 +587,9 @@ func (c *common) frameSkip(skip int) runtime.Frame {
        var firstFrame, prevFrame, frame runtime.Frame
        for more := true; more; prevFrame = frame {
                frame, more = frames.Next()
+               if frame.Function == "runtime.gopanic" {
+                       continue
+               }
                if frame.Function == c.cleanupName {
                        frames = runtime.CallersFrames(c.cleanupPc)
                        continue
@@ -729,6 +836,7 @@ func (c *common) Failed() bool {
 // created during the test. Calling FailNow does not stop
 // those other goroutines.
 func (c *common) FailNow() {
+       c.checkFuzzFn("FailNow")
        c.Fail()
 
        // Calling runtime.Goexit will exit the goroutine, which
@@ -797,47 +905,59 @@ func (c *common) logDepth(s string, depth int) {
 // and records the text in the error log. For tests, the text will be printed only if
 // the test fails or the -test.v flag is set. For benchmarks, the text is always
 // printed to avoid having performance depend on the value of the -test.v flag.
-func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
+func (c *common) Log(args ...interface{}) {
+       c.checkFuzzFn("Log")
+       c.log(fmt.Sprintln(args...))
+}
 
 // Logf formats its arguments according to the format, analogous to Printf, and
 // records the text in the error log. A final newline is added if not provided. For
 // tests, the text will be printed only if the test fails or the -test.v flag is
 // set. For benchmarks, the text is always printed to avoid having performance
 // depend on the value of the -test.v flag.
-func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
+func (c *common) Logf(format string, args ...interface{}) {
+       c.checkFuzzFn("Logf")
+       c.log(fmt.Sprintf(format, args...))
+}
 
 // Error is equivalent to Log followed by Fail.
 func (c *common) Error(args ...interface{}) {
+       c.checkFuzzFn("Error")
        c.log(fmt.Sprintln(args...))
        c.Fail()
 }
 
 // Errorf is equivalent to Logf followed by Fail.
 func (c *common) Errorf(format string, args ...interface{}) {
+       c.checkFuzzFn("Errorf")
        c.log(fmt.Sprintf(format, args...))
        c.Fail()
 }
 
 // Fatal is equivalent to Log followed by FailNow.
 func (c *common) Fatal(args ...interface{}) {
+       c.checkFuzzFn("Fatal")
        c.log(fmt.Sprintln(args...))
        c.FailNow()
 }
 
 // Fatalf is equivalent to Logf followed by FailNow.
 func (c *common) Fatalf(format string, args ...interface{}) {
+       c.checkFuzzFn("Fatalf")
        c.log(fmt.Sprintf(format, args...))
        c.FailNow()
 }
 
 // Skip is equivalent to Log followed by SkipNow.
 func (c *common) Skip(args ...interface{}) {
+       c.checkFuzzFn("Skip")
        c.log(fmt.Sprintln(args...))
        c.SkipNow()
 }
 
 // Skipf is equivalent to Logf followed by SkipNow.
 func (c *common) Skipf(format string, args ...interface{}) {
+       c.checkFuzzFn("Skipf")
        c.log(fmt.Sprintf(format, args...))
        c.SkipNow()
 }
@@ -851,6 +971,7 @@ func (c *common) Skipf(format string, args ...interface{}) {
 // other goroutines created during the test. Calling SkipNow does not stop
 // those other goroutines.
 func (c *common) SkipNow() {
+       c.checkFuzzFn("SkipNow")
        c.mu.Lock()
        c.skipped = true
        c.finished = true
@@ -890,6 +1011,7 @@ func (c *common) Helper() {
 // subtests complete. Cleanup functions will be called in last added,
 // first called order.
 func (c *common) Cleanup(f func()) {
+       c.checkFuzzFn("Cleanup")
        var pc [maxStackLen]uintptr
        // Skip two extra frames to account for this function and runtime.Callers itself.
        n := runtime.Callers(2, pc[:])
@@ -923,6 +1045,7 @@ func (c *common) Cleanup(f func()) {
 // 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 {
+       c.checkFuzzFn("TempDir")
        // Use a single parent directory for all the temporary directories
        // created by a test, each numbered sequentially.
        c.tempDirMu.Lock()
@@ -988,6 +1111,7 @@ func (c *common) TempDir() string {
 //
 // This cannot be used in parallel tests.
 func (c *common) Setenv(key, value string) {
+       c.checkFuzzFn("Setenv")
        prevValue, ok := os.LookupEnv(key)
 
        if err := os.Setenv(key, value); err != nil {
@@ -1080,6 +1204,12 @@ func (t *T) Parallel() {
                panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests")
        }
        t.isParallel = true
+       if t.parent.barrier == nil {
+               // T.Parallel has no effect when fuzzing.
+               // Multiple processes may run in parallel, but only one input can run at a
+               // time per process so we can attribute crashes to specific inputs.
+               return
+       }
 
        // We don't want to include the time we spend waiting for serial tests
        // in the test duration. Record the elapsed time thus far and reset the
@@ -1152,7 +1282,14 @@ func tRunner(t *T, fn func(t *T)) {
                        t.Errorf("race detected during execution of test")
                }
 
-               // If the test panicked, print any test output before dying.
+               // Check if the test panicked or Goexited inappropriately.
+               //
+               // If this happens in a normal test, print output but continue panicking.
+               // tRunner is called in its own goroutine, so this terminates the process.
+               //
+               // If this happens while fuzzing, recover from the panic and treat it like a
+               // normal failure. It's important that the process keeps running in order to
+               // find short inputs that cause panics.
                err := recover()
                signal := true
 
@@ -1173,6 +1310,19 @@ func tRunner(t *T, fn func(t *T)) {
                                }
                        }
                }
+
+               if err != nil && t.context.isFuzzing {
+                       prefix := "panic: "
+                       if err == errNilPanicOrGoexit {
+                               prefix = ""
+                       }
+                       t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
+                       t.mu.Lock()
+                       t.finished = true
+                       t.mu.Unlock()
+                       err = nil
+               }
+
                // Use a deferred call to ensure that we report that the test is
                // complete even if a cleanup function calls t.FailNow. See issue 41355.
                didPanic := false
@@ -1242,7 +1392,7 @@ func tRunner(t *T, fn func(t *T)) {
                t.report() // Report after all subtests have finished.
 
                // Do not lock t.done to allow race detector to detect race in case
-               // the user does not appropriately synchronizes a goroutine.
+               // the user does not appropriately synchronize a goroutine.
                t.done = true
                if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 {
                        t.setRan()
@@ -1327,6 +1477,12 @@ type testContext struct {
        match    *matcher
        deadline time.Time
 
+       // isFuzzing is true in the context used when generating random inputs
+       // for fuzz targets. isFuzzing is false when running normal tests and
+       // when running fuzz tests as unit tests (without -fuzz or when -fuzz
+       // does not match).
+       isFuzzing bool
+
        mu sync.Mutex
 
        // Channel used to signal tests that are ready to be run in parallel.
@@ -1390,6 +1546,16 @@ func (f matchStringOnly) ImportPath() string                          { return "
 func (f matchStringOnly) StartTestLog(io.Writer)                      {}
 func (f matchStringOnly) StopTestLog() error                          { return errMain }
 func (f matchStringOnly) SetPanicOnExit0(bool)                        {}
+func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
+       return errMain
+}
+func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
+func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
+       return nil, errMain
+}
+func (f matchStringOnly) CheckCorpus([]interface{}, []reflect.Type) error { return nil }
+func (f matchStringOnly) ResetCoverage()                                  {}
+func (f matchStringOnly) SnapshotCoverage()                               {}
 
 // Main is an internal function, part of the implementation of the "go test" command.
 // It was exported because it is cross-package and predates "internal" packages.
@@ -1398,15 +1564,16 @@ func (f matchStringOnly) SetPanicOnExit0(bool)                        {}
 // new functionality is added to the testing package.
 // Systems simulating "go test" should be updated to use MainStart.
 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
-       os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, examples).Run())
+       os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
 }
 
 // M is a type passed to a TestMain function to run the actual tests.
 type M struct {
-       deps       testDeps
-       tests      []InternalTest
-       benchmarks []InternalBenchmark
-       examples   []InternalExample
+       deps        testDeps
+       tests       []InternalTest
+       benchmarks  []InternalBenchmark
+       fuzzTargets []InternalFuzzTarget
+       examples    []InternalExample
 
        timer     *time.Timer
        afterOnce sync.Once
@@ -1431,18 +1598,25 @@ type testDeps interface {
        StartTestLog(io.Writer)
        StopTestLog() error
        WriteProfileTo(string, io.Writer, int) error
+       CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
+       RunFuzzWorker(func(corpusEntry) error) error
+       ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
+       CheckCorpus([]interface{}, []reflect.Type) error
+       ResetCoverage()
+       SnapshotCoverage()
 }
 
 // MainStart is meant for use by tests generated by 'go test'.
 // It is not meant to be called directly and is not subject to the Go 1 compatibility document.
 // It may change signature from release to release.
-func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
+func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
        Init()
        return &M{
-               deps:       deps,
-               tests:      tests,
-               benchmarks: benchmarks,
-               examples:   examples,
+               deps:        deps,
+               tests:       tests,
+               benchmarks:  benchmarks,
+               fuzzTargets: fuzzTargets,
+               examples:    examples,
        }
 }
 
@@ -1469,9 +1643,15 @@ func (m *M) Run() (code int) {
                m.exitCode = 2
                return
        }
+       if *matchFuzz != "" && *fuzzCacheDir == "" {
+               fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
+               flag.Usage()
+               m.exitCode = 2
+               return
+       }
 
        if len(*matchList) != 0 {
-               listTests(m.deps.MatchString, m.tests, m.benchmarks, m.examples)
+               listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
                m.exitCode = 0
                return
        }
@@ -1499,22 +1679,42 @@ func (m *M) Run() (code int) {
 
        m.before()
        defer m.after()
-       deadline := m.startAlarm()
-       haveExamples = len(m.examples) > 0
-       testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
-       exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
-       m.stopAlarm()
-       if !testRan && !exampleRan && *matchBenchmarks == "" {
-               fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
+
+       // Run tests, examples, and benchmarks unless this is a fuzz worker process.
+       // Workers start after this is done by their parent process, and they should
+       // not repeat this work.
+       if !*isFuzzWorker {
+               deadline := m.startAlarm()
+               haveExamples = len(m.examples) > 0
+               testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
+               fuzzTargetsRan, fuzzTargetsOk := runFuzzTargets(m.deps, m.fuzzTargets, deadline)
+               exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
+               m.stopAlarm()
+               if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
+                       fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
+               }
+               if !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
+                       fmt.Println("FAIL")
+                       m.exitCode = 1
+                       return
+               }
        }
-       if !testOk || !exampleOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
+
+       fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
+       if !fuzzingOk {
                fmt.Println("FAIL")
-               m.exitCode = 1
+               if *isFuzzWorker {
+                       m.exitCode = fuzzWorkerExitCode
+               } else {
+                       m.exitCode = 1
+               }
                return
        }
 
-       fmt.Println("PASS")
        m.exitCode = 0
+       if !*isFuzzWorker {
+               fmt.Println("PASS")
+       }
        return
 }
 
@@ -1535,7 +1735,7 @@ func (t *T) report() {
        }
 }
 
-func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
+func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
        if _, err := matchString(*matchList, "non-empty"); err != nil {
                fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
                os.Exit(1)
@@ -1551,6 +1751,11 @@ func listTests(matchString func(pat, str string) (bool, error), tests []Internal
                        fmt.Println(bench.Name)
                }
        }
+       for _, fuzzTarget := range fuzzTargets {
+               if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
+                       fmt.Println(fuzzTarget.Name)
+               }
+       }
        for _, example := range examples {
                if ok, _ := matchString(*matchList, example.Name); ok {
                        fmt.Println(example.Name)
@@ -1580,6 +1785,12 @@ func runTests(matchString func(pat, str string) (bool, error), tests []InternalT
                        if shouldFailFast() {
                                break
                        }
+                       if i > 0 && !ran {
+                               // There were no tests to run on the first
+                               // iteration. This won't change, so no reason
+                               // to keep trying.
+                               break
+                       }
                        ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
                        ctx.deadline = deadline
                        t := &T{
index 7b3029433690c94b932bbda092392c3599a7b53e..10093881fbef66440d3f9cf46018220049886a19 100644 (file)
@@ -112,6 +112,14 @@ data, defined in detail in the corresponding sections that follow.
                T0 is executed; otherwise, dot is set to the successive elements
                of the array, slice, or map and T1 is executed.
 
+       {{break}}
+               The innermost {{range pipeline}} loop is ended early, stopping the
+               current iteration and bypassing all remaining iterations.
+
+       {{continue}}
+               The current iteration of the innermost {{range pipeline}} loop is
+               stopped, and the loop starts the next iteration.
+
        {{template "name"}}
                The template with the specified name is executed with nil data.
 
@@ -307,9 +315,10 @@ Predefined global functions are named as follows.
 
        and
                Returns the boolean AND of its arguments by returning the
-               first empty argument or the last argument, that is,
-               "and x y" behaves as "if x then y else x". All the
-               arguments are evaluated.
+               first empty argument or the last argument. That is,
+               "and x y" behaves as "if x then y else x."
+               Evaluation proceeds through the arguments left to right
+               and returns when the result is determined.
        call
                Returns the result of calling the first argument, which
                must be a function, with the remaining arguments as parameters.
@@ -344,8 +353,9 @@ Predefined global functions are named as follows.
        or
                Returns the boolean OR of its arguments by returning the
                first non-empty argument or the last argument, that is,
-               "or x y" behaves as "if x then x else y". All the
-               arguments are evaluated.
+               "or x y" behaves as "if x then x else y".
+               Evaluation proceeds through the arguments left to right
+               and returns when the result is determined.
        print
                An alias for fmt.Sprint
        printf
index 5ad3b4ec582c411fe7d4d3819c03a82f5c0041f9..c42cbb2ad3030dbea199f14b21d72ac3620b0e03 100644 (file)
@@ -5,6 +5,7 @@
 package template
 
 import (
+       "errors"
        "fmt"
        "internal/fmtsort"
        "io"
@@ -243,6 +244,12 @@ func (t *Template) DefinedTemplates() string {
        return b.String()
 }
 
+// Sentinel errors for use with panic to signal early exits from range loops.
+var (
+       walkBreak    = errors.New("break")
+       walkContinue = errors.New("continue")
+)
+
 // Walk functions step through the major pieces of the template structure,
 // generating output as they go.
 func (s *state) walk(dot reflect.Value, node parse.Node) {
@@ -255,7 +262,11 @@ func (s *state) walk(dot reflect.Value, node parse.Node) {
                if len(node.Pipe.Decl) == 0 {
                        s.printValue(node, val)
                }
+       case *parse.BreakNode:
+               panic(walkBreak)
        case *parse.CommentNode:
+       case *parse.ContinueNode:
+               panic(walkContinue)
        case *parse.IfNode:
                s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
        case *parse.ListNode:
@@ -316,7 +327,7 @@ func isTrue(val reflect.Value) (truth, ok bool) {
                truth = val.Bool()
        case reflect.Complex64, reflect.Complex128:
                truth = val.Complex() != 0
-       case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
+       case reflect.Chan, reflect.Func, reflect.Pointer, reflect.Interface:
                truth = !val.IsNil()
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
                truth = val.Int() != 0
@@ -334,6 +345,11 @@ func isTrue(val reflect.Value) (truth, ok bool) {
 
 func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
        s.at(r)
+       defer func() {
+               if r := recover(); r != nil && r != walkBreak {
+                       panic(r)
+               }
+       }()
        defer s.pop(s.mark())
        val, _ := indirect(s.evalPipeline(dot, r.Pipe))
        // mark top of stack before any variables in the body are pushed.
@@ -347,8 +363,14 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
                if len(r.Pipe.Decl) > 1 {
                        s.setTopVar(2, index)
                }
+               defer s.pop(mark)
+               defer func() {
+                       // Consume panic(walkContinue)
+                       if r := recover(); r != nil && r != walkContinue {
+                               panic(r)
+                       }
+               }()
                s.walk(elem, r.List)
-               s.pop(mark)
        }
        switch val.Kind() {
        case reflect.Array, reflect.Slice:
@@ -572,11 +594,11 @@ func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ide
 func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value {
        s.at(node)
        name := node.Ident
-       function, ok := findFunction(name, s.tmpl)
+       function, isBuiltin, ok := findFunction(name, s.tmpl)
        if !ok {
                s.errorf("%q is not a defined function", name)
        }
-       return s.evalCall(dot, function, cmd, name, args, final)
+       return s.evalCall(dot, function, isBuiltin, cmd, name, args, final)
 }
 
 // evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
@@ -601,11 +623,11 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
        // Unless it's an interface, need to get to a value of type *T to guarantee
        // we see all methods of T and *T.
        ptr := receiver
-       if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Ptr && ptr.CanAddr() {
+       if ptr.Kind() != reflect.Interface && ptr.Kind() != reflect.Pointer && ptr.CanAddr() {
                ptr = ptr.Addr()
        }
        if method := ptr.MethodByName(fieldName); method.IsValid() {
-               return s.evalCall(dot, method, node, fieldName, args, final)
+               return s.evalCall(dot, method, false, node, fieldName, args, final)
        }
        hasArgs := len(args) > 1 || final != missingVal
        // It's not a method; must be a field of a struct or an element of a map.
@@ -613,10 +635,13 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
        case reflect.Struct:
                tField, ok := receiver.Type().FieldByName(fieldName)
                if ok {
-                       field := receiver.FieldByIndex(tField.Index)
+                       field, err := receiver.FieldByIndexErr(tField.Index)
                        if !tField.IsExported() {
                                s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
                        }
+                       if err != nil {
+                               s.errorf("%v", err)
+                       }
                        // If it's a function, we must call it.
                        if hasArgs {
                                s.errorf("%s has arguments but cannot be invoked as function", fieldName)
@@ -643,7 +668,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
                        }
                        return result
                }
-       case reflect.Ptr:
+       case reflect.Pointer:
                etyp := receiver.Type().Elem()
                if etyp.Kind() == reflect.Struct {
                        if _, ok := etyp.FieldByName(fieldName); !ok {
@@ -669,7 +694,7 @@ var (
 // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
 // it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
 // as the function itself.
-func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value {
+func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value {
        if args != nil {
                args = args[1:] // Zeroth arg is function name/node; not passed to function.
        }
@@ -691,6 +716,38 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
                // TODO: This could still be a confusing error; maybe goodFunc should provide info.
                s.errorf("can't call method/function %q with %d results", name, typ.NumOut())
        }
+
+       unwrap := func(v reflect.Value) reflect.Value {
+               if v.Type() == reflectValueType {
+                       v = v.Interface().(reflect.Value)
+               }
+               return v
+       }
+
+       // Special case for builtin and/or, which short-circuit.
+       if isBuiltin && (name == "and" || name == "or") {
+               argType := typ.In(0)
+               var v reflect.Value
+               for _, arg := range args {
+                       v = s.evalArg(dot, argType, arg).Interface().(reflect.Value)
+                       if truth(v) == (name == "or") {
+                               // This value was already unwrapped
+                               // by the .Interface().(reflect.Value).
+                               return v
+                       }
+               }
+               if final != missingVal {
+                       // The last argument to and/or is coming from
+                       // the pipeline. We didn't short circuit on an earlier
+                       // argument, so we are going to return this one.
+                       // We don't have to evaluate final, but we do
+                       // have to check its type. Then, since we are
+                       // going to return it, we have to unwrap it.
+                       v = unwrap(s.validateType(final, argType))
+               }
+               return v
+       }
+
        // Build the arg list.
        argv := make([]reflect.Value, numIn)
        // Args must be evaluated. Fixed args first.
@@ -728,16 +785,13 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
                s.at(node)
                s.errorf("error calling %s: %w", name, err)
        }
-       if v.Type() == reflectValueType {
-               v = v.Interface().(reflect.Value)
-       }
-       return v
+       return unwrap(v)
 }
 
 // canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
 func canBeNil(typ reflect.Type) bool {
        switch typ.Kind() {
-       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
                return true
        case reflect.Struct:
                return typ == reflectValueType
@@ -774,12 +828,12 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
                // are much more constrained, so it makes more sense there than here.
                // Besides, one is almost always all you need.
                switch {
-               case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
+               case value.Kind() == reflect.Pointer && value.Type().Elem().AssignableTo(typ):
                        value = value.Elem()
                        if !value.IsValid() {
                                s.errorf("dereference of nil pointer of type %s", typ)
                        }
-               case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
+               case reflect.PointerTo(value.Type()).AssignableTo(typ) && value.CanAddr():
                        value = value.Addr()
                default:
                        s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
@@ -931,7 +985,7 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Valu
 // if it's nil. If the returned bool is true, the returned value's kind will be
 // either a pointer or interface.
 func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
-       for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
+       for ; v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface; v = v.Elem() {
                if v.IsNil() {
                        return v, true
                }
@@ -970,7 +1024,7 @@ func (s *state) printValue(n parse.Node, v reflect.Value) {
 // printableValue returns the, possibly indirected, interface value inside v that
 // is best for a call to formatted printer.
 func printableValue(v reflect.Value) (interface{}, bool) {
-       if v.Kind() == reflect.Ptr {
+       if v.Kind() == reflect.Pointer {
                v, _ = indirect(v) // fmt.Fprint handles nil.
        }
        if !v.IsValid() {
@@ -978,7 +1032,7 @@ func printableValue(v reflect.Value) (interface{}, bool) {
        }
 
        if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
-               if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
+               if v.CanAddr() && (reflect.PointerTo(v.Type()).Implements(errorType) || reflect.PointerTo(v.Type()).Implements(fmtStringerType)) {
                        v = v.Addr()
                } else {
                        switch v.Kind() {
index ef521645a7f5d5b71c30ddee90362448971ed561..3c40aa901e19ec3007c8967bc6c1381a13a9849c 100644 (file)
@@ -481,8 +481,19 @@ var execTests = []execTest{
        {"not", "{{not true}} {{not false}}", "false true", nil, true},
        {"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
        {"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
+       {"or short-circuit", "{{or 0 1 (die)}}", "1", nil, true},
+       {"and short-circuit", "{{and 1 0 (die)}}", "0", nil, true},
+       {"or short-circuit2", "{{or 0 0 (die)}}", "", nil, false},
+       {"and short-circuit2", "{{and 1 1 (die)}}", "", nil, false},
+       {"and pipe-true", "{{1 | and 1}}", "1", nil, true},
+       {"and pipe-false", "{{0 | and 1}}", "0", nil, true},
+       {"or pipe-true", "{{1 | or 0}}", "1", nil, true},
+       {"or pipe-false", "{{0 | or 0}}", "0", nil, true},
+       {"and undef", "{{and 1 .Unknown}}", "<no value>", nil, true},
+       {"or undef", "{{or 0 .Unknown}}", "<no value>", nil, true},
        {"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
        {"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
+       {"boolean if pipe", "{{if true | not | and 1}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
 
        // Indexing.
        {"slice[0]", "{{index .SI 0}}", "3", tVal, true},
@@ -564,6 +575,8 @@ var execTests = []execTest{
        {"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
        {"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
        {"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+       {"range []int break else", "{{range .SI}}-{{.}}-{{break}}NOTREACHED{{else}}EMPTY{{end}}", "-3-", tVal, true},
+       {"range []int continue else", "{{range .SI}}-{{.}}-{{continue}}NOTREACHED{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
        {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
        {"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
        {"range map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", tVal, true},
@@ -764,6 +777,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) {
                "add":         add,
                "count":       count,
                "dddArg":      dddArg,
+               "die":         func() bool { panic("die") },
                "echo":        echo,
                "makemap":     makemap,
                "mapOfThree":  mapOfThree,
@@ -1773,3 +1787,26 @@ func TestIssue39807(t *testing.T) {
 
        wg.Wait()
 }
+
+// Issue 48215: embedded nil pointer causes panic.
+// Fixed by adding FieldByIndexErr to the reflect package.
+func TestIssue48215(t *testing.T) {
+       type A struct {
+               S string
+       }
+       type B struct {
+               *A
+       }
+       tmpl, err := New("").Parse(`{{ .S }}`)
+       if err != nil {
+               t.Fatal(err)
+       }
+       err = tmpl.Execute(io.Discard, B{})
+       // We expect an error, not a panic.
+       if err == nil {
+               t.Fatal("did not get error for nil embedded struct")
+       }
+       if !strings.Contains(err.Error(), "reflect: indirection through nil pointer to embedded struct field A") {
+               t.Fatal(err)
+       }
+}
index fff833ed29813e21f8826914acf20b1e038ddf7b..11e2e903c850da17f829f8801a815f727827e4ae 100644 (file)
@@ -139,18 +139,18 @@ func goodName(name string) bool {
 }
 
 // findFunction looks for a function in the template, and global map.
-func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
+func findFunction(name string, tmpl *Template) (v reflect.Value, isBuiltin, ok bool) {
        if tmpl != nil && tmpl.common != nil {
                tmpl.muFuncs.RLock()
                defer tmpl.muFuncs.RUnlock()
                if fn := tmpl.execFuncs[name]; fn.IsValid() {
-                       return fn, true
+                       return fn, false, true
                }
        }
        if fn := builtinFuncs()[name]; fn.IsValid() {
-               return fn, true
+               return fn, true, true
        }
-       return reflect.Value{}, false
+       return reflect.Value{}, false, false
 }
 
 // prepareArg checks if value can be used as an argument of type argType, and
@@ -382,31 +382,13 @@ func truth(arg reflect.Value) bool {
 // and computes the Boolean AND of its arguments, returning
 // the first false argument it encounters, or the last argument.
 func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
-       if !truth(arg0) {
-               return arg0
-       }
-       for i := range args {
-               arg0 = args[i]
-               if !truth(arg0) {
-                       break
-               }
-       }
-       return arg0
+       panic("unreachable") // implemented as a special case in evalCall
 }
 
 // or computes the Boolean OR of its arguments, returning
 // the first true argument it encounters, or the last argument.
 func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
-       if truth(arg0) {
-               return arg0
-       }
-       for i := range args {
-               arg0 = args[i]
-               if truth(arg0) {
-                       break
-               }
-       }
-       return arg0
+       panic("unreachable") // implemented as a special case in evalCall
 }
 
 // not returns the Boolean negation of its argument.
index b543ab5c47c6d3f06c57b20ce5993f57f63df32f..6b81ffe7acbb5806154ad0430c26638c4cd23a2d 100644 (file)
@@ -452,3 +452,13 @@ func TestIssue19294(t *testing.T) {
                }
        }
 }
+
+// Issue 48436
+func TestAddToZeroTemplate(t *testing.T) {
+       tree, err := parse.Parse("c", cloneText3, "", "", nil, builtins())
+       if err != nil {
+               t.Fatal(err)
+       }
+       var tmpl Template
+       tmpl.AddParseTree("x", tree["c"])
+}
index addce2d890d6d842445dae44c8d140a90416c41a..1035afad72a93f4eaa2d0282c83a43e68bba5e0c 100644 (file)
@@ -51,13 +51,11 @@ func (t *Template) setOption(opt string) {
        if opt == "" {
                panic("empty option string")
        }
-       elems := strings.Split(opt, "=")
-       switch len(elems) {
-       case 2:
-               // key=value
-               switch elems[0] {
+       // key=value
+       if key, value, ok := strings.Cut(opt, "="); ok {
+               switch key {
                case "missingkey":
-                       switch elems[1] {
+                       switch value {
                        case "invalid", "default":
                                t.option.missingKey = mapInvalid
                                return
index 6784071b1118d16f752d5b39e8467af013881f7e..95e33771c09732747140500c2e0a5c97104ad46f 100644 (file)
@@ -62,6 +62,8 @@ const (
        // Keywords appear after all the rest.
        itemKeyword  // used only to delimit the keywords
        itemBlock    // block keyword
+       itemBreak    // break keyword
+       itemContinue // continue keyword
        itemDot      // the cursor, spelled '.'
        itemDefine   // define keyword
        itemElse     // else keyword
@@ -76,6 +78,8 @@ const (
 var key = map[string]itemType{
        ".":        itemDot,
        "block":    itemBlock,
+       "break":    itemBreak,
+       "continue": itemContinue,
        "define":   itemDefine,
        "else":     itemElse,
        "end":      itemEnd,
@@ -119,6 +123,8 @@ type lexer struct {
        parenDepth  int       // nesting depth of ( ) exprs
        line        int       // 1+number of newlines seen
        startLine   int       // start line of this item
+       breakOK     bool      // break keyword allowed
+       continueOK  bool      // continue keyword allowed
 }
 
 // next returns the next rune in the input.
@@ -461,7 +467,12 @@ Loop:
                        }
                        switch {
                        case key[word] > itemKeyword:
-                               l.emit(key[word])
+                               item := key[word]
+                               if item == itemBreak && !l.breakOK || item == itemContinue && !l.continueOK {
+                                       l.emit(itemIdentifier)
+                               } else {
+                                       l.emit(item)
+                               }
                        case word[0] == '.':
                                l.emit(itemField)
                        case word == "true", word == "false":
index 6510eed674dd9fecdae833ff8ae710e1522c17cb..df6aabffb20e13c9010faf779a0b190bf8d43ac4 100644 (file)
@@ -35,6 +35,8 @@ var itemName = map[itemType]string{
        // keywords
        itemDot:      ".",
        itemBlock:    "block",
+       itemBreak:    "break",
+       itemContinue: "continue",
        itemDefine:   "define",
        itemElse:     "else",
        itemIf:       "if",
index 177482f9b26059b5183e29b0146985b796dc134d..47268225c8ca1cd4aef1f4cc5e4bd4c9d0543904 100644 (file)
@@ -71,6 +71,8 @@ const (
        NodeVariable                   // A $ variable.
        NodeWith                       // A with action.
        NodeComment                    // A comment.
+       NodeBreak                      // A break action.
+       NodeContinue                   // A continue action.
 )
 
 // Nodes.
@@ -907,6 +909,40 @@ func (i *IfNode) Copy() Node {
        return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
 }
 
+// BreakNode represents a {{break}} action.
+type BreakNode struct {
+       tr *Tree
+       NodeType
+       Pos
+       Line int
+}
+
+func (t *Tree) newBreak(pos Pos, line int) *BreakNode {
+       return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line}
+}
+
+func (b *BreakNode) Copy() Node                  { return b.tr.newBreak(b.Pos, b.Line) }
+func (b *BreakNode) String() string              { return "{{break}}" }
+func (b *BreakNode) tree() *Tree                 { return b.tr }
+func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") }
+
+// ContinueNode represents a {{continue}} action.
+type ContinueNode struct {
+       tr *Tree
+       NodeType
+       Pos
+       Line int
+}
+
+func (t *Tree) newContinue(pos Pos, line int) *ContinueNode {
+       return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line}
+}
+
+func (c *ContinueNode) Copy() Node                  { return c.tr.newContinue(c.Pos, c.Line) }
+func (c *ContinueNode) String() string              { return "{{continue}}" }
+func (c *ContinueNode) tree() *Tree                 { return c.tr }
+func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") }
+
 // RangeNode represents a {{range}} action and its commands.
 type RangeNode struct {
        BranchNode
index 1a63961c13ecce1c892584698d26e54836a1eed4..64b29a2e169bd2e4e51e9eee73b0fae7494382aa 100644 (file)
@@ -31,7 +31,7 @@ type Tree struct {
        vars       []string // variables defined at the moment.
        treeSet    map[string]*Tree
        actionLine int // line of left delim starting action
-       mode       Mode
+       rangeDepth int
 }
 
 // A mode value is a set of flags (or 0). Modes control parser behavior.
@@ -224,6 +224,8 @@ func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet ma
        t.vars = []string{"$"}
        t.funcs = funcs
        t.treeSet = treeSet
+       lex.breakOK = !t.hasFunction("break")
+       lex.continueOK = !t.hasFunction("continue")
 }
 
 // stopParse terminates parsing.
@@ -386,6 +388,10 @@ func (t *Tree) action() (n Node) {
        switch token := t.nextNonSpace(); token.typ {
        case itemBlock:
                return t.blockControl()
+       case itemBreak:
+               return t.breakControl(token.pos, token.line)
+       case itemContinue:
+               return t.continueControl(token.pos, token.line)
        case itemElse:
                return t.elseControl()
        case itemEnd:
@@ -405,6 +411,32 @@ func (t *Tree) action() (n Node) {
        return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim))
 }
 
+// Break:
+//     {{break}}
+// Break keyword is past.
+func (t *Tree) breakControl(pos Pos, line int) Node {
+       if token := t.next(); token.typ != itemRightDelim {
+               t.unexpected(token, "in {{break}}")
+       }
+       if t.rangeDepth == 0 {
+               t.errorf("{{break}} outside {{range}}")
+       }
+       return t.newBreak(pos, line)
+}
+
+// Continue:
+//     {{continue}}
+// Continue keyword is past.
+func (t *Tree) continueControl(pos Pos, line int) Node {
+       if token := t.next(); token.typ != itemRightDelim {
+               t.unexpected(token, "in {{continue}}")
+       }
+       if t.rangeDepth == 0 {
+               t.errorf("{{continue}} outside {{range}}")
+       }
+       return t.newContinue(pos, line)
+}
+
 // Pipeline:
 //     declarations? command ('|' command)*
 func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) {
@@ -480,8 +512,14 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
        defer t.popVars(len(t.vars))
        pipe = t.pipeline(context, itemRightDelim)
+       if context == "range" {
+               t.rangeDepth++
+       }
        var next Node
        list, next = t.itemList()
+       if context == "range" {
+               t.rangeDepth--
+       }
        switch next.Type() {
        case nodeEnd: //done
        case nodeElse:
@@ -523,7 +561,8 @@ func (t *Tree) ifControl() Node {
 //     {{range pipeline}} itemList {{else}} itemList {{end}}
 // Range keyword is past.
 func (t *Tree) rangeControl() Node {
-       return t.newRange(t.parseControl(false, "range"))
+       r := t.newRange(t.parseControl(false, "range"))
+       return r
 }
 
 // With:
index 9b1be272e573d98e38c3da477f50660fdeddd3d0..c3679a08decb4d73246622d6e6d12a133444d8ef 100644 (file)
@@ -230,6 +230,10 @@ var parseTests = []parseTest{
                `{{range $x := .SI}}{{.}}{{end}}`},
        {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
                `{{range $x, $y := .SI}}{{.}}{{end}}`},
+       {"range with break", "{{range .SI}}{{.}}{{break}}{{end}}", noError,
+               `{{range .SI}}{{.}}{{break}}{{end}}`},
+       {"range with continue", "{{range .SI}}{{.}}{{continue}}{{end}}", noError,
+               `{{range .SI}}{{.}}{{continue}}{{end}}`},
        {"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError,
                `{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`},
        {"template", "{{template `x`}}", noError,
@@ -279,6 +283,10 @@ var parseTests = []parseTest{
        {"adjacent args", "{{printf 3`x`}}", hasError, ""},
        {"adjacent args with .", "{{printf `x`.}}", hasError, ""},
        {"extra end after if", "{{if .X}}a{{else if .Y}}b{{end}}{{end}}", hasError, ""},
+       {"break outside range", "{{range .}}{{end}} {{break}}", hasError, ""},
+       {"continue outside range", "{{range .}}{{end}} {{continue}}", hasError, ""},
+       {"break in range else", "{{range .}}{{else}}{{break}}{{end}}", hasError, ""},
+       {"continue in range else", "{{range .}}{{else}}{{continue}}{{end}}", hasError, ""},
        // Other kinds of assignments and operators aren't available yet.
        {"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"},
        {"bug0b", "{{$x += 1}}{{$x}}", hasError, ""},
index fd74d45e9b1c6df9a0bf45206eba1d040dd0d3b9..776be9cd075d37dc9863c6dccdf551298d9a0a77 100644 (file)
@@ -127,9 +127,9 @@ func (t *Template) copy(c *common) *Template {
 // its definition. If it has been defined and already has that name, the existing
 // definition is replaced; otherwise a new template is created, defined, and returned.
 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+       t.init()
        t.muTmpl.Lock()
        defer t.muTmpl.Unlock()
-       t.init()
        nt := t
        if name != t.name {
                nt = t.New(name)
index 34490c859ddb51af4c18ddddea22da1cace87a76..2a9821baa91959f335b93bd602cd998137cafb1e 100644 (file)
@@ -6,7 +6,6 @@
 // the binary.
 
 //go:build timetzdata
-// +build timetzdata
 
 package time
 
index f4b4f48142f69387b72babac32ac888ff036145d..5fb9cdc969395a0ef040de8d877cdbece5c60520 100644 (file)
@@ -74,7 +74,7 @@ import "errors"
 // for compatibility with fixed-width Unix time formats. A leading zero represents
 // a zero-padded value.
 //
-// The formats  and 002 are space-padded and zero-padded
+// The formats __2 and 002 are space-padded and zero-padded
 // three-character day of year; there is no unpadded day of year format.
 //
 // A comma or decimal point followed by one or more zeros represents
@@ -146,10 +146,11 @@ const (
        stdFracSecond0                                 // ".0", ".00", ... , trailing zeros included
        stdFracSecond9                                 // ".9", ".99", ..., trailing zeros omitted
 
-       stdNeedDate  = 1 << 8             // need month, day, year
-       stdNeedClock = 2 << 8             // need hour, minute, second
-       stdArgShift  = 16                 // extra argument in high bits, above low stdArgShift
-       stdMask      = 1<<stdArgShift - 1 // mask out argument
+       stdNeedDate       = 1 << 8             // need month, day, year
+       stdNeedClock      = 2 << 8             // need hour, minute, second
+       stdArgShift       = 16                 // extra argument in high bits, above low stdArgShift
+       stdSeparatorShift = 28                 // extra argument in high 4 bits for fractional second separators
+       stdMask           = 1<<stdArgShift - 1 // mask out argument
 )
 
 // std0x records the std values for "01", "02", ..., "06".
@@ -289,11 +290,11 @@ func nextStdChunk(layout string) (prefix string, std int, suffix string) {
                                }
                                // String of digits must end here - only fractional second is all digits.
                                if !isDigit(layout, j) {
-                                       std := stdFracSecond0
+                                       code := stdFracSecond0
                                        if layout[i+1] == '9' {
-                                               std = stdFracSecond9
+                                               code = stdFracSecond9
                                        }
-                                       std |= (j - (i + 1)) << stdArgShift
+                                       std := stdFracSecond(code, j-(i+1), c)
                                        return layout[0:i], std, layout[j:]
                                }
                        }
@@ -430,9 +431,36 @@ func atoi(s string) (x int, err error) {
        return x, nil
 }
 
+// The "std" value passed to formatNano contains two packed fields: the number of
+// digits after the decimal and the separator character (period or comma).
+// These functions pack and unpack that variable.
+func stdFracSecond(code, n, c int) int {
+       // Use 0xfff to make the failure case even more absurd.
+       if c == '.' {
+               return code | ((n & 0xfff) << stdArgShift)
+       }
+       return code | ((n & 0xfff) << stdArgShift) | 1<<stdSeparatorShift
+}
+
+func digitsLen(std int) int {
+       return (std >> stdArgShift) & 0xfff
+}
+
+func separator(std int) byte {
+       if (std >> stdSeparatorShift) == 0 {
+               return '.'
+       }
+       return ','
+}
+
 // formatNano appends a fractional second, as nanoseconds, to b
 // and returns the result.
-func formatNano(b []byte, nanosec uint, n int, trim bool) []byte {
+func formatNano(b []byte, nanosec uint, std int) []byte {
+       var (
+               n         = digitsLen(std)
+               separator = separator(std)
+               trim      = std&stdMask == stdFracSecond9
+       )
        u := nanosec
        var buf [9]byte
        for start := len(buf); start > 0; {
@@ -452,7 +480,7 @@ func formatNano(b []byte, nanosec uint, n int, trim bool) []byte {
                        return b
                }
        }
-       b = append(b, '.')
+       b = append(b, separator)
        return append(b, buf[:n]...)
 }
 
@@ -479,7 +507,7 @@ func (t Time) String() string {
                }
                m1, m2 := m2/1e9, m2%1e9
                m0, m1 := m1/1e9, m1%1e9
-               var buf []byte
+               buf := make([]byte, 0, 24)
                buf = append(buf, " m="...)
                buf = append(buf, sign)
                wid := 0
@@ -498,7 +526,8 @@ func (t Time) String() string {
 // GoString implements fmt.GoStringer and formats t to be printed in Go source
 // code.
 func (t Time) GoString() string {
-       buf := []byte("time.Date(")
+       buf := make([]byte, 0, 70)
+       buf = append(buf, "time.Date("...)
        buf = appendInt(buf, t.Year(), 0)
        month := t.Month()
        if January <= month && month <= December {
@@ -732,7 +761,7 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
                        b = appendInt(b, zone/60, 2)
                        b = appendInt(b, zone%60, 2)
                case stdFracSecond0, stdFracSecond9:
-                       b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9)
+                       b = formatNano(b, uint(t.Nanosecond()), std)
                }
        }
        return b
@@ -1164,7 +1193,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
                case stdFracSecond0:
                        // stdFracSecond0 requires the exact number of digits as specified in
                        // the layout.
-                       ndigit := 1 + (std >> stdArgShift)
+                       ndigit := 1 + digitsLen(std)
                        if len(value) < ndigit {
                                err = errBad
                                break
@@ -1373,10 +1402,7 @@ func parseSignedOffset(value string) int {
        if err != nil || value[1:] == rem {
                return 0
        }
-       if sign == '-' {
-               x = -x
-       }
-       if x < -23 || 23 < x {
+       if x > 23 {
                return 0
        }
        return len(value) - len(rem)
@@ -1391,16 +1417,19 @@ func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string,
                err = errBad
                return
        }
+       if nbytes > 10 {
+               value = value[:10]
+               nbytes = 10
+       }
        if ns, err = atoi(value[1:nbytes]); err != nil {
                return
        }
-       if ns < 0 || 1e9 <= ns {
+       if ns < 0 {
                rangeErrString = "fractional second"
                return
        }
        // We need nanoseconds, which means scaling by the number
-       // of missing digits in the format, maximum length 10. If it's
-       // longer than 10, we won't scale.
+       // of missing digits in the format, maximum length 10.
        scaleDigits := 10 - nbytes
        for i := 0; i < scaleDigits; i++ {
                ns *= 10
@@ -1411,19 +1440,19 @@ func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string,
 var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
 
 // leadingInt consumes the leading [0-9]* from s.
-func leadingInt(s string) (x int64, rem string, err error) {
+func leadingInt(s string) (x uint64, rem string, err error) {
        i := 0
        for ; i < len(s); i++ {
                c := s[i]
                if c < '0' || c > '9' {
                        break
                }
-               if x > (1<<63-1)/10 {
+               if x > 1<<63/10 {
                        // overflow
                        return 0, "", errLeadingInt
                }
-               x = x*10 + int64(c) - '0'
-               if x < 0 {
+               x = x*10 + uint64(c) - '0'
+               if x > 1<<63 {
                        // overflow
                        return 0, "", errLeadingInt
                }
@@ -1434,7 +1463,7 @@ func leadingInt(s string) (x int64, rem string, err error) {
 // leadingFraction consumes the leading [0-9]* from s.
 // It is used only for fractions, so does not return an error on overflow,
 // it just stops accumulating precision.
-func leadingFraction(s string) (x int64, scale float64, rem string) {
+func leadingFraction(s string) (x uint64, scale float64, rem string) {
        i := 0
        scale = 1
        overflow := false
@@ -1451,8 +1480,8 @@ func leadingFraction(s string) (x int64, scale float64, rem string) {
                        overflow = true
                        continue
                }
-               y := x*10 + int64(c) - '0'
-               if y < 0 {
+               y := x*10 + uint64(c) - '0'
+               if y > 1<<63 {
                        overflow = true
                        continue
                }
@@ -1462,15 +1491,15 @@ func leadingFraction(s string) (x int64, scale float64, rem string) {
        return x, scale, s[i:]
 }
 
-var unitMap = map[string]int64{
-       "ns": int64(Nanosecond),
-       "us": int64(Microsecond),
-       "µs": int64(Microsecond), // U+00B5 = micro symbol
-       "μs": int64(Microsecond), // U+03BC = Greek letter mu
-       "ms": int64(Millisecond),
-       "s":  int64(Second),
-       "m":  int64(Minute),
-       "h":  int64(Hour),
+var unitMap = map[string]uint64{
+       "ns": uint64(Nanosecond),
+       "us": uint64(Microsecond),
+       "µs": uint64(Microsecond), // U+00B5 = micro symbol
+       "μs": uint64(Microsecond), // U+03BC = Greek letter mu
+       "ms": uint64(Millisecond),
+       "s":  uint64(Second),
+       "m":  uint64(Minute),
+       "h":  uint64(Hour),
 }
 
 // ParseDuration parses a duration string.
@@ -1481,7 +1510,7 @@ var unitMap = map[string]int64{
 func ParseDuration(s string) (Duration, error) {
        // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
        orig := s
-       var d int64
+       var d uint64
        neg := false
 
        // Consume [-+]?
@@ -1501,7 +1530,7 @@ func ParseDuration(s string) (Duration, error) {
        }
        for s != "" {
                var (
-                       v, f  int64       // integers before, after decimal point
+                       v, f  uint64      // integers before, after decimal point
                        scale float64 = 1 // value = v + f/scale
                )
 
@@ -1549,7 +1578,7 @@ func ParseDuration(s string) (Duration, error) {
                if !ok {
                        return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig))
                }
-               if v > (1<<63-1)/unit {
+               if v > 1<<63/unit {
                        // overflow
                        return 0, errors.New("time: invalid duration " + quote(orig))
                }
@@ -1557,21 +1586,22 @@ func ParseDuration(s string) (Duration, error) {
                if f > 0 {
                        // float64 is needed to be nanosecond accurate for fractions of hours.
                        // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
-                       v += int64(float64(f) * (float64(unit) / scale))
-                       if v < 0 {
+                       v += uint64(float64(f) * (float64(unit) / scale))
+                       if v > 1<<63 {
                                // overflow
                                return 0, errors.New("time: invalid duration " + quote(orig))
                        }
                }
                d += v
-               if d < 0 {
-                       // overflow
+               if d > 1<<63 {
                        return 0, errors.New("time: invalid duration " + quote(orig))
                }
        }
-
        if neg {
-               d = -d
+               return -Duration(d), nil
+       }
+       if d > 1<<63-1 {
+               return 0, errors.New("time: invalid duration " + quote(orig))
        }
        return Duration(d), nil
 }
index 1af41e2dfb315a65e6d154779d3665a4d7fdc268..db95536390040ba692271eef48f0bf5078c57672 100644 (file)
@@ -832,3 +832,64 @@ func TestQuote(t *testing.T) {
        }
 
 }
+
+// Issue 48037
+func TestFormatFractionalSecondSeparators(t *testing.T) {
+       tests := []struct {
+               s, want string
+       }{
+               {`15:04:05.000`, `21:00:57.012`},
+               {`15:04:05.999`, `21:00:57.012`},
+               {`15:04:05,000`, `21:00:57,012`},
+               {`15:04:05,999`, `21:00:57,012`},
+       }
+
+       // The numeric time represents Thu Feb  4 21:00:57.012345600 PST 2009
+       time := Unix(0, 1233810057012345600)
+       for _, tt := range tests {
+               if q := time.Format(tt.s); q != tt.want {
+                       t.Errorf("Format(%q) = got %q, want %q", tt.s, q, tt.want)
+               }
+       }
+}
+
+// Issue 48685
+func TestParseFractionalSecondsLongerThanNineDigits(t *testing.T) {
+       tests := []struct {
+               s    string
+               want int
+       }{
+               // 9 digits
+               {"2021-09-29T16:04:33.000000000Z", 0},
+               {"2021-09-29T16:04:33.000000001Z", 1},
+               {"2021-09-29T16:04:33.100000000Z", 100_000_000},
+               {"2021-09-29T16:04:33.100000001Z", 100_000_001},
+               {"2021-09-29T16:04:33.999999999Z", 999_999_999},
+               {"2021-09-29T16:04:33.012345678Z", 12_345_678},
+               // 10 digits, truncates
+               {"2021-09-29T16:04:33.0000000000Z", 0},
+               {"2021-09-29T16:04:33.0000000001Z", 0},
+               {"2021-09-29T16:04:33.1000000000Z", 100_000_000},
+               {"2021-09-29T16:04:33.1000000009Z", 100_000_000},
+               {"2021-09-29T16:04:33.9999999999Z", 999_999_999},
+               {"2021-09-29T16:04:33.0123456789Z", 12_345_678},
+               // 11 digits, truncates
+               {"2021-09-29T16:04:33.10000000000Z", 100_000_000},
+               {"2021-09-29T16:04:33.00123456789Z", 1_234_567},
+               // 12 digits, truncates
+               {"2021-09-29T16:04:33.000123456789Z", 123_456},
+               // 15 digits, truncates
+               {"2021-09-29T16:04:33.9999999999999999Z", 999_999_999},
+       }
+
+       for _, tt := range tests {
+               tm, err := Parse(RFC3339, tt.s)
+               if err != nil {
+                       t.Errorf("Unexpected error: %v", err)
+                       continue
+               }
+               if got := tm.Nanosecond(); got != tt.want {
+                       t.Errorf("Parse(%q) = got %d, want %d", tt.s, got, tt.want)
+               }
+       }
+}
index 9fd2f2b7626ea68170e1bd0bf16f32c438d79e22..a8651bfdb87b550b5a91b9ad0d964cb28bced5d8 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 //
 // usage:
index 87a4208b058e1bd77e395374e1063e484d02d9a8..2c75e449d31098a22fc02b0ed8035536041e7920 100644 (file)
@@ -12,7 +12,7 @@ func init() {
 func initTestingZone() {
        z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
        if err != nil {
-               panic("cannot load America/Los_Angeles for testing: " + err.Error())
+               panic("cannot load America/Los_Angeles for testing: " + err.Error() + "; you may want to use -tags=timetzdata")
        }
        z.name = "Local"
        localLoc = *z
index 4f4579941469cd978ef39c0b01e0f281e3ed39f3..b467d1d589d1e70fa32914f1f3cce1f8859ae877 100644 (file)
@@ -139,12 +139,8 @@ func (t *Timer) Reset(d Duration) bool {
        return resetTimer(&t.r, w)
 }
 
+// sendTime does a non-blocking send of the current time on c.
 func sendTime(c interface{}, seq uintptr) {
-       // Non-blocking send of time on c.
-       // Used in NewTimer, it cannot block anyway (buffer).
-       // Used in NewTicker, dropping sends on the floor is
-       // the desired behavior when the reader gets behind,
-       // because the sends are periodic.
        select {
        case c.(chan Time) <- Now():
        default:
index e0172bf5e0b7361891b6fcbef8c5db35460af763..c48e704eb7b10cce96a6378a7e30a60f36d31816 100644 (file)
@@ -7,6 +7,7 @@ package time_test
 import (
        "errors"
        "fmt"
+       "math/rand"
        "runtime"
        "strings"
        "sync"
@@ -561,6 +562,72 @@ func TestTimerModifiedEarlier(t *testing.T) {
        }
 }
 
+// Test that rapidly moving timers earlier and later doesn't cause
+// some of the sleep times to be lost.
+// Issue 47762
+func TestAdjustTimers(t *testing.T) {
+       var rnd = rand.New(rand.NewSource(Now().UnixNano()))
+
+       timers := make([]*Timer, 100)
+       states := make([]int, len(timers))
+       indices := rnd.Perm(len(timers))
+
+       for len(indices) != 0 {
+               var ii = rnd.Intn(len(indices))
+               var i = indices[ii]
+
+               var timer = timers[i]
+               var state = states[i]
+               states[i]++
+
+               switch state {
+               case 0:
+                       timers[i] = NewTimer(0)
+               case 1:
+                       <-timer.C // Timer is now idle.
+
+               // Reset to various long durations, which we'll cancel.
+               case 2:
+                       if timer.Reset(1 * Minute) {
+                               panic("shouldn't be active (1)")
+                       }
+               case 4:
+                       if timer.Reset(3 * Minute) {
+                               panic("shouldn't be active (3)")
+                       }
+               case 6:
+                       if timer.Reset(2 * Minute) {
+                               panic("shouldn't be active (2)")
+                       }
+
+               // Stop and drain a long-duration timer.
+               case 3, 5, 7:
+                       if !timer.Stop() {
+                               t.Logf("timer %d state %d Stop returned false", i, state)
+                               <-timer.C
+                       }
+
+               // Start a short-duration timer we expect to select without blocking.
+               case 8:
+                       if timer.Reset(0) {
+                               t.Fatal("timer.Reset returned true")
+                       }
+               case 9:
+                       now := Now()
+                       <-timer.C
+                       dur := Since(now)
+                       if dur > 750*Millisecond {
+                               t.Errorf("timer %d took %v to complete", i, dur)
+                       }
+
+               // Timer is done. Swap with tail and remove.
+               case 10:
+                       indices[ii] = indices[len(indices)-1]
+                       indices = indices[:len(indices)-1]
+               }
+       }
+}
+
 // Benchmark timer latency when the thread that creates the timer is busy with
 // other work and the timers must be serviced by other threads.
 // https://golang.org/issue/38860
index 4dc55e44aa5fb6a92ad1b7b28db4ea27b83d4549..ba37cf54244bee4471d4b04b49d77353df9e871e 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build plan9
-// +build plan9
 
 package time
 
index 60fc090dc967ff2785609295cb2e185924c5b9ba..a949a6af225a407ad7ceacbc4925a6f1f7a29034 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
 
 package time
 
index 81d2a43f2838800bf0b1d8cc456882600fc35de3..f9522b0b754ad6c2566b0e04cb45fd856a7857b5 100644 (file)
@@ -14,9 +14,9 @@ type Ticker struct {
 }
 
 // NewTicker returns a new Ticker containing a channel that will send
-// the time on the channel after each tick. The period of the ticks is
-// specified by the duration argument. The ticker will adjust the time
-// interval or drop ticks to make up for slow receivers.
+// the current time on the channel after each tick. The period of the
+// ticks is specified by the duration argument. The ticker will adjust
+// the time interval or drop ticks to make up for slow receivers.
 // The duration d must be greater than zero; if not, NewTicker will
 // panic. Stop the ticker to release associated resources.
 func NewTicker(d Duration) *Ticker {
index b5d0a189bc84045782f5d190af1b5b5b15a0afca..d8cd59228f0fd47adf01273d384fd48a876f44c4 100644 (file)
@@ -15,10 +15,11 @@ func TestTicker(t *testing.T) {
        // We want to test that a ticker takes as much time as expected.
        // Since we don't want the test to run for too long, we don't
        // want to use lengthy times. This makes the test inherently flaky.
-       // So only report an error if it fails five times in a row.
+       // Start with a short time, but try again with a long one if the
+       // first test fails.
 
-       count := 10
-       delta := 20 * Millisecond
+       baseCount := 10
+       baseDelta := 20 * Millisecond
 
        // On Darwin ARM64 the tick frequency seems limited. Issue 35692.
        if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
@@ -27,8 +28,8 @@ func TestTicker(t *testing.T) {
                // Since tick frequency is limited on Darwin ARM64, use even
                // number to give the ticks more time to let the test pass.
                // See CL 220638.
-               count = 6
-               delta = 100 * Millisecond
+               baseCount = 6
+               baseDelta = 100 * Millisecond
        }
 
        var errs []string
@@ -38,7 +39,17 @@ func TestTicker(t *testing.T) {
                }
        }
 
-       for i := 0; i < 5; i++ {
+       for _, test := range []struct {
+               count int
+               delta Duration
+       }{{
+               count: baseCount,
+               delta: baseDelta,
+       }, {
+               count: 8,
+               delta: 1 * Second,
+       }} {
+               count, delta := test.count, test.delta
                ticker := NewTicker(delta)
                t0 := Now()
                for i := 0; i < count/2; i++ {
index 4ecc3d82dcc95895742e6219c95503c994722c0f..edf0c6261026ddf6e6599b302870a691f694adca 100644 (file)
@@ -425,7 +425,6 @@ const (
        internalToUnix int64 = -unixToInternal
 
        wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay
-       internalToWall int64 = -wallToInternal
 )
 
 // IsZero reports whether t represents the zero time instant,
@@ -1163,19 +1162,26 @@ func (t Time) UnixNano() int64 {
        return (t.unixSec())*1e9 + int64(t.nsec())
 }
 
-const timeBinaryVersion byte = 1
+const (
+       timeBinaryVersionV1 byte = iota + 1 // For general situation
+       timeBinaryVersionV2                 // For LMT only
+)
 
 // MarshalBinary implements the encoding.BinaryMarshaler interface.
 func (t Time) MarshalBinary() ([]byte, error) {
        var offsetMin int16 // minutes east of UTC. -1 is UTC.
+       var offsetSec int8
+       version := timeBinaryVersionV1
 
        if t.Location() == UTC {
                offsetMin = -1
        } else {
                _, offset := t.Zone()
                if offset%60 != 0 {
-                       return nil, errors.New("Time.MarshalBinary: zone offset has fractional minute")
+                       version = timeBinaryVersionV2
+                       offsetSec = int8(offset % 60)
                }
+
                offset /= 60
                if offset < -32768 || offset == -1 || offset > 32767 {
                        return nil, errors.New("Time.MarshalBinary: unexpected zone offset")
@@ -1186,8 +1192,8 @@ func (t Time) MarshalBinary() ([]byte, error) {
        sec := t.sec()
        nsec := t.nsec()
        enc := []byte{
-               timeBinaryVersion, // byte 0 : version
-               byte(sec >> 56),   // bytes 1-8: seconds
+               version,         // byte 0 : version
+               byte(sec >> 56), // bytes 1-8: seconds
                byte(sec >> 48),
                byte(sec >> 40),
                byte(sec >> 32),
@@ -1202,6 +1208,9 @@ func (t Time) MarshalBinary() ([]byte, error) {
                byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes
                byte(offsetMin),
        }
+       if version == timeBinaryVersionV2 {
+               enc = append(enc, byte(offsetSec))
+       }
 
        return enc, nil
 }
@@ -1213,11 +1222,16 @@ func (t *Time) UnmarshalBinary(data []byte) error {
                return errors.New("Time.UnmarshalBinary: no data")
        }
 
-       if buf[0] != timeBinaryVersion {
+       version := buf[0]
+       if version != timeBinaryVersionV1 && version != timeBinaryVersionV2 {
                return errors.New("Time.UnmarshalBinary: unsupported version")
        }
 
-       if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
+       wantLen := /*version*/ 1 + /*sec*/ 8 + /*nsec*/ 4 + /*zone offset*/ 2
+       if version == timeBinaryVersionV2 {
+               wantLen++
+       }
+       if len(buf) != wantLen {
                return errors.New("Time.UnmarshalBinary: invalid length")
        }
 
@@ -1230,6 +1244,9 @@ func (t *Time) UnmarshalBinary(data []byte) error {
 
        buf = buf[4:]
        offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
+       if version == timeBinaryVersionV2 {
+               offset += int(buf[2])
+       }
 
        *t = Time{}
        t.wall = uint64(nsec)
index cea5f2d3f5acebcd18214e0167bf6a2a8de9f5d7..5007b6e723128a0827afb8af853e0a6e9086f10c 100644 (file)
@@ -9,6 +9,7 @@ import (
        "encoding/gob"
        "encoding/json"
        "fmt"
+       "math"
        "math/big"
        "math/rand"
        "os"
@@ -767,7 +768,6 @@ var notEncodableTimes = []struct {
        time Time
        want string
 }{
-       {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 1)), "Time.MarshalBinary: zone offset has fractional minute"},
        {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -1*60)), "Time.MarshalBinary: unexpected zone offset"},
        {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -32769*60)), "Time.MarshalBinary: unexpected zone offset"},
        {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 32768*60)), "Time.MarshalBinary: unexpected zone offset"},
@@ -886,8 +886,13 @@ var parseDurationTests = []struct {
        {"9223372036854775807ns", (1<<63 - 1) * Nanosecond},
        {"9223372036854775.807us", (1<<63 - 1) * Nanosecond},
        {"9223372036s854ms775us807ns", (1<<63 - 1) * Nanosecond},
-       // large negative value
-       {"-9223372036854775807ns", -1<<63 + 1*Nanosecond},
+       {"-9223372036854775808ns", -1 << 63 * Nanosecond},
+       {"-9223372036854775.808us", -1 << 63 * Nanosecond},
+       {"-9223372036s854ms775us808ns", -1 << 63 * Nanosecond},
+       // largest negative value
+       {"-9223372036854775808ns", -1 << 63 * Nanosecond},
+       // largest negative round trip value, see https://golang.org/issue/48629
+       {"-2562047h47m16.854775808s", -1 << 63 * Nanosecond},
        // huge string; issue 15011.
        {"0.100000000000000000000h", 6 * Minute},
        // This value tests the first overflow check in leadingFraction.
@@ -925,9 +930,7 @@ var parseDurationErrorTests = []struct {
        // overflow
        {"9223372036854775810ns", `"9223372036854775810ns"`},
        {"9223372036854775808ns", `"9223372036854775808ns"`},
-       // largest negative value of type int64 in nanoseconds should fail
-       // see https://go-review.googlesource.com/#/c/2461/
-       {"-9223372036854775808ns", `"-9223372036854775808ns"`},
+       {"-9223372036854775809ns", `"-9223372036854775809ns"`},
        {"9223372036854776us", `"9223372036854776us"`},
        {"3000000h", `"3000000h"`},
        {"9223372036854775.808us", `"9223372036854775.808us"`},
@@ -946,6 +949,19 @@ func TestParseDurationErrors(t *testing.T) {
 }
 
 func TestParseDurationRoundTrip(t *testing.T) {
+       // https://golang.org/issue/48629
+       max0 := Duration(math.MaxInt64)
+       max1, err := ParseDuration(max0.String())
+       if err != nil || max0 != max1 {
+               t.Errorf("round-trip failed: %d => %q => %d, %v", max0, max0.String(), max1, err)
+       }
+
+       min0 := Duration(math.MinInt64)
+       min1, err := ParseDuration(min0.String())
+       if err != nil || min0 != min1 {
+               t.Errorf("round-trip failed: %d => %q => %d, %v", min0, min0.String(), min1, err)
+       }
+
        for i := 0; i < 100; i++ {
                // Resolutions finer than milliseconds will result in
                // imprecise round-trips.
@@ -1437,6 +1453,37 @@ func TestMarshalBinaryZeroTime(t *testing.T) {
        }
 }
 
+func TestMarshalBinaryVersion2(t *testing.T) {
+       t0, err := Parse(RFC3339, "1880-01-01T00:00:00Z")
+       if err != nil {
+               t.Errorf("Failed to parse time, error = %v", err)
+       }
+       loc, err := LoadLocation("US/Eastern")
+       if err != nil {
+               t.Errorf("Failed to load location, error = %v", err)
+       }
+       t1 := t0.In(loc)
+       b, err := t1.MarshalBinary()
+       if err != nil {
+               t.Errorf("Failed to Marshal, error = %v", err)
+       }
+
+       t2 := Time{}
+       err = t2.UnmarshalBinary(b)
+       if err != nil {
+               t.Errorf("Failed to Unmarshal, error = %v", err)
+       }
+
+       if !(t0.Equal(t1) && t1.Equal(t2)) {
+               if !t0.Equal(t1) {
+                       t.Errorf("The result t1: %+v after Marshal is not matched original t0: %+v", t1, t0)
+               }
+               if !t1.Equal(t2) {
+                       t.Errorf("The result t2: %+v after Unmarshal is not matched original t1: %+v", t2, t1)
+               }
+       }
+}
+
 // Issue 17720: Zero value of time.Month fails to print
 func TestZeroMonthString(t *testing.T) {
        if got, want := Month(0).String(), "%!Month(0)"; got != want {
index 0869c8458c60ae18edf1f1398534022b28f56ce7..4f40b51c7365e08652e395d4449853a701f2a140 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ignore
-// +build ignore
 
 // This program generates zipdata.go from $GOROOT/lib/time/zoneinfo.zip.
 package main
index 57aed03fec36cc5300913fc5c12b48febb6b4e3f..7b39f869e644fb62d90345d5741c861fa40dcb75 100644 (file)
@@ -631,12 +631,13 @@ var zoneinfoOnce sync.Once
 // Otherwise, the name is taken to be a location name corresponding to a file
 // in the IANA Time Zone database, such as "America/New_York".
 //
-// The time zone database needed by LoadLocation may not be
-// present on all systems, especially non-Unix systems.
-// LoadLocation looks in the directory or uncompressed zip file
-// named by the ZONEINFO environment variable, if any, then looks in
-// known installation locations on Unix systems,
-// and finally looks in $GOROOT/lib/time/zoneinfo.zip.
+// LoadLocation looks for the IANA Time Zone database in the following
+// locations in order:
+//
+// - the directory or uncompressed zip file named by the ZONEINFO environment variable
+// - on a Unix system, the system standard installation location
+// - $GOROOT/lib/time/zoneinfo.zip
+// - the time/tzdata package, if it was imported
 func LoadLocation(name string) (*Location, error) {
        if name == "" || name == "UTC" {
                return UTC, nil
index 044691e13058520fdb290497731aa5db98a95b09..7eccabf24924309dfc053dbbb302bd22e34e8997 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build ios
-// +build ios
 
 package time
 
index 8245614d2e15c158d16a1c805c80409539c5f43a..d0aefb908898f930b5bfe68948fbd03571e502c2 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build js && wasm
-// +build js,wasm
 
 package time
 
index 4ea029dbde97984e4600633f0ce5cb1a6b54d0c1..23f8b3cdb4af2b81852a24168a09f29a10dcb2ff 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || (darwin && !ios) || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || solaris
-// +build aix darwin,!ios dragonfly freebsd linux,!android netbsd openbsd solaris
 
 // Parse "zoneinfo" time zone file.
 // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
index b75b374c3d535123a0ef21e41af50d368d4ce403..de95295cd3f6bdb24ce224a2cb310d0f0e42bddc 100644 (file)
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 //go:build aix || (darwin && !ios) || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || solaris
-// +build aix darwin,!ios dragonfly freebsd linux,!android netbsd openbsd solaris
 
 package time_test
 
index 50c5b18a48e63d8269996a21e810fbface9e6acf..d3a47aca91b7489ff9e27e9ea470dd3d30a356dd 100644 (file)
@@ -194,3 +194,63 @@ func ExampleSpecialCase() {
        // U+0130 'İ'
        // U+0130 'İ'
 }
+
+func ExampleIsDigit() {
+       fmt.Printf("%t\n", unicode.IsDigit('৩'))
+       fmt.Printf("%t\n", unicode.IsDigit('A'))
+       // Output:
+       // true
+       // false
+}
+
+func ExampleIsNumber() {
+       fmt.Printf("%t\n", unicode.IsNumber('Ⅷ'))
+       fmt.Printf("%t\n", unicode.IsNumber('A'))
+       // Output:
+       // true
+       // false
+}
+
+func ExampleIsLetter() {
+       fmt.Printf("%t\n", unicode.IsLetter('A'))
+       fmt.Printf("%t\n", unicode.IsLetter('7'))
+       // Output:
+       // true
+       // false
+}
+
+func ExampleIsLower() {
+       fmt.Printf("%t\n", unicode.IsLower('a'))
+       fmt.Printf("%t\n", unicode.IsLower('A'))
+       // Output:
+       // true
+       // false
+}
+
+func ExampleIsUpper() {
+       fmt.Printf("%t\n", unicode.IsUpper('A'))
+       fmt.Printf("%t\n", unicode.IsUpper('a'))
+       // Output:
+       // true
+       // false
+}
+
+func ExampleIsTitle() {
+       fmt.Printf("%t\n", unicode.IsTitle('Dž'))
+       fmt.Printf("%t\n", unicode.IsTitle('a'))
+       // Output:
+       // true
+       // false
+}
+
+func ExampleIsSpace() {
+       fmt.Printf("%t\n", unicode.IsSpace(' '))
+       fmt.Printf("%t\n", unicode.IsSpace('\n'))
+       fmt.Printf("%t\n", unicode.IsSpace('\t'))
+       fmt.Printf("%t\n", unicode.IsSpace('a'))
+       // Output:
+       // true
+       // true
+       // true
+       // false
+}
index 557e8a7770c7dd9fc70e4e60baf18fd093f19e35..6938c7e6a7742655d8d09bcae767bfd8fb1bf659 100644 (file)
@@ -369,6 +369,32 @@ func EncodeRune(p []byte, r rune) int {
        }
 }
 
+// AppendRune appends the UTF-8 encoding of r to the end of p and
+// returns the extended buffer. If the rune is out of range,
+// it appends the encoding of RuneError.
+func AppendRune(p []byte, r rune) []byte {
+       // This function is inlineable for fast handling of ASCII.
+       if uint32(r) <= rune1Max {
+               return append(p, byte(r))
+       }
+       return appendRuneNonASCII(p, r)
+}
+
+func appendRuneNonASCII(p []byte, r rune) []byte {
+       // Negative values are erroneous. Making it unsigned addresses the problem.
+       switch i := uint32(r); {
+       case i <= rune2Max:
+               return append(p, t2|byte(r>>6), tx|byte(r)&maskx)
+       case i > MaxRune, surrogateMin <= i && i <= surrogateMax:
+               r = RuneError
+               fallthrough
+       case i <= rune3Max:
+               return append(p, t3|byte(r>>12), tx|byte(r>>6)&maskx, tx|byte(r)&maskx)
+       default:
+               return append(p, t4|byte(r>>18), tx|byte(r>>12)&maskx, tx|byte(r>>6)&maskx, tx|byte(r)&maskx)
+       }
+}
+
 // RuneCount returns the number of runes in p. Erroneous and short
 // encodings are treated as single runes of width 1 byte.
 func RuneCount(p []byte) int {
index eaf1b5ffee39e00a464c7ed00cf1b2267dc5ad62..a60040ecfde8db8853d59b62d30375a960b91993 100644 (file)
@@ -127,6 +127,17 @@ func TestEncodeRune(t *testing.T) {
        }
 }
 
+func TestAppendRune(t *testing.T) {
+       for _, m := range utf8map {
+               if buf := AppendRune(nil, m.r); string(buf) != m.str {
+                       t.Errorf("AppendRune(nil, %#04x) = %s, want %s", m.r, buf, m.str)
+               }
+               if buf := AppendRune([]byte("init"), m.r); string(buf) != "init"+m.str {
+                       t.Errorf("AppendRune(nil, %#04x) = %s, want %s", m.r, buf, "init"+m.str)
+               }
+       }
+}
+
 func TestDecodeRune(t *testing.T) {
        for _, m := range utf8map {
                b := []byte(m.str)
@@ -583,6 +594,20 @@ func BenchmarkEncodeJapaneseRune(b *testing.B) {
        }
 }
 
+func BenchmarkAppendASCIIRune(b *testing.B) {
+       buf := make([]byte, UTFMax)
+       for i := 0; i < b.N; i++ {
+               AppendRune(buf[:0], 'a')
+       }
+}
+
+func BenchmarkAppendJapaneseRune(b *testing.B) {
+       buf := make([]byte, UTFMax)
+       for i := 0; i < b.N; i++ {
+               AppendRune(buf[:0], '本')
+       }
+}
+
 func BenchmarkDecodeASCIIRune(b *testing.B) {
        a := []byte{'a'}
        for i := 0; i < b.N; i++ {
index 8fb49a13e3bf23167b8f1e4ff48adbb8fd413fe8..63cae9e6f0b1ba54dfd55721f855350e8e3a48b3 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build go1.11 && gc && !purego
 // +build go1.11,gc,!purego
 
 #include "textflag.h"
index 3dad4b2fa27b6a63f22d5eeccb74866df6d8074f..5c0fed26f85027845e4acaaa7dda6699fa670c25 100644 (file)
@@ -19,6 +19,7 @@
 // The differences in this and the original implementation are
 // due to the calling conventions and initialization of constants.
 
+//go:build gc && !purego
 // +build gc,!purego
 
 #include "textflag.h"
index 818161189bc4b10c7edb4a92d7eb63769d9b0bcc..f3ef5a019d9593e4d70ce876f48f3a74562d245e 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build gc && !purego
 // +build gc,!purego
 
 #include "go_asm.h"
index 55226b0e6c2c59503bf3c0c36cf1f0c59611cbf5..867c181a14c07411be6f31accc1cd85d5fdc615e 100644 (file)
@@ -4,6 +4,7 @@
 
 // This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
 
+//go:build gc && !purego
 // +build gc,!purego
 
 #include "textflag.h"
index 4b9a655d1b56231fdf6f70bbc93dd146277ad3ef..cda3fdd3540dd0363d6e2d1e85a3ad161fb0078f 100644 (file)
@@ -10,6 +10,8 @@ package curve25519 // import "golang.org/x/crypto/curve25519"
 import (
        "crypto/subtle"
        "fmt"
+
+       "golang.org/x/crypto/curve25519/internal/field"
 )
 
 // ScalarMult sets dst to the product scalar * point.
@@ -18,7 +20,55 @@ import (
 // zeroes, irrespective of the scalar. Instead, use the X25519 function, which
 // will return an error.
 func ScalarMult(dst, scalar, point *[32]byte) {
-       scalarMult(dst, scalar, point)
+       var e [32]byte
+
+       copy(e[:], scalar[:])
+       e[0] &= 248
+       e[31] &= 127
+       e[31] |= 64
+
+       var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
+       x1.SetBytes(point[:])
+       x2.One()
+       x3.Set(&x1)
+       z3.One()
+
+       swap := 0
+       for pos := 254; pos >= 0; pos-- {
+               b := e[pos/8] >> uint(pos&7)
+               b &= 1
+               swap ^= int(b)
+               x2.Swap(&x3, swap)
+               z2.Swap(&z3, swap)
+               swap = int(b)
+
+               tmp0.Subtract(&x3, &z3)
+               tmp1.Subtract(&x2, &z2)
+               x2.Add(&x2, &z2)
+               z2.Add(&x3, &z3)
+               z3.Multiply(&tmp0, &x2)
+               z2.Multiply(&z2, &tmp1)
+               tmp0.Square(&tmp1)
+               tmp1.Square(&x2)
+               x3.Add(&z3, &z2)
+               z2.Subtract(&z3, &z2)
+               x2.Multiply(&tmp1, &tmp0)
+               tmp1.Subtract(&tmp1, &tmp0)
+               z2.Square(&z2)
+
+               z3.Mult32(&tmp1, 121666)
+               x3.Square(&x3)
+               tmp0.Add(&tmp0, &z3)
+               z3.Multiply(&x1, &z2)
+               z2.Multiply(&tmp1, &tmp0)
+       }
+
+       x2.Swap(&x3, swap)
+       z2.Swap(&z3, swap)
+
+       z2.Invert(&z2)
+       x2.Multiply(&x2, &z2)
+       copy(dst[:], x2.Bytes())
 }
 
 // ScalarBaseMult sets dst to the product scalar * base where base is the
diff --git a/src/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go b/src/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go
deleted file mode 100644 (file)
index 8485848..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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.
-
-//go:build amd64 && gc && !purego
-// +build amd64,gc,!purego
-
-package curve25519
-
-// These functions are implemented in the .s files. The names of the functions
-// in the rest of the file are also taken from the SUPERCOP sources to help
-// people following along.
-
-//go:noescape
-
-func cswap(inout *[5]uint64, v uint64)
-
-//go:noescape
-
-func ladderstep(inout *[5][5]uint64)
-
-//go:noescape
-
-func freeze(inout *[5]uint64)
-
-//go:noescape
-
-func mul(dest, a, b *[5]uint64)
-
-//go:noescape
-
-func square(out, in *[5]uint64)
-
-// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
-func mladder(xr, zr *[5]uint64, s *[32]byte) {
-       var work [5][5]uint64
-
-       work[0] = *xr
-       setint(&work[1], 1)
-       setint(&work[2], 0)
-       work[3] = *xr
-       setint(&work[4], 1)
-
-       j := uint(6)
-       var prevbit byte
-
-       for i := 31; i >= 0; i-- {
-               for j < 8 {
-                       bit := ((*s)[i] >> j) & 1
-                       swap := bit ^ prevbit
-                       prevbit = bit
-                       cswap(&work[1], uint64(swap))
-                       ladderstep(&work)
-                       j--
-               }
-               j = 7
-       }
-
-       *xr = work[1]
-       *zr = work[2]
-}
-
-func scalarMult(out, in, base *[32]byte) {
-       var e [32]byte
-       copy(e[:], (*in)[:])
-       e[0] &= 248
-       e[31] &= 127
-       e[31] |= 64
-
-       var t, z [5]uint64
-       unpack(&t, base)
-       mladder(&t, &z, &e)
-       invert(&z, &z)
-       mul(&t, &t, &z)
-       pack(out, &t)
-}
-
-func setint(r *[5]uint64, v uint64) {
-       r[0] = v
-       r[1] = 0
-       r[2] = 0
-       r[3] = 0
-       r[4] = 0
-}
-
-// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
-// order.
-func unpack(r *[5]uint64, x *[32]byte) {
-       r[0] = uint64(x[0]) |
-               uint64(x[1])<<8 |
-               uint64(x[2])<<16 |
-               uint64(x[3])<<24 |
-               uint64(x[4])<<32 |
-               uint64(x[5])<<40 |
-               uint64(x[6]&7)<<48
-
-       r[1] = uint64(x[6])>>3 |
-               uint64(x[7])<<5 |
-               uint64(x[8])<<13 |
-               uint64(x[9])<<21 |
-               uint64(x[10])<<29 |
-               uint64(x[11])<<37 |
-               uint64(x[12]&63)<<45
-
-       r[2] = uint64(x[12])>>6 |
-               uint64(x[13])<<2 |
-               uint64(x[14])<<10 |
-               uint64(x[15])<<18 |
-               uint64(x[16])<<26 |
-               uint64(x[17])<<34 |
-               uint64(x[18])<<42 |
-               uint64(x[19]&1)<<50
-
-       r[3] = uint64(x[19])>>1 |
-               uint64(x[20])<<7 |
-               uint64(x[21])<<15 |
-               uint64(x[22])<<23 |
-               uint64(x[23])<<31 |
-               uint64(x[24])<<39 |
-               uint64(x[25]&15)<<47
-
-       r[4] = uint64(x[25])>>4 |
-               uint64(x[26])<<4 |
-               uint64(x[27])<<12 |
-               uint64(x[28])<<20 |
-               uint64(x[29])<<28 |
-               uint64(x[30])<<36 |
-               uint64(x[31]&127)<<44
-}
-
-// pack sets out = x where out is the usual, little-endian form of the 5,
-// 51-bit limbs in x.
-func pack(out *[32]byte, x *[5]uint64) {
-       t := *x
-       freeze(&t)
-
-       out[0] = byte(t[0])
-       out[1] = byte(t[0] >> 8)
-       out[2] = byte(t[0] >> 16)
-       out[3] = byte(t[0] >> 24)
-       out[4] = byte(t[0] >> 32)
-       out[5] = byte(t[0] >> 40)
-       out[6] = byte(t[0] >> 48)
-
-       out[6] ^= byte(t[1]<<3) & 0xf8
-       out[7] = byte(t[1] >> 5)
-       out[8] = byte(t[1] >> 13)
-       out[9] = byte(t[1] >> 21)
-       out[10] = byte(t[1] >> 29)
-       out[11] = byte(t[1] >> 37)
-       out[12] = byte(t[1] >> 45)
-
-       out[12] ^= byte(t[2]<<6) & 0xc0
-       out[13] = byte(t[2] >> 2)
-       out[14] = byte(t[2] >> 10)
-       out[15] = byte(t[2] >> 18)
-       out[16] = byte(t[2] >> 26)
-       out[17] = byte(t[2] >> 34)
-       out[18] = byte(t[2] >> 42)
-       out[19] = byte(t[2] >> 50)
-
-       out[19] ^= byte(t[3]<<1) & 0xfe
-       out[20] = byte(t[3] >> 7)
-       out[21] = byte(t[3] >> 15)
-       out[22] = byte(t[3] >> 23)
-       out[23] = byte(t[3] >> 31)
-       out[24] = byte(t[3] >> 39)
-       out[25] = byte(t[3] >> 47)
-
-       out[25] ^= byte(t[4]<<4) & 0xf0
-       out[26] = byte(t[4] >> 4)
-       out[27] = byte(t[4] >> 12)
-       out[28] = byte(t[4] >> 20)
-       out[29] = byte(t[4] >> 28)
-       out[30] = byte(t[4] >> 36)
-       out[31] = byte(t[4] >> 44)
-}
-
-// invert calculates r = x^-1 mod p using Fermat's little theorem.
-func invert(r *[5]uint64, x *[5]uint64) {
-       var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
-
-       square(&z2, x)        /* 2 */
-       square(&t, &z2)       /* 4 */
-       square(&t, &t)        /* 8 */
-       mul(&z9, &t, x)       /* 9 */
-       mul(&z11, &z9, &z2)   /* 11 */
-       square(&t, &z11)      /* 22 */
-       mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
-
-       square(&t, &z2_5_0)      /* 2^6 - 2^1 */
-       for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
-               square(&t, &t)
-       }
-       mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
-
-       square(&t, &z2_10_0)      /* 2^11 - 2^1 */
-       for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
-               square(&t, &t)
-       }
-       mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
-
-       square(&t, &z2_20_0)      /* 2^21 - 2^1 */
-       for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
-               square(&t, &t)
-       }
-       mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
-
-       square(&t, &t)            /* 2^41 - 2^1 */
-       for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
-               square(&t, &t)
-       }
-       mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
-
-       square(&t, &z2_50_0)      /* 2^51 - 2^1 */
-       for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
-               square(&t, &t)
-       }
-       mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
-
-       square(&t, &z2_100_0)      /* 2^101 - 2^1 */
-       for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
-               square(&t, &t)
-       }
-       mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
-
-       square(&t, &t)            /* 2^201 - 2^1 */
-       for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
-               square(&t, &t)
-       }
-       mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
-
-       square(&t, &t) /* 2^251 - 2^1 */
-       square(&t, &t) /* 2^252 - 2^2 */
-       square(&t, &t) /* 2^253 - 2^3 */
-
-       square(&t, &t) /* 2^254 - 2^4 */
-
-       square(&t, &t)   /* 2^255 - 2^5 */
-       mul(r, &t, &z11) /* 2^255 - 21 */
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s b/src/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s
deleted file mode 100644 (file)
index 6c53380..0000000
+++ /dev/null
@@ -1,1793 +0,0 @@
-// 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.
-
-// This code was translated into a form compatible with 6a from the public
-// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
-
-// +build amd64,gc,!purego
-
-#define REDMASK51     0x0007FFFFFFFFFFFF
-
-// These constants cannot be encoded in non-MOVQ immediates.
-// We access them directly from memory instead.
-
-DATA ·_121666_213(SB)/8, $996687872
-GLOBL ·_121666_213(SB), 8, $8
-
-DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
-GLOBL ·_2P0(SB), 8, $8
-
-DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
-GLOBL ·_2P1234(SB), 8, $8
-
-// func freeze(inout *[5]uint64)
-TEXT ·freeze(SB),7,$0-8
-       MOVQ inout+0(FP), DI
-
-       MOVQ 0(DI),SI
-       MOVQ 8(DI),DX
-       MOVQ 16(DI),CX
-       MOVQ 24(DI),R8
-       MOVQ 32(DI),R9
-       MOVQ $REDMASK51,AX
-       MOVQ AX,R10
-       SUBQ $18,R10
-       MOVQ $3,R11
-REDUCELOOP:
-       MOVQ SI,R12
-       SHRQ $51,R12
-       ANDQ AX,SI
-       ADDQ R12,DX
-       MOVQ DX,R12
-       SHRQ $51,R12
-       ANDQ AX,DX
-       ADDQ R12,CX
-       MOVQ CX,R12
-       SHRQ $51,R12
-       ANDQ AX,CX
-       ADDQ R12,R8
-       MOVQ R8,R12
-       SHRQ $51,R12
-       ANDQ AX,R8
-       ADDQ R12,R9
-       MOVQ R9,R12
-       SHRQ $51,R12
-       ANDQ AX,R9
-       IMUL3Q $19,R12,R12
-       ADDQ R12,SI
-       SUBQ $1,R11
-       JA REDUCELOOP
-       MOVQ $1,R12
-       CMPQ R10,SI
-       CMOVQLT R11,R12
-       CMPQ AX,DX
-       CMOVQNE R11,R12
-       CMPQ AX,CX
-       CMOVQNE R11,R12
-       CMPQ AX,R8
-       CMOVQNE R11,R12
-       CMPQ AX,R9
-       CMOVQNE R11,R12
-       NEGQ R12
-       ANDQ R12,AX
-       ANDQ R12,R10
-       SUBQ R10,SI
-       SUBQ AX,DX
-       SUBQ AX,CX
-       SUBQ AX,R8
-       SUBQ AX,R9
-       MOVQ SI,0(DI)
-       MOVQ DX,8(DI)
-       MOVQ CX,16(DI)
-       MOVQ R8,24(DI)
-       MOVQ R9,32(DI)
-       RET
-
-// func ladderstep(inout *[5][5]uint64)
-TEXT ·ladderstep(SB),0,$296-8
-       MOVQ inout+0(FP),DI
-
-       MOVQ 40(DI),SI
-       MOVQ 48(DI),DX
-       MOVQ 56(DI),CX
-       MOVQ 64(DI),R8
-       MOVQ 72(DI),R9
-       MOVQ SI,AX
-       MOVQ DX,R10
-       MOVQ CX,R11
-       MOVQ R8,R12
-       MOVQ R9,R13
-       ADDQ ·_2P0(SB),AX
-       ADDQ ·_2P1234(SB),R10
-       ADDQ ·_2P1234(SB),R11
-       ADDQ ·_2P1234(SB),R12
-       ADDQ ·_2P1234(SB),R13
-       ADDQ 80(DI),SI
-       ADDQ 88(DI),DX
-       ADDQ 96(DI),CX
-       ADDQ 104(DI),R8
-       ADDQ 112(DI),R9
-       SUBQ 80(DI),AX
-       SUBQ 88(DI),R10
-       SUBQ 96(DI),R11
-       SUBQ 104(DI),R12
-       SUBQ 112(DI),R13
-       MOVQ SI,0(SP)
-       MOVQ DX,8(SP)
-       MOVQ CX,16(SP)
-       MOVQ R8,24(SP)
-       MOVQ R9,32(SP)
-       MOVQ AX,40(SP)
-       MOVQ R10,48(SP)
-       MOVQ R11,56(SP)
-       MOVQ R12,64(SP)
-       MOVQ R13,72(SP)
-       MOVQ 40(SP),AX
-       MULQ 40(SP)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 40(SP),AX
-       SHLQ $1,AX
-       MULQ 48(SP)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 40(SP),AX
-       SHLQ $1,AX
-       MULQ 56(SP)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 40(SP),AX
-       SHLQ $1,AX
-       MULQ 64(SP)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 40(SP),AX
-       SHLQ $1,AX
-       MULQ 72(SP)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 48(SP),AX
-       MULQ 48(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 48(SP),AX
-       SHLQ $1,AX
-       MULQ 56(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 48(SP),AX
-       SHLQ $1,AX
-       MULQ 64(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 48(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 72(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 56(SP),AX
-       MULQ 56(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 56(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 64(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 56(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 72(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 64(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 64(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 64(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 72(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 72(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 72(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       ANDQ DX,SI
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ADDQ R10,CX
-       ANDQ DX,R8
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ADDQ R12,CX
-       ANDQ DX,R9
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ADDQ R14,CX
-       ANDQ DX,AX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,80(SP)
-       MOVQ R8,88(SP)
-       MOVQ R9,96(SP)
-       MOVQ AX,104(SP)
-       MOVQ R10,112(SP)
-       MOVQ 0(SP),AX
-       MULQ 0(SP)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 0(SP),AX
-       SHLQ $1,AX
-       MULQ 8(SP)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 0(SP),AX
-       SHLQ $1,AX
-       MULQ 16(SP)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 0(SP),AX
-       SHLQ $1,AX
-       MULQ 24(SP)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 0(SP),AX
-       SHLQ $1,AX
-       MULQ 32(SP)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 8(SP),AX
-       MULQ 8(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 8(SP),AX
-       SHLQ $1,AX
-       MULQ 16(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 8(SP),AX
-       SHLQ $1,AX
-       MULQ 24(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 8(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 32(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 16(SP),AX
-       MULQ 16(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 16(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 24(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 16(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 32(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 24(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 24(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 24(SP),DX
-       IMUL3Q $38,DX,AX
-       MULQ 32(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 32(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       ANDQ DX,SI
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ADDQ R10,CX
-       ANDQ DX,R8
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ADDQ R12,CX
-       ANDQ DX,R9
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ADDQ R14,CX
-       ANDQ DX,AX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,120(SP)
-       MOVQ R8,128(SP)
-       MOVQ R9,136(SP)
-       MOVQ AX,144(SP)
-       MOVQ R10,152(SP)
-       MOVQ SI,SI
-       MOVQ R8,DX
-       MOVQ R9,CX
-       MOVQ AX,R8
-       MOVQ R10,R9
-       ADDQ ·_2P0(SB),SI
-       ADDQ ·_2P1234(SB),DX
-       ADDQ ·_2P1234(SB),CX
-       ADDQ ·_2P1234(SB),R8
-       ADDQ ·_2P1234(SB),R9
-       SUBQ 80(SP),SI
-       SUBQ 88(SP),DX
-       SUBQ 96(SP),CX
-       SUBQ 104(SP),R8
-       SUBQ 112(SP),R9
-       MOVQ SI,160(SP)
-       MOVQ DX,168(SP)
-       MOVQ CX,176(SP)
-       MOVQ R8,184(SP)
-       MOVQ R9,192(SP)
-       MOVQ 120(DI),SI
-       MOVQ 128(DI),DX
-       MOVQ 136(DI),CX
-       MOVQ 144(DI),R8
-       MOVQ 152(DI),R9
-       MOVQ SI,AX
-       MOVQ DX,R10
-       MOVQ CX,R11
-       MOVQ R8,R12
-       MOVQ R9,R13
-       ADDQ ·_2P0(SB),AX
-       ADDQ ·_2P1234(SB),R10
-       ADDQ ·_2P1234(SB),R11
-       ADDQ ·_2P1234(SB),R12
-       ADDQ ·_2P1234(SB),R13
-       ADDQ 160(DI),SI
-       ADDQ 168(DI),DX
-       ADDQ 176(DI),CX
-       ADDQ 184(DI),R8
-       ADDQ 192(DI),R9
-       SUBQ 160(DI),AX
-       SUBQ 168(DI),R10
-       SUBQ 176(DI),R11
-       SUBQ 184(DI),R12
-       SUBQ 192(DI),R13
-       MOVQ SI,200(SP)
-       MOVQ DX,208(SP)
-       MOVQ CX,216(SP)
-       MOVQ R8,224(SP)
-       MOVQ R9,232(SP)
-       MOVQ AX,240(SP)
-       MOVQ R10,248(SP)
-       MOVQ R11,256(SP)
-       MOVQ R12,264(SP)
-       MOVQ R13,272(SP)
-       MOVQ 224(SP),SI
-       IMUL3Q $19,SI,AX
-       MOVQ AX,280(SP)
-       MULQ 56(SP)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 232(SP),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,288(SP)
-       MULQ 48(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 200(SP),AX
-       MULQ 40(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 200(SP),AX
-       MULQ 48(SP)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 200(SP),AX
-       MULQ 56(SP)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 200(SP),AX
-       MULQ 64(SP)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 200(SP),AX
-       MULQ 72(SP)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 208(SP),AX
-       MULQ 40(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 208(SP),AX
-       MULQ 48(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 208(SP),AX
-       MULQ 56(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 208(SP),AX
-       MULQ 64(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 208(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 72(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 216(SP),AX
-       MULQ 40(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 216(SP),AX
-       MULQ 48(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 216(SP),AX
-       MULQ 56(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 216(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 64(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 216(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 72(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 224(SP),AX
-       MULQ 40(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 224(SP),AX
-       MULQ 48(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 280(SP),AX
-       MULQ 64(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 280(SP),AX
-       MULQ 72(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 232(SP),AX
-       MULQ 40(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 288(SP),AX
-       MULQ 56(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 288(SP),AX
-       MULQ 64(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 288(SP),AX
-       MULQ 72(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ANDQ DX,SI
-       ADDQ R10,CX
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ANDQ DX,R8
-       ADDQ R12,CX
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ANDQ DX,R9
-       ADDQ R14,CX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       ANDQ DX,AX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,40(SP)
-       MOVQ R8,48(SP)
-       MOVQ R9,56(SP)
-       MOVQ AX,64(SP)
-       MOVQ R10,72(SP)
-       MOVQ 264(SP),SI
-       IMUL3Q $19,SI,AX
-       MOVQ AX,200(SP)
-       MULQ 16(SP)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 272(SP),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,208(SP)
-       MULQ 8(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 240(SP),AX
-       MULQ 0(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 240(SP),AX
-       MULQ 8(SP)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 240(SP),AX
-       MULQ 16(SP)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 240(SP),AX
-       MULQ 24(SP)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 240(SP),AX
-       MULQ 32(SP)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 248(SP),AX
-       MULQ 0(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 248(SP),AX
-       MULQ 8(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 248(SP),AX
-       MULQ 16(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 248(SP),AX
-       MULQ 24(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 248(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 256(SP),AX
-       MULQ 0(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 256(SP),AX
-       MULQ 8(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 256(SP),AX
-       MULQ 16(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 256(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 24(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 256(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 264(SP),AX
-       MULQ 0(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 264(SP),AX
-       MULQ 8(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 200(SP),AX
-       MULQ 24(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 200(SP),AX
-       MULQ 32(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 272(SP),AX
-       MULQ 0(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 208(SP),AX
-       MULQ 16(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 208(SP),AX
-       MULQ 24(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 208(SP),AX
-       MULQ 32(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ANDQ DX,SI
-       ADDQ R10,CX
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ANDQ DX,R8
-       ADDQ R12,CX
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ANDQ DX,R9
-       ADDQ R14,CX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       ANDQ DX,AX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,DX
-       MOVQ R8,CX
-       MOVQ R9,R11
-       MOVQ AX,R12
-       MOVQ R10,R13
-       ADDQ ·_2P0(SB),DX
-       ADDQ ·_2P1234(SB),CX
-       ADDQ ·_2P1234(SB),R11
-       ADDQ ·_2P1234(SB),R12
-       ADDQ ·_2P1234(SB),R13
-       ADDQ 40(SP),SI
-       ADDQ 48(SP),R8
-       ADDQ 56(SP),R9
-       ADDQ 64(SP),AX
-       ADDQ 72(SP),R10
-       SUBQ 40(SP),DX
-       SUBQ 48(SP),CX
-       SUBQ 56(SP),R11
-       SUBQ 64(SP),R12
-       SUBQ 72(SP),R13
-       MOVQ SI,120(DI)
-       MOVQ R8,128(DI)
-       MOVQ R9,136(DI)
-       MOVQ AX,144(DI)
-       MOVQ R10,152(DI)
-       MOVQ DX,160(DI)
-       MOVQ CX,168(DI)
-       MOVQ R11,176(DI)
-       MOVQ R12,184(DI)
-       MOVQ R13,192(DI)
-       MOVQ 120(DI),AX
-       MULQ 120(DI)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 120(DI),AX
-       SHLQ $1,AX
-       MULQ 128(DI)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 120(DI),AX
-       SHLQ $1,AX
-       MULQ 136(DI)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 120(DI),AX
-       SHLQ $1,AX
-       MULQ 144(DI)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 120(DI),AX
-       SHLQ $1,AX
-       MULQ 152(DI)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 128(DI),AX
-       MULQ 128(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 128(DI),AX
-       SHLQ $1,AX
-       MULQ 136(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 128(DI),AX
-       SHLQ $1,AX
-       MULQ 144(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 128(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 152(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 136(DI),AX
-       MULQ 136(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 136(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 144(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 136(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 152(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 144(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 144(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 144(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 152(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 152(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 152(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       ANDQ DX,SI
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ADDQ R10,CX
-       ANDQ DX,R8
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ADDQ R12,CX
-       ANDQ DX,R9
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ADDQ R14,CX
-       ANDQ DX,AX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,120(DI)
-       MOVQ R8,128(DI)
-       MOVQ R9,136(DI)
-       MOVQ AX,144(DI)
-       MOVQ R10,152(DI)
-       MOVQ 160(DI),AX
-       MULQ 160(DI)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 160(DI),AX
-       SHLQ $1,AX
-       MULQ 168(DI)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 160(DI),AX
-       SHLQ $1,AX
-       MULQ 176(DI)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 160(DI),AX
-       SHLQ $1,AX
-       MULQ 184(DI)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 160(DI),AX
-       SHLQ $1,AX
-       MULQ 192(DI)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 168(DI),AX
-       MULQ 168(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 168(DI),AX
-       SHLQ $1,AX
-       MULQ 176(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 168(DI),AX
-       SHLQ $1,AX
-       MULQ 184(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 168(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 192(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 176(DI),AX
-       MULQ 176(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 176(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 184(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 176(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 192(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 184(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 184(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 184(DI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 192(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 192(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 192(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       ANDQ DX,SI
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ADDQ R10,CX
-       ANDQ DX,R8
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ADDQ R12,CX
-       ANDQ DX,R9
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ADDQ R14,CX
-       ANDQ DX,AX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,160(DI)
-       MOVQ R8,168(DI)
-       MOVQ R9,176(DI)
-       MOVQ AX,184(DI)
-       MOVQ R10,192(DI)
-       MOVQ 184(DI),SI
-       IMUL3Q $19,SI,AX
-       MOVQ AX,0(SP)
-       MULQ 16(DI)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 192(DI),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,8(SP)
-       MULQ 8(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 160(DI),AX
-       MULQ 0(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 160(DI),AX
-       MULQ 8(DI)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 160(DI),AX
-       MULQ 16(DI)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 160(DI),AX
-       MULQ 24(DI)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 160(DI),AX
-       MULQ 32(DI)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 168(DI),AX
-       MULQ 0(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 168(DI),AX
-       MULQ 8(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 168(DI),AX
-       MULQ 16(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 168(DI),AX
-       MULQ 24(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 168(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 176(DI),AX
-       MULQ 0(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 176(DI),AX
-       MULQ 8(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 176(DI),AX
-       MULQ 16(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 176(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 24(DI)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 176(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 184(DI),AX
-       MULQ 0(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 184(DI),AX
-       MULQ 8(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 0(SP),AX
-       MULQ 24(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 0(SP),AX
-       MULQ 32(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 192(DI),AX
-       MULQ 0(DI)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 8(SP),AX
-       MULQ 16(DI)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 8(SP),AX
-       MULQ 24(DI)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 8(SP),AX
-       MULQ 32(DI)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ANDQ DX,SI
-       ADDQ R10,CX
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ANDQ DX,R8
-       ADDQ R12,CX
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ANDQ DX,R9
-       ADDQ R14,CX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       ANDQ DX,AX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,160(DI)
-       MOVQ R8,168(DI)
-       MOVQ R9,176(DI)
-       MOVQ AX,184(DI)
-       MOVQ R10,192(DI)
-       MOVQ 144(SP),SI
-       IMUL3Q $19,SI,AX
-       MOVQ AX,0(SP)
-       MULQ 96(SP)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 152(SP),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,8(SP)
-       MULQ 88(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 120(SP),AX
-       MULQ 80(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 120(SP),AX
-       MULQ 88(SP)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 120(SP),AX
-       MULQ 96(SP)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 120(SP),AX
-       MULQ 104(SP)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 120(SP),AX
-       MULQ 112(SP)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 128(SP),AX
-       MULQ 80(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 128(SP),AX
-       MULQ 88(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 128(SP),AX
-       MULQ 96(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 128(SP),AX
-       MULQ 104(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 128(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 112(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 136(SP),AX
-       MULQ 80(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 136(SP),AX
-       MULQ 88(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 136(SP),AX
-       MULQ 96(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 136(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 104(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 136(SP),DX
-       IMUL3Q $19,DX,AX
-       MULQ 112(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 144(SP),AX
-       MULQ 80(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 144(SP),AX
-       MULQ 88(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 0(SP),AX
-       MULQ 104(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 0(SP),AX
-       MULQ 112(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 152(SP),AX
-       MULQ 80(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 8(SP),AX
-       MULQ 96(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 8(SP),AX
-       MULQ 104(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 8(SP),AX
-       MULQ 112(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ANDQ DX,SI
-       ADDQ R10,CX
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ANDQ DX,R8
-       ADDQ R12,CX
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ANDQ DX,R9
-       ADDQ R14,CX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       ANDQ DX,AX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,40(DI)
-       MOVQ R8,48(DI)
-       MOVQ R9,56(DI)
-       MOVQ AX,64(DI)
-       MOVQ R10,72(DI)
-       MOVQ 160(SP),AX
-       MULQ ·_121666_213(SB)
-       SHRQ $13,AX
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 168(SP),AX
-       MULQ ·_121666_213(SB)
-       SHRQ $13,AX
-       ADDQ AX,CX
-       MOVQ DX,R8
-       MOVQ 176(SP),AX
-       MULQ ·_121666_213(SB)
-       SHRQ $13,AX
-       ADDQ AX,R8
-       MOVQ DX,R9
-       MOVQ 184(SP),AX
-       MULQ ·_121666_213(SB)
-       SHRQ $13,AX
-       ADDQ AX,R9
-       MOVQ DX,R10
-       MOVQ 192(SP),AX
-       MULQ ·_121666_213(SB)
-       SHRQ $13,AX
-       ADDQ AX,R10
-       IMUL3Q $19,DX,DX
-       ADDQ DX,SI
-       ADDQ 80(SP),SI
-       ADDQ 88(SP),CX
-       ADDQ 96(SP),R8
-       ADDQ 104(SP),R9
-       ADDQ 112(SP),R10
-       MOVQ SI,80(DI)
-       MOVQ CX,88(DI)
-       MOVQ R8,96(DI)
-       MOVQ R9,104(DI)
-       MOVQ R10,112(DI)
-       MOVQ 104(DI),SI
-       IMUL3Q $19,SI,AX
-       MOVQ AX,0(SP)
-       MULQ 176(SP)
-       MOVQ AX,SI
-       MOVQ DX,CX
-       MOVQ 112(DI),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,8(SP)
-       MULQ 168(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 80(DI),AX
-       MULQ 160(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 80(DI),AX
-       MULQ 168(SP)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 80(DI),AX
-       MULQ 176(SP)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 80(DI),AX
-       MULQ 184(SP)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 80(DI),AX
-       MULQ 192(SP)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 88(DI),AX
-       MULQ 160(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 88(DI),AX
-       MULQ 168(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 88(DI),AX
-       MULQ 176(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 88(DI),AX
-       MULQ 184(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 88(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 192(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 96(DI),AX
-       MULQ 160(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 96(DI),AX
-       MULQ 168(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 96(DI),AX
-       MULQ 176(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 96(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 184(SP)
-       ADDQ AX,SI
-       ADCQ DX,CX
-       MOVQ 96(DI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 192(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 104(DI),AX
-       MULQ 160(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 104(DI),AX
-       MULQ 168(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 0(SP),AX
-       MULQ 184(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 0(SP),AX
-       MULQ 192(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 112(DI),AX
-       MULQ 160(SP)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 8(SP),AX
-       MULQ 176(SP)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 8(SP),AX
-       MULQ 184(SP)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 8(SP),AX
-       MULQ 192(SP)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ $REDMASK51,DX
-       SHLQ $13,SI,CX
-       ANDQ DX,SI
-       SHLQ $13,R8,R9
-       ANDQ DX,R8
-       ADDQ CX,R8
-       SHLQ $13,R10,R11
-       ANDQ DX,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ DX,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ DX,R14
-       ADDQ R13,R14
-       IMUL3Q $19,R15,CX
-       ADDQ CX,SI
-       MOVQ SI,CX
-       SHRQ $51,CX
-       ADDQ R8,CX
-       MOVQ CX,R8
-       SHRQ $51,CX
-       ANDQ DX,SI
-       ADDQ R10,CX
-       MOVQ CX,R9
-       SHRQ $51,CX
-       ANDQ DX,R8
-       ADDQ R12,CX
-       MOVQ CX,AX
-       SHRQ $51,CX
-       ANDQ DX,R9
-       ADDQ R14,CX
-       MOVQ CX,R10
-       SHRQ $51,CX
-       ANDQ DX,AX
-       IMUL3Q $19,CX,CX
-       ADDQ CX,SI
-       ANDQ DX,R10
-       MOVQ SI,80(DI)
-       MOVQ R8,88(DI)
-       MOVQ R9,96(DI)
-       MOVQ AX,104(DI)
-       MOVQ R10,112(DI)
-       RET
-
-// func cswap(inout *[4][5]uint64, v uint64)
-TEXT ·cswap(SB),7,$0
-       MOVQ inout+0(FP),DI
-       MOVQ v+8(FP),SI
-
-       SUBQ $1, SI
-       NOTQ SI
-       MOVQ SI, X15
-       PSHUFD $0x44, X15, X15
-
-       MOVOU 0(DI), X0
-       MOVOU 16(DI), X2
-       MOVOU 32(DI), X4
-       MOVOU 48(DI), X6
-       MOVOU 64(DI), X8
-       MOVOU 80(DI), X1
-       MOVOU 96(DI), X3
-       MOVOU 112(DI), X5
-       MOVOU 128(DI), X7
-       MOVOU 144(DI), X9
-
-       MOVO X1, X10
-       MOVO X3, X11
-       MOVO X5, X12
-       MOVO X7, X13
-       MOVO X9, X14
-
-       PXOR X0, X10
-       PXOR X2, X11
-       PXOR X4, X12
-       PXOR X6, X13
-       PXOR X8, X14
-       PAND X15, X10
-       PAND X15, X11
-       PAND X15, X12
-       PAND X15, X13
-       PAND X15, X14
-       PXOR X10, X0
-       PXOR X10, X1
-       PXOR X11, X2
-       PXOR X11, X3
-       PXOR X12, X4
-       PXOR X12, X5
-       PXOR X13, X6
-       PXOR X13, X7
-       PXOR X14, X8
-       PXOR X14, X9
-
-       MOVOU X0, 0(DI)
-       MOVOU X2, 16(DI)
-       MOVOU X4, 32(DI)
-       MOVOU X6, 48(DI)
-       MOVOU X8, 64(DI)
-       MOVOU X1, 80(DI)
-       MOVOU X3, 96(DI)
-       MOVOU X5, 112(DI)
-       MOVOU X7, 128(DI)
-       MOVOU X9, 144(DI)
-       RET
-
-// func mul(dest, a, b *[5]uint64)
-TEXT ·mul(SB),0,$16-24
-       MOVQ dest+0(FP), DI
-       MOVQ a+8(FP), SI
-       MOVQ b+16(FP), DX
-
-       MOVQ DX,CX
-       MOVQ 24(SI),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,0(SP)
-       MULQ 16(CX)
-       MOVQ AX,R8
-       MOVQ DX,R9
-       MOVQ 32(SI),DX
-       IMUL3Q $19,DX,AX
-       MOVQ AX,8(SP)
-       MULQ 8(CX)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 0(SI),AX
-       MULQ 0(CX)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 0(SI),AX
-       MULQ 8(CX)
-       MOVQ AX,R10
-       MOVQ DX,R11
-       MOVQ 0(SI),AX
-       MULQ 16(CX)
-       MOVQ AX,R12
-       MOVQ DX,R13
-       MOVQ 0(SI),AX
-       MULQ 24(CX)
-       MOVQ AX,R14
-       MOVQ DX,R15
-       MOVQ 0(SI),AX
-       MULQ 32(CX)
-       MOVQ AX,BX
-       MOVQ DX,BP
-       MOVQ 8(SI),AX
-       MULQ 0(CX)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 8(SI),AX
-       MULQ 8(CX)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 8(SI),AX
-       MULQ 16(CX)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 8(SI),AX
-       MULQ 24(CX)
-       ADDQ AX,BX
-       ADCQ DX,BP
-       MOVQ 8(SI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(CX)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 16(SI),AX
-       MULQ 0(CX)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 16(SI),AX
-       MULQ 8(CX)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 16(SI),AX
-       MULQ 16(CX)
-       ADDQ AX,BX
-       ADCQ DX,BP
-       MOVQ 16(SI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 24(CX)
-       ADDQ AX,R8
-       ADCQ DX,R9
-       MOVQ 16(SI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(CX)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 24(SI),AX
-       MULQ 0(CX)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ 24(SI),AX
-       MULQ 8(CX)
-       ADDQ AX,BX
-       ADCQ DX,BP
-       MOVQ 0(SP),AX
-       MULQ 24(CX)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 0(SP),AX
-       MULQ 32(CX)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 32(SI),AX
-       MULQ 0(CX)
-       ADDQ AX,BX
-       ADCQ DX,BP
-       MOVQ 8(SP),AX
-       MULQ 16(CX)
-       ADDQ AX,R10
-       ADCQ DX,R11
-       MOVQ 8(SP),AX
-       MULQ 24(CX)
-       ADDQ AX,R12
-       ADCQ DX,R13
-       MOVQ 8(SP),AX
-       MULQ 32(CX)
-       ADDQ AX,R14
-       ADCQ DX,R15
-       MOVQ $REDMASK51,SI
-       SHLQ $13,R8,R9
-       ANDQ SI,R8
-       SHLQ $13,R10,R11
-       ANDQ SI,R10
-       ADDQ R9,R10
-       SHLQ $13,R12,R13
-       ANDQ SI,R12
-       ADDQ R11,R12
-       SHLQ $13,R14,R15
-       ANDQ SI,R14
-       ADDQ R13,R14
-       SHLQ $13,BX,BP
-       ANDQ SI,BX
-       ADDQ R15,BX
-       IMUL3Q $19,BP,DX
-       ADDQ DX,R8
-       MOVQ R8,DX
-       SHRQ $51,DX
-       ADDQ R10,DX
-       MOVQ DX,CX
-       SHRQ $51,DX
-       ANDQ SI,R8
-       ADDQ R12,DX
-       MOVQ DX,R9
-       SHRQ $51,DX
-       ANDQ SI,CX
-       ADDQ R14,DX
-       MOVQ DX,AX
-       SHRQ $51,DX
-       ANDQ SI,R9
-       ADDQ BX,DX
-       MOVQ DX,R10
-       SHRQ $51,DX
-       ANDQ SI,AX
-       IMUL3Q $19,DX,DX
-       ADDQ DX,R8
-       ANDQ SI,R10
-       MOVQ R8,0(DI)
-       MOVQ CX,8(DI)
-       MOVQ R9,16(DI)
-       MOVQ AX,24(DI)
-       MOVQ R10,32(DI)
-       RET
-
-// func square(out, in *[5]uint64)
-TEXT ·square(SB),7,$0-16
-       MOVQ out+0(FP), DI
-       MOVQ in+8(FP), SI
-
-       MOVQ 0(SI),AX
-       MULQ 0(SI)
-       MOVQ AX,CX
-       MOVQ DX,R8
-       MOVQ 0(SI),AX
-       SHLQ $1,AX
-       MULQ 8(SI)
-       MOVQ AX,R9
-       MOVQ DX,R10
-       MOVQ 0(SI),AX
-       SHLQ $1,AX
-       MULQ 16(SI)
-       MOVQ AX,R11
-       MOVQ DX,R12
-       MOVQ 0(SI),AX
-       SHLQ $1,AX
-       MULQ 24(SI)
-       MOVQ AX,R13
-       MOVQ DX,R14
-       MOVQ 0(SI),AX
-       SHLQ $1,AX
-       MULQ 32(SI)
-       MOVQ AX,R15
-       MOVQ DX,BX
-       MOVQ 8(SI),AX
-       MULQ 8(SI)
-       ADDQ AX,R11
-       ADCQ DX,R12
-       MOVQ 8(SI),AX
-       SHLQ $1,AX
-       MULQ 16(SI)
-       ADDQ AX,R13
-       ADCQ DX,R14
-       MOVQ 8(SI),AX
-       SHLQ $1,AX
-       MULQ 24(SI)
-       ADDQ AX,R15
-       ADCQ DX,BX
-       MOVQ 8(SI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 32(SI)
-       ADDQ AX,CX
-       ADCQ DX,R8
-       MOVQ 16(SI),AX
-       MULQ 16(SI)
-       ADDQ AX,R15
-       ADCQ DX,BX
-       MOVQ 16(SI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 24(SI)
-       ADDQ AX,CX
-       ADCQ DX,R8
-       MOVQ 16(SI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 32(SI)
-       ADDQ AX,R9
-       ADCQ DX,R10
-       MOVQ 24(SI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 24(SI)
-       ADDQ AX,R9
-       ADCQ DX,R10
-       MOVQ 24(SI),DX
-       IMUL3Q $38,DX,AX
-       MULQ 32(SI)
-       ADDQ AX,R11
-       ADCQ DX,R12
-       MOVQ 32(SI),DX
-       IMUL3Q $19,DX,AX
-       MULQ 32(SI)
-       ADDQ AX,R13
-       ADCQ DX,R14
-       MOVQ $REDMASK51,SI
-       SHLQ $13,CX,R8
-       ANDQ SI,CX
-       SHLQ $13,R9,R10
-       ANDQ SI,R9
-       ADDQ R8,R9
-       SHLQ $13,R11,R12
-       ANDQ SI,R11
-       ADDQ R10,R11
-       SHLQ $13,R13,R14
-       ANDQ SI,R13
-       ADDQ R12,R13
-       SHLQ $13,R15,BX
-       ANDQ SI,R15
-       ADDQ R14,R15
-       IMUL3Q $19,BX,DX
-       ADDQ DX,CX
-       MOVQ CX,DX
-       SHRQ $51,DX
-       ADDQ R9,DX
-       ANDQ SI,CX
-       MOVQ DX,R8
-       SHRQ $51,DX
-       ADDQ R11,DX
-       ANDQ SI,R8
-       MOVQ DX,R9
-       SHRQ $51,DX
-       ADDQ R13,DX
-       ANDQ SI,R9
-       MOVQ DX,AX
-       SHRQ $51,DX
-       ADDQ R15,DX
-       ANDQ SI,AX
-       MOVQ DX,R10
-       SHRQ $51,DX
-       IMUL3Q $19,DX,DX
-       ADDQ DX,CX
-       ANDQ SI,R10
-       MOVQ CX,0(DI)
-       MOVQ R8,8(DI)
-       MOVQ R9,16(DI)
-       MOVQ AX,24(DI)
-       MOVQ R10,32(DI)
-       RET
diff --git a/src/vendor/golang.org/x/crypto/curve25519/curve25519_generic.go b/src/vendor/golang.org/x/crypto/curve25519/curve25519_generic.go
deleted file mode 100644 (file)
index c43b13f..0000000
+++ /dev/null
@@ -1,828 +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.
-
-package curve25519
-
-import "encoding/binary"
-
-// This code is a port of the public domain, "ref10" implementation of
-// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
-
-// fieldElement represents an element of the field GF(2^255 - 19). An element
-// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
-// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
-// context.
-type fieldElement [10]int32
-
-func feZero(fe *fieldElement) {
-       for i := range fe {
-               fe[i] = 0
-       }
-}
-
-func feOne(fe *fieldElement) {
-       feZero(fe)
-       fe[0] = 1
-}
-
-func feAdd(dst, a, b *fieldElement) {
-       for i := range dst {
-               dst[i] = a[i] + b[i]
-       }
-}
-
-func feSub(dst, a, b *fieldElement) {
-       for i := range dst {
-               dst[i] = a[i] - b[i]
-       }
-}
-
-func feCopy(dst, src *fieldElement) {
-       for i := range dst {
-               dst[i] = src[i]
-       }
-}
-
-// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
-//
-// Preconditions: b in {0,1}.
-func feCSwap(f, g *fieldElement, b int32) {
-       b = -b
-       for i := range f {
-               t := b & (f[i] ^ g[i])
-               f[i] ^= t
-               g[i] ^= t
-       }
-}
-
-// load3 reads a 24-bit, little-endian value from in.
-func load3(in []byte) int64 {
-       var r int64
-       r = int64(in[0])
-       r |= int64(in[1]) << 8
-       r |= int64(in[2]) << 16
-       return r
-}
-
-// load4 reads a 32-bit, little-endian value from in.
-func load4(in []byte) int64 {
-       return int64(binary.LittleEndian.Uint32(in))
-}
-
-func feFromBytes(dst *fieldElement, src *[32]byte) {
-       h0 := load4(src[:])
-       h1 := load3(src[4:]) << 6
-       h2 := load3(src[7:]) << 5
-       h3 := load3(src[10:]) << 3
-       h4 := load3(src[13:]) << 2
-       h5 := load4(src[16:])
-       h6 := load3(src[20:]) << 7
-       h7 := load3(src[23:]) << 5
-       h8 := load3(src[26:]) << 4
-       h9 := (load3(src[29:]) & 0x7fffff) << 2
-
-       var carry [10]int64
-       carry[9] = (h9 + 1<<24) >> 25
-       h0 += carry[9] * 19
-       h9 -= carry[9] << 25
-       carry[1] = (h1 + 1<<24) >> 25
-       h2 += carry[1]
-       h1 -= carry[1] << 25
-       carry[3] = (h3 + 1<<24) >> 25
-       h4 += carry[3]
-       h3 -= carry[3] << 25
-       carry[5] = (h5 + 1<<24) >> 25
-       h6 += carry[5]
-       h5 -= carry[5] << 25
-       carry[7] = (h7 + 1<<24) >> 25
-       h8 += carry[7]
-       h7 -= carry[7] << 25
-
-       carry[0] = (h0 + 1<<25) >> 26
-       h1 += carry[0]
-       h0 -= carry[0] << 26
-       carry[2] = (h2 + 1<<25) >> 26
-       h3 += carry[2]
-       h2 -= carry[2] << 26
-       carry[4] = (h4 + 1<<25) >> 26
-       h5 += carry[4]
-       h4 -= carry[4] << 26
-       carry[6] = (h6 + 1<<25) >> 26
-       h7 += carry[6]
-       h6 -= carry[6] << 26
-       carry[8] = (h8 + 1<<25) >> 26
-       h9 += carry[8]
-       h8 -= carry[8] << 26
-
-       dst[0] = int32(h0)
-       dst[1] = int32(h1)
-       dst[2] = int32(h2)
-       dst[3] = int32(h3)
-       dst[4] = int32(h4)
-       dst[5] = int32(h5)
-       dst[6] = int32(h6)
-       dst[7] = int32(h7)
-       dst[8] = int32(h8)
-       dst[9] = int32(h9)
-}
-
-// feToBytes marshals h to s.
-// Preconditions:
-//   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-//
-// Write p=2^255-19; q=floor(h/p).
-// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
-//
-// Proof:
-//   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
-//   Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
-//
-//   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
-//   Then 0<y<1.
-//
-//   Write r=h-pq.
-//   Have 0<=r<=p-1=2^255-20.
-//   Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
-//
-//   Write x=r+19(2^-255)r+y.
-//   Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
-//
-//   Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
-//   so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
-func feToBytes(s *[32]byte, h *fieldElement) {
-       var carry [10]int32
-
-       q := (19*h[9] + (1 << 24)) >> 25
-       q = (h[0] + q) >> 26
-       q = (h[1] + q) >> 25
-       q = (h[2] + q) >> 26
-       q = (h[3] + q) >> 25
-       q = (h[4] + q) >> 26
-       q = (h[5] + q) >> 25
-       q = (h[6] + q) >> 26
-       q = (h[7] + q) >> 25
-       q = (h[8] + q) >> 26
-       q = (h[9] + q) >> 25
-
-       // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
-       h[0] += 19 * q
-       // Goal: Output h-2^255 q, which is between 0 and 2^255-20.
-
-       carry[0] = h[0] >> 26
-       h[1] += carry[0]
-       h[0] -= carry[0] << 26
-       carry[1] = h[1] >> 25
-       h[2] += carry[1]
-       h[1] -= carry[1] << 25
-       carry[2] = h[2] >> 26
-       h[3] += carry[2]
-       h[2] -= carry[2] << 26
-       carry[3] = h[3] >> 25
-       h[4] += carry[3]
-       h[3] -= carry[3] << 25
-       carry[4] = h[4] >> 26
-       h[5] += carry[4]
-       h[4] -= carry[4] << 26
-       carry[5] = h[5] >> 25
-       h[6] += carry[5]
-       h[5] -= carry[5] << 25
-       carry[6] = h[6] >> 26
-       h[7] += carry[6]
-       h[6] -= carry[6] << 26
-       carry[7] = h[7] >> 25
-       h[8] += carry[7]
-       h[7] -= carry[7] << 25
-       carry[8] = h[8] >> 26
-       h[9] += carry[8]
-       h[8] -= carry[8] << 26
-       carry[9] = h[9] >> 25
-       h[9] -= carry[9] << 25
-       // h10 = carry9
-
-       // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
-       // Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
-       // evidently 2^255 h10-2^255 q = 0.
-       // Goal: Output h[0]+...+2^230 h[9].
-
-       s[0] = byte(h[0] >> 0)
-       s[1] = byte(h[0] >> 8)
-       s[2] = byte(h[0] >> 16)
-       s[3] = byte((h[0] >> 24) | (h[1] << 2))
-       s[4] = byte(h[1] >> 6)
-       s[5] = byte(h[1] >> 14)
-       s[6] = byte((h[1] >> 22) | (h[2] << 3))
-       s[7] = byte(h[2] >> 5)
-       s[8] = byte(h[2] >> 13)
-       s[9] = byte((h[2] >> 21) | (h[3] << 5))
-       s[10] = byte(h[3] >> 3)
-       s[11] = byte(h[3] >> 11)
-       s[12] = byte((h[3] >> 19) | (h[4] << 6))
-       s[13] = byte(h[4] >> 2)
-       s[14] = byte(h[4] >> 10)
-       s[15] = byte(h[4] >> 18)
-       s[16] = byte(h[5] >> 0)
-       s[17] = byte(h[5] >> 8)
-       s[18] = byte(h[5] >> 16)
-       s[19] = byte((h[5] >> 24) | (h[6] << 1))
-       s[20] = byte(h[6] >> 7)
-       s[21] = byte(h[6] >> 15)
-       s[22] = byte((h[6] >> 23) | (h[7] << 3))
-       s[23] = byte(h[7] >> 5)
-       s[24] = byte(h[7] >> 13)
-       s[25] = byte((h[7] >> 21) | (h[8] << 4))
-       s[26] = byte(h[8] >> 4)
-       s[27] = byte(h[8] >> 12)
-       s[28] = byte((h[8] >> 20) | (h[9] << 6))
-       s[29] = byte(h[9] >> 2)
-       s[30] = byte(h[9] >> 10)
-       s[31] = byte(h[9] >> 18)
-}
-
-// feMul calculates h = f * g
-// Can overlap h with f or g.
-//
-// Preconditions:
-//    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
-//    |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
-//
-// Postconditions:
-//    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-//
-// Notes on implementation strategy:
-//
-// Using schoolbook multiplication.
-// Karatsuba would save a little in some cost models.
-//
-// Most multiplications by 2 and 19 are 32-bit precomputations;
-// cheaper than 64-bit postcomputations.
-//
-// There is one remaining multiplication by 19 in the carry chain;
-// one *19 precomputation can be merged into this,
-// but the resulting data flow is considerably less clean.
-//
-// There are 12 carries below.
-// 10 of them are 2-way parallelizable and vectorizable.
-// Can get away with 11 carries, but then data flow is much deeper.
-//
-// With tighter constraints on inputs can squeeze carries into int32.
-func feMul(h, f, g *fieldElement) {
-       f0 := f[0]
-       f1 := f[1]
-       f2 := f[2]
-       f3 := f[3]
-       f4 := f[4]
-       f5 := f[5]
-       f6 := f[6]
-       f7 := f[7]
-       f8 := f[8]
-       f9 := f[9]
-       g0 := g[0]
-       g1 := g[1]
-       g2 := g[2]
-       g3 := g[3]
-       g4 := g[4]
-       g5 := g[5]
-       g6 := g[6]
-       g7 := g[7]
-       g8 := g[8]
-       g9 := g[9]
-       g1_19 := 19 * g1 // 1.4*2^29
-       g2_19 := 19 * g2 // 1.4*2^30; still ok
-       g3_19 := 19 * g3
-       g4_19 := 19 * g4
-       g5_19 := 19 * g5
-       g6_19 := 19 * g6
-       g7_19 := 19 * g7
-       g8_19 := 19 * g8
-       g9_19 := 19 * g9
-       f1_2 := 2 * f1
-       f3_2 := 2 * f3
-       f5_2 := 2 * f5
-       f7_2 := 2 * f7
-       f9_2 := 2 * f9
-       f0g0 := int64(f0) * int64(g0)
-       f0g1 := int64(f0) * int64(g1)
-       f0g2 := int64(f0) * int64(g2)
-       f0g3 := int64(f0) * int64(g3)
-       f0g4 := int64(f0) * int64(g4)
-       f0g5 := int64(f0) * int64(g5)
-       f0g6 := int64(f0) * int64(g6)
-       f0g7 := int64(f0) * int64(g7)
-       f0g8 := int64(f0) * int64(g8)
-       f0g9 := int64(f0) * int64(g9)
-       f1g0 := int64(f1) * int64(g0)
-       f1g1_2 := int64(f1_2) * int64(g1)
-       f1g2 := int64(f1) * int64(g2)
-       f1g3_2 := int64(f1_2) * int64(g3)
-       f1g4 := int64(f1) * int64(g4)
-       f1g5_2 := int64(f1_2) * int64(g5)
-       f1g6 := int64(f1) * int64(g6)
-       f1g7_2 := int64(f1_2) * int64(g7)
-       f1g8 := int64(f1) * int64(g8)
-       f1g9_38 := int64(f1_2) * int64(g9_19)
-       f2g0 := int64(f2) * int64(g0)
-       f2g1 := int64(f2) * int64(g1)
-       f2g2 := int64(f2) * int64(g2)
-       f2g3 := int64(f2) * int64(g3)
-       f2g4 := int64(f2) * int64(g4)
-       f2g5 := int64(f2) * int64(g5)
-       f2g6 := int64(f2) * int64(g6)
-       f2g7 := int64(f2) * int64(g7)
-       f2g8_19 := int64(f2) * int64(g8_19)
-       f2g9_19 := int64(f2) * int64(g9_19)
-       f3g0 := int64(f3) * int64(g0)
-       f3g1_2 := int64(f3_2) * int64(g1)
-       f3g2 := int64(f3) * int64(g2)
-       f3g3_2 := int64(f3_2) * int64(g3)
-       f3g4 := int64(f3) * int64(g4)
-       f3g5_2 := int64(f3_2) * int64(g5)
-       f3g6 := int64(f3) * int64(g6)
-       f3g7_38 := int64(f3_2) * int64(g7_19)
-       f3g8_19 := int64(f3) * int64(g8_19)
-       f3g9_38 := int64(f3_2) * int64(g9_19)
-       f4g0 := int64(f4) * int64(g0)
-       f4g1 := int64(f4) * int64(g1)
-       f4g2 := int64(f4) * int64(g2)
-       f4g3 := int64(f4) * int64(g3)
-       f4g4 := int64(f4) * int64(g4)
-       f4g5 := int64(f4) * int64(g5)
-       f4g6_19 := int64(f4) * int64(g6_19)
-       f4g7_19 := int64(f4) * int64(g7_19)
-       f4g8_19 := int64(f4) * int64(g8_19)
-       f4g9_19 := int64(f4) * int64(g9_19)
-       f5g0 := int64(f5) * int64(g0)
-       f5g1_2 := int64(f5_2) * int64(g1)
-       f5g2 := int64(f5) * int64(g2)
-       f5g3_2 := int64(f5_2) * int64(g3)
-       f5g4 := int64(f5) * int64(g4)
-       f5g5_38 := int64(f5_2) * int64(g5_19)
-       f5g6_19 := int64(f5) * int64(g6_19)
-       f5g7_38 := int64(f5_2) * int64(g7_19)
-       f5g8_19 := int64(f5) * int64(g8_19)
-       f5g9_38 := int64(f5_2) * int64(g9_19)
-       f6g0 := int64(f6) * int64(g0)
-       f6g1 := int64(f6) * int64(g1)
-       f6g2 := int64(f6) * int64(g2)
-       f6g3 := int64(f6) * int64(g3)
-       f6g4_19 := int64(f6) * int64(g4_19)
-       f6g5_19 := int64(f6) * int64(g5_19)
-       f6g6_19 := int64(f6) * int64(g6_19)
-       f6g7_19 := int64(f6) * int64(g7_19)
-       f6g8_19 := int64(f6) * int64(g8_19)
-       f6g9_19 := int64(f6) * int64(g9_19)
-       f7g0 := int64(f7) * int64(g0)
-       f7g1_2 := int64(f7_2) * int64(g1)
-       f7g2 := int64(f7) * int64(g2)
-       f7g3_38 := int64(f7_2) * int64(g3_19)
-       f7g4_19 := int64(f7) * int64(g4_19)
-       f7g5_38 := int64(f7_2) * int64(g5_19)
-       f7g6_19 := int64(f7) * int64(g6_19)
-       f7g7_38 := int64(f7_2) * int64(g7_19)
-       f7g8_19 := int64(f7) * int64(g8_19)
-       f7g9_38 := int64(f7_2) * int64(g9_19)
-       f8g0 := int64(f8) * int64(g0)
-       f8g1 := int64(f8) * int64(g1)
-       f8g2_19 := int64(f8) * int64(g2_19)
-       f8g3_19 := int64(f8) * int64(g3_19)
-       f8g4_19 := int64(f8) * int64(g4_19)
-       f8g5_19 := int64(f8) * int64(g5_19)
-       f8g6_19 := int64(f8) * int64(g6_19)
-       f8g7_19 := int64(f8) * int64(g7_19)
-       f8g8_19 := int64(f8) * int64(g8_19)
-       f8g9_19 := int64(f8) * int64(g9_19)
-       f9g0 := int64(f9) * int64(g0)
-       f9g1_38 := int64(f9_2) * int64(g1_19)
-       f9g2_19 := int64(f9) * int64(g2_19)
-       f9g3_38 := int64(f9_2) * int64(g3_19)
-       f9g4_19 := int64(f9) * int64(g4_19)
-       f9g5_38 := int64(f9_2) * int64(g5_19)
-       f9g6_19 := int64(f9) * int64(g6_19)
-       f9g7_38 := int64(f9_2) * int64(g7_19)
-       f9g8_19 := int64(f9) * int64(g8_19)
-       f9g9_38 := int64(f9_2) * int64(g9_19)
-       h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
-       h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
-       h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
-       h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
-       h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
-       h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
-       h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
-       h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
-       h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
-       h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
-       var carry [10]int64
-
-       // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
-       //   i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
-       // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
-       //   i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
-
-       carry[0] = (h0 + (1 << 25)) >> 26
-       h1 += carry[0]
-       h0 -= carry[0] << 26
-       carry[4] = (h4 + (1 << 25)) >> 26
-       h5 += carry[4]
-       h4 -= carry[4] << 26
-       // |h0| <= 2^25
-       // |h4| <= 2^25
-       // |h1| <= 1.51*2^58
-       // |h5| <= 1.51*2^58
-
-       carry[1] = (h1 + (1 << 24)) >> 25
-       h2 += carry[1]
-       h1 -= carry[1] << 25
-       carry[5] = (h5 + (1 << 24)) >> 25
-       h6 += carry[5]
-       h5 -= carry[5] << 25
-       // |h1| <= 2^24; from now on fits into int32
-       // |h5| <= 2^24; from now on fits into int32
-       // |h2| <= 1.21*2^59
-       // |h6| <= 1.21*2^59
-
-       carry[2] = (h2 + (1 << 25)) >> 26
-       h3 += carry[2]
-       h2 -= carry[2] << 26
-       carry[6] = (h6 + (1 << 25)) >> 26
-       h7 += carry[6]
-       h6 -= carry[6] << 26
-       // |h2| <= 2^25; from now on fits into int32 unchanged
-       // |h6| <= 2^25; from now on fits into int32 unchanged
-       // |h3| <= 1.51*2^58
-       // |h7| <= 1.51*2^58
-
-       carry[3] = (h3 + (1 << 24)) >> 25
-       h4 += carry[3]
-       h3 -= carry[3] << 25
-       carry[7] = (h7 + (1 << 24)) >> 25
-       h8 += carry[7]
-       h7 -= carry[7] << 25
-       // |h3| <= 2^24; from now on fits into int32 unchanged
-       // |h7| <= 2^24; from now on fits into int32 unchanged
-       // |h4| <= 1.52*2^33
-       // |h8| <= 1.52*2^33
-
-       carry[4] = (h4 + (1 << 25)) >> 26
-       h5 += carry[4]
-       h4 -= carry[4] << 26
-       carry[8] = (h8 + (1 << 25)) >> 26
-       h9 += carry[8]
-       h8 -= carry[8] << 26
-       // |h4| <= 2^25; from now on fits into int32 unchanged
-       // |h8| <= 2^25; from now on fits into int32 unchanged
-       // |h5| <= 1.01*2^24
-       // |h9| <= 1.51*2^58
-
-       carry[9] = (h9 + (1 << 24)) >> 25
-       h0 += carry[9] * 19
-       h9 -= carry[9] << 25
-       // |h9| <= 2^24; from now on fits into int32 unchanged
-       // |h0| <= 1.8*2^37
-
-       carry[0] = (h0 + (1 << 25)) >> 26
-       h1 += carry[0]
-       h0 -= carry[0] << 26
-       // |h0| <= 2^25; from now on fits into int32 unchanged
-       // |h1| <= 1.01*2^24
-
-       h[0] = int32(h0)
-       h[1] = int32(h1)
-       h[2] = int32(h2)
-       h[3] = int32(h3)
-       h[4] = int32(h4)
-       h[5] = int32(h5)
-       h[6] = int32(h6)
-       h[7] = int32(h7)
-       h[8] = int32(h8)
-       h[9] = int32(h9)
-}
-
-// feSquare calculates h = f*f. Can overlap h with f.
-//
-// Preconditions:
-//    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
-//
-// Postconditions:
-//    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-func feSquare(h, f *fieldElement) {
-       f0 := f[0]
-       f1 := f[1]
-       f2 := f[2]
-       f3 := f[3]
-       f4 := f[4]
-       f5 := f[5]
-       f6 := f[6]
-       f7 := f[7]
-       f8 := f[8]
-       f9 := f[9]
-       f0_2 := 2 * f0
-       f1_2 := 2 * f1
-       f2_2 := 2 * f2
-       f3_2 := 2 * f3
-       f4_2 := 2 * f4
-       f5_2 := 2 * f5
-       f6_2 := 2 * f6
-       f7_2 := 2 * f7
-       f5_38 := 38 * f5 // 1.31*2^30
-       f6_19 := 19 * f6 // 1.31*2^30
-       f7_38 := 38 * f7 // 1.31*2^30
-       f8_19 := 19 * f8 // 1.31*2^30
-       f9_38 := 38 * f9 // 1.31*2^30
-       f0f0 := int64(f0) * int64(f0)
-       f0f1_2 := int64(f0_2) * int64(f1)
-       f0f2_2 := int64(f0_2) * int64(f2)
-       f0f3_2 := int64(f0_2) * int64(f3)
-       f0f4_2 := int64(f0_2) * int64(f4)
-       f0f5_2 := int64(f0_2) * int64(f5)
-       f0f6_2 := int64(f0_2) * int64(f6)
-       f0f7_2 := int64(f0_2) * int64(f7)
-       f0f8_2 := int64(f0_2) * int64(f8)
-       f0f9_2 := int64(f0_2) * int64(f9)
-       f1f1_2 := int64(f1_2) * int64(f1)
-       f1f2_2 := int64(f1_2) * int64(f2)
-       f1f3_4 := int64(f1_2) * int64(f3_2)
-       f1f4_2 := int64(f1_2) * int64(f4)
-       f1f5_4 := int64(f1_2) * int64(f5_2)
-       f1f6_2 := int64(f1_2) * int64(f6)
-       f1f7_4 := int64(f1_2) * int64(f7_2)
-       f1f8_2 := int64(f1_2) * int64(f8)
-       f1f9_76 := int64(f1_2) * int64(f9_38)
-       f2f2 := int64(f2) * int64(f2)
-       f2f3_2 := int64(f2_2) * int64(f3)
-       f2f4_2 := int64(f2_2) * int64(f4)
-       f2f5_2 := int64(f2_2) * int64(f5)
-       f2f6_2 := int64(f2_2) * int64(f6)
-       f2f7_2 := int64(f2_2) * int64(f7)
-       f2f8_38 := int64(f2_2) * int64(f8_19)
-       f2f9_38 := int64(f2) * int64(f9_38)
-       f3f3_2 := int64(f3_2) * int64(f3)
-       f3f4_2 := int64(f3_2) * int64(f4)
-       f3f5_4 := int64(f3_2) * int64(f5_2)
-       f3f6_2 := int64(f3_2) * int64(f6)
-       f3f7_76 := int64(f3_2) * int64(f7_38)
-       f3f8_38 := int64(f3_2) * int64(f8_19)
-       f3f9_76 := int64(f3_2) * int64(f9_38)
-       f4f4 := int64(f4) * int64(f4)
-       f4f5_2 := int64(f4_2) * int64(f5)
-       f4f6_38 := int64(f4_2) * int64(f6_19)
-       f4f7_38 := int64(f4) * int64(f7_38)
-       f4f8_38 := int64(f4_2) * int64(f8_19)
-       f4f9_38 := int64(f4) * int64(f9_38)
-       f5f5_38 := int64(f5) * int64(f5_38)
-       f5f6_38 := int64(f5_2) * int64(f6_19)
-       f5f7_76 := int64(f5_2) * int64(f7_38)
-       f5f8_38 := int64(f5_2) * int64(f8_19)
-       f5f9_76 := int64(f5_2) * int64(f9_38)
-       f6f6_19 := int64(f6) * int64(f6_19)
-       f6f7_38 := int64(f6) * int64(f7_38)
-       f6f8_38 := int64(f6_2) * int64(f8_19)
-       f6f9_38 := int64(f6) * int64(f9_38)
-       f7f7_38 := int64(f7) * int64(f7_38)
-       f7f8_38 := int64(f7_2) * int64(f8_19)
-       f7f9_76 := int64(f7_2) * int64(f9_38)
-       f8f8_19 := int64(f8) * int64(f8_19)
-       f8f9_38 := int64(f8) * int64(f9_38)
-       f9f9_38 := int64(f9) * int64(f9_38)
-       h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
-       h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
-       h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
-       h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
-       h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
-       h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
-       h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
-       h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
-       h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
-       h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
-       var carry [10]int64
-
-       carry[0] = (h0 + (1 << 25)) >> 26
-       h1 += carry[0]
-       h0 -= carry[0] << 26
-       carry[4] = (h4 + (1 << 25)) >> 26
-       h5 += carry[4]
-       h4 -= carry[4] << 26
-
-       carry[1] = (h1 + (1 << 24)) >> 25
-       h2 += carry[1]
-       h1 -= carry[1] << 25
-       carry[5] = (h5 + (1 << 24)) >> 25
-       h6 += carry[5]
-       h5 -= carry[5] << 25
-
-       carry[2] = (h2 + (1 << 25)) >> 26
-       h3 += carry[2]
-       h2 -= carry[2] << 26
-       carry[6] = (h6 + (1 << 25)) >> 26
-       h7 += carry[6]
-       h6 -= carry[6] << 26
-
-       carry[3] = (h3 + (1 << 24)) >> 25
-       h4 += carry[3]
-       h3 -= carry[3] << 25
-       carry[7] = (h7 + (1 << 24)) >> 25
-       h8 += carry[7]
-       h7 -= carry[7] << 25
-
-       carry[4] = (h4 + (1 << 25)) >> 26
-       h5 += carry[4]
-       h4 -= carry[4] << 26
-       carry[8] = (h8 + (1 << 25)) >> 26
-       h9 += carry[8]
-       h8 -= carry[8] << 26
-
-       carry[9] = (h9 + (1 << 24)) >> 25
-       h0 += carry[9] * 19
-       h9 -= carry[9] << 25
-
-       carry[0] = (h0 + (1 << 25)) >> 26
-       h1 += carry[0]
-       h0 -= carry[0] << 26
-
-       h[0] = int32(h0)
-       h[1] = int32(h1)
-       h[2] = int32(h2)
-       h[3] = int32(h3)
-       h[4] = int32(h4)
-       h[5] = int32(h5)
-       h[6] = int32(h6)
-       h[7] = int32(h7)
-       h[8] = int32(h8)
-       h[9] = int32(h9)
-}
-
-// feMul121666 calculates h = f * 121666. Can overlap h with f.
-//
-// Preconditions:
-//    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
-//
-// Postconditions:
-//    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-func feMul121666(h, f *fieldElement) {
-       h0 := int64(f[0]) * 121666
-       h1 := int64(f[1]) * 121666
-       h2 := int64(f[2]) * 121666
-       h3 := int64(f[3]) * 121666
-       h4 := int64(f[4]) * 121666
-       h5 := int64(f[5]) * 121666
-       h6 := int64(f[6]) * 121666
-       h7 := int64(f[7]) * 121666
-       h8 := int64(f[8]) * 121666
-       h9 := int64(f[9]) * 121666
-       var carry [10]int64
-
-       carry[9] = (h9 + (1 << 24)) >> 25
-       h0 += carry[9] * 19
-       h9 -= carry[9] << 25
-       carry[1] = (h1 + (1 << 24)) >> 25
-       h2 += carry[1]
-       h1 -= carry[1] << 25
-       carry[3] = (h3 + (1 << 24)) >> 25
-       h4 += carry[3]
-       h3 -= carry[3] << 25
-       carry[5] = (h5 + (1 << 24)) >> 25
-       h6 += carry[5]
-       h5 -= carry[5] << 25
-       carry[7] = (h7 + (1 << 24)) >> 25
-       h8 += carry[7]
-       h7 -= carry[7] << 25
-
-       carry[0] = (h0 + (1 << 25)) >> 26
-       h1 += carry[0]
-       h0 -= carry[0] << 26
-       carry[2] = (h2 + (1 << 25)) >> 26
-       h3 += carry[2]
-       h2 -= carry[2] << 26
-       carry[4] = (h4 + (1 << 25)) >> 26
-       h5 += carry[4]
-       h4 -= carry[4] << 26
-       carry[6] = (h6 + (1 << 25)) >> 26
-       h7 += carry[6]
-       h6 -= carry[6] << 26
-       carry[8] = (h8 + (1 << 25)) >> 26
-       h9 += carry[8]
-       h8 -= carry[8] << 26
-
-       h[0] = int32(h0)
-       h[1] = int32(h1)
-       h[2] = int32(h2)
-       h[3] = int32(h3)
-       h[4] = int32(h4)
-       h[5] = int32(h5)
-       h[6] = int32(h6)
-       h[7] = int32(h7)
-       h[8] = int32(h8)
-       h[9] = int32(h9)
-}
-
-// feInvert sets out = z^-1.
-func feInvert(out, z *fieldElement) {
-       var t0, t1, t2, t3 fieldElement
-       var i int
-
-       feSquare(&t0, z)
-       for i = 1; i < 1; i++ {
-               feSquare(&t0, &t0)
-       }
-       feSquare(&t1, &t0)
-       for i = 1; i < 2; i++ {
-               feSquare(&t1, &t1)
-       }
-       feMul(&t1, z, &t1)
-       feMul(&t0, &t0, &t1)
-       feSquare(&t2, &t0)
-       for i = 1; i < 1; i++ {
-               feSquare(&t2, &t2)
-       }
-       feMul(&t1, &t1, &t2)
-       feSquare(&t2, &t1)
-       for i = 1; i < 5; i++ {
-               feSquare(&t2, &t2)
-       }
-       feMul(&t1, &t2, &t1)
-       feSquare(&t2, &t1)
-       for i = 1; i < 10; i++ {
-               feSquare(&t2, &t2)
-       }
-       feMul(&t2, &t2, &t1)
-       feSquare(&t3, &t2)
-       for i = 1; i < 20; i++ {
-               feSquare(&t3, &t3)
-       }
-       feMul(&t2, &t3, &t2)
-       feSquare(&t2, &t2)
-       for i = 1; i < 10; i++ {
-               feSquare(&t2, &t2)
-       }
-       feMul(&t1, &t2, &t1)
-       feSquare(&t2, &t1)
-       for i = 1; i < 50; i++ {
-               feSquare(&t2, &t2)
-       }
-       feMul(&t2, &t2, &t1)
-       feSquare(&t3, &t2)
-       for i = 1; i < 100; i++ {
-               feSquare(&t3, &t3)
-       }
-       feMul(&t2, &t3, &t2)
-       feSquare(&t2, &t2)
-       for i = 1; i < 50; i++ {
-               feSquare(&t2, &t2)
-       }
-       feMul(&t1, &t2, &t1)
-       feSquare(&t1, &t1)
-       for i = 1; i < 5; i++ {
-               feSquare(&t1, &t1)
-       }
-       feMul(out, &t1, &t0)
-}
-
-func scalarMultGeneric(out, in, base *[32]byte) {
-       var e [32]byte
-
-       copy(e[:], in[:])
-       e[0] &= 248
-       e[31] &= 127
-       e[31] |= 64
-
-       var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
-       feFromBytes(&x1, base)
-       feOne(&x2)
-       feCopy(&x3, &x1)
-       feOne(&z3)
-
-       swap := int32(0)
-       for pos := 254; pos >= 0; pos-- {
-               b := e[pos/8] >> uint(pos&7)
-               b &= 1
-               swap ^= int32(b)
-               feCSwap(&x2, &x3, swap)
-               feCSwap(&z2, &z3, swap)
-               swap = int32(b)
-
-               feSub(&tmp0, &x3, &z3)
-               feSub(&tmp1, &x2, &z2)
-               feAdd(&x2, &x2, &z2)
-               feAdd(&z2, &x3, &z3)
-               feMul(&z3, &tmp0, &x2)
-               feMul(&z2, &z2, &tmp1)
-               feSquare(&tmp0, &tmp1)
-               feSquare(&tmp1, &x2)
-               feAdd(&x3, &z3, &z2)
-               feSub(&z2, &z3, &z2)
-               feMul(&x2, &tmp1, &tmp0)
-               feSub(&tmp1, &tmp1, &tmp0)
-               feSquare(&z2, &z2)
-               feMul121666(&z3, &tmp1)
-               feSquare(&x3, &x3)
-               feAdd(&tmp0, &tmp0, &z3)
-               feMul(&z3, &x1, &z2)
-               feMul(&z2, &tmp1, &tmp0)
-       }
-
-       feCSwap(&x2, &x3, swap)
-       feCSwap(&z2, &z3, swap)
-
-       feInvert(&z2, &z2)
-       feMul(&x2, &x2, &z2)
-       feToBytes(out, &x2)
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go b/src/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go
deleted file mode 100644 (file)
index 259728a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.
-
-//go:build !amd64 || !gc || purego
-// +build !amd64 !gc purego
-
-package curve25519
-
-func scalarMult(out, in, base *[32]byte) {
-       scalarMultGeneric(out, in, base)
-}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/README b/src/vendor/golang.org/x/crypto/curve25519/internal/field/README
new file mode 100644 (file)
index 0000000..e25bca7
--- /dev/null
@@ -0,0 +1,7 @@
+This package is kept in sync with crypto/ed25519/internal/edwards25519/field in
+the standard library.
+
+If there are any changes in the standard library that need to be synced to this
+package, run sync.sh. It will not overwrite any local changes made since the
+previous sync, so it's ok to land changes in this package first, and then sync
+to the standard library later.
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe.go
new file mode 100644 (file)
index 0000000..ca841ad
--- /dev/null
@@ -0,0 +1,416 @@
+// Copyright (c) 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 field implements fast arithmetic modulo 2^255-19.
+package field
+
+import (
+       "crypto/subtle"
+       "encoding/binary"
+       "math/bits"
+)
+
+// Element represents an element of the field GF(2^255-19). Note that this
+// is not a cryptographically secure group, and should only be used to interact
+// with edwards25519.Point coordinates.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Element struct {
+       // An element t represents the integer
+       //     t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
+       //
+       // Between operations, all limbs are expected to be lower than 2^52.
+       l0 uint64
+       l1 uint64
+       l2 uint64
+       l3 uint64
+       l4 uint64
+}
+
+const maskLow51Bits uint64 = (1 << 51) - 1
+
+var feZero = &Element{0, 0, 0, 0, 0}
+
+// Zero sets v = 0, and returns v.
+func (v *Element) Zero() *Element {
+       *v = *feZero
+       return v
+}
+
+var feOne = &Element{1, 0, 0, 0, 0}
+
+// One sets v = 1, and returns v.
+func (v *Element) One() *Element {
+       *v = *feOne
+       return v
+}
+
+// reduce reduces v modulo 2^255 - 19 and returns it.
+func (v *Element) reduce() *Element {
+       v.carryPropagate()
+
+       // After the light reduction we now have a field element representation
+       // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
+
+       // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
+       // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
+       c := (v.l0 + 19) >> 51
+       c = (v.l1 + c) >> 51
+       c = (v.l2 + c) >> 51
+       c = (v.l3 + c) >> 51
+       c = (v.l4 + c) >> 51
+
+       // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
+       // effectively applying the reduction identity to the carry.
+       v.l0 += 19 * c
+
+       v.l1 += v.l0 >> 51
+       v.l0 = v.l0 & maskLow51Bits
+       v.l2 += v.l1 >> 51
+       v.l1 = v.l1 & maskLow51Bits
+       v.l3 += v.l2 >> 51
+       v.l2 = v.l2 & maskLow51Bits
+       v.l4 += v.l3 >> 51
+       v.l3 = v.l3 & maskLow51Bits
+       // no additional carry
+       v.l4 = v.l4 & maskLow51Bits
+
+       return v
+}
+
+// Add sets v = a + b, and returns v.
+func (v *Element) Add(a, b *Element) *Element {
+       v.l0 = a.l0 + b.l0
+       v.l1 = a.l1 + b.l1
+       v.l2 = a.l2 + b.l2
+       v.l3 = a.l3 + b.l3
+       v.l4 = a.l4 + b.l4
+       // Using the generic implementation here is actually faster than the
+       // assembly. Probably because the body of this function is so simple that
+       // the compiler can figure out better optimizations by inlining the carry
+       // propagation. TODO
+       return v.carryPropagateGeneric()
+}
+
+// Subtract sets v = a - b, and returns v.
+func (v *Element) Subtract(a, b *Element) *Element {
+       // We first add 2 * p, to guarantee the subtraction won't underflow, and
+       // then subtract b (which can be up to 2^255 + 2^13 * 19).
+       v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
+       v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
+       v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
+       v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
+       v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
+       return v.carryPropagate()
+}
+
+// Negate sets v = -a, and returns v.
+func (v *Element) Negate(a *Element) *Element {
+       return v.Subtract(feZero, a)
+}
+
+// Invert sets v = 1/z mod p, and returns v.
+//
+// If z == 0, Invert returns v = 0.
+func (v *Element) Invert(z *Element) *Element {
+       // Inversion is implemented as exponentiation with exponent p − 2. It uses the
+       // same sequence of 255 squarings and 11 multiplications as [Curve25519].
+       var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
+
+       z2.Square(z)             // 2
+       t.Square(&z2)            // 4
+       t.Square(&t)             // 8
+       z9.Multiply(&t, z)       // 9
+       z11.Multiply(&z9, &z2)   // 11
+       t.Square(&z11)           // 22
+       z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
+
+       t.Square(&z2_5_0) // 2^6 - 2^1
+       for i := 0; i < 4; i++ {
+               t.Square(&t) // 2^10 - 2^5
+       }
+       z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
+
+       t.Square(&z2_10_0) // 2^11 - 2^1
+       for i := 0; i < 9; i++ {
+               t.Square(&t) // 2^20 - 2^10
+       }
+       z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
+
+       t.Square(&z2_20_0) // 2^21 - 2^1
+       for i := 0; i < 19; i++ {
+               t.Square(&t) // 2^40 - 2^20
+       }
+       t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
+
+       t.Square(&t) // 2^41 - 2^1
+       for i := 0; i < 9; i++ {
+               t.Square(&t) // 2^50 - 2^10
+       }
+       z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
+
+       t.Square(&z2_50_0) // 2^51 - 2^1
+       for i := 0; i < 49; i++ {
+               t.Square(&t) // 2^100 - 2^50
+       }
+       z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
+
+       t.Square(&z2_100_0) // 2^101 - 2^1
+       for i := 0; i < 99; i++ {
+               t.Square(&t) // 2^200 - 2^100
+       }
+       t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
+
+       t.Square(&t) // 2^201 - 2^1
+       for i := 0; i < 49; i++ {
+               t.Square(&t) // 2^250 - 2^50
+       }
+       t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
+
+       t.Square(&t) // 2^251 - 2^1
+       t.Square(&t) // 2^252 - 2^2
+       t.Square(&t) // 2^253 - 2^3
+       t.Square(&t) // 2^254 - 2^4
+       t.Square(&t) // 2^255 - 2^5
+
+       return v.Multiply(&t, &z11) // 2^255 - 21
+}
+
+// Set sets v = a, and returns v.
+func (v *Element) Set(a *Element) *Element {
+       *v = *a
+       return v
+}
+
+// SetBytes sets v to x, which must be a 32-byte little-endian encoding.
+//
+// Consistent with RFC 7748, the most significant bit (the high bit of the
+// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
+// are accepted. Note that this is laxer than specified by RFC 8032.
+func (v *Element) SetBytes(x []byte) *Element {
+       if len(x) != 32 {
+               panic("edwards25519: invalid field element input size")
+       }
+
+       // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
+       v.l0 = binary.LittleEndian.Uint64(x[0:8])
+       v.l0 &= maskLow51Bits
+       // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
+       v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
+       v.l1 &= maskLow51Bits
+       // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
+       v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
+       v.l2 &= maskLow51Bits
+       // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
+       v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
+       v.l3 &= maskLow51Bits
+       // Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
+       // Note: not bytes 25:33, shift 4, to avoid overread.
+       v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
+       v.l4 &= maskLow51Bits
+
+       return v
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of v.
+func (v *Element) Bytes() []byte {
+       // This function is outlined to make the allocations inline in the caller
+       // rather than happen on the heap.
+       var out [32]byte
+       return v.bytes(&out)
+}
+
+func (v *Element) bytes(out *[32]byte) []byte {
+       t := *v
+       t.reduce()
+
+       var buf [8]byte
+       for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
+               bitsOffset := i * 51
+               binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
+               for i, bb := range buf {
+                       off := bitsOffset/8 + i
+                       if off >= len(out) {
+                               break
+                       }
+                       out[off] |= bb
+               }
+       }
+
+       return out[:]
+}
+
+// Equal returns 1 if v and u are equal, and 0 otherwise.
+func (v *Element) Equal(u *Element) int {
+       sa, sv := u.Bytes(), v.Bytes()
+       return subtle.ConstantTimeCompare(sa, sv)
+}
+
+// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
+func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *Element) Select(a, b *Element, cond int) *Element {
+       m := mask64Bits(cond)
+       v.l0 = (m & a.l0) | (^m & b.l0)
+       v.l1 = (m & a.l1) | (^m & b.l1)
+       v.l2 = (m & a.l2) | (^m & b.l2)
+       v.l3 = (m & a.l3) | (^m & b.l3)
+       v.l4 = (m & a.l4) | (^m & b.l4)
+       return v
+}
+
+// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
+func (v *Element) Swap(u *Element, cond int) {
+       m := mask64Bits(cond)
+       t := m & (v.l0 ^ u.l0)
+       v.l0 ^= t
+       u.l0 ^= t
+       t = m & (v.l1 ^ u.l1)
+       v.l1 ^= t
+       u.l1 ^= t
+       t = m & (v.l2 ^ u.l2)
+       v.l2 ^= t
+       u.l2 ^= t
+       t = m & (v.l3 ^ u.l3)
+       v.l3 ^= t
+       u.l3 ^= t
+       t = m & (v.l4 ^ u.l4)
+       v.l4 ^= t
+       u.l4 ^= t
+}
+
+// IsNegative returns 1 if v is negative, and 0 otherwise.
+func (v *Element) IsNegative() int {
+       return int(v.Bytes()[0] & 1)
+}
+
+// Absolute sets v to |u|, and returns v.
+func (v *Element) Absolute(u *Element) *Element {
+       return v.Select(new(Element).Negate(u), u, u.IsNegative())
+}
+
+// Multiply sets v = x * y, and returns v.
+func (v *Element) Multiply(x, y *Element) *Element {
+       feMul(v, x, y)
+       return v
+}
+
+// Square sets v = x * x, and returns v.
+func (v *Element) Square(x *Element) *Element {
+       feSquare(v, x)
+       return v
+}
+
+// Mult32 sets v = x * y, and returns v.
+func (v *Element) Mult32(x *Element, y uint32) *Element {
+       x0lo, x0hi := mul51(x.l0, y)
+       x1lo, x1hi := mul51(x.l1, y)
+       x2lo, x2hi := mul51(x.l2, y)
+       x3lo, x3hi := mul51(x.l3, y)
+       x4lo, x4hi := mul51(x.l4, y)
+       v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
+       v.l1 = x1lo + x0hi
+       v.l2 = x2lo + x1hi
+       v.l3 = x3lo + x2hi
+       v.l4 = x4lo + x3hi
+       // The hi portions are going to be only 32 bits, plus any previous excess,
+       // so we can skip the carry propagation.
+       return v
+}
+
+// mul51 returns lo + hi * 2⁵¹ = a * b.
+func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
+       mh, ml := bits.Mul64(a, uint64(b))
+       lo = ml & maskLow51Bits
+       hi = (mh << 13) | (ml >> 51)
+       return
+}
+
+// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
+func (v *Element) Pow22523(x *Element) *Element {
+       var t0, t1, t2 Element
+
+       t0.Square(x)             // x^2
+       t1.Square(&t0)           // x^4
+       t1.Square(&t1)           // x^8
+       t1.Multiply(x, &t1)      // x^9
+       t0.Multiply(&t0, &t1)    // x^11
+       t0.Square(&t0)           // x^22
+       t0.Multiply(&t1, &t0)    // x^31
+       t1.Square(&t0)           // x^62
+       for i := 1; i < 5; i++ { // x^992
+               t1.Square(&t1)
+       }
+       t0.Multiply(&t1, &t0)     // x^1023 -> 1023 = 2^10 - 1
+       t1.Square(&t0)            // 2^11 - 2
+       for i := 1; i < 10; i++ { // 2^20 - 2^10
+               t1.Square(&t1)
+       }
+       t1.Multiply(&t1, &t0)     // 2^20 - 1
+       t2.Square(&t1)            // 2^21 - 2
+       for i := 1; i < 20; i++ { // 2^40 - 2^20
+               t2.Square(&t2)
+       }
+       t1.Multiply(&t2, &t1)     // 2^40 - 1
+       t1.Square(&t1)            // 2^41 - 2
+       for i := 1; i < 10; i++ { // 2^50 - 2^10
+               t1.Square(&t1)
+       }
+       t0.Multiply(&t1, &t0)     // 2^50 - 1
+       t1.Square(&t0)            // 2^51 - 2
+       for i := 1; i < 50; i++ { // 2^100 - 2^50
+               t1.Square(&t1)
+       }
+       t1.Multiply(&t1, &t0)      // 2^100 - 1
+       t2.Square(&t1)             // 2^101 - 2
+       for i := 1; i < 100; i++ { // 2^200 - 2^100
+               t2.Square(&t2)
+       }
+       t1.Multiply(&t2, &t1)     // 2^200 - 1
+       t1.Square(&t1)            // 2^201 - 2
+       for i := 1; i < 50; i++ { // 2^250 - 2^50
+               t1.Square(&t1)
+       }
+       t0.Multiply(&t1, &t0)     // 2^250 - 1
+       t0.Square(&t0)            // 2^251 - 2
+       t0.Square(&t0)            // 2^252 - 4
+       return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
+}
+
+// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
+var sqrtM1 = &Element{1718705420411056, 234908883556509,
+       2233514472574048, 2117202627021982, 765476049583133}
+
+// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
+//
+// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
+// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
+// and returns r and 0.
+func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
+       var a, b Element
+
+       // r = (u * v3) * (u * v7)^((p-5)/8)
+       v2 := a.Square(v)
+       uv3 := b.Multiply(u, b.Multiply(v2, v))
+       uv7 := a.Multiply(uv3, a.Square(v2))
+       r.Multiply(uv3, r.Pow22523(uv7))
+
+       check := a.Multiply(v, a.Square(r)) // check = v * r^2
+
+       uNeg := b.Negate(u)
+       correctSignSqrt := check.Equal(u)
+       flippedSignSqrt := check.Equal(uNeg)
+       flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
+
+       rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
+       // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
+       r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
+
+       r.Absolute(r) // Choose the nonnegative square root.
+       return r, correctSignSqrt | flippedSignSqrt
+}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
new file mode 100644 (file)
index 0000000..44dc8e8
--- /dev/null
@@ -0,0 +1,13 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+// +build amd64,gc,!purego
+
+package field
+
+// feMul sets out = a * b. It works like feMulGeneric.
+//go:noescape
+func feMul(out *Element, a *Element, b *Element)
+
+// feSquare sets out = a * a. It works like feSquareGeneric.
+//go:noescape
+func feSquare(out *Element, a *Element)
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
new file mode 100644 (file)
index 0000000..293f013
--- /dev/null
@@ -0,0 +1,379 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+// +build amd64,gc,!purego
+
+#include "textflag.h"
+
+// func feMul(out *Element, a *Element, b *Element)
+TEXT ·feMul(SB), NOSPLIT, $0-24
+       MOVQ a+8(FP), CX
+       MOVQ b+16(FP), BX
+
+       // r0 = a0×b0
+       MOVQ (CX), AX
+       MULQ (BX)
+       MOVQ AX, DI
+       MOVQ DX, SI
+
+       // r0 += 19×a1×b4
+       MOVQ   8(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r0 += 19×a2×b3
+       MOVQ   16(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r0 += 19×a3×b2
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   16(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r0 += 19×a4×b1
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   8(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r1 = a0×b1
+       MOVQ (CX), AX
+       MULQ 8(BX)
+       MOVQ AX, R9
+       MOVQ DX, R8
+
+       // r1 += a1×b0
+       MOVQ 8(CX), AX
+       MULQ (BX)
+       ADDQ AX, R9
+       ADCQ DX, R8
+
+       // r1 += 19×a2×b4
+       MOVQ   16(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, R9
+       ADCQ   DX, R8
+
+       // r1 += 19×a3×b3
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(BX)
+       ADDQ   AX, R9
+       ADCQ   DX, R8
+
+       // r1 += 19×a4×b2
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   16(BX)
+       ADDQ   AX, R9
+       ADCQ   DX, R8
+
+       // r2 = a0×b2
+       MOVQ (CX), AX
+       MULQ 16(BX)
+       MOVQ AX, R11
+       MOVQ DX, R10
+
+       // r2 += a1×b1
+       MOVQ 8(CX), AX
+       MULQ 8(BX)
+       ADDQ AX, R11
+       ADCQ DX, R10
+
+       // r2 += a2×b0
+       MOVQ 16(CX), AX
+       MULQ (BX)
+       ADDQ AX, R11
+       ADCQ DX, R10
+
+       // r2 += 19×a3×b4
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, R11
+       ADCQ   DX, R10
+
+       // r2 += 19×a4×b3
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(BX)
+       ADDQ   AX, R11
+       ADCQ   DX, R10
+
+       // r3 = a0×b3
+       MOVQ (CX), AX
+       MULQ 24(BX)
+       MOVQ AX, R13
+       MOVQ DX, R12
+
+       // r3 += a1×b2
+       MOVQ 8(CX), AX
+       MULQ 16(BX)
+       ADDQ AX, R13
+       ADCQ DX, R12
+
+       // r3 += a2×b1
+       MOVQ 16(CX), AX
+       MULQ 8(BX)
+       ADDQ AX, R13
+       ADCQ DX, R12
+
+       // r3 += a3×b0
+       MOVQ 24(CX), AX
+       MULQ (BX)
+       ADDQ AX, R13
+       ADCQ DX, R12
+
+       // r3 += 19×a4×b4
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, R13
+       ADCQ   DX, R12
+
+       // r4 = a0×b4
+       MOVQ (CX), AX
+       MULQ 32(BX)
+       MOVQ AX, R15
+       MOVQ DX, R14
+
+       // r4 += a1×b3
+       MOVQ 8(CX), AX
+       MULQ 24(BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // r4 += a2×b2
+       MOVQ 16(CX), AX
+       MULQ 16(BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // r4 += a3×b1
+       MOVQ 24(CX), AX
+       MULQ 8(BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // r4 += a4×b0
+       MOVQ 32(CX), AX
+       MULQ (BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // First reduction chain
+       MOVQ   $0x0007ffffffffffff, AX
+       SHLQ   $0x0d, DI, SI
+       SHLQ   $0x0d, R9, R8
+       SHLQ   $0x0d, R11, R10
+       SHLQ   $0x0d, R13, R12
+       SHLQ   $0x0d, R15, R14
+       ANDQ   AX, DI
+       IMUL3Q $0x13, R14, R14
+       ADDQ   R14, DI
+       ANDQ   AX, R9
+       ADDQ   SI, R9
+       ANDQ   AX, R11
+       ADDQ   R8, R11
+       ANDQ   AX, R13
+       ADDQ   R10, R13
+       ANDQ   AX, R15
+       ADDQ   R12, R15
+
+       // Second reduction chain (carryPropagate)
+       MOVQ   DI, SI
+       SHRQ   $0x33, SI
+       MOVQ   R9, R8
+       SHRQ   $0x33, R8
+       MOVQ   R11, R10
+       SHRQ   $0x33, R10
+       MOVQ   R13, R12
+       SHRQ   $0x33, R12
+       MOVQ   R15, R14
+       SHRQ   $0x33, R14
+       ANDQ   AX, DI
+       IMUL3Q $0x13, R14, R14
+       ADDQ   R14, DI
+       ANDQ   AX, R9
+       ADDQ   SI, R9
+       ANDQ   AX, R11
+       ADDQ   R8, R11
+       ANDQ   AX, R13
+       ADDQ   R10, R13
+       ANDQ   AX, R15
+       ADDQ   R12, R15
+
+       // Store output
+       MOVQ out+0(FP), AX
+       MOVQ DI, (AX)
+       MOVQ R9, 8(AX)
+       MOVQ R11, 16(AX)
+       MOVQ R13, 24(AX)
+       MOVQ R15, 32(AX)
+       RET
+
+// func feSquare(out *Element, a *Element)
+TEXT ·feSquare(SB), NOSPLIT, $0-16
+       MOVQ a+8(FP), CX
+
+       // r0 = l0×l0
+       MOVQ (CX), AX
+       MULQ (CX)
+       MOVQ AX, SI
+       MOVQ DX, BX
+
+       // r0 += 38×l1×l4
+       MOVQ   8(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, SI
+       ADCQ   DX, BX
+
+       // r0 += 38×l2×l3
+       MOVQ   16(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   24(CX)
+       ADDQ   AX, SI
+       ADCQ   DX, BX
+
+       // r1 = 2×l0×l1
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 8(CX)
+       MOVQ AX, R8
+       MOVQ DX, DI
+
+       // r1 += 38×l2×l4
+       MOVQ   16(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, R8
+       ADCQ   DX, DI
+
+       // r1 += 19×l3×l3
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(CX)
+       ADDQ   AX, R8
+       ADCQ   DX, DI
+
+       // r2 = 2×l0×l2
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 16(CX)
+       MOVQ AX, R10
+       MOVQ DX, R9
+
+       // r2 += l1×l1
+       MOVQ 8(CX), AX
+       MULQ 8(CX)
+       ADDQ AX, R10
+       ADCQ DX, R9
+
+       // r2 += 38×l3×l4
+       MOVQ   24(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, R10
+       ADCQ   DX, R9
+
+       // r3 = 2×l0×l3
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 24(CX)
+       MOVQ AX, R12
+       MOVQ DX, R11
+
+       // r3 += 2×l1×l2
+       MOVQ   8(CX), AX
+       IMUL3Q $0x02, AX, AX
+       MULQ   16(CX)
+       ADDQ   AX, R12
+       ADCQ   DX, R11
+
+       // r3 += 19×l4×l4
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, R12
+       ADCQ   DX, R11
+
+       // r4 = 2×l0×l4
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 32(CX)
+       MOVQ AX, R14
+       MOVQ DX, R13
+
+       // r4 += 2×l1×l3
+       MOVQ   8(CX), AX
+       IMUL3Q $0x02, AX, AX
+       MULQ   24(CX)
+       ADDQ   AX, R14
+       ADCQ   DX, R13
+
+       // r4 += l2×l2
+       MOVQ 16(CX), AX
+       MULQ 16(CX)
+       ADDQ AX, R14
+       ADCQ DX, R13
+
+       // First reduction chain
+       MOVQ   $0x0007ffffffffffff, AX
+       SHLQ   $0x0d, SI, BX
+       SHLQ   $0x0d, R8, DI
+       SHLQ   $0x0d, R10, R9
+       SHLQ   $0x0d, R12, R11
+       SHLQ   $0x0d, R14, R13
+       ANDQ   AX, SI
+       IMUL3Q $0x13, R13, R13
+       ADDQ   R13, SI
+       ANDQ   AX, R8
+       ADDQ   BX, R8
+       ANDQ   AX, R10
+       ADDQ   DI, R10
+       ANDQ   AX, R12
+       ADDQ   R9, R12
+       ANDQ   AX, R14
+       ADDQ   R11, R14
+
+       // Second reduction chain (carryPropagate)
+       MOVQ   SI, BX
+       SHRQ   $0x33, BX
+       MOVQ   R8, DI
+       SHRQ   $0x33, DI
+       MOVQ   R10, R9
+       SHRQ   $0x33, R9
+       MOVQ   R12, R11
+       SHRQ   $0x33, R11
+       MOVQ   R14, R13
+       SHRQ   $0x33, R13
+       ANDQ   AX, SI
+       IMUL3Q $0x13, R13, R13
+       ADDQ   R13, SI
+       ANDQ   AX, R8
+       ADDQ   BX, R8
+       ANDQ   AX, R10
+       ADDQ   DI, R10
+       ANDQ   AX, R12
+       ADDQ   R9, R12
+       ANDQ   AX, R14
+       ADDQ   R11, R14
+
+       // Store output
+       MOVQ out+0(FP), AX
+       MOVQ SI, (AX)
+       MOVQ R8, 8(AX)
+       MOVQ R10, 16(AX)
+       MOVQ R12, 24(AX)
+       MOVQ R14, 32(AX)
+       RET
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
new file mode 100644 (file)
index 0000000..ddb6c9b
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 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.
+
+//go:build !amd64 || !gc || purego
+// +build !amd64 !gc purego
+
+package field
+
+func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
+
+func feSquare(v, x *Element) { feSquareGeneric(v, x) }
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
new file mode 100644 (file)
index 0000000..af459ef
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright (c) 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.
+
+//go:build arm64 && gc && !purego
+// +build arm64,gc,!purego
+
+package field
+
+//go:noescape
+func carryPropagate(v *Element)
+
+func (v *Element) carryPropagate() *Element {
+       carryPropagate(v)
+       return v
+}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
new file mode 100644 (file)
index 0000000..5c91e45
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (c) 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.
+
+//go:build arm64 && gc && !purego
+// +build arm64,gc,!purego
+
+#include "textflag.h"
+
+// carryPropagate works exactly like carryPropagateGeneric and uses the
+// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
+// avoids loading R0-R4 twice and uses LDP and STP.
+//
+// See https://golang.org/issues/43145 for the main compiler issue.
+//
+// func carryPropagate(v *Element)
+TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
+       MOVD v+0(FP), R20
+
+       LDP 0(R20), (R0, R1)
+       LDP 16(R20), (R2, R3)
+       MOVD 32(R20), R4
+
+       AND $0x7ffffffffffff, R0, R10
+       AND $0x7ffffffffffff, R1, R11
+       AND $0x7ffffffffffff, R2, R12
+       AND $0x7ffffffffffff, R3, R13
+       AND $0x7ffffffffffff, R4, R14
+
+       ADD R0>>51, R11, R11
+       ADD R1>>51, R12, R12
+       ADD R2>>51, R13, R13
+       ADD R3>>51, R14, R14
+       // R4>>51 * 19 + R10 -> R10
+       LSR $51, R4, R21
+       MOVD $19, R22
+       MADD R22, R10, R21, R10
+
+       STP (R10, R11), 0(R20)
+       STP (R12, R13), 16(R20)
+       MOVD R14, 32(R20)
+
+       RET
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
new file mode 100644 (file)
index 0000000..234a5b2
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright (c) 2021 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:build !arm64 || !gc || purego
+// +build !arm64 !gc purego
+
+package field
+
+func (v *Element) carryPropagate() *Element {
+       return v.carryPropagateGeneric()
+}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go b/src/vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go
new file mode 100644 (file)
index 0000000..7b5b78c
--- /dev/null
@@ -0,0 +1,264 @@
+// Copyright (c) 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 field
+
+import "math/bits"
+
+// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
+// bits.Mul64 and bits.Add64 intrinsics.
+type uint128 struct {
+       lo, hi uint64
+}
+
+// mul64 returns a * b.
+func mul64(a, b uint64) uint128 {
+       hi, lo := bits.Mul64(a, b)
+       return uint128{lo, hi}
+}
+
+// addMul64 returns v + a * b.
+func addMul64(v uint128, a, b uint64) uint128 {
+       hi, lo := bits.Mul64(a, b)
+       lo, c := bits.Add64(lo, v.lo, 0)
+       hi, _ = bits.Add64(hi, v.hi, c)
+       return uint128{lo, hi}
+}
+
+// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
+func shiftRightBy51(a uint128) uint64 {
+       return (a.hi << (64 - 51)) | (a.lo >> 51)
+}
+
+func feMulGeneric(v, a, b *Element) {
+       a0 := a.l0
+       a1 := a.l1
+       a2 := a.l2
+       a3 := a.l3
+       a4 := a.l4
+
+       b0 := b.l0
+       b1 := b.l1
+       b2 := b.l2
+       b3 := b.l3
+       b4 := b.l4
+
+       // Limb multiplication works like pen-and-paper columnar multiplication, but
+       // with 51-bit limbs instead of digits.
+       //
+       //                          a4   a3   a2   a1   a0  x
+       //                          b4   b3   b2   b1   b0  =
+       //                         ------------------------
+       //                        a4b0 a3b0 a2b0 a1b0 a0b0  +
+       //                   a4b1 a3b1 a2b1 a1b1 a0b1       +
+       //              a4b2 a3b2 a2b2 a1b2 a0b2            +
+       //         a4b3 a3b3 a2b3 a1b3 a0b3                 +
+       //    a4b4 a3b4 a2b4 a1b4 a0b4                      =
+       //   ----------------------------------------------
+       //      r8   r7   r6   r5   r4   r3   r2   r1   r0
+       //
+       // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
+       // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
+       // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
+       //
+       // Reduction can be carried out simultaneously to multiplication. For
+       // example, we do not compute r5: whenever the result of a multiplication
+       // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
+       //
+       //            a4b0    a3b0    a2b0    a1b0    a0b0  +
+       //            a3b1    a2b1    a1b1    a0b1 19×a4b1  +
+       //            a2b2    a1b2    a0b2 19×a4b2 19×a3b2  +
+       //            a1b3    a0b3 19×a4b3 19×a3b3 19×a2b3  +
+       //            a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4  =
+       //           --------------------------------------
+       //              r4      r3      r2      r1      r0
+       //
+       // Finally we add up the columns into wide, overlapping limbs.
+
+       a1_19 := a1 * 19
+       a2_19 := a2 * 19
+       a3_19 := a3 * 19
+       a4_19 := a4 * 19
+
+       // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+       r0 := mul64(a0, b0)
+       r0 = addMul64(r0, a1_19, b4)
+       r0 = addMul64(r0, a2_19, b3)
+       r0 = addMul64(r0, a3_19, b2)
+       r0 = addMul64(r0, a4_19, b1)
+
+       // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
+       r1 := mul64(a0, b1)
+       r1 = addMul64(r1, a1, b0)
+       r1 = addMul64(r1, a2_19, b4)
+       r1 = addMul64(r1, a3_19, b3)
+       r1 = addMul64(r1, a4_19, b2)
+
+       // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
+       r2 := mul64(a0, b2)
+       r2 = addMul64(r2, a1, b1)
+       r2 = addMul64(r2, a2, b0)
+       r2 = addMul64(r2, a3_19, b4)
+       r2 = addMul64(r2, a4_19, b3)
+
+       // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
+       r3 := mul64(a0, b3)
+       r3 = addMul64(r3, a1, b2)
+       r3 = addMul64(r3, a2, b1)
+       r3 = addMul64(r3, a3, b0)
+       r3 = addMul64(r3, a4_19, b4)
+
+       // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+       r4 := mul64(a0, b4)
+       r4 = addMul64(r4, a1, b3)
+       r4 = addMul64(r4, a2, b2)
+       r4 = addMul64(r4, a3, b1)
+       r4 = addMul64(r4, a4, b0)
+
+       // After the multiplication, we need to reduce (carry) the five coefficients
+       // to obtain a result with limbs that are at most slightly larger than 2⁵¹,
+       // to respect the Element invariant.
+       //
+       // Overall, the reduction works the same as carryPropagate, except with
+       // wider inputs: we take the carry for each coefficient by shifting it right
+       // by 51, and add it to the limb above it. The top carry is multiplied by 19
+       // according to the reduction identity and added to the lowest limb.
+       //
+       // The largest coefficient (r0) will be at most 111 bits, which guarantees
+       // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
+       //
+       //     r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+       //     r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
+       //     r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
+       //     r0 < 2⁷ × 2⁵² × 2⁵²
+       //     r0 < 2¹¹¹
+       //
+       // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
+       // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
+       // allows us to easily apply the reduction identity.
+       //
+       //     r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+       //     r4 < 5 × 2⁵² × 2⁵²
+       //     r4 < 2¹⁰⁷
+       //
+
+       c0 := shiftRightBy51(r0)
+       c1 := shiftRightBy51(r1)
+       c2 := shiftRightBy51(r2)
+       c3 := shiftRightBy51(r3)
+       c4 := shiftRightBy51(r4)
+
+       rr0 := r0.lo&maskLow51Bits + c4*19
+       rr1 := r1.lo&maskLow51Bits + c0
+       rr2 := r2.lo&maskLow51Bits + c1
+       rr3 := r3.lo&maskLow51Bits + c2
+       rr4 := r4.lo&maskLow51Bits + c3
+
+       // Now all coefficients fit into 64-bit registers but are still too large to
+       // be passed around as a Element. We therefore do one last carry chain,
+       // where the carries will be small enough to fit in the wiggle room above 2⁵¹.
+       *v = Element{rr0, rr1, rr2, rr3, rr4}
+       v.carryPropagate()
+}
+
+func feSquareGeneric(v, a *Element) {
+       l0 := a.l0
+       l1 := a.l1
+       l2 := a.l2
+       l3 := a.l3
+       l4 := a.l4
+
+       // Squaring works precisely like multiplication above, but thanks to its
+       // symmetry we get to group a few terms together.
+       //
+       //                          l4   l3   l2   l1   l0  x
+       //                          l4   l3   l2   l1   l0  =
+       //                         ------------------------
+       //                        l4l0 l3l0 l2l0 l1l0 l0l0  +
+       //                   l4l1 l3l1 l2l1 l1l1 l0l1       +
+       //              l4l2 l3l2 l2l2 l1l2 l0l2            +
+       //         l4l3 l3l3 l2l3 l1l3 l0l3                 +
+       //    l4l4 l3l4 l2l4 l1l4 l0l4                      =
+       //   ----------------------------------------------
+       //      r8   r7   r6   r5   r4   r3   r2   r1   r0
+       //
+       //            l4l0    l3l0    l2l0    l1l0    l0l0  +
+       //            l3l1    l2l1    l1l1    l0l1 19×l4l1  +
+       //            l2l2    l1l2    l0l2 19×l4l2 19×l3l2  +
+       //            l1l3    l0l3 19×l4l3 19×l3l3 19×l2l3  +
+       //            l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4  =
+       //           --------------------------------------
+       //              r4      r3      r2      r1      r0
+       //
+       // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
+       // only three Mul64 and four Add64, instead of five and eight.
+
+       l0_2 := l0 * 2
+       l1_2 := l1 * 2
+
+       l1_38 := l1 * 38
+       l2_38 := l2 * 38
+       l3_38 := l3 * 38
+
+       l3_19 := l3 * 19
+       l4_19 := l4 * 19
+
+       // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
+       r0 := mul64(l0, l0)
+       r0 = addMul64(r0, l1_38, l4)
+       r0 = addMul64(r0, l2_38, l3)
+
+       // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
+       r1 := mul64(l0_2, l1)
+       r1 = addMul64(r1, l2_38, l4)
+       r1 = addMul64(r1, l3_19, l3)
+
+       // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
+       r2 := mul64(l0_2, l2)
+       r2 = addMul64(r2, l1, l1)
+       r2 = addMul64(r2, l3_38, l4)
+
+       // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
+       r3 := mul64(l0_2, l3)
+       r3 = addMul64(r3, l1_2, l2)
+       r3 = addMul64(r3, l4_19, l4)
+
+       // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
+       r4 := mul64(l0_2, l4)
+       r4 = addMul64(r4, l1_2, l3)
+       r4 = addMul64(r4, l2, l2)
+
+       c0 := shiftRightBy51(r0)
+       c1 := shiftRightBy51(r1)
+       c2 := shiftRightBy51(r2)
+       c3 := shiftRightBy51(r3)
+       c4 := shiftRightBy51(r4)
+
+       rr0 := r0.lo&maskLow51Bits + c4*19
+       rr1 := r1.lo&maskLow51Bits + c0
+       rr2 := r2.lo&maskLow51Bits + c1
+       rr3 := r3.lo&maskLow51Bits + c2
+       rr4 := r4.lo&maskLow51Bits + c3
+
+       *v = Element{rr0, rr1, rr2, rr3, rr4}
+       v.carryPropagate()
+}
+
+// carryPropagate brings the limbs below 52 bits by applying the reduction
+// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. TODO inline
+func (v *Element) carryPropagateGeneric() *Element {
+       c0 := v.l0 >> 51
+       c1 := v.l1 >> 51
+       c2 := v.l2 >> 51
+       c3 := v.l3 >> 51
+       c4 := v.l4 >> 51
+
+       v.l0 = v.l0&maskLow51Bits + c4*19
+       v.l1 = v.l1&maskLow51Bits + c0
+       v.l2 = v.l2&maskLow51Bits + c1
+       v.l3 = v.l3&maskLow51Bits + c2
+       v.l4 = v.l4&maskLow51Bits + c3
+
+       return v
+}
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint b/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint
new file mode 100644 (file)
index 0000000..e3685f9
--- /dev/null
@@ -0,0 +1 @@
+b0c49ae9f59d233526f8934262c5bbbe14d4358d
diff --git a/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh b/src/vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh
new file mode 100644 (file)
index 0000000..1ba22a8
--- /dev/null
@@ -0,0 +1,19 @@
+#! /bin/bash
+set -euo pipefail
+
+cd "$(git rev-parse --show-toplevel)"
+
+STD_PATH=src/crypto/ed25519/internal/edwards25519/field
+LOCAL_PATH=curve25519/internal/field
+LAST_SYNC_REF=$(cat $LOCAL_PATH/sync.checkpoint)
+
+git fetch https://go.googlesource.com/go master
+
+if git diff --quiet $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH; then
+    echo "No changes."
+else
+    NEW_REF=$(git rev-parse FETCH_HEAD | tee $LOCAL_PATH/sync.checkpoint)
+    echo "Applying changes from $LAST_SYNC_REF to $NEW_REF..."
+    git diff $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH | \
+        git apply -3 --directory=$LOCAL_PATH
+fi
index 2cb03731408c96bfca262d0801b57aee9d2ca85a..1d74f0f88189b152f06e8f581474a70a8b4a8b0c 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build gc && !purego
 // +build gc,!purego
 
 #include "textflag.h"
index 3cede539dc40d7c2136a67e03295f2c05dd950aa..58422aad230570fa1b3292a95e1332d50a965042 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build gc && !purego
 // +build gc,!purego
 
 #include "textflag.h"
index bdd882c606def8a9fdd42aeb774327cb23dac70c..69c64f84217dec5b6a04da680c76d433bcf8f342 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:build gc && !purego
 // +build gc,!purego
 
 #include "textflag.h"
index 4f6ad968a247e4de7ea06e991164e3197ba02120..1898ed0fad5decd0d030bc927412a00c014c6dc4 100644 (file)
@@ -422,5 +422,9 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
                        b = b[l:]
                }
        }
+       // The only remaining bytes in b should be alignment.
+       // However, under some circumstances DragonFly BSD appears to put
+       // more addresses in the message than are indicated in the address
+       // bitmask, so don't check for this.
        return as[:], nil
 }
index d53bb7f9b13108c9c1367da1874897afe5fb46e4..456a8363fec9dd708175a1f09ea9cfcc35520b31 100644 (file)
@@ -53,7 +53,7 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) {
                if w, ok := wireFormats[int(b[3])]; !ok {
                        nskips++
                } else {
-                       m, err := w.parse(typ, b)
+                       m, err := w.parse(typ, b[:l])
                        if err != nil {
                                return nil, err
                        }
index fe91be1249c5c3cd4bab18b5e25181e11fe0284a..3599601740c267d459db3f453a04d74e8e045880 100644 (file)
@@ -134,9 +134,6 @@ func probeRoutingStack() (int, map[int]*wireFormat) {
                } else {
                        ifm.bodyOff = sizeofIfMsghdrFreeBSD11
                }
-               if rel >= 1102000 { // see https://github.com/freebsd/freebsd/commit/027c7f4d66ff8d8c4a46c3665a5ee7d6d8462034#diff-ad4e5b7f1449ea3fc87bc97280de145b
-                       align = wordSize
-               }
        }
        rtm.parse = rtm.parseRouteMessage
        ifm.parse = ifm.parseInterfaceMessage
index abbec2d44bfbe30fa5dda7fd33da3cbf9bdc9523..b56886f261631b85368088313b20e8ad4a6e68ff 100644 (file)
@@ -56,6 +56,7 @@ var X86 struct {
        HasAVX512BF16       bool // Advanced vector extension 512 BFloat16 Instructions
        HasBMI1             bool // Bit manipulation instruction set 1
        HasBMI2             bool // Bit manipulation instruction set 2
+       HasCX16             bool // Compare and exchange 16 Bytes
        HasERMS             bool // Enhanced REP for MOVSB and STOSB
        HasFMA              bool // Fused-multiply-add instructions
        HasOSXSAVE          bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
index 54ca4667fb8ea05bc0965e04e631cbe52541ab09..5ea287b7eca3a5ec762a44f2f94f33adc4b68111 100644 (file)
@@ -39,6 +39,7 @@ func initOptions() {
                {Name: "avx512bf16", Feature: &X86.HasAVX512BF16},
                {Name: "bmi1", Feature: &X86.HasBMI1},
                {Name: "bmi2", Feature: &X86.HasBMI2},
+               {Name: "cx16", Feature: &X86.HasCX16},
                {Name: "erms", Feature: &X86.HasERMS},
                {Name: "fma", Feature: &X86.HasFMA},
                {Name: "osxsave", Feature: &X86.HasOSXSAVE},
@@ -73,6 +74,7 @@ func archInit() {
        X86.HasPCLMULQDQ = isSet(1, ecx1)
        X86.HasSSSE3 = isSet(9, ecx1)
        X86.HasFMA = isSet(12, ecx1)
+       X86.HasCX16 = isSet(13, ecx1)
        X86.HasSSE41 = isSet(19, ecx1)
        X86.HasSSE42 = isSet(20, ecx1)
        X86.HasPOPCNT = isSet(23, ecx1)
index ff01db5cdc77fe99287db108845ae5403a729678..770a08e1fb4761a4f2d051a03d32731f9ca22e0b 100644 (file)
@@ -1,14 +1,15 @@
-# golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e
+# golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
 ## explicit; go 1.17
 golang.org/x/crypto/chacha20
 golang.org/x/crypto/chacha20poly1305
 golang.org/x/crypto/cryptobyte
 golang.org/x/crypto/cryptobyte/asn1
 golang.org/x/crypto/curve25519
+golang.org/x/crypto/curve25519/internal/field
 golang.org/x/crypto/hkdf
 golang.org/x/crypto/internal/subtle
 golang.org/x/crypto/poly1305
-# golang.org/x/net v0.0.0-20210510120150-4163338589ed
+# golang.org/x/net v0.0.0-20211005215030-d2e5035098b3
 ## explicit; go 1.17
 golang.org/x/net/dns/dnsmessage
 golang.org/x/net/http/httpguts
@@ -18,10 +19,10 @@ golang.org/x/net/idna
 golang.org/x/net/lif
 golang.org/x/net/nettest
 golang.org/x/net/route
-# golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744
+# golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac
 ## explicit; go 1.17
 golang.org/x/sys/cpu
-# golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f
+# golang.org/x/text v0.3.7
 ## explicit; go 1.17
 golang.org/x/text/secure/bidirule
 golang.org/x/text/transform
diff --git a/test/abi/method_wrapper.go b/test/abi/method_wrapper.go
new file mode 100644 (file)
index 0000000..7aa262f
--- /dev/null
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S int
+
+type T struct {
+       a int
+       S
+}
+
+//go:noinline
+func (s *S) M(a int, x [2]int, b float64, y [2]float64) (S, int, [2]int, float64, [2]float64) {
+       return *s, a, x, b, y
+}
+
+var s S = 42
+var t = &T{S: s}
+
+var fn = (*T).M // force a method wrapper
+
+func main() {
+       a := 123
+       x := [2]int{456, 789}
+       b := 1.2
+       y := [2]float64{3.4, 5.6}
+       s1, a1, x1, b1, y1 := fn(t, a, x, b, y)
+       if a1 != a || x1 != x || b1 != b || y1 != y || s1 != s {
+               panic("FAIL")
+       }
+}
diff --git a/test/asmhdr.dir/main.go b/test/asmhdr.dir/main.go
new file mode 100644 (file)
index 0000000..808b5de
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2021 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 "unsafe"
+
+const (
+       smallInt = 42
+
+       // For bigInt, we use a value that's too big for an int64, but still
+       // fits in uint64. go/constant uses a different representation for
+       // values larger than int64, but the cmd/asm parser can't parse
+       // anything bigger than a uint64.
+       bigInt = 0xffffffffffffffff
+
+       stringVal = "test"
+)
+
+var (
+       smallIntAsm int64
+       bigIntAsm   uint64
+       stringAsm   [len(stringVal)]byte
+)
+
+type typ struct {
+       a uint64
+       b [100]uint8
+       c uint8
+}
+
+var (
+       typSize uint64
+
+       typA, typB, typC uint64
+)
+
+func main() {
+       if smallInt != smallIntAsm {
+               println("smallInt", smallInt, "!=", smallIntAsm)
+       }
+       if bigInt != bigIntAsm {
+               println("bigInt", uint64(bigInt), "!=", bigIntAsm)
+       }
+       if stringVal != string(stringAsm[:]) {
+               println("stringVal", stringVal, "!=", string(stringAsm[:]))
+       }
+
+       // We also include boolean consts in go_asm.h, but they're
+       // defined to be "true" or "false", and it's not clear how to
+       // use that in assembly.
+
+       if want := unsafe.Sizeof(typ{}); want != uintptr(typSize) {
+               println("typSize", want, "!=", typSize)
+       }
+       if want := unsafe.Offsetof(typ{}.a); want != uintptr(typA) {
+               println("typA", want, "!=", typA)
+       }
+       if want := unsafe.Offsetof(typ{}.b); want != uintptr(typB) {
+               println("typB", want, "!=", typB)
+       }
+       if want := unsafe.Offsetof(typ{}.c); want != uintptr(typC) {
+               println("typC", want, "!=", typC)
+       }
+}
diff --git a/test/asmhdr.dir/main.s b/test/asmhdr.dir/main.s
new file mode 100644 (file)
index 0000000..7e2d8e7
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2021 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 "go_asm.h"
+#define RODATA 8
+
+DATA ·smallIntAsm(SB)/8, $const_smallInt
+GLOBL ·smallIntAsm(SB),RODATA,$8
+
+DATA ·bigIntAsm(SB)/8, $const_bigInt
+GLOBL ·bigIntAsm(SB),RODATA,$8
+
+DATA ·stringAsm(SB)/4, $const_stringVal
+GLOBL ·stringAsm(SB),RODATA,$4
+
+DATA ·typSize(SB)/8, $typ__size
+GLOBL ·typSize(SB),RODATA,$8
+
+DATA ·typA(SB)/8, $typ_a
+GLOBL ·typA(SB),RODATA,$8
+
+DATA ·typB(SB)/8, $typ_b
+GLOBL ·typB(SB),RODATA,$8
+
+DATA ·typC(SB)/8, $typ_c
+GLOBL ·typC(SB),RODATA,$8
diff --git a/test/asmhdr.go b/test/asmhdr.go
new file mode 100644 (file)
index 0000000..772f98e
--- /dev/null
@@ -0,0 +1,9 @@
+// buildrundir
+
+// Copyright 2021 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 the -asmhdr output of the compiler.
+
+package ignored
index eb0f338036c3c8e7907b670265cc361f0007186d..00841d52ae27db5c9be6f59fefd9512103c26e8e 100644 (file)
@@ -84,6 +84,38 @@ func NegAddFromConstNeg(a int) int {
        return c
 }
 
+func SubSubNegSimplify(a, b int) int {
+       // amd64:"NEGQ"
+       // ppc64:"NEG"
+       // ppc64le:"NEG"
+       r := (a - b) - a
+       return r
+}
+
+func SubAddSimplify(a, b int) int {
+       // amd64:-"SUBQ",-"ADDQ"
+       // ppc64:-"SUB",-"ADD"
+       // ppc64le:-"SUB",-"ADD"
+       r := a + (b - a)
+       return r
+}
+
+func SubAddNegSimplify(a, b int) int {
+       // amd64:"NEGQ",-"ADDQ",-"SUBQ"
+       // ppc64:"NEG",-"ADD",-"SUB"
+       // ppc64le:"NEG",-"ADD",-"SUB"
+       r := a - (b + a)
+       return r
+}
+
+func AddAddSubSimplify(a, b, c int) int {
+       // amd64:-"SUBQ"
+       // ppc64:-"SUB"
+       // ppc64le:-"SUB"
+       r := a + (b + (c - a))
+       return r
+}
+
 // -------------------- //
 //    Multiplication    //
 // -------------------- //
@@ -135,30 +167,40 @@ func MulMemSrc(a []uint32, b []float32) {
 func MergeMuls1(n int) int {
        // amd64:"IMUL3Q\t[$]46"
        // 386:"IMUL3L\t[$]46"
+       // ppc64le:"MULLD\t[$]46"
+       // ppc64:"MULLD\t[$]46"
        return 15*n + 31*n // 46n
 }
 
 func MergeMuls2(n int) int {
        // amd64:"IMUL3Q\t[$]23","(ADDQ\t[$]29)|(LEAQ\t29)"
        // 386:"IMUL3L\t[$]23","ADDL\t[$]29"
+       // ppc64le/power9:"MADDLD",-"MULLD\t[$]23",-"ADD\t[$]29"
+        // ppc64le/power8:"MULLD\t[$]23","ADD\t[$]29"
        return 5*n + 7*(n+1) + 11*(n+2) // 23n + 29
 }
 
 func MergeMuls3(a, n int) int {
        // amd64:"ADDQ\t[$]19",-"IMULQ\t[$]19"
        // 386:"ADDL\t[$]19",-"IMULL\t[$]19"
+       // ppc64:"ADD\t[$]19",-"MULLD\t[$]19"
+       // ppc64le:"ADD\t[$]19",-"MULLD\t[$]19"
        return a*n + 19*n // (a+19)n
 }
 
 func MergeMuls4(n int) int {
        // amd64:"IMUL3Q\t[$]14"
        // 386:"IMUL3L\t[$]14"
+       // ppc64:"MULLD\t[$]14"
+       // ppc64le:"MULLD\t[$]14"
        return 23*n - 9*n // 14n
 }
 
 func MergeMuls5(a, n int) int {
        // amd64:"ADDQ\t[$]-19",-"IMULQ\t[$]19"
        // 386:"ADDL\t[$]-19",-"IMULL\t[$]19"
+       // ppc64:"ADD\t[$]-19",-"MULLD\t[$]19"
+       // ppc64le:"ADD\t[$]-19",-"MULLD\t[$]19"
        return a*n - 19*n // (a-19)n
 }
 
@@ -217,7 +259,7 @@ func FloatDivs(a []float32) float32 {
 
 func Pow2Mods(n1 uint, n2 int) (uint, int) {
        // 386:"ANDL\t[$]31",-"DIVL"
-       // amd64:"ANDQ\t[$]31",-"DIVQ"
+       // amd64:"ANDL\t[$]31",-"DIVQ"
        // arm:"AND\t[$]31",-".*udiv"
        // arm64:"AND\t[$]31",-"UDIV"
        // ppc64:"ANDCC\t[$]31"
@@ -428,7 +470,7 @@ func LenDiv2(s string) int {
 
 func LenMod1(a []int) int {
        // 386:"ANDL\t[$]1023"
-       // amd64:"ANDQ\t[$]1023"
+       // amd64:"ANDL\t[$]1023"
        // arm64:"AND\t[$]1023",-"SDIV"
        // arm/6:"AND",-".*udiv"
        // arm/7:"BFC",-".*udiv",-"AND"
@@ -439,7 +481,7 @@ func LenMod1(a []int) int {
 
 func LenMod2(s string) int {
        // 386:"ANDL\t[$]2047"
-       // amd64:"ANDQ\t[$]2047"
+       // amd64:"ANDL\t[$]2047"
        // arm64:"AND\t[$]2047",-"SDIV"
        // arm/6:"AND",-".*udiv"
        // arm/7:"BFC",-".*udiv",-"AND"
@@ -460,7 +502,7 @@ func CapDiv(a []int) int {
 
 func CapMod(a []int) int {
        // 386:"ANDL\t[$]4095"
-       // amd64:"ANDQ\t[$]4095"
+       // amd64:"ANDL\t[$]4095"
        // arm64:"AND\t[$]4095",-"SDIV"
        // arm/6:"AND",-".*udiv"
        // arm/7:"BFC",-".*udiv",-"AND"
@@ -483,6 +525,8 @@ func MULA(a, b, c uint32) (uint32, uint32, uint32) {
        r1 := c*79 + a
        // arm:`ADD`,-`MULA`,-`MUL\s`
        // arm64:`ADD`,-`MADD`,-`MULW`
+       // ppc64:`ADD`,-`MULLD`
+       // ppc64le:`ADD`,-`MULLD`
        r2 := b*64 + c
        return r0, r1, r2
 }
@@ -498,6 +542,8 @@ func MULS(a, b, c uint32) (uint32, uint32, uint32) {
        r1 := a - c*79
        // arm/7:`SUB`,-`MULS`,-`MUL\s`
        // arm64:`SUB`,-`MSUBW`,-`MULW`
+       // ppc64:`SUB`,-`MULLD`
+       // ppc64le:`SUB`,-`MULLD`
        r2 := c - b*64
        return r0, r1, r2
 }
@@ -526,12 +572,20 @@ func divInt(v int64) int64 {
 // "(z + C) -x -> C + (z - x)" can optimize the following cases.
 func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) {
        // arm64:"SUB","ADD\t[$]2"
+        // ppc64:"SUB","ADD\t[$]2"
+        // ppc64le:"SUB","ADD\t[$]2"
        r0 := (i0 + 3) - (j0 + 1)
        // arm64:"SUB","SUB\t[$]4"
+        // ppc64:"SUB","ADD\t[$]-4"
+        // ppc64le:"SUB","ADD\t[$]-4"
        r1 := (i1 - 3) - (j1 + 1)
        // arm64:"SUB","ADD\t[$]4"
+        // ppc64:"SUB","ADD\t[$]4"
+        // ppc64le:"SUB","ADD\t[$]4"
        r2 := (i2 + 3) - (j2 - 1)
        // arm64:"SUB","SUB\t[$]2"
+       // ppc64:"SUB","ADD\t[$]-2"
+       // ppc64le:"SUB","ADD\t[$]-2"
        r3 := (i3 - 3) - (j3 - 1)
        return r0, r1, r2, r3
 }
@@ -540,14 +594,20 @@ func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) {
 // "(C - z) - x -> C - (z + x)" can optimize the following cases.
 func constantFold2(i0, j0, i1, j1 int) (int, int) {
        // arm64:"ADD","MOVD\t[$]2","SUB"
+       // ppc64le: `SUBC\tR[0-9]+,\s[$]2,\sR`
+       // ppc64: `SUBC\tR[0-9]+,\s[$]2,\sR`
        r0 := (3 - i0) - (j0 + 1)
        // arm64:"ADD","MOVD\t[$]4","SUB"
+       // ppc64le: `SUBC\tR[0-9]+,\s[$]4,\sR`
+       // ppc64: `SUBC\tR[0-9]+,\s[$]4,\sR`
        r1 := (3 - i1) - (j1 - 1)
        return r0, r1
 }
 
 func constantFold3(i, j int) int {
        // arm64: "MOVD\t[$]30","MUL",-"ADD",-"LSL"
+        // ppc64:"MULLD\t[$]30","MULLD"
+        // ppc64le:"MULLD\t[$]30","MULLD"
        r := (5 * i) * (6 * j)
        return r
 }
index 0fe6799ec1d68e427e204401da2ebe2a958be05b..8327da6cf8b414f3fbd6daf3d35ff0457704eef0 100644 (file)
@@ -77,11 +77,13 @@ func bfxil2(x, y uint64) uint64 {
 }
 
 // sbfiz
+// merge shifts into sbfiz: (x << lc) >> rc && lc > rc.
 func sbfiz1(x int64) int64 {
        // arm64:"SBFIZ\t[$]1, R[0-9]+, [$]60",-"LSL",-"ASR"
        return (x << 4) >> 3
 }
 
+// merge shift and sign-extension into sbfiz.
 func sbfiz2(x int32) int64 {
        return int64(x << 3) // arm64:"SBFIZ\t[$]3, R[0-9]+, [$]29",-"LSL"
 }
@@ -94,12 +96,27 @@ func sbfiz4(x int8) int64 {
        return int64(x << 3) // arm64:"SBFIZ\t[$]3, R[0-9]+, [$]5",-"LSL"
 }
 
+// sbfiz combinations.
+// merge shift with sbfiz into sbfiz.
 func sbfiz5(x int32) int32 {
        // arm64:"SBFIZ\t[$]1, R[0-9]+, [$]28",-"LSL",-"ASR"
        return (x << 4) >> 3
 }
 
+func sbfiz6(x int16) int64 {
+       return int64(x+1) << 3 // arm64:"SBFIZ\t[$]3, R[0-9]+, [$]16",-"LSL"
+}
+
+func sbfiz7(x int8) int64 {
+       return int64(x+1) << 62 // arm64:"SBFIZ\t[$]62, R[0-9]+, [$]2",-"LSL"
+}
+
+func sbfiz8(x int32) int64 {
+       return int64(x+1) << 40 // arm64:"SBFIZ\t[$]40, R[0-9]+, [$]24",-"LSL"
+}
+
 // sbfx
+// merge shifts into sbfx: (x << lc) >> rc && lc <= rc.
 func sbfx1(x int64) int64 {
        return (x << 3) >> 4 // arm64:"SBFX\t[$]1, R[0-9]+, [$]60",-"LSL",-"ASR"
 }
@@ -108,6 +125,7 @@ func sbfx2(x int64) int64 {
        return (x << 60) >> 60 // arm64:"SBFX\tZR, R[0-9]+, [$]4",-"LSL",-"ASR"
 }
 
+//  merge shift and sign-extension into sbfx.
 func sbfx3(x int32) int64 {
        return int64(x) >> 3 // arm64:"SBFX\t[$]3, R[0-9]+, [$]29",-"ASR"
 }
@@ -120,123 +138,189 @@ func sbfx5(x int8) int64 {
        return int64(x) >> 3 // arm64:"SBFX\t[$]3, R[0-9]+, [$]5",-"ASR"
 }
 
-func sbfx6(x int32) int32 {
+func sbfx6(x int32) int64 {
+       return int64(x >> 30) // arm64:"SBFX\t[$]30, R[0-9]+, [$]2"
+}
+
+func sbfx7(x int16) int64 {
+       return int64(x >> 10) // arm64:"SBFX\t[$]10, R[0-9]+, [$]6"
+}
+
+func sbfx8(x int8) int64 {
+       return int64(x >> 5) // arm64:"SBFX\t[$]5, R[0-9]+, [$]3"
+}
+
+// sbfx combinations.
+// merge shifts with sbfiz into sbfx.
+func sbfx9(x int32) int32 {
        return (x << 3) >> 4 // arm64:"SBFX\t[$]1, R[0-9]+, [$]28",-"LSL",-"ASR"
 }
 
-// ubfiz
-func ubfiz1(x uint64) uint64 {
-       // arm64:"UBFIZ\t[$]3, R[0-9]+, [$]12",-"LSL",-"AND"
-       // s390x:"RISBGZ\t[$]49, [$]60, [$]3,",-"SLD",-"AND"
-       return (x & 0xfff) << 3
+// merge sbfx and sign-extension into sbfx.
+func sbfx10(x int32) int64 {
+       c := x + 5
+       return int64(c >> 20) // arm64"SBFX\t[$]20, R[0-9]+, [$]12",-"MOVW\tR[0-9]+, R[0-9]+"
 }
 
-func ubfiz2(x uint64) uint64 {
-       // arm64:"UBFIZ\t[$]4, R[0-9]+, [$]12",-"LSL",-"AND"
-       // s390x:"RISBGZ\t[$]48, [$]59, [$]4,",-"SLD",-"AND"
-       return (x << 4) & 0xfff0
+// ubfiz
+// merge shifts into ubfiz: (x<<lc)>>rc && lc>rc
+func ubfiz1(x uint64) uint64 {
+       // arm64:"UBFIZ\t[$]1, R[0-9]+, [$]60",-"LSL",-"LSR"
+       // s390x:"RISBGZ\t[$]3, [$]62, [$]1, ",-"SLD",-"SRD"
+       return (x << 4) >> 3
 }
 
-func ubfiz3(x uint32) uint64 {
+// merge shift and zero-extension into ubfiz.
+func ubfiz2(x uint32) uint64 {
        return uint64(x+1) << 3 // arm64:"UBFIZ\t[$]3, R[0-9]+, [$]32",-"LSL"
 }
 
-func ubfiz4(x uint16) uint64 {
+func ubfiz3(x uint16) uint64 {
        return uint64(x+1) << 3 // arm64:"UBFIZ\t[$]3, R[0-9]+, [$]16",-"LSL"
 }
 
-func ubfiz5(x uint8) uint64 {
+func ubfiz4(x uint8) uint64 {
        return uint64(x+1) << 3 // arm64:"UBFIZ\t[$]3, R[0-9]+, [$]8",-"LSL"
 }
 
-func ubfiz6(x uint64) uint64 {
-       // arm64:"UBFIZ\t[$]1, R[0-9]+, [$]60",-"LSL",-"LSR"
-       // s390x:"RISBGZ\t[$]3, [$]62, [$]1, ",-"SLD",-"SRD"
-       return (x << 4) >> 3
+func ubfiz5(x uint8) uint64 {
+       return uint64(x) << 60 // arm64:"UBFIZ\t[$]60, R[0-9]+, [$]4",-"LSL"
+}
+
+func ubfiz6(x uint32) uint64 {
+       return uint64(x << 30) // arm64:"UBFIZ\t[$]30, R[0-9]+, [$]2",
+}
+
+func ubfiz7(x uint16) uint64 {
+       return uint64(x << 10) // arm64:"UBFIZ\t[$]10, R[0-9]+, [$]6",
+}
+
+func ubfiz8(x uint8) uint64 {
+       return uint64(x << 7) // arm64:"UBFIZ\t[$]7, R[0-9]+, [$]1",
+}
+
+// merge ANDconst into ubfiz.
+func ubfiz9(x uint64) uint64 {
+       // arm64:"UBFIZ\t[$]3, R[0-9]+, [$]12",-"LSL",-"AND"
+       // s390x:"RISBGZ\t[$]49, [$]60, [$]3,",-"SLD",-"AND"
+       return (x & 0xfff) << 3
+}
+
+func ubfiz10(x uint64) uint64 {
+       // arm64:"UBFIZ\t[$]4, R[0-9]+, [$]12",-"LSL",-"AND"
+       // s390x:"RISBGZ\t[$]48, [$]59, [$]4,",-"SLD",-"AND"
+       return (x << 4) & 0xfff0
 }
 
-func ubfiz7(x uint32) uint32 {
+// ubfiz combinations
+func ubfiz11(x uint32) uint32 {
        // arm64:"UBFIZ\t[$]1, R[0-9]+, [$]28",-"LSL",-"LSR"
        return (x << 4) >> 3
 }
 
-func ubfiz8(x uint64) uint64 {
+func ubfiz12(x uint64) uint64 {
        // arm64:"UBFIZ\t[$]1, R[0-9]+, [$]20",-"LSL",-"LSR"
        // s390x:"RISBGZ\t[$]43, [$]62, [$]1, ",-"SLD",-"SRD",-"AND"
        return ((x & 0xfffff) << 4) >> 3
 }
 
-func ubfiz9(x uint64) uint64 {
+func ubfiz13(x uint64) uint64 {
        // arm64:"UBFIZ\t[$]5, R[0-9]+, [$]13",-"LSL",-"LSR",-"AND"
        return ((x << 3) & 0xffff) << 2
 }
 
-func ubfiz10(x uint64) uint64 {
+func ubfiz14(x uint64) uint64 {
        // arm64:"UBFIZ\t[$]7, R[0-9]+, [$]12",-"LSL",-"LSR",-"AND"
        // s390x:"RISBGZ\t[$]45, [$]56, [$]7, ",-"SLD",-"SRD",-"AND"
        return ((x << 5) & (0xfff << 5)) << 2
 }
 
 // ubfx
+// merge shifts into ubfx: (x<<lc)>>rc && lc<rc
 func ubfx1(x uint64) uint64 {
-       // arm64:"UBFX\t[$]25, R[0-9]+, [$]10",-"LSR",-"AND"
-       // s390x:"RISBGZ\t[$]54, [$]63, [$]39, ",-"SRD",-"AND"
-       return (x >> 25) & 1023
-}
-
-func ubfx2(x uint64) uint64 {
-       // arm64:"UBFX\t[$]4, R[0-9]+, [$]8",-"LSR",-"AND"
-       // s390x:"RISBGZ\t[$]56, [$]63, [$]60, ",-"SRD",-"AND"
-       return (x & 0x0ff0) >> 4
+       // arm64:"UBFX\t[$]1, R[0-9]+, [$]62",-"LSL",-"LSR"
+       // s390x:"RISBGZ\t[$]2, [$]63, [$]63,",-"SLD",-"SRD"
+       return (x << 1) >> 2
 }
 
-func ubfx3(x uint32) uint64 {
+// merge shift and zero-extension into ubfx.
+func ubfx2(x uint32) uint64 {
        return uint64(x >> 15) // arm64:"UBFX\t[$]15, R[0-9]+, [$]17",-"LSR"
 }
 
-func ubfx4(x uint16) uint64 {
+func ubfx3(x uint16) uint64 {
        return uint64(x >> 9) // arm64:"UBFX\t[$]9, R[0-9]+, [$]7",-"LSR"
 }
 
-func ubfx5(x uint8) uint64 {
+func ubfx4(x uint8) uint64 {
        return uint64(x >> 3) // arm64:"UBFX\t[$]3, R[0-9]+, [$]5",-"LSR"
 }
 
-func ubfx6(x uint64) uint64 {
-       // arm64:"UBFX\t[$]1, R[0-9]+, [$]62",-"LSL",-"LSR"
-       // s390x:"RISBGZ\t[$]2, [$]63, [$]63,",-"SLD",-"SRD"
-       return (x << 1) >> 2
+func ubfx5(x uint32) uint64 {
+       return uint64(x) >> 30 // arm64:"UBFX\t[$]30, R[0-9]+, [$]2"
 }
 
-func ubfx7(x uint32) uint32 {
+func ubfx6(x uint16) uint64 {
+       return uint64(x) >> 10 // arm64:"UBFX\t[$]10, R[0-9]+, [$]6"
+}
+
+func ubfx7(x uint8) uint64 {
+       return uint64(x) >> 3 // arm64:"UBFX\t[$]3, R[0-9]+, [$]5"
+}
+
+// merge ANDconst into ubfx.
+func ubfx8(x uint64) uint64 {
+       // arm64:"UBFX\t[$]25, R[0-9]+, [$]10",-"LSR",-"AND"
+       // s390x:"RISBGZ\t[$]54, [$]63, [$]39, ",-"SRD",-"AND"
+       return (x >> 25) & 1023
+}
+
+func ubfx9(x uint64) uint64 {
+       // arm64:"UBFX\t[$]4, R[0-9]+, [$]8",-"LSR",-"AND"
+       // s390x:"RISBGZ\t[$]56, [$]63, [$]60, ",-"SRD",-"AND"
+       return (x & 0x0ff0) >> 4
+}
+
+// ubfx combinations.
+func ubfx10(x uint32) uint32 {
        // arm64:"UBFX\t[$]1, R[0-9]+, [$]30",-"LSL",-"LSR"
        return (x << 1) >> 2
 }
 
-func ubfx8(x uint64) uint64 {
+func ubfx11(x uint64) uint64 {
        // arm64:"UBFX\t[$]1, R[0-9]+, [$]12",-"LSL",-"LSR",-"AND"
        // s390x:"RISBGZ\t[$]52, [$]63, [$]63,",-"SLD",-"SRD",-"AND"
        return ((x << 1) >> 2) & 0xfff
 }
 
-func ubfx9(x uint64) uint64 {
+func ubfx12(x uint64) uint64 {
        // arm64:"UBFX\t[$]4, R[0-9]+, [$]11",-"LSL",-"LSR",-"AND"
        // s390x:"RISBGZ\t[$]53, [$]63, [$]60, ",-"SLD",-"SRD",-"AND"
        return ((x >> 3) & 0xfff) >> 1
 }
 
-func ubfx10(x uint64) uint64 {
+func ubfx13(x uint64) uint64 {
        // arm64:"UBFX\t[$]5, R[0-9]+, [$]56",-"LSL",-"LSR"
        // s390x:"RISBGZ\t[$]8, [$]63, [$]59, ",-"SLD",-"SRD"
        return ((x >> 2) << 5) >> 8
 }
 
-func ubfx11(x uint64) uint64 {
+func ubfx14(x uint64) uint64 {
        // arm64:"UBFX\t[$]1, R[0-9]+, [$]19",-"LSL",-"LSR"
        // s390x:"RISBGZ\t[$]45, [$]63, [$]63, ",-"SLD",-"SRD",-"AND"
        return ((x & 0xfffff) << 3) >> 4
 }
 
+// merge ubfx and zero-extension into ubfx.
+func ubfx15(x uint64) bool {
+       midr := x + 10
+       part_num := uint16((midr >> 4) & 0xfff)
+       if part_num == 0xd0c { // arm64:"UBFX\t[$]4, R[0-9]+, [$]12",-"MOVHU\tR[0-9]+, R[0-9]+"
+               return true
+       }
+       return false
+}
+
 // Check that we don't emit comparisons for constant shifts.
 //go:nosplit
 func shift_no_cmp(x int) int {
index 8117a623072934c4a64be3f62060965bd9769f17..e7826b8e658dc89d6ae97516b6f8a6339796f8b1 100644 (file)
@@ -6,6 +6,8 @@
 
 package codegen
 
+import "math/bits"
+
 /************************************
  * 64-bit instructions
  ************************************/
@@ -330,7 +332,7 @@ func bitSetPowerOf2Test(x int) bool {
 }
 
 func bitSetTest(x int) bool {
-       // amd64:"ANDQ\t[$]9, AX"
+       // amd64:"ANDL\t[$]9, AX"
        // amd64:"CMPQ\tAX, [$]9"
        return x&9 == 9
 }
@@ -355,3 +357,9 @@ func issue44228b(a []int32, i int) bool {
        // amd64: "BTL", -"SHL"
        return a[i>>5]&(1<<(i&31)) != 0
 }
+
+func issue48467(x, y uint64) uint64 {
+       // arm64: -"NEG"
+       d, borrow := bits.Sub64(x, y, 0)
+       return x - d&(-borrow)
+}
diff --git a/test/codegen/bmi.go b/test/codegen/bmi.go
new file mode 100644 (file)
index 0000000..0c25e0b
--- /dev/null
@@ -0,0 +1,47 @@
+// asmcheck
+
+// Copyright 2021 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 codegen
+
+func andn64(x, y int64) int64 {
+       // amd64/v3:"ANDNQ"
+       return x &^ y
+}
+
+func andn32(x, y int32) int32 {
+       // amd64/v3:"ANDNL"
+       return x &^ y
+}
+
+func blsi64(x int64) int64 {
+       // amd64/v3:"BLSIQ"
+       return x & -x
+}
+
+func blsi32(x int32) int32 {
+       // amd64/v3:"BLSIL"
+       return x & -x
+}
+
+func blsmsk64(x int64) int64 {
+       // amd64/v3:"BLSMSKQ"
+       return x ^ (x - 1)
+}
+
+func blsmsk32(x int32) int32 {
+       // amd64/v3:"BLSMSKL"
+       return x ^ (x - 1)
+}
+
+func blsr64(x int64) int64 {
+       // amd64/v3:"BLSRQ"
+       return x & (x - 1)
+}
+
+func blsr32(x int32) int32 {
+       // amd64/v3:"BLSRL"
+       return x & (x - 1)
+}
index 929b1b49b9bd012c5471e4d21a185fa765b7045d..a32423308e02c6ae36ee3c15d9ba2da1ff6a709e 100644 (file)
@@ -27,7 +27,7 @@ func convertNeq0L(x uint32, c bool) bool {
 }
 
 func convertNeq0Q(x uint64, c bool) bool {
-       // amd64:"ANDQ\t[$]1",-"SETB"
+       // amd64:"ANDL\t[$]1",-"SETB"
        b := x&1 != 0
        return c && b
 }
index 17dcd94ae1eff13f0db08f07150a2692fc18a3c1..fd32ea335ce3aa9dc9ebe48c55b7c895ae049f29 100644 (file)
@@ -538,3 +538,81 @@ func CmpToOneU_ex2(a uint8, b uint16, c uint32, d uint64) int {
        }
        return 0
 }
+
+// Check that small memequals are replaced with eq instructions
+
+func equalConstString1() bool {
+       a := string("A")
+       b := string("Z")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a == b
+}
+
+func equalVarString1(a string) bool {
+       b := string("Z")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a[:1] == b
+}
+
+func equalConstString2() bool {
+       a := string("AA")
+       b := string("ZZ")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a == b
+}
+
+func equalVarString2(a string) bool {
+       b := string("ZZ")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a[:2] == b
+}
+
+func equalConstString4() bool {
+       a := string("AAAA")
+       b := string("ZZZZ")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a == b
+}
+
+func equalVarString4(a string) bool {
+       b := string("ZZZZ")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a[:4] == b
+}
+
+func equalConstString8() bool {
+       a := string("AAAAAAAA")
+       b := string("ZZZZZZZZ")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a == b
+}
+
+func equalVarString8(a string) bool {
+       b := string("ZZZZZZZZ")
+       // amd64:-".*memequal"
+       // arm64:-".*memequal"
+       // ppc64:-".*memequal"
+       // ppc64le:-".*memequal"
+       return a[:8] == b
+}
index ea8a01f803f7b92998e73d051ba75f11d311a13c..9b3bf75b7a35cd924634e53881b1634d9fd2029e 100644 (file)
@@ -103,6 +103,8 @@ func moveArchLowering1(b []byte, x *[1]byte) {
        _ = b[1]
        // amd64:-".*memmove"
        // arm64:-".*memmove"
+       // ppc64:-".*memmove"
+       // ppc64le:-".*memmove"
        copy(b, x[:])
 }
 
@@ -110,6 +112,8 @@ func moveArchLowering2(b []byte, x *[2]byte) {
        _ = b[2]
        // amd64:-".*memmove"
        // arm64:-".*memmove"
+       // ppc64:-".*memmove"
+       // ppc64le:-".*memmove"
        copy(b, x[:])
 }
 
@@ -117,6 +121,8 @@ func moveArchLowering4(b []byte, x *[4]byte) {
        _ = b[4]
        // amd64:-".*memmove"
        // arm64:-".*memmove"
+       // ppc64:-".*memmove"
+       // ppc64le:-".*memmove"
        copy(b, x[:])
 }
 
@@ -124,6 +130,8 @@ func moveArchLowering8(b []byte, x *[8]byte) {
        _ = b[8]
        // amd64:-".*memmove"
        // arm64:-".*memmove"
+       // ppc64:-".*memmove"
+       // ppc64le:-".*memmove"
        copy(b, x[:])
 }
 
diff --git a/test/codegen/issue48054.go b/test/codegen/issue48054.go
new file mode 100644 (file)
index 0000000..1f3a041
--- /dev/null
@@ -0,0 +1,31 @@
+// asmcheck
+
+// Copyright 2021 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 codegen
+
+func a(n string) bool {
+       // arm64:"CBZ"
+       if len(n) > 0 {
+               return true
+       }
+       return false
+}
+
+func a2(n []int) bool {
+       // arm64:"CBZ"
+       if len(n) > 0 {
+               return true
+       }
+       return false
+}
+
+func a3(n []int) bool {
+       // amd64:"TESTQ"
+       if len(n) < 1 {
+               return true
+       }
+       return false
+}
index 04cb4e577da6acd6fe0cbd540a6ac93eca0aee7a..ad154e0c40917f2b6a2501e913991c257496dfdf 100644 (file)
@@ -11,6 +11,8 @@ import "math"
 var sink64 [8]float64
 
 func approx(x float64) {
+       // amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
+       // amd64:"ROUNDSD\t[$]2"
        // s390x:"FIDBR\t[$]6"
        // arm64:"FRINTPD"
        // ppc64:"FRIP"
@@ -18,6 +20,8 @@ func approx(x float64) {
        // wasm:"F64Ceil"
        sink64[0] = math.Ceil(x)
 
+       // amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
+       // amd64:"ROUNDSD\t[$]1"
        // s390x:"FIDBR\t[$]7"
        // arm64:"FRINTMD"
        // ppc64:"FRIM"
@@ -31,6 +35,8 @@ func approx(x float64) {
        // ppc64le:"FRIN"
        sink64[2] = math.Round(x)
 
+       // amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
+       // amd64:"ROUNDSD\t[$]3"
        // s390x:"FIDBR\t[$]5"
        // arm64:"FRINTZD"
        // ppc64:"FRIZ"
@@ -38,6 +44,8 @@ func approx(x float64) {
        // wasm:"F64Trunc"
        sink64[3] = math.Trunc(x)
 
+       // amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
+       // amd64:"ROUNDSD\t[$]0"
        // s390x:"FIDBR\t[$]4"
        // arm64:"FRINTND"
        // wasm:"F64Nearest"
@@ -73,6 +81,7 @@ func abs(x, y float64) {
        // s390x:"LPDFR\t",-"MOVD\t"     (no integer load/store)
        // ppc64:"FABS\t"
        // ppc64le:"FABS\t"
+       // riscv64:"FABSD\t"
        // wasm:"F64Abs"
        // arm/6:"ABSD\t"
        sink64[0] = math.Abs(x)
@@ -96,6 +105,7 @@ func copysign(a, b, c float64) {
        // s390x:"CPSDR",-"MOVD"         (no integer load/store)
        // ppc64:"FCPSGN"
        // ppc64le:"FCPSGN"
+       // riscv64:"FSGNJD"
        // wasm:"F64Copysign"
        sink64[0] = math.Copysign(a, b)
 
@@ -103,6 +113,7 @@ func copysign(a, b, c float64) {
        // s390x:"LNDFR\t",-"MOVD\t"     (no integer load/store)
        // ppc64:"FCPSGN"
        // ppc64le:"FCPSGN"
+       // riscv64:"FSGNJD"
        // arm64:"ORR", -"AND"
        sink64[1] = math.Copysign(c, -1)
 
@@ -115,19 +126,37 @@ func copysign(a, b, c float64) {
        // s390x:"CPSDR\t",-"MOVD\t"     (no integer load/store)
        // ppc64:"FCPSGN"
        // ppc64le:"FCPSGN"
+       // riscv64:"FSGNJD"
        sink64[3] = math.Copysign(-1, c)
 }
 
 func fma(x, y, z float64) float64 {
+       // amd64/v3:-".*x86HasFMA"
        // amd64:"VFMADD231SD"
        // arm/6:"FMULAD"
        // arm64:"FMADDD"
        // s390x:"FMADD"
        // ppc64:"FMADD"
        // ppc64le:"FMADD"
+       // riscv64:"FMADDD"
        return math.FMA(x, y, z)
 }
 
+func fms(x, y, z float64) float64 {
+       // riscv64:"FMSUBD"
+       return math.FMA(x, y, -z)
+}
+
+func fnma(x, y, z float64) float64 {
+       // riscv64:"FNMADDD"
+       return math.FMA(-x, y, z)
+}
+
+func fnms(x, y, z float64) float64 {
+       // riscv64:"FNMSUBD"
+       return math.FMA(x, -y, -z)
+}
+
 func fromFloat64(f64 float64) uint64 {
        // amd64:"MOVQ\tX.*, [^X].*"
        // arm64:"FMOVD\tF.*, R.*"
index 03012eff5d8444a2e71e5f0a49ccc8e850ae004c..859490c363c306a49bb8a760cc392f2f6cbbb4d7 100644 (file)
@@ -93,6 +93,8 @@ func Len32(n uint32) int {
        // arm:"CLZ" arm64:"CLZ"
        // mips:"CLZ"
        // wasm:"I64Clz"
+       // ppc64: "CNTLZW"
+       // ppc64le: "CNTLZW"
        return bits.Len32(n)
 }
 
@@ -118,8 +120,9 @@ func Len8(n uint8) int {
 //    bits.OnesCount    //
 // -------------------- //
 
-// TODO(register args) Restore a m d 6 4 :.*x86HasPOPCNT when only one ABI is tested.
+// TODO(register args) Restore a m d 6 4 / v 1 :.*x86HasPOPCNT when only one ABI is tested.
 func OnesCount(n uint) int {
+       // amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
        // amd64:"POPCNTQ"
        // arm64:"VCNT","VUADDLV"
        // s390x:"POPCNT"
@@ -130,6 +133,7 @@ func OnesCount(n uint) int {
 }
 
 func OnesCount64(n uint64) int {
+       // amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
        // amd64:"POPCNTQ"
        // arm64:"VCNT","VUADDLV"
        // s390x:"POPCNT"
@@ -140,6 +144,7 @@ func OnesCount64(n uint64) int {
 }
 
 func OnesCount32(n uint32) int {
+       // amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
        // amd64:"POPCNTL"
        // arm64:"VCNT","VUADDLV"
        // s390x:"POPCNT"
@@ -150,6 +155,7 @@ func OnesCount32(n uint32) int {
 }
 
 func OnesCount16(n uint16) int {
+       // amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
        // amd64:"POPCNTL"
        // arm64:"VCNT","VUADDLV"
        // s390x:"POPCNT"
@@ -272,7 +278,8 @@ func RotateLeftVariable32(n uint32, m int) uint32 {
 // ------------------------ //
 
 func TrailingZeros(n uint) int {
-       // amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ"
+       // amd64/v1,amd64/v2:"BSFQ","MOVL\t\\$64","CMOVQEQ"
+       // amd64/v3:"TZCNTQ"
        // arm:"CLZ"
        // arm64:"RBIT","CLZ"
        // s390x:"FLOGR"
@@ -285,7 +292,8 @@ func TrailingZeros(n uint) int {
 }
 
 func TrailingZeros64(n uint64) int {
-       // amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ"
+       // amd64/v1,amd64/v2:"BSFQ","MOVL\t\\$64","CMOVQEQ"
+       // amd64/v3:"TZCNTQ"
        // arm64:"RBIT","CLZ"
        // s390x:"FLOGR"
        // ppc64/power8:"ANDN","POPCNTD"
@@ -303,7 +311,8 @@ func TrailingZeros64Subtract(n uint64) int {
 }
 
 func TrailingZeros32(n uint32) int {
-       // amd64:"BTSQ\\t\\$32","BSFQ"
+       // amd64/v1,amd64/v2:"BTSQ\\t\\$32","BSFQ"
+       // amd64/v3:"TZCNTL"
        // arm:"CLZ"
        // arm64:"RBITW","CLZW"
        // s390x:"FLOGR","MOVWZ"
@@ -343,7 +352,8 @@ func TrailingZeros8(n uint8) int {
 func IterateBits(n uint) int {
        i := 0
        for n != 0 {
-               // amd64:"BSFQ",-"CMOVEQ"
+               // amd64/v1,amd64/v2:"BSFQ",-"CMOVEQ"
+               // amd64/v3:"TZCNTQ"
                i += bits.TrailingZeros(n)
                n &= n - 1
        }
@@ -353,7 +363,8 @@ func IterateBits(n uint) int {
 func IterateBits64(n uint64) int {
        i := 0
        for n != 0 {
-               // amd64:"BSFQ",-"CMOVEQ"
+               // amd64/v1,amd64/v2:"BSFQ",-"CMOVEQ"
+               // amd64/v3:"TZCNTQ"
                i += bits.TrailingZeros64(n)
                n &= n - 1
        }
@@ -363,7 +374,8 @@ func IterateBits64(n uint64) int {
 func IterateBits32(n uint32) int {
        i := 0
        for n != 0 {
-               // amd64:"BSFL",-"BTSQ"
+               // amd64/v1,amd64/v2:"BSFL",-"BTSQ"
+               // amd64/v3:"TZCNTL"
                i += bits.TrailingZeros32(n)
                n &= n - 1
        }
@@ -373,7 +385,8 @@ func IterateBits32(n uint32) int {
 func IterateBits16(n uint16) int {
        i := 0
        for n != 0 {
-               // amd64:"BSFL",-"BTSL"
+               // amd64/v1,amd64/v2:"BSFL",-"BTSL"
+               // amd64/v3:"TZCNTL"
                // arm64:"RBITW","CLZW",-"ORR"
                i += bits.TrailingZeros16(n)
                n &= n - 1
@@ -384,7 +397,8 @@ func IterateBits16(n uint16) int {
 func IterateBits8(n uint8) int {
        i := 0
        for n != 0 {
-               // amd64:"BSFL",-"BTSL"
+               // amd64/v1,amd64/v2:"BSFL",-"BTSL"
+               // amd64/v3:"TZCNTL"
                // arm64:"RBITW","CLZW",-"ORR"
                i += bits.TrailingZeros8(n)
                n &= n - 1
@@ -710,6 +724,7 @@ func Mul64(x, y uint64) (hi, lo uint64) {
        // ppc64le:"MULHDU","MULLD"
        // s390x:"MLGR"
        // mips64: "MULVU"
+       // riscv64:"MULHU","MUL"
        return bits.Mul64(x, y)
 }
 
index d74dae07f5b5481379a03524dc1250528999c060..97e1d4bdfb7ad6eff579801f1b23362c9a75e6de 100644 (file)
@@ -70,7 +70,8 @@ func load_le16_idx(b []byte, idx int) {
 }
 
 func load_be64(b []byte) {
-       // amd64:`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR`
+       // amd64/v1,amd64/v2:`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR`
+       // amd64/v3:`MOVBEQ`
        // s390x:`MOVD\s\(.*\),`
        // arm64:`REV`,`MOVD\s\(R[0-9]+\),`,-`MOV[BHW]`,-`REVW`,-`REV16W`
        // ppc64le:`MOVDBR`,-`MOV[BHW]Z`
@@ -78,7 +79,8 @@ func load_be64(b []byte) {
 }
 
 func load_be64_idx(b []byte, idx int) {
-       // amd64:`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR`
+       // amd64/v1,amd64/v2:`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR`
+       // amd64/v3: `MOVBEQ`
        // s390x:`MOVD\s\(.*\)\(.*\*1\),`
        // arm64:`REV`,`MOVD\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[WHB]`,-`REVW`,-`REV16W`
        // ppc64le:`MOVDBR`,-`MOV[BHW]Z`
@@ -86,7 +88,8 @@ func load_be64_idx(b []byte, idx int) {
 }
 
 func load_be32(b []byte) {
-       // amd64:`BSWAPL`,-`MOV[BW]`,-`OR`
+       // amd64/v1,amd64/v2:`BSWAPL`,-`MOV[BW]`,-`OR`
+       // amd64/v3: `MOVBEL`
        // s390x:`MOVWZ\s\(.*\),`
        // arm64:`REVW`,`MOVWU\s\(R[0-9]+\),`,-`MOV[BH]`,-`REV16W`
        // ppc64le:`MOVWBR`,-`MOV[BH]Z`
@@ -94,7 +97,8 @@ func load_be32(b []byte) {
 }
 
 func load_be32_idx(b []byte, idx int) {
-       // amd64:`BSWAPL`,-`MOV[BW]`,-`OR`
+       // amd64/v1,amd64/v2:`BSWAPL`,-`MOV[BW]`,-`OR`
+       // amd64/v3: `MOVBEL`
        // s390x:`MOVWZ\s\(.*\)\(.*\*1\),`
        // arm64:`REVW`,`MOVWU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[HB]`,-`REV16W`
        // ppc64le:`MOVWBR`,-`MOV[BH]Z`
@@ -179,7 +183,8 @@ func load_be_byte4_uint32(s []byte) uint32 {
 
 func load_be_byte4_uint32_inv(s []byte) uint32 {
        // arm64:`MOVWU\t\(R[0-9]+\)`,`REVW`,-`ORR`,-`REV16W`,-`MOV[BH]`
-       // amd64:`MOVL\s\([A-Z]+\)`,`BSWAPL`,-`MOV[BW]`,-`OR`
+       // amd64/v1,amd64/v2:`MOVL\s\([A-Z]+\)`,`BSWAPL`,-`MOV[BW]`,-`OR`
+       // amd64/v3: `MOVBEL`
        return uint32(s[3]) | uint32(s[2])<<8 | uint32(s[1])<<16 | uint32(s[0])<<24
 }
 
@@ -191,7 +196,8 @@ func load_be_byte8_uint64(s []byte) uint64 {
 
 func load_be_byte8_uint64_inv(s []byte) uint64 {
        // arm64:`MOVD\t\(R[0-9]+\)`,`REV`,-`ORR`,-`REVW`,-`REV16W`,-`MOV[BHW]`
-       // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR`
+       // amd64/v1,amd64/v2:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR`
+       // amd64/v3: `MOVBEQ`
        // ppc64le:`MOVDBR\t\(R[0-9]+\)`,-`MOV[BHW]Z`
        return uint64(s[7]) | uint64(s[6])<<8 | uint64(s[5])<<16 | uint64(s[4])<<24 | uint64(s[3])<<32 | uint64(s[2])<<40 | uint64(s[1])<<48 | uint64(s[0])<<56
 }
@@ -409,7 +415,8 @@ func store_le16_idx(b []byte, idx int) {
 }
 
 func store_be64(b []byte) {
-       // amd64:`BSWAPQ`,-`SHR.`
+       // amd64/v1,amd64/v2:`BSWAPQ`,-`SHR.`
+       // amd64/v3: `MOVBEQ`
        // arm64:`MOVD`,`REV`,-`MOV[WBH]`,-`REVW`,-`REV16W`
        // ppc64le:`MOVDBR`
        // s390x:`MOVD\s.*\(.*\)$`,-`SRW\s`,-`SRD\s`
@@ -417,7 +424,8 @@ func store_be64(b []byte) {
 }
 
 func store_be64_idx(b []byte, idx int) {
-       // amd64:`BSWAPQ`,-`SHR.`
+       // amd64/v1,amd64/v2:`BSWAPQ`,-`SHR.`
+       // amd64/v3:`MOVBEQ`
        // arm64:`REV`,`MOVD\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOV[BHW]`,-`REV16W`,-`REVW`
        // ppc64le:`MOVDBR`
        // s390x:`MOVD\s.*\(.*\)\(.*\*1\)$`,-`SRW\s`,-`SRD\s`
@@ -425,15 +433,29 @@ func store_be64_idx(b []byte, idx int) {
 }
 
 func store_be32(b []byte) {
-       // amd64:`BSWAPL`,-`SHR.`
+       // amd64/v1,amd64/v2:`BSWAPL`,-`SHR.`
+       // amd64/v3:`MOVBEL`
        // arm64:`MOVW`,`REVW`,-`MOV[BH]`,-`REV16W`
        // ppc64le:`MOVWBR`
        // s390x:`MOVW\s.*\(.*\)$`,-`SRW\s`,-`SRD\s`
        binary.BigEndian.PutUint32(b, sink32)
 }
 
+func store_be64_load(b, x *[8]byte) {
+       // arm64:-`REV`
+       // amd64:-`BSWAPQ`
+       binary.BigEndian.PutUint64(b[:], binary.BigEndian.Uint64(x[:]))
+}
+
+func store_be32_load(b, x *[8]byte) {
+       // arm64:-`REVW`
+       // amd64:-`BSWAPL`
+       binary.BigEndian.PutUint32(b[:], binary.BigEndian.Uint32(x[:]))
+}
+
 func store_be32_idx(b []byte, idx int) {
-       // amd64:`BSWAPL`,-`SHR.`
+       // amd64/v1,amd64/v2:`BSWAPL`,-`SHR.`
+       // amd64/v3:`MOVBEL`
        // arm64:`REVW`,`MOVW\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOV[BH]`,-`REV16W`
        // ppc64le:`MOVWBR`
        // s390x:`MOVW\s.*\(.*\)\(.*\*1\)$`,-`SRW\s`,-`SRD\s`
@@ -496,14 +518,16 @@ func store_be_byte_2(b []byte, val uint16) {
 func store_be_byte_4(b []byte, val uint32) {
        _ = b[4]
        // arm64:`REVW`,`MOVW\sR[0-9]+,\s1\(R[0-9]+\)`,-`MOVB`,-`MOVH`,-`REV16W`
-       // amd64:`MOVL\s[A-Z]+,\s1\([A-Z]+\)`,-`MOVB`,-`MOVW`
+       // amd64/v1,amd64/v2:`MOVL\s[A-Z]+,\s1\([A-Z]+\)`,-`MOVB`,-`MOVW`
+       // amd64/v3:`MOVBEL\s[A-Z]+,\s1\([A-Z]+\)`
        b[1], b[2], b[3], b[4] = byte(val>>24), byte(val>>16), byte(val>>8), byte(val)
 }
 
 func store_be_byte_8(b []byte, val uint64) {
        _ = b[8]
        // arm64:`REV`,`MOVD\sR[0-9]+,\s1\(R[0-9]+\)`,-`MOVB`,-`MOVH`,-`MOVW`,-`REV16W`,-`REVW`
-       // amd64:`MOVQ\s[A-Z]+,\s1\([A-Z]+\)`,-`MOVB`,-`MOVW`,-`MOVL`
+       // amd64/v1,amd64/v2:`MOVQ\s[A-Z]+,\s1\([A-Z]+\)`,-`MOVB`,-`MOVW`,-`MOVL`
+       // amd64/v3:`MOVBEQ\s[A-Z]+,\s1\([A-Z]+\)`, -`MOVBEL`
        b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8] = byte(val>>56), byte(val>>48), byte(val>>40), byte(val>>32), byte(val>>24), byte(val>>16), byte(val>>8), byte(val)
 }
 
index 424fd2008d25fb84db5170afb00c3504560fa772..d8e2917bf276c75a7e2f6afebe292d86a81cf985 100644 (file)
@@ -15,19 +15,18 @@ var val32 [8]uint32
 var val16 [8]uint16
 var val8 [8]uint8
 
-// ----------------------------- //
-//    avoid zero/sign extensions //
-// ----------------------------- //
+// Avoid zero/sign extensions following a load
+// which has extended the value correctly.
+// Note: No tests are done for int8 since
+// an extra extension is usually needed due to
+// no signed byte load.
 
-func set16(x8 int8, u8 uint8, y8 int8, z8 uint8) {
+func set16(x8 int8, u8 *uint8, y8 int8, z8 uint8) {
        // Truncate not needed, load does sign/zero extend
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       sval16[0] = int16(x8)
 
        // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       val16[0] = uint16(u8)
+       val16[0] = uint16(*u8)
 
        // AND not needed due to size
        // ppc64:-"ANDCC"
@@ -36,217 +35,186 @@ func set16(x8 int8, u8 uint8, y8 int8, z8 uint8) {
 
        // ppc64:-"ANDCC"
        // ppc64le:-"ANDCC"
-       val16[1] = 255 & uint16(u8+z8)
+       val16[1] = 255 & uint16(*u8+z8)
 
 }
-func shiftidx(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) {
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       sval16[0] = int16(val16[x8>>1])
+func shiftidx(u8 *uint8, x16 *int16, u16 *uint16) {
 
        // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       val16[0] = uint16(sval16[u8>>2])
+       val16[0] = uint16(sval16[*u8>>2])
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       sval16[1] = int16(val16[x16>>1])
+       sval16[1] = int16(val16[*x16>>1])
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       val16[1] = uint16(sval16[u16>>2])
+       val16[1] = uint16(sval16[*u16>>2])
 
 }
 
-func setnox(x8 int8, u8 uint8, y8 int8, z8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) {
-       // Truncate not needed due to sign/zero extension on load
-
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       sval16[0] = int16(x8)
+func setnox(x8 int8, u8 *uint8, y8 *int8, z8 *uint8, x16 *int16, u16 *uint16, x32 *int32, u32 *uint32) {
 
        // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       val16[0] = uint16(u8)
+       val16[0] = uint16(*u8)
 
        // AND not needed due to size
        // ppc64:-"ANDCC"
        // ppc64le:-"ANDCC"
-       sval16[1] = 255 & int16(x8+y8)
+       sval16[1] = 255 & int16(x8+*y8)
 
        // ppc64:-"ANDCC"
        // ppc64le:-"ANDCC"
-       val16[1] = 255 & uint16(u8+z8)
-
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       sval32[0] = int32(x8)
+       val16[1] = 255 & uint16(*u8+*z8)
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       sval32[1] = int32(x16)
+       sval32[1] = int32(*x16)
 
        //ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        //ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       val32[0] = uint32(u8)
+       val32[0] = uint32(*u8)
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       val32[1] = uint32(u16)
-
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       sval64[0] = int64(x8)
+       val32[1] = uint32(*u16)
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       sval64[1] = int64(x16)
+       sval64[1] = int64(*x16)
 
        // ppc64:-"MOVW\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVW\tR\\d+,\\sR\\d+"
-       sval64[2] = int64(x32)
+       sval64[2] = int64(*x32)
 
        //ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        //ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       val64[0] = uint64(u8)
+       val64[0] = uint64(*u8)
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       val64[1] = uint64(u16)
+       val64[1] = uint64(*u16)
 
        // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+"
-       val64[2] = uint64(u32)
+       val64[2] = uint64(*u32)
 }
 
-func cmp16(x8 int8, u8 uint8, x32 int32, u32 uint32, x64 int64, u64 uint64) bool {
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       if int16(x8) == sval16[0] {
-               return true
-       }
+func cmp16(u8 *uint8, x32 *int32, u32 *uint32, x64 *int64, u64 *uint64) bool {
 
        // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       if uint16(u8) == val16[0] {
+       if uint16(*u8) == val16[0] {
                return true
        }
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       if uint16(u32>>16) == val16[0] {
+       if uint16(*u32>>16) == val16[0] {
                return true
        }
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       if uint16(u64>>48) == val16[0] {
+       if uint16(*u64>>48) == val16[0] {
                return true
        }
 
        // Verify the truncates are using the correct sign.
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       if int16(x32) == sval16[0] {
+       if int16(*x32) == sval16[0] {
                return true
        }
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       if uint16(u32) == val16[0] {
+       if uint16(*u32) == val16[0] {
                return true
        }
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       if int16(x64) == sval16[0] {
+       if int16(*x64) == sval16[0] {
                return true
        }
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       if uint16(u64) == val16[0] {
+       if uint16(*u64) == val16[0] {
                return true
        }
 
        return false
 }
 
-func cmp32(x8 int8, u8 uint8, x16 int16, u16 uint16, x64 int64, u64 uint64) bool {
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       if int32(x8) == sval32[0] {
-               return true
-       }
+func cmp32(u8 *uint8, x16 *int16, u16 *uint16, x64 *int64, u64 *uint64) bool {
 
        // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       if uint32(u8) == val32[0] {
+       if uint32(*u8) == val32[0] {
                return true
        }
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       if int32(x16) == sval32[0] {
+       if int32(*x16) == sval32[0] {
                return true
        }
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       if uint32(u16) == val32[0] {
+       if uint32(*u16) == val32[0] {
                return true
        }
 
        // Verify the truncates are using the correct sign.
        // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+"
-       if int32(x64) == sval32[0] {
+       if int32(*x64) == sval32[0] {
                return true
        }
 
        // ppc64:-"MOVW\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVW\tR\\d+,\\sR\\d+"
-       if uint32(u64) == val32[0] {
+       if uint32(*u64) == val32[0] {
                return true
        }
 
        return false
 }
 
-func cmp64(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) bool {
-       // ppc64:-"MOVB\tR\\d+,\\sR\\d+"
-       // ppc64le:-"MOVB\tR\\d+,\\sR\\d+"
-       if int64(x8) == sval64[0] {
-               return true
-       }
+func cmp64(u8 *uint8, x16 *int16, u16 *uint16, x32 *int32, u32 *uint32) bool {
 
        // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+"
-       if uint64(u8) == val64[0] {
+       if uint64(*u8) == val64[0] {
                return true
        }
 
        // ppc64:-"MOVH\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVH\tR\\d+,\\sR\\d+"
-       if int64(x16) == sval64[0] {
+       if int64(*x16) == sval64[0] {
                return true
        }
 
        // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+"
-       if uint64(u16) == val64[0] {
+       if uint64(*u16) == val64[0] {
                return true
        }
 
        // ppc64:-"MOVW\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVW\tR\\d+,\\sR\\d+"
-       if int64(x32) == sval64[0] {
+       if int64(*x32) == sval64[0] {
                return true
        }
 
        // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+"
        // ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+"
-       if uint64(u32) == val64[0] {
+       if uint64(*u32) == val64[0] {
                return true
        }
        return false
index 519cc8326338be8f512d345296a75f0fc980b4d3..204efaeafcd9e35e9342b2a2bc1d0de7b4d50730 100644 (file)
@@ -34,8 +34,15 @@ func rot64(x uint64) uint64 {
        // ppc64le:"ROTL\t[$]9"
        a += x<<9 ^ x>>55
 
-       // s390x:"RISBGZ\t[$]0, [$]63, [$]7, "
+       // amd64:"ROLQ\t[$]10"
+       // arm64:"ROR\t[$]54"
+       // s390x:"RISBGZ\t[$]0, [$]63, [$]10, "
+       // ppc64:"ROTL\t[$]10"
+       // ppc64le:"ROTL\t[$]10"
        // arm64:"ROR\t[$]57" // TODO this is not great line numbering, but then again, the instruction did appear
+       // s390x:"RISBGZ\t[$]0, [$]63, [$]7, " // TODO ditto
+       a += bits.RotateLeft64(x, 10)
+
        return a
 }
 
@@ -64,8 +71,16 @@ func rot32(x uint32) uint32 {
        // ppc64le:"ROTLW\t[$]9"
        a += x<<9 ^ x>>23
 
-       // s390x:"RLL\t[$]7"
+       // amd64:"ROLL\t[$]10"
+       // arm:"MOVW\tR\\d+@>22"
+       // arm64:"RORW\t[$]22"
+       // s390x:"RLL\t[$]10"
+       // ppc64:"ROTLW\t[$]10"
+       // ppc64le:"ROTLW\t[$]10"
        // arm64:"RORW\t[$]25" // TODO this is not great line numbering, but then again, the instruction did appear
+       // s390x:"RLL\t[$]7" // TODO ditto
+       a += bits.RotateLeft32(x, 10)
+
        return a
 }
 
@@ -211,3 +226,26 @@ func checkMaskedRotate32(a []uint32, r int) {
        a[i] = bits.RotateLeft32(a[3], 4) & 0xFFF00FFF
        i++
 }
+
+// combined arithmetic and rotate on arm64
+func checkArithmeticWithRotate(a *[1000]uint64) {
+       // arm64: "AND\tR[0-9]+@>51, R[0-9]+, R[0-9]+"
+       a[2] = a[1] & bits.RotateLeft64(a[0], 13)
+       // arm64: "ORR\tR[0-9]+@>51, R[0-9]+, R[0-9]+"
+       a[5] = a[4] | bits.RotateLeft64(a[3], 13)
+       // arm64: "EOR\tR[0-9]+@>51, R[0-9]+, R[0-9]+"
+       a[8] = a[7] ^ bits.RotateLeft64(a[6], 13)
+       // arm64: "MVN\tR[0-9]+@>51, R[0-9]+"
+       a[10] = ^bits.RotateLeft64(a[9], 13)
+       // arm64: "BIC\tR[0-9]+@>51, R[0-9]+, R[0-9]+"
+       a[13] = a[12] &^ bits.RotateLeft64(a[11], 13)
+       // arm64: "EON\tR[0-9]+@>51, R[0-9]+, R[0-9]+"
+       a[16] = a[15] ^ ^bits.RotateLeft64(a[14], 13)
+       // arm64: "ORN\tR[0-9]+@>51, R[0-9]+, R[0-9]+"
+       a[19] = a[18] | ^bits.RotateLeft64(a[17], 13)
+       // arm64: "TST\tR[0-9]+@>51, R[0-9]+"
+       if a[18]&bits.RotateLeft64(a[19], 13) == 0 {
+               a[20] = 1
+       }
+
+}
index 06f6f1247399b8710bc9da0247f275bc277b8abb..b3ed69d9e343015e12541b08656cc515a53326ff 100644 (file)
 
 package codegen
 
+// ------------------ //
+//   constant shifts  //
+// ------------------ //
+
+func lshConst64x64(v int64) int64 {
+       // riscv64:"SLLI",-"AND",-"SLTIU"
+       return v << uint64(33)
+}
+
+func rshConst64Ux64(v uint64) uint64 {
+       // riscv64:"SRLI",-"AND",-"SLTIU"
+       return v >> uint64(33)
+}
+
+func rshConst64x64(v int64) int64 {
+       // riscv64:"SRAI",-"OR",-"SLTIU"
+       return v >> uint64(33)
+}
+
+func lshConst32x64(v int32) int32 {
+       // riscv64:"SLLI",-"AND",-"SLTIU"
+       return v << uint64(29)
+}
+
+func rshConst32Ux64(v uint32) uint32 {
+       // riscv64:"SRLI",-"AND",-"SLTIU"
+       return v >> uint64(29)
+}
+
+func rshConst32x64(v int32) int32 {
+       // riscv64:"SRAI",-"OR",-"SLTIU"
+       return v >> uint64(29)
+}
+
+func lshConst64x32(v int64) int64 {
+       // riscv64:"SLLI",-"AND",-"SLTIU"
+       return v << uint32(33)
+}
+
+func rshConst64Ux32(v uint64) uint64 {
+       // riscv64:"SRLI",-"AND",-"SLTIU"
+       return v >> uint32(33)
+}
+
+func rshConst64x32(v int64) int64 {
+       // riscv64:"SRAI",-"OR",-"SLTIU"
+       return v >> uint32(33)
+}
+
 // ------------------ //
 //   masked shifts    //
 // ------------------ //
 
 func lshMask64x64(v int64, s uint64) int64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-"ORN",-"ISEL"
+       // riscv64:"SLL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v << (s & 63)
 }
 
 func rshMask64Ux64(v uint64, s uint64) uint64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-"ORN",-"ISEL"
+       // riscv64:"SRL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> (s & 63)
 }
 
 func rshMask64x64(v int64, s uint64) int64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-ORN",-"ISEL"
+       // riscv64:"SRA","OR","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> (s & 63)
 }
 
 func lshMask32x64(v int32, s uint64) int32 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ISEL",-"ORN"
        // ppc64:"ISEL",-"ORN"
+       // ppc64le:"ISEL",-"ORN"
+       // riscv64:"SLL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v << (s & 63)
 }
 
 func rshMask32Ux64(v uint32, s uint64) uint32 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ISEL",-"ORN"
        // ppc64:"ISEL",-"ORN"
+       // ppc64le:"ISEL",-"ORN"
+       // riscv64:"SRL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> (s & 63)
 }
 
 func rshMask32x64(v int32, s uint64) int32 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ISEL",-"ORN"
        // ppc64:"ISEL",-"ORN"
+       // ppc64le:"ISEL",-"ORN"
+       // riscv64:"SRA","OR","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> (s & 63)
 }
 
 func lshMask64x32(v int64, s uint32) int64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN"
        // ppc64:"ANDCC",-"ORN"
+       // ppc64le:"ANDCC",-"ORN"
+       // riscv64:"SLL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v << (s & 63)
 }
 
 func rshMask64Ux32(v uint64, s uint32) uint64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN"
        // ppc64:"ANDCC",-"ORN"
+       // ppc64le:"ANDCC",-"ORN"
+       // riscv64:"SRL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> (s & 63)
 }
 
 func rshMask64x32(v int64, s uint32) int64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-"ORN",-"ISEL"
+       // riscv64:"SRA","OR","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> (s & 63)
 }
 
 func lshMask64x32Ext(v int64, s int32) int64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-"ORN",-"ISEL"
+       // riscv64:"SLL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v << uint(s&63)
 }
 
 func rshMask64Ux32Ext(v uint64, s int32) uint64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-"ORN",-"ISEL"
+       // riscv64:"SRL","AND","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> uint(s&63)
 }
 
 func rshMask64x32Ext(v int64, s int32) int64 {
-       // s390x:-"RISBGZ",-"AND",-"LOCGR"
-       // ppc64le:"ANDCC",-"ORN",-"ISEL"
        // ppc64:"ANDCC",-"ORN",-"ISEL"
+       // ppc64le:"ANDCC",-"ORN",-"ISEL"
+       // riscv64:"SRA","OR","SLTIU"
+       // s390x:-"RISBGZ",-"AND",-"LOCGR"
        return v >> uint(s&63)
 }
 
@@ -126,17 +187,19 @@ func lshSignedMasked(v8 int8, v16 int16, v32 int32, v64 int64, x int) {
 //   bounded shifts   //
 // ------------------ //
 
-func rshGuarded64(v int64, s uint) int64 {
+func lshGuarded64(v int64, s uint) int64 {
        if s < 64 {
+               // riscv64:"SLL","AND","SLTIU"
                // s390x:-"RISBGZ",-"AND",-"LOCGR"
                // wasm:-"Select",-".*LtU"
-               return v >> s
+               return v << s
        }
        panic("shift too large")
 }
 
 func rshGuarded64U(v uint64, s uint) uint64 {
        if s < 64 {
+               // riscv64:"SRL","AND","SLTIU"
                // s390x:-"RISBGZ",-"AND",-"LOCGR"
                // wasm:-"Select",-".*LtU"
                return v >> s
@@ -144,11 +207,12 @@ func rshGuarded64U(v uint64, s uint) uint64 {
        panic("shift too large")
 }
 
-func lshGuarded64(v int64, s uint) int64 {
+func rshGuarded64(v int64, s uint) int64 {
        if s < 64 {
+               // riscv64:"SRA","OR","SLTIU"
                // s390x:-"RISBGZ",-"AND",-"LOCGR"
                // wasm:-"Select",-".*LtU"
-               return v << s
+               return v >> s
        }
        panic("shift too large")
 }
index 24c2dff9339a689b749f5ac79046a53d7880db68..1008f1af9ceca8b1d28c58537eef5519636e9d92 100644 (file)
@@ -7,6 +7,5 @@
 package main
 
 func main() {
-       var s string = nil;     // ERROR "illegal|invalid|incompatible|cannot"
-       _ = s
+       var s string = nil // ERROR "illegal|invalid|incompatible|cannot"
 }
index 2c9d120ed069bf7b4a74984a999123ab641ebc3b..de606da1679d979ca4001f395b2aea552361ca91 100644 (file)
@@ -7,7 +7,6 @@
 package main
 
 func main() {
-       const a uint64 = 10;
-       var b int64 = a;        // ERROR "convert|cannot|incompatible"
-       _ = b
+       const a uint64 = 10
+       var b int64 = a // ERROR "convert|cannot|incompatible"
 }
index 88210a59b3e520c780f47cd0a1738b31f57684f0..caf3168536e2a8ce3e978a280e51cded7563dcff 100644 (file)
@@ -9,6 +9,5 @@ package main
 func f() (int, bool) { return 0, true }
 
 func main() {
-       x, y := f(), 2; // ERROR "multi|2-valued"
-       _, _ = x, y
+       x, y := f(), 2 // ERROR "multi|2-valued"
 }
index fea6829992f57ac699f7fe08f934dfec767b7a38..7e8346ee0f631bd8bc1383b2f5ffcdf7a1556f3f 100644 (file)
@@ -9,18 +9,14 @@
 package main
 
 func f1() {
-       a, b := f()     // ERROR "assignment mismatch|does not match|cannot initialize"
-       _ = a
-       _ = b
+       a, b := f() // ERROR "assignment mismatch|does not match|cannot initialize"
 }
 
 func f2() {
        var a, b int
-       a, b = f()      // ERROR "assignment mismatch|does not match|cannot assign"
-       _ = a
-       _ = b
+       a, b = f() // ERROR "assignment mismatch|does not match|cannot assign"
 }
 
 func f() int {
-       return 1;
+       return 1
 }
diff --git a/test/fixedbugs/gcc101994.go b/test/fixedbugs/gcc101994.go
new file mode 100644 (file)
index 0000000..6e1e2b8
--- /dev/null
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2021 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.
+
+// https://gcc.gnu.org/PR101994
+// gccgo compiler crash with zero-sized result.
+
+package p
+
+type Empty struct{}
+
+func F() (int, Empty) {
+       return 0, Empty{}
+}
index 876ea58ef97634a9d26154ecd1dd28cb87cc185e..a58ccce2db16d43bfeed7540f0b4e0381fca9687 100644 (file)
@@ -10,7 +10,7 @@
 package main
 
 type I interface {
-       int // ERROR "interface contains embedded non-interface|not an interface"
+       int // ERROR "interface contains embedded non-interface|embedding non-interface type"
 }
 
 func New() I {
index 14a223977b4a1ddd1952d063f97e6bcd27517bc8..6dd2fbfbf6d6cfc91ad8f20d764af494d41c5dec 100644 (file)
@@ -1,4 +1,4 @@
-// errorcheck
+// compile -G=3
 
 // Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -6,4 +6,5 @@
 
 package p
 
-var x any // ERROR "undefined: any|undefined type .*any.*|cannot use any outside constraint position"
+// any is now permitted instead of interface{}
+var x any
index 77cac3ee16a230119167bc51d2806225b87f3d48..5db0a48a345faf5a25247ed1ac46b2fd4f8a50b6 100644 (file)
@@ -15,5 +15,5 @@ func f() {
 func g2() ([]byte, []byte) { return nil, nil }
 
 func f2() {
-       g2()[:] // ERROR "multiple-value g2.. in single-value context|attempt to slice object that is not|2\-valued g"
+       g2()[:] // ERROR "multiple-value g2.* in single-value context|attempt to slice object that is not|2\-valued g"
 }
index d5210e87b0f5af9d9183dbd7335f6ece002e6689..edf88d489ecc666b93e5bc8c1fc40d5140b1de71 100644 (file)
@@ -6,11 +6,11 @@
 
 package p
 
-var x int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
+var x int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|multiple-value "
 
 func f() {
-       var _ int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
-       var a int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
+       var _ int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|multiple-value "
+       var a int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|multiple-value "
        a = three()         // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|cannot assign"
        b := three()        // ERROR "assignment mismatch: 1 variable but three returns 3 values|single variable set to multiple-value|multiple-value function call in single-value context|cannot initialize"
        _, _ = a, b
index 2fc0eb2a58ea17a7987ee0bf478c8097ab735731..86fb6384cdb5b48c99028db2e5fd1b60703b0ca8 100644 (file)
@@ -6,7 +6,7 @@
 
 package main
 
-var a = twoResults()       // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|2\-valued"
+var a = twoResults()       // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|multiple-value twoResults\(\) .*in single-value context"
 var b, c, d = twoResults() // ERROR "assignment mismatch: 3 variables but twoResults returns 2 values|cannot initialize"
 var e, f = oneResult()     // ERROR "assignment mismatch: 2 variables but oneResult returns 1 value|cannot initialize"
 
index 28bb8cde28343791ae0215febdc80eef699c31f3..673c6ab3e0f894b886f459f1cd10ba38e52688bd 100644 (file)
@@ -4,13 +4,16 @@
 
 package main
 
-import "./c"
-import "reflect"
+import (
+       "reflect"
+
+       "./c"
+)
 
 func main() {
        x := c.F()
        p := c.P()
-       t := reflect.PtrTo(reflect.TypeOf(x))
+       t := reflect.PointerTo(reflect.TypeOf(x))
        tp := reflect.TypeOf(p)
        if t != tp {
                panic("FAIL")
diff --git a/test/fixedbugs/issue46938.go b/test/fixedbugs/issue46938.go
new file mode 100644 (file)
index 0000000..87532d4
--- /dev/null
@@ -0,0 +1,29 @@
+// run -gcflags="-d=checkptr"
+
+// Copyright 2021 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() {
+       defer func() {
+               err := recover()
+               if err == nil {
+                       panic("expected panic")
+               }
+               if got := err.(error).Error(); !strings.Contains(got, "slice bounds out of range") {
+                       panic("expected panic slice out of bound, got " + got)
+               }
+       }()
+       s := make([]int64, 100)
+       p := unsafe.Pointer(&s[0])
+       n := 1000
+
+       _ = (*[10]int64)(p)[:n:n]
+}
diff --git a/test/fixedbugs/issue47068.dir/a.go b/test/fixedbugs/issue47068.dir/a.go
new file mode 100644 (file)
index 0000000..f7b780d
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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
+
+func A() {
+       var m map[int]int = map[int]int{
+               0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0,
+               10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0,
+               20: 0, 21: 0, 22: 0, 23: 0, 24: 0, 25: 0, 26: 0, 27: 0, 28: 0, 29: 0}
+       if len(m) != 30 {
+               panic("unepexted map length")
+       }
+}
diff --git a/test/fixedbugs/issue47068.dir/b.go b/test/fixedbugs/issue47068.dir/b.go
new file mode 100644 (file)
index 0000000..d341a4a
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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
+
+import "reflect"
+
+func B() {
+       t1 := reflect.TypeOf([30]int{})
+       t2 := reflect.TypeOf(new([30]int)).Elem()
+       if t1 != t2 {
+               panic("[30]int types do not match")
+       }
+}
diff --git a/test/fixedbugs/issue47068.dir/main.go b/test/fixedbugs/issue47068.dir/main.go
new file mode 100644 (file)
index 0000000..16ef5b7
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 (
+       "a"
+       "b"
+)
+
+func main() {
+       a.A()
+       b.B()
+}
similarity index 54%
rename from src/internal/cpu/cpu_386.go
rename to test/fixedbugs/issue47068.go
index 561c81f8083518a397202083d53cf4f797ce8b9c..af6f1341729458e04aba9a8a7110ec999540bc2a 100644 (file)
@@ -1,7 +1,7 @@
-// Copyright 2018 The Go Authors. All rights reserved.
+// rundir
+
+// 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 cpu
-
-const GOARCH = "386"
+package ignored
diff --git a/test/fixedbugs/issue47712.go b/test/fixedbugs/issue47712.go
new file mode 100644 (file)
index 0000000..81a2681
--- /dev/null
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2021 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() {
+       if false {
+               defer func() {
+                       _ = recover()
+               }()
+       }
+}
+
+func g() {
+       for false {
+               defer func() {
+                       _ = recover()
+               }()
+       }
+}
diff --git a/test/fixedbugs/issue47771.go b/test/fixedbugs/issue47771.go
new file mode 100644 (file)
index 0000000..a434bff
--- /dev/null
@@ -0,0 +1,19 @@
+// run
+
+// Copyright 2021 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.
+
+// gofrontend miscompiled some cases of append(s, make(typ, ln)...).
+
+package main
+
+var g int
+
+func main() {
+       a := []*int{&g, &g, &g, &g}
+       a = append(a[:0], make([]*int, len(a) - 1)...)
+       if len(a) != 3 || a[0] != nil || a[1] != nil || a[2] != nil {
+               panic(a)
+       }
+}
diff --git a/test/fixedbugs/issue47928.go b/test/fixedbugs/issue47928.go
new file mode 100644 (file)
index 0000000..3bc291d
--- /dev/null
@@ -0,0 +1,21 @@
+// run -goexperiment fieldtrack
+
+// Copyright 2021 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 i interface{} = new(T)
+       if _, ok := i.(interface{ Bad() }); ok {
+               panic("FAIL")
+       }
+}
+
+type T struct{ U }
+
+type U struct{}
+
+//go:nointerface
+func (*U) Bad() {}
diff --git a/test/fixedbugs/issue48026.go b/test/fixedbugs/issue48026.go
new file mode 100644 (file)
index 0000000..a693d33
--- /dev/null
@@ -0,0 +1,26 @@
+// compile -d=ssa/check/on
+
+// Copyright 2021 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
+
+var i int
+
+type t struct {
+       a, b, c, d, e int
+}
+
+func f(p t, q int) int {
+       var a, b, c, d, e, f, g int
+       var h, i, j, k, l, m int
+       _, _, _, _, _, _, _ = a, b, c, d, e, f, g
+       _, _, _, _, _, _ = h, i, j, k, l, m
+       return 0
+}
+
+func g() int {
+       var v t
+       return f(v, 1<<i)
+}
diff --git a/test/fixedbugs/issue48033.go b/test/fixedbugs/issue48033.go
new file mode 100644 (file)
index 0000000..044b98c
--- /dev/null
@@ -0,0 +1,40 @@
+// compile
+
+// Copyright 2021 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 (
+       "fmt"
+       "strings"
+)
+
+type app struct {
+       Name string
+}
+
+func bug() func() {
+       return func() {
+
+               // the issue is this if true block
+               if true {
+                       return
+               }
+
+               var xx = []app{}
+               var gapp app
+               for _, app := range xx {
+                       if strings.ToUpper("") == app.Name {
+                               fmt.Printf("%v\n", app)
+                               gapp = app
+                       }
+               }
+               fmt.Println(gapp)
+       }
+}
+
+func main() {
+       bug()
+}
diff --git a/test/fixedbugs/issue48088.dir/a.go b/test/fixedbugs/issue48088.dir/a.go
new file mode 100644 (file)
index 0000000..2bb879d
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 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
+
+type T1 struct {
+       *T2
+}
+
+type T2 struct {
+}
+
+func (t2 *T2) M() {
+}
+
+func F() {
+       f(T1.M)
+}
+
+func f(f func(T1)) {
+}
diff --git a/test/fixedbugs/issue48088.dir/b.go b/test/fixedbugs/issue48088.dir/b.go
new file mode 100644 (file)
index 0000000..221f2dd
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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
+
+import "a"
+
+func F() {
+       a.F()
+}
similarity index 54%
rename from src/internal/cpu/cpu_amd64.go
rename to test/fixedbugs/issue48088.go
index 9b0015362d53fba083efefb8a8f0c3b7e42a4a9c..b83fbd7af16a576c16e0fc73b84f1ca0f618b756 100644 (file)
@@ -1,7 +1,7 @@
-// Copyright 2018 The Go Authors. All rights reserved.
+// compiledir
+
+// Copyright 2021 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package cpu
-
-const GOARCH = "amd64"
+package ignored
diff --git a/test/fixedbugs/issue48092.go b/test/fixedbugs/issue48092.go
new file mode 100644 (file)
index 0000000..47b812c
--- /dev/null
@@ -0,0 +1,17 @@
+// compile -B
+
+// Copyright 2021 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.
+
+// Make sure that we can at least compile this code
+// successfully with -B. We can't ever produce the right
+// answer at runtime with -B, as the access must panic.
+
+package p
+
+type A [0]byte
+
+func (a *A) Get(i int) byte {
+       return a[i]
+}
diff --git a/test/fixedbugs/issue48097.go b/test/fixedbugs/issue48097.go
new file mode 100644 (file)
index 0000000..b08c2a2
--- /dev/null
@@ -0,0 +1,12 @@
+// errorcheck -complete
+
+// Copyright 2021 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() // ERROR "missing function body"
+
+//go:noescape
+func f() {} // ERROR "can only use //go:noescape with external func implementations"
diff --git a/test/fixedbugs/issue48230.go b/test/fixedbugs/issue48230.go
new file mode 100644 (file)
index 0000000..5f21376
--- /dev/null
@@ -0,0 +1,10 @@
+// errorcheck
+
+// Copyright 2021 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
+
+//go:embed issue48230.go // ERROR `go:embed only allowed in Go files that import "embed"`
+var _ string
diff --git a/test/fixedbugs/issue48289.go b/test/fixedbugs/issue48289.go
new file mode 100644 (file)
index 0000000..94dbeee
--- /dev/null
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2021 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 "fmt"
+
+func main() {
+       ch := make(chan int, 1)
+
+       var ptrs [2]*int
+       for i := range ptrs {
+               ch <- i
+               select {
+               case x := <-ch:
+                       ptrs[i] = &x
+               }
+       }
+
+       for i, ptr := range ptrs {
+               if *ptr != i {
+                       panic(fmt.Sprintf("got *ptr %d, want %d", *ptr, i))
+               }
+       }
+}
diff --git a/test/fixedbugs/issue48301.go b/test/fixedbugs/issue48301.go
new file mode 100644 (file)
index 0000000..1ff9ffb
--- /dev/null
@@ -0,0 +1,13 @@
+// errorcheck -G=0
+
+// Copyright 2021 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.
+
+// Don't crash while reporting the error.
+
+package p
+
+func _() {
+       type T = T // ERROR "T uses T|invalid recursive type T"
+}
diff --git a/test/fixedbugs/issue48357.go b/test/fixedbugs/issue48357.go
new file mode 100644 (file)
index 0000000..5b39fc4
--- /dev/null
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2021 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"
+
+type T [129]byte
+
+func main() {
+       m := map[string]T{}
+       v := reflect.ValueOf(m)
+       v.SetMapIndex(reflect.ValueOf("a"), reflect.ValueOf(T{}))
+       g = m["a"]
+}
+
+var g T
diff --git a/test/fixedbugs/issue48459.go b/test/fixedbugs/issue48459.go
new file mode 100644 (file)
index 0000000..ceb7788
--- /dev/null
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2021 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() {
+       if true {
+               return
+       }
+
+       defer func() {
+               recover()
+       }()
+}
diff --git a/test/fixedbugs/issue48473.go b/test/fixedbugs/issue48473.go
new file mode 100644 (file)
index 0000000..8edef1f
--- /dev/null
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2021 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 "fmt"
+
+func f(x uint64) uint64 {
+       s := "\x04"
+       c := s[0]
+       return x - x<<c<<4
+}
+
+func g(x uint32) uint32 {
+       s := "\x04"
+       c := s[0]
+       return x - x<<c<<4
+}
+
+func main() {
+       if want, got := uint64(0xffffffffffffff01), f(1); want != got {
+               panic(fmt.Sprintf("want %x got %x", want, got))
+       }
+       if want, got := uint32(0xffffff01), g(1); want != got {
+               panic(fmt.Sprintf("want %x got %x", want, got))
+       }
+}
diff --git a/test/fixedbugs/issue48476.go b/test/fixedbugs/issue48476.go
new file mode 100644 (file)
index 0000000..6b77f7c
--- /dev/null
@@ -0,0 +1,21 @@
+// run
+
+// Copyright 2021 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 "fmt"
+
+//go:noinline
+func f(x uint64) uint64 {
+       s := "\x04"
+       c := s[0]
+       return x << c << 4
+}
+func main() {
+       if want, got := uint64(1<<8), f(1); want != got {
+               panic(fmt.Sprintf("want %x got %x", want, got))
+       }
+}
diff --git a/test/fixedbugs/issue48536.go b/test/fixedbugs/issue48536.go
new file mode 100644 (file)
index 0000000..68c7d1c
--- /dev/null
@@ -0,0 +1,29 @@
+// run
+
+// Copyright 2021 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 "unsafe"
+
+var i = 257
+
+func main() {
+       var buf [10]byte
+       p0 := unsafe.Pointer(&buf[0])
+       p1 := unsafe.Pointer(&buf[1])
+
+       if p := unsafe.Add(p0, uint8(i)); p != p1 {
+               println("FAIL:", p, "!=", p1)
+       }
+
+       var x uint8
+       if i != 0 {
+               x = 1
+       }
+       if p := unsafe.Add(p0, x); p != p1 {
+               println("FAIL:", p, "!=", p1)
+       }
+}
diff --git a/test/fixedbugs/issue48558.go b/test/fixedbugs/issue48558.go
new file mode 100644 (file)
index 0000000..9ab56d9
--- /dev/null
@@ -0,0 +1,77 @@
+// errorcheck
+
+// Copyright 2021 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 _(a, b, c int) {
+       _ = a
+       _ = a, b    // ERROR "assignment mismatch: 1 variable but 2 values"
+       _ = a, b, c // ERROR "assignment mismatch: 1 variable but 3 values"
+
+       _, _ = a // ERROR "assignment mismatch: 2 variables but 1 value"
+       _, _ = a, b
+       _, _ = a, b, c // ERROR "assignment mismatch: 2 variables but 3 values"
+
+       _, _, _ = a    // ERROR "assignment mismatch: 3 variables but 1 value"
+       _, _, _ = a, b // ERROR "assignment mismatch: 3 variables but 2 values"
+       _, _, _ = a, b, c
+}
+
+func f1() int
+func f2() (int, int)
+func f3() (int, int, int)
+
+func _() {
+       _ = f1()
+       _ = f2() // ERROR "assignment mismatch: 1 variable but f2 returns 2 values"
+       _ = f3() // ERROR "assignment mismatch: 1 variable but f3 returns 3 values"
+
+       _, _ = f1() // ERROR "assignment mismatch: 2 variables but f1 returns 1 value"
+       _, _ = f2()
+       _, _ = f3() // ERROR "assignment mismatch: 2 variables but f3 returns 3 values"
+
+       _, _, _ = f1() // ERROR "assignment mismatch: 3 variables but f1 returns 1 value"
+       _, _, _ = f2() // ERROR "assignment mismatch: 3 variables but f2 returns 2 values"
+       _, _, _ = f3()
+
+       // test just a few := cases as they use the same code as the = case
+       a1 := f3()         // ERROR "assignment mismatch: 1 variable but f3 returns 3 values"
+       a2, b2 := f1()     // ERROR "assignment mismatch: 2 variables but f1 returns 1 value"
+       a3, b3, c3 := f2() // ERROR "assignment mismatch: 3 variables but f2 returns 2 values"
+}
+
+type T struct{}
+
+func (T) f1() int
+func (T) f2() (int, int)
+func (T) f3() (int, int, int)
+
+func _(x T) {
+       _ = x.f1()
+       _ = x.f2() // ERROR "assignment mismatch: 1 variable but .\.f2 returns 2 values"
+       _ = x.f3() // ERROR "assignment mismatch: 1 variable but .\.f3 returns 3 values"
+
+       _, _ = x.f1() // ERROR "assignment mismatch: 2 variables but .\.f1 returns 1 value"
+       _, _ = x.f2()
+       _, _ = x.f3() // ERROR "assignment mismatch: 2 variables but .\.f3 returns 3 values"
+
+       _, _, _ = x.f1() // ERROR "assignment mismatch: 3 variables but .\.f1 returns 1 value"
+       _, _, _ = x.f2() // ERROR "assignment mismatch: 3 variables but .\.f2 returns 2 values"
+       _, _, _ = x.f3()
+
+       // test just a few := cases as they use the same code as the = case
+       a1 := x.f3()         // ERROR "assignment mismatch: 1 variable but .\.f3 returns 3 values"
+       a2, b2 := x.f1()     // ERROR "assignment mismatch: 2 variables but .\.f1 returns 1 value"
+       a3, b3, c3 := x.f2() // ERROR "assignment mismatch: 3 variables but .\.f2 returns 2 values"
+}
+
+// some one-off cases
+func _() {
+       _ = (f2)
+       _ = f1(), 2         // ERROR "assignment mismatch: 1 variable but 2 values"
+       _, _ = (f1()), f2() // ERROR "multiple-value f2\(\) .*in single-value context"
+       _, _, _ = f3(), 3   // ERROR "assignment mismatch: 3 variables but 2 values|multiple-value f3\(\) .*in single-value context"
+}
diff --git a/test/fixedbugs/issue48784.go b/test/fixedbugs/issue48784.go
new file mode 100644 (file)
index 0000000..b07f524
--- /dev/null
@@ -0,0 +1,23 @@
+// errorcheck -e
+
+// Copyright 2021 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{}
+
+var s string
+var b bool
+var i int
+var t T
+var a [1]int
+
+var (
+       _ = s == nil // ERROR "invalid operation:.*mismatched types string and (untyped )?nil"
+       _ = b == nil // ERROR "invalid operation:.*mismatched types bool and (untyped )?nil"
+       _ = i == nil // ERROR "invalid operation:.*mismatched types int and (untyped )?nil"
+       _ = t == nil // ERROR "invalid operation:.*mismatched types T and (untyped )?nil"
+       _ = a == nil // ERROR "invalid operation:.*mismatched types \[1\]int and (untyped )?nil"
+)
diff --git a/test/fixedbugs/issue48898.go b/test/fixedbugs/issue48898.go
new file mode 100644 (file)
index 0000000..c3af164
--- /dev/null
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2021 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() {
+       defer func() {
+               println(recover().(int))
+       }()
+       func() {
+               func() (_ [2]int) { type _ int; return }()
+               func() {
+                       defer func() {
+                               defer func() {
+                                       recover()
+                               }()
+                               defer panic(3)
+                               panic(2)
+                       }()
+                       defer func() {
+                               recover()
+                       }()
+                       panic(1)
+               }()
+               defer func() {}()
+       }()
+
+       var x = 123
+       func() {
+               // in the original issue, this defer was not executed (which is incorrect)
+               defer print(x)
+               func() {
+                       defer func() {}()
+                       panic(4)
+               }()
+       }()
+}
diff --git a/test/fixedbugs/issue48898.out b/test/fixedbugs/issue48898.out
new file mode 100644 (file)
index 0000000..81c545e
--- /dev/null
@@ -0,0 +1 @@
+1234
diff --git a/test/fixedbugs/issue48916.go b/test/fixedbugs/issue48916.go
new file mode 100644 (file)
index 0000000..cbe97b5
--- /dev/null
@@ -0,0 +1,37 @@
+// compile
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 48916: expand_calls pass crashes due to a (dead)
+// use of an OpInvalid value.
+
+package p
+
+type T struct {
+       num int64
+}
+
+func foo(vs map[T]struct{}, d T) error {
+       _, ok := vs[d]
+       if !ok {
+               return nil
+       }
+
+       switch d.num {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+               var num float64
+               if num != 0 {
+                       return nil
+               }
+       }
+
+       return nil
+}
diff --git a/test/fixedbugs/issue49003.go b/test/fixedbugs/issue49003.go
new file mode 100644 (file)
index 0000000..da6c19b
--- /dev/null
@@ -0,0 +1,12 @@
+// errorcheck
+
+// Copyright 2021 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(s string) int {
+       for range s {
+       }
+} // ERROR "missing return"
diff --git a/test/fixedbugs/issue49005a.go b/test/fixedbugs/issue49005a.go
new file mode 100644 (file)
index 0000000..55d92c4
--- /dev/null
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2021 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 interface{ M() }
+
+func F() T
+
+var _ = F().(*X) // ERROR "undefined: X"
diff --git a/test/fixedbugs/issue49005b.go b/test/fixedbugs/issue49005b.go
new file mode 100644 (file)
index 0000000..9bff4e9
--- /dev/null
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2021 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 interface{ M() }
+
+func F() T
+
+var _ = F().(*X) // ERROR "impossible type assertion:( F\(\).\(\*X\))?\n\t\*X does not implement T \(missing M method\)"
+
+type X struct{}
diff --git a/test/fixedbugs/issue49016.dir/a.go b/test/fixedbugs/issue49016.dir/a.go
new file mode 100644 (file)
index 0000000..36639b7
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2021 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
+
+type Node interface {
+       Position()
+}
+
+type noder struct{}
+
+func (noder) Position() {}
+
+type Scope map[int][]Node
+
+func (s Scope) M1() Scope {
+       if x, ok := s[0]; ok {
+               return x[0].(struct {
+                       noder
+                       Scope
+               }).Scope
+       }
+       return nil
+}
+
+func (s Scope) M2() Scope {
+       if x, ok := s[0]; ok {
+               st, _ := x[0].(struct {
+                       noder
+                       Scope
+               })
+               return st.Scope
+       }
+       return nil
+}
diff --git a/test/fixedbugs/issue49016.dir/b.go b/test/fixedbugs/issue49016.dir/b.go
new file mode 100644 (file)
index 0000000..1dd63f8
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2021 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
+
+type t int
+
+func (t) m() {}
+
+func F1() interface{} { return struct{ t }{} }
+func F2() interface{} { return *new(struct{ t }) }
+func F3() interface{} { var x [1]struct{ t }; return x[0] }
diff --git a/test/fixedbugs/issue49016.dir/c.go b/test/fixedbugs/issue49016.dir/c.go
new file mode 100644 (file)
index 0000000..2cc6681
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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 c
+
+import "./a"
+
+var _ = (&a.Scope{}).M1()
diff --git a/test/fixedbugs/issue49016.dir/d.go b/test/fixedbugs/issue49016.dir/d.go
new file mode 100644 (file)
index 0000000..e933dc0
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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 d
+
+import "./a"
+
+var _ = (&a.Scope{}).M2()
diff --git a/test/fixedbugs/issue49016.dir/e.go b/test/fixedbugs/issue49016.dir/e.go
new file mode 100644 (file)
index 0000000..5f43179
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 e
+
+import (
+       "./b"
+)
+
+var _ = b.F1()
diff --git a/test/fixedbugs/issue49016.dir/f.go b/test/fixedbugs/issue49016.dir/f.go
new file mode 100644 (file)
index 0000000..2cd978e
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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 f
+
+import "./b"
+
+var _ = b.F2()
diff --git a/test/fixedbugs/issue49016.dir/g.go b/test/fixedbugs/issue49016.dir/g.go
new file mode 100644 (file)
index 0000000..b90353f
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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 g
+
+import "./b"
+
+var _ = b.F3()
diff --git a/test/fixedbugs/issue49016.go b/test/fixedbugs/issue49016.go
new file mode 100644 (file)
index 0000000..b83fbd7
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 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/issue49029.go b/test/fixedbugs/issue49029.go
new file mode 100644 (file)
index 0000000..51c9a78
--- /dev/null
@@ -0,0 +1,25 @@
+// compile
+
+// Copyright 2021 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 s struct {
+       f func()
+}
+
+func f() {
+       ch := make(chan struct{}, 1)
+       _ = [...]struct{ slice []s }{
+               {}, {}, {}, {},
+               {
+                       slice: []s{
+                               {
+                                       f: func() { ch <- struct{}{} },
+                               },
+                       },
+               },
+       }
+}
diff --git a/test/fixedbugs/issue49094.dir/a.go b/test/fixedbugs/issue49094.dir/a.go
new file mode 100644 (file)
index 0000000..9ec0fd9
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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
+
+type A struct{}
+
+func (a *A) f() bool {
+       return true
+}
diff --git a/test/fixedbugs/issue49094.dir/b.go b/test/fixedbugs/issue49094.dir/b.go
new file mode 100644 (file)
index 0000000..f236195
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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
+
+import "./a"
+
+func M(r *a.A) string {
+       return ""
+}
diff --git a/test/fixedbugs/issue49094.dir/p.go b/test/fixedbugs/issue49094.dir/p.go
new file mode 100644 (file)
index 0000000..581faf1
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 (
+       "./b"
+)
+
+type S struct{}
+
+func (S) M() {
+       b.M(nil)
+}
diff --git a/test/fixedbugs/issue49094.go b/test/fixedbugs/issue49094.go
new file mode 100644 (file)
index 0000000..b83fbd7
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2021 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/issue49100.go b/test/fixedbugs/issue49100.go
new file mode 100644 (file)
index 0000000..3a2e972
--- /dev/null
@@ -0,0 +1,27 @@
+// run
+
+// 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.
+
+package main
+
+func f(j int) {
+loop:
+       for i := 0; i < 4; i++ {
+               if i == 1 {
+                       continue loop
+               }
+               println(j, i)
+       }
+}
+
+func main() {
+loop:
+       for j := 0; j < 5; j++ {
+               f(j)
+               if j == 3 {
+                       break loop
+               }
+       }
+}
diff --git a/test/fixedbugs/issue49100.out b/test/fixedbugs/issue49100.out
new file mode 100644 (file)
index 0000000..326d413
--- /dev/null
@@ -0,0 +1,12 @@
+0 0
+0 2
+0 3
+1 0
+1 2
+1 3
+2 0
+2 2
+2 3
+3 0
+3 2
+3 3
diff --git a/test/fixedbugs/issue49100b.go b/test/fixedbugs/issue49100b.go
new file mode 100644 (file)
index 0000000..992ff96
--- /dev/null
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2021 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 r(j int) {
+loop:
+       for i, c := range "goclang" {
+               if i == 2 {
+                       continue loop
+               }
+               println(string(c))
+       }
+}
+
+func main() {
+loop:
+       for j := 0; j < 4; j++ {
+               r(j)
+               if j == 0 {
+                       break loop
+               }
+       }
+}
diff --git a/test/fixedbugs/issue49100b.out b/test/fixedbugs/issue49100b.out
new file mode 100644 (file)
index 0000000..d5abb92
--- /dev/null
@@ -0,0 +1,6 @@
+g
+o
+l
+a
+n
+g
diff --git a/test/fixedbugs/issue49110.go b/test/fixedbugs/issue49110.go
new file mode 100644 (file)
index 0000000..5e1bde9
--- /dev/null
@@ -0,0 +1,16 @@
+// run
+
+// Copyright 2021 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 main() {
+       _ = reflect.StructOf([]reflect.StructField{
+               {Name: "_", PkgPath: "main", Type: reflect.TypeOf(int(0))},
+               {Name: "_", PkgPath: "main", Type: reflect.TypeOf(int(0))},
+       })
+}
diff --git a/test/fixedbugs/issue49122.go b/test/fixedbugs/issue49122.go
new file mode 100644 (file)
index 0000000..c62a627
--- /dev/null
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2021 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
+
+var B []bool
+var N int
+
+func f(p bool, m map[bool]bool) bool {
+       var q bool
+       _ = p || N&N < N || B[0] || B[0]
+       return p && q && m[q]
+}
diff --git a/test/fixedbugs/issue49143.dir/a.go b/test/fixedbugs/issue49143.dir/a.go
new file mode 100644 (file)
index 0000000..5aefcd8
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2021 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 "sync"
+
+type Loader[K comparable, R any] struct {
+       batch *LoaderBatch[K, R]
+}
+
+func (l *Loader[K, R]) Load() error {
+       l.batch.f()
+       return nil
+}
+
+type LoaderBatch[K comparable, R any] struct {
+       once    *sync.Once
+}
+
+func (b *LoaderBatch[K, R]) f() {
+       b.once.Do(func() {})
+}
diff --git a/test/fixedbugs/issue49143.dir/b.go b/test/fixedbugs/issue49143.dir/b.go
new file mode 100644 (file)
index 0000000..48eecdb
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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
+
+import "./a"
+
+
+type Loaders struct {
+       Loader *a.Loader[int, int]
+}
+
+func NewLoaders() *Loaders {
+       return new(Loaders)
+}
diff --git a/test/fixedbugs/issue49143.dir/c.go b/test/fixedbugs/issue49143.dir/c.go
new file mode 100644 (file)
index 0000000..89262e3
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 c
+
+import "./b"
+
+type Resolver struct{}
+
+type todoResolver struct{ *Resolver }
+
+func (r *todoResolver) F() {
+       b.NewLoaders().Loader.Load()
+}
diff --git a/test/fixedbugs/issue49143.dir/p.go b/test/fixedbugs/issue49143.dir/p.go
new file mode 100644 (file)
index 0000000..f11d2f2
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 (
+       "./c"
+)
+
+var _ = &c.Resolver{}
diff --git a/test/fixedbugs/issue49143.go b/test/fixedbugs/issue49143.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -G=3
+
+// Copyright 2021 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/issue49145.go b/test/fixedbugs/issue49145.go
new file mode 100644 (file)
index 0000000..d666681
--- /dev/null
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2021 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 f(j int) {
+loop:
+       switch j {
+       case 1:
+               break loop
+       default:
+               println(j)
+       }
+}
+
+func main() {
+loop:
+       for j := 0; j < 5; j++ {
+               f(j)
+               if j == 3 {
+                       break loop
+               }
+       }
+}
diff --git a/test/fixedbugs/issue49145.out b/test/fixedbugs/issue49145.out
new file mode 100644 (file)
index 0000000..1556c06
--- /dev/null
@@ -0,0 +1,3 @@
+0
+2
+3
diff --git a/test/fixedbugs/issue49240.go b/test/fixedbugs/issue49240.go
new file mode 100644 (file)
index 0000000..26929fe
--- /dev/null
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2021 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() {
+       go copy([]int{1: 0}, []int{})
+}
diff --git a/test/fixedbugs/issue49249.go b/test/fixedbugs/issue49249.go
new file mode 100644 (file)
index 0000000..f152a5a
--- /dev/null
@@ -0,0 +1,55 @@
+// compile -l
+
+// Copyright 2021 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() int {
+       var a, b struct {
+               s struct {
+                       s struct {
+                               byte
+                               float32
+                       }
+               }
+       }
+       _ = a
+
+       return func() int {
+               return func() int {
+                       a = struct {
+                               s struct {
+                                       s struct {
+                                               byte
+                                               float32
+                                       }
+                               }
+                       }{b.s}
+                       return 0
+               }()
+       }()
+}
+
+func g() int {
+       var a, b struct {
+               s [1][1]struct {
+                       byte
+                       float32
+               }
+       }
+       _ = a
+
+       return func() int {
+               return func() int {
+                       a = struct {
+                               s [1][1]struct {
+                                       byte
+                                       float32
+                               }
+                       }{b.s}
+                       return 0
+               }()
+       }()
+}
index f5c5296a2bf7c60dd05f8cdc6ebeb302e2c72195..ea53e7a69ae0b2c7c77a0e6cbb2942236bf3f61e 100644 (file)
@@ -13,12 +13,10 @@ const zero = 0
 
 func main() {
        var x int
-       _ = x
-       x = make(map[int]int) // ERROR "cannot use make\(map\[int\]int\)|incompatible"
-       x = make(map[int]int, 0) // ERROR "cannot use make\(map\[int\]int, 0\)|incompatible"
+       x = make(map[int]int)       // ERROR "cannot use make\(map\[int\]int\)|incompatible"
+       x = make(map[int]int, 0)    // ERROR "cannot use make\(map\[int\]int, 0\)|incompatible"
        x = make(map[int]int, zero) // ERROR "cannot use make\(map\[int\]int, zero\)|incompatible"
-       x = make(chan int) // ERROR "cannot use make\(chan int\)|incompatible"
-       x = make(chan int, 0) // ERROR "cannot use make\(chan int, 0\)|incompatible"
-       x = make(chan int, zero) // ERROR "cannot use make\(chan int, zero\)|incompatible"
-       _ = x
+       x = make(chan int)          // ERROR "cannot use make\(chan int\)|incompatible"
+       x = make(chan int, 0)       // ERROR "cannot use make\(chan int, 0\)|incompatible"
+       x = make(chan int, zero)    // ERROR "cannot use make\(chan int, zero\)|incompatible"
 }
index a73c0ba7b1da0f185268f35d76801252744a6d25..d0ebe84aa5fcee84106a07fb44e33b8a03c3fb71 100644 (file)
@@ -135,8 +135,7 @@ func s1(x int) int { // ERROR "can inline s1"
        return foo() // ERROR "inlining call to s1.func1"
 }
 
-// can't currently inline functions with a break statement
-func switchBreak(x, y int) int {
+func switchBreak(x, y int) int { // ERROR "can inline switchBreak"
        var n int
        switch x {
        case 0:
@@ -161,6 +160,19 @@ func switchType(x interface{}) int { // ERROR "can inline switchType" "x does no
        }
 }
 
+func inlineRangeIntoMe(data []int) { // ERROR "can inline inlineRangeIntoMe" "data does not escape"
+       rangeFunc(data, 12) // ERROR "inlining call to rangeFunc"
+}
+
+func rangeFunc(xs []int, b int) int { // ERROR "can inline rangeFunc" "xs does not escape"
+       for i, x := range xs {
+               if x == b {
+                       return i
+               }
+       }
+       return -1
+}
+
 type T struct{}
 
 func (T) meth(int, int) {} // ERROR "can inline T.meth"
@@ -218,8 +230,7 @@ func for1(fn func() bool) { // ERROR "can inline for1" "fn does not escape"
        }
 }
 
-// BAD: for2 should be inlineable too.
-func for2(fn func() bool) { // ERROR "fn does not escape"
+func for2(fn func() bool) { // ERROR "can inline for2" "fn does not escape"
 Loop:
        for {
                if fn() {
diff --git a/test/inline_endian.go b/test/inline_endian.go
new file mode 100644 (file)
index 0000000..e00e06a
--- /dev/null
@@ -0,0 +1,23 @@
+// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
+
+//go:build (386 || amd64 || arm64 || ppc64le || s390x) && !gcflags_noopt
+// +build 386 amd64 arm64 ppc64le s390x
+// +build !gcflags_noopt
+
+// Copyright 2021 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.
+
+// Similar to inline.go, but only for architectures that can merge loads.
+
+package foo
+
+import (
+       "encoding/binary"
+)
+
+// Ensure that simple encoding/binary functions are cheap enough
+// that functions using them can also be inlined (issue 42958).
+func endian(b []byte) uint64 { // ERROR "can inline endian" "b does not escape"
+       return binary.LittleEndian.Uint64(b) + binary.BigEndian.Uint64(b) // ERROR "inlining call to binary.littleEndian.Uint64" "inlining call to binary.bigEndian.Uint64"
+}
index c21e4da390ab0fd92df3288c2d2d64fe994eb649..a71b3f4bf89ddd2f048ec4913ea1cb91e0faebcb 100644 (file)
@@ -24,7 +24,6 @@ type Start struct {
 
 func (start *Start) Next() *Inst { return nil }
 
-
 func AddInst(Inst) *Inst {
        print("ok in addinst\n")
        return nil
@@ -33,8 +32,6 @@ func AddInst(Inst) *Inst {
 func main() {
        print("call addinst\n")
        var x Inst = AddInst(new(Start)) // ERROR "pointer to interface|incompatible type"
-       _ = x
        print("return from  addinst\n")
-       var y *Inst = new(Start)  // ERROR "pointer to interface|incompatible type"
-       _ = y
+       var y *Inst = new(Start) // ERROR "pointer to interface|incompatible type"
 }
index c61a0d7d95ce09259d389d7d1220bd96476dc73b..7d51b94802841f23e34e989dff025f538d15e124 100644 (file)
@@ -1,6 +1,6 @@
 package x
 
-func indexByte(xs []byte, b byte) int { // ERROR "xs does not escape"
+func indexByte(xs []byte, b byte) int { // ERROR "xs does not escape" "can inline indexByte"
        for i, x := range xs {
                if x == b {
                        return i
index 43e66a584958bbb03fd2177b01b20f87c62c6871..cb7f9be3452a04a247391c5fc6c54a1b4e68f183 100644 (file)
@@ -16,13 +16,10 @@ var x, y int
 //go:linkname x ok
 
 // ERROR "//go:linkname requires linkname argument or -p compiler flag"
-// BAD: want error "//go:linkname must refer to declared function or variable"
-// BAD: want error "//go:linkname must refer to declared function or variable"
+// ERROR "//go:linkname must refer to declared function or variable"
+// ERROR "//go:linkname must refer to declared function or variable"
 // ERROR "duplicate //go:linkname for x"
 
-// The two BAD lines are just waiting for #42938 before we can
-// re-enable the errors.
-
 //line linkname2.go:18
 //go:linkname y
 //go:linkname nonexist nonexist
index 2883b83baedff28f9c275f38888cd1238659c7d4..aac9a7766c02fe61189fa6ae8ad8240dc4e88330 100644 (file)
@@ -1,5 +1,5 @@
 // errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
-// +build amd64,goexperiment.regabiargs
+// +build amd64,goexperiment.regabiargs arm64,goexperiment.regabiargs
 
 // Copyright 2014 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/test/maymorestack.go b/test/maymorestack.go
new file mode 100644 (file)
index 0000000..ec84ad4
--- /dev/null
@@ -0,0 +1,47 @@
+// run -gcflags=-d=maymorestack=main.mayMoreStack
+
+// Copyright 2021 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 the maymorestack testing hook by injecting a hook that counts
+// how many times it is called and checking that count.
+
+package main
+
+import "runtime"
+
+var count uint32
+
+//go:nosplit
+func mayMoreStack() {
+       count++
+}
+
+func main() {
+       const wantCount = 128
+
+       anotherFunc(wantCount - 1) // -1 because the call to main already counted
+
+       if count == 0 {
+               panic("mayMoreStack not called")
+       } else if count != wantCount {
+               println(count, "!=", wantCount)
+               panic("wrong number of calls to mayMoreStack")
+       }
+}
+
+//go:noinline
+func anotherFunc(n int) {
+       // Trigger a stack growth on at least some calls to
+       // anotherFunc to test that mayMoreStack is called outside the
+       // morestack loop. It's also important that it is called
+       // before (not after) morestack, but that's hard to test.
+       var x [1 << 10]byte
+
+       if n > 1 {
+               anotherFunc(n - 1)
+       }
+
+       runtime.KeepAlive(x)
+}
index 42429978b45a691297fd1eba287b6b52dc774599..688238c5119fa68d97cc3d1906033ebf5c82f18d 100644 (file)
@@ -16,7 +16,7 @@ func (s S) M() {}
 
 func main() {
        t := reflect.TypeOf(S(0))
-       fn, ok := reflect.PtrTo(t).MethodByName("M")
+       fn, ok := reflect.PointerTo(t).MethodByName("M")
        if !ok {
                panic("FAIL")
        }
index 6296234d56588ff93a1d153414962c6c6d0a96cd..942fd032f2165a55ce64f5c2bfee94fcdac99a34 100644 (file)
@@ -32,6 +32,10 @@ import (
        "unicode"
 )
 
+// CompilerDefaultGLevel is the -G level used by default when not overridden by a
+// command-line flag
+const CompilerDefaultGLevel = 3
+
 var (
        verbose        = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
        keep           = flag.Bool("k", false, "keep. keep temporary directory.")
@@ -81,12 +85,12 @@ var unifiedEnabled, defaultGLevels = func() (bool, string) {
        // won't need to disable tests for it anymore anyway.
        enabled := strings.Contains(","+env.GOEXPERIMENT+",", ",unified,")
 
-       // Normal test runs should test with both -G=0 and -G=3 for types2
-       // coverage. But the unified experiment always uses types2, so
-       // testing with -G=3 is redundant.
-       glevels := "0,3"
-       if enabled {
-               glevels = "0"
+       // Test both -G=0 and -G=3 on the longtest builders, to make sure we
+       // don't accidentally break -G=0 mode until we're ready to remove it
+       // completely. But elsewhere, testing -G=3 alone should be enough.
+       glevels := "3"
+       if strings.Contains(os.Getenv("GO_BUILDER_NAME"), "longtest") {
+               glevels = "0,3"
        }
 
        return enabled, glevels
@@ -340,13 +344,18 @@ type test struct {
 }
 
 // initExpectFail initializes t.expectFail based on the build+test
-// configuration. It should only be called for tests known to use
-// types2.
-func (t *test) initExpectFail() {
+// configuration.
+func (t *test) initExpectFail(hasGFlag bool) {
        if *force {
                return
        }
 
+       if t.glevel == 0 && !hasGFlag && !unifiedEnabled {
+               // tests should always pass when run w/o types2 (i.e., using the
+               // legacy typechecker, option -G=0).
+               return
+       }
+
        failureSets := []map[string]bool{types2Failures}
 
        // Note: gccgo supports more 32-bit architectures than this, but
@@ -526,9 +535,9 @@ func (ctxt *context) match(name string) bool {
        if name == "" {
                return false
        }
-       if i := strings.Index(name, ","); i >= 0 {
+       if first, rest, ok := strings.Cut(name, ","); ok {
                // comma-separated list
-               return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
+               return ctxt.match(first) && ctxt.match(rest)
        }
        if strings.HasPrefix(name, "!!") { // bad syntax, reject always
                return false
@@ -581,14 +590,14 @@ func init() { checkShouldTest() }
 // over and over.
 func (t *test) goGcflags() string {
        flags := os.Getenv("GO_GCFLAGS")
-       if t.glevel != 0 {
+       if t.glevel != CompilerDefaultGLevel {
                flags = fmt.Sprintf("%s -G=%v", flags, t.glevel)
        }
        return "-gcflags=all=" + flags
 }
 
 func (t *test) goGcflagsIsEmpty() bool {
-       return "" == os.Getenv("GO_GCFLAGS") && t.glevel == 0
+       return "" == os.Getenv("GO_GCFLAGS") && t.glevel == CompilerDefaultGLevel
 }
 
 var errTimeout = errors.New("command exceeded time limit")
@@ -613,24 +622,23 @@ func (t *test) run() {
        }
 
        // Execution recipe stops at first blank line.
-       pos := strings.Index(t.src, "\n\n")
-       if pos == -1 {
+       action, _, ok := strings.Cut(t.src, "\n\n")
+       if !ok {
                t.err = fmt.Errorf("double newline ending execution recipe not found in %s", t.goFileName())
                return
        }
-       action := t.src[:pos]
-       if nl := strings.Index(action, "\n"); nl >= 0 && strings.Contains(action[:nl], "+build") {
+       if firstLine, rest, ok := strings.Cut(action, "\n"); ok && strings.Contains(firstLine, "+build") {
                // skip first line
-               action = action[nl+1:]
+               action = rest
        }
        action = strings.TrimPrefix(action, "//")
 
        // Check for build constraints only up to the actual code.
-       pkgPos := strings.Index(t.src, "\npackage")
-       if pkgPos == -1 {
-               pkgPos = pos // some files are intentionally malformed
+       header, _, ok := strings.Cut(t.src, "\npackage")
+       if !ok {
+               header = action // some files are intentionally malformed
        }
-       if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
+       if ok, why := shouldTest(header, goos, goarch); !ok {
                if *showSkips {
                        fmt.Printf("%-20s %-20s: %s\n", "skip", t.goFileName(), why)
                }
@@ -750,7 +758,8 @@ func (t *test) run() {
                        }
                }
 
-               if hasGFlag && t.glevel != 0 {
+               // In unified IR mode, run the test regardless of explicit -G flag.
+               if !unifiedEnabled && hasGFlag && t.glevel != CompilerDefaultGLevel {
                        // test provides explicit -G flag already; don't run again
                        if *verbose {
                                fmt.Printf("excl\t%s\n", t.goFileName())
@@ -758,13 +767,7 @@ func (t *test) run() {
                        return false
                }
 
-               if t.glevel == 0 && !hasGFlag && !unifiedEnabled {
-                       // tests should always pass when run w/o types2 (i.e., using the
-                       // legacy typechecker).
-                       return true
-               }
-
-               t.initExpectFail()
+               t.initExpectFail(hasGFlag)
 
                switch tool {
                case Build, Run:
@@ -776,11 +779,13 @@ func (t *test) run() {
                        }
 
                default:
-                       // we don't know how to add -G for this test yet
-                       if *verbose {
-                               fmt.Printf("excl\t%s\n", t.goFileName())
+                       if t.glevel != CompilerDefaultGLevel {
+                               // we don't know how to add -G for this test yet
+                               if *verbose {
+                                       fmt.Printf("excl\t%s\n", t.goFileName())
+                               }
+                               return false
                        }
-                       return false
                }
 
                return true
@@ -1510,8 +1515,8 @@ func (t *test) errorCheck(outStr string, wantAuto bool, fullshort ...string) (er
                        // Assume errmsg says "file:line: foo".
                        // Cut leading "file:line: " to avoid accidental matching of file name instead of message.
                        text := errmsg
-                       if i := strings.Index(text, " "); i >= 0 {
-                               text = text[i+1:]
+                       if _, suffix, ok := strings.Cut(text, " "); ok {
+                               text = suffix
                        }
                        if we.re.MatchString(text) {
                                matched = true
@@ -1556,31 +1561,26 @@ func (t *test) updateErrors(out, file string) {
        }
        lines := strings.Split(string(src), "\n")
        // Remove old errors.
-       for i, ln := range lines {
-               pos := strings.Index(ln, " // ERROR ")
-               if pos >= 0 {
-                       lines[i] = ln[:pos]
-               }
+       for i := range lines {
+               lines[i], _, _ = strings.Cut(lines[i], " // ERROR ")
        }
        // Parse new errors.
        errors := make(map[int]map[string]bool)
        tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
        for _, errStr := range splitOutput(out, false) {
-               colon1 := strings.Index(errStr, ":")
-               if colon1 < 0 || errStr[:colon1] != file {
+               errFile, rest, ok := strings.Cut(errStr, ":")
+               if !ok || errFile != file {
                        continue
                }
-               colon2 := strings.Index(errStr[colon1+1:], ":")
-               if colon2 < 0 {
+               lineStr, msg, ok := strings.Cut(rest, ":")
+               if !ok {
                        continue
                }
-               colon2 += colon1 + 1
-               line, err := strconv.Atoi(errStr[colon1+1 : colon2])
+               line, err := strconv.Atoi(lineStr)
                line--
                if err != nil || line < 0 || line >= len(lines) {
                        continue
                }
-               msg := errStr[colon2+2:]
                msg = strings.Replace(msg, file, base, -1) // normalize file mentions in error itself
                msg = strings.TrimLeft(msg, " \t")
                for _, r := range []string{`\`, `*`, `+`, `?`, `[`, `]`, `(`, `)`} {
@@ -1747,7 +1747,7 @@ var (
        // are the supported variants.
        archVariants = map[string][]string{
                "386":     {"GO386", "sse2", "softfloat"},
-               "amd64":   {},
+               "amd64":   {"GOAMD64", "v1", "v2", "v3", "v4"},
                "arm":     {"GOARM", "5", "6", "7"},
                "arm64":   {},
                "mips":    {"GOMIPS", "hardfloat", "softfloat"},
@@ -1756,6 +1756,7 @@ var (
                "ppc64le": {"GOPPC64", "power8", "power9"},
                "s390x":   {},
                "wasm":    {},
+               "riscv64": {},
        }
 )
 
@@ -2177,14 +2178,7 @@ var types2Failures32Bit = setOf(
 )
 
 var g3Failures = setOf(
-       "writebarrier.go", // correct diagnostics, but different lines (probably irgen's fault)
-
-       "fixedbugs/issue30862.go", // -G=3 doesn't handle //go:nointerface
-
        "typeparam/nested.go", // -G=3 doesn't support function-local types with generics
-
-       "typeparam/mdempsky/4.go",  // -G=3 can't export functions with labeled breaks in loops
-       "typeparam/mdempsky/15.go", // ICE in (*irgen).buildClosure
 )
 
 var unifiedFailures = setOf(
@@ -2194,6 +2188,7 @@ var unifiedFailures = setOf(
 
        "fixedbugs/issue42284.go", // prints "T(0) does not escape", but test expects "a.I(a.T(0)) does not escape"
        "fixedbugs/issue7921.go",  // prints "… escapes to heap", but test expects "string(…) escapes to heap"
+       "typeparam/issue48538.go", // assertion failure, interprets struct key as closure variable
 )
 
 func setOf(keys ...string) map[string]bool {
index 4f95d02615dbdb5b94adaf6d04d3b6b1b372f3af..b9d9800391816012d29ab5513c2aa9f8a1416995 100644 (file)
@@ -15,7 +15,7 @@ package main
 // Verify that type switch statements with impossible cases are detected by the compiler.
 func f0(e error) {
        switch e.(type) {
-       case int: // ERROR "impossible type switch case: e \(type error\) cannot have dynamic type int \(missing Error method\)|impossible type assertion"
+       case int: // ERROR "impossible type switch case: (int\n\t)?e \(.*type error\) cannot have dynamic type int \(missing Error method\)"
        }
 }
 
@@ -41,6 +41,6 @@ func (*X) Foo() {}
 func f2() {
        var i I
        switch i.(type) {
-       case X: // ERROR "impossible type switch case: i \(type I\) cannot have dynamic type X \(Foo method has pointer receiver\)|impossible type assertion"
+       case X: // ERROR "impossible type switch case: (X\n\t)?i \(.*type I\) cannot have dynamic type X \(Foo method has pointer receiver\)"
        }
 }
index cad6e84c4e496b5c5c76e42f86833605d9bc3e6f..f1822831b2773fcbe8afe44d624158d3390463d4 100644 (file)
@@ -6,11 +6,6 @@
 
 package main
 
-import (
-       "fmt"
-       "math"
-)
-
 type Numeric interface {
        ~int | ~int8 | ~int16 | ~int32 | ~int64 |
                ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
@@ -43,55 +38,57 @@ type Complex interface {
        ~complex64 | ~complex128
 }
 
-// orderedAbs is a helper type that defines an Abs method for
-// ordered numeric types.
-type orderedAbs[T orderedNumeric] T
-
-func (a orderedAbs[T]) Abs() orderedAbs[T] {
-       if a < 0 {
-               return -a
-       }
-       return a
-}
-
-// complexAbs is a helper type that defines an Abs method for
-// complex types.
-type complexAbs[T Complex] T
-
-func (a complexAbs[T]) Abs() complexAbs[T] {
-       r := float64(real(a))
-       i := float64(imag(a))
-       d := math.Sqrt(r*r + i*i)
-       return complexAbs[T](complex(d, 0))
-}
-
-// OrderedAbsDifference returns the absolute value of the difference
-// between a and b, where a and b are of an ordered type.
-func orderedAbsDifference[T orderedNumeric](a, b T) T {
-       return T(absDifference(orderedAbs[T](a), orderedAbs[T](b)))
-}
-
-// ComplexAbsDifference returns the absolute value of the difference
-// between a and b, where a and b are of a complex type.
-func complexAbsDifference[T Complex](a, b T) T {
-       return T(absDifference(complexAbs[T](a), complexAbs[T](b)))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // orderedAbs is a helper type that defines an Abs method for
+// // ordered numeric types.
+// type orderedAbs[T orderedNumeric] T
+//
+// func (a orderedAbs[T]) Abs() orderedAbs[T] {
+//     if a < 0 {
+//             return -a
+//     }
+//     return a
+// }
+//
+// // complexAbs is a helper type that defines an Abs method for
+// // complex types.
+// type complexAbs[T Complex] T
+//
+// func (a complexAbs[T]) Abs() complexAbs[T] {
+//     r := float64(real(a))
+//     i := float64(imag(a))
+//     d := math.Sqrt(r*r + i*i)
+//     return complexAbs[T](complex(d, 0))
+// }
+//
+// // OrderedAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of an ordered type.
+// func orderedAbsDifference[T orderedNumeric](a, b T) T {
+//     return T(absDifference(orderedAbs[T](a), orderedAbs[T](b)))
+// }
+//
+// // ComplexAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of a complex type.
+// func complexAbsDifference[T Complex](a, b T) T {
+//     return T(absDifference(complexAbs[T](a), complexAbs[T](b)))
+// }
 
 func main() {
-       if got, want := orderedAbsDifference(1.0, -2.0), 3.0; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-       if got, want := orderedAbsDifference(-1.0, 2.0), 3.0; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-       if got, want := orderedAbsDifference(-20, 15), 35; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-
-       if got, want := complexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-       if got, want := complexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
+       // // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+       // if got, want := orderedAbsDifference(1.0, -2.0), 3.0; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       // if got, want := orderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       // if got, want := orderedAbsDifference(-20, 15), 35; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       //
+       // if got, want := complexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       // if got, want := complexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
 }
index 7b5bfbe2aced91f92fdc096aafde63f1bc24fb6c..60822fdb8bd8691d92e5124df61b207686f386ca 100644 (file)
@@ -4,10 +4,6 @@
 
 package a
 
-import (
-       "math"
-)
-
 type Numeric interface {
        ~int | ~int8 | ~int16 | ~int32 | ~int64 |
                ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
@@ -40,36 +36,37 @@ type Complex interface {
        ~complex64 | ~complex128
 }
 
-// orderedAbs is a helper type that defines an Abs method for
-// ordered numeric types.
-type orderedAbs[T orderedNumeric] T
-
-func (a orderedAbs[T]) Abs() orderedAbs[T] {
-       if a < 0 {
-               return -a
-       }
-       return a
-}
-
-// complexAbs is a helper type that defines an Abs method for
-// complex types.
-type complexAbs[T Complex] T
-
-func (a complexAbs[T]) Abs() complexAbs[T] {
-       r := float64(real(a))
-       i := float64(imag(a))
-       d := math.Sqrt(r*r + i*i)
-       return complexAbs[T](complex(d, 0))
-}
-
-// OrderedAbsDifference returns the absolute value of the difference
-// between a and b, where a and b are of an ordered type.
-func OrderedAbsDifference[T orderedNumeric](a, b T) T {
-       return T(absDifference(orderedAbs[T](a), orderedAbs[T](b)))
-}
-
-// ComplexAbsDifference returns the absolute value of the difference
-// between a and b, where a and b are of a complex type.
-func ComplexAbsDifference[T Complex](a, b T) T {
-       return T(absDifference(complexAbs[T](a), complexAbs[T](b)))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// // orderedAbs is a helper type that defines an Abs method for
+// // ordered numeric types.
+// type orderedAbs[T orderedNumeric] T
+//
+// func (a orderedAbs[T]) Abs() orderedAbs[T] {
+//     if a < 0 {
+//             return -a
+//     }
+//     return a
+// }
+//
+// // complexAbs is a helper type that defines an Abs method for
+// // complex types.
+// type complexAbs[T Complex] T
+//
+// func (a complexAbs[T]) Abs() complexAbs[T] {
+//     r := float64(real(a))
+//     i := float64(imag(a))
+//     d := math.Sqrt(r*r + i*i)
+//     return complexAbs[T](complex(d, 0))
+// }
+//
+// // OrderedAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of an ordered type.
+// func OrderedAbsDifference[T orderedNumeric](a, b T) T {
+//     return T(absDifference(orderedAbs[T](a), orderedAbs[T](b)))
+// }
+//
+// // ComplexAbsDifference returns the absolute value of the difference
+// // between a and b, where a and b are of a complex type.
+// func ComplexAbsDifference[T Complex](a, b T) T {
+//     return T(absDifference(complexAbs[T](a), complexAbs[T](b)))
+// }
index 8eefdbdf384939cc8dba4ca7307fc183c4f04491..c648013327d345d59c343db64b1f337860a81384 100644 (file)
@@ -4,26 +4,22 @@
 
 package main
 
-import (
-       "a"
-       "fmt"
-)
-
 func main() {
-       if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-       if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-       if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-
-       if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
-       if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
-               panic(fmt.Sprintf("got = %v, want = %v", got, want))
-       }
+       // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+       // if got, want := a.OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       // if got, want := a.OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       // if got, want := a.OrderedAbsDifference(-20, 15), 35; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       //
+       // if got, want := a.ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
+       // if got, want := a.ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
+       //      panic(fmt.Sprintf("got = %v, want = %v", got, want))
+       // }
 }
index 221a6c758dcf4a1dfe8c48eb1b0c41aaa497db1b..24ce95472f4ab4c2f041730b07b08c74f7186f0a 100644 (file)
@@ -10,16 +10,18 @@ type R[T any] struct {
        F T
 }
 
-type S = R
+// type S = R // disallowed for now
 
 type Sint = R[int]
 
-type Simp = a.Rimp
+// type Simp = a.Rimp // disallowed for now
 
-type SimpString Simp[string]
+// type SimpString Simp[string] // disallowed for now
+type SimpString a.Rimp[string]
 
 func main() {
-       var s S[int]
+       // var s S[int] // disallowed for now
+       var s R[int]
        if s.F != 0 {
                panic(s.F)
        }
@@ -27,7 +29,8 @@ func main() {
        if s2.F != 0 {
                panic(s2.F)
        }
-       var s3 Simp[string]
+       // var s3 Simp[string] // disallowed for now
+       var s3 a.Rimp[string]
        if s3.F != "" {
                panic(s3.F)
        }
index 8b9bc2039fc310d5971c128bbefcefc44540ceba..42b542ed78c13c5e18061c61d13fd554fb52f432 100644 (file)
@@ -9,7 +9,7 @@ package main
 type Recv <-chan int
 
 type sliceOf[E any] interface {
-       type []E
+       ~[]E
 }
 
 func _Append[S sliceOf[T], T any](s S, t ...T) S {
index 22f416422da426ea6552a6a801b1eb0d53c12fdb..a14eb544ce73d45fe3b386cf46f96c770b715654 100644 (file)
@@ -59,12 +59,13 @@ type Ints interface {
        ~int32 | ~int
 }
 
-type StringInt[T Ints] T
-
-//go:noinline
-func (m StringInt[T]) String() string {
-       return strconv.Itoa(int(m))
-}
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type StringInt[T Ints] T
+//
+// //go:noinline
+// func (m StringInt[T]) String() string {
+//     return strconv.Itoa(int(m))
+// }
 
 type StringStruct[T Ints] struct {
        f T
@@ -84,22 +85,23 @@ func main() {
                panic(fmt.Sprintf("got %s, want %s", got, want))
        }
 
-       x2 := []StringInt[myint]{StringInt[myint](5), StringInt[myint](7), StringInt[myint](6)}
-
-       // stringify on an instantiated type, whose bound method is associated with
-       // the generic type StringInt[T], which maps directly to T.
-       got2 := stringify(x2)
-       want2 := []string{ "5", "7", "6" }
-       if !reflect.DeepEqual(got2, want2) {
-               panic(fmt.Sprintf("got %s, want %s", got2, want2))
-       }
+       // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+       // x2 := []StringInt[myint]{StringInt[myint](5), StringInt[myint](7), StringInt[myint](6)}
+       //
+       // // stringify on an instantiated type, whose bound method is associated with
+       // // the generic type StringInt[T], which maps directly to T.
+       // got2 := stringify(x2)
+       // want2 := []string{"5", "7", "6"}
+       // if !reflect.DeepEqual(got2, want2) {
+       //      panic(fmt.Sprintf("got %s, want %s", got2, want2))
+       // }
 
        // stringify on an instantiated type, whose bound method is associated with
        // the generic type StringStruct[T], which maps to a struct containing T.
        x3 := []StringStruct[myint]{StringStruct[myint]{f: 11}, StringStruct[myint]{f: 10}, StringStruct[myint]{f: 9}}
 
        got3 := stringify(x3)
-       want3 := []string{ "11", "10", "9" }
+       want3 := []string{"11", "10", "9"}
        if !reflect.DeepEqual(got3, want3) {
                panic(fmt.Sprintf("got %s, want %s", got3, want3))
        }
index 6ddb6b2d08b11238827d2ce2f71e8c19b886fcbf..3dbdd1b05eb593cbcc1a117ee7cbd08493e05be0 100644 (file)
@@ -19,7 +19,7 @@ type MySlice []int
 type MyFloatSlice []float64
 
 type _SliceOf[E any] interface {
-       type []E
+       ~[]E
 }
 
 func _DoubleElems[S _SliceOf[E], E Number](s S) S {
diff --git a/test/typeparam/eface.go b/test/typeparam/eface.go
new file mode 100644 (file)
index 0000000..1421b7f
--- /dev/null
@@ -0,0 +1,67 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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.
+
+// Make sure we handle instantiated empty interfaces.
+
+package main
+
+type E[T any] interface {
+}
+
+//go:noinline
+func f[T any](x E[T]) interface{} {
+       return x
+}
+
+//go:noinline
+func g[T any](x interface{}) E[T] {
+       return x
+}
+
+type I[T any] interface {
+       foo()
+}
+
+type myint int
+
+func (x myint) foo() {}
+
+//go:noinline
+func h[T any](x I[T]) interface{ foo() } {
+       return x
+}
+
+//go:noinline
+func i[T any](x interface{ foo() }) I[T] {
+       return x
+}
+
+func main() {
+       if f[int](1) != 1 {
+               println("test 1 failed")
+       }
+       if f[int](2) != (interface{})(2) {
+               println("test 2 failed")
+       }
+       if g[int](3) != 3 {
+               println("test 3 failed")
+       }
+       if g[int](4) != (E[int])(4) {
+               println("test 4 failed")
+       }
+       if h[int](myint(5)) != myint(5) {
+               println("test 5 failed")
+       }
+       if h[int](myint(6)) != interface{ foo() }(myint(6)) {
+               println("test 6 failed")
+       }
+       if i[int](myint(7)) != myint(7) {
+               println("test 7 failed")
+       }
+       if i[int](myint(8)) != I[int](myint(8)) {
+               println("test 8 failed")
+       }
+}
diff --git a/test/typeparam/genembed.go b/test/typeparam/genembed.go
new file mode 100644 (file)
index 0000000..43ab3d6
--- /dev/null
@@ -0,0 +1,52 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 wrappers/interfaces for generic type embedding another generic type.
+
+package main
+
+import "fmt"
+
+type A[T any] struct {
+       B[T]
+}
+
+type B[T any] struct {
+       val T
+}
+
+func (b *B[T]) get() T {
+       return b.val
+}
+
+type getter[T any] interface {
+       get() T
+}
+
+//go:noinline
+func doGet[T any](i getter[T]) T {
+       return i.get()
+}
+
+//go:noline
+func doGet2[T any](i interface{}) T {
+       i2 := i.(getter[T])
+       return i2.get()
+}
+
+func main() {
+       a := A[int]{B: B[int]{3}}
+       var i getter[int] = &a
+
+       if got, want := doGet(i), 3; got != want {
+               panic(fmt.Sprintf("got %v, want %v", got, want))
+       }
+
+       as := A[string]{B: B[string]{"abc"}}
+       if got, want := doGet2[string](&as), "abc"; got != want {
+               panic(fmt.Sprintf("got %v, want %v", got, want))
+       }
+}
diff --git a/test/typeparam/genembed2.go b/test/typeparam/genembed2.go
new file mode 100644 (file)
index 0000000..6effd2e
--- /dev/null
@@ -0,0 +1,46 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 for declaration and use of a parameterized embedded field.
+
+package main
+
+import (
+       "fmt"
+       "sync"
+)
+
+type MyStruct[T any] struct {
+       val T
+}
+
+type Lockable[T any] struct {
+       MyStruct[T]
+       mu sync.Mutex
+}
+
+// Get returns the value stored in a Lockable.
+func (l *Lockable[T]) Get() T {
+       l.mu.Lock()
+       defer l.mu.Unlock()
+       return l.MyStruct.val
+}
+
+// Set sets the value in a Lockable.
+func (l *Lockable[T]) Set(v T) {
+       l.mu.Lock()
+       defer l.mu.Unlock()
+       l.MyStruct = MyStruct[T]{v}
+}
+
+func main() {
+       var li Lockable[int]
+
+       li.Set(5)
+       if got, want := li.Get(), 5; got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+}
diff --git a/test/typeparam/geninline.dir/a.go b/test/typeparam/geninline.dir/a.go
new file mode 100644 (file)
index 0000000..fe5ba22
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2021 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
+
+type IVal[T comparable] interface {
+       check(want T)
+}
+
+type Val[T comparable] struct {
+       val T
+}
+
+//go:noinline
+func (l *Val[T]) check(want T) {
+       if l.val != want {
+               panic("hi")
+       }
+}
+
+func Test1() {
+       var l Val[int]
+       if l.val != 0 {
+               panic("hi")
+       }
+       _ = IVal[int](&l)
+}
+
+func Test2() {
+       var l Val[float64]
+       l.val = 3.0
+       l.check(float64(3))
+       _ = IVal[float64](&l)
+}
+
+type privateVal[T comparable] struct {
+       val T
+}
+
+//go:noinline
+func (l *privateVal[T]) check(want T) {
+       if l.val != want {
+               panic("hi")
+       }
+}
+
+type Outer struct {
+       val privateVal[string]
+}
+
+func Test3() {
+       var o Outer
+       o.val.check("")
+       _ = IVal[string](&o.val)
+}
diff --git a/test/typeparam/geninline.dir/main.go b/test/typeparam/geninline.dir/main.go
new file mode 100644 (file)
index 0000000..6dc36ba
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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 "a"
+
+// Testing inlining of functions that refer to instantiated exported and non-exported
+// generic types.
+
+func main() {
+       a.Test1()
+       a.Test2()
+       a.Test3()
+}
diff --git a/test/typeparam/geninline.go b/test/typeparam/geninline.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/index2.go b/test/typeparam/index2.go
new file mode 100644 (file)
index 0000000..683b76f
--- /dev/null
@@ -0,0 +1,67 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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.
+
+// Testing various generic uses of indexing, both for reads and writes.
+
+package main
+
+import "fmt"
+
+// Can index an argument (read/write) constrained to be a slice or an array.
+func Index1[T interface{ []int64 | [5]int64 }](x T) int64 {
+       x[2] = 5
+       return x[3]
+}
+
+// Can index an argument (read) constrained to be a byte array or a string.
+func Index2[T interface{ []byte | string }](x T) byte {
+       return x[3]
+}
+
+// Can index an argument (write) constrained to be a byte array, but not a string.
+func Index2a[T interface{ []byte }](x T) byte {
+       x[2] = 'b'
+       return x[3]
+}
+
+// Can index an argument (read/write) constrained to be a map. Maps can't
+// be combined with any other type for indexing purposes.
+func Index3[T interface{ map[int]int64 }](x T) int64 {
+       x[2] = 43
+       return x[3]
+}
+
+// But the type of the map keys or values can be parameterized.
+func Index4[T any](x map[int]T) T {
+       var zero T
+       x[2] = zero
+       return x[3]
+}
+
+func test[T comparable](got, want T) {
+       if got != want {
+               panic(fmt.Sprintf("got %v, want %v", got, want))
+       }
+}
+
+func main() {
+       x := make([]int64, 4)
+       x[3] = 2
+       y := [5]int64{1, 2, 3, 4, 5}
+       z := "abcd"
+       w := make([]byte, 4)
+       w[3] = 5
+       v := make(map[int]int64)
+       v[3] = 18
+
+       test(Index1(x), int64(2))
+       test(Index1(y), int64(4))
+       test(Index2(z), byte(100))
+       test(Index2(w), byte(5))
+       test(Index2a(w), byte(5))
+       test(Index3(v), int64(18))
+       test(Index4(v), int64(18))
+}
index 5ebce72628ff6157e09ea9a4cbc75f7e6291643c..98260694dc1ab0ccfb020711e88aba0bbb81c6f2 100644 (file)
@@ -77,8 +77,9 @@ func test1[T any](arg T) {
        // calling method expressions
        m1x := B1[T].m1
        m1x(b1, arg)
-       m2x := B2[T].m2
-       m2x(b2, arg)
+       // TODO(khr): reenable these.
+       //m2x := B2[T].m2
+       //m2x(b2, arg)
 
        // calling method values
        m1v := b1.m1
diff --git a/test/typeparam/issue46461.go b/test/typeparam/issue46461.go
new file mode 100644 (file)
index 0000000..2c54a6b
--- /dev/null
@@ -0,0 +1,13 @@
+// compile -G=3
+
+// Copyright 2021 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[U interface{ M() T[U] }] int
+
+type X int
+
+func (X) M() T[X] { return 0 }
diff --git a/test/typeparam/issue46461b.dir/a.go b/test/typeparam/issue46461b.dir/a.go
new file mode 100644 (file)
index 0000000..0d53b3e
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2021 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
+
+type T[U interface{ M() T[U] }] int
diff --git a/test/typeparam/issue46461b.dir/b.go b/test/typeparam/issue46461b.dir/b.go
new file mode 100644 (file)
index 0000000..3393a37
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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
+
+import "./a"
+
+type X int
+
+func (X) M() a.T[X] { return 0 }
diff --git a/test/typeparam/issue46461b.go b/test/typeparam/issue46461b.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -G=3
+
+// Copyright 2021 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/typeparam/issue46591.go b/test/typeparam/issue46591.go
new file mode 100644 (file)
index 0000000..e7b9fa2
--- /dev/null
@@ -0,0 +1,22 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T[_ any] struct{}
+
+var m = map[interface{}]int{
+       T[struct{ int }]{}: 0,
+       T[struct {
+               int "x"
+       }]{}: 0,
+}
+
+func main() {
+       if len(m) != 2 {
+               panic(len(m))
+       }
+}
diff --git a/test/typeparam/issue47272.go b/test/typeparam/issue47272.go
new file mode 100644 (file)
index 0000000..6771cb9
--- /dev/null
@@ -0,0 +1,55 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "errors"
+       "fmt"
+)
+
+type Option[T any] struct {
+       ok  bool
+       val T
+}
+
+func (o Option[T]) String() string {
+       if o.ok {
+               return fmt.Sprintf("Some(%v)", o.val)
+       }
+       return "None"
+}
+
+func Some[T any](val T) Option[T] { return Option[T]{ok: true, val: val} }
+func None[T any]() Option[T]      { return Option[T]{ok: false} }
+
+type Result[T, E any] struct {
+       ok  bool
+       val T
+       err E
+}
+
+func (r Result[T, E]) String() string {
+       if r.ok {
+               return fmt.Sprintf("Ok(%v)", r.val)
+       }
+       return fmt.Sprintf("Err(%v)", r.err)
+}
+
+func Ok[T, E any](val T) Result[T, E]  { return Result[T, E]{ok: true, val: val} }
+func Err[T, E any](err E) Result[T, E] { return Result[T, E]{ok: false, err: err} }
+
+func main() {
+       a := Some[int](1)
+       b := None[int]()
+       fmt.Println(a, b)
+
+       x := Ok[int, error](1)
+       y := Err[int, error](errors.New("test"))
+       fmt.Println(x, y)
+       // fmt.Println(x)
+       _, _, _, _ = a, b, x, y
+}
diff --git a/test/typeparam/issue47272.out b/test/typeparam/issue47272.out
new file mode 100644 (file)
index 0000000..9c433fa
--- /dev/null
@@ -0,0 +1,2 @@
+Some(1) None
+Ok(1) Err(test)
diff --git a/test/typeparam/issue47514c.dir/a.go b/test/typeparam/issue47514c.dir/a.go
new file mode 100644 (file)
index 0000000..782b1d2
--- /dev/null
@@ -0,0 +1,5 @@
+package a
+
+type Doer[T any] interface {
+       Do() T
+}
diff --git a/test/typeparam/issue47514c.dir/main.go b/test/typeparam/issue47514c.dir/main.go
new file mode 100644 (file)
index 0000000..bc1166f
--- /dev/null
@@ -0,0 +1,10 @@
+package main
+
+import "a"
+
+func Do[T any](doer a.Doer[T]) {
+       doer.Do()
+}
+
+func main() {
+}
diff --git a/test/typeparam/issue47514c.go b/test/typeparam/issue47514c.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue47676.go b/test/typeparam/issue47676.go
new file mode 100644 (file)
index 0000000..1b01624
--- /dev/null
@@ -0,0 +1,23 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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() {
+       d := diff([]int{}, func(int) string {
+               return "foo"
+       })
+       d()
+}
+
+func diff[T any](previous []T, uniqueKey func(T) string) func() {
+       return func() {
+               newJSON := map[string]T{}
+               for _, prev := range previous {
+                       delete(newJSON, uniqueKey(prev))
+               }
+       }
+}
diff --git a/test/typeparam/issue47684.go b/test/typeparam/issue47684.go
new file mode 100644 (file)
index 0000000..2798b78
--- /dev/null
@@ -0,0 +1,19 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 f[G any]() int {
+       return func() int {
+               return func() int {
+                       return 0
+               }()
+       }()
+}
+
+func main() {
+       f[int]()
+}
diff --git a/test/typeparam/issue47684b.go b/test/typeparam/issue47684b.go
new file mode 100644 (file)
index 0000000..c43ef8d
--- /dev/null
@@ -0,0 +1,23 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 f[G any]() interface{} {
+       return func() interface{} {
+               return func() interface{} {
+                       var x G
+                       return x
+               }()
+       }()
+}
+
+func main() {
+       x := f[int]()
+       if v, ok := x.(int); !ok || v != 0 {
+               panic("bad")
+       }
+}
diff --git a/test/typeparam/issue47684c.go b/test/typeparam/issue47684c.go
new file mode 100644 (file)
index 0000000..32f1b66
--- /dev/null
@@ -0,0 +1,19 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 f[G any]() func()func()int {
+       return func() func()int {
+               return func() int {
+                       return 0
+               }
+       }
+}
+
+func main() {
+       f[int]()()()
+}
diff --git a/test/typeparam/issue47708.go b/test/typeparam/issue47708.go
new file mode 100644 (file)
index 0000000..35d57c8
--- /dev/null
@@ -0,0 +1,37 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type FooType[T any] interface {
+       Foo(BarType[T]) string
+}
+type BarType[T any] interface {
+       Bar(FooType[T]) string
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Baz[T any] T
+// func (l Baz[T]) Foo(v BarType[T]) string {
+//     return v.Bar(l)
+// }
+// type Bob[T any] T
+// func (l Bob[T]) Bar(v FooType[T]) string {
+//     if v,ok := v.(Baz[T]);ok{
+//             return fmt.Sprintf("%v%v",v,l)
+//     }
+//     return ""
+// }
+
+func main() {
+       // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+       // var baz Baz[int] = 123
+       // var bob Bob[int] = 456
+       //
+       // if got, want := baz.Foo(bob), "123456"; got != want {
+       //      panic(fmt.Sprintf("got %s want %s", got, want))
+       // }
+}
diff --git a/test/typeparam/issue47710.go b/test/typeparam/issue47710.go
new file mode 100644 (file)
index 0000000..0882cb4
--- /dev/null
@@ -0,0 +1,19 @@
+// compile -G=3
+
+// Copyright 2021 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 FooType[t any] interface {
+       Foo(BarType[t])
+}
+type BarType[t any] interface {
+       Int(IntType[t]) FooType[int]
+}
+
+type IntType[t any] int
+
+func (n IntType[t]) Foo(BarType[t]) {}
+func (n IntType[_]) String()    {}
diff --git a/test/typeparam/issue47713.go b/test/typeparam/issue47713.go
new file mode 100644 (file)
index 0000000..a38eea1
--- /dev/null
@@ -0,0 +1,52 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "encoding"
+       "fmt"
+)
+
+type Seralizable interface {
+       encoding.BinaryMarshaler
+       encoding.BinaryUnmarshaler
+}
+
+type SerDeString string
+
+func (s *SerDeString) UnmarshalBinary(in []byte) error {
+       *s = SerDeString(in)
+       return nil
+}
+
+func (s SerDeString) MarshalBinary() ([]byte, error) {
+       return []byte(s), nil
+}
+
+
+type GenericSerializable[T Seralizable] struct {
+       Key string
+       Value T
+}
+
+func (g GenericSerializable[T]) Send() {
+       out, err := g.Value.MarshalBinary()
+       if err != nil {
+               panic("bad")
+       }
+       var newval SerDeString
+       newval.UnmarshalBinary(out)
+       fmt.Printf("Sent %s\n", newval)
+}
+
+func main() {
+       val := SerDeString("asdf")
+       x := GenericSerializable[*SerDeString]{
+               Value: &val,
+       }
+       x.Send()
+}
diff --git a/test/typeparam/issue47713.out b/test/typeparam/issue47713.out
new file mode 100644 (file)
index 0000000..a6e7719
--- /dev/null
@@ -0,0 +1 @@
+Sent asdf
diff --git a/test/typeparam/issue47716.go b/test/typeparam/issue47716.go
new file mode 100644 (file)
index 0000000..7f34fcb
--- /dev/null
@@ -0,0 +1,68 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "fmt"
+       "unsafe"
+)
+
+// size returns the size of type T
+func size[T any](x T) uintptr {
+       return unsafe.Sizeof(x)
+}
+
+// size returns the alignment of type T
+func align[T any](x T) uintptr {
+       return unsafe.Alignof(x)
+}
+
+type Tstruct[T any] struct {
+       f1 T
+       f2 int
+}
+
+// offset returns the offset of field f2 in the generic type Tstruct
+func (r *Tstruct[T]) offset() uintptr {
+       return unsafe.Offsetof(r.f2)
+}
+
+func main() {
+       v1 := int(5)
+       if got, want := size(v1), unsafe.Sizeof(v1); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+       if got, want := align(v1), unsafe.Alignof(v1); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+
+       v2 := "abc"
+       if got, want := size(v2), unsafe.Sizeof(v2); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+       if got, want := align(v2), unsafe.Alignof(v2); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+
+       var v3 Tstruct[int]
+       if got, want := unsafe.Offsetof(v3.f2), unsafe.Sizeof(v1); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+
+       var v4 Tstruct[interface{}]
+       var v5 interface{}
+       if got, want := unsafe.Offsetof(v4.f2), unsafe.Sizeof(v5); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+
+       if got, want := v3.offset(), unsafe.Offsetof(v3.f2); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+       if got, want := v4.offset(), unsafe.Offsetof(v4.f2); got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+}
diff --git a/test/typeparam/issue47723.go b/test/typeparam/issue47723.go
new file mode 100644 (file)
index 0000000..9ef6040
--- /dev/null
@@ -0,0 +1,23 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 f[_ any]() int {
+       var a [1]int
+       _ = func() int {
+               return func() int {
+                       return 0
+               }()
+       }()
+       return a[func() int {
+               return 0
+       }()]
+}
+
+func main() {
+       f[int]()
+}
diff --git a/test/typeparam/issue47740.go b/test/typeparam/issue47740.go
new file mode 100644 (file)
index 0000000..ea1168f
--- /dev/null
@@ -0,0 +1,40 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 "fmt"
+
+type Exp[Ty any] interface {
+       Eval() Ty
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// type Lit[Ty any] Ty
+//
+// func (lit Lit[Ty]) Eval() Ty       { return Ty(lit) }
+// func (lit Lit[Ty]) String() string { return fmt.Sprintf("(lit %v)", Ty(lit)) }
+
+type Eq[Ty any] struct {
+       a Exp[Ty]
+       b Exp[Ty]
+}
+
+func (e Eq[Ty]) String() string {
+       return fmt.Sprintf("(eq %v %v)", e.a, e.b)
+}
+
+// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+// var (
+//     e0 = Eq[int]{Lit[int](128), Lit[int](64)}
+//     e1 = Eq[bool]{Lit[bool](true), Lit[bool](true)}
+// )
+
+func main() {
+       // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
+       // fmt.Printf("%v\n", e0)
+       // fmt.Printf("%v\n", e1)
+}
diff --git a/test/typeparam/issue47740.out b/test/typeparam/issue47740.out
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/typeparam/issue47740b.go b/test/typeparam/issue47740b.go
new file mode 100644 (file)
index 0000000..2a91d35
--- /dev/null
@@ -0,0 +1,23 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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"
+
+type S[T any] struct {
+       a interface{}
+}
+
+func (e S[T]) M() {
+       v := reflect.ValueOf(e.a)
+       _, _ = v.Interface().(int)
+}
+
+func main() {
+       e := S[int]{0}
+       e.M()
+}
diff --git a/test/typeparam/issue47775.dir/b.go b/test/typeparam/issue47775.dir/b.go
new file mode 100644 (file)
index 0000000..b6d7ba9
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2021 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
+
+type C[T any] struct {
+}
+
+func (c *C[T]) reset() {
+}
+
+func New[T any]() {
+       c := &C[T]{}
+       z(c.reset)
+}
+
+func z(interface{}) {
+}
diff --git a/test/typeparam/issue47775.dir/main.go b/test/typeparam/issue47775.dir/main.go
new file mode 100644 (file)
index 0000000..ed284dd
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "b"
+
+func main() {
+       b.New[int]()
+}
diff --git a/test/typeparam/issue47775.go b/test/typeparam/issue47775.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue47775b.go b/test/typeparam/issue47775b.go
new file mode 100644 (file)
index 0000000..6d3fc8d
--- /dev/null
@@ -0,0 +1,28 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type C[T any] struct {
+}
+
+func (c *C[T]) reset() {
+}
+
+func New[T any]() {
+       c := &C[T]{}
+       i = c.reset
+       z(c.reset)
+}
+
+var i interface{}
+
+func z(interface{}) {
+}
+
+func main() {
+       New[int]()
+}
diff --git a/test/typeparam/issue47797.go b/test/typeparam/issue47797.go
new file mode 100644 (file)
index 0000000..3e80d3c
--- /dev/null
@@ -0,0 +1,22 @@
+// compile -G=3
+
+// Copyright 2021 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 Foo[T any] struct {
+        Val T
+}
+
+func (f Foo[T]) Bat() {}
+
+type Bar struct {
+        Foo[int]
+}
+
+func foo() {
+        var b Bar
+        b.Bat()
+}
diff --git a/test/typeparam/issue47877.go b/test/typeparam/issue47877.go
new file mode 100644 (file)
index 0000000..0a83459
--- /dev/null
@@ -0,0 +1,23 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Map[K comparable, V any] struct {
+        m map[K]V
+}
+
+func NewMap[K comparable, V any]() Map[K, V] {
+        return Map[K, V]{m: map[K]V{}}
+}
+
+func (m Map[K, V]) Get(key K) V {
+        return m.m[key]
+}
+
+func main() {
+        _ = NewMap[int, struct{}]()
+}
diff --git a/test/typeparam/issue47878.go b/test/typeparam/issue47878.go
new file mode 100644 (file)
index 0000000..6ad183d
--- /dev/null
@@ -0,0 +1,56 @@
+// compile -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Src1[T any] func() Src1[T]
+
+func (s *Src1[T]) Next() {
+       *s = (*s)()
+}
+
+type Src2[T any] []func() Src2[T]
+
+func (s Src2[T]) Next() {
+       _ = s[0]()
+}
+
+type Src3[T comparable] map[T]func() Src3[T]
+
+func (s Src3[T]) Next() {
+       var a T
+       _ = s[a]()
+}
+
+type Src4[T any] chan func() T
+
+func (s Src4[T]) Next() {
+       _ = (<-s)()
+}
+
+type Src5[T any] func() Src5[T]
+
+func (s Src5[T]) Next() {
+       var x interface{} = s
+       _ = (x.(Src5[T]))()
+}
+
+func main() {
+       var src1 Src1[int]
+       src1.Next()
+
+       var src2 Src2[int]
+       src2.Next()
+
+       var src3 Src3[string]
+       src3.Next()
+
+       var src4 Src4[int]
+       src4.Next()
+
+       var src5 Src5[int]
+       src5.Next()
+}
diff --git a/test/typeparam/issue47892.dir/a.go b/test/typeparam/issue47892.dir/a.go
new file mode 100644 (file)
index 0000000..b63d604
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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
+
+type Index[T any] interface {
+       G() T
+}
+
+type I1[T any] struct {
+       a T
+}
+
+func (i *I1[T]) G() T {
+       return i.a
+}
diff --git a/test/typeparam/issue47892.dir/main.go b/test/typeparam/issue47892.dir/main.go
new file mode 100644 (file)
index 0000000..bd610d4
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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 "a"
+
+type Model[T any] struct {
+       index       a.Index[T]
+}
+
+func NewModel[T any](index a.Index[T]) Model[T] {
+       return Model[T]{
+               index:       index,
+       }
+}
+
+func main() {
+       _ = NewModel[int]((*a.I1[int])(nil))
+}
diff --git a/test/typeparam/issue47892.go b/test/typeparam/issue47892.go
new file mode 100644 (file)
index 0000000..572f680
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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
\ No newline at end of file
diff --git a/test/typeparam/issue47892b.dir/a.go b/test/typeparam/issue47892b.dir/a.go
new file mode 100644 (file)
index 0000000..5adb492
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2021 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
+
+type T struct{ p *int64 }
+
+type i struct{}
+
+func G() *T { return &T{nil} }
+
+func (j i) F(a, b *T) *T {
+       n := *a.p + *b.p
+       return &T{&n}
+}
+
+func (j i) G() *T {
+       return &T{}
+}
+
+type I[Idx any] interface {
+       G() Idx
+       F(a, b Idx) Idx
+}
+
+func Gen() I[*T] {
+       return i{}
+}
diff --git a/test/typeparam/issue47892b.dir/main.go b/test/typeparam/issue47892b.dir/main.go
new file mode 100644 (file)
index 0000000..70df440
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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 "a"
+
+type S[Idx any] struct {
+       A string
+       B Idx
+}
+
+type O[Idx any] struct {
+       A int
+       B a.I[Idx]
+}
diff --git a/test/typeparam/issue47892b.go b/test/typeparam/issue47892b.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -G=3
+
+// Copyright 2021 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/typeparam/issue47896.go b/test/typeparam/issue47896.go
new file mode 100644 (file)
index 0000000..1b2f265
--- /dev/null
@@ -0,0 +1,74 @@
+//  compile -G=3
+
+// Copyright 2021 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 (
+       "database/sql"
+)
+
+// Collection generic interface which things can be added to.
+type Collection[T any] interface {
+       Add(T)
+}
+
+// Slice generic slice implementation of a Collection
+type Slice[T any] []*T
+
+func (s *Slice[T]) Add(t *T) {
+       *s = append(*s, t)
+}
+
+type Scanner interface {
+       Scan(...interface{}) error
+}
+
+type Mapper[T any] func(s Scanner, t T) error
+
+type Repository[T any] struct {
+       db *sql.DB
+}
+
+func (r *Repository[T]) scan(rows *sql.Rows, m Mapper[*T], c Collection[*T]) error {
+       for rows.Next() {
+               t := new(T)
+               if err := m(rows, t); err != nil {
+                       return err
+               }
+               c.Add(t)
+       }
+       return rows.Err()
+}
+
+func (r *Repository[T]) query(query string, m Mapper[*T], c Collection[*T]) error {
+       rows, err := r.db.Query(query)
+       if err != nil {
+               return err
+       }
+       if err := r.scan(rows, m, c); err != nil {
+               rows.Close()
+               return err
+       }
+       return rows.Close()
+}
+
+type Actor struct {
+       ActorID   uint16
+       FirstName string
+       LastName  string
+}
+
+type ActorRepository struct {
+       r Repository[Actor]
+}
+
+func (ActorRepository) scan(s Scanner, a *Actor) error {
+       return s.Scan(&a.ActorID, &a.FirstName, &a.LastName)
+}
+
+func (r *ActorRepository) SelectAll(c Collection[*Actor]) error {
+       return r.r.query("SELECT `actor_id`, `first_name`, `last_name` FROM `actor` LIMIT 10", r.scan, c)
+}
diff --git a/test/typeparam/issue47901.go b/test/typeparam/issue47901.go
new file mode 100644 (file)
index 0000000..cd07973
--- /dev/null
@@ -0,0 +1,21 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Chan[T any] chan Chan[T]
+
+func (ch Chan[T]) recv() Chan[T] {
+       return <-ch
+}
+
+func main() {
+       ch := Chan[int](make(chan Chan[int]))
+       go func() {
+               ch <- make(Chan[int])
+       }()
+       ch.recv()
+}
diff --git a/test/typeparam/issue47924.go b/test/typeparam/issue47924.go
new file mode 100644 (file)
index 0000000..1d1bab3
--- /dev/null
@@ -0,0 +1,15 @@
+// compile -G=3
+
+// Copyright 2021 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 Cache[K any] struct{}
+
+func (c Cache[K]) foo(x interface{}, f func(K) bool) {
+       f(x.(K))
+}
+
+var _ Cache[int]
diff --git a/test/typeparam/issue47925.go b/test/typeparam/issue47925.go
new file mode 100644 (file)
index 0000000..1b07193
--- /dev/null
@@ -0,0 +1,20 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type myifacer[T any] interface{ do(T) error }
+
+type stuff[T any] struct{}
+
+func (s stuff[T]) run() interface{} {
+       var i myifacer[T]
+       return i
+}
+
+func main() {
+       stuff[int]{}.run()
+}
diff --git a/test/typeparam/issue47925b.go b/test/typeparam/issue47925b.go
new file mode 100644 (file)
index 0000000..f4a99ec
--- /dev/null
@@ -0,0 +1,33 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I[T any] interface {
+       foo()
+}
+
+type E[T any] interface {
+}
+
+//go:noinline
+func f[T I[T]](x T) E[T] {
+       // contains a cast from nonempty to empty interface
+       return E[T](I[T](x))
+}
+
+type S struct {
+       x int
+}
+
+func (s *S) foo() {}
+
+func main() {
+       i := f(&S{x: 7})
+       if i.(*S).x != 7 {
+               panic("bad")
+       }
+}
diff --git a/test/typeparam/issue47925c.go b/test/typeparam/issue47925c.go
new file mode 100644 (file)
index 0000000..0ba23e6
--- /dev/null
@@ -0,0 +1,36 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I[T any] interface {
+       foo()
+}
+
+type J[T any] interface {
+       foo()
+       bar()
+}
+
+//go:noinline
+func f[T J[T]](x T) I[T] {
+       // contains a cast between two nonempty interfaces
+       return I[T](J[T](x))
+}
+
+type S struct {
+       x int
+}
+
+func (s *S) foo() {}
+func (s *S) bar() {}
+
+func main() {
+       i := f(&S{x: 7})
+       if i.(*S).x != 7 {
+               panic("bad")
+       }
+}
diff --git a/test/typeparam/issue47925d.go b/test/typeparam/issue47925d.go
new file mode 100644 (file)
index 0000000..231961b
--- /dev/null
@@ -0,0 +1,47 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I[T any] interface {
+       foo()
+}
+
+type J[T any] interface {
+       foo()
+       bar()
+}
+
+//go:noinline
+func f[T J[T]](x T, g func(T) T) I[T] {
+       // contains a cast between two nonempty interfaces
+       // Also make sure we don't evaluate g(x) twice.
+       return I[T](J[T](g(x)))
+}
+
+type S struct {
+       x int
+}
+
+func (s *S) foo() {}
+func (s *S) bar() {}
+
+var cnt int
+
+func inc(s *S) *S {
+       cnt++
+       return s
+}
+
+func main() {
+       i := f(&S{x: 7}, inc)
+       if i.(*S).x != 7 {
+               panic("bad")
+       }
+       if cnt != 1 {
+               panic("multiple calls")
+       }
+}
diff --git a/test/typeparam/issue47929.go b/test/typeparam/issue47929.go
new file mode 100644 (file)
index 0000000..a5636f2
--- /dev/null
@@ -0,0 +1,29 @@
+// compile -G=3 -p=p
+
+// Copyright 2021 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 v4
+
+var sink interface{}
+
+//go:noinline
+func Do(result, body interface{}) {
+       sink = &result
+}
+
+func DataAction(result DataActionResponse, body DataActionRequest) {
+       Do(&result, body)
+}
+
+type DataActionRequest struct {
+       Action *interface{}
+}
+
+type DataActionResponse struct {
+       ValidationErrors *ValidationError
+}
+
+type ValidationError struct {
+}
diff --git a/test/typeparam/issue47948.go b/test/typeparam/issue47948.go
new file mode 100644 (file)
index 0000000..8e5df81
--- /dev/null
@@ -0,0 +1,18 @@
+// compile -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type fun func()
+
+func F[T any]() {
+       _ = fun(func() {
+
+       })
+}
+func main() {
+       F[int]()
+}
diff --git a/test/typeparam/issue47966.go b/test/typeparam/issue47966.go
new file mode 100644 (file)
index 0000000..f431f7f
--- /dev/null
@@ -0,0 +1,9 @@
+// compile -G=3
+
+// Copyright 2021 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 C comparable
diff --git a/test/typeparam/issue48013.go b/test/typeparam/issue48013.go
new file mode 100644 (file)
index 0000000..179d9f4
--- /dev/null
@@ -0,0 +1,39 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "fmt"
+       "unsafe"
+)
+
+type S[T any] struct {
+       val T
+}
+
+// Test type substitution where base type is unsafe.Pointer
+type U[T any] unsafe.Pointer
+
+func test[T any]() T {
+       var q U[T]
+       var v struct {
+               // Test derived type that contains an unsafe.Pointer
+               p   unsafe.Pointer
+               val T
+       }
+       _ = q
+       return v.val
+}
+
+func main() {
+       want := 0
+       got := test[int]()
+       if got != want {
+               panic(fmt.Sprintf("got %f, want %f", got, want))
+       }
+
+}
diff --git a/test/typeparam/issue48016.go b/test/typeparam/issue48016.go
new file mode 100644 (file)
index 0000000..582751e
--- /dev/null
@@ -0,0 +1,35 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "fmt"
+       "strconv"
+)
+
+func test1[T any](fn func(T) int, v T) int {
+       fn1 := func() int {
+               var i interface{} = v
+               val := fn(i.(T))
+               return val
+       }
+       return fn1()
+}
+
+func main() {
+       want := 123
+       got := test1(func(s string) int {
+               r, err := strconv.Atoi(s)
+               if err != nil {
+                       return 0
+               }
+               return r
+       }, "123")
+       if got != want {
+               panic(fmt.Sprintf("got %f, want %f", got, want))
+       }
+}
diff --git a/test/typeparam/issue48030.go b/test/typeparam/issue48030.go
new file mode 100644 (file)
index 0000000..9fc4428
--- /dev/null
@@ -0,0 +1,26 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Src[T any] func() Src[T]
+
+func Seq[T any]() Src[T] {
+       return nil
+}
+
+func Seq2[T1 any, T2 any](v1 T1, v2 T2) Src[T2] {
+       return nil
+}
+
+func main() {
+       // Type args fully supplied
+       Seq[int]()
+       // Partial inference of type args
+       Seq2[int](5, "abc")
+       // Full inference of type args
+       Seq2(5, "abc")
+}
diff --git a/test/typeparam/issue48042.go b/test/typeparam/issue48042.go
new file mode 100644 (file)
index 0000000..db5de3d
--- /dev/null
@@ -0,0 +1,77 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "fmt"
+       "reflect"
+)
+
+type G[T any] interface {
+       g() func()(*T)
+}
+type Foo[T any] struct {
+
+}
+// OCALL
+func (l *Foo[T]) f1() (*T) {
+       return g[T]()()
+}
+// OCALLFUNC
+func (l *Foo[T]) f2() (*T) {
+       var f = g[T]
+       return f()()
+}
+// OCALLMETH
+func (l *Foo[T]) f3() (*T) {
+       return l.g()()
+}
+// OCALLINTER
+func (l *Foo[T]) f4() (*T) {
+       var g G[T] = l
+       return g.g()()
+}
+// ODYNAMICDOTTYPE
+func (l *Foo[T]) f5() (*T) {
+       var x interface{}
+       x = g[T]
+       return x.(func()func()(*T))()()
+}
+func (l *Foo[T]) g() func() (*T) {
+       return func() (*T) {
+               t := new(T)
+               reflect.ValueOf(t).Elem().SetInt(100)
+               return t
+       }
+}
+func g[T any]() func() (*T) {
+       return func() (*T) {
+               t := new(T)
+               reflect.ValueOf(t).Elem().SetInt(100)
+               return t
+       }
+}
+
+func main() {
+       foo := Foo[int]{}
+       // Make sure the function conversion is correct
+       if n := *(foo.f1()) ; n != 100{
+               panic(fmt.Sprintf("%v",n))
+       }
+       if n := *(foo.f2()) ; n != 100{
+               panic(fmt.Sprintf("%v",n))
+       }
+       if n := *(foo.f3()) ; n != 100{
+               panic(fmt.Sprintf("%v",n))
+       }
+       if n := *(foo.f4()) ; n != 100{
+               panic(fmt.Sprintf("%v",n))
+       }
+       if n := *(foo.f5()) ; n != 100{
+               panic(fmt.Sprintf("%v",n))
+       }
+}
\ No newline at end of file
diff --git a/test/typeparam/issue48047.go b/test/typeparam/issue48047.go
new file mode 100644 (file)
index 0000000..1bff65a
--- /dev/null
@@ -0,0 +1,30 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A[T any] struct {
+       field B[T]
+}
+
+type B[T any] interface {
+       Work(T)
+}
+
+func (a *A[T]) Work(t T) {
+       a.field.Work(t)
+}
+
+type BImpl struct{}
+
+func (b BImpl) Work(s string) {}
+
+func main() {
+       a := &A[string]{
+               field: BImpl{},
+       }
+       a.Work("")
+}
diff --git a/test/typeparam/issue48049.go b/test/typeparam/issue48049.go
new file mode 100644 (file)
index 0000000..3a00514
--- /dev/null
@@ -0,0 +1,33 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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() {
+       Gooer2[byte]()
+}
+
+type Fooer[T any] interface {
+       Foo(p T)
+}
+
+type fooer1[T any] struct{}
+
+func (fooer1[T]) Foo(T) {}
+
+type fooer2[T any] struct {
+       r []Fooer[T]
+}
+
+//go:noinline
+func (mr fooer2[T]) Foo(p T) {
+       mr.r[0] = fooer1[T]{}
+       return
+}
+
+func Gooer2[T any]() Fooer[T] {
+       return fooer2[T]{}
+}
diff --git a/test/typeparam/issue48056.go b/test/typeparam/issue48056.go
new file mode 100644 (file)
index 0000000..8d1c3ef
--- /dev/null
@@ -0,0 +1,27 @@
+// compile -G=3
+
+// Copyright 2021 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 B[T any] interface {
+       Work()
+}
+type BImpl[T any] struct{}
+
+func (b *BImpl[T]) Work() {
+}
+
+type A[T any] struct {
+       B[T]
+}
+
+func f[T any]() {
+       s := &A[T]{
+               &BImpl[T]{},
+       }
+       // golang.org/issue/48056
+       s.Work()
+}
diff --git a/test/typeparam/issue48094.dir/a.go b/test/typeparam/issue48094.dir/a.go
new file mode 100644 (file)
index 0000000..dd8c16f
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2021 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 "unsafe"
+
+func F[T any]() uintptr {
+       var t T
+       return unsafe.Sizeof(t)
+}
+
+func G[T any]() uintptr {
+       var t T
+       return unsafe.Alignof(t)
+}
+
+//func H[T any]() uintptr {
+//     type S struct {
+//             a T
+//             b T
+//     }
+//     var s S
+//     return unsafe.Offsetof(s.b)
+//}
diff --git a/test/typeparam/issue48094.dir/main.go b/test/typeparam/issue48094.dir/main.go
new file mode 100644 (file)
index 0000000..eb1ddbe
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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 "a"
+
+func main() {
+       if a.F[int64]() != 8 {
+               panic("bad")
+       }
+       if a.G[int8]() != 1 {
+               panic("bad")
+       }
+       // TODO: enable once 47631 is fixed.
+       //if a.H[int64]() != 8 {
+       //      panic("bad")
+       //}
+}
diff --git a/test/typeparam/issue48094.go b/test/typeparam/issue48094.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48094b.dir/a.go b/test/typeparam/issue48094b.dir/a.go
new file mode 100644 (file)
index 0000000..a113a22
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2021 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
+
+func F() { G(0) }
+func G[T any](t T) {}
diff --git a/test/typeparam/issue48094b.dir/b.go b/test/typeparam/issue48094b.dir/b.go
new file mode 100644 (file)
index 0000000..242b34a
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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
+
+import "./a"
+
+func H() { a.F() }
diff --git a/test/typeparam/issue48094b.go b/test/typeparam/issue48094b.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -G=3
+
+// Copyright 2021 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/typeparam/issue48137.go b/test/typeparam/issue48137.go
new file mode 100644 (file)
index 0000000..3dd7810
--- /dev/null
@@ -0,0 +1,25 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Constraint[T any] interface {
+       ~func() T
+}
+
+func Foo[T Constraint[T]]() T {
+       var t T
+
+       t = func() T {
+               return t
+       }
+       return t
+}
+
+func main() {
+       type Bar func() Bar
+       Foo[Bar]()
+}
diff --git a/test/typeparam/issue48185a.dir/p.go b/test/typeparam/issue48185a.dir/p.go
new file mode 100644 (file)
index 0000000..176c7f4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2021 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 MarshalOptions struct {
+       Marshalers *Marshalers
+}
+
+type Encoder struct {}
+
+type Marshalers = marshalers[MarshalOptions, Encoder]
+
+type marshalers[Options, Coder any] struct{}
+
+func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers {
+       return &Marshalers{}
+}
diff --git a/test/typeparam/issue48185a.dir/p_test.go b/test/typeparam/issue48185a.dir/p_test.go
new file mode 100644 (file)
index 0000000..52c87a7
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "p"
+
+func main() {
+       _ = p.MarshalFuncV1[int](func(int) ([]byte, error) { return nil, nil })
+}
diff --git a/test/typeparam/issue48185a.go b/test/typeparam/issue48185a.go
new file mode 100644 (file)
index 0000000..40df49f
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2021 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/typeparam/issue48185b.dir/a.go b/test/typeparam/issue48185b.dir/a.go
new file mode 100644 (file)
index 0000000..9aed60c
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2021 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 (
+       "reflect"
+       "sync"
+)
+
+type addressableValue struct{ reflect.Value }
+
+type arshalers[Options, Coder any] struct {
+       fncVals  []typedArshaler[Options, Coder]
+       fncCache sync.Map // map[reflect.Type]unmarshaler
+}
+type typedArshaler[Options, Coder any] struct {
+       typ reflect.Type
+       fnc func(Options, *Coder, addressableValue) error
+}
+
+type UnmarshalOptions1 struct {
+       // Unmarshalers is a list of type-specific unmarshalers to use.
+       Unmarshalers *arshalers[UnmarshalOptions1, Decoder1]
+}
+
+type Decoder1 struct {
+}
+
+func (a *arshalers[Options, Coder]) lookup(fnc func(Options, *Coder, addressableValue) error, t reflect.Type) func(Options, *Coder, addressableValue) error {
+       return fnc
+}
+
+func UnmarshalFuncV2[T any](fn func(UnmarshalOptions1, *Decoder1, T) error) *arshalers[UnmarshalOptions1, Decoder1] {
+       return &arshalers[UnmarshalOptions1, Decoder1]{}
+}
diff --git a/test/typeparam/issue48185b.dir/main.go b/test/typeparam/issue48185b.dir/main.go
new file mode 100644 (file)
index 0000000..978e6ae
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2021 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 (
+       "a"
+       "fmt"
+)
+
+func main() {
+       _ = a.UnmarshalOptions1{
+               Unmarshalers: a.UnmarshalFuncV2(func(opts a.UnmarshalOptions1, dec *a.Decoder1, val *interface{}) (err error) {
+                       return fmt.Errorf("error")
+               }),
+       }
+}
diff --git a/test/typeparam/issue48185b.go b/test/typeparam/issue48185b.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48191.go b/test/typeparam/issue48191.go
new file mode 100644 (file)
index 0000000..967004d
--- /dev/null
@@ -0,0 +1,269 @@
+// compile -c=2 -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I1 interface {
+       int8 | int16 | int32 | int64 | int | uint
+}
+type I2 interface{ float32 | float64 }
+type I3 interface{ string }
+
+func F[G1 I1, G2 I2, G3 I3]() {
+       var m0 map[G2]rune
+       var ch0, ch1 chan bool
+       var ast0, ast1 []struct{ s0 G3 }
+       var ai64_2 []int64
+       var m1, m2, m3 map[bool]map[int]struct {
+               m0 map[G2]byte
+               s1 G3
+       }
+       var i8_0, i8_1 G1
+       var i16_0 int16
+       var am3, am4 []map[float64]map[G2]*func(*byte, map[uint]int64, G3, struct{}) G2
+       var pi64_0, pi64_1 *int64
+       var i, i1, i2 int
+       var as5, as6, as7 []G3
+       var ch2, ch3, ch4 chan uint
+       var m4, m5, m6 map[G1]chan bool
+
+       if func(G2, int32) byte {
+               return m1[false][30].m0[G2(28.6)] * m3[func(bool, uint) bool {
+                       return false
+               }(false, uint(94))][31].m0[G2(185.0)] * m1[(true || true) && (false && false)][51-i2].m0[G2(278.6)]
+       }(G2(672.5), int32(35)) < m3[<-m5[func(int64, int64) G1 {
+               return i8_1
+       }(*pi64_0, int64(50))]][15&i1^i2^i2].m0[G2(895.3)] || (func(int64, uint) uint {
+               return uint(94)
+       }(int64(30), uint(95))&^<-ch2^<-ch4)&<-ch2^<-ch4 == <-ch2 {
+               var f0 float64
+               var pf2 *float64
+               var ch5, ch6 chan int16
+               var fnc0 func(*int64, G2, struct {
+                       i8_0  G1
+                       m1    map[float64]bool
+                       i64_2 int64
+               }, map[byte]func(G2, float64, *uint, float64) struct{}) complex128 = func(p0 *int64, p1 G2, p2 struct {
+                       i8_0  G1
+                       m1    map[float64]bool
+                       i64_2 int64
+               }, p3 map[byte]func(G2, float64, *uint, float64) struct{}) complex128 {
+                       p0 = pi64_1
+                       m5 = map[G1]chan bool{(p2.i8_0 + i8_1 + i8_1 ^ i8_1) * p2.i8_0 / p2.i8_0: m4[p2.i8_0>><-ch2]}
+                       return (2.65i - 31.18i) * func(byte, byte) complex128 {
+                               return 13.12i - 32.90i + (44.15i - 70.53i - (87.16i*92.67i + (24.18i - 9.13i))) + (func(G1, int16) complex128 {
+                                       return 55.80i
+                               }(G1(30), int16(80)) + 8.48i*79.18i + (37.30i*73.81i + (21.01i - 76.30i)) + func(G3, G2) complex128 {
+                                       return 35.58i
+                               }(G3("2JYizeFiEMvXLkUR"), p1)*(81.59i-21.76i))
+                       }(m1[<-m5[G1(37)*i8_1<<i8_1%p2.i8_0]][i2].m0[p1], m1[<-ch0][55&i2/i2^i].m0[func(G3, float64) G2 {
+                               return G2(619.2)
+                       }(G3(""), 954.0)])
+               }
+               var m7 map[G2]int64
+               var ch7 chan byte
+               var fnc1 func(bool, func(chan G2, struct {
+                       h0 G2
+               }, int64) **rune, int) map[complex128]int32 = func(p0 bool, p1 func(chan G2, struct {
+                       h0 G2
+               }, int64) **rune, p2 int) map[complex128]int32 {
+                       pf2 = pf2
+                       as7 = as7
+                       return map[complex128]int32{(94.02i - 22.19i) * (fnc0(pi64_0, G2(554.1)*G2(i1), struct {
+                               i8_0  G1
+                               m1    map[float64]bool
+                               i64_2 int64
+                       }{G1(68)*i8_0 ^ i8_0, map[float64]bool{f0: <-m6[G1(33)]}, (int64(40) ^ ai64_2[77]) % *pi64_1}, map[byte]func(G2, float64, *uint, float64) struct {
+                       }{func(float64, float64) byte {
+                               return byte(32)
+                       }(878.2, 984.4) + m3[true][12].m0[G2(594.0)]: nil}) - (fnc0(pi64_0, G2(241.1)+G2(i2), struct {
+                               i8_0  G1
+                               m1    map[float64]bool
+                               i64_2 int64
+                       }{i8_0, map[float64]bool{904.1: false}, int64(83) + m7[G2(357.7)]}, map[byte]func(G2, float64, *uint, float64) struct {
+                       }{byte(85) | m1[true][99].m0[G2(372.7)]: nil}) - (fnc0(pi64_0, G2(239.9), struct {
+                               i8_0  G1
+                               m1    map[float64]bool
+                               i64_2 int64
+                       }{G1(68), map[float64]bool{555.6: false}, int64(0)}, map[byte]func(G2, float64, *uint, float64) struct {
+                       }{byte(18) & <-ch7: nil}) + (88.17i - 0.55i)))): int32(73) % int32(i)}
+               }
+               as5[54] = as6[(len(func(bool, G2) G3 {
+                       return G3("")
+               }(false, G2(190.8)))|i1^i1)%i1-i1] + m2[68 != i || 'M'&'\xf4'|'H'&'\u1311' >= '4'&'\uab3e'>>uint(83) && (<-m6[G1(24)%i8_0] && <-ch1)][i].s1
+               i = len([]G3{ast1[2].s0})
+               i16_0 = <-ch6 / i16_0 & <-ch6
+               i = (i1^i|i2|i2)/i + i
+               m6 = m4
+               am3 = am3
+               m1[G2(869.6) == G2(i2)] = m2[func(float64, rune) byte {
+                       return func(G3, byte) byte {
+                               return byte(42)
+                       }(G3("8iDnlygG194xl"), byte(89))
+               }(*pf2, '\u9cf4')/m1[func(G3, float64) bool {
+                       return false
+               }(G3("6MbwBSHYzr9t0zD"), 774.4)][76].m0[G2(508.0)]/m2[<-m4[i8_0]][92&^i2].m0[G2(807.0)] > m3[(int32(39)|int32(i2))&^int32(i2) < int32(i2)][89*i1&i2].m0[G2(327.5)]]
+               m2[<-m4[func(G1, complex128) G1 {
+                       return i8_1
+               }(i8_0, 35.01i)] && <-m4[func(int, G1) G1 {
+                       return G1(0)
+               }(10, G1(70))*i8_1&i8_1>><-ch2] || fnc0(pi64_0, G2(689.5), struct {
+                       i8_0  G1
+                       m1    map[float64]bool
+                       i64_2 int64
+               }{(G1(78)*i8_1 - i8_1) / i8_1, map[float64]bool{499.2: <-m6[G1(88)^i8_0]}, int64(83) &^ ai64_2[33] & *pi64_1 * ai64_2[i1]}, map[byte]func(G2, float64, *uint, float64) struct {
+               }{m1[len(G3("bNIJZq")+G3("Fri5pn1MsZzYtsaV7b")) >= i][i^i1].m0[G2(691.7)]: nil}) != 71.77i-34.84i] = map[int]struct {
+                       m0 map[G2]byte
+                       s1 G3
+               }{((18+i2)&^i2%i2 ^ i) / i: m3[(G2(267.1)*G2(i1) > G2(i2) || (false || true || (true || false))) && func(int32, int64) bool {
+                       return <-ch0
+               }(int32(63), ai64_2[61&^i1&i2])][i|i^i1]}
+               i2 = 90 - i1
+               _, _, _, _, _, _, _, _ = f0, pf2, ch5, ch6, fnc0, m7, ch7, fnc1
+       } else {
+               var m7 map[G1]chan uint
+               var ch5, ch6, ch7 chan G3
+               var i32_0, i32_1 int32
+               var m8, m9, m10 map[bool]struct {
+               }
+               pi64_1 = pi64_0
+               m6[func(G3, G2) G1 {
+                       return (G1(35) | i8_0) << i8_1 / i8_1 &^ i8_1 / i8_1
+               }(G3("YBiKg"), G2(122.6))] = make(chan bool)
+               ast0 = ast0
+               i8_1 = (((G1(10)+i8_1)&i8_0+i8_0)&i8_0&i8_1 ^ i8_1) & i8_1
+               am4 = am3
+               i32_1 = int32(10) &^ i32_0
+               m8[func(float64, G3) bool {
+                       return func(rune, int16) bool {
+                               return (G2(267.0)*G2(i2) == G2(i) || func(G2, G3) bool {
+                                       return <-ch0
+                               }(G2(53.3), <-ch5)) && func(G2, G1) int32 {
+                                       return int32(63)
+                               }(G2(804.8), G1(2))-i32_0 < i32_1
+                       }('\xbd', i16_0)
+               }(370.9, ast0[len([]complex128{})+i-i2].s0) && (G2(245.0)-G2(i1) == G2(i1) || byte(17)&m2[false][26].m0[G2(628.5)] > m3[false][55].m0[G2(608.8)] || func(G1, G1) bool {
+                       return true
+               }(G1(24), G1(2)) || (<-m5[G1(38)] || <-ch1) && func(int32, int) bool {
+                       return false && true
+               }(int32(6), i1) && '\x26'&'\x27'|func(G2, G3) rune {
+                       return '\x13'
+               }(G2(229.6), G3("ys1msVeg61uSImCDkRG3C")) <= 'V'>>uint(88)-('\xbe'+'\uafd4')) == (53.04i == 37.22i)] = m8[func(byte, int64) bool {
+                       return <-ch1
+               }(m3[false && false][96].m0[G2(147.6)], *pi64_0) && 643.5 > float64(i1) && (<-ch0 && <-ch1)]
+               i8_1 = func(byte, uint) G1 {
+                       return G1(68)
+               }(m2[<-ch1 || <-m5[G1(96)+i8_0] || func(bool, int32) bool {
+                       return func(int, byte) bool {
+                               return m1[true][89].s1 <= G3("2ZMnHGOMQnyHSbJ")
+                       }(i2, m2[<-m6[G1(47)]][94].m0[G2(981.3)])
+               }(<-m4[G1(0)&^i8_0&i8_0], i32_0)][i2%i&^i].m0[func(complex128, rune) G2 {
+                       return G2(93.1) * G2(i2)
+               }(4.63i, m0[G2(975.8)])], uint(21))
+               _, _, _, _, _, _, _, _, _ = m7, ch5, ch6, ch7, i32_0, i32_1, m8, m9, m10
+       }
+
+       if *pi64_0>><-ch3 <= *pi64_0 || func(bool, int32) int32 {
+               return (int32(69)&^int32(i2) + int32(i2)) * int32(i2)
+       }(true, int32(49))^int32(i2) >= int32(i) {
+               var ai8_8, ai8_9 []G1
+               var pi2, pi3, pi4 *int
+               var pi8_5, pi8_6 *G1
+               var i64_0, i64_1 int64
+               m1[754.8*float64(i2) != float64(i) && 6.26i == 69.99i] = map[int]struct {
+                       m0 map[G2]byte
+                       s1 G3
+               }{len([]G2{G2(935.9) / G2(i2), func(int64, G2) G2 {
+                       return G2(720.5)
+               }(int64(36), G2(349.7))})&*pi2 + i2 - i1: m1[(uint(29) >= <-ch4 || int64(45)+ai64_2[18] >= *pi64_1) == (func(G2, G2) bool {
+                       return <-m5[G1(25)]
+               }(G2(447.2), G2(946.6)) || func(int, int16) bool {
+                       return true
+               }(40, int16(41)) && byte(51) >= m2[true][13].m0[G2(6.6)])][*pi3]}
+               am4 = []map[float64]map[G2]*func(*byte, map[uint]int64, G3, struct {
+               }) G2{am4[i2%*pi3]}
+               pi2 = &i2
+               pi64_0 = pi64_1
+               ai8_8[*pi3] = *pi8_5&ai8_9[(*pi4+*pi3)%*pi3] ^ ai8_8[90+i2|*pi4]
+               ai64_2 = []int64{}
+               m4 = m4
+               pi2 = &i1
+               pi3 = &i2
+               _, _, _, _, _, _, _, _, _ = ai8_8, ai8_9, pi2, pi3, pi4, pi8_5, pi8_6, i64_0, i64_1
+       }
+
+       if (true || false || int32(68) > int32(i1) || <-m5[G1(11)-i8_0] && true) && func(int, float64) bool {
+               return <-m5[(G1(83)-i8_1)&^i8_1]
+       }(i1, 886.6) || func(byte, int) bool {
+               return 401.0/float64(i1)/float64(i1)-float64(i) == float64(i2)
+       }(m1[(G1(85)^i8_1)&^i8_1 <= i8_1][72].m0[G2(617.4)], i1) || (<-m6[(G1(3)|i8_0)>><-ch2%i8_0|i8_0] || <-ch0) {
+               var ch5 chan map[byte]complex128
+               var fnc0 func(int32, *map[rune]complex128) complex128
+               var c0 complex128
+               var st0, st1, st2 struct {
+               }
+               var au8 []uint
+               var st3, st4, st5 struct {
+                       ph0 *G2
+                       st1 struct {
+                               m0   map[rune]complex128
+                               pch1 *chan int64
+                               m2   map[bool]byte
+                               st3  struct {
+                                       ch0 chan func(map[G1]*struct {
+                                               pm0 *map[bool]int64
+                                               h1  G2
+                                       }, struct {
+                                               u0 uint
+                                       }, uint, float64) *struct {
+                                               ch0 chan map[int16]G2
+                                       }
+                                       i1  int
+                                       ch2 chan complex128
+                               }
+                       }
+                       pm2 *map[int64]struct {
+                               s0  G3
+                               pi1 *int
+                               st2 struct {
+                                       m0 map[int]map[rune]int64
+                                       r1 rune
+                               }
+                       }
+               }
+               var am9, am10, am11 []map[uint]int64
+               m1[G3("E")+(*st4.pm2)[*pi64_0+<-*st3.st1.pch1].s0 < (*st4.pm2)[int64(46)].s0+(G3("4Jsp3pv0x")+G3("MTKt98c")+(G3("E6Nxqpl70")+G3("eXhhxb")))+(G3("siISQNeBXoQIHwGB")+G3("CzocwLRWIUD")+(G3("cDWy3E3qpeJOmw1wP9wZ")+G3("S3ZRONdtB7K1LBC"))+func(G1, uint) G3 {
+                       return m2[false][74].s1
+               }(G1(9), uint(26)))+func(G2, int) G3 {
+                       return G3("WzncXvaqK4zPn")
+               }(G2(291.6), i)+(ast1[(40^i1+i1)&^st4.st1.st3.i1].s0+func(byte, int64) G3 {
+                       return m2[207.7 == float64(i2) && (false || false)][i2].s1
+               }(byte(34), am11[25][func(int32, float64) uint {
+                       return uint(77)
+               }(int32(29), 403.1)]))] = map[int]struct {
+                       m0 map[G2]byte
+                       s1 G3
+               }{st3.st1.st3.i1: m2[<-m4[i8_1]][st5.st1.st3.i1-st3.st1.st3.i1-i2]}
+               st1 = struct {
+               }{}
+               pi64_0 = pi64_1
+               m4 = m6
+               as7 = as7
+               m6[(i8_0+i8_0)&^i8_1&^i8_1] = m5[G1(96)^i8_1]
+               st2 = struct {
+               }{}
+               st1 = struct {
+               }{}
+               am10 = []map[uint]int64{am9[len((*st4.pm2)[int64(65)].s0)+i], am11[st4.st1.st3.i1%st4.st1.st3.i1^i1]}
+               i2 = st5.st1.st3.i1*i - st5.st1.st3.i1
+               _, _, _, _, _, _, _, _, _, _, _, _, _ = ch5, fnc0, c0, st0, st1, st2, au8, st3, st4, st5, am9, am10, am11
+       }
+
+}
+
+func main() {
+       F[int16, float32, string]()
+}
diff --git a/test/typeparam/issue48198.go b/test/typeparam/issue48198.go
new file mode 100644 (file)
index 0000000..1d7e44e
--- /dev/null
@@ -0,0 +1,22 @@
+// compile -G=3
+
+// Copyright 2021 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 Foo[T any] struct {
+}
+
+func (foo Foo[T]) Get()  {
+}
+
+var(
+       _ = Foo[byte]{}
+       _ = Foo[[]byte]{}
+       _ = Foo[map[byte]rune]{}
+
+       _ = Foo[rune]{}
+       _ = Foo[[]rune]{}
+       _ = Foo[map[rune]byte]{}
+)
diff --git a/test/typeparam/issue48225.go b/test/typeparam/issue48225.go
new file mode 100644 (file)
index 0000000..887ffd8
--- /dev/null
@@ -0,0 +1,37 @@
+// run -gcflags="-G=3"
+
+// Copyright 2021 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"
+
+type Foo[T any] struct {
+       val int
+}
+
+func (foo Foo[T]) Get() *T {
+       if foo.val != 1 {
+               panic("bad val field in Foo receiver")
+       }
+       return new(T)
+}
+
+var (
+       newInt    = Foo[int]{val: 1}.Get
+       newString = Foo[string]{val: 1}.Get
+)
+
+func main() {
+       i := newInt()
+       s := newString()
+
+       if t := reflect.TypeOf(i).String(); t != "*int" {
+               panic(t)
+       }
+       if t := reflect.TypeOf(s).String(); t != "*string" {
+               panic(t)
+       }
+}
diff --git a/test/typeparam/issue48253.go b/test/typeparam/issue48253.go
new file mode 100644 (file)
index 0000000..7bd0234
--- /dev/null
@@ -0,0 +1,34 @@
+// run -gcflags="-G=3"
+
+// Copyright 2021 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"
+)
+
+type A[T any] struct {
+       B[int]
+}
+
+type B[T any] struct {
+}
+
+func (b B[T]) Bat() {
+       t := new(T)
+       if tt := reflect.TypeOf(t); tt.Kind() != reflect.Pointer || tt.Elem().Kind() != reflect.Int {
+               panic("unexpected type, want: *int, got: "+tt.String())
+       }
+}
+
+type Foo struct {
+       A[string]
+}
+func main() {
+       Foo{}.A.Bat()
+       Foo{}.A.B.Bat()
+       Foo{}.Bat()
+}
diff --git a/test/typeparam/issue48276a.go b/test/typeparam/issue48276a.go
new file mode 100644 (file)
index 0000000..060ac3e
--- /dev/null
@@ -0,0 +1,19 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 "fmt"
+
+func main() {
+       IsZero[interface{}]("")
+}
+
+func IsZero[T comparable](val T) bool {
+       var zero T
+       fmt.Printf("%v:%v\n", zero, val)
+       return val != zero
+}
diff --git a/test/typeparam/issue48276a.out b/test/typeparam/issue48276a.out
new file mode 100644 (file)
index 0000000..7e8a8a9
--- /dev/null
@@ -0,0 +1 @@
+<nil>:
diff --git a/test/typeparam/issue48276b.go b/test/typeparam/issue48276b.go
new file mode 100644 (file)
index 0000000..67c3e3d
--- /dev/null
@@ -0,0 +1,15 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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() {
+       f[interface{}](nil)
+}
+
+func f[T any](x T) {
+       var _ interface{} = x
+}
diff --git a/test/typeparam/issue48280.dir/a.go b/test/typeparam/issue48280.dir/a.go
new file mode 100644 (file)
index 0000000..17859e6
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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
+
+type I[T I[T]] interface {
+       F() T
+}
+
+type S struct{}
diff --git a/test/typeparam/issue48280.dir/main.go b/test/typeparam/issue48280.dir/main.go
new file mode 100644 (file)
index 0000000..b9981c6
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "a"
+
+func main() {
+       _ = a.S{}
+}
diff --git a/test/typeparam/issue48280.go b/test/typeparam/issue48280.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48306.dir/a.go b/test/typeparam/issue48306.dir/a.go
new file mode 100644 (file)
index 0000000..739750b
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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
+
+type I[T I[T]] interface {
+       F() T
+}
diff --git a/test/typeparam/issue48306.dir/main.go b/test/typeparam/issue48306.dir/main.go
new file mode 100644 (file)
index 0000000..5d602fe
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 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 "a"
+
+type S struct{}
+
+func (*S) F() *S { return nil }
+
+func main() {
+       var _ a.I[*S] = &S{}
+}
diff --git a/test/typeparam/issue48306.go b/test/typeparam/issue48306.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48317.go b/test/typeparam/issue48317.go
new file mode 100644 (file)
index 0000000..c8f088d
--- /dev/null
@@ -0,0 +1,38 @@
+// run -gcflags="-G=3"
+
+// Copyright 2021 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 (
+       "encoding/json"
+)
+
+type A[T any] struct {
+       F1 string `json:"t1"`
+       F2 T      `json:"t2"`
+       B  B      `json:"t3"`
+}
+
+type B struct {
+       F4 int `json:"t4"`
+}
+
+func a[T any]() {
+       data := `{"t1":"1","t2":2,"t3":{"t4":4}}`
+       a1 := A[T]{}
+       if err := json.Unmarshal([]byte(data), &a1); err != nil {
+               panic(err)
+       }
+       if bytes, err := json.Marshal(&a1); err != nil {
+               panic(err)
+       } else if string(bytes) != data {
+               panic(string(bytes))
+       }
+}
+
+func main() {
+       a[int]()
+}
diff --git a/test/typeparam/issue48318.go b/test/typeparam/issue48318.go
new file mode 100644 (file)
index 0000000..ae53a28
--- /dev/null
@@ -0,0 +1,33 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "encoding/xml"
+       "fmt"
+)
+
+type A[T, U any] struct {
+       Name T `xml:"name"`
+       Data U `xml:"data"`
+}
+
+func main() {
+       src := &A[string, int]{Name: "name", Data: 1}
+       data, err := xml.Marshal(src)
+       if err != nil {
+               panic(err)
+       }
+       dst := &A[string, int]{}
+       err = xml.Unmarshal(data, dst)
+       if err != nil {
+               panic(err)
+       }
+       if *src != *dst {
+               panic(fmt.Sprintf("wanted %#v got %#v", src, dst))
+       }
+}
diff --git a/test/typeparam/issue48337a.dir/a.go b/test/typeparam/issue48337a.dir/a.go
new file mode 100644 (file)
index 0000000..6f1b128
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2021 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 (
+       "fmt"
+       "sync"
+)
+
+type WrapperWithLock[T any] interface {
+       PrintWithLock()
+}
+
+func NewWrapperWithLock[T any](value T) WrapperWithLock[T] {
+       return &wrapperWithLock[T]{
+               Object: value,
+       }
+}
+
+type wrapperWithLock[T any] struct {
+       Lock   sync.Mutex
+       Object T
+}
+
+func (w *wrapperWithLock[T]) PrintWithLock() {
+       w.Lock.Lock()
+       defer w.Lock.Unlock()
+
+       fmt.Println(w.Object)
+}
diff --git a/test/typeparam/issue48337a.dir/main.go b/test/typeparam/issue48337a.dir/main.go
new file mode 100644 (file)
index 0000000..16f7115
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2021 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 "a"
+
+func main() {
+       obj := a.NewWrapperWithLock("this file does import sync")
+       obj.PrintWithLock()
+}
diff --git a/test/typeparam/issue48337a.go b/test/typeparam/issue48337a.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48337a.out b/test/typeparam/issue48337a.out
new file mode 100644 (file)
index 0000000..fa8d3ee
--- /dev/null
@@ -0,0 +1 @@
+this file does import sync
diff --git a/test/typeparam/issue48337b.dir/a.go b/test/typeparam/issue48337b.dir/a.go
new file mode 100644 (file)
index 0000000..a3c2e88
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2021 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
+
+type Container[T any] struct {
+       X T
+}
+
+func NewContainer[T any](x T) *Container[T] {
+       return &Container[T]{x}
+}
+
+type MetaContainer struct {
+       C *Container[Value]
+}
+
+type Value struct{}
+
+func NewMetaContainer() *MetaContainer {
+       c := NewContainer(Value{})
+       // c := &Container[Value]{Value{}} // <-- this works
+       return &MetaContainer{c}
+}
diff --git a/test/typeparam/issue48337b.dir/main.go b/test/typeparam/issue48337b.dir/main.go
new file mode 100644 (file)
index 0000000..0b2814c
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "a"
+
+func main() {
+       a.NewMetaContainer()
+}
diff --git a/test/typeparam/issue48337b.go b/test/typeparam/issue48337b.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48344.go b/test/typeparam/issue48344.go
new file mode 100644 (file)
index 0000000..7ea539c
--- /dev/null
@@ -0,0 +1,26 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type G[T any] interface {
+       g()
+}
+
+type Foo[T any] struct {
+}
+
+func (foo *Foo[T]) g() {
+
+}
+
+func f[T any]() {
+       v := []G[T]{}
+       v = append(v, &Foo[T]{})
+}
+func main() {
+       f[int]()
+}
diff --git a/test/typeparam/issue48424.go b/test/typeparam/issue48424.go
new file mode 100644 (file)
index 0000000..3253e64
--- /dev/null
@@ -0,0 +1,54 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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.
+
+// Smoke test for constraint literals with elided interface
+// per issue #48424.
+
+package main
+
+func identity[T int](x T) T {
+       return x
+}
+
+func min[T int|string](x, y T) T {
+       if x < y {
+               return x
+       }
+       return y
+}
+
+func max[T ~float64](x, y T) T {
+       if x > y {
+               return x
+       }
+       return y
+}
+
+func main() {
+       if identity(1) != 1 {
+               panic("identity(1) failed")
+       }
+
+       if min(2, 3) != 2 {
+               panic("min(2, 3) failed")
+       }
+
+       if min("foo", "bar") != "bar" {
+               panic(`min("foo", "bar") failed`)
+       }
+
+       if max(2, 3) != 3 {
+               panic("max(2, 3) failed")
+       }
+}
+
+// Some random type parameter lists with elided interfaces.
+
+type (
+       _ [T struct{}] struct{}
+       _ [M map[K]V, K comparable, V any] struct{}
+       _ [_ interface{}|int] struct{}
+)
diff --git a/test/typeparam/issue48453.go b/test/typeparam/issue48453.go
new file mode 100644 (file)
index 0000000..0f751d3
--- /dev/null
@@ -0,0 +1,21 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:noinline
+func CopyMap[M interface{ ~map[K]V }, K comparable, V any](m M) M {
+       out := make(M, len(m))
+       for k, v := range m {
+               out[k] = v
+       }
+       return out
+}
+
+func main() {
+       var m map[*string]int
+       CopyMap(m)
+}
diff --git a/test/typeparam/issue48454.dir/a.go b/test/typeparam/issue48454.dir/a.go
new file mode 100644 (file)
index 0000000..9613916
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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 "sync"
+
+type Val[T any] struct {
+       mu  sync.RWMutex
+       val T
+}
+
+func (v *Val[T]) Has() {
+       v.mu.RLock()
+}
diff --git a/test/typeparam/issue48454.dir/b.go b/test/typeparam/issue48454.dir/b.go
new file mode 100644 (file)
index 0000000..2b59b71
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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
+
+import "a"
+
+type Session struct {
+       privateField a.Val[string]
+}
diff --git a/test/typeparam/issue48454.dir/main.go b/test/typeparam/issue48454.dir/main.go
new file mode 100644 (file)
index 0000000..becb5f3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "b"
+
+func main() {
+       var _ b.Session
+}
diff --git a/test/typeparam/issue48454.go b/test/typeparam/issue48454.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48462.dir/a.go b/test/typeparam/issue48462.dir/a.go
new file mode 100644 (file)
index 0000000..26c704d
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2021 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
+
+func Unique[T comparable](set []T) []T {
+       nset := make([]T, 0, 8)
+
+loop:
+       for _, s := range set {
+               for _, e := range nset {
+                       if s == e {
+                               continue loop
+                       }
+               }
+
+               nset = append(nset, s)
+       }
+
+       return nset
+}
diff --git a/test/typeparam/issue48462.dir/main.go b/test/typeparam/issue48462.dir/main.go
new file mode 100644 (file)
index 0000000..8054ddd
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 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 (
+       "fmt"
+       "reflect"
+
+       "a"
+)
+
+func main() {
+       e := []int{1, 2, 2, 3, 1, 6}
+
+       got := a.Unique(e)
+       want := []int{1, 2, 3, 6}
+       if !reflect.DeepEqual(got, want) {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+
+}
diff --git a/test/typeparam/issue48462.go b/test/typeparam/issue48462.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48537.go b/test/typeparam/issue48537.go
new file mode 100644 (file)
index 0000000..a2dc5cf
--- /dev/null
@@ -0,0 +1,21 @@
+// compile -G=3
+
+// Copyright 2021 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() {
+}
+
+type C interface {
+       map[int]string
+}
+
+func f[A C]() A {
+       return A{
+               1: "a",
+               2: "b",
+       }
+}
diff --git a/test/typeparam/issue48538.go b/test/typeparam/issue48538.go
new file mode 100644 (file)
index 0000000..fed9b5e
--- /dev/null
@@ -0,0 +1,60 @@
+// compile -G=3
+
+// Copyright 2021 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.
+
+// Testing composite literal for a type param constrained to be a struct or a map.
+
+package p
+
+type C interface {
+       ~struct{ b1, b2 string }
+}
+
+func f[T C]() T {
+       return T{
+               b1: "a",
+               b2: "b",
+       }
+}
+
+func f2[T ~struct{ b1, b2 string }]() T {
+       return T{
+               b1: "a",
+               b2: "b",
+       }
+}
+
+type D interface {
+       map[string]string | S
+}
+
+type S map[string]string
+
+func g[T D]() T {
+       b1 := "foo"
+       b2 := "bar"
+       return T{
+               b1: "a",
+               b2: "b",
+       }
+}
+
+func g2[T map[string]string]() T {
+       b1 := "foo"
+       b2 := "bar"
+       return T{
+               b1: "a",
+               b2: "b",
+       }
+}
+
+func g3[T S]() T {
+       b1 := "foo"
+       b2 := "bar"
+       return T{
+               b1: "a",
+               b2: "b",
+       }
+}
diff --git a/test/typeparam/issue48598.go b/test/typeparam/issue48598.go
new file mode 100644 (file)
index 0000000..ea360f2
--- /dev/null
@@ -0,0 +1,28 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Iterator[T any] interface {
+       Iterate()
+}
+
+type IteratorFunc[T any] func(fn func(T) bool)
+
+func (f IteratorFunc[T]) Iterate() {
+}
+
+func FromIterator[T any](it Iterator[T]) {
+       it.Iterate()
+}
+
+func Foo[T, R any]() {
+       FromIterator[R](IteratorFunc[R](nil))
+}
+
+func main() {
+       Foo[int, int]()
+}
diff --git a/test/typeparam/issue48602.go b/test/typeparam/issue48602.go
new file mode 100644 (file)
index 0000000..53ce20e
--- /dev/null
@@ -0,0 +1,25 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Iterator[T any] interface {
+       Iterate(fn T)
+}
+
+type IteratorFunc[T any] func(fn T)
+
+func (f IteratorFunc[T]) Iterate(fn T) {
+       f(fn)
+}
+
+func Foo[R any]() {
+       var _ Iterator[R] = IteratorFunc[R](nil)
+}
+
+func main() {
+       Foo[int]()
+}
diff --git a/test/typeparam/issue48604.go b/test/typeparam/issue48604.go
new file mode 100644 (file)
index 0000000..1babd3f
--- /dev/null
@@ -0,0 +1,25 @@
+// build -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo[T any] interface {
+       CreateBar() Bar[T]
+}
+
+type Bar[T any] func() Bar[T]
+
+func (f Bar[T]) CreateBar() Bar[T] {
+       return f
+}
+
+func abc[R any]() {
+       var _ Foo[R] = Bar[R](nil)()
+}
+
+func main() {
+       abc[int]()
+}
\ No newline at end of file
diff --git a/test/typeparam/issue48609.go b/test/typeparam/issue48609.go
new file mode 100644 (file)
index 0000000..6cf6908
--- /dev/null
@@ -0,0 +1,16 @@
+// compile -G=3
+
+// Copyright 2021 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[T ~chan E, E any](e E) T {
+       ch := make(T)
+       go func() {
+               defer close(ch)
+               ch <- e
+       }()
+       return ch
+}
diff --git a/test/typeparam/issue48617.go b/test/typeparam/issue48617.go
new file mode 100644 (file)
index 0000000..4b00570
--- /dev/null
@@ -0,0 +1,29 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Foo[T any] interface {
+       CreateBar() Bar[T]
+}
+
+type Bar[T any] func() Bar[T]
+
+func (f Bar[T]) CreateBar() Bar[T] {
+       return f
+}
+
+func abc[T any]() {
+       var b Bar[T] = func() Bar[T] {
+               var b Bar[T]
+               return b
+       }
+       var _ Foo[T] = b()
+}
+
+func main() {
+       abc[int]()
+}
diff --git a/test/typeparam/issue48645a.go b/test/typeparam/issue48645a.go
new file mode 100644 (file)
index 0000000..8d5aac9
--- /dev/null
@@ -0,0 +1,31 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 (
+       "fmt"
+       "reflect"
+)
+
+type Stream[T any] struct {
+}
+
+func (s Stream[T]) DropWhile() Stream[T] {
+       return Pipe[T, T](s)
+}
+
+func Pipe[T, R any](s Stream[T]) Stream[R] {
+       it := func(fn func(R) bool) {
+       }
+       fmt.Println(reflect.TypeOf(it).String())
+       return Stream[R]{}
+}
+
+func main() {
+       s := Stream[int]{}
+       s = s.DropWhile()
+}
diff --git a/test/typeparam/issue48645a.out b/test/typeparam/issue48645a.out
new file mode 100644 (file)
index 0000000..5093d0f
--- /dev/null
@@ -0,0 +1 @@
+func(func(int) bool)
diff --git a/test/typeparam/issue48645b.go b/test/typeparam/issue48645b.go
new file mode 100644 (file)
index 0000000..0f3a7f2
--- /dev/null
@@ -0,0 +1,81 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type Iterator[T any] interface {
+       Iterate(fn func(T) bool)
+}
+
+type IteratorFunc[T any] func(fn func(T) bool)
+
+func (f IteratorFunc[T]) Iterate(fn func(T) bool) {
+       f(fn)
+}
+
+type Stream[T any] struct {
+       it Iterator[T]
+}
+
+func (s Stream[T]) Iterate(fn func(T) bool) {
+       if s.it == nil {
+               return
+       }
+       s.it.Iterate(fn)
+}
+
+func FromIterator[T any](it Iterator[T]) Stream[T] {
+       return Stream[T]{it: it}
+}
+
+func (s Stream[T]) DropWhile(fn func(T) bool) Stream[T] {
+       return Pipe[T, T](s, func(t T) (T, bool) {
+               return t, true
+       })
+}
+
+func Pipe[T, R any](s Stream[T], op func(d T) (R, bool)) Stream[R] {
+       it := func(fn func(R) bool) {
+               // XXX Not getting the closure right when converting to interface.
+               // s.it.Iterate(func(t T) bool {
+               //      r, ok := op(t)
+               //      if !ok {
+               //              return true
+               //      }
+
+               //      return fn(r)
+               // })
+       }
+
+       return FromIterator[R](IteratorFunc[R](it))
+}
+
+func Reduce[T, U any](s Stream[T], identity U, acc func(U, T) U) (r U) {
+       r = identity
+       s.Iterate(func(t T) bool {
+               r = acc(r, t)
+               return true
+       })
+
+       return r
+}
+
+type myIterator struct {
+}
+
+func (myIterator) Iterate(fn func(int) bool) {
+}
+
+func main() {
+       s := Stream[int]{}
+       s.it = myIterator{}
+       s = s.DropWhile(func(i int) bool {
+               return false
+       })
+       Reduce(s, nil, func(acc []int, e int) []int {
+               return append(acc, e)
+       })
+}
diff --git a/test/typeparam/issue48716.dir/a.go b/test/typeparam/issue48716.dir/a.go
new file mode 100644 (file)
index 0000000..63e599d
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2021 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
+
+type Pair[L, R any] struct {
+       L L
+       R R
+}
+
+func Two[L, R any](l L, r R) Pair[L, R] {
+       return Pair[L, R]{L: l, R: r}
+}
+
+type Map[K, V any] interface {
+       Put(K, V)
+       Len() int
+       Iterate(func(Pair[K, V]) bool)
+}
+
+type HashMap[K comparable, V any] struct {
+       m map[K]V
+}
+
+func NewHashMap[K comparable, V any](capacity int) HashMap[K, V] {
+       var m map[K]V
+       if capacity >= 1 {
+               m = make(map[K]V, capacity)
+       } else {
+               m = map[K]V{}
+       }
+
+       return HashMap[K, V]{m: m}
+}
+
+func (m HashMap[K, V]) Put(k K, v V) {
+       m.m[k] = v
+}
+
+func (m HashMap[K, V]) Len() int {
+       return len(m.m)
+}
+
+func (m HashMap[K, V]) Iterate(cb func(Pair[K, V]) bool) {
+       for k, v := range m.m {
+               if !cb(Two(k, v)) {
+                       return
+               }
+       }
+}
diff --git a/test/typeparam/issue48716.dir/main.go b/test/typeparam/issue48716.dir/main.go
new file mode 100644 (file)
index 0000000..adde0f5
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2021 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 (
+       "a"
+)
+
+// Creates copy of set
+func Copy[T comparable](src MapSet[T]) (dst MapSet[T]) {
+       dst = HashSet[T](src.Len())
+       Fill(src, dst)
+       return
+}
+
+// Fill src from dst
+func Fill[T any](src, dst MapSet[T]) {
+       src.Iterate(func(t T) bool {
+               dst.Add(t)
+               return true
+       })
+       return
+}
+
+type MapSet[T any] struct {
+       m a.Map[T, struct{}]
+}
+
+func HashSet[T comparable](capacity int) MapSet[T] {
+       return FromMap[T](a.NewHashMap[T, struct{}](capacity))
+}
+
+func FromMap[T any](m a.Map[T, struct{}]) MapSet[T] {
+       return MapSet[T]{
+               m: m,
+       }
+}
+
+func (s MapSet[T]) Add(t T) {
+       s.m.Put(t, struct{}{})
+}
+
+func (s MapSet[T]) Len() int {
+       return s.m.Len()
+}
+
+func (s MapSet[T]) Iterate(cb func(T) bool) {
+       s.m.Iterate(func(p a.Pair[T, struct{}]) bool {
+               return cb(p.L)
+       })
+}
+
+func main() {
+       x := FromMap[int](a.NewHashMap[int, struct{}](1))
+       Copy[int](x)
+}
diff --git a/test/typeparam/issue48716.go b/test/typeparam/issue48716.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue48838.go b/test/typeparam/issue48838.go
new file mode 100644 (file)
index 0000000..ef2150d
--- /dev/null
@@ -0,0 +1,31 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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() {
+       check[string]()
+}
+
+func check[T any]() {
+       var result setter[T]
+       switch result.(type) {
+       case fooA[T]:
+       case fooB[T]:
+       }
+}
+
+type setter[T any] interface {
+       Set(T)
+}
+
+type fooA[T any] struct{}
+
+func (fooA[T]) Set(T) {}
+
+type fooB[T any] struct{}
+
+func (fooB[T]) Set(T) {}
diff --git a/test/typeparam/issue48962.go b/test/typeparam/issue48962.go
new file mode 100644 (file)
index 0000000..de9a23c
--- /dev/null
@@ -0,0 +1,15 @@
+// errorcheck -G=3
+
+// Copyright 2021 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 T0[P any] struct { // ERROR "invalid recursive type"
+       f P
+}
+
+type T1 struct {
+       _ T0[T1]
+}
diff --git a/test/typeparam/issue49027.dir/a.go b/test/typeparam/issue49027.dir/a.go
new file mode 100644 (file)
index 0000000..da88297
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2021 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
+
+func Conv(v interface{}) string {
+       return conv[string](v)
+}
+
+func conv[T any](v interface{}) T {
+       return v.(T)
+}
+
+func Conv2(v interface{}) (string, bool) {
+       return conv2[string](v)
+}
+
+func conv2[T any](v interface{}) (T, bool) {
+       x, ok := v.(T)
+       return x, ok
+}
+
+func Conv3(v interface{}) string {
+       return conv3[string](v)
+}
+
+func conv3[T any](v interface{}) T {
+       switch v := v.(type) {
+       case T:
+               return v
+       default:
+               var z T
+               return z
+       }
+}
+
+type Mystring string
+
+func (Mystring) Foo() {
+}
+
+func Conv4(v interface{Foo()}) Mystring {
+       return conv4[Mystring](v)
+}
+
+func conv4[T interface{Foo()}](v interface{Foo()}) T {
+       switch v := v.(type) {
+       case T:
+               return v
+       default:
+               var z T
+               return z
+       }
+}
diff --git a/test/typeparam/issue49027.dir/main.go b/test/typeparam/issue49027.dir/main.go
new file mode 100644 (file)
index 0000000..aa20a2f
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2021 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 (
+       "a"
+       "fmt"
+)
+
+func main() {
+       s := "foo"
+       x := a.Conv(s)
+       if x != s {
+               panic(fmt.Sprintf("got %s wanted %s", x, s))
+       }
+       y, ok := a.Conv2(s)
+       if !ok {
+               panic("conversion failed")
+       }
+       if y != s {
+               panic(fmt.Sprintf("got %s wanted %s", y, s))
+       }
+       z := a.Conv3(s)
+       if z != s {
+               panic(fmt.Sprintf("got %s wanted %s", z, s))
+       }
+       w := a.Conv4(a.Mystring(s))
+       if w != a.Mystring(s) {
+               panic(fmt.Sprintf("got %s wanted %s", w, s))
+       }
+}
diff --git a/test/typeparam/issue49027.go b/test/typeparam/issue49027.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue49049.go b/test/typeparam/issue49049.go
new file mode 100644 (file)
index 0000000..f4fdd05
--- /dev/null
@@ -0,0 +1,27 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type A[T any] interface {
+       m()
+}
+
+type Z struct {
+       a,b int
+}
+
+func (z *Z) m() {
+}
+
+func test[T any]() {
+       var a A[T] = &Z{}
+       f := a.m
+       f()
+}
+func main() {
+       test[string]()
+}
diff --git a/test/typeparam/issue49241.dir/a.go b/test/typeparam/issue49241.dir/a.go
new file mode 100644 (file)
index 0000000..34c9965
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2021 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
+
+type T[P any] struct {
+       x P
+}
+
+type U struct {
+       a,b int
+}
diff --git a/test/typeparam/issue49241.dir/b.go b/test/typeparam/issue49241.dir/b.go
new file mode 100644 (file)
index 0000000..45c1afb
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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
+
+import "a"
+
+//go:noinline
+func F() interface {} {
+       return a.T[int]{}
+}
+
+//go:noinline
+func G() interface{} {
+       return struct{X,Y a.U}{}
+}
diff --git a/test/typeparam/issue49241.dir/c.go b/test/typeparam/issue49241.dir/c.go
new file mode 100644 (file)
index 0000000..ea3bab2
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2021 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 c
+
+import "a"
+
+//go:noinline
+func F() interface {} {
+       return a.T[int]{}
+}
+
+//go:noinline
+func G() interface{} {
+       return struct{X,Y a.U}{}
+}
diff --git a/test/typeparam/issue49241.dir/main.go b/test/typeparam/issue49241.dir/main.go
new file mode 100644 (file)
index 0000000..7c8a8b1
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2021 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 (
+       "b"
+       "c"
+)
+
+func main() {
+       if b.G() != c.G() {
+               println(b.G(), c.G())
+               panic("bad")
+       }
+       if b.F() != c.F() {
+               println(b.F(), c.F())
+               panic("bad")
+       }
+}
diff --git a/test/typeparam/issue49241.go b/test/typeparam/issue49241.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/issue49246.dir/a.go b/test/typeparam/issue49246.dir/a.go
new file mode 100644 (file)
index 0000000..97459ee
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2021 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
+
+type R[T any] struct{ v T }
+
+func (r R[T]) Self() R[T] { return R[T]{} }
+
+type Fn[T any] func() R[T]
+
+func X() (r R[int]) { return r.Self() }
+
+func Y[T any](a Fn[T]) Fn[int] {
+       return func() (r R[int]) {
+               // No crash: return R[int]{}
+               return r.Self()
+       }
+}
diff --git a/test/typeparam/issue49246.dir/b.go b/test/typeparam/issue49246.dir/b.go
new file mode 100644 (file)
index 0000000..5141b72
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2021 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
+
+import "./a"
+
+func Crash() { a.Y(a.X)() }
diff --git a/test/typeparam/issue49246.go b/test/typeparam/issue49246.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -G=3
+
+// Copyright 2021 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/typeparam/issue49295.go b/test/typeparam/issue49295.go
new file mode 100644 (file)
index 0000000..435b44d
--- /dev/null
@@ -0,0 +1,30 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 "io"
+
+type Reader struct {
+       buf []byte
+}
+type Token *[16]byte
+
+func Read[T interface{ ~*[16]byte }](r *Reader) (t T, err error) {
+       if n := len(t); len(r.buf) >= n {
+               t = T(r.buf[:n])
+               r.buf = r.buf[n:]
+               return
+       }
+       err = io.EOF
+       return
+}
+
+func main() {
+       r := &Reader{buf: []byte("0123456789abcdef")}
+       token, err := Read[Token](r)
+       _, _ = token, err
+}
diff --git a/test/typeparam/issue49309.go b/test/typeparam/issue49309.go
new file mode 100644 (file)
index 0000000..36da86a
--- /dev/null
@@ -0,0 +1,25 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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 genfunc[T any](f func(c T)) {
+       var r T
+
+       f(r)
+}
+
+func myfunc(c string) {
+       test2(c)
+}
+
+//go:noinline
+func test2(a interface{}) {
+}
+
+func main() {
+       genfunc(myfunc)
+}
diff --git a/test/typeparam/recoverimp.dir/a.go b/test/typeparam/recoverimp.dir/a.go
new file mode 100644 (file)
index 0000000..a465fd1
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2021 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 "fmt"
+
+func F[T any](a T) {
+       defer func() {
+               if x := recover(); x != nil {
+                       fmt.Printf("panic: %v\n", x)
+               }
+       }()
+       panic(a)
+}
diff --git a/test/typeparam/recoverimp.dir/main.go b/test/typeparam/recoverimp.dir/main.go
new file mode 100644 (file)
index 0000000..c9d8e3c
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2021 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 "a"
+
+func main() {
+       a.F(5.3)
+       a.F("hello")
+}
diff --git a/test/typeparam/recoverimp.go b/test/typeparam/recoverimp.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 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/typeparam/recoverimp.out b/test/typeparam/recoverimp.out
new file mode 100644 (file)
index 0000000..3c8b38c
--- /dev/null
@@ -0,0 +1,2 @@
+panic: 5.3
+panic: hello
index 99455e93fa1c908a7543829d63c6510f2a89e59a..412023b20a0abb792d604c5b786a950683014280 100644 (file)
@@ -15,7 +15,7 @@ import (
 
 type Setter[B any] interface {
        Set(string)
-       type *B
+       ~*B
 }
 
 // Takes two type parameters where PT = *T
index da12e9f9fc9ededbb4a4f477cf8a979de9096e21..dbcfae893185e3b9f2e07f1060c523c0c48b3155 100644 (file)
@@ -45,7 +45,7 @@ func Equal[Elem comparable](s1, s2 []Elem) bool {
        return true
 }
 
-// EqualFn reports whether two slices are equal using a comparision
+// EqualFn reports whether two slices are equal using a comparison
 // function on each element.
 func EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
        if len(s1) != len(s2) {
index b5e8e0c60637ed80736bfdfc65ce09c8d4c3b116..4bdf10748e50c33c5b82b4a04fbc8db95fed12db 100644 (file)
@@ -60,7 +60,7 @@ func _Equal[Elem comparable](s1, s2 []Elem) bool {
        return true
 }
 
-// _EqualFn reports whether two slices are equal using a comparision
+// _EqualFn reports whether two slices are equal using a comparison
 // function on each element.
 func _EqualFn[Elem any](s1, s2 []Elem, eq func(Elem, Elem) bool) bool {
        if len(s1) != len(s2) {
index 5243dc5c3c15f7d806f2c9f80942d81ce05e8671..f32b40062d6bc8ca75ae25ef5dbe64054ff5ea35 100644 (file)
@@ -1,4 +1,4 @@
-// compile -G
+// compile -G=1
 
 // Copyright 2020 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
index b4e84baf8a7fb3e4a6b57b6fce273bad22ef8eb4..c519b4f51c3d701d17df5eca36060cdbe2737b64 100644 (file)
@@ -14,7 +14,9 @@ import (
        "fmt"
 )
 
-type value[T comparable] struct {
+type C comparable
+
+type value[T C] struct {
        val T
 }
 
index 698877a6f00d65d13bc0c76edb2a6d3928644c00..ef024ce40f08b6516bee45da6f57b605cfc6be70 100644 (file)
@@ -8,11 +8,12 @@
 
 package tparam1
 
-// The predeclared identifier "any" is only visible as a constraint
-// in a type parameter list.
-var _ any     // ERROR "cannot use any outside constraint position"
-func _(_ any) // ERROR "cannot use any outside constraint position"
-type _[_ any /* ok here */] struct{}
+// The predeclared identifier "any" may be used in place of interface{}.
+var _ any
+
+func _(_ any)
+
+type _[_ any] struct{}
 
 const N = 10
 
@@ -24,16 +25,16 @@ type (
        _[T1, T2 any, T3 any] struct{}
 )
 
-func _[T any]() {}
-func _[T, T any]() {} // ERROR "T redeclared"
+func _[T any]()             {}
+func _[T, T any]()          {} // ERROR "T redeclared"
 func _[T1, T2 any](x T1) T2 { panic(0) }
 
 // Type parameters are visible from opening [ to end of function.
 type C interface{}
 
-func _[T interface{}]() {}
-func _[T C]() {}
-func _[T struct{}]() {}// ERROR "not an interface"
+func _[T interface{}]()        {}
+func _[T C]()                  {}
+func _[T struct{}]()           {} // ok if #48424 is accepted
 func _[T interface{ m() T }]() {}
 func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() {
        var _ T1
index 5ba14261ab0823efee35dc1e626906316daabfe2..8d6a228de555d6ae2dcfe773056130095c5f459a 100644 (file)
@@ -6,23 +6,26 @@
 
 // This file tests type lists & structural constraints.
 
+// Note: This test has been adjusted to use the new
+//       type set notation rather than type lists.
+
 package p
 
 // Assignability of an unnamed pointer type to a type parameter that
 // has a matching underlying type.
-func _[T interface{}, PT interface{ type *T }](x T) PT {
+func _[T interface{}, PT interface{ ~*T }](x T) PT {
        return &x
 }
 
 // Indexing of generic types containing type parameters in their type list:
-func at[T interface{ type []E }, E any](x T, i int) E {
+func at[T interface{ ~[]E }, E any](x T, i int) E {
        return x[i]
 }
 
 // A generic type inside a function acts like a named type. Its underlying
 // type is itself, its "operational type" is defined by the type list in
 // the tybe bound, if any.
-func _[T interface{ type int }](x T) {
+func _[T interface{ ~int }](x T) {
        type myint int
        var _ int = int(x)
        var _ T = 42
@@ -30,36 +33,36 @@ func _[T interface{ type int }](x T) {
 }
 
 // Indexing a generic type which has a structural contraints to be an array.
-func _[T interface{ type [10]int }](x T) {
+func _[T interface{ ~[10]int }](x T) {
        _ = x[9] // ok
 }
 
 // Dereference of a generic type which has a structural contraint to be a pointer.
-func _[T interface{ type *int }](p T) int {
+func _[T interface{ ~*int }](p T) int {
        return *p
 }
 
 // Channel send and receive on a generic type which has a structural constraint to
 // be a channel.
-func _[T interface{ type chan int }](ch T) int {
+func _[T interface{ ~chan int }](ch T) int {
        // This would deadlock if executed (but ok for a compile test)
        ch <- 0
        return <-ch
 }
 
 // Calling of a generic type which has a structural constraint to be a function.
-func _[T interface{ type func() }](f T) {
+func _[T interface{ ~func() }](f T) {
        f()
        go f()
 }
 
 // Same, but function has a parameter and return value.
-func _[T interface{ type func(string) int }](f T) int {
+func _[T interface{ ~func(string) int }](f T) int {
        return f("hello")
 }
 
 // Map access of a generic type which has a structural constraint to be a map.
-func _[V any, T interface{ type map[string]V }](p T) V {
+func _[V any, T interface{ ~map[string]V }](p T) V {
        return p["test"]
 }
 
@@ -85,7 +88,7 @@ func f1x() {
 }
 */
 
-func f2[A any, B interface{ type []A }](_ A, _ B) {}
+func f2[A any, B interface{ ~[]A }](_ A, _ B) {}
 func f2x() {
        f := f2[byte]
        f(byte(0), []byte{})
@@ -105,7 +108,7 @@ func f3x() {
 }
 */
 
-func f4[A any, B interface{ type []C }, C interface{ type *A }](_ A, _ B, c C) {}
+func f4[A any, B interface{ ~[]C }, C interface{ ~*A }](_ A, _ B, c C) {}
 func f4x() {
        f := f4[int]
        var x int
@@ -114,18 +117,18 @@ func f4x() {
 }
 
 func f5[A interface {
-       type struct {
+       ~struct {
                b B
                c C
        }
-}, B any, C interface{ type *B }](x B) A { panic(0) }
+}, B any, C interface{ ~*B }](x B) A { panic(0) }
 func f5x() {
        x := f5(1.2)
        var _ float64 = x.b
        var _ float64 = *x.c
 }
 
-func f6[A any, B interface{ type struct{ f []A } }](B) A { panic(0) }
+func f6[A any, B interface{ ~struct{ f []A } }](B) A { panic(0) }
 func f6x() {
        x := f6(struct{ f []string }{})
        var _ string = x
index 913c56321cc7a6f790483d608b55b37e14593727..0e434e1383adce5b5d3141edd1f33d6aabe6e4d4 100644 (file)
@@ -16,7 +16,7 @@ func f[T any](i interface{}) {
                println("int", x)
        case int32, int16:
                println("int32/int16", reflect.ValueOf(x).Int())
-       case struct { a, b T }:
+       case struct{ a, b T }:
                println("struct{T,T}", x.a, x.b)
        default:
                println("other", reflect.ValueOf(x).Int())
@@ -26,6 +26,6 @@ func main() {
        f[float64](float64(6))
        f[float64](int(7))
        f[float64](int32(8))
-       f[float64](struct{a, b float64}{a:1, b:2})
+       f[float64](struct{ a, b float64 }{a: 1, b: 2})
        f[float64](int8(9))
 }
index 4c940aa85599c12c4b4300744983ae769d43da49..d04bcbdc7d6a2f8f41d9c617791b8c8aa01661a7 100644 (file)
@@ -47,6 +47,11 @@ func main() {
                // size overflows address space
                mustPanic(func() { _ = unsafe.Slice(new(uint64), maxUintptr/8) })
                mustPanic(func() { _ = unsafe.Slice(new(uint64), maxUintptr/8+1) })
+
+               // sliced memory overflows address space
+               last := (*byte)(unsafe.Pointer(^uintptr(0)))
+               _ = unsafe.Slice(last, 1)
+               mustPanic(func() { _ = unsafe.Slice(last, 2) })
        }
 }
 
index dbf0b6dde28662d0d6670037744c6611866e31a1..1b30fa509e5503275904c53fb7d559296ab85259 100644 (file)
@@ -289,3 +289,17 @@ func f27(p *int) []interface{} {
                p,           // ERROR "write barrier"
        }
 }
+
+var g28 [256]uint64
+
+func f28() []interface{} {
+       return []interface{}{
+               false,      // no write barrier
+               true,       // no write barrier
+               0,          // no write barrier
+               1,          // no write barrier
+               uint8(127), // no write barrier
+               int8(-4),   // no write barrier
+               &g28[5],    // no write barrier
+       }
+}
index 214d481164442aab25c7e5f9189933108a54c005..fd36d67d1ad6dc8b189473a7e45206edea866428 100644 (file)
@@ -218,7 +218,7 @@ func main() {
                        }
                        fmt.Printf("%s: expected no error; got %q\n", t.name, err)
                case t.err != "" && err != "":
-                       if strings.Index(err, t.err) < 0 {
+                       if !strings.Contains(err, t.err) {
                                if !bad {
                                        bad = true
                                        fmt.Printf("BUG\n")