mirror of
https://github.com/golang/go.git
synced 2026-01-30 23:52:05 +03:00
Compare commits
4 Commits
dev.corety
...
go1.22rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa72f3e034 | ||
|
|
fb23428a85 | ||
|
|
f06eaf0c4f | ||
|
|
796f59df92 |
15
.github/ISSUE_TEMPLATE/00-bug.yml
vendored
15
.github/ISSUE_TEMPLATE/00-bug.yml
vendored
@@ -23,9 +23,9 @@ body:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: go-env
|
||||
id: os-and-processor
|
||||
attributes:
|
||||
label: "Output of `go env` in your module/workspace:"
|
||||
label: "What operating system and processor architecture are you using (`go env`)?"
|
||||
placeholder: |
|
||||
GO111MODULE=""
|
||||
GOARCH="arm64"
|
||||
@@ -78,17 +78,16 @@ body:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: "What did you see happen?"
|
||||
description: Command invocations and their associated output, functions with their arguments and return results, full stacktraces for panics (upload a file if it is very long), etc. Prefer copying text output over using screenshots.
|
||||
label: "What did you expect to see?"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you expect to see?"
|
||||
description: Why is the current output incorrect, and any additional context we may need to understand the issue.
|
||||
label: "What did you see instead?"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/01-pkgsite.yml
vendored
12
.github/ISSUE_TEMPLATE/01-pkgsite.yml
vendored
@@ -33,15 +33,15 @@ body:
|
||||
description: "If possible, provide a recipe for reproducing the error. Starting with a Private/Incognito tab/window may help rule out problematic browser extensions."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you see happen?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: "What did you expect to see?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you see instead?"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
19
.github/ISSUE_TEMPLATE/02-pkgsite-removal.yml
vendored
19
.github/ISSUE_TEMPLATE/02-pkgsite-removal.yml
vendored
@@ -10,33 +10,20 @@ body:
|
||||
id: package-path
|
||||
attributes:
|
||||
label: "What is the path of the package that you would like to have removed?"
|
||||
description: |
|
||||
We can remove packages with a shared path prefix.
|
||||
For example, a request for 'github.com/author' would remove all pkg.go.dev pages with that package path prefix.
|
||||
description: "We can remove packages with a shared path prefix. For example, a request for 'github.com/author' would remove all pkg.go.dev pages with that package path prefix."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: package-owner
|
||||
attributes:
|
||||
label: "Are you the owner of this package?"
|
||||
description: |
|
||||
Only the package owners can request to have their packages removed from pkg.go.dev.
|
||||
If the package path doesn't include your github username, please provide some other form of proof of ownership.
|
||||
description: "Only the package owners can request to have their packages removed from pkg.go.dev."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: retraction-reason
|
||||
attributes:
|
||||
label: "What is the reason that you could not retract this package instead?"
|
||||
description: |
|
||||
Requesting we remove a module here only hides the generated documentation on pkg.go.dev.
|
||||
It does not affect the behaviour of proxy.golang.org or the go command.
|
||||
Instead we recommend using the retract directive which will be processed by all 3 of the above.
|
||||
|
||||
If you have deleted your repo, please recreate it and publish a retraction.
|
||||
|
||||
Retracting a module version involves adding a retract directive to your go.mod file and publishing a new version.
|
||||
For example: https://github.com/jba/retract-demo/blob/main/go.mod#L5-L8.
|
||||
See https://pkg.go.dev/about#removing-a-package for additional tips on retractions.
|
||||
description: "If you would like to have your module removed from pkg.go.dev, we recommend that you retract them, so that they can be removed from the go command and proxy.golang.org as well. Retracting a module version involves adding a retract directive to your go.mod file and publishing a new version. For example: https://github.com/jba/retract-demo/blob/main/go.mod#L5-L8. See https://pkg.go.dev/about#removing-a-package for additional tips on retractions."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/03-gopls.yml
vendored
16
.github/ISSUE_TEMPLATE/03-gopls.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please answer these questions before submitting your issue. Thanks!"
|
||||
- type: textarea
|
||||
- type: input
|
||||
id: gopls-version
|
||||
attributes:
|
||||
label: "gopls version"
|
||||
@@ -25,13 +25,7 @@ body:
|
||||
id: what-did-you-do
|
||||
attributes:
|
||||
label: "What did you do?"
|
||||
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is better. A failing unit test is the best."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you see happen?"
|
||||
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on go.dev/play is better. A failing unit test is the best."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
@@ -40,6 +34,12 @@ body:
|
||||
label: "What did you expect to see?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you see instead?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: editor-and-settings
|
||||
attributes:
|
||||
|
||||
18
.github/ISSUE_TEMPLATE/04-vuln.yml
vendored
18
.github/ISSUE_TEMPLATE/04-vuln.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please answer these questions before submitting your issue. Thanks! To add a new vulnerability to the Go vulnerability database (https://vuln.go.dev), see https://go.dev/s/vulndb-report-new. To report an issue about a report, see https://go.dev/s/vulndb-report-feedback."
|
||||
- type: textarea
|
||||
- type: input
|
||||
id: govulncheck-version
|
||||
attributes:
|
||||
label: govulncheck version
|
||||
@@ -25,9 +25,9 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: go-env
|
||||
id: os-and-processor
|
||||
attributes:
|
||||
label: "Output of `go env` in your module/workspace:"
|
||||
label: "What operating system and processor architecture are you using (`go env`)?"
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
@@ -38,15 +38,15 @@ body:
|
||||
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is best."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you see happen?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: "What did you expect to see?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: "What did you see instead?"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Language Change Proposals
|
||||
description: Changes to the language
|
||||
labels: ["Proposal", "LanguageChange", "LanguageChangeReview"]
|
||||
title: "proposal: spec: proposal title"
|
||||
labels: ["Proposal", "v2", "LanguageChange"]
|
||||
title: "proposal: Go 2: proposal title"
|
||||
|
||||
|
||||
body:
|
||||
|
||||
74
.github/ISSUE_TEMPLATE/12-telemetry.yml
vendored
74
.github/ISSUE_TEMPLATE/12-telemetry.yml
vendored
@@ -1,30 +1,68 @@
|
||||
name: Go Telemetry Proposals
|
||||
description: Changes to the telemetry upload configuration
|
||||
description: New telemetry counter or update on an existing one
|
||||
title: "x/telemetry/config: proposal title"
|
||||
labels: ["Telemetry-Proposal"]
|
||||
projects: ["golang/29"]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Summary
|
||||
description: >
|
||||
What change are you proposing to the upload configuration, and why?
|
||||
For new upload configuration, which new counters will be collected, what
|
||||
do they measure, and why is it important to collect them?
|
||||
Note that uploaded data must not carry sensitive user information.
|
||||
See [go.dev/doc/telemetry#proposals](https://go.dev/doc/telemetry#proposals)
|
||||
for more details on telemetry proposals.
|
||||
label: Counter names
|
||||
description: Names of counters to add or update.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed Config Change
|
||||
description: >
|
||||
A CL containing proposed changes to the
|
||||
[config.txt](https://go.googlesource.com/telemetry/+/master/internal/chartconfig/config.txt)
|
||||
chart configuration.
|
||||
See the [chartconfig](https://pkg.go.dev/golang.org/x/telemetry/internal/chartconfig)
|
||||
package for an explanation of the chart config format.
|
||||
For an example change, see [CL 564619](https://go.dev/cl/564619).
|
||||
label: Description
|
||||
description: What do these counters measure?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Rationale
|
||||
description: |
|
||||
Why is the counter important?
|
||||
For example, what new insights will it provide, and how will that information be used?
|
||||
If this is about updating existing counters, why is the change necessary?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Do the counters carry sensitive user information?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How?
|
||||
description: |
|
||||
How do we plan to compute the info?
|
||||
If available, include the code location or cl that uses the golang.org/x/telemetry/counter API.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed Graph Config
|
||||
description: |
|
||||
Approved telemetry counters are maintained as [Go Telemetry Graph Config](https://golang.org/x/telemetry/internal/graphconfig) records.
|
||||
Please draft the record entry for your proposal here.
|
||||
If multiple records need to be included, separate them with `---` lines.
|
||||
You can check the list of the approved counters and their current configuration in [config.txt](https://go.googlesource.com/telemetry/+/master/internal/configgen/config.txt).
|
||||
render: Text
|
||||
value: |
|
||||
counter: gopls/bug
|
||||
title: Gopls bug reports
|
||||
description: Stacks of bugs encountered on the gopls server.
|
||||
type: partition, histogram, stack # choose only one.
|
||||
program: golang.org/x/tools/gopls
|
||||
counter: gopls/bug
|
||||
depth: 16 # only if type is stack.
|
||||
version: v0.13.0 # the first binary version containing this counter.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: New or Update
|
||||
description: Is this a new counter? See [config.txt](https://go.googlesource.com/telemetry/+/master/internal/configgen/config.txt) for the list of approved counters.
|
||||
options:
|
||||
- New
|
||||
- Update
|
||||
default: 0
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -37,7 +37,7 @@ _testmain.go
|
||||
/src/go/build/zcgo.go
|
||||
/src/go/doc/headscan
|
||||
/src/internal/buildcfg/zbootstrap.go
|
||||
/src/internal/runtime/sys/zversion.go
|
||||
/src/runtime/internal/sys/zversion.go
|
||||
/src/unicode/maketables
|
||||
/src/time/tzdata/zzipdata.go
|
||||
/test.out
|
||||
|
||||
4
LICENSE
4
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright 2009 The Go Authors.
|
||||
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
|
||||
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
||||
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 LLC nor the names of its
|
||||
* 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.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Go is an open source programming language that makes it easy to build simple,
|
||||
reliable, and efficient software.
|
||||
|
||||

|
||||
*Gopher image by [Renee French][rf], licensed under [Creative Commons 4.0 Attribution license][cc4-by].*
|
||||
*Gopher image by [Renee French][rf], licensed under [Creative Commons 4.0 Attributions license][cc4-by].*
|
||||
|
||||
Our canonical Git repository is located at https://go.googlesource.com/go.
|
||||
There is a mirror of the repository at https://github.com/golang/go.
|
||||
|
||||
@@ -21,6 +21,3 @@ warning output from the go api tool. Each file should be named
|
||||
nnnnn.txt, after the issue number for the accepted proposal.
|
||||
(The #nnnnn suffix must also appear at the end of each line in the file;
|
||||
that will be preserved when next/*.txt is concatenated into go1.XX.txt.)
|
||||
|
||||
When you add a file to the api/next directory, you must add at least one file
|
||||
under doc/next. See doc/README.md for details.
|
||||
|
||||
@@ -598,7 +598,3 @@ pkg syscall (freebsd-arm64-cgo), const SYS_MKNODAT = 498
|
||||
pkg syscall (freebsd-arm64-cgo), const SYS_STAT = 188
|
||||
pkg syscall (freebsd-arm64-cgo), const SYS_STAT ideal-int
|
||||
pkg syscall (freebsd-arm64-cgo), const SYS_STATFS = 396
|
||||
pkg syscall (openbsd-386), const ELAST = 91
|
||||
pkg syscall (openbsd-386-cgo), const ELAST = 91
|
||||
pkg syscall (openbsd-amd64), const ELAST = 91
|
||||
pkg syscall (openbsd-amd64-cgo), const ELAST = 91
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
pkg archive/tar, method (*Writer) AddFS(fs.FS) error #58000
|
||||
pkg archive/tar, type FileInfoNames interface { Gname, IsDir, ModTime, Mode, Name, Size, Sys, Uname } #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Gname(int) (string, error) #50102
|
||||
pkg archive/tar, type FileInfoNames interface, IsDir() bool #50102
|
||||
pkg archive/tar, type FileInfoNames interface, ModTime() time.Time #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Mode() fs.FileMode #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Name() string #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Size() int64 #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Sys() interface{} #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Uname(int) (string, error) #50102
|
||||
pkg archive/zip, method (*Writer) AddFS(fs.FS) error #54898
|
||||
pkg cmp, func Or[$0 comparable](...$0) $0 #60204
|
||||
pkg crypto/x509, func OIDFromInts([]uint64) (OID, error) #60665
|
||||
|
||||
158
api/go1.23.txt
158
api/go1.23.txt
@@ -1,158 +0,0 @@
|
||||
pkg archive/tar, type FileInfoNames interface { Gname, IsDir, ModTime, Mode, Name, Size, Sys, Uname } #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Gname() (string, error) #50102
|
||||
pkg archive/tar, type FileInfoNames interface, IsDir() bool #50102
|
||||
pkg archive/tar, type FileInfoNames interface, ModTime() time.Time #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Mode() fs.FileMode #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Name() string #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Size() int64 #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Sys() interface{} #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Uname() (string, error) #50102
|
||||
pkg crypto/tls, const QUICResumeSession = 8 #63691
|
||||
pkg crypto/tls, const QUICResumeSession QUICEventKind #63691
|
||||
pkg crypto/tls, const QUICStoreSession = 9 #63691
|
||||
pkg crypto/tls, const QUICStoreSession QUICEventKind #63691
|
||||
pkg crypto/tls, method (*ECHRejectionError) Error() string #63369
|
||||
pkg crypto/tls, method (*QUICConn) StoreSession(*SessionState) error #63691
|
||||
pkg crypto/tls, type Config struct, EncryptedClientHelloConfigList []uint8 #63369
|
||||
pkg crypto/tls, type Config struct, EncryptedClientHelloRejectionVerify func(ConnectionState) error #63369
|
||||
pkg crypto/tls, type ConnectionState struct, ECHAccepted bool #63369
|
||||
pkg crypto/tls, type ECHRejectionError struct #63369
|
||||
pkg crypto/tls, type ECHRejectionError struct, RetryConfigList []uint8 #63369
|
||||
pkg crypto/tls, type QUICConfig struct, EnableSessionEvents bool #63691
|
||||
pkg crypto/tls, type QUICEvent struct, SessionState *SessionState #63691
|
||||
pkg crypto/tls, type QUICSessionTicketOptions struct, Extra [][]uint8 #63691
|
||||
pkg crypto/x509, func ParseOID(string) (OID, error) #66249
|
||||
pkg crypto/x509, method (*OID) UnmarshalBinary([]uint8) error #66249
|
||||
pkg crypto/x509, method (*OID) UnmarshalText([]uint8) error #66249
|
||||
pkg crypto/x509, method (OID) MarshalBinary() ([]uint8, error) #66249
|
||||
pkg crypto/x509, method (OID) MarshalText() ([]uint8, error) #66249
|
||||
pkg debug/elf, const PT_OPENBSD_NOBTCFI = 1705237480 #66054
|
||||
pkg debug/elf, const PT_OPENBSD_NOBTCFI ProgType #66054
|
||||
pkg debug/elf, const STT_GNU_IFUNC = 10 #66836
|
||||
pkg debug/elf, const STT_GNU_IFUNC SymType #66836
|
||||
pkg debug/elf, const STT_RELC = 8 #66836
|
||||
pkg debug/elf, const STT_RELC SymType #66836
|
||||
pkg debug/elf, const STT_SRELC = 9 #66836
|
||||
pkg debug/elf, const STT_SRELC SymType #66836
|
||||
pkg encoding/binary, func Append([]uint8, ByteOrder, interface{}) ([]uint8, error) #60023
|
||||
pkg encoding/binary, func Decode([]uint8, ByteOrder, interface{}) (int, error) #60023
|
||||
pkg encoding/binary, func Encode([]uint8, ByteOrder, interface{}) (int, error) #60023
|
||||
pkg go/ast, func Preorder(Node) iter.Seq[Node] #66339
|
||||
pkg go/types, method (*Alias) Origin() *Alias #67143
|
||||
pkg go/types, method (*Alias) Rhs() Type #66559
|
||||
pkg go/types, method (*Alias) SetTypeParams([]*TypeParam) #67143
|
||||
pkg go/types, method (*Alias) TypeArgs() *TypeList #67143
|
||||
pkg go/types, method (*Alias) TypeParams() *TypeParamList #67143
|
||||
pkg go/types, method (*Func) Signature() *Signature #65772
|
||||
pkg iter, func Pull2[$0 interface{}, $1 interface{}](Seq2[$0, $1]) (func() ($0, $1, bool), func()) #61897
|
||||
pkg iter, func Pull[$0 interface{}](Seq[$0]) (func() ($0, bool), func()) #61897
|
||||
pkg iter, type Seq2[$0 interface{}, $1 interface{}] func(func($0, $1) bool) #61897
|
||||
pkg iter, type Seq[$0 interface{}] func(func($0) bool) #61897
|
||||
pkg maps, func All[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) iter.Seq2[$1, $2] #61900
|
||||
pkg maps, func Collect[$0 comparable, $1 interface{}](iter.Seq2[$0, $1]) map[$0]$1 #61900
|
||||
pkg maps, func Insert[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0, iter.Seq2[$1, $2]) #61900
|
||||
pkg maps, func Keys[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) iter.Seq[$1] #61900
|
||||
pkg maps, func Values[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) iter.Seq[$2] #61900
|
||||
pkg math/rand/v2, func Uint() uint #61716
|
||||
pkg math/rand/v2, method (*ChaCha8) Read([]uint8) (int, error) #67059
|
||||
pkg math/rand/v2, method (*Rand) Uint() uint #61716
|
||||
pkg net, method (*DNSError) Unwrap() error #63116
|
||||
pkg net, method (*TCPConn) SetKeepAliveConfig(KeepAliveConfig) error #62254
|
||||
pkg net, type DNSError struct, UnwrapErr error #63116
|
||||
pkg net, type Dialer struct, KeepAliveConfig KeepAliveConfig #62254
|
||||
pkg net, type KeepAliveConfig struct #62254
|
||||
pkg net, type KeepAliveConfig struct, Count int #62254
|
||||
pkg net, type KeepAliveConfig struct, Enable bool #62254
|
||||
pkg net, type KeepAliveConfig struct, Idle time.Duration #62254
|
||||
pkg net, type KeepAliveConfig struct, Interval time.Duration #62254
|
||||
pkg net, type ListenConfig struct, KeepAliveConfig KeepAliveConfig #62254
|
||||
pkg net/http, func ParseCookie(string) ([]*Cookie, error) #66008
|
||||
pkg net/http, func ParseSetCookie(string) (*Cookie, error) #66008
|
||||
pkg net/http, method (*Request) CookiesNamed(string) []*Cookie #61472
|
||||
pkg net/http, type Cookie struct, Partitioned bool #62490
|
||||
pkg net/http, type Cookie struct, Quoted bool #46443
|
||||
pkg net/http, type Request struct, Pattern string #66405
|
||||
pkg net/http/httptest, func NewRequestWithContext(context.Context, string, string, io.Reader) *http.Request #59473
|
||||
pkg os, func CopyFS(string, fs.FS) error #62484
|
||||
pkg path/filepath, func Localize(string) (string, error) #57151
|
||||
pkg reflect, func SliceAt(Type, unsafe.Pointer, int) Value #61308
|
||||
pkg reflect, method (Value) Seq() iter.Seq[Value] #66056
|
||||
pkg reflect, method (Value) Seq2() iter.Seq2[Value, Value] #66056
|
||||
pkg reflect, type Type interface, CanSeq() bool #66056
|
||||
pkg reflect, type Type interface, CanSeq2() bool #66056
|
||||
pkg reflect, type Type interface, OverflowComplex(complex128) bool #60427
|
||||
pkg reflect, type Type interface, OverflowFloat(float64) bool #60427
|
||||
pkg reflect, type Type interface, OverflowInt(int64) bool #60427
|
||||
pkg reflect, type Type interface, OverflowUint(uint64) bool #60427
|
||||
pkg runtime/debug, func SetCrashOutput(*os.File, CrashOptions) error #42888
|
||||
pkg runtime/debug, type CrashOptions struct #67182
|
||||
pkg slices, func All[$0 interface{ ~[]$1 }, $1 interface{}]($0) iter.Seq2[int, $1] #61899
|
||||
pkg slices, func AppendSeq[$0 interface{ ~[]$1 }, $1 interface{}]($0, iter.Seq[$1]) $0 #61899
|
||||
pkg slices, func Backward[$0 interface{ ~[]$1 }, $1 interface{}]($0) iter.Seq2[int, $1] #61899
|
||||
pkg slices, func Chunk[$0 interface{ ~[]$1 }, $1 interface{}]($0, int) iter.Seq[$0] #53987
|
||||
pkg slices, func Collect[$0 interface{}](iter.Seq[$0]) []$0 #61899
|
||||
pkg slices, func Repeat[$0 interface{ ~[]$1 }, $1 interface{}]($0, int) $0 #65238
|
||||
pkg slices, func SortedFunc[$0 interface{}](iter.Seq[$0], func($0, $0) int) []$0 #61899
|
||||
pkg slices, func SortedStableFunc[$0 interface{}](iter.Seq[$0], func($0, $0) int) []$0 #61899
|
||||
pkg slices, func Sorted[$0 cmp.Ordered](iter.Seq[$0]) []$0 #61899
|
||||
pkg slices, func Values[$0 interface{ ~[]$1 }, $1 interface{}]($0) iter.Seq[$1] #61899
|
||||
pkg structs, type HostLayout struct #66408
|
||||
pkg sync, method (*Map) Clear() #61696
|
||||
pkg sync/atomic, func AndInt32(*int32, int32) int32 #61395
|
||||
pkg sync/atomic, func AndInt64(*int64, int64) int64 #61395
|
||||
pkg sync/atomic, func AndUint32(*uint32, uint32) uint32 #61395
|
||||
pkg sync/atomic, func AndUint64(*uint64, uint64) uint64 #61395
|
||||
pkg sync/atomic, func AndUintptr(*uintptr, uintptr) uintptr #61395
|
||||
pkg sync/atomic, func OrInt32(*int32, int32) int32 #61395
|
||||
pkg sync/atomic, func OrInt64(*int64, int64) int64 #61395
|
||||
pkg sync/atomic, func OrUint32(*uint32, uint32) uint32 #61395
|
||||
pkg sync/atomic, func OrUint64(*uint64, uint64) uint64 #61395
|
||||
pkg sync/atomic, func OrUintptr(*uintptr, uintptr) uintptr #61395
|
||||
pkg sync/atomic, method (*Int32) And(int32) int32 #61395
|
||||
pkg sync/atomic, method (*Int32) Or(int32) int32 #61395
|
||||
pkg sync/atomic, method (*Int64) And(int64) int64 #61395
|
||||
pkg sync/atomic, method (*Int64) Or(int64) int64 #61395
|
||||
pkg sync/atomic, method (*Uint32) And(uint32) uint32 #61395
|
||||
pkg sync/atomic, method (*Uint32) Or(uint32) uint32 #61395
|
||||
pkg sync/atomic, method (*Uint64) And(uint64) uint64 #61395
|
||||
pkg sync/atomic, method (*Uint64) Or(uint64) uint64 #61395
|
||||
pkg sync/atomic, method (*Uintptr) And(uintptr) uintptr #61395
|
||||
pkg sync/atomic, method (*Uintptr) Or(uintptr) uintptr #61395
|
||||
pkg syscall (openbsd-386), const EBADMSG = 92 #67998
|
||||
pkg syscall (openbsd-386), const ELAST = 95 #67998
|
||||
pkg syscall (openbsd-386), const ENOTRECOVERABLE = 93 #67998
|
||||
pkg syscall (openbsd-386), const ENOTRECOVERABLE Errno #67998
|
||||
pkg syscall (openbsd-386), const EOWNERDEAD = 94 #67998
|
||||
pkg syscall (openbsd-386), const EOWNERDEAD Errno #67998
|
||||
pkg syscall (openbsd-386), const EPROTO = 95 #67998
|
||||
pkg syscall (openbsd-386-cgo), const EBADMSG = 92 #67998
|
||||
pkg syscall (openbsd-386-cgo), const ELAST = 95 #67998
|
||||
pkg syscall (openbsd-386-cgo), const ENOTRECOVERABLE = 93 #67998
|
||||
pkg syscall (openbsd-386-cgo), const ENOTRECOVERABLE Errno #67998
|
||||
pkg syscall (openbsd-386-cgo), const EOWNERDEAD = 94 #67998
|
||||
pkg syscall (openbsd-386-cgo), const EOWNERDEAD Errno #67998
|
||||
pkg syscall (openbsd-386-cgo), const EPROTO = 95 #67998
|
||||
pkg syscall (openbsd-amd64), const EBADMSG = 92 #67998
|
||||
pkg syscall (openbsd-amd64), const ELAST = 95 #67998
|
||||
pkg syscall (openbsd-amd64), const ENOTRECOVERABLE = 93 #67998
|
||||
pkg syscall (openbsd-amd64), const ENOTRECOVERABLE Errno #67998
|
||||
pkg syscall (openbsd-amd64), const EOWNERDEAD = 94 #67998
|
||||
pkg syscall (openbsd-amd64), const EOWNERDEAD Errno #67998
|
||||
pkg syscall (openbsd-amd64), const EPROTO = 95 #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const EBADMSG = 92 #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const ELAST = 95 #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const ENOTRECOVERABLE = 93 #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const ENOTRECOVERABLE Errno #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const EOWNERDEAD = 94 #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const EOWNERDEAD Errno #67998
|
||||
pkg syscall (openbsd-amd64-cgo), const EPROTO = 95 #67998
|
||||
pkg syscall (windows-386), const WSAENOPROTOOPT = 10042 #62254
|
||||
pkg syscall (windows-386), const WSAENOPROTOOPT Errno #62254
|
||||
pkg syscall (windows-amd64), const WSAENOPROTOOPT = 10042 #62254
|
||||
pkg syscall (windows-amd64), const WSAENOPROTOOPT Errno #62254
|
||||
pkg syscall, const EBADMSG Errno #67998
|
||||
pkg syscall, const EPROTO Errno #67998
|
||||
pkg unicode/utf16, func RuneLen(int32) int #44940
|
||||
pkg unique, func Make[$0 comparable]($0) Handle[$0] #62483
|
||||
pkg unique, method (Handle[$0]) Value() $0 #62483
|
||||
pkg unique, type Handle[$0 comparable] struct #62483
|
||||
230
api/go1.24.txt
230
api/go1.24.txt
@@ -1,230 +0,0 @@
|
||||
pkg bytes, func FieldsFuncSeq([]uint8, func(int32) bool) iter.Seq[[]uint8] #61901
|
||||
pkg bytes, func FieldsSeq([]uint8) iter.Seq[[]uint8] #61901
|
||||
pkg bytes, func Lines([]uint8) iter.Seq[[]uint8] #61901
|
||||
pkg bytes, func SplitAfterSeq([]uint8, []uint8) iter.Seq[[]uint8] #61901
|
||||
pkg bytes, func SplitSeq([]uint8, []uint8) iter.Seq[[]uint8] #61901
|
||||
pkg crypto/cipher, func NewCFBDecrypter //deprecated #69445
|
||||
pkg crypto/cipher, func NewCFBEncrypter //deprecated #69445
|
||||
pkg crypto/cipher, func NewGCMWithRandomNonce(Block) (AEAD, error) #69981
|
||||
pkg crypto/cipher, func NewOFB //deprecated #69445
|
||||
pkg crypto/fips140, func Enabled() bool #70123
|
||||
pkg crypto/hkdf, func Expand[$0 hash.Hash](func() $0, []uint8, string, int) ([]uint8, error) #61477
|
||||
pkg crypto/hkdf, func Extract[$0 hash.Hash](func() $0, []uint8, []uint8) ([]uint8, error) #61477
|
||||
pkg crypto/hkdf, func Key[$0 hash.Hash](func() $0, []uint8, []uint8, string, int) ([]uint8, error) #61477
|
||||
pkg crypto/mlkem, const CiphertextSize1024 = 1568 #70122
|
||||
pkg crypto/mlkem, const CiphertextSize1024 ideal-int #70122
|
||||
pkg crypto/mlkem, const CiphertextSize768 = 1088 #70122
|
||||
pkg crypto/mlkem, const CiphertextSize768 ideal-int #70122
|
||||
pkg crypto/mlkem, const EncapsulationKeySize1024 = 1568 #70122
|
||||
pkg crypto/mlkem, const EncapsulationKeySize1024 ideal-int #70122
|
||||
pkg crypto/mlkem, const EncapsulationKeySize768 = 1184 #70122
|
||||
pkg crypto/mlkem, const EncapsulationKeySize768 ideal-int #70122
|
||||
pkg crypto/mlkem, const SeedSize = 64 #70122
|
||||
pkg crypto/mlkem, const SeedSize ideal-int #70122
|
||||
pkg crypto/mlkem, const SharedKeySize = 32 #70122
|
||||
pkg crypto/mlkem, const SharedKeySize ideal-int #70122
|
||||
pkg crypto/mlkem, func GenerateKey1024() (*DecapsulationKey1024, error) #70122
|
||||
pkg crypto/mlkem, func GenerateKey768() (*DecapsulationKey768, error) #70122
|
||||
pkg crypto/mlkem, func NewDecapsulationKey1024([]uint8) (*DecapsulationKey1024, error) #70122
|
||||
pkg crypto/mlkem, func NewDecapsulationKey768([]uint8) (*DecapsulationKey768, error) #70122
|
||||
pkg crypto/mlkem, func NewEncapsulationKey1024([]uint8) (*EncapsulationKey1024, error) #70122
|
||||
pkg crypto/mlkem, func NewEncapsulationKey768([]uint8) (*EncapsulationKey768, error) #70122
|
||||
pkg crypto/mlkem, method (*DecapsulationKey1024) Bytes() []uint8 #70122
|
||||
pkg crypto/mlkem, method (*DecapsulationKey1024) Decapsulate([]uint8) ([]uint8, error) #70122
|
||||
pkg crypto/mlkem, method (*DecapsulationKey1024) EncapsulationKey() *EncapsulationKey1024 #70122
|
||||
pkg crypto/mlkem, method (*DecapsulationKey768) Bytes() []uint8 #70122
|
||||
pkg crypto/mlkem, method (*DecapsulationKey768) Decapsulate([]uint8) ([]uint8, error) #70122
|
||||
pkg crypto/mlkem, method (*DecapsulationKey768) EncapsulationKey() *EncapsulationKey768 #70122
|
||||
pkg crypto/mlkem, method (*EncapsulationKey1024) Bytes() []uint8 #70122
|
||||
pkg crypto/mlkem, method (*EncapsulationKey1024) Encapsulate() ([]uint8, []uint8) #70122
|
||||
pkg crypto/mlkem, method (*EncapsulationKey768) Bytes() []uint8 #70122
|
||||
pkg crypto/mlkem, method (*EncapsulationKey768) Encapsulate() ([]uint8, []uint8) #70122
|
||||
pkg crypto/mlkem, type DecapsulationKey1024 struct #70122
|
||||
pkg crypto/mlkem, type DecapsulationKey768 struct #70122
|
||||
pkg crypto/mlkem, type EncapsulationKey1024 struct #70122
|
||||
pkg crypto/mlkem, type EncapsulationKey768 struct #70122
|
||||
pkg crypto/pbkdf2, func Key[$0 hash.Hash](func() $0, string, []uint8, int, int) ([]uint8, error) #69488
|
||||
pkg crypto/rand, func Text() string #67057
|
||||
pkg crypto/sha3, func New224() *SHA3 #69982
|
||||
pkg crypto/sha3, func New256() *SHA3 #69982
|
||||
pkg crypto/sha3, func New384() *SHA3 #69982
|
||||
pkg crypto/sha3, func New512() *SHA3 #69982
|
||||
pkg crypto/sha3, func NewCSHAKE128([]uint8, []uint8) *SHAKE #69982
|
||||
pkg crypto/sha3, func NewCSHAKE256([]uint8, []uint8) *SHAKE #69982
|
||||
pkg crypto/sha3, func NewSHAKE128() *SHAKE #69982
|
||||
pkg crypto/sha3, func NewSHAKE256() *SHAKE #69982
|
||||
pkg crypto/sha3, func Sum224([]uint8) [28]uint8 #69982
|
||||
pkg crypto/sha3, func Sum256([]uint8) [32]uint8 #69982
|
||||
pkg crypto/sha3, func Sum384([]uint8) [48]uint8 #69982
|
||||
pkg crypto/sha3, func Sum512([]uint8) [64]uint8 #69982
|
||||
pkg crypto/sha3, func SumSHAKE128([]uint8, int) []uint8 #69982
|
||||
pkg crypto/sha3, func SumSHAKE256([]uint8, int) []uint8 #69982
|
||||
pkg crypto/sha3, method (*SHA3) AppendBinary([]uint8) ([]uint8, error) #69982
|
||||
pkg crypto/sha3, method (*SHA3) BlockSize() int #69982
|
||||
pkg crypto/sha3, method (*SHA3) MarshalBinary() ([]uint8, error) #69982
|
||||
pkg crypto/sha3, method (*SHA3) Reset() #69982
|
||||
pkg crypto/sha3, method (*SHA3) Size() int #69982
|
||||
pkg crypto/sha3, method (*SHA3) Sum([]uint8) []uint8 #69982
|
||||
pkg crypto/sha3, method (*SHA3) UnmarshalBinary([]uint8) error #69982
|
||||
pkg crypto/sha3, method (*SHA3) Write([]uint8) (int, error) #69982
|
||||
pkg crypto/sha3, method (*SHAKE) AppendBinary([]uint8) ([]uint8, error) #69982
|
||||
pkg crypto/sha3, method (*SHAKE) BlockSize() int #69982
|
||||
pkg crypto/sha3, method (*SHAKE) MarshalBinary() ([]uint8, error) #69982
|
||||
pkg crypto/sha3, method (*SHAKE) Read([]uint8) (int, error) #69982
|
||||
pkg crypto/sha3, method (*SHAKE) Reset() #69982
|
||||
pkg crypto/sha3, method (*SHAKE) UnmarshalBinary([]uint8) error #69982
|
||||
pkg crypto/sha3, method (*SHAKE) Write([]uint8) (int, error) #69982
|
||||
pkg crypto/sha3, type SHA3 struct #69982
|
||||
pkg crypto/sha3, type SHAKE struct #69982
|
||||
pkg crypto/subtle, func WithDataIndependentTiming(func()) #66450
|
||||
pkg crypto/tls, const X25519MLKEM768 = 4588 #69985
|
||||
pkg crypto/tls, const X25519MLKEM768 CurveID #69985
|
||||
pkg crypto/tls, type ClientHelloInfo struct, Extensions []uint16 #32936
|
||||
pkg crypto/tls, type Config struct, EncryptedClientHelloKeys []EncryptedClientHelloKey #68500
|
||||
pkg crypto/tls, type EncryptedClientHelloKey struct #68500
|
||||
pkg crypto/tls, type EncryptedClientHelloKey struct, Config []uint8 #68500
|
||||
pkg crypto/tls, type EncryptedClientHelloKey struct, PrivateKey []uint8 #68500
|
||||
pkg crypto/tls, type EncryptedClientHelloKey struct, SendAsRetry bool #68500
|
||||
pkg crypto/x509, const NoValidChains = 10 #68484
|
||||
pkg crypto/x509, const NoValidChains InvalidReason #68484
|
||||
pkg crypto/x509, method (OID) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg crypto/x509, method (OID) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg crypto/x509, type Certificate struct, InhibitAnyPolicy int #68484
|
||||
pkg crypto/x509, type Certificate struct, InhibitAnyPolicyZero bool #68484
|
||||
pkg crypto/x509, type Certificate struct, InhibitPolicyMapping int #68484
|
||||
pkg crypto/x509, type Certificate struct, InhibitPolicyMappingZero bool #68484
|
||||
pkg crypto/x509, type Certificate struct, PolicyMappings []PolicyMapping #68484
|
||||
pkg crypto/x509, type Certificate struct, RequireExplicitPolicy int #68484
|
||||
pkg crypto/x509, type Certificate struct, RequireExplicitPolicyZero bool #68484
|
||||
pkg crypto/x509, type PolicyMapping struct #68484
|
||||
pkg crypto/x509, type PolicyMapping struct, IssuerDomainPolicy OID #68484
|
||||
pkg crypto/x509, type PolicyMapping struct, SubjectDomainPolicy OID #68484
|
||||
pkg crypto/x509, type VerifyOptions struct, CertificatePolicies []OID #68484
|
||||
pkg debug/elf, const VER_FLG_BASE = 1 #63952
|
||||
pkg debug/elf, const VER_FLG_BASE DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VER_FLG_INFO = 4 #63952
|
||||
pkg debug/elf, const VER_FLG_INFO DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VER_FLG_WEAK = 2 #63952
|
||||
pkg debug/elf, const VER_FLG_WEAK DynamicVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagGlobal = 2 #63952
|
||||
pkg debug/elf, const VerFlagGlobal SymbolVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagHidden = 4 #63952
|
||||
pkg debug/elf, const VerFlagHidden SymbolVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagLocal = 1 #63952
|
||||
pkg debug/elf, const VerFlagLocal SymbolVersionFlag #63952
|
||||
pkg debug/elf, const VerFlagNone = 0 #63952
|
||||
pkg debug/elf, const VerFlagNone SymbolVersionFlag #63952
|
||||
pkg debug/elf, method (*File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) #63952
|
||||
pkg debug/elf, method (*File) DynamicVersions() ([]DynamicVersion, error) #63952
|
||||
pkg debug/elf, type DynamicVersion struct #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Deps []string #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Flags DynamicVersionFlag #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Index uint16 #63952
|
||||
pkg debug/elf, type DynamicVersion struct, Version uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Dep string #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Flags DynamicVersionFlag #63952
|
||||
pkg debug/elf, type DynamicVersionDep struct, Other uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionFlag uint16 #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Name string #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Needs []DynamicVersionDep #63952
|
||||
pkg debug/elf, type DynamicVersionNeed struct, Version uint16 #63952
|
||||
pkg debug/elf, type Symbol struct, VersionFlags SymbolVersionFlag #63952
|
||||
pkg debug/elf, type Symbol struct, VersionIndex int16 #63952
|
||||
pkg debug/elf, type SymbolVersionFlag uint8 #63952
|
||||
pkg encoding, type BinaryAppender interface { AppendBinary } #62384
|
||||
pkg encoding, type BinaryAppender interface, AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg encoding, type TextAppender interface { AppendText } #62384
|
||||
pkg encoding, type TextAppender interface, AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg go/types, method (*Interface) EmbeddedTypes() iter.Seq[Type] #66626
|
||||
pkg go/types, method (*Interface) ExplicitMethods() iter.Seq[*Func] #66626
|
||||
pkg go/types, method (*Interface) Methods() iter.Seq[*Func] #66626
|
||||
pkg go/types, method (*MethodSet) Methods() iter.Seq[*Selection] #66626
|
||||
pkg go/types, method (*Named) Methods() iter.Seq[*Func] #66626
|
||||
pkg go/types, method (*Scope) Children() iter.Seq[*Scope] #66626
|
||||
pkg go/types, method (*Struct) Fields() iter.Seq[*Var] #66626
|
||||
pkg go/types, method (*Tuple) Variables() iter.Seq[*Var] #66626
|
||||
pkg go/types, method (*TypeList) Types() iter.Seq[Type] #66626
|
||||
pkg go/types, method (*TypeParamList) TypeParams() iter.Seq[*TypeParam] #66626
|
||||
pkg go/types, method (*Union) Terms() iter.Seq[*Term] #66626
|
||||
pkg hash/maphash, func Comparable[$0 comparable](Seed, $0) uint64 #54670
|
||||
pkg hash/maphash, func WriteComparable[$0 comparable](*Hash, $0) #54670
|
||||
pkg log/slog, method (*LevelVar) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg log/slog, method (Level) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg log/slog, var DiscardHandler Handler #62005
|
||||
pkg math/big, method (*Float) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg math/big, method (*Int) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg math/big, method (*Rat) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg math/rand/v2, method (*ChaCha8) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg math/rand/v2, method (*PCG) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg net, method (IP) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg net/http, method (*Protocols) SetHTTP1(bool) #67814
|
||||
pkg net/http, method (*Protocols) SetHTTP2(bool) #67814
|
||||
pkg net/http, method (*Protocols) SetUnencryptedHTTP2(bool) #67816
|
||||
pkg net/http, method (Protocols) HTTP1() bool #67814
|
||||
pkg net/http, method (Protocols) HTTP2() bool #67814
|
||||
pkg net/http, method (Protocols) String() string #67814
|
||||
pkg net/http, method (Protocols) UnencryptedHTTP2() bool #67816
|
||||
pkg net/http, type HTTP2Config struct #67813
|
||||
pkg net/http, type HTTP2Config struct, CountError func(string) #67813
|
||||
pkg net/http, type HTTP2Config struct, MaxConcurrentStreams int #67813
|
||||
pkg net/http, type HTTP2Config struct, MaxDecoderHeaderTableSize int #67813
|
||||
pkg net/http, type HTTP2Config struct, MaxEncoderHeaderTableSize int #67813
|
||||
pkg net/http, type HTTP2Config struct, MaxReadFrameSize int #67813
|
||||
pkg net/http, type HTTP2Config struct, MaxReceiveBufferPerConnection int #67813
|
||||
pkg net/http, type HTTP2Config struct, MaxReceiveBufferPerStream int #67813
|
||||
pkg net/http, type HTTP2Config struct, PermitProhibitedCipherSuites bool #67813
|
||||
pkg net/http, type HTTP2Config struct, PingTimeout time.Duration #67813
|
||||
pkg net/http, type HTTP2Config struct, SendPingTimeout time.Duration #67813
|
||||
pkg net/http, type HTTP2Config struct, WriteByteTimeout time.Duration #67813
|
||||
pkg net/http, type Protocols struct #67814
|
||||
pkg net/http, type Server struct, HTTP2 *HTTP2Config #67813
|
||||
pkg net/http, type Server struct, Protocols *Protocols #67814
|
||||
pkg net/http, type Transport struct, HTTP2 *HTTP2Config #67813
|
||||
pkg net/http, type Transport struct, Protocols *Protocols #67814
|
||||
pkg net/netip, method (Addr) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg net/netip, method (Addr) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg net/netip, method (AddrPort) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg net/netip, method (AddrPort) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg net/netip, method (Prefix) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg net/netip, method (Prefix) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg net/url, method (*URL) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg os, func OpenInRoot(string, string) (*File, error) #67002
|
||||
pkg os, func OpenRoot(string) (*Root, error) #67002
|
||||
pkg os, method (*Root) Close() error #67002
|
||||
pkg os, method (*Root) Create(string) (*File, error) #67002
|
||||
pkg os, method (*Root) FS() fs.FS #67002
|
||||
pkg os, method (*Root) Lstat(string) (fs.FileInfo, error) #67002
|
||||
pkg os, method (*Root) Mkdir(string, fs.FileMode) error #67002
|
||||
pkg os, method (*Root) Name() string #67002
|
||||
pkg os, method (*Root) Open(string) (*File, error) #67002
|
||||
pkg os, method (*Root) OpenFile(string, int, fs.FileMode) (*File, error) #67002
|
||||
pkg os, method (*Root) OpenRoot(string) (*Root, error) #67002
|
||||
pkg os, method (*Root) Remove(string) error #67002
|
||||
pkg os, method (*Root) Stat(string) (fs.FileInfo, error) #67002
|
||||
pkg os, type Root struct #67002
|
||||
pkg regexp, method (*Regexp) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg runtime, func AddCleanup[$0 interface{}, $1 interface{}](*$0, func($1), $1) Cleanup #67535
|
||||
pkg runtime, func GOROOT //deprecated #51473
|
||||
pkg runtime, method (Cleanup) Stop() #67535
|
||||
pkg runtime, type Cleanup struct #67535
|
||||
pkg strings, func FieldsFuncSeq(string, func(int32) bool) iter.Seq[string] #61901
|
||||
pkg strings, func FieldsSeq(string) iter.Seq[string] #61901
|
||||
pkg strings, func Lines(string) iter.Seq[string] #61901
|
||||
pkg strings, func SplitAfterSeq(string, string) iter.Seq[string] #61901
|
||||
pkg strings, func SplitSeq(string, string) iter.Seq[string] #61901
|
||||
pkg testing, method (*B) Chdir(string) #62516
|
||||
pkg testing, method (*B) Context() context.Context #36532
|
||||
pkg testing, method (*B) Loop() bool #61515
|
||||
pkg testing, method (*F) Chdir(string) #62516
|
||||
pkg testing, method (*F) Context() context.Context #36532
|
||||
pkg testing, method (*T) Chdir(string) #62516
|
||||
pkg testing, method (*T) Context() context.Context #36532
|
||||
pkg testing, type TB interface, Chdir(string) #62516
|
||||
pkg testing, type TB interface, Context() context.Context #36532
|
||||
pkg time, method (Time) AppendBinary([]uint8) ([]uint8, error) #62384
|
||||
pkg time, method (Time) AppendText([]uint8) ([]uint8, error) #62384
|
||||
pkg weak, func Make[$0 interface{}](*$0) Pointer[$0] #67552
|
||||
pkg weak, method (Pointer[$0]) Value() *$0 #67552
|
||||
pkg weak, type Pointer[$0 interface{}] struct #67552
|
||||
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.22
|
||||
parent-branch: master
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# Release Notes
|
||||
|
||||
The `initial` and `next` subdirectories of this directory are for release notes.
|
||||
|
||||
## For developers
|
||||
|
||||
Release notes should be added to `next` by editing existing files or creating
|
||||
new files. **Do not add RELNOTE=yes comments in CLs.** Instead, add a file to
|
||||
the CL (or ask the author to do so).
|
||||
|
||||
At the end of the development cycle, the files will be merged by being
|
||||
concatenated in sorted order by pathname. Files in the directory matching the
|
||||
glob "*stdlib/*minor" are treated specially. They should be in subdirectories
|
||||
corresponding to standard library package paths, and headings for those package
|
||||
paths will be generated automatically.
|
||||
|
||||
Files in this repo's `api/next` directory must have corresponding files in
|
||||
`doc/next/*stdlib/*minor`.
|
||||
The files should be in the subdirectory for the package with the new
|
||||
API, and should be named after the issue number of the API proposal.
|
||||
For example, if the directory `6-stdlib/99-minor` is present,
|
||||
then an `api/next` file with the line
|
||||
|
||||
pkg net/http, function F #12345
|
||||
|
||||
should have a corresponding file named `doc/next/6-stdlib/99-minor/net/http/12345.md`.
|
||||
At a minimum, that file should contain either a full sentence or a TODO,
|
||||
ideally referring to a person with the responsibility to complete the note.
|
||||
|
||||
If your CL addresses an accepted proposal, mention the proposal issue number in
|
||||
your release note in the form `/issue/NUMBER`. A link to the issue in the text
|
||||
will have this form (see below). If you don't want to mention the issue in the
|
||||
text, add it as a comment:
|
||||
```
|
||||
<!-- go.dev/issue/12345 -->
|
||||
```
|
||||
If an accepted proposal is mentioned in a CL but not in the release notes, it will be
|
||||
flagged as a TODO by the automated tooling. That is true even for proposals that add API.
|
||||
|
||||
Use the following forms in your markdown:
|
||||
|
||||
[http.Request] # symbol documentation; auto-linked as in Go doc strings
|
||||
[Request] # short form, for symbols in the package being documented
|
||||
[net/http] # package link
|
||||
[#12345](/issue/12345) # GitHub issues
|
||||
[CL 6789](/cl/6789) # Gerrit changelists
|
||||
|
||||
To preview `next` content in merged form using a local instance of the website, run:
|
||||
|
||||
```
|
||||
go run golang.org/x/website/cmd/golangorg@latest -goroot=..
|
||||
```
|
||||
|
||||
Then open http://localhost:6060/doc/next. Refresh the page to see your latest edits.
|
||||
|
||||
## For the release team
|
||||
|
||||
The `relnote` tool, at `golang.org/x/build/cmd/relnote`, operates on the files
|
||||
in `doc/next`.
|
||||
|
||||
As a release cycle nears completion, run `relnote todo` to get a list of
|
||||
unfinished release note work.
|
||||
|
||||
To prepare the release notes for a release, run `relnote generate`.
|
||||
That will merge the `.md` files in `next` into a single file.
|
||||
Atomically (as close to it as possible) add that file to `_content/doc` directory
|
||||
of the website repository and remove the `doc/next` directory in this repository.
|
||||
|
||||
To begin the next release development cycle, populate the contents of `next`
|
||||
with those of `initial`. From the repo root:
|
||||
|
||||
> cd doc
|
||||
> cp -R initial/ next
|
||||
|
||||
Then edit `next/1-intro.md` to refer to the next version.
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Language version go1.17 (Oct 15, 2021)",
|
||||
"Subtitle": "Version of Oct 15, 2021",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -656,7 +656,7 @@ and are discussed in that section.
|
||||
|
||||
<p>
|
||||
Numeric constants represent exact values of arbitrary precision and do not overflow.
|
||||
Consequently, there are no constants denoting the IEEE 754 negative zero, infinity,
|
||||
Consequently, there are no constants denoting the IEEE-754 negative zero, infinity,
|
||||
and not-a-number values.
|
||||
</p>
|
||||
|
||||
@@ -882,8 +882,8 @@ int16 the set of all signed 16-bit integers (-32768 to 32767)
|
||||
int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)
|
||||
int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
|
||||
|
||||
float32 the set of all IEEE 754 32-bit floating-point numbers
|
||||
float64 the set of all IEEE 754 64-bit floating-point numbers
|
||||
float32 the set of all IEEE-754 32-bit floating-point numbers
|
||||
float64 the set of all IEEE-754 64-bit floating-point numbers
|
||||
|
||||
complex64 the set of all complex numbers with float32 real and imaginary parts
|
||||
complex128 the set of all complex numbers with float64 real and imaginary parts
|
||||
@@ -3814,7 +3814,7 @@ For floating-point and complex numbers,
|
||||
<code>+x</code> is the same as <code>x</code>,
|
||||
while <code>-x</code> is the negation of <code>x</code>.
|
||||
The result of a floating-point or complex division by zero is not specified beyond the
|
||||
IEEE 754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
|
||||
IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
|
||||
occurs is implementation-specific.
|
||||
</p>
|
||||
|
||||
@@ -3904,7 +3904,7 @@ These terms and the result of the comparisons are defined as follows:
|
||||
|
||||
<li>
|
||||
Floating-point values are comparable and ordered,
|
||||
as defined by the IEEE 754 standard.
|
||||
as defined by the IEEE-754 standard.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
@@ -4252,7 +4252,7 @@ When converting an integer or floating-point number to a floating-point type,
|
||||
or a complex number to another complex type, the result value is rounded
|
||||
to the precision specified by the destination type.
|
||||
For instance, the value of a variable <code>x</code> of type <code>float32</code>
|
||||
may be stored using additional precision beyond that of an IEEE 754 32-bit number,
|
||||
may be stored using additional precision beyond that of an IEEE-754 32-bit number,
|
||||
but float32(x) represents the result of rounding <code>x</code>'s value to
|
||||
32-bit precision. Similarly, <code>x + 0.1</code> may use more than 32 bits
|
||||
of precision, but <code>float32(x + 0.1)</code> does not.
|
||||
|
||||
1007
doc/go1.22.html
Normal file
1007
doc/go1.22.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -82,7 +82,7 @@ while still insisting that races are errors and that tools can diagnose and repo
|
||||
<p>
|
||||
The following formal definition of Go's memory model closely follows
|
||||
the approach presented by Hans-J. Boehm and Sarita V. Adve in
|
||||
“<a href="https://dl.acm.org/doi/10.1145/1375581.1375591">Foundations of the C++ Concurrency Memory Model</a>”,
|
||||
“<a href="https://www.hpl.hp.com/techreports/2008/HPL-2008-56.pdf">Foundations of the C++ Concurrency Memory Model</a>”,
|
||||
published in PLDI 2008.
|
||||
The definition of data-race-free programs and the guarantee of sequential consistency
|
||||
for race-free programs are equivalent to the ones in that work.
|
||||
@@ -98,12 +98,12 @@ which in turn are made up of memory operations.
|
||||
A <i>memory operation</i> is modeled by four details:
|
||||
</p>
|
||||
<ul>
|
||||
<li>its kind, indicating whether it is an ordinary data read, an ordinary data write,
|
||||
or a <i>synchronizing operation</i> such as an atomic data access,
|
||||
a mutex operation, or a channel operation,</li>
|
||||
<li>its location in the program,</li>
|
||||
<li>the memory location or variable being accessed, and</li>
|
||||
<li>the values read or written by the operation.</li>
|
||||
<li>its kind, indicating whether it is an ordinary data read, an ordinary data write,
|
||||
or a <i>synchronizing operation</i> such as an atomic data access,
|
||||
a mutex operation, or a channel operation,
|
||||
<li>its location in the program,
|
||||
<li>the memory location or variable being accessed, and
|
||||
<li>the values read or written by the operation.
|
||||
</ul>
|
||||
<p>
|
||||
Some memory operations are <i>read-like</i>, including read, atomic read, mutex lock, and channel receive.
|
||||
@@ -162,8 +162,8 @@ where visible means that both of the following hold:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li><i>w</i> happens before <i>r</i>.</li>
|
||||
<li><i>w</i> does not happen before any other write <i>w'</i> (to <i>x</i>) that happens before <i>r</i>.</li>
|
||||
<li><i>w</i> happens before <i>r</i>.
|
||||
<li><i>w</i> does not happen before any other write <i>w'</i> (to <i>x</i>) that happens before <i>r</i>.
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
|
||||
477
doc/go_spec.html
477
doc/go_spec.html
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Language version go1.24 (Nov 20, 2024)",
|
||||
"Subtitle": "Version of Nov 1, 2023",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -70,14 +70,6 @@ enumerations or code snippets that are not further specified. The character <cod
|
||||
language.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A link of the form [<a href="#Language_versions">Go 1.xx</a>] indicates that a described
|
||||
language feature (or some aspect of it) was changed or added with language version 1.xx and
|
||||
thus requires at minimum that language version to build.
|
||||
For details, see the <a href="#Language_versions">linked section</a>
|
||||
in the <a href="#Appendix">appendix</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="Source_code_representation">Source code representation</h2>
|
||||
|
||||
<p>
|
||||
@@ -271,8 +263,7 @@ continue for import return var
|
||||
|
||||
<p>
|
||||
The following character sequences represent <a href="#Operators">operators</a>
|
||||
(including <a href="#Assignment_statements">assignment operators</a>) and punctuation
|
||||
[<a href="#Go_1.18">Go 1.18</a>]:
|
||||
(including <a href="#Assignment_statements">assignment operators</a>) and punctuation:
|
||||
</p>
|
||||
<pre class="grammar">
|
||||
+ & += &= && == != ( )
|
||||
@@ -290,8 +281,7 @@ An integer literal is a sequence of digits representing an
|
||||
<a href="#Constants">integer constant</a>.
|
||||
An optional prefix sets a non-decimal base: <code>0b</code> or <code>0B</code>
|
||||
for binary, <code>0</code>, <code>0o</code>, or <code>0O</code> for octal,
|
||||
and <code>0x</code> or <code>0X</code> for hexadecimal
|
||||
[<a href="#Go_1.13">Go 1.13</a>].
|
||||
and <code>0x</code> or <code>0X</code> for hexadecimal.
|
||||
A single <code>0</code> is considered a decimal zero.
|
||||
In hexadecimal literals, letters <code>a</code> through <code>f</code>
|
||||
and <code>A</code> through <code>F</code> represent values 10 through 15.
|
||||
@@ -357,8 +347,7 @@ prefix, an integer part (hexadecimal digits), a radix point, a fractional part (
|
||||
and an exponent part (<code>p</code> or <code>P</code> followed by an optional sign and decimal digits).
|
||||
One of the integer part or the fractional part may be elided; the radix point may be elided as well,
|
||||
but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.)
|
||||
An exponent value exp scales the mantissa (integer and fractional part) by 2<sup>exp</sup>
|
||||
[<a href="#Go_1.13">Go 1.13</a>].
|
||||
An exponent value exp scales the mantissa (integer and fractional part) by 2<sup>exp</sup>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -422,8 +411,7 @@ It consists of an <a href="#Integer_literals">integer</a> or
|
||||
<a href="#Floating-point_literals">floating-point</a> literal
|
||||
followed by the lowercase letter <code>i</code>.
|
||||
The value of an imaginary literal is the value of the respective
|
||||
integer or floating-point literal multiplied by the imaginary unit <i>i</i>
|
||||
[<a href="#Go_1.13">Go 1.13</a>]
|
||||
integer or floating-point literal multiplied by the imaginary unit <i>i</i>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -674,7 +662,7 @@ and are discussed in that section.
|
||||
|
||||
<p>
|
||||
Numeric constants represent exact values of arbitrary precision and do not overflow.
|
||||
Consequently, there are no constants denoting the IEEE 754 negative zero, infinity,
|
||||
Consequently, there are no constants denoting the IEEE-754 negative zero, infinity,
|
||||
and not-a-number values.
|
||||
</p>
|
||||
|
||||
@@ -861,8 +849,8 @@ int16 the set of all signed 16-bit integers (-32768 to 32767)
|
||||
int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)
|
||||
int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
|
||||
|
||||
float32 the set of all IEEE 754 32-bit floating-point numbers
|
||||
float64 the set of all IEEE 754 64-bit floating-point numbers
|
||||
float32 the set of all IEEE-754 32-bit floating-point numbers
|
||||
float64 the set of all IEEE-754 64-bit floating-point numbers
|
||||
|
||||
complex64 the set of all complex numbers with float32 real and imaginary parts
|
||||
complex128 the set of all complex numbers with float64 real and imaginary parts
|
||||
@@ -1086,7 +1074,7 @@ A field declared with a type but no explicit field name is called an <i>embedded
|
||||
An embedded field must be specified as
|
||||
a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>,
|
||||
and <code>T</code> itself may not be
|
||||
a pointer type or type parameter. The unqualified type name acts as the field name.
|
||||
a pointer type. The unqualified type name acts as the field name.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -1127,7 +1115,7 @@ of a struct except that they cannot be used as field names in
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given a struct type <code>S</code> and a type name
|
||||
Given a struct type <code>S</code> and a <a href="#Types">named type</a>
|
||||
<code>T</code>, promoted methods are included in the method set of the struct as follows:
|
||||
</p>
|
||||
<ul>
|
||||
@@ -1352,7 +1340,6 @@ interface{}
|
||||
|
||||
<p>
|
||||
For convenience, the predeclared type <code>any</code> is an alias for the empty interface.
|
||||
[<a href="#Go_1.18">Go 1.18</a>]
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -1388,15 +1375,13 @@ as the <code>File</code> interface.
|
||||
In a slightly more general form
|
||||
an interface <code>T</code> may use a (possibly qualified) interface type
|
||||
name <code>E</code> as an interface element. This is called
|
||||
<i>embedding</i> interface <code>E</code> in <code>T</code>
|
||||
[<a href="#Go_1.14">Go 1.14</a>].
|
||||
<i>embedding</i> interface <code>E</code> in <code>T</code>.
|
||||
The type set of <code>T</code> is the <i>intersection</i> of the type sets
|
||||
defined by <code>T</code>'s explicitly declared methods and the type sets
|
||||
of <code>T</code>’s embedded interfaces.
|
||||
In other words, the type set of <code>T</code> is the set of all types that implement all the
|
||||
explicitly declared methods of <code>T</code> and also all the methods of
|
||||
<code>E</code>
|
||||
[<a href="#Go_1.18">Go 1.18</a>].
|
||||
<code>E</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -1435,8 +1420,7 @@ type ReadCloser interface {
|
||||
<p>
|
||||
In their most general form, an interface element may also be an arbitrary type term
|
||||
<code>T</code>, or a term of the form <code>~T</code> specifying the underlying type <code>T</code>,
|
||||
or a union of terms <code>t<sub>1</sub>|t<sub>2</sub>|…|t<sub>n</sub></code>
|
||||
[<a href="#Go_1.18">Go 1.18</a>].
|
||||
or a union of terms <code>t<sub>1</sub>|t<sub>2</sub>|…|t<sub>n</sub></code>.
|
||||
Together with method specifications, these elements enable the precise
|
||||
definition of an interface's type set as follows:
|
||||
</p>
|
||||
@@ -1682,7 +1666,6 @@ maps grow to accommodate the number of items
|
||||
stored in them, with the exception of <code>nil</code> maps.
|
||||
A <code>nil</code> map is equivalent to an empty map except that no elements
|
||||
may be added.
|
||||
</p>
|
||||
|
||||
<h3 id="Channel_types">Channel types</h3>
|
||||
|
||||
@@ -1927,8 +1910,8 @@ components have identical types. In detail:
|
||||
<li>Two slice types are identical if they have identical element types.</li>
|
||||
|
||||
<li>Two struct types are identical if they have the same sequence of fields,
|
||||
and if corresponding pairs of fields have the same names, identical types,
|
||||
and identical tags, and are either both embedded or both not embedded.
|
||||
and if corresponding fields have the same names, and identical types,
|
||||
and identical tags.
|
||||
<a href="#Exported_identifiers">Non-exported</a> field names from different
|
||||
packages are always different.</li>
|
||||
|
||||
@@ -2320,9 +2303,7 @@ as an <a href="#Operands">operand</a>, and in <a href="#Assignment_statements">a
|
||||
|
||||
<p>
|
||||
The following identifiers are implicitly declared in the
|
||||
<a href="#Blocks">universe block</a>
|
||||
[<a href="#Go_1.18">Go 1.18</a>]
|
||||
[<a href="#Go_1.21">Go 1.21</a>]:
|
||||
<a href="#Blocks">universe block</a>:
|
||||
</p>
|
||||
<pre class="grammar">
|
||||
Types:
|
||||
@@ -2506,17 +2487,16 @@ TypeSpec = AliasDecl | TypeDef .
|
||||
<h4 id="Alias_declarations">Alias declarations</h4>
|
||||
|
||||
<p>
|
||||
An alias declaration binds an identifier to the given type
|
||||
[<a href="#Go_1.9">Go 1.9</a>].
|
||||
An alias declaration binds an identifier to the given type.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
AliasDecl = identifier [ TypeParameters ] "=" Type .
|
||||
AliasDecl = identifier "=" Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Within the <a href="#Declarations_and_scope">scope</a> of
|
||||
the identifier, it serves as an <i>alias</i> for the given type.
|
||||
the identifier, it serves as an <i>alias</i> for the type.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -2526,24 +2506,6 @@ type (
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the alias declaration specifies <a href="#Type_parameter_declarations">type parameters</a>
|
||||
[<a href="#Go_1.24">Go 1.24</a>], the type name denotes a <i>generic alias</i>.
|
||||
Generic aliases must be <a href="#Instantiations">instantiated</a> when they
|
||||
are used.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type set[P comparable] = map[P]bool
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In an alias declaration the given type cannot be a type parameter.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type A[P any] = P // illegal: P is a type parameter
|
||||
</pre>
|
||||
|
||||
<h4 id="Type_definitions">Type definitions</h4>
|
||||
|
||||
@@ -2674,8 +2636,7 @@ func (l *List[T]) Len() int { … }
|
||||
A type parameter list declares the <i>type parameters</i> of a generic function or type declaration.
|
||||
The type parameter list looks like an ordinary <a href="#Function_types">function parameter list</a>
|
||||
except that the type parameter names must all be present and the list is enclosed
|
||||
in square brackets rather than parentheses
|
||||
[<a href="#Go_1.18">Go 1.18</a>].
|
||||
in square brackets rather than parentheses.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -2758,8 +2719,7 @@ type T6[P int] struct{ f *T6[P] } // ok: reference to T6 is not in type para
|
||||
<p>
|
||||
A <i>type constraint</i> is an <a href="#Interface_types">interface</a> that defines the
|
||||
set of permissible type arguments for the respective type parameter and controls the
|
||||
operations supported by values of that type parameter
|
||||
[<a href="#Go_1.18">Go 1.18</a>].
|
||||
operations supported by values of that type parameter.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -2789,8 +2749,7 @@ other interfaces based on their type sets. But this should get us going for now.
|
||||
The <a href="#Predeclared_identifiers">predeclared</a>
|
||||
<a href="#Interface_types">interface type</a> <code>comparable</code>
|
||||
denotes the set of all non-interface types that are
|
||||
<a href="#Comparison_operators">strictly comparable</a>
|
||||
[<a href="#Go_1.18">Go 1.18</a>].
|
||||
<a href="#Comparison_operators">strictly comparable</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -2823,8 +2782,7 @@ if <code>T</code> is an element of the type set defined by <code>C</code>; i.e.,
|
||||
if <code>T</code> <a href="#Implementing_an_interface">implements</a> <code>C</code>.
|
||||
As an exception, a <a href="#Comparison_operators">strictly comparable</a>
|
||||
type constraint may also be satisfied by a <a href="#Comparison_operators">comparable</a>
|
||||
(not necessarily strictly comparable) type argument
|
||||
[<a href="#Go_1.20">Go 1.20</a>].
|
||||
(not necessarily strictly comparable) type argument.
|
||||
More precisely:
|
||||
</p>
|
||||
|
||||
@@ -3093,7 +3051,7 @@ to the base type <code>Point</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the receiver base type is a <a href="#Type_definitions">generic type</a>, the
|
||||
If the receiver base type is a <a href="#Type_declarations">generic type</a>, the
|
||||
receiver specification must declare corresponding type parameters for the method
|
||||
to use. This makes the receiver type parameters available to the method.
|
||||
Syntactically, this type parameter declaration looks like an
|
||||
@@ -3117,22 +3075,6 @@ func (p Pair[A, B]) Swap() Pair[B, A] { … } // receiver declares A, B
|
||||
func (p Pair[First, _]) First() First { … } // receiver declares First, corresponds to A in Pair
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the receiver type is denoted by (a pointer to) an <a href="#Alias_declarations">alias</a>,
|
||||
the alias must not be generic and it must not denote an instantiated generic type, neither
|
||||
directly nor indirectly via another alias, and irrespective of pointer indirections.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type GPoint[P any] = Point
|
||||
type HPoint = *GPoint[int]
|
||||
type IPair = Pair[int, int]
|
||||
|
||||
func (*GPoint[P]) Draw(P) { … } // illegal: alias must not be generic
|
||||
func (HPoint) Draw(P) { … } // illegal: alias must not denote instantiated type GPoint[int]
|
||||
func (*IPair) Second() int { … } // illegal: alias must not denote instantiated type Pair[int, int]
|
||||
</pre>
|
||||
|
||||
<h2 id="Expressions">Expressions</h2>
|
||||
|
||||
<p>
|
||||
@@ -4364,7 +4306,7 @@ with the same underlying array.
|
||||
|
||||
<p>
|
||||
A generic function or type is <i>instantiated</i> by substituting <i>type arguments</i>
|
||||
for the type parameters [<a href="#Go_1.18">Go 1.18</a>].
|
||||
for the type parameters.
|
||||
Instantiation proceeds in two steps:
|
||||
</p>
|
||||
|
||||
@@ -4817,7 +4759,6 @@ to the type of the other operand.
|
||||
|
||||
<p>
|
||||
The right operand in a shift expression must have <a href="#Numeric_types">integer type</a>
|
||||
[<a href="#Go_1.13">Go 1.13</a>]
|
||||
or be an untyped constant <a href="#Representability">representable</a> by a
|
||||
value of type <code>uint</code>.
|
||||
If the left operand of a non-constant shift expression is an untyped constant,
|
||||
@@ -5056,7 +4997,7 @@ For floating-point and complex numbers,
|
||||
<code>+x</code> is the same as <code>x</code>,
|
||||
while <code>-x</code> is the negation of <code>x</code>.
|
||||
The result of a floating-point or complex division by zero is not specified beyond the
|
||||
IEEE 754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
|
||||
IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
|
||||
occurs is implementation-specific.
|
||||
</p>
|
||||
|
||||
@@ -5146,7 +5087,7 @@ These terms and the result of the comparisons are defined as follows:
|
||||
|
||||
<li>
|
||||
Floating-point types are comparable and ordered.
|
||||
Two floating-point values are compared as defined by the IEEE 754 standard.
|
||||
Two floating-point values are compared as defined by the IEEE-754 standard.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
@@ -5485,8 +5426,7 @@ in any of these cases:
|
||||
<code>x</code> is a string and <code>T</code> is a slice of bytes or runes.
|
||||
</li>
|
||||
<li>
|
||||
<code>x</code> is a slice, <code>T</code> is an array [<a href="#Go_1.20">Go 1.20</a>]
|
||||
or a pointer to an array [<a href="#Go_1.17">Go 1.17</a>],
|
||||
<code>x</code> is a slice, <code>T</code> is an array or a pointer to an array,
|
||||
and the slice and array types have <a href="#Type_identity">identical</a> element types.
|
||||
</li>
|
||||
</ul>
|
||||
@@ -5576,7 +5516,7 @@ When converting an integer or floating-point number to a floating-point type,
|
||||
or a <a href="#Numeric_types">complex number</a> to another complex type, the result value is rounded
|
||||
to the precision specified by the destination type.
|
||||
For instance, the value of a variable <code>x</code> of type <code>float32</code>
|
||||
may be stored using additional precision beyond that of an IEEE 754 32-bit number,
|
||||
may be stored using additional precision beyond that of an IEEE-754 32-bit number,
|
||||
but float32(x) represents the result of rounding <code>x</code>'s value to
|
||||
32-bit precision. Similarly, <code>x + 0.1</code> may use more than 32 bits
|
||||
of precision, but <code>float32(x + 0.1)</code> does not.
|
||||
@@ -6576,6 +6516,7 @@ additionally it may specify an <i>init</i>
|
||||
and a <i>post</i> statement, such as an assignment,
|
||||
an increment or decrement statement. The init statement may be a
|
||||
<a href="#Short_variable_declarations">short variable declaration</a>, but the post statement must not.
|
||||
Variables declared by the init statement are re-used in each iteration.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
@@ -6607,55 +6548,12 @@ for cond { S() } is the same as for ; cond ; { S() }
|
||||
for { S() } is the same as for true { S() }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Each iteration has its own separate declared variable (or variables)
|
||||
[<a href="#Go_1.22">Go 1.22</a>].
|
||||
The variable used by the first iteration is declared by the init statement.
|
||||
The variable used by each subsequent iteration is declared implicitly before
|
||||
executing the post statement and initialized to the value of the previous
|
||||
iteration's variable at that moment.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var prints []func()
|
||||
for i := 0; i < 5; i++ {
|
||||
prints = append(prints, func() { println(i) })
|
||||
i++
|
||||
}
|
||||
for _, p := range prints {
|
||||
p()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
prints
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
1
|
||||
3
|
||||
5
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Prior to [<a href="#Go_1.22">Go 1.22</a>], iterations share one set of variables
|
||||
instead of having their own separate variables.
|
||||
In that case, the example above prints
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
6
|
||||
6
|
||||
6
|
||||
</pre>
|
||||
|
||||
<h4 id="For_range">For statements with <code>range</code> clause</h4>
|
||||
|
||||
<p>
|
||||
A "for" statement with a "range" clause
|
||||
iterates through all entries of an array, slice, string or map, values received on
|
||||
a channel, integer values from zero to an upper limit [<a href="#Go_1.22">Go 1.22</a>],
|
||||
or values passed to an iterator function's yield function [<a href="#Go_1.23">Go 1.23</a>].
|
||||
a channel, or integer values from zero to an upper limit.
|
||||
For each entry it assigns <i>iteration values</i>
|
||||
to corresponding <i>iteration variables</i> if present and then executes the block.
|
||||
</p>
|
||||
@@ -6668,23 +6566,19 @@ RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
|
||||
The expression on the right in the "range" clause is called the <i>range expression</i>,
|
||||
its <a href="#Core_types">core type</a> must be
|
||||
an array, pointer to an array, slice, string, map, channel permitting
|
||||
<a href="#Receive_operator">receive operations</a>, an integer, or
|
||||
a function with specific signature (see below).
|
||||
<a href="#Receive_operator">receive operations</a>, or an integer.
|
||||
As with an assignment, if present the operands on the left must be
|
||||
<a href="#Address_operators">addressable</a> or map index expressions; they
|
||||
denote the iteration variables.
|
||||
If the range expression is a function, the maximum number of iteration variables depends on
|
||||
the function signature.
|
||||
If the range expression is a channel or integer, at most one iteration variable is permitted;
|
||||
otherwise there may be up to two.
|
||||
denote the iteration variables. If the range expression is a channel or integer,
|
||||
at most one iteration variable is permitted, otherwise there may be up to two.
|
||||
If the last iteration variable is the <a href="#Blank_identifier">blank identifier</a>,
|
||||
the range clause is equivalent to the same clause without that identifier.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The range expression <code>x</code> is evaluated before beginning the loop,
|
||||
with one exception: if at most one iteration variable is present and <code>x</code> or
|
||||
<a href="#Length_and_capacity"><code>len(x)</code></a> is <a href="#Constants">constant</a>,
|
||||
The range expression <code>x</code> is evaluated once before beginning the loop,
|
||||
with one exception: if at most one iteration variable is present and
|
||||
<code>len(x)</code> is <a href="#Length_and_capacity">constant</a>,
|
||||
the range expression is not evaluated.
|
||||
</p>
|
||||
|
||||
@@ -6695,16 +6589,13 @@ if the respective iteration variables are present:
|
||||
</p>
|
||||
|
||||
<pre class="grammar">
|
||||
Range expression 1st value 2nd value
|
||||
Range expression 1st value 2nd value
|
||||
|
||||
array or slice a [n]E, *[n]E, or []E index i int a[i] E
|
||||
string s string type index i int see below rune
|
||||
map m map[K]V key k K m[k] V
|
||||
channel c chan E, <-chan E element e E
|
||||
integer value n integer type, or untyped int value i see below
|
||||
function, 0 values f func(func() bool)
|
||||
function, 1 value f func(func(V) bool) value v V
|
||||
function, 2 values f func(func(K, V) bool) key k K v V
|
||||
array or slice a [n]E, *[n]E, or []E index i int a[i] E
|
||||
string s string type index i int see below rune
|
||||
map m map[K]V key k K m[k] V
|
||||
channel c chan E, <-chan E element e E
|
||||
integer n integer type I value i I
|
||||
</pre>
|
||||
|
||||
<ol>
|
||||
@@ -6745,51 +6636,26 @@ is <code>nil</code>, the range expression blocks forever.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
For an integer value <code>n</code>, where <code>n</code> is of <a href="#Numeric_types">integer type</a>
|
||||
or an untyped <a href="#Constants">integer constant</a>, the iteration values 0 through <code>n-1</code>
|
||||
are produced in increasing order.
|
||||
If <code>n</code> is of integer type, the iteration values have that same type.
|
||||
Otherwise, the type of <code>n</code> is determined as if it were assigned to the
|
||||
iteration variable.
|
||||
Specifically:
|
||||
if the iteration variable is preexisting, the type of the iteration values is the type of the iteration
|
||||
variable, which must be of integer type.
|
||||
Otherwise, if the iteration variable is declared by the "range" clause or is absent,
|
||||
the type of the iteration values is the <a href="#Constants">default type</a> for <code>n</code>.
|
||||
For an integer value <code>n</code>, the iteration values 0 through <code>n-1</code>
|
||||
are produced in increasing order, with the same type as <code>n</code>.
|
||||
If <code>n</code> <= 0, the loop does not run any iterations.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
For a function <code>f</code>, the iteration proceeds by calling <code>f</code>
|
||||
with a new, synthesized <code>yield</code> function as its argument.
|
||||
If <code>yield</code> is called before <code>f</code> returns,
|
||||
the arguments to <code>yield</code> become the iteration values
|
||||
for executing the loop body once.
|
||||
After each successive loop iteration, <code>yield</code> returns true
|
||||
and may be called again to continue the loop.
|
||||
As long as the loop body does not terminate, the "range" clause will continue
|
||||
to generate iteration values this way for each <code>yield</code> call until
|
||||
<code>f</code> returns.
|
||||
If the loop body terminates (such as by a <code>break</code> statement),
|
||||
<code>yield</code> returns false and must not be called again.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
The iteration values are assigned to the respective
|
||||
iteration variables as in an <a href="#Assignment_statements">assignment statement</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The iteration variables may be declared by the "range" clause using a form of
|
||||
<a href="#Short_variable_declarations">short variable declaration</a>
|
||||
(<code>:=</code>).
|
||||
In this case their <a href="#Declarations_and_scope">scope</a> is the block of the "for" statement
|
||||
and each iteration has its own new variables [<a href="#Go_1.22">Go 1.22</a>]
|
||||
(see also <a href="#For_clause">"for" statements with a ForClause</a>).
|
||||
The variables have the types of their respective iteration values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the iteration variables are not explicitly declared by the "range" clause,
|
||||
they must be preexisting.
|
||||
In this case, the iteration values are assigned to the respective variables
|
||||
as in an <a href="#Assignment_statements">assignment statement</a>.
|
||||
In this case their types are set to the types of the respective iteration values
|
||||
and their <a href="#Declarations_and_scope">scope</a> is the block of the "for"
|
||||
statement; they are re-used in each iteration.
|
||||
If the iteration variables are declared outside the "for" statement,
|
||||
after execution their values will be those of the last iteration.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -6832,53 +6698,6 @@ for i := range 10 {
|
||||
// type of i is int (default type for untyped constant 10)
|
||||
f(i)
|
||||
}
|
||||
|
||||
// invalid: 256 cannot be assigned to uint8
|
||||
var u uint8
|
||||
for u = range 256 {
|
||||
}
|
||||
|
||||
// invalid: 1e3 is a floating-point constant
|
||||
for range 1e3 {
|
||||
}
|
||||
|
||||
// fibo generates the Fibonacci sequence
|
||||
fibo := func(yield func(x int) bool) {
|
||||
f0, f1 := 0, 1
|
||||
for yield(f0) {
|
||||
f0, f1 = f1, f0+f1
|
||||
}
|
||||
}
|
||||
|
||||
// print the Fibonacci numbers below 1000:
|
||||
for x := range fibo {
|
||||
if x >= 1000 {
|
||||
break
|
||||
}
|
||||
fmt.Printf("%d ", x)
|
||||
}
|
||||
// output: 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
|
||||
|
||||
// iteration support for a recursive tree data structure
|
||||
type Tree[K cmp.Ordered, V any] struct {
|
||||
left, right *Tree[K, V]
|
||||
key K
|
||||
value V
|
||||
}
|
||||
|
||||
func (t *Tree[K, V]) walk(yield func(key K, val V) bool) bool {
|
||||
return t == nil || t.left.walk(yield) && yield(t.key, t.value) && t.right.walk(yield)
|
||||
}
|
||||
|
||||
func (t *Tree[K, V]) Walk(yield func(key K, val V) bool) {
|
||||
t.walk(yield)
|
||||
}
|
||||
|
||||
// walk tree t in-order
|
||||
var t Tree[string, int]
|
||||
for k, v := range t.Walk {
|
||||
// process k, v
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -7402,7 +7221,7 @@ The number of elements copied is the minimum of
|
||||
<code>len(src)</code> and <code>len(dst)</code>.
|
||||
As a special case, if the destination's core type is <code>[]byte</code>,
|
||||
<code>copy</code> also accepts a source argument with core type
|
||||
<a href="#Core_types"><code>bytestring</code></a>.
|
||||
</a> <a href="#Core_types"><code>bytestring</code></a>.
|
||||
This form copies the bytes from the byte slice or string into the byte slice.
|
||||
</p>
|
||||
|
||||
@@ -7430,8 +7249,7 @@ n3 := copy(b, "Hello, World!") // n3 == 5, b is []byte("Hello")
|
||||
<p>
|
||||
The built-in function <code>clear</code> takes an argument of <a href="#Map_types">map</a>,
|
||||
<a href="#Slice_types">slice</a>, or <a href="#Type_parameter_declarations">type parameter</a> type,
|
||||
and deletes or zeroes out all elements
|
||||
[<a href="#Go_1.21">Go 1.21</a>].
|
||||
and deletes or zeroes out all elements.
|
||||
</p>
|
||||
|
||||
<pre class="grammar">
|
||||
@@ -7698,8 +7516,7 @@ The precise behavior is implementation-dependent.
|
||||
The built-in functions <code>min</code> and <code>max</code> compute the
|
||||
smallest—or largest, respectively—value of a fixed number of
|
||||
arguments of <a href="#Comparison_operators">ordered types</a>.
|
||||
There must be at least one argument
|
||||
[<a href="#Go_1.21">Go 1.21</a>].
|
||||
There must be at least one argument.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -8415,8 +8232,8 @@ of if the general conversion rules take care of this.
|
||||
<p>
|
||||
A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
|
||||
value may not be <a href="#Address_operators">dereferenced</a>.
|
||||
Any pointer or value of <a href="#Core_types">core type</a> <code>uintptr</code> can be
|
||||
<a href="#Conversions">converted</a> to a type of core type <code>Pointer</code> and vice versa.
|
||||
Any pointer or value of <a href="#Underlying_types">underlying type</a> <code>uintptr</code> can be
|
||||
<a href="#Conversions">converted</a> to a type of underlying type <code>Pointer</code> and vice versa.
|
||||
The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
|
||||
</p>
|
||||
|
||||
@@ -8427,10 +8244,6 @@ bits = *(*uint64)(unsafe.Pointer(&f))
|
||||
type ptr unsafe.Pointer
|
||||
bits = *(*uint64)(ptr(&f))
|
||||
|
||||
func f[P ~*B, B any](p P) uintptr {
|
||||
return uintptr(unsafe.Pointer(p))
|
||||
}
|
||||
|
||||
var p ptr = nil
|
||||
</pre>
|
||||
|
||||
@@ -8479,8 +8292,7 @@ of constant size.
|
||||
|
||||
<p>
|
||||
The function <code>Add</code> adds <code>len</code> to <code>ptr</code>
|
||||
and returns the updated pointer <code>unsafe.Pointer(uintptr(ptr) + uintptr(len))</code>
|
||||
[<a href="#Go_1.17">Go 1.17</a>].
|
||||
and returns the updated pointer <code>unsafe.Pointer(uintptr(ptr) + uintptr(len))</code>.
|
||||
The <code>len</code> argument must be of <a href="#Numeric_types">integer type</a> or an untyped <a href="#Constants">constant</a>.
|
||||
A constant <code>len</code> argument must be <a href="#Representability">representable</a> by a value of type <code>int</code>;
|
||||
if it is an untyped constant it is given type <code>int</code>.
|
||||
@@ -8500,8 +8312,7 @@ and whose length and capacity are <code>len</code>.
|
||||
<p>
|
||||
except that, as a special case, if <code>ptr</code>
|
||||
is <code>nil</code> and <code>len</code> is zero,
|
||||
<code>Slice</code> returns <code>nil</code>
|
||||
[<a href="#Go_1.17">Go 1.17</a>].
|
||||
<code>Slice</code> returns <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -8510,16 +8321,14 @@ A constant <code>len</code> argument must be non-negative and <a href="#Represen
|
||||
if it is an untyped constant it is given type <code>int</code>.
|
||||
At run time, if <code>len</code> is negative,
|
||||
or if <code>ptr</code> is <code>nil</code> and <code>len</code> is not zero,
|
||||
a <a href="#Run_time_panics">run-time panic</a> occurs
|
||||
[<a href="#Go_1.17">Go 1.17</a>].
|
||||
a <a href="#Run_time_panics">run-time panic</a> occurs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function <code>SliceData</code> returns a pointer to the underlying array of the <code>slice</code> argument.
|
||||
If the slice's capacity <code>cap(slice)</code> is not zero, that pointer is <code>&slice[:1][0]</code>.
|
||||
If <code>slice</code> is <code>nil</code>, the result is <code>nil</code>.
|
||||
Otherwise it is a non-<code>nil</code> pointer to an unspecified memory address
|
||||
[<a href="#Go_1.20">Go 1.20</a>].
|
||||
Otherwise it is a non-<code>nil</code> pointer to an unspecified memory address.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -8528,14 +8337,12 @@ The function <code>String</code> returns a <code>string</code> value whose under
|
||||
The same requirements apply to the <code>ptr</code> and <code>len</code> argument as in the function
|
||||
<code>Slice</code>. If <code>len</code> is zero, the result is the empty string <code>""</code>.
|
||||
Since Go strings are immutable, the bytes passed to <code>String</code> must not be modified afterwards.
|
||||
[<a href="#Go_1.20">Go 1.20</a>]
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The function <code>StringData</code> returns a pointer to the underlying bytes of the <code>str</code> argument.
|
||||
For an empty string the return value is unspecified, and may be <code>nil</code>.
|
||||
Since Go strings are immutable, the bytes returned by <code>StringData</code> must not be modified
|
||||
[<a href="#Go_1.20">Go 1.20</a>].
|
||||
Since Go strings are immutable, the bytes returned by <code>StringData</code> must not be modified.
|
||||
</p>
|
||||
|
||||
<h3 id="Size_and_alignment_guarantees">Size and alignment guarantees</h3>
|
||||
@@ -8576,160 +8383,6 @@ A struct or array type has size zero if it contains no fields (or elements, resp
|
||||
|
||||
<h2 id="Appendix">Appendix</h2>
|
||||
|
||||
<h3 id="Language_versions">Language versions</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/doc/go1compat">Go 1 compatibility guarantee</a> ensures that
|
||||
programs written to the Go 1 specification will continue to compile and run
|
||||
correctly, unchanged, over the lifetime of that specification.
|
||||
More generally, as adjustments are made and features added to the language,
|
||||
the compatibility guarantee ensures that a Go program that works with a
|
||||
specific Go language version will continue to work with any subsequent version.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For instance, the ability to use the prefix <code>0b</code> for binary
|
||||
integer literals was introduced with Go 1.13, indicated
|
||||
by [<a href="#Go_1.13">Go 1.13</a>] in the section on
|
||||
<a href="#Integer_literals">integer literals</a>.
|
||||
Source code containing an integer literal such as <code>0b1011</code>
|
||||
will be rejected if the implied or required language version used by
|
||||
the compiler is older than Go 1.13.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following table describes the minimum language version required for
|
||||
features introduced after Go 1.
|
||||
</p>
|
||||
|
||||
<h4 id="Go_1.9">Go 1.9</h4>
|
||||
<ul>
|
||||
<li>
|
||||
An <a href="#Alias_declarations">alias declaration</a> may be used to declare an alias name for a type.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.13">Go 1.13</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#Integer_literals">Integer literals</a> may use the prefixes <code>0b</code>, <code>0B</code>, <code>0o</code>,
|
||||
and <code>0O</code> for binary, and octal literals, respectively.
|
||||
</li>
|
||||
<li>
|
||||
Hexadecimal <a href="#Floating-point_literals">floating-point literals</a> may be written using the prefixes
|
||||
<code>0x</code> and <code>0X</code>.
|
||||
</li>
|
||||
<li>
|
||||
The <a href="#Imaginary_literals">imaginary suffix</a> <code>i</code> may be used with any (binary, decimal, hexadecimal)
|
||||
integer or floating-point literal, not just decimal literals.
|
||||
</li>
|
||||
<li>
|
||||
The digits of any number literal may be <a href="#Integer_literals">separated</a> (grouped)
|
||||
using underscores <code>_</code>.
|
||||
</li>
|
||||
<li>
|
||||
The shift count in a <a href="#Operators">shift operation</a> may be a signed integer type.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.14">Go 1.14</h4>
|
||||
<ul>
|
||||
<li>
|
||||
Emdedding a method more than once through different <a href="#Embedded_interfaces">embedded interfaces</a>
|
||||
is not an error.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.17">Go 1.17</h4>
|
||||
<ul>
|
||||
<li>
|
||||
A slice may be <a href="#Conversions">converted</a> to an array pointer if the slice and array element
|
||||
types match, and the array is not longer than the slice.
|
||||
</li>
|
||||
<li>
|
||||
The built-in <a href="#Package_unsafe">package <code>unsafe</code></a> includes the new functions
|
||||
<code>Add</code> and <code>Slice</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.18">Go 1.18</h4>
|
||||
<p>
|
||||
The 1.18 release adds polymorphic functions and types ("generics") to the language.
|
||||
Specifically:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
The set of <a href="#Operators_and_punctuation">operators and punctuation</a> includes the new token <code>~</code>.
|
||||
</li>
|
||||
<li>
|
||||
Function and type declarations may declare <a href="#Type_parameter_declarations">type parameters</a>.
|
||||
</li>
|
||||
<li>
|
||||
Interface types may <a href="#General_interfaces">embed arbitrary types</a> (not just type names of interfaces)
|
||||
as well as union and <code>~T</code> type elements.
|
||||
</li>
|
||||
<li>
|
||||
The set of <a href="#Predeclared_identifiers">predeclared</a> types includes the new types
|
||||
<code>any</code> and <code>comparable</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.20">Go 1.20</h4>
|
||||
<ul>
|
||||
<li>
|
||||
A slice may be <a href="#Conversions">converted</a> to an array if the slice and array element
|
||||
types match and the array is not longer than the slice.
|
||||
</li>
|
||||
<li>
|
||||
The built-in <a href="#Package_unsafe">package <code>unsafe</code></a> includes the new functions
|
||||
<code>SliceData</code>, <code>String</code>, and <code>StringData</code>.
|
||||
</li>
|
||||
<li>
|
||||
<a href="#Comparison_operators">Comparable types</a> (such as ordinary interfaces) may satisfy
|
||||
<code>comparable</code> constraints, even if the type arguments are not strictly comparable.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.21">Go 1.21</h4>
|
||||
<ul>
|
||||
<li>
|
||||
The set of <a href="#Predeclared_identifiers">predeclared</a> functions includes the new functions
|
||||
<code>min</code>, <code>max</code>, and <code>clear</code>.
|
||||
</li>
|
||||
<li>
|
||||
<a href="#Type_inference">Type inference</a> uses the types of interface methods for inference.
|
||||
It also infers type arguments for generic functions assigned to variables or
|
||||
passed as arguments to other (possibly generic) functions.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.22">Go 1.22</h4>
|
||||
<ul>
|
||||
<li>
|
||||
In a <a href="#For_statements">"for" statement</a>, each iteration has its own set of iteration
|
||||
variables rather than sharing the same variables in each iteration.
|
||||
</li>
|
||||
<li>
|
||||
A "for" statement with <a href="#For_range">"range" clause</a> may iterate over
|
||||
integer values from zero to an upper limit.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.23">Go 1.23</h4>
|
||||
<ul>
|
||||
<li>A "for" statement with <a href="#For_range">"range" clause</a> accepts an iterator
|
||||
function as range expression.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="Go_1.24">Go 1.24</h4>
|
||||
<ul>
|
||||
<li>
|
||||
An <a href="#Alias_declarations">alias declaration</a> may declare
|
||||
<a href="#Type_parameter_declarations">type parameters</a>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="Type_unification_rules">Type unification rules</h3>
|
||||
|
||||
<p>
|
||||
|
||||
169
doc/godebug.md
169
doc/godebug.md
@@ -34,7 +34,6 @@ For example, if a Go program is running in an environment that contains
|
||||
|
||||
then that Go program will disable the use of HTTP/2 by default in both
|
||||
the HTTP client and the HTTP server.
|
||||
Unrecognized settings in the `GODEBUG` environment variable are ignored.
|
||||
It is also possible to set the default `GODEBUG` for a given program
|
||||
(discussed below).
|
||||
|
||||
@@ -89,38 +88,14 @@ Because this method of setting GODEBUG defaults was introduced only in Go 1.21,
|
||||
programs listing versions of Go earlier than Go 1.20 are configured to match Go 1.20,
|
||||
not the older version.
|
||||
|
||||
To override these defaults, starting in Go 1.23, the work module's `go.mod`
|
||||
or the workspace's `go.work` can list one or more `godebug` lines:
|
||||
|
||||
godebug (
|
||||
default=go1.21
|
||||
panicnil=1
|
||||
asynctimerchan=0
|
||||
)
|
||||
|
||||
The special key `default` indicates a Go version to take unspecified
|
||||
settings from. This allows setting the GODEBUG defaults separately
|
||||
from the Go language version in the module.
|
||||
In this example, the program is asking for Go 1.21 semantics and
|
||||
then asking for the old pre-Go 1.21 `panic(nil)` behavior and the
|
||||
new Go 1.23 `asynctimerchan=0` behavior.
|
||||
|
||||
Only the work module's `go.mod` is consulted for `godebug` directives.
|
||||
Any directives in required dependency modules are ignored.
|
||||
It is an error to list a `godebug` with an unrecognized setting.
|
||||
(Toolchains older than Go 1.23 reject all `godebug` lines, since they do not
|
||||
understand `godebug` at all.)
|
||||
|
||||
The defaults from the `go` and `godebug` lines apply to all main
|
||||
packages that are built. For more fine-grained control,
|
||||
starting in Go 1.21, a main package's source files
|
||||
To override these defaults, a main package's source files
|
||||
can include one or more `//go:debug` directives at the top of the file
|
||||
(preceding the `package` statement).
|
||||
The `godebug` lines in the previous example would be written:
|
||||
Continuing the `panicnil` example, if the module or workspace is updated
|
||||
to say `go` `1.21`, the program can opt back into the old `panic(nil)`
|
||||
behavior by including this directive:
|
||||
|
||||
//go:debug default=go1.21
|
||||
//go:debug panicnil=1
|
||||
//go:debug asynctimerchan=0
|
||||
|
||||
Starting in Go 1.21, the Go toolchain treats a `//go:debug` directive
|
||||
with an unrecognized GODEBUG setting as an invalid program.
|
||||
@@ -151,127 +126,6 @@ for example,
|
||||
see the [runtime documentation](/pkg/runtime#hdr-Environment_Variables)
|
||||
and the [go command documentation](/cmd/go#hdr-Build_and_test_caching).
|
||||
|
||||
### Go 1.24
|
||||
|
||||
Go 1.24 changed the global [`math/rand.Seed`](/pkg/math/rand/#Seed) to be a
|
||||
no-op. This behavior is controlled by the `randseednop` setting.
|
||||
For Go 1.24 it defaults to `randseednop=1`.
|
||||
Using `randseednop=0` reverts to the pre-Go 1.24 behavior.
|
||||
|
||||
Go 1.24 added new values for the `multipathtcp` setting.
|
||||
The possible values for `multipathtcp` are now:
|
||||
- "0": disable MPTCP on dialers and listeners by default
|
||||
- "1": enable MPTCP on dialers and listeners by default
|
||||
- "2": enable MPTCP on listeners only by default
|
||||
- "3": enable MPTCP on dialers only by default
|
||||
|
||||
For Go 1.24, it now defaults to multipathtcp="2", thus
|
||||
enabled by default on listeners. Using multipathtcp="0" reverts to the
|
||||
pre-Go 1.24 behavior.
|
||||
|
||||
Go 1.24 changed the behavior of `go test -json` to emit build errors as JSON
|
||||
instead of text.
|
||||
These new JSON events are distinguished by new `Action` values,
|
||||
but can still cause problems with CI systems that aren't robust to these events.
|
||||
This behavior can be controlled with the `gotestjsonbuildtext` setting.
|
||||
Using `gotestjsonbuildtext=1` restores the 1.23 behavior.
|
||||
This setting will be removed in a future release, Go 1.28 at the earliest.
|
||||
|
||||
Go 1.24 changed [`crypto/rsa`](/pkg/crypto/rsa) to require RSA keys to be at
|
||||
least 1024 bits. This behavior can be controlled with the `rsa1024min` setting.
|
||||
Using `rsa1024min=0` restores the Go 1.23 behavior.
|
||||
|
||||
Go 1.24 introduced a mechanism for enabling platform specific Data Independent
|
||||
Timing (DIT) modes in the [`crypto/subtle`](/pkg/crypto/subtle) package. This
|
||||
mode can be enabled for an entire program with the `dataindependenttiming` setting.
|
||||
For Go 1.24 it defaults to `dataindependenttiming=0`. There is no change in default
|
||||
behavior from Go 1.23 when `dataindependenttiming` is unset.
|
||||
Using `dataindependenttiming=1` enables the DIT mode for the entire Go program.
|
||||
When enabled, DIT will be enabled when calling into C from Go. When enabled,
|
||||
calling into Go code from C will enable DIT, and disable it before returning to
|
||||
C if it was not enabled when Go code was entered.
|
||||
This currently only affects arm64 programs. For all other platforms it is a no-op.
|
||||
|
||||
Go 1.24 removed the `x509sha1` setting. `crypto/x509` no longer supports verifying
|
||||
signatures on certificates that use SHA-1 based signature algorithms.
|
||||
|
||||
Go 1.24 changes the default value of the [`x509usepolicies`
|
||||
setting.](/pkg/crypto/x509/#CreateCertificate) from `0` to `1`. When marshalling
|
||||
certificates, policies are now taken from the
|
||||
[`Certificate.Policies`](/pkg/crypto/x509/#Certificate.Policies) field rather
|
||||
than the
|
||||
[`Certificate.PolicyIdentifiers`](/pkg/crypto/x509/#Certificate.PolicyIdentifiers)
|
||||
field by default.
|
||||
|
||||
Go 1.24 enabled the post-quantum key exchange mechanism
|
||||
X25519MLKEM768 by default. The default can be reverted using the
|
||||
[`tlsmlkem` setting](/pkg/crypto/tls/#Config.CurvePreferences).
|
||||
Go 1.24 also removed X25519Kyber768Draft00 and the Go 1.23 `tlskyber` setting.
|
||||
|
||||
Go 1.24 made [`ParsePKCS1PrivateKey`](/pkg/crypto/x509/#ParsePKCS1PrivateKey)
|
||||
use and validate the CRT parameters in the encoded private key. This behavior
|
||||
can be controlled with the `x509rsacrt` setting. Using `x509rsacrt=0` restores
|
||||
the Go 1.23 behavior.
|
||||
|
||||
### Go 1.23
|
||||
|
||||
Go 1.23 changed the channels created by package time to be unbuffered
|
||||
(synchronous), which makes correct use of the [`Timer.Stop`](/pkg/time/#Timer.Stop)
|
||||
and [`Timer.Reset`](/pkg/time/#Timer.Reset) method results much easier.
|
||||
The [`asynctimerchan` setting](/pkg/time/#NewTimer) disables this change.
|
||||
There are no runtime metrics for this change,
|
||||
This setting may be removed in a future release, Go 1.27 at the earliest.
|
||||
|
||||
Go 1.23 changed the mode bits reported by [`os.Lstat`](/pkg/os#Lstat) and [`os.Stat`](/pkg/os#Stat)
|
||||
for reparse points, which can be controlled with the `winsymlink` setting.
|
||||
As of Go 1.23 (`winsymlink=1`), mount points no longer have [`os.ModeSymlink`](/pkg/os#ModeSymlink)
|
||||
set, and reparse points that are not symlinks, Unix sockets, or dedup files now
|
||||
always have [`os.ModeIrregular`](/pkg/os#ModeIrregular) set. As a result of these changes,
|
||||
[`filepath.EvalSymlinks`](/pkg/path/filepath#EvalSymlinks) no longer evaluates
|
||||
mount points, which was a source of many inconsistencies and bugs.
|
||||
At previous versions (`winsymlink=0`), mount points are treated as symlinks,
|
||||
and other reparse points with non-default [`os.ModeType`](/pkg/os#ModeType) bits
|
||||
(such as [`os.ModeDir`](/pkg/os#ModeDir)) do not have the `ModeIrregular` bit set.
|
||||
|
||||
Go 1.23 changed [`os.Readlink`](/pkg/os#Readlink) and [`filepath.EvalSymlinks`](/pkg/path/filepath#EvalSymlinks)
|
||||
to avoid trying to normalize volumes to drive letters, which was not always even possible.
|
||||
This behavior is controlled by the `winreadlinkvolume` setting.
|
||||
For Go 1.23, it defaults to `winreadlinkvolume=1`.
|
||||
Previous versions default to `winreadlinkvolume=0`.
|
||||
|
||||
Go 1.23 enabled the experimental post-quantum key exchange mechanism
|
||||
X25519Kyber768Draft00 by default. The default can be reverted using the
|
||||
[`tlskyber` setting](/pkg/crypto/tls/#Config.CurvePreferences).
|
||||
|
||||
Go 1.23 changed the behavior of
|
||||
[crypto/x509.ParseCertificate](/pkg/crypto/x509/#ParseCertificate) to reject
|
||||
serial numbers that are negative. This change can be reverted with
|
||||
the [`x509negativeserial` setting](/pkg/crypto/x509/#ParseCertificate).
|
||||
|
||||
Go 1.23 re-enabled support in html/template for ECMAScript 6 template literals by default.
|
||||
The [`jstmpllitinterp` setting](/pkg/html/template#hdr-Security_Model) no longer has
|
||||
any effect.
|
||||
|
||||
Go 1.23 changed the default TLS cipher suites used by clients and servers when
|
||||
not explicitly configured, removing 3DES cipher suites. The default can be reverted
|
||||
using the [`tls3des` setting](/pkg/crypto/tls/#Config.CipherSuites).
|
||||
|
||||
Go 1.23 changed the behavior of [`tls.X509KeyPair`](/pkg/crypto/tls#X509KeyPair)
|
||||
and [`tls.LoadX509KeyPair`](/pkg/crypto/tls#LoadX509KeyPair) to populate the
|
||||
Leaf field of the returned [`tls.Certificate`](/pkg/crypto/tls#Certificate).
|
||||
This behavior is controlled by the `x509keypairleaf` setting. For Go 1.23, it
|
||||
defaults to `x509keypairleaf=1`. Previous versions default to
|
||||
`x509keypairleaf=0`.
|
||||
|
||||
Go 1.23 changed
|
||||
[`net/http.ServeContent`](/pkg/net/http#ServeContent),
|
||||
[`net/http.ServeFile`](/pkg/net/http#ServeFile), and
|
||||
[`net/http.ServeFS`](/pkg/net/http#ServeFS) to
|
||||
remove Cache-Control, Content-Encoding, Etag, and Last-Modified headers
|
||||
when serving an error. This behavior is controlled by
|
||||
the [`httpservecontentkeepheaders` setting](/pkg/net/http#ServeContent).
|
||||
Using `httpservecontentkeepheaders=1` restores the pre-Go 1.23 behavior.
|
||||
|
||||
### Go 1.22
|
||||
|
||||
Go 1.22 adds a configurable limit to control the maximum acceptable RSA key size
|
||||
@@ -294,8 +148,8 @@ for the explicit representation of [type aliases](/ref/spec#Type_declarations).
|
||||
Whether the type checker produces `Alias` types or not is controlled by the
|
||||
[`gotypesalias` setting](/pkg/go/types#Alias).
|
||||
For Go 1.22 it defaults to `gotypesalias=0`.
|
||||
For Go 1.23, `gotypesalias=1` will become the default.
|
||||
This setting will be removed in a future release, Go 1.27 at the earliest.
|
||||
For Go 1.23, `gotypealias=1` will become the default.
|
||||
This setting will be removed in a future release, Go 1.24 at the earliest.
|
||||
|
||||
Go 1.22 changed the default minimum TLS version supported by both servers
|
||||
and clients to TLS 1.2. The default can be reverted to TLS 1.0 using the
|
||||
@@ -303,7 +157,7 @@ and clients to TLS 1.2. The default can be reverted to TLS 1.0 using the
|
||||
|
||||
Go 1.22 changed the default TLS cipher suites used by clients and servers when
|
||||
not explicitly configured, removing the cipher suites which used RSA based key
|
||||
exchange. The default can be reverted using the [`tlsrsakex` setting](/pkg/crypto/tls/#Config).
|
||||
exchange. The default can be revert using the [`tlsrsakex` setting](/pkg/crypto/tls/#Config).
|
||||
|
||||
Go 1.22 disabled
|
||||
[`ConnectionState.ExportKeyingMaterial`](/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial)
|
||||
@@ -394,18 +248,11 @@ Go 1.19 made it an error for path lookups to resolve to binaries in the current
|
||||
controlled by the [`execerrdot` setting](/pkg/os/exec#hdr-Executables_in_the_current_directory).
|
||||
There is no plan to remove this setting.
|
||||
|
||||
Go 1.19 started sending EDNS0 additional headers on DNS requests.
|
||||
This can reportedly break the DNS server provided on some routers,
|
||||
such as CenturyLink Zyxel C3000Z.
|
||||
This can be changed by the [`netedns0` setting](/pkg/net#hdr-Name_Resolution).
|
||||
This setting is available in Go 1.21.12, Go 1.22.5, Go 1.23, and later.
|
||||
There is no plan to remove this setting.
|
||||
|
||||
### Go 1.18
|
||||
|
||||
Go 1.18 removed support for SHA1 in most X.509 certificates,
|
||||
controlled by the [`x509sha1` setting](/pkg/crypto/x509#InsecureAlgorithmError).
|
||||
This setting was removed in Go 1.24.
|
||||
This setting will be removed in a future release, Go 1.22 at the earliest.
|
||||
|
||||
### Go 1.10
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<!--
|
||||
NOTE: In this document and others in this directory, the convention is to
|
||||
set fixed-width phrases with non-fixed-width spaces, as in
|
||||
`hello` `world`.
|
||||
-->
|
||||
|
||||
<style>
|
||||
main ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
## DRAFT RELEASE NOTES — Introduction to Go 1.N {#introduction}
|
||||
|
||||
**Go 1.N is not yet released. These are work-in-progress release notes.
|
||||
Go 1.N is expected to be released in {Month} {Year}.**
|
||||
@@ -1,3 +0,0 @@
|
||||
## Changes to the language {#language}
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
## Tools {#tools}
|
||||
|
||||
### Go command {#go-command}
|
||||
|
||||
### Cgo {#cgo}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
## Runtime {#runtime}
|
||||
@@ -1,7 +0,0 @@
|
||||
## Compiler {#compiler}
|
||||
|
||||
## Assembler {#assembler}
|
||||
|
||||
## Linker {#linker}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
## Standard library {#library}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
### Minor changes to the library {#minor_library_changes}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
API changes and other small changes to the standard library go here.
|
||||
@@ -1,2 +0,0 @@
|
||||
## Ports {#ports}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Copyright 2024 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
# Rules for building and testing new FIPS snapshots.
|
||||
# For example:
|
||||
#
|
||||
# make v1.2.3.zip
|
||||
# make v1.2.3.test
|
||||
#
|
||||
# and then if changes are needed, check them into master
|
||||
# and run 'make v1.2.3.rm' and repeat.
|
||||
#
|
||||
# Note that once published a snapshot zip file should never
|
||||
# be modified. We record the sha256 hashes of the zip files
|
||||
# in fips140.sum, and the cmd/go/internal/fips140 test checks
|
||||
# that the zips match.
|
||||
#
|
||||
# When the zip file is finalized, run 'make updatesum' to update
|
||||
# fips140.sum.
|
||||
|
||||
default:
|
||||
@echo nothing to make
|
||||
|
||||
# make v1.2.3.zip builds a v1.2.3.zip file
|
||||
# from the current origin/master.
|
||||
# copy and edit the 'go run' command by hand to use a different branch.
|
||||
v%.zip:
|
||||
git fetch origin master
|
||||
go run ../../src/cmd/go/internal/fips140/mkzip.go -b master v$*
|
||||
|
||||
# normally mkzip refuses to overwrite an existing zip file.
|
||||
# make v1.2.3.rm removes the zip file and and unpacked
|
||||
# copy from the module cache.
|
||||
v%.rm:
|
||||
rm -f v$*.zip
|
||||
chmod -R u+w $$(go env GOMODCACHE)/golang.org/fips140@v$* 2>/dev/null || true
|
||||
rm -rf $$(go env GOMODCACHE)/golang.org/fips140@v$*
|
||||
|
||||
# make v1.2.3.test runs the crypto tests using that snapshot.
|
||||
v%.test:
|
||||
GOFIPS140=v$* go test -short crypto...
|
||||
|
||||
# make updatesum updates the fips140.sum file.
|
||||
updatesum:
|
||||
go test cmd/go/internal/fips140 -update
|
||||
@@ -1,9 +0,0 @@
|
||||
This directory holds snapshots of the crypto/internal/fips140 tree
|
||||
that are being validated and certified for FIPS-140 use.
|
||||
The file x.txt (for example, inprocess.txt, certified.txt)
|
||||
defines the meaning of the FIPS version alias x, listing
|
||||
the exact version to use.
|
||||
|
||||
The zip files are created by cmd/go/internal/fips140/mkzip.go.
|
||||
The fips140.sum file lists checksums for the zip files.
|
||||
See the Makefile for recipes.
|
||||
@@ -1,11 +0,0 @@
|
||||
# SHA256 checksums of snapshot zip files in this directory.
|
||||
# These checksums are included in the FIPS security policy
|
||||
# (validation instructions sent to the lab) and MUST NOT CHANGE.
|
||||
# That is, the zip files themselves must not change.
|
||||
#
|
||||
# It is okay to add new zip files to the list, and it is okay to
|
||||
# remove zip files from the list when they are removed from
|
||||
# this directory. To update this file:
|
||||
#
|
||||
# go test cmd/go/internal/fips140 -update
|
||||
#
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: go run mkzip.go zoneinfo.zip\n")
|
||||
fmt.Fprintf(os.Stderr, "usage: go run mkzip.go ../../zoneinfo.zip\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
# in the CL match the update.bash in the CL.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2024b
|
||||
DATA=2024b
|
||||
CODE=2023c
|
||||
DATA=2023c
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2023 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
case "$GOWASIRUNTIME" in
|
||||
"wasmedge")
|
||||
exec wasmedge --dir=/ --env PWD="$PWD" --env PATH="$PATH" ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
;;
|
||||
"wasmer")
|
||||
exec wasmer run --dir=/ --env PWD="$PWD" --env PATH="$PATH" ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||
;;
|
||||
"wazero")
|
||||
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
;;
|
||||
"wasmtime" | "")
|
||||
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" -W max-wasm-stack=1048576 ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,22 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script configures clang to target the iOS simulator. If you'd like to
|
||||
# build for real iOS devices, change SDK to "iphoneos" and PLATFORM to "ios".
|
||||
# This uses the latest available iOS SDK, which is recommended. To select a
|
||||
# specific SDK, run 'xcodebuild -showsdks' to see the available SDKs and replace
|
||||
# iphonesimulator with one of them.
|
||||
|
||||
SDK=iphonesimulator
|
||||
PLATFORM=ios-simulator
|
||||
|
||||
# This uses the latest available iOS SDK, which is recommended.
|
||||
# To select a specific SDK, run 'xcodebuild -showsdks'
|
||||
# to see the available SDKs and replace iphoneos with one of them.
|
||||
if [ "$GOARCH" == "arm64" ]; then
|
||||
SDK=iphoneos
|
||||
PLATFORM=ios
|
||||
CLANGARCH="arm64"
|
||||
else
|
||||
SDK=iphonesimulator
|
||||
PLATFORM=ios-simulator
|
||||
CLANGARCH="x86_64"
|
||||
fi
|
||||
|
||||
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
|
||||
|
||||
export IPHONEOS_DEPLOYMENT_TARGET=5.1
|
||||
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
|
||||
CLANG=`xcrun --sdk $SDK --find clang`
|
||||
|
||||
|
||||
@@ -1,21 +1,44 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// This program can be used as go_ios_$GOARCH_exec by the Go tool. It executes
|
||||
// binaries on the iOS Simulator using the XCode toolchain.
|
||||
// This program can be used as go_ios_$GOARCH_exec by the Go tool.
|
||||
// It executes binaries on an iOS device using the XCode toolchain
|
||||
// and the ios-deploy program: https://github.com/phonegap/ios-deploy
|
||||
//
|
||||
// This script supports an extra flag, -lldb, that pauses execution
|
||||
// just before the main program begins and allows the user to control
|
||||
// the remote lldb session. This flag is appended to the end of the
|
||||
// script's arguments and is not passed through to the underlying
|
||||
// binary.
|
||||
//
|
||||
// This script requires that three environment variables be set:
|
||||
//
|
||||
// GOIOS_DEV_ID: The codesigning developer id or certificate identifier
|
||||
// GOIOS_APP_ID: The provisioning app id prefix. Must support wildcard app ids.
|
||||
// GOIOS_TEAM_ID: The team id that owns the app id prefix.
|
||||
//
|
||||
// $GOROOT/misc/ios contains a script, detect.go, that attempts to autodetect these.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const debug = false
|
||||
@@ -87,8 +110,18 @@ func runMain() (int, error) {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
err = runOnSimulator(appdir)
|
||||
if goarch := os.Getenv("GOARCH"); goarch == "arm64" {
|
||||
err = runOnDevice(appdir)
|
||||
} else {
|
||||
err = runOnSimulator(appdir)
|
||||
}
|
||||
if err != nil {
|
||||
// If the lldb driver completed with an exit code, use that.
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
if ws, ok := err.Sys().(interface{ ExitStatus() int }); ok {
|
||||
return ws.ExitStatus(), nil
|
||||
}
|
||||
}
|
||||
return 1, err
|
||||
}
|
||||
return 0, nil
|
||||
@@ -102,6 +135,61 @@ func runOnSimulator(appdir string) error {
|
||||
return runSimulator(appdir, bundleID, os.Args[2:])
|
||||
}
|
||||
|
||||
func runOnDevice(appdir string) error {
|
||||
// e.g. B393DDEB490947F5A463FD074299B6C0AXXXXXXX
|
||||
devID = getenv("GOIOS_DEV_ID")
|
||||
|
||||
// e.g. Z8B3JBXXXX.org.golang.sample, Z8B3JBXXXX prefix is available at
|
||||
// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
|
||||
appID = getenv("GOIOS_APP_ID")
|
||||
|
||||
// e.g. Z8B3JBXXXX, available at
|
||||
// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
|
||||
teamID = getenv("GOIOS_TEAM_ID")
|
||||
|
||||
// Device IDs as listed with ios-deploy -c.
|
||||
deviceID = os.Getenv("GOIOS_DEVICE_ID")
|
||||
|
||||
if _, id, ok := strings.Cut(appID, "."); ok {
|
||||
bundleID = id
|
||||
}
|
||||
|
||||
if err := signApp(appdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := uninstallDevice(bundleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := installDevice(appdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mountDevImage(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Kill any hanging debug bridges that might take up port 3222.
|
||||
exec.Command("killall", "idevicedebugserverproxy").Run()
|
||||
|
||||
closer, err := startDebugBridge()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
return runDevice(appdir, bundleID, os.Args[2:])
|
||||
}
|
||||
|
||||
func getenv(envvar string) string {
|
||||
s := os.Getenv(envvar)
|
||||
if s == "" {
|
||||
log.Fatalf("%s not set\nrun $GOROOT/misc/ios/detect.go to attempt to autodetect", envvar)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func assembleApp(appdir, bin string) error {
|
||||
if err := os.MkdirAll(appdir, 0755); err != nil {
|
||||
return err
|
||||
@@ -129,6 +217,236 @@ func assembleApp(appdir, bin string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func signApp(appdir string) error {
|
||||
entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
|
||||
cmd := exec.Command(
|
||||
"codesign",
|
||||
"-f",
|
||||
"-s", devID,
|
||||
"--entitlements", entitlementsPath,
|
||||
appdir,
|
||||
)
|
||||
if debug {
|
||||
log.Println(strings.Join(cmd.Args, " "))
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("codesign: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mountDevImage ensures a developer image is mounted on the device.
|
||||
// The image contains the device lldb server for idevicedebugserverproxy
|
||||
// to connect to.
|
||||
func mountDevImage() error {
|
||||
// Check for existing mount.
|
||||
cmd := idevCmd(exec.Command("ideviceimagemounter", "-l", "-x"))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("ideviceimagemounter: %v", err)
|
||||
}
|
||||
var info struct {
|
||||
Dict struct {
|
||||
Data []byte `xml:",innerxml"`
|
||||
} `xml:"dict"`
|
||||
}
|
||||
if err := xml.Unmarshal(out, &info); err != nil {
|
||||
return fmt.Errorf("mountDevImage: failed to decode mount information: %v", err)
|
||||
}
|
||||
dict, err := parsePlistDict(info.Dict.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("mountDevImage: failed to parse mount information: %v", err)
|
||||
}
|
||||
if dict["ImagePresent"] == "true" && dict["Status"] == "Complete" {
|
||||
return nil
|
||||
}
|
||||
// Some devices only give us an ImageSignature key.
|
||||
if _, exists := dict["ImageSignature"]; exists {
|
||||
return nil
|
||||
}
|
||||
// No image is mounted. Find a suitable image.
|
||||
imgPath, err := findDevImage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigPath := imgPath + ".signature"
|
||||
cmd = idevCmd(exec.Command("ideviceimagemounter", imgPath, sigPath))
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("ideviceimagemounter: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// findDevImage use the device iOS version and build to locate a suitable
|
||||
// developer image.
|
||||
func findDevImage() (string, error) {
|
||||
cmd := idevCmd(exec.Command("ideviceinfo"))
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ideviceinfo: %v", err)
|
||||
}
|
||||
var iosVer, buildVer string
|
||||
lines := bytes.Split(out, []byte("\n"))
|
||||
for _, line := range lines {
|
||||
key, val, ok := strings.Cut(string(line), ": ")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "ProductVersion":
|
||||
iosVer = val
|
||||
case "BuildVersion":
|
||||
buildVer = val
|
||||
}
|
||||
}
|
||||
if iosVer == "" || buildVer == "" {
|
||||
return "", errors.New("failed to parse ideviceinfo output")
|
||||
}
|
||||
verSplit := strings.Split(iosVer, ".")
|
||||
if len(verSplit) > 2 {
|
||||
// Developer images are specific to major.minor ios version.
|
||||
// Cut off the patch version.
|
||||
iosVer = strings.Join(verSplit[:2], ".")
|
||||
}
|
||||
sdkBase := "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport"
|
||||
patterns := []string{fmt.Sprintf("%s (%s)", iosVer, buildVer), fmt.Sprintf("%s (*)", iosVer), fmt.Sprintf("%s*", iosVer)}
|
||||
for _, pattern := range patterns {
|
||||
matches, err := filepath.Glob(filepath.Join(sdkBase, pattern, "DeveloperDiskImage.dmg"))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("findDevImage: %v", err)
|
||||
}
|
||||
if len(matches) > 0 {
|
||||
return matches[0], nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("failed to find matching developer image for iOS version %s build %s", iosVer, buildVer)
|
||||
}
|
||||
|
||||
// startDebugBridge ensures that the idevicedebugserverproxy runs on
|
||||
// port 3222.
|
||||
func startDebugBridge() (func(), error) {
|
||||
errChan := make(chan error, 1)
|
||||
cmd := idevCmd(exec.Command("idevicedebugserverproxy", "3222"))
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("idevicedebugserverproxy: %v", err)
|
||||
}
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
if _, ok := err.(*exec.ExitError); ok {
|
||||
errChan <- fmt.Errorf("idevicedebugserverproxy: %s", stderr.Bytes())
|
||||
} else {
|
||||
errChan <- fmt.Errorf("idevicedebugserverproxy: %v", err)
|
||||
}
|
||||
}
|
||||
errChan <- nil
|
||||
}()
|
||||
closer := func() {
|
||||
cmd.Process.Kill()
|
||||
<-errChan
|
||||
}
|
||||
// Dial localhost:3222 to ensure the proxy is ready.
|
||||
delay := time.Second / 4
|
||||
for attempt := 0; attempt < 5; attempt++ {
|
||||
conn, err := net.DialTimeout("tcp", "localhost:3222", 5*time.Second)
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
return closer, nil
|
||||
}
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
delay *= 2
|
||||
case err := <-errChan:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
closer()
|
||||
return nil, errors.New("failed to set up idevicedebugserverproxy")
|
||||
}
|
||||
|
||||
// findDeviceAppPath returns the device path to the app with the
|
||||
// given bundle ID. It parses the output of ideviceinstaller -l -o xml,
|
||||
// looking for the bundle ID and the corresponding Path value.
|
||||
func findDeviceAppPath(bundleID string) (string, error) {
|
||||
cmd := idevCmd(exec.Command("ideviceinstaller", "-l", "-o", "xml"))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return "", fmt.Errorf("ideviceinstaller: -l -o xml %v", err)
|
||||
}
|
||||
var list struct {
|
||||
Apps []struct {
|
||||
Data []byte `xml:",innerxml"`
|
||||
} `xml:"array>dict"`
|
||||
}
|
||||
if err := xml.Unmarshal(out, &list); err != nil {
|
||||
return "", fmt.Errorf("failed to parse ideviceinstaller output: %v", err)
|
||||
}
|
||||
for _, app := range list.Apps {
|
||||
values, err := parsePlistDict(app.Data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("findDeviceAppPath: failed to parse app dict: %v", err)
|
||||
}
|
||||
if values["CFBundleIdentifier"] == bundleID {
|
||||
if path, ok := values["Path"]; ok {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("failed to find device path for bundle: %s", bundleID)
|
||||
}
|
||||
|
||||
// Parse an xml encoded plist. Plist values are mapped to string.
|
||||
func parsePlistDict(dict []byte) (map[string]string, error) {
|
||||
d := xml.NewDecoder(bytes.NewReader(dict))
|
||||
values := make(map[string]string)
|
||||
var key string
|
||||
var hasKey bool
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok, ok := tok.(xml.StartElement); ok {
|
||||
if tok.Name.Local == "key" {
|
||||
if err := d.DecodeElement(&key, &tok); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hasKey = true
|
||||
} else if hasKey {
|
||||
var val string
|
||||
var err error
|
||||
switch n := tok.Name.Local; n {
|
||||
case "true", "false":
|
||||
// Bools are represented as <true/> and <false/>.
|
||||
val = n
|
||||
err = d.Skip()
|
||||
default:
|
||||
err = d.DecodeElement(&val, &tok)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values[key] = val
|
||||
hasKey = false
|
||||
} else {
|
||||
if err := d.Skip(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func installSimulator(appdir string) error {
|
||||
cmd := exec.Command(
|
||||
"xcrun", "simctl", "install",
|
||||
@@ -142,20 +460,138 @@ func installSimulator(appdir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runSimulator(appdir, bundleID string, args []string) error {
|
||||
xcrunArgs := []string{"simctl", "spawn",
|
||||
"booted",
|
||||
appdir + "/gotest",
|
||||
func uninstallDevice(bundleID string) error {
|
||||
cmd := idevCmd(exec.Command(
|
||||
"ideviceinstaller",
|
||||
"-U", bundleID,
|
||||
))
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("ideviceinstaller -U %q: %s", bundleID, err)
|
||||
}
|
||||
xcrunArgs = append(xcrunArgs, args...)
|
||||
cmd := exec.Command("xcrun", xcrunArgs...)
|
||||
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
||||
err := cmd.Run()
|
||||
return nil
|
||||
}
|
||||
|
||||
func installDevice(appdir string) error {
|
||||
attempt := 0
|
||||
for {
|
||||
cmd := idevCmd(exec.Command(
|
||||
"ideviceinstaller",
|
||||
"-i", appdir,
|
||||
))
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
// Sometimes, installing the app fails for some reason.
|
||||
// Give the device a few seconds and try again.
|
||||
if attempt < 5 {
|
||||
time.Sleep(5 * time.Second)
|
||||
attempt++
|
||||
continue
|
||||
}
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("ideviceinstaller -i %q: %v (%d attempts)", appdir, err, attempt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func idevCmd(cmd *exec.Cmd) *exec.Cmd {
|
||||
if deviceID != "" {
|
||||
// Inject -u device_id after the executable, but before the arguments.
|
||||
args := []string{cmd.Args[0], "-u", deviceID}
|
||||
cmd.Args = append(args, cmd.Args[1:]...)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runSimulator(appdir, bundleID string, args []string) error {
|
||||
cmd := exec.Command(
|
||||
"xcrun", "simctl", "launch",
|
||||
"--wait-for-debugger",
|
||||
"booted",
|
||||
bundleID,
|
||||
)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("xcrun simctl launch booted %q: %v", bundleID, err)
|
||||
}
|
||||
var processID int
|
||||
var ignore string
|
||||
if _, err := fmt.Sscanf(string(out), "%s %d", &ignore, &processID); err != nil {
|
||||
return fmt.Errorf("runSimulator: couldn't find processID from `simctl launch`: %v (%q)", err, out)
|
||||
}
|
||||
_, err = runLLDB("ios-simulator", appdir, strconv.Itoa(processID), args)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
func runDevice(appdir, bundleID string, args []string) error {
|
||||
attempt := 0
|
||||
for {
|
||||
// The device app path reported by the device might be stale, so retry
|
||||
// the lookup of the device path along with the lldb launching below.
|
||||
deviceapp, err := findDeviceAppPath(bundleID)
|
||||
if err != nil {
|
||||
// The device app path might not yet exist for a newly installed app.
|
||||
if attempt == 5 {
|
||||
return err
|
||||
}
|
||||
attempt++
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
out, err := runLLDB("remote-ios", appdir, deviceapp, args)
|
||||
// If the program was not started it can be retried without papering over
|
||||
// real test failures.
|
||||
started := bytes.HasPrefix(out, []byte("lldb: running program"))
|
||||
if started || err == nil || attempt == 5 {
|
||||
return err
|
||||
}
|
||||
// Sometimes, the app was not yet ready to launch or the device path was
|
||||
// stale. Retry.
|
||||
attempt++
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func runLLDB(target, appdir, deviceapp string, args []string) ([]byte, error) {
|
||||
var env []string
|
||||
for _, e := range os.Environ() {
|
||||
// Don't override TMPDIR, HOME, GOCACHE on the device.
|
||||
if strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "GOCACHE=") {
|
||||
continue
|
||||
}
|
||||
env = append(env, e)
|
||||
}
|
||||
lldb := exec.Command(
|
||||
"python",
|
||||
"-", // Read script from stdin.
|
||||
target,
|
||||
appdir,
|
||||
deviceapp,
|
||||
)
|
||||
lldb.Args = append(lldb.Args, args...)
|
||||
lldb.Env = env
|
||||
lldb.Stdin = strings.NewReader(lldbDriver)
|
||||
lldb.Stdout = os.Stdout
|
||||
var out bytes.Buffer
|
||||
lldb.Stderr = io.MultiWriter(&out, os.Stderr)
|
||||
err := lldb.Start()
|
||||
if err == nil {
|
||||
// Forward SIGQUIT to the lldb driver which in turn will forward
|
||||
// to the running program.
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGQUIT)
|
||||
proc := lldb.Process
|
||||
go func() {
|
||||
for sig := range sigs {
|
||||
proc.Signal(sig)
|
||||
}
|
||||
}()
|
||||
err = lldb.Wait()
|
||||
signal.Stop(sigs)
|
||||
close(sigs)
|
||||
}
|
||||
return out.Bytes(), err
|
||||
}
|
||||
|
||||
func copyLocalDir(dst, src string) error {
|
||||
@@ -364,3 +800,112 @@ const resourceRules = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
</dict>
|
||||
</plist>
|
||||
`
|
||||
|
||||
const lldbDriver = `
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
|
||||
platform, exe, device_exe_or_pid, args = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4:]
|
||||
|
||||
env = []
|
||||
for k, v in os.environ.items():
|
||||
env.append(k + "=" + v)
|
||||
|
||||
sys.path.append('/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python')
|
||||
|
||||
import lldb
|
||||
|
||||
debugger = lldb.SBDebugger.Create()
|
||||
debugger.SetAsync(True)
|
||||
debugger.SkipLLDBInitFiles(True)
|
||||
|
||||
err = lldb.SBError()
|
||||
target = debugger.CreateTarget(exe, None, platform, True, err)
|
||||
if not target.IsValid() or not err.Success():
|
||||
sys.stderr.write("lldb: failed to setup up target: %s\n" % (err))
|
||||
sys.exit(1)
|
||||
|
||||
listener = debugger.GetListener()
|
||||
|
||||
if platform == 'remote-ios':
|
||||
target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_exe_or_pid))
|
||||
process = target.ConnectRemote(listener, 'connect://localhost:3222', None, err)
|
||||
else:
|
||||
process = target.AttachToProcessWithID(listener, int(device_exe_or_pid), err)
|
||||
|
||||
if not err.Success():
|
||||
sys.stderr.write("lldb: failed to connect to remote target %s: %s\n" % (device_exe_or_pid, err))
|
||||
sys.exit(1)
|
||||
|
||||
# Don't stop on signals.
|
||||
sigs = process.GetUnixSignals()
|
||||
for i in range(0, sigs.GetNumSignals()):
|
||||
sig = sigs.GetSignalAtIndex(i)
|
||||
sigs.SetShouldStop(sig, False)
|
||||
sigs.SetShouldNotify(sig, False)
|
||||
|
||||
event = lldb.SBEvent()
|
||||
running = False
|
||||
prev_handler = None
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
process.Signal(signal)
|
||||
|
||||
def run_program():
|
||||
# Forward SIGQUIT to the program.
|
||||
prev_handler = signal.signal(signal.SIGQUIT, signal_handler)
|
||||
# Tell the Go driver that the program is running and should not be retried.
|
||||
sys.stderr.write("lldb: running program\n")
|
||||
running = True
|
||||
# Process is stopped at attach/launch. Let it run.
|
||||
process.Continue()
|
||||
|
||||
if platform != 'remote-ios':
|
||||
# For the local emulator the program is ready to run.
|
||||
# For remote device runs, we need to wait for eStateConnected,
|
||||
# below.
|
||||
run_program()
|
||||
|
||||
while True:
|
||||
if not listener.WaitForEvent(1, event):
|
||||
continue
|
||||
if not lldb.SBProcess.EventIsProcessEvent(event):
|
||||
continue
|
||||
if running:
|
||||
# Pass through stdout and stderr.
|
||||
while True:
|
||||
out = process.GetSTDOUT(8192)
|
||||
if not out:
|
||||
break
|
||||
sys.stdout.write(out)
|
||||
while True:
|
||||
out = process.GetSTDERR(8192)
|
||||
if not out:
|
||||
break
|
||||
sys.stderr.write(out)
|
||||
state = process.GetStateFromEvent(event)
|
||||
if state in [lldb.eStateCrashed, lldb.eStateDetached, lldb.eStateUnloaded, lldb.eStateExited]:
|
||||
if running:
|
||||
signal.signal(signal.SIGQUIT, prev_handler)
|
||||
break
|
||||
elif state == lldb.eStateConnected:
|
||||
if platform == 'remote-ios':
|
||||
process.RemoteLaunch(args, env, None, None, None, None, 0, False, err)
|
||||
if not err.Success():
|
||||
sys.stderr.write("lldb: failed to launch remote process: %s\n" % (err))
|
||||
process.Kill()
|
||||
debugger.Terminate()
|
||||
sys.exit(1)
|
||||
run_program()
|
||||
|
||||
exitStatus = process.GetExitStatus()
|
||||
exitDesc = process.GetExitDescription()
|
||||
process.Kill()
|
||||
debugger.Terminate()
|
||||
if exitStatus == 0 and exitDesc is not None:
|
||||
# Ensure tests fail when killed by a signal.
|
||||
exitStatus = 123
|
||||
|
||||
sys.exit(exitStatus)
|
||||
`
|
||||
|
||||
31
misc/wasm/go_wasip1_wasm_exec
Executable file
31
misc/wasm/go_wasip1_wasm_exec
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2023 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
case "$GOWASIRUNTIME" in
|
||||
"wasmedge")
|
||||
exec wasmedge --dir=/ --env PWD="$PWD" --env PATH="$PATH" ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
;;
|
||||
"wasmer")
|
||||
exec wasmer run --dir=/ --env PWD="$PWD" --env PATH="$PATH" ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||
;;
|
||||
"wazero")
|
||||
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
;;
|
||||
"wasmtime" | "")
|
||||
# Match the major version in "wasmtime-cli 14.0.0". For versions before 14
|
||||
# we need to use the old CLI. This requires Bash v3.0 and above.
|
||||
# TODO(johanbrandhorst): Remove this condition once 1.22 is released.
|
||||
# From 1.23 onwards we'll only support the new wasmtime CLI.
|
||||
if [[ "$(wasmtime --version)" =~ wasmtime-cli[[:space:]]([0-9]+)\.[0-9]+\.[0-9]+ && "${BASH_REMATCH[1]}" -lt 14 ]]; then
|
||||
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" --max-wasm-stack 1048576 ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||
else
|
||||
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" -W max-wasm-stack=1048576 ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -17,7 +17,7 @@ license that can be found in the LICENSE file.
|
||||
<script src="https://cdn.jsdelivr.net/npm/text-encoding@0.7.0/lib/encoding.min.js"></script>
|
||||
(see https://caniuse.com/#feat=textencoder)
|
||||
-->
|
||||
<script src="../../lib/wasm/wasm_exec.js"></script>
|
||||
<script src="wasm_exec.js"></script>
|
||||
<script>
|
||||
if (!WebAssembly.instantiateStreaming) { // polyfill
|
||||
WebAssembly.instantiateStreaming = async (resp, importObject) => {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
if (!globalThis.fs) {
|
||||
let outputBuf = "";
|
||||
globalThis.fs = {
|
||||
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_DIRECTORY: -1 }, // unused
|
||||
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);
|
||||
const nl = outputBuf.lastIndexOf("\n");
|
||||
@@ -73,14 +73,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalThis.path) {
|
||||
globalThis.path = {
|
||||
resolve(...pathSegments) {
|
||||
return pathSegments.join("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalThis.crypto) {
|
||||
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
|
||||
}
|
||||
@@ -216,16 +208,10 @@
|
||||
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
|
||||
}
|
||||
|
||||
const testCallExport = (a, b) => {
|
||||
this._inst.exports.testExport0();
|
||||
return this._inst.exports.testExport(a, b);
|
||||
}
|
||||
|
||||
const timeOrigin = Date.now() - performance.now();
|
||||
this.importObject = {
|
||||
_gotest: {
|
||||
add: (a, b) => a + b,
|
||||
callExport: testCallExport,
|
||||
},
|
||||
gojs: {
|
||||
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||
@@ -11,7 +11,6 @@ if (process.argv.length < 3) {
|
||||
|
||||
globalThis.require = require;
|
||||
globalThis.fs = require("fs");
|
||||
globalThis.path = require("path");
|
||||
globalThis.TextEncoder = require("util").TextEncoder;
|
||||
globalThis.TextDecoder = require("util").TextDecoder;
|
||||
|
||||
@@ -31,17 +31,13 @@ Maintaining vendor directories
|
||||
|
||||
Before updating vendor directories, ensure that module mode is enabled.
|
||||
Make sure that GO111MODULE is not set in the environment, or that it is
|
||||
set to 'on' or 'auto', and if you use a go.work file, set GOWORK=off.
|
||||
|
||||
Also, ensure that 'go env GOROOT' shows the root of this Go source
|
||||
tree. Otherwise, the results are undefined. It's recommended to build
|
||||
Go from source and use that 'go' binary to update its source tree.
|
||||
set to 'on' or 'auto'.
|
||||
|
||||
Requirements may be added, updated, and removed with 'go get'.
|
||||
The vendor directory may be updated with 'go mod vendor'.
|
||||
A typical sequence might be:
|
||||
|
||||
cd src # or src/cmd
|
||||
cd src
|
||||
go get golang.org/x/net@master
|
||||
go mod tidy
|
||||
go mod vendor
|
||||
|
||||
@@ -10,4 +10,4 @@ if [ ! -f make.bash ]; then
|
||||
fi
|
||||
. ./make.bash "$@" --no-banner
|
||||
bash run.bash --no-rebuild
|
||||
"$GOTOOLDIR/dist" banner # print build info
|
||||
$GOTOOLDIR/dist banner # print build info
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"fmt"
|
||||
"internal/godebug"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"math"
|
||||
"path"
|
||||
"reflect"
|
||||
@@ -613,7 +612,9 @@ func (fi headerFileInfo) String() string {
|
||||
}
|
||||
|
||||
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
||||
var sysStat func(fi fs.FileInfo, h *Header, doNameLookups bool) error
|
||||
var sysStat func(fi fs.FileInfo, h *Header) error
|
||||
|
||||
var loadUidAndGid func(fi fs.FileInfo, uid, gid *int)
|
||||
|
||||
const (
|
||||
// Mode constants from the USTAR spec:
|
||||
@@ -642,8 +643,8 @@ const (
|
||||
// to provide the full path name of the file.
|
||||
//
|
||||
// If fi implements [FileInfoNames]
|
||||
// Header.Gname and Header.Uname
|
||||
// are provided by the methods of the interface.
|
||||
// the Gname and Uname of the header are
|
||||
// provided by the methods of the interface.
|
||||
func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
if fi == nil {
|
||||
return nil, errors.New("archive/tar: FileInfo is nil")
|
||||
@@ -697,43 +698,55 @@ func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
h.Gname = sys.Gname
|
||||
h.AccessTime = sys.AccessTime
|
||||
h.ChangeTime = sys.ChangeTime
|
||||
h.Xattrs = maps.Clone(sys.Xattrs)
|
||||
if sys.Xattrs != nil {
|
||||
h.Xattrs = make(map[string]string)
|
||||
for k, v := range sys.Xattrs {
|
||||
h.Xattrs[k] = v
|
||||
}
|
||||
}
|
||||
if sys.Typeflag == TypeLink {
|
||||
// hard link
|
||||
h.Typeflag = TypeLink
|
||||
h.Size = 0
|
||||
h.Linkname = sys.Linkname
|
||||
}
|
||||
h.PAXRecords = maps.Clone(sys.PAXRecords)
|
||||
if sys.PAXRecords != nil {
|
||||
h.PAXRecords = make(map[string]string)
|
||||
for k, v := range sys.PAXRecords {
|
||||
h.PAXRecords[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
var doNameLookups = true
|
||||
if iface, ok := fi.(FileInfoNames); ok {
|
||||
doNameLookups = false
|
||||
var err error
|
||||
h.Gname, err = iface.Gname()
|
||||
if loadUidAndGid != nil {
|
||||
loadUidAndGid(fi, &h.Uid, &h.Gid)
|
||||
}
|
||||
h.Gname, err = iface.Gname(h.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.Uname, err = iface.Uname()
|
||||
h.Uname, err = iface.Uname(h.Uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
if sysStat != nil {
|
||||
return h, sysStat(fi, h, doNameLookups)
|
||||
return h, sysStat(fi, h)
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// FileInfoNames extends [fs.FileInfo].
|
||||
// FileInfoNames extends [FileInfo] to translate UID/GID to names.
|
||||
// Passing an instance of this to [FileInfoHeader] permits the caller
|
||||
// to avoid a system-dependent name lookup by specifying the Uname and Gname directly.
|
||||
// to control UID/GID resolution.
|
||||
type FileInfoNames interface {
|
||||
fs.FileInfo
|
||||
// Uname should give a user name.
|
||||
Uname() (string, error)
|
||||
// Gname should give a group name.
|
||||
Gname() (string, error)
|
||||
// Uname should translate a UID into a user name.
|
||||
Uname(uid int) (string, error)
|
||||
// Gname should translate a GID into a group name.
|
||||
Gname(gid int) (string, error)
|
||||
}
|
||||
|
||||
// isHeaderOnlyType checks if the given type flag is of the type that has no
|
||||
|
||||
@@ -811,7 +811,9 @@ func (sr sparseFileReader) physicalRemaining() int64 {
|
||||
type zeroReader struct{}
|
||||
|
||||
func (zeroReader) Read(b []byte) (int, error) {
|
||||
clear(b)
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,16 +7,14 @@ package tar
|
||||
import (
|
||||
"bytes"
|
||||
"compress/bzip2"
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"maps"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -27,7 +25,7 @@ func TestReader(t *testing.T) {
|
||||
vectors := []struct {
|
||||
file string // Test input file
|
||||
headers []*Header // Expected output headers
|
||||
chksums []string // CRC32 checksum of files, leave as nil if not checked
|
||||
chksums []string // MD5 checksum of files, leave as nil if not checked
|
||||
err error // Expected error to occur
|
||||
}{{
|
||||
file: "testdata/gnu.tar",
|
||||
@@ -55,8 +53,8 @@ func TestReader(t *testing.T) {
|
||||
Format: FormatGNU,
|
||||
}},
|
||||
chksums: []string{
|
||||
"6cbd88fc",
|
||||
"ddac04b3",
|
||||
"e38b27eaccb4391bdec553a7f3ae6b2f",
|
||||
"c65bd2e50a56a2138bf1716f2fd56fe9",
|
||||
},
|
||||
}, {
|
||||
file: "testdata/sparse-formats.tar",
|
||||
@@ -149,11 +147,11 @@ func TestReader(t *testing.T) {
|
||||
Format: FormatGNU,
|
||||
}},
|
||||
chksums: []string{
|
||||
"5375e1d2",
|
||||
"5375e1d2",
|
||||
"5375e1d2",
|
||||
"5375e1d2",
|
||||
"8eb179ba",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"6f53234398c2449fe67c1812d993012f",
|
||||
"b0061974914468de549a2af8ced10316",
|
||||
},
|
||||
}, {
|
||||
file: "testdata/star.tar",
|
||||
@@ -270,7 +268,7 @@ func TestReader(t *testing.T) {
|
||||
Format: FormatPAX,
|
||||
}},
|
||||
chksums: []string{
|
||||
"5fd7e86a",
|
||||
"0afb597b283fe61b5d4879669a350556",
|
||||
},
|
||||
}, {
|
||||
file: "testdata/pax-records.tar",
|
||||
@@ -657,7 +655,7 @@ func TestReader(t *testing.T) {
|
||||
if v.chksums == nil {
|
||||
continue
|
||||
}
|
||||
h := crc32.NewIEEE()
|
||||
h := md5.New()
|
||||
_, err = io.CopyBuffer(h, tr, rdbuf) // Effectively an incremental read
|
||||
if err != nil {
|
||||
break
|
||||
@@ -1019,7 +1017,7 @@ func TestParsePAX(t *testing.T) {
|
||||
for i, v := range vectors {
|
||||
r := strings.NewReader(v.in)
|
||||
got, err := parsePAX(r)
|
||||
if !maps.Equal(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
|
||||
if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
|
||||
t.Errorf("test %d, parsePAX():\ngot %v\nwant %v", i, got, v.want)
|
||||
}
|
||||
if ok := err == nil; ok != v.ok {
|
||||
@@ -1136,7 +1134,7 @@ func TestReadOldGNUSparseMap(t *testing.T) {
|
||||
v.input = v.input[copy(blk[:], v.input):]
|
||||
tr := Reader{r: bytes.NewReader(v.input)}
|
||||
got, err := tr.readOldGNUSparseMap(&hdr, &blk)
|
||||
if !slices.Equal(got, v.wantMap) {
|
||||
if !equalSparseEntries(got, v.wantMap) {
|
||||
t.Errorf("test %d, readOldGNUSparseMap(): got %v, want %v", i, got, v.wantMap)
|
||||
}
|
||||
if err != v.wantErr {
|
||||
@@ -1327,7 +1325,7 @@ func TestReadGNUSparsePAXHeaders(t *testing.T) {
|
||||
r := strings.NewReader(v.inputData + "#") // Add canary byte
|
||||
tr := Reader{curr: ®FileReader{r, int64(r.Len())}}
|
||||
got, err := tr.readGNUSparsePAXHeaders(&hdr)
|
||||
if !slices.Equal(got, v.wantMap) {
|
||||
if !equalSparseEntries(got, v.wantMap) {
|
||||
t.Errorf("test %d, readGNUSparsePAXHeaders(): got %v, want %v", i, got, v.wantMap)
|
||||
}
|
||||
if err != v.wantErr {
|
||||
|
||||
@@ -17,36 +17,37 @@ import (
|
||||
|
||||
func init() {
|
||||
sysStat = statUnix
|
||||
loadUidAndGid = loadUidAndGidFunc
|
||||
}
|
||||
|
||||
// userMap and groupMap caches UID and GID lookups for performance reasons.
|
||||
// The downside is that renaming uname or gname by the OS never takes effect.
|
||||
var userMap, groupMap sync.Map // map[int]string
|
||||
|
||||
func statUnix(fi fs.FileInfo, h *Header, doNameLookups bool) error {
|
||||
func statUnix(fi fs.FileInfo, h *Header) error {
|
||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
h.Uid = int(sys.Uid)
|
||||
h.Gid = int(sys.Gid)
|
||||
if doNameLookups {
|
||||
// Best effort at populating Uname and Gname.
|
||||
// The os/user functions may fail for any number of reasons
|
||||
// (not implemented on that platform, cgo not enabled, etc).
|
||||
if u, ok := userMap.Load(h.Uid); ok {
|
||||
h.Uname = u.(string)
|
||||
} else if u, err := user.LookupId(strconv.Itoa(h.Uid)); err == nil {
|
||||
h.Uname = u.Username
|
||||
userMap.Store(h.Uid, h.Uname)
|
||||
}
|
||||
if g, ok := groupMap.Load(h.Gid); ok {
|
||||
h.Gname = g.(string)
|
||||
} else if g, err := user.LookupGroupId(strconv.Itoa(h.Gid)); err == nil {
|
||||
h.Gname = g.Name
|
||||
groupMap.Store(h.Gid, h.Gname)
|
||||
}
|
||||
|
||||
// Best effort at populating Uname and Gname.
|
||||
// The os/user functions may fail for any number of reasons
|
||||
// (not implemented on that platform, cgo not enabled, etc).
|
||||
if u, ok := userMap.Load(h.Uid); ok {
|
||||
h.Uname = u.(string)
|
||||
} else if u, err := user.LookupId(strconv.Itoa(h.Uid)); err == nil {
|
||||
h.Uname = u.Username
|
||||
userMap.Store(h.Uid, h.Uname)
|
||||
}
|
||||
if g, ok := groupMap.Load(h.Gid); ok {
|
||||
h.Gname = g.(string)
|
||||
} else if g, err := user.LookupGroupId(strconv.Itoa(h.Gid)); err == nil {
|
||||
h.Gname = g.Name
|
||||
groupMap.Store(h.Gid, h.Gname)
|
||||
}
|
||||
|
||||
h.AccessTime = statAtime(sys)
|
||||
h.ChangeTime = statCtime(sys)
|
||||
|
||||
@@ -99,3 +100,12 @@ func statUnix(fi fs.FileInfo, h *Header, doNameLookups bool) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadUidAndGidFunc(fi fs.FileInfo, uid, gid *int) {
|
||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
*uid = int(sys.Uid)
|
||||
*gid = int(sys.Gid)
|
||||
}
|
||||
|
||||
@@ -11,13 +11,11 @@ import (
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -100,6 +98,10 @@ func (f *testFile) Seek(pos int64, whence int) (int64, error) {
|
||||
return f.pos, nil
|
||||
}
|
||||
|
||||
func equalSparseEntries(x, y []sparseEntry) bool {
|
||||
return (len(x) == 0 && len(y) == 0) || reflect.DeepEqual(x, y)
|
||||
}
|
||||
|
||||
func TestSparseEntries(t *testing.T) {
|
||||
vectors := []struct {
|
||||
in []sparseEntry
|
||||
@@ -196,11 +198,11 @@ func TestSparseEntries(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
gotAligned := alignSparseEntries(append([]sparseEntry{}, v.in...), v.size)
|
||||
if !slices.Equal(gotAligned, v.wantAligned) {
|
||||
if !equalSparseEntries(gotAligned, v.wantAligned) {
|
||||
t.Errorf("test %d, alignSparseEntries():\ngot %v\nwant %v", i, gotAligned, v.wantAligned)
|
||||
}
|
||||
gotInverted := invertSparseEntries(append([]sparseEntry{}, v.in...), v.size)
|
||||
if !slices.Equal(gotInverted, v.wantInverted) {
|
||||
if !equalSparseEntries(gotInverted, v.wantInverted) {
|
||||
t.Errorf("test %d, inverseSparseEntries():\ngot %v\nwant %v", i, gotInverted, v.wantInverted)
|
||||
}
|
||||
}
|
||||
@@ -742,7 +744,7 @@ func TestHeaderAllowedFormats(t *testing.T) {
|
||||
if formats != v.formats {
|
||||
t.Errorf("test %d, allowedFormats(): got %v, want %v", i, formats, v.formats)
|
||||
}
|
||||
if formats&FormatPAX > 0 && !maps.Equal(paxHdrs, v.paxHdrs) && !(len(paxHdrs) == 0 && len(v.paxHdrs) == 0) {
|
||||
if formats&FormatPAX > 0 && !reflect.DeepEqual(paxHdrs, v.paxHdrs) && !(len(paxHdrs) == 0 && len(v.paxHdrs) == 0) {
|
||||
t.Errorf("test %d, allowedFormats():\ngot %v\nwant %s", i, paxHdrs, v.paxHdrs)
|
||||
}
|
||||
if (formats != FormatUnknown) && (err != nil) {
|
||||
@@ -847,7 +849,10 @@ func Benchmark(b *testing.B) {
|
||||
|
||||
}
|
||||
|
||||
var _ fileInfoNames = fileInfoNames{}
|
||||
const (
|
||||
testUid = 10
|
||||
testGid = 20
|
||||
)
|
||||
|
||||
type fileInfoNames struct{}
|
||||
|
||||
@@ -875,24 +880,39 @@ func (f *fileInfoNames) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Uname() (string, error) {
|
||||
return "Uname", nil
|
||||
func (f *fileInfoNames) Uname(uid int) (string, error) {
|
||||
if uid == testUid {
|
||||
return "Uname", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Gname() (string, error) {
|
||||
return "Gname", nil
|
||||
func (f *fileInfoNames) Gname(gid int) (string, error) {
|
||||
if gid == testGid {
|
||||
return "Gname", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func TestFileInfoHeaderUseFileInfoNames(t *testing.T) {
|
||||
origLoadUidAndGid := loadUidAndGid
|
||||
defer func() {
|
||||
loadUidAndGid = origLoadUidAndGid
|
||||
}()
|
||||
loadUidAndGid = func(fi fs.FileInfo, uid, gid *int) {
|
||||
*uid = testUid
|
||||
*gid = testGid
|
||||
}
|
||||
|
||||
info := &fileInfoNames{}
|
||||
header, err := FileInfoHeader(info, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if header.Uname != "Uname" {
|
||||
t.Fatalf("header.Uname: got %s, want %s", header.Uname, "Uname")
|
||||
t.Fatalf("header.Uname: got %v, want %v", header.Uname, "Uname")
|
||||
}
|
||||
if header.Gname != "Gname" {
|
||||
t.Fatalf("header.Gname: got %s, want %s", header.Gname, "Gname")
|
||||
t.Fatalf("header.Gname: got %v, want %v", header.Gname, "Gname")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"path"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -170,10 +169,16 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
|
||||
// Write PAX records to the output.
|
||||
isGlobal := hdr.Typeflag == TypeXGlobalHeader
|
||||
if len(paxHdrs) > 0 || isGlobal {
|
||||
// Sort keys for deterministic ordering.
|
||||
var keys []string
|
||||
for k := range paxHdrs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// Write each record to a buffer.
|
||||
var buf strings.Builder
|
||||
// Sort keys for deterministic ordering.
|
||||
for _, k := range slices.Sorted(maps.Keys(paxHdrs)) {
|
||||
for _, k := range keys {
|
||||
rec, err := formatPAXRecord(k, paxHdrs[k])
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -408,7 +413,7 @@ func (tw *Writer) AddFS(fsys fs.FS) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if name == "." {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
info, err := d.Info()
|
||||
@@ -416,7 +421,7 @@ func (tw *Writer) AddFS(fsys fs.FS) error {
|
||||
return err
|
||||
}
|
||||
// TODO(#49580): Handle symlinks when fs.ReadLinkFS is available.
|
||||
if !d.IsDir() && !info.Mode().IsRegular() {
|
||||
if !info.Mode().IsRegular() {
|
||||
return errors.New("tar: cannot add non-regular file")
|
||||
}
|
||||
h, err := FileInfoHeader(info, "")
|
||||
@@ -427,9 +432,6 @@ func (tw *Writer) AddFS(fsys fs.FS) error {
|
||||
if err := tw.WriteHeader(h); err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
f, err := fsys.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -666,7 +668,6 @@ func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
func (sw sparseFileWriter) logicalRemaining() int64 {
|
||||
return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
|
||||
}
|
||||
|
||||
func (sw sparseFileWriter) physicalRemaining() int64 {
|
||||
return sw.fw.physicalRemaining()
|
||||
}
|
||||
|
||||
@@ -10,10 +10,9 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -582,10 +581,10 @@ func TestPaxSymlink(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hdr, err := FileInfoHeader(fileinfo, "")
|
||||
hdr.Typeflag = TypeSymlink
|
||||
if err != nil {
|
||||
t.Fatalf("os.Stat:1 %v", err)
|
||||
}
|
||||
hdr.Typeflag = TypeSymlink
|
||||
// Force a PAX long linkname to be written
|
||||
longLinkname := strings.Repeat("1234567890/1234567890", 10)
|
||||
hdr.Linkname = longLinkname
|
||||
@@ -703,7 +702,7 @@ func TestPaxXattrs(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !maps.Equal(hdr.Xattrs, xattrs) {
|
||||
if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
|
||||
t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
|
||||
hdr.Xattrs, xattrs)
|
||||
}
|
||||
@@ -750,7 +749,7 @@ func TestPaxHeadersSorted(t *testing.T) {
|
||||
bytes.Index(buf.Bytes(), []byte("foo=foo")),
|
||||
bytes.Index(buf.Bytes(), []byte("qux=qux")),
|
||||
}
|
||||
if !slices.IsSorted(indices) {
|
||||
if !sort.IntsAreSorted(indices) {
|
||||
t.Fatal("PAX headers are not sorted")
|
||||
}
|
||||
}
|
||||
@@ -762,10 +761,10 @@ func TestUSTARLongName(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hdr, err := FileInfoHeader(fileinfo, "")
|
||||
hdr.Typeflag = TypeDir
|
||||
if err != nil {
|
||||
t.Fatalf("os.Stat:1 %v", err)
|
||||
}
|
||||
hdr.Typeflag = TypeDir
|
||||
// Force a PAX long name to be written. The name was taken from a practical example
|
||||
// that fails and replaced ever char through numbers to anonymize the sample.
|
||||
longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
|
||||
@@ -1339,40 +1338,29 @@ func TestFileWriter(t *testing.T) {
|
||||
|
||||
func TestWriterAddFS(t *testing.T) {
|
||||
fsys := fstest.MapFS{
|
||||
"emptyfolder": {Mode: 0o755 | os.ModeDir},
|
||||
"file.go": {Data: []byte("hello")},
|
||||
"subfolder/another.go": {Data: []byte("world")},
|
||||
// Notably missing here is the "subfolder" directory. This makes sure even
|
||||
// if we don't have a subfolder directory listed.
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
tw := NewWriter(&buf)
|
||||
if err := tw.AddFS(fsys); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Add subfolder into fsys to match what we'll read from the tar.
|
||||
fsys["subfolder"] = &fstest.MapFile{Mode: 0o555 | os.ModeDir}
|
||||
|
||||
// Test that we can get the files back from the archive
|
||||
tr := NewReader(&buf)
|
||||
|
||||
names := make([]string, 0, len(fsys))
|
||||
for name := range fsys {
|
||||
names = append(names, name)
|
||||
entries, err := fsys.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
entriesLeft := len(fsys)
|
||||
for _, name := range names {
|
||||
entriesLeft--
|
||||
|
||||
entryInfo, err := fsys.Stat(name)
|
||||
if err != nil {
|
||||
t.Fatalf("getting entry info error: %v", err)
|
||||
var curfname string
|
||||
for _, entry := range entries {
|
||||
curfname = entry.Name()
|
||||
if entry.IsDir() {
|
||||
curfname += "/"
|
||||
continue
|
||||
}
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
@@ -1382,33 +1370,22 @@ func TestWriterAddFS(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hdr.Name != name {
|
||||
t.Errorf("test fs has filename %v; archive header has %v",
|
||||
name, hdr.Name)
|
||||
}
|
||||
|
||||
if entryInfo.Mode() != hdr.FileInfo().Mode() {
|
||||
t.Errorf("%s: test fs has mode %v; archive header has %v",
|
||||
name, entryInfo.Mode(), hdr.FileInfo().Mode())
|
||||
}
|
||||
|
||||
if entryInfo.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
origdata := fsys[name].Data
|
||||
|
||||
if hdr.Name != curfname {
|
||||
t.Fatalf("got filename %v, want %v",
|
||||
curfname, hdr.Name)
|
||||
}
|
||||
|
||||
origdata := fsys[curfname].Data
|
||||
if string(data) != string(origdata) {
|
||||
t.Fatalf("test fs has file content %v; archive header has %v",
|
||||
t.Fatalf("got file content %v, want %v",
|
||||
data, origdata)
|
||||
}
|
||||
}
|
||||
if entriesLeft > 0 {
|
||||
t.Fatalf("not all entries are in the archive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriterAddFSNonRegularFiles(t *testing.T) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -699,13 +699,9 @@ func findSignatureInBlock(b []byte) int {
|
||||
if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
|
||||
// n is length of comment
|
||||
n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
|
||||
if n+directoryEndLen+i > len(b) {
|
||||
// Truncated comment.
|
||||
// Some parsers (such as Info-ZIP) ignore the truncated comment
|
||||
// rather than treating it as a hard error.
|
||||
return -1
|
||||
if n+directoryEndLen+i <= len(b) {
|
||||
return i
|
||||
}
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
@@ -862,19 +858,14 @@ func (r *Reader) initFileList() {
|
||||
}
|
||||
}
|
||||
|
||||
slices.SortFunc(r.fileList, func(a, b fileListEntry) int {
|
||||
return fileEntryCompare(a.name, b.name)
|
||||
})
|
||||
sort.Slice(r.fileList, func(i, j int) bool { return fileEntryLess(r.fileList[i].name, r.fileList[j].name) })
|
||||
})
|
||||
}
|
||||
|
||||
func fileEntryCompare(x, y string) int {
|
||||
func fileEntryLess(x, y string) bool {
|
||||
xdir, xelem, _ := split(x)
|
||||
ydir, yelem, _ := split(y)
|
||||
if xdir != ydir {
|
||||
return strings.Compare(xdir, ydir)
|
||||
}
|
||||
return strings.Compare(xelem, yelem)
|
||||
return xdir < ydir || xdir == ydir && xelem < yelem
|
||||
}
|
||||
|
||||
// Open opens the named file in the ZIP archive,
|
||||
@@ -902,8 +893,14 @@ func (r *Reader) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
func split(name string) (dir, elem string, isDir bool) {
|
||||
name, isDir = strings.CutSuffix(name, "/")
|
||||
i := strings.LastIndexByte(name, '/')
|
||||
if len(name) > 0 && name[len(name)-1] == '/' {
|
||||
isDir = true
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
i := len(name) - 1
|
||||
for i >= 0 && name[i] != '/' {
|
||||
i--
|
||||
}
|
||||
if i < 0 {
|
||||
return ".", name, isDir
|
||||
}
|
||||
@@ -919,12 +916,9 @@ func (r *Reader) openLookup(name string) *fileListEntry {
|
||||
|
||||
dir, elem, _ := split(name)
|
||||
files := r.fileList
|
||||
i, _ := slices.BinarySearchFunc(files, dir, func(a fileListEntry, dir string) (ret int) {
|
||||
idir, ielem, _ := split(a.name)
|
||||
if dir != idir {
|
||||
return strings.Compare(idir, dir)
|
||||
}
|
||||
return strings.Compare(ielem, elem)
|
||||
i := sort.Search(len(files), func(i int) bool {
|
||||
idir, ielem, _ := split(files[i].name)
|
||||
return idir > dir || idir == dir && ielem >= elem
|
||||
})
|
||||
if i < len(files) {
|
||||
fname := files[i].name
|
||||
@@ -937,21 +931,13 @@ func (r *Reader) openLookup(name string) *fileListEntry {
|
||||
|
||||
func (r *Reader) openReadDir(dir string) []fileListEntry {
|
||||
files := r.fileList
|
||||
i, _ := slices.BinarySearchFunc(files, dir, func(a fileListEntry, dir string) int {
|
||||
idir, _, _ := split(a.name)
|
||||
if dir != idir {
|
||||
return strings.Compare(idir, dir)
|
||||
}
|
||||
// find the first entry with dir
|
||||
return +1
|
||||
i := sort.Search(len(files), func(i int) bool {
|
||||
idir, _, _ := split(files[i].name)
|
||||
return idir >= dir
|
||||
})
|
||||
j, _ := slices.BinarySearchFunc(files, dir, func(a fileListEntry, dir string) int {
|
||||
jdir, _, _ := split(a.name)
|
||||
if dir != jdir {
|
||||
return strings.Compare(jdir, dir)
|
||||
}
|
||||
// find the last entry with dir
|
||||
return -1
|
||||
j := sort.Search(len(files), func(j int) bool {
|
||||
jdir, _, _ := split(files[j].name)
|
||||
return jdir > dir
|
||||
})
|
||||
return files[i:j]
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
@@ -570,14 +570,6 @@ var tests = []ZipTest{
|
||||
},
|
||||
},
|
||||
},
|
||||
// Issue 66869: Don't skip over an EOCDR with a truncated comment.
|
||||
// The test file sneakily hides a second EOCDR before the first one;
|
||||
// previously we would extract one file ("file") from this archive,
|
||||
// while most other tools would reject the file or extract a different one ("FILE").
|
||||
{
|
||||
Name: "comment-truncated.zip",
|
||||
Error: ErrFormat,
|
||||
},
|
||||
}
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
@@ -912,7 +904,9 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
||||
// type zeros struct{}
|
||||
//
|
||||
// func (zeros) Read(b []byte) (int, error) {
|
||||
// clear(b)
|
||||
// for i := range b {
|
||||
// b[i] = 0
|
||||
// }
|
||||
// return len(b), nil
|
||||
// }
|
||||
//
|
||||
@@ -1274,7 +1268,7 @@ func TestFSWalk(t *testing.T) {
|
||||
} else if !test.wantErr && sawErr {
|
||||
t.Error("unexpected error")
|
||||
}
|
||||
if test.want != nil && !slices.Equal(files, test.want) {
|
||||
if test.want != nil && !reflect.DeepEqual(files, test.want) {
|
||||
t.Errorf("got %v want %v", files, test.want)
|
||||
}
|
||||
})
|
||||
@@ -1580,7 +1574,7 @@ func TestCVE202141772(t *testing.T) {
|
||||
t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
|
||||
}
|
||||
}
|
||||
if !slices.Equal(names, entryNames) {
|
||||
if !reflect.DeepEqual(names, entryNames) {
|
||||
t.Errorf("Unexpected file entries: %q", names)
|
||||
}
|
||||
if _, err := r.Open(""); err == nil {
|
||||
@@ -1693,7 +1687,7 @@ func TestInsecurePaths(t *testing.T) {
|
||||
for _, f := range zr.File {
|
||||
gotPaths = append(gotPaths, f.Name)
|
||||
}
|
||||
if !slices.Equal(gotPaths, []string{path}) {
|
||||
if !reflect.DeepEqual(gotPaths, []string{path}) {
|
||||
t.Errorf("NewReader for archive with file %q: got files %q", path, gotPaths)
|
||||
continue
|
||||
}
|
||||
@@ -1718,7 +1712,7 @@ func TestDisableInsecurePathCheck(t *testing.T) {
|
||||
for _, f := range zr.File {
|
||||
gotPaths = append(gotPaths, f.Name)
|
||||
}
|
||||
if want := []string{name}; !slices.Equal(gotPaths, want) {
|
||||
if want := []string{name}; !reflect.DeepEqual(gotPaths, want) {
|
||||
t.Errorf("NewReader with zipinsecurepath=1: got files %q, want %q", gotPaths, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@ type FileHeader struct {
|
||||
// Deprecated: Use CompressedSize64 instead.
|
||||
CompressedSize uint32
|
||||
|
||||
// UncompressedSize is the uncompressed size of the file in bytes.
|
||||
// UncompressedSize is the compressed size of the file in bytes.
|
||||
// If either the uncompressed or compressed size of the file
|
||||
// does not fit in 32 bits, UncompressedSize is set to ^uint32(0).
|
||||
// does not fit in 32 bits, CompressedSize is set to ^uint32(0).
|
||||
//
|
||||
// Deprecated: Use UncompressedSize64 instead.
|
||||
UncompressedSize uint32
|
||||
|
||||
BIN
src/archive/zip/testdata/comment-truncated.zip
vendored
BIN
src/archive/zip/testdata/comment-truncated.zip
vendored
Binary file not shown.
@@ -213,8 +213,7 @@ func (w *Writer) Close() error {
|
||||
// The name must be a relative path: it must not start with a drive
|
||||
// letter (e.g. C:) or leading slash, and only forward slashes are
|
||||
// allowed. To create a directory instead of a file, add a trailing
|
||||
// slash to the name. Duplicate names will not overwrite previous entries
|
||||
// and are appended to the zip file.
|
||||
// slash to the name.
|
||||
// The file's contents must be written to the [io.Writer] before the next
|
||||
// call to [Writer.Create], [Writer.CreateHeader], or [Writer.Close].
|
||||
func (w *Writer) Create(name string) (io.Writer, error) {
|
||||
@@ -434,10 +433,6 @@ func writeHeader(w io.Writer, h *header) error {
|
||||
// [Writer.CreateHeader], [Writer.CreateRaw], or [Writer.Close].
|
||||
//
|
||||
// In contrast to [Writer.CreateHeader], the bytes passed to Writer are not compressed.
|
||||
//
|
||||
// CreateRaw's argument is stored in w. If the argument is a pointer to the embedded
|
||||
// [FileHeader] in a [File] obtained from a [Reader] created from in-memory data,
|
||||
// then w will refer to all of that memory.
|
||||
func (w *Writer) CreateRaw(fh *FileHeader) (io.Writer, error) {
|
||||
if err := w.prepare(fh); err != nil {
|
||||
return nil, err
|
||||
@@ -476,10 +471,7 @@ func (w *Writer) Copy(f *File) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy the FileHeader so w doesn't store a pointer to the data
|
||||
// of f's entire archive. See #65499.
|
||||
fh := f.FileHeader
|
||||
fw, err := w.CreateRaw(&fh)
|
||||
fw, err := w.CreateRaw(&f.FileHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -505,14 +497,14 @@ func (w *Writer) AddFS(fsys fs.FS) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if name == "." {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() && !info.Mode().IsRegular() {
|
||||
if !info.Mode().IsRegular() {
|
||||
return errors.New("zip: cannot add non-regular file")
|
||||
}
|
||||
h, err := FileInfoHeader(info)
|
||||
@@ -525,9 +517,6 @@ func (w *Writer) AddFS(fsys fs.FS) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
f, err := fsys.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -612,7 +601,7 @@ func (w *fileWriter) writeDataDescriptor() error {
|
||||
}
|
||||
// Write data descriptor. This is more complicated than one would
|
||||
// think, see e.g. comments in zipfile.c:putextended() and
|
||||
// https://bugs.openjdk.org/browse/JDK-7073588.
|
||||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588.
|
||||
// The approach here is to write 8 byte sizes if needed without
|
||||
// adding a zip64 extra in the local header (too late anyway).
|
||||
var buf []byte
|
||||
|
||||
@@ -108,7 +108,7 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
// TestWriterComment is test for EOCD comment read/write.
|
||||
func TestWriterComment(t *testing.T) {
|
||||
tests := []struct {
|
||||
var tests = []struct {
|
||||
comment string
|
||||
ok bool
|
||||
}{
|
||||
@@ -158,7 +158,7 @@ func TestWriterComment(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWriterUTF8(t *testing.T) {
|
||||
utf8Tests := []struct {
|
||||
var utf8Tests = []struct {
|
||||
name string
|
||||
comment string
|
||||
nonUTF8 bool
|
||||
@@ -619,23 +619,26 @@ func TestWriterAddFS(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
w := NewWriter(buf)
|
||||
tests := []WriteTest{
|
||||
{Name: "emptyfolder", Mode: 0o755 | os.ModeDir},
|
||||
{Name: "file.go", Data: []byte("hello"), Mode: 0644},
|
||||
{Name: "subfolder/another.go", Data: []byte("world"), Mode: 0644},
|
||||
// Notably missing here is the "subfolder" directory. This makes sure even
|
||||
// if we don't have a subfolder directory listed.
|
||||
{
|
||||
Name: "file.go",
|
||||
Data: []byte("hello"),
|
||||
Mode: 0644,
|
||||
},
|
||||
{
|
||||
Name: "subfolder/another.go",
|
||||
Data: []byte("world"),
|
||||
Mode: 0644,
|
||||
},
|
||||
}
|
||||
err := w.AddFS(writeTestsToFS(tests))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Add subfolder into fsys to match what we'll read from the tar.
|
||||
tests = append(tests[:2:2], WriteTest{Name: "subfolder", Mode: 0o555 | os.ModeDir}, tests[2])
|
||||
|
||||
// read it back
|
||||
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
|
||||
if err != nil {
|
||||
|
||||
@@ -8,14 +8,13 @@ package zip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -215,8 +214,9 @@ func (r *rleBuffer) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
skipParts, _ := slices.BinarySearchFunc(r.buf, off, func(rb repeatedByte, off int64) int {
|
||||
return cmp.Compare(rb.off+rb.n, off)
|
||||
skipParts := sort.Search(len(r.buf), func(i int) bool {
|
||||
part := &r.buf[i]
|
||||
return part.off+part.n > off
|
||||
})
|
||||
parts := r.buf[skipParts:]
|
||||
if len(parts) > 0 {
|
||||
@@ -814,6 +814,8 @@ func TestSuffixSaver(t *testing.T) {
|
||||
type zeros struct{}
|
||||
|
||||
func (zeros) Read(p []byte) (int, error) {
|
||||
clear(p)
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
@@ -29,9 +29,6 @@ var (
|
||||
// Buffered input.
|
||||
|
||||
// Reader implements buffering for an io.Reader object.
|
||||
// A new Reader is created by calling [NewReader] or [NewReaderSize];
|
||||
// alternatively the zero value of a Reader may be used after calling [Reset]
|
||||
// on it.
|
||||
type Reader struct {
|
||||
buf []byte
|
||||
rd io.Reader // reader provided by the client
|
||||
@@ -133,10 +130,9 @@ func (b *Reader) readErr() error {
|
||||
}
|
||||
|
||||
// Peek returns the next n bytes without advancing the reader. The bytes stop
|
||||
// being valid at the next read call. If necessary, Peek will read more bytes
|
||||
// into the buffer in order to make n bytes available. If Peek returns fewer
|
||||
// than n bytes, it also returns an error explaining why the read is short.
|
||||
// The error is [ErrBufferFull] if n is larger than b's buffer size.
|
||||
// being valid at the next read call. If Peek returns fewer than n bytes, it
|
||||
// also returns an error explaining why the read is short. The error is
|
||||
// [ErrBufferFull] if n is larger than b's buffer size.
|
||||
//
|
||||
// Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding
|
||||
// until the next read operation.
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/asan"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
@@ -586,9 +585,6 @@ func TestWriteInvalidRune(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReadStringAllocs(t *testing.T) {
|
||||
if asan.Enabled {
|
||||
t.Skip("test allocates more with -asan; see #70079")
|
||||
}
|
||||
r := strings.NewReader(" foo foo 42 42 42 42 42 42 42 42 4.2 4.2 4.2 4.2\n")
|
||||
buf := NewReader(r)
|
||||
allocs := testing.AllocsPerRun(100, func() {
|
||||
@@ -640,7 +636,7 @@ func TestWriter(t *testing.T) {
|
||||
for l := 0; l < len(written); l++ {
|
||||
if written[l] != data[l] {
|
||||
t.Errorf("wrong bytes written")
|
||||
t.Errorf("want=%q", data[:len(written)])
|
||||
t.Errorf("want=%q", data[0:len(written)])
|
||||
t.Errorf("have=%q", written)
|
||||
}
|
||||
}
|
||||
@@ -939,6 +935,7 @@ func (t *testReader) Read(buf []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func testReadLine(t *testing.T, input []byte) {
|
||||
//for stride := 1; stride < len(input); stride++ {
|
||||
for stride := 1; stride < 2; stride++ {
|
||||
done := 0
|
||||
reader := testReader{input, stride}
|
||||
|
||||
@@ -33,33 +33,6 @@ func ExampleWriter_AvailableBuffer() {
|
||||
// Output: 1 2 3 4
|
||||
}
|
||||
|
||||
// ExampleWriter_ReadFrom demonstrates how to use the ReadFrom method of Writer.
|
||||
func ExampleWriter_ReadFrom() {
|
||||
var buf bytes.Buffer
|
||||
writer := bufio.NewWriter(&buf)
|
||||
|
||||
data := "Hello, world!\nThis is a ReadFrom example."
|
||||
reader := strings.NewReader(data)
|
||||
|
||||
n, err := writer.ReadFrom(reader)
|
||||
if err != nil {
|
||||
fmt.Println("ReadFrom Error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = writer.Flush(); err != nil {
|
||||
fmt.Println("Flush Error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Bytes written:", n)
|
||||
fmt.Println("Buffer contents:", buf.String())
|
||||
// Output:
|
||||
// Bytes written: 41
|
||||
// Buffer contents: Hello, world!
|
||||
// This is a ReadFrom example.
|
||||
}
|
||||
|
||||
// The simplest use of a Scanner, to read standard input as a set of lines.
|
||||
func ExampleScanner_lines() {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
@@ -41,7 +41,7 @@ GOROOT="$(cd .. && pwd)"
|
||||
|
||||
gettargets() {
|
||||
../bin/go tool dist list | sed -e 's|/|-|' |
|
||||
grep -E -v '^(android|ios)' # need C toolchain even for cross-compiling
|
||||
egrep -v '^(android|ios)' # need C toolchain even for cross-compiling
|
||||
echo linux-arm-arm5
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,10 @@ type int32 int32
|
||||
// Range: -9223372036854775808 through 9223372036854775807.
|
||||
type int64 int64
|
||||
|
||||
// float32 is the set of all IEEE 754 32-bit floating-point numbers.
|
||||
// float32 is the set of all IEEE-754 32-bit floating-point numbers.
|
||||
type float32 float32
|
||||
|
||||
// float64 is the set of all IEEE 754 64-bit floating-point numbers.
|
||||
// float64 is the set of all IEEE-754 64-bit floating-point numbers.
|
||||
type float64 float64
|
||||
|
||||
// complex64 is the set of all complex numbers with float32 real and
|
||||
|
||||
@@ -62,7 +62,7 @@ func (b *Buffer) AvailableBuffer() []byte { return b.buf[len(b.buf):] }
|
||||
// String returns the contents of the unread portion of the buffer
|
||||
// as a string. If the [Buffer] is a nil pointer, it returns "<nil>".
|
||||
//
|
||||
// To build strings more efficiently, see the [strings.Builder] type.
|
||||
// To build strings more efficiently, see the strings.Builder type.
|
||||
func (b *Buffer) String() string {
|
||||
if b == nil {
|
||||
// Special case, useful in debugging.
|
||||
@@ -193,9 +193,9 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
|
||||
return copy(b.buf[m:], s), nil
|
||||
}
|
||||
|
||||
// MinRead is the minimum slice size passed to a [Buffer.Read] call by
|
||||
// MinRead is the minimum slice size passed to a Read call by
|
||||
// [Buffer.ReadFrom]. As long as the [Buffer] has at least MinRead bytes beyond
|
||||
// what is required to hold the contents of r, [Buffer.ReadFrom] will not grow the
|
||||
// what is required to hold the contents of r, ReadFrom will not grow the
|
||||
// underlying buffer.
|
||||
const MinRead = 512
|
||||
|
||||
@@ -247,13 +247,13 @@ func growSlice(b []byte, n int) []byte {
|
||||
c = 2 * cap(b)
|
||||
}
|
||||
b2 := append([]byte(nil), make([]byte, c)...)
|
||||
i := copy(b2, b)
|
||||
return b2[:i]
|
||||
copy(b2, b)
|
||||
return b2[:len(b)]
|
||||
}
|
||||
|
||||
// WriteTo writes data to w until the buffer is drained or an error occurs.
|
||||
// The return value n is the number of bytes written; it always fits into an
|
||||
// int, but it is int64 to match the [io.WriterTo] interface. Any error
|
||||
// int, but it is int64 to match the io.WriterTo interface. Any error
|
||||
// encountered during the write is also returned.
|
||||
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
|
||||
b.lastRead = opInvalid
|
||||
@@ -313,7 +313,7 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
|
||||
|
||||
// Read reads the next len(p) bytes from the buffer or until the buffer
|
||||
// is drained. The return value n is the number of bytes read. If the
|
||||
// buffer has no data to return, err is [io.EOF] (unless len(p) is zero);
|
||||
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
|
||||
// otherwise it is nil.
|
||||
func (b *Buffer) Read(p []byte) (n int, err error) {
|
||||
b.lastRead = opInvalid
|
||||
@@ -352,7 +352,7 @@ func (b *Buffer) Next(n int) []byte {
|
||||
}
|
||||
|
||||
// ReadByte reads and returns the next byte from the buffer.
|
||||
// If no byte is available, it returns error [io.EOF].
|
||||
// If no byte is available, it returns error io.EOF.
|
||||
func (b *Buffer) ReadByte() (byte, error) {
|
||||
if b.empty() {
|
||||
// Buffer is empty, reset to recover space.
|
||||
@@ -424,7 +424,7 @@ func (b *Buffer) UnreadByte() error {
|
||||
// ReadBytes reads until the first occurrence of delim in the input,
|
||||
// returning a slice containing the data up to and including the delimiter.
|
||||
// If ReadBytes encounters an error before finding a delimiter,
|
||||
// it returns the data read before the error and the error itself (often [io.EOF]).
|
||||
// it returns the data read before the error and the error itself (often io.EOF).
|
||||
// ReadBytes returns err != nil if and only if the returned data does not end in
|
||||
// delim.
|
||||
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
|
||||
@@ -452,7 +452,7 @@ func (b *Buffer) readSlice(delim byte) (line []byte, err error) {
|
||||
// ReadString reads until the first occurrence of delim in the input,
|
||||
// returning a string containing the data up to and including the delimiter.
|
||||
// If ReadString encounters an error before finding a delimiter,
|
||||
// it returns the data read before the error and the error itself (often [io.EOF]).
|
||||
// it returns the data read before the error and the error itself (often io.EOF).
|
||||
// ReadString returns err != nil if and only if the returned data does not end
|
||||
// in delim.
|
||||
func (b *Buffer) ReadString(delim byte) (line string, err error) {
|
||||
|
||||
@@ -7,7 +7,6 @@ package bytes_test
|
||||
import (
|
||||
. "bytes"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
@@ -95,22 +94,6 @@ func TestNewBuffer(t *testing.T) {
|
||||
check(t, "NewBuffer", buf, testString)
|
||||
}
|
||||
|
||||
var buf Buffer
|
||||
|
||||
// Calling NewBuffer and immediately shallow copying the Buffer struct
|
||||
// should not result in any allocations.
|
||||
// This can be used to reset the underlying []byte of an existing Buffer.
|
||||
func TestNewBufferShallow(t *testing.T) {
|
||||
testenv.SkipIfOptimizationOff(t)
|
||||
n := testing.AllocsPerRun(1000, func() {
|
||||
buf = *NewBuffer(testBytes)
|
||||
})
|
||||
if n > 0 {
|
||||
t.Errorf("allocations occurred while shallow copying")
|
||||
}
|
||||
check(t, "NewBuffer", &buf, testString)
|
||||
}
|
||||
|
||||
func TestNewBufferString(t *testing.T) {
|
||||
buf := NewBufferString(testString)
|
||||
check(t, "NewBufferString", buf, testString)
|
||||
@@ -213,7 +196,7 @@ func TestLargeByteWrites(t *testing.T) {
|
||||
func TestLargeStringReads(t *testing.T) {
|
||||
var buf Buffer
|
||||
for i := 3; i < 30; i += 3 {
|
||||
s := fillString(t, "TestLargeReads (1)", &buf, "", 5, testString[:len(testString)/i])
|
||||
s := fillString(t, "TestLargeReads (1)", &buf, "", 5, testString[0:len(testString)/i])
|
||||
empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(testString)))
|
||||
}
|
||||
check(t, "TestLargeStringReads (3)", &buf, "")
|
||||
@@ -222,7 +205,7 @@ func TestLargeStringReads(t *testing.T) {
|
||||
func TestLargeByteReads(t *testing.T) {
|
||||
var buf Buffer
|
||||
for i := 3; i < 30; i += 3 {
|
||||
s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, testBytes[:len(testBytes)/i])
|
||||
s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
|
||||
empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(testString)))
|
||||
}
|
||||
check(t, "TestLargeByteReads (3)", &buf, "")
|
||||
@@ -274,7 +257,7 @@ func TestNil(t *testing.T) {
|
||||
func TestReadFrom(t *testing.T) {
|
||||
var buf Buffer
|
||||
for i := 3; i < 30; i += 3 {
|
||||
s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, testBytes[:len(testBytes)/i])
|
||||
s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
|
||||
var b Buffer
|
||||
b.ReadFrom(&buf)
|
||||
empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(testString)))
|
||||
@@ -337,7 +320,7 @@ func TestReadFromNegativeReader(t *testing.T) {
|
||||
func TestWriteTo(t *testing.T) {
|
||||
var buf Buffer
|
||||
for i := 3; i < 30; i += 3 {
|
||||
s := fillBytes(t, "TestWriteTo (1)", &buf, "", 5, testBytes[:len(testBytes)/i])
|
||||
s := fillBytes(t, "TestWriteTo (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
|
||||
var b Buffer
|
||||
buf.WriteTo(&b)
|
||||
empty(t, "TestWriteTo (2)", &b, s, make([]byte, len(testString)))
|
||||
|
||||
@@ -8,10 +8,8 @@ package bytes
|
||||
|
||||
import (
|
||||
"internal/bytealg"
|
||||
"math/bits"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
_ "unsafe" // for linkname
|
||||
)
|
||||
|
||||
// Equal reports whether a and b
|
||||
@@ -134,10 +132,9 @@ func LastIndexByte(s []byte, c byte) int {
|
||||
// IndexRune interprets s as a sequence of UTF-8-encoded code points.
|
||||
// It returns the byte index of the first occurrence in s of the given rune.
|
||||
// It returns -1 if rune is not present in s.
|
||||
// If r is [utf8.RuneError], it returns the first instance of any
|
||||
// If r is utf8.RuneError, it returns the first instance of any
|
||||
// invalid UTF-8 byte sequence.
|
||||
func IndexRune(s []byte, r rune) int {
|
||||
const haveFastIndex = bytealg.MaxBruteForce > 0
|
||||
switch {
|
||||
case 0 <= r && r < utf8.RuneSelf:
|
||||
return IndexByte(s, byte(r))
|
||||
@@ -153,64 +150,9 @@ func IndexRune(s []byte, r rune) int {
|
||||
case !utf8.ValidRune(r):
|
||||
return -1
|
||||
default:
|
||||
// Search for rune r using the last byte of its UTF-8 encoded form.
|
||||
// The distribution of the last byte is more uniform compared to the
|
||||
// first byte which has a 78% chance of being [240, 243, 244].
|
||||
var b [utf8.UTFMax]byte
|
||||
n := utf8.EncodeRune(b[:], r)
|
||||
last := n - 1
|
||||
i := last
|
||||
fails := 0
|
||||
for i < len(s) {
|
||||
if s[i] != b[last] {
|
||||
o := IndexByte(s[i+1:], b[last])
|
||||
if o < 0 {
|
||||
return -1
|
||||
}
|
||||
i += o + 1
|
||||
}
|
||||
// Step backwards comparing bytes.
|
||||
for j := 1; j < n; j++ {
|
||||
if s[i-j] != b[last-j] {
|
||||
goto next
|
||||
}
|
||||
}
|
||||
return i - last
|
||||
next:
|
||||
fails++
|
||||
i++
|
||||
if (haveFastIndex && fails > bytealg.Cutover(i)) && i < len(s) ||
|
||||
(!haveFastIndex && fails >= 4+i>>4 && i < len(s)) {
|
||||
goto fallback
|
||||
}
|
||||
}
|
||||
return -1
|
||||
|
||||
fallback:
|
||||
// Switch to bytealg.Index, if available, or a brute force search when
|
||||
// IndexByte returns too many false positives.
|
||||
if haveFastIndex {
|
||||
if j := bytealg.Index(s[i-last:], b[:n]); j >= 0 {
|
||||
return i + j - last
|
||||
}
|
||||
} else {
|
||||
// If bytealg.Index is not available a brute force search is
|
||||
// ~1.5-3x faster than Rabin-Karp since n is small.
|
||||
c0 := b[last]
|
||||
c1 := b[last-1] // There are at least 2 chars to match
|
||||
loop:
|
||||
for ; i < len(s); i++ {
|
||||
if s[i] == c0 && s[i-1] == c1 {
|
||||
for k := 2; k < n; k++ {
|
||||
if s[i-k] != b[last-k] {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
return i - last
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
return Index(s, b[:n])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,20 +354,22 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
|
||||
// the subslices between those separators.
|
||||
// If sep is empty, SplitN splits after each UTF-8 sequence.
|
||||
// The count determines the number of subslices to return:
|
||||
// - n > 0: at most n subslices; the last subslice will be the unsplit remainder;
|
||||
// - n == 0: the result is nil (zero subslices);
|
||||
// - n < 0: all subslices.
|
||||
//
|
||||
// To split around the first instance of a separator, see [Cut].
|
||||
// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
|
||||
// n == 0: the result is nil (zero subslices)
|
||||
// n < 0: all subslices
|
||||
//
|
||||
// To split around the first instance of a separator, see Cut.
|
||||
func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
|
||||
|
||||
// SplitAfterN slices s into subslices after each instance of sep and
|
||||
// returns a slice of those subslices.
|
||||
// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
|
||||
// The count determines the number of subslices to return:
|
||||
// - n > 0: at most n subslices; the last subslice will be the unsplit remainder;
|
||||
// - n == 0: the result is nil (zero subslices);
|
||||
// - n < 0: all subslices.
|
||||
//
|
||||
// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
|
||||
// n == 0: the result is nil (zero subslices)
|
||||
// n < 0: all subslices
|
||||
func SplitAfterN(s, sep []byte, n int) [][]byte {
|
||||
return genSplit(s, sep, len(sep), n)
|
||||
}
|
||||
@@ -435,7 +379,7 @@ func SplitAfterN(s, sep []byte, n int) [][]byte {
|
||||
// If sep is empty, Split splits after each UTF-8 sequence.
|
||||
// It is equivalent to SplitN with a count of -1.
|
||||
//
|
||||
// To split around the first instance of a separator, see [Cut].
|
||||
// To split around the first instance of a separator, see Cut.
|
||||
func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
|
||||
|
||||
// SplitAfter slices s into all subslices after each instance of sep and
|
||||
@@ -450,7 +394,7 @@ var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
|
||||
|
||||
// Fields interprets s as a sequence of UTF-8-encoded code points.
|
||||
// It splits the slice s around each instance of one or more consecutive white space
|
||||
// characters, as defined by [unicode.IsSpace], returning a slice of subslices of s or an
|
||||
// characters, as defined by unicode.IsSpace, returning a slice of subslices of s or an
|
||||
// empty slice if s contains only white space.
|
||||
func Fields(s []byte) [][]byte {
|
||||
// First count the fields.
|
||||
@@ -581,7 +525,7 @@ func Join(s [][]byte, sep []byte) []byte {
|
||||
n += len(v)
|
||||
}
|
||||
|
||||
b := bytealg.MakeNoZero(n)[:n:n]
|
||||
b := bytealg.MakeNoZero(n)
|
||||
bp := copy(b, s[0])
|
||||
for _, v := range s[1:] {
|
||||
bp += copy(b[bp:], sep)
|
||||
@@ -592,7 +536,7 @@ func Join(s [][]byte, sep []byte) []byte {
|
||||
|
||||
// HasPrefix reports whether the byte slice s begins with prefix.
|
||||
func HasPrefix(s, prefix []byte) bool {
|
||||
return len(s) >= len(prefix) && Equal(s[:len(prefix)], prefix)
|
||||
return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
|
||||
}
|
||||
|
||||
// HasSuffix reports whether the byte slice s ends with suffix.
|
||||
@@ -624,18 +568,6 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// Despite being an exported symbol,
|
||||
// Repeat is linknamed by widely used packages.
|
||||
// Notable members of the hall of shame include:
|
||||
// - gitee.com/quant1x/num
|
||||
//
|
||||
// Do not remove or change the type signature.
|
||||
// See go.dev/issue/67401.
|
||||
//
|
||||
// Note that this comment is not part of the doc comment.
|
||||
//
|
||||
//go:linkname Repeat
|
||||
|
||||
// Repeat returns a new byte slice consisting of count copies of b.
|
||||
//
|
||||
// It panics if count is negative or if the result of (len(b) * count)
|
||||
@@ -651,11 +583,10 @@ func Repeat(b []byte, count int) []byte {
|
||||
if count < 0 {
|
||||
panic("bytes: negative Repeat count")
|
||||
}
|
||||
hi, lo := bits.Mul(uint(len(b)), uint(count))
|
||||
if hi > 0 || lo > uint(maxInt) {
|
||||
if len(b) >= maxInt/count {
|
||||
panic("bytes: Repeat output length overflow")
|
||||
}
|
||||
n := int(lo) // lo = len(b) * count
|
||||
n := len(b) * count
|
||||
|
||||
if len(b) == 0 {
|
||||
return []byte{}
|
||||
@@ -679,10 +610,13 @@ func Repeat(b []byte, count int) []byte {
|
||||
chunkMax = len(b)
|
||||
}
|
||||
}
|
||||
nb := bytealg.MakeNoZero(n)[:n:n]
|
||||
nb := bytealg.MakeNoZero(n)
|
||||
bp := copy(nb, b)
|
||||
for bp < n {
|
||||
chunk := min(bp, chunkMax)
|
||||
chunk := bp
|
||||
if chunk > chunkMax {
|
||||
chunk = chunkMax
|
||||
}
|
||||
bp += copy(nb[bp:], nb[:chunk])
|
||||
}
|
||||
return nb
|
||||
@@ -706,7 +640,7 @@ func ToUpper(s []byte) []byte {
|
||||
// Just return a copy.
|
||||
return append([]byte(""), s...)
|
||||
}
|
||||
b := bytealg.MakeNoZero(len(s))[:len(s):len(s)]
|
||||
b := bytealg.MakeNoZero(len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if 'a' <= c && c <= 'z' {
|
||||
@@ -736,7 +670,7 @@ func ToLower(s []byte) []byte {
|
||||
if !hasUpper {
|
||||
return append([]byte(""), s...)
|
||||
}
|
||||
b := bytealg.MakeNoZero(len(s))[:len(s):len(s)]
|
||||
b := bytealg.MakeNoZero(len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2024 The Go 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
|
||||
|
||||
package bytes_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIssue65571(t *testing.T) {
|
||||
b := make([]byte, 1<<31+1)
|
||||
b[1<<31] = 1
|
||||
i := bytes.IndexByte(b, 1)
|
||||
if i != 1<<31 {
|
||||
t.Errorf("IndexByte(b, 1) = %d; want %d", i, 1<<31)
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,9 @@ import (
|
||||
. "bytes"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"iter"
|
||||
"math"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode"
|
||||
@@ -19,6 +18,18 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func eq(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func sliceOfString(s [][]byte) []string {
|
||||
result := make([]string, len(s))
|
||||
for i, v := range s {
|
||||
@@ -27,37 +38,6 @@ func sliceOfString(s [][]byte) []string {
|
||||
return result
|
||||
}
|
||||
|
||||
func collect(t *testing.T, seq iter.Seq[[]byte]) [][]byte {
|
||||
out := slices.Collect(seq)
|
||||
out1 := slices.Collect(seq)
|
||||
if !slices.Equal(sliceOfString(out), sliceOfString(out1)) {
|
||||
t.Fatalf("inconsistent seq:\n%s\n%s", out, out1)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type LinesTest struct {
|
||||
a string
|
||||
b []string
|
||||
}
|
||||
|
||||
var linesTests = []LinesTest{
|
||||
{a: "abc\nabc\n", b: []string{"abc\n", "abc\n"}},
|
||||
{a: "abc\r\nabc", b: []string{"abc\r\n", "abc"}},
|
||||
{a: "abc\r\n", b: []string{"abc\r\n"}},
|
||||
{a: "\nabc", b: []string{"\n", "abc"}},
|
||||
{a: "\nabc\n\n", b: []string{"\n", "abc\n", "\n"}},
|
||||
}
|
||||
|
||||
func TestLines(t *testing.T) {
|
||||
for _, s := range linesTests {
|
||||
result := sliceOfString(slices.Collect(Lines([]byte(s.a))))
|
||||
if !slices.Equal(result, s.b) {
|
||||
t.Errorf(`slices.Collect(Lines(%q)) = %q; want %q`, s.a, result, s.b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For ease of reading, the test cases use strings that are converted to byte
|
||||
// slices before invoking the functions.
|
||||
|
||||
@@ -197,11 +177,6 @@ var indexTests = []BinOpTest{
|
||||
{"oxoxoxoxoxoxoxoxoxoxoxox", "oy", -1},
|
||||
// test fallback to Rabin-Karp.
|
||||
{"000000000000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000001", 5},
|
||||
// test fallback to IndexRune
|
||||
{"oxoxoxoxoxoxoxoxoxoxox☺", "☺", 22},
|
||||
// invalid UTF-8 byte sequence (must be longer than bytealg.MaxBruteForce to
|
||||
// test that we don't use IndexRune)
|
||||
{"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx\xed\x9f\xc0", "\xed\x9f\xc0", 105},
|
||||
}
|
||||
|
||||
var lastIndexTests = []BinOpTest{
|
||||
@@ -450,31 +425,6 @@ func TestIndexRune(t *testing.T) {
|
||||
{"some_text=some_value", '=', 9},
|
||||
{"☺a", 'a', 3},
|
||||
{"a☻☺b", '☺', 4},
|
||||
{"𠀳𠀗𠀾𠁄𠀧𠁆𠁂𠀫𠀖𠀪𠀲𠀴𠁀𠀨𠀿", '𠀿', 56},
|
||||
|
||||
// 2 bytes
|
||||
{"ӆ", 'ӆ', 0},
|
||||
{"a", 'ӆ', -1},
|
||||
{" ӆ", 'ӆ', 2},
|
||||
{" a", 'ӆ', -1},
|
||||
{strings.Repeat("ц", 64) + "ӆ", 'ӆ', 128}, // test cutover
|
||||
{strings.Repeat("ц", 64), 'ӆ', -1},
|
||||
|
||||
// 3 bytes
|
||||
{"Ꚁ", 'Ꚁ', 0},
|
||||
{"a", 'Ꚁ', -1},
|
||||
{" Ꚁ", 'Ꚁ', 2},
|
||||
{" a", 'Ꚁ', -1},
|
||||
{strings.Repeat("Ꙁ", 64) + "Ꚁ", 'Ꚁ', 192}, // test cutover
|
||||
{strings.Repeat("Ꙁ", 64) + "Ꚁ", '䚀', -1}, // 'Ꚁ' and '䚀' share the same last two bytes
|
||||
|
||||
// 4 bytes
|
||||
{"𡌀", '𡌀', 0},
|
||||
{"a", '𡌀', -1},
|
||||
{" 𡌀", '𡌀', 2},
|
||||
{" a", '𡌀', -1},
|
||||
{strings.Repeat("𡋀", 64) + "𡌀", '𡌀', 256}, // test cutover
|
||||
{strings.Repeat("𡋀", 64) + "𡌀", '𣌀', -1}, // '𡌀' and '𣌀' share the same last two bytes
|
||||
|
||||
// RuneError should match any invalid UTF-8 byte sequence.
|
||||
{"<22>", '<27>', 0},
|
||||
@@ -488,13 +438,6 @@ func TestIndexRune(t *testing.T) {
|
||||
{"a☺b☻c☹d\xe2\x98<39>\xff<66>\xed\xa0\x80", -1, -1},
|
||||
{"a☺b☻c☹d\xe2\x98<39>\xff<66>\xed\xa0\x80", 0xD800, -1}, // Surrogate pair
|
||||
{"a☺b☻c☹d\xe2\x98<39>\xff<66>\xed\xa0\x80", utf8.MaxRune + 1, -1},
|
||||
|
||||
// Test the cutover to bytealg.Index when it is triggered in
|
||||
// the middle of rune that contains consecutive runs of equal bytes.
|
||||
{"aaaaaKKKK\U000bc104", '\U000bc104', 17}, // cutover: (n + 16) / 8
|
||||
{"aaaaaKKKK鄄", '鄄', 17},
|
||||
{"aaKKKKKa\U000bc104", '\U000bc104', 18}, // cutover: 4 + n>>4
|
||||
{"aaKKKKKa鄄", '鄄', 18},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := IndexRune([]byte(tt.in), tt.rune); got != tt.want {
|
||||
@@ -642,21 +585,6 @@ func BenchmarkIndexRuneASCII(b *testing.B) {
|
||||
benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune))
|
||||
}
|
||||
|
||||
func BenchmarkIndexRuneUnicode(b *testing.B) {
|
||||
b.Run("Latin", func(b *testing.B) {
|
||||
// Latin is mostly 1, 2, 3 byte runes.
|
||||
benchBytes(b, indexSizes, bmIndexRuneUnicode(unicode.Latin, 'é'))
|
||||
})
|
||||
b.Run("Cyrillic", func(b *testing.B) {
|
||||
// Cyrillic is mostly 2 and 3 byte runes.
|
||||
benchBytes(b, indexSizes, bmIndexRuneUnicode(unicode.Cyrillic, 'Ꙁ'))
|
||||
})
|
||||
b.Run("Han", func(b *testing.B) {
|
||||
// Han consists only of 3 and 4 byte runes.
|
||||
benchBytes(b, indexSizes, bmIndexRuneUnicode(unicode.Han, '𠀿'))
|
||||
})
|
||||
}
|
||||
|
||||
func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) {
|
||||
return func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
@@ -687,61 +615,6 @@ func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) {
|
||||
}
|
||||
}
|
||||
|
||||
func bmIndexRuneUnicode(rt *unicode.RangeTable, needle rune) func(b *testing.B, n int) {
|
||||
var rs []rune
|
||||
for _, r16 := range rt.R16 {
|
||||
for r := rune(r16.Lo); r <= rune(r16.Hi); r += rune(r16.Stride) {
|
||||
if r != needle {
|
||||
rs = append(rs, rune(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, r32 := range rt.R32 {
|
||||
for r := rune(r32.Lo); r <= rune(r32.Hi); r += rune(r32.Stride) {
|
||||
if r != needle {
|
||||
rs = append(rs, rune(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Shuffle the runes so that they are not in descending order.
|
||||
// The sort is deterministic since this is used for benchmarks,
|
||||
// which need to be repeatable.
|
||||
rr := rand.New(rand.NewSource(1))
|
||||
rr.Shuffle(len(rs), func(i, j int) {
|
||||
rs[i], rs[j] = rs[j], rs[i]
|
||||
})
|
||||
uchars := string(rs)
|
||||
|
||||
return func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
o := copy(buf, uchars)
|
||||
for o < len(buf) {
|
||||
o += copy(buf[o:], uchars)
|
||||
}
|
||||
|
||||
// Make space for the needle rune at the end of buf.
|
||||
m := utf8.RuneLen(needle)
|
||||
for o := m; o > 0; {
|
||||
_, sz := utf8.DecodeLastRune(buf)
|
||||
copy(buf[len(buf)-sz:], "\x00\x00\x00\x00")
|
||||
buf = buf[:len(buf)-sz]
|
||||
o -= sz
|
||||
}
|
||||
buf = utf8.AppendRune(buf[:n-m], needle)
|
||||
|
||||
n -= m // adjust for rune len
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := IndexRune(buf, needle)
|
||||
if j != n {
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
for i := range buf {
|
||||
buf[i] = '\x00'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEqual(b *testing.B) {
|
||||
b.Run("0", func(b *testing.B) {
|
||||
var buf [4]byte
|
||||
@@ -756,11 +629,6 @@ func BenchmarkEqual(b *testing.B) {
|
||||
})
|
||||
|
||||
sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20}
|
||||
|
||||
b.Run("same", func(b *testing.B) {
|
||||
benchBytes(b, sizes, bmEqual(func(a, b []byte) bool { return Equal(a, a) }))
|
||||
})
|
||||
|
||||
benchBytes(b, sizes, bmEqual(Equal))
|
||||
}
|
||||
|
||||
@@ -935,18 +803,10 @@ func TestSplit(t *testing.T) {
|
||||
}
|
||||
|
||||
result := sliceOfString(a)
|
||||
if !slices.Equal(result, tt.a) {
|
||||
if !eq(result, tt.a) {
|
||||
t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
|
||||
continue
|
||||
}
|
||||
|
||||
if tt.n < 0 {
|
||||
b := sliceOfString(slices.Collect(SplitSeq([]byte(tt.s), []byte(tt.sep))))
|
||||
if !slices.Equal(b, tt.a) {
|
||||
t.Errorf(`collect(SplitSeq(%q, %q)) = %v; want %v`, tt.s, tt.sep, b, tt.a)
|
||||
}
|
||||
}
|
||||
|
||||
if tt.n == 0 || len(a) == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -960,8 +820,8 @@ func TestSplit(t *testing.T) {
|
||||
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
|
||||
}
|
||||
if tt.n < 0 {
|
||||
b := sliceOfString(Split([]byte(tt.s), []byte(tt.sep)))
|
||||
if !slices.Equal(result, b) {
|
||||
b := Split([]byte(tt.s), []byte(tt.sep))
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
|
||||
}
|
||||
}
|
||||
@@ -1001,18 +861,11 @@ func TestSplitAfter(t *testing.T) {
|
||||
}
|
||||
|
||||
result := sliceOfString(a)
|
||||
if !slices.Equal(result, tt.a) {
|
||||
if !eq(result, tt.a) {
|
||||
t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
|
||||
continue
|
||||
}
|
||||
|
||||
if tt.n < 0 {
|
||||
b := sliceOfString(slices.Collect(SplitAfterSeq([]byte(tt.s), []byte(tt.sep))))
|
||||
if !slices.Equal(b, tt.a) {
|
||||
t.Errorf(`collect(SplitAfterSeq(%q, %q)) = %v; want %v`, tt.s, tt.sep, b, tt.a)
|
||||
}
|
||||
}
|
||||
|
||||
if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
|
||||
t.Errorf("last appended result was %s; want %s", x, want)
|
||||
}
|
||||
@@ -1022,8 +875,8 @@ func TestSplitAfter(t *testing.T) {
|
||||
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
|
||||
}
|
||||
if tt.n < 0 {
|
||||
b := sliceOfString(SplitAfter([]byte(tt.s), []byte(tt.sep)))
|
||||
if !slices.Equal(result, b) {
|
||||
b := SplitAfter([]byte(tt.s), []byte(tt.sep))
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
|
||||
}
|
||||
}
|
||||
@@ -1061,16 +914,11 @@ func TestFields(t *testing.T) {
|
||||
}
|
||||
|
||||
result := sliceOfString(a)
|
||||
if !slices.Equal(result, tt.a) {
|
||||
if !eq(result, tt.a) {
|
||||
t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
|
||||
continue
|
||||
}
|
||||
|
||||
result2 := sliceOfString(collect(t, FieldsSeq([]byte(tt.s))))
|
||||
if !slices.Equal(result2, tt.a) {
|
||||
t.Errorf(`collect(FieldsSeq(%q)) = %v; want %v`, tt.s, result2, tt.a)
|
||||
}
|
||||
|
||||
if string(b) != tt.s {
|
||||
t.Errorf("slice changed to %s; want %s", string(b), tt.s)
|
||||
}
|
||||
@@ -1086,7 +934,7 @@ func TestFieldsFunc(t *testing.T) {
|
||||
for _, tt := range fieldstests {
|
||||
a := FieldsFunc([]byte(tt.s), unicode.IsSpace)
|
||||
result := sliceOfString(a)
|
||||
if !slices.Equal(result, tt.a) {
|
||||
if !eq(result, tt.a) {
|
||||
t.Errorf("FieldsFunc(%q, unicode.IsSpace) = %v; want %v", tt.s, a, tt.a)
|
||||
continue
|
||||
}
|
||||
@@ -1109,15 +957,10 @@ func TestFieldsFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
result := sliceOfString(a)
|
||||
if !slices.Equal(result, tt.a) {
|
||||
if !eq(result, tt.a) {
|
||||
t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
|
||||
}
|
||||
|
||||
result2 := sliceOfString(collect(t, FieldsFuncSeq([]byte(tt.s), pred)))
|
||||
if !slices.Equal(result2, tt.a) {
|
||||
t.Errorf(`collect(FieldsFuncSeq(%q)) = %v; want %v`, tt.s, result2, tt.a)
|
||||
}
|
||||
|
||||
if string(b) != tt.s {
|
||||
t.Errorf("slice changed to %s; want %s", b, tt.s)
|
||||
}
|
||||
@@ -1394,48 +1237,45 @@ func repeat(b []byte, count int) (err error) {
|
||||
|
||||
// See Issue golang.org/issue/16237
|
||||
func TestRepeatCatchesOverflow(t *testing.T) {
|
||||
type testCase struct {
|
||||
tests := [...]struct {
|
||||
s string
|
||||
count int
|
||||
errStr string
|
||||
}
|
||||
|
||||
runTestCases := func(prefix string, tests []testCase) {
|
||||
for i, tt := range tests {
|
||||
err := repeat([]byte(tt.s), tt.count)
|
||||
if tt.errStr == "" {
|
||||
if err != nil {
|
||||
t.Errorf("#%d panicked %v", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if err == nil || !strings.Contains(err.Error(), tt.errStr) {
|
||||
t.Errorf("%s#%d got %q want %q", prefix, i, err, tt.errStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const maxInt = int(^uint(0) >> 1)
|
||||
|
||||
runTestCases("", []testCase{
|
||||
}{
|
||||
0: {"--", -2147483647, "negative"},
|
||||
1: {"", maxInt, ""},
|
||||
1: {"", int(^uint(0) >> 1), ""},
|
||||
2: {"-", 10, ""},
|
||||
3: {"gopher", 0, ""},
|
||||
4: {"-", -1, "negative"},
|
||||
5: {"--", -102, "negative"},
|
||||
6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
|
||||
})
|
||||
|
||||
const is64Bit = 1<<(^uintptr(0)>>63)/2 != 0
|
||||
if !is64Bit {
|
||||
return
|
||||
}
|
||||
|
||||
runTestCases("64-bit", []testCase{
|
||||
0: {"-", maxInt, "out of range"},
|
||||
})
|
||||
for i, tt := range tests {
|
||||
err := repeat([]byte(tt.s), tt.count)
|
||||
if tt.errStr == "" {
|
||||
if err != nil {
|
||||
t.Errorf("#%d panicked %v", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if err == nil || !strings.Contains(err.Error(), tt.errStr) {
|
||||
t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runesEqual(a, b []rune) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, r := range a {
|
||||
if r != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type RunesTest struct {
|
||||
@@ -1458,7 +1298,7 @@ func TestRunes(t *testing.T) {
|
||||
for _, tt := range RunesTests {
|
||||
tin := []byte(tt.in)
|
||||
a := Runes(tin)
|
||||
if !slices.Equal(a, tt.out) {
|
||||
if !runesEqual(a, tt.out) {
|
||||
t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out)
|
||||
continue
|
||||
}
|
||||
@@ -2184,11 +2024,6 @@ func makeBenchInputHard() []byte {
|
||||
var benchInputHard = makeBenchInputHard()
|
||||
|
||||
func benchmarkIndexHard(b *testing.B, sep []byte) {
|
||||
n := Index(benchInputHard, sep)
|
||||
if n < 0 {
|
||||
n = len(benchInputHard)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
for i := 0; i < b.N; i++ {
|
||||
Index(benchInputHard, sep)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"unicode"
|
||||
)
|
||||
@@ -102,7 +102,7 @@ func ExampleBuffer_Read() {
|
||||
fmt.Println(n)
|
||||
fmt.Println(b.String())
|
||||
fmt.Println(string(rdbuf))
|
||||
// Output:
|
||||
// Output
|
||||
// 1
|
||||
// bcde
|
||||
// a
|
||||
@@ -118,7 +118,7 @@ func ExampleBuffer_ReadByte() {
|
||||
}
|
||||
fmt.Println(c)
|
||||
fmt.Println(b.String())
|
||||
// Output:
|
||||
// Output
|
||||
// 97
|
||||
// bcde
|
||||
}
|
||||
@@ -165,8 +165,11 @@ func ExampleCompare_search() {
|
||||
// Binary search to find a matching byte slice.
|
||||
var needle []byte
|
||||
var haystack [][]byte // Assume sorted
|
||||
_, found := slices.BinarySearchFunc(haystack, needle, bytes.Compare)
|
||||
if found {
|
||||
i := sort.Search(len(haystack), func(i int) bool {
|
||||
// Return haystack[i] >= needle.
|
||||
return bytes.Compare(haystack[i], needle) >= 0
|
||||
})
|
||||
if i < len(haystack) && bytes.Equal(haystack[i], needle) {
|
||||
// Found it!
|
||||
}
|
||||
}
|
||||
@@ -502,10 +505,10 @@ func ExampleTitle() {
|
||||
|
||||
func ExampleToTitle() {
|
||||
fmt.Printf("%s\n", bytes.ToTitle([]byte("loud noises")))
|
||||
fmt.Printf("%s\n", bytes.ToTitle([]byte("брат")))
|
||||
fmt.Printf("%s\n", bytes.ToTitle([]byte("хлеб")))
|
||||
// Output:
|
||||
// LOUD NOISES
|
||||
// БРАТ
|
||||
// ХЛЕБ
|
||||
}
|
||||
|
||||
func ExampleToTitleSpecial() {
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bytes
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Lines returns an iterator over the newline-terminated lines in the byte slice s.
|
||||
// The lines yielded by the iterator include their terminating newlines.
|
||||
// If s is empty, the iterator yields no lines at all.
|
||||
// If s does not end in a newline, the final yielded line will not end in a newline.
|
||||
// It returns a single-use iterator.
|
||||
func Lines(s []byte) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
for len(s) > 0 {
|
||||
var line []byte
|
||||
if i := IndexByte(s, '\n'); i >= 0 {
|
||||
line, s = s[:i+1], s[i+1:]
|
||||
} else {
|
||||
line, s = s, nil
|
||||
}
|
||||
if !yield(line[:len(line):len(line)]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// explodeSeq returns an iterator over the runes in s.
|
||||
func explodeSeq(s []byte) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
for len(s) > 0 {
|
||||
_, size := utf8.DecodeRune(s)
|
||||
if !yield(s[:size:size]) {
|
||||
return
|
||||
}
|
||||
s = s[size:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// splitSeq is SplitSeq or SplitAfterSeq, configured by how many
|
||||
// bytes of sep to include in the results (none or all).
|
||||
func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] {
|
||||
if len(sep) == 0 {
|
||||
return explodeSeq(s)
|
||||
}
|
||||
return func(yield func([]byte) bool) {
|
||||
for {
|
||||
i := Index(s, sep)
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
frag := s[:i+sepSave]
|
||||
if !yield(frag[:len(frag):len(frag)]) {
|
||||
return
|
||||
}
|
||||
s = s[i+len(sep):]
|
||||
}
|
||||
yield(s[:len(s):len(s)])
|
||||
}
|
||||
}
|
||||
|
||||
// SplitSeq returns an iterator over all substrings of s separated by sep.
|
||||
// The iterator yields the same strings that would be returned by Split(s, sep),
|
||||
// but without constructing the slice.
|
||||
// It returns a single-use iterator.
|
||||
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
return splitSeq(s, sep, 0)
|
||||
}
|
||||
|
||||
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
||||
// The iterator yields the same strings that would be returned by SplitAfter(s, sep),
|
||||
// but without constructing the slice.
|
||||
// It returns a single-use iterator.
|
||||
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||
return splitSeq(s, sep, len(sep))
|
||||
}
|
||||
|
||||
// FieldsSeq returns an iterator over substrings of s split around runs of
|
||||
// whitespace characters, as defined by unicode.IsSpace.
|
||||
// The iterator yields the same strings that would be returned by Fields(s),
|
||||
// but without constructing the slice.
|
||||
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
start := -1
|
||||
for i := 0; i < len(s); {
|
||||
size := 1
|
||||
r := rune(s[i])
|
||||
isSpace := asciiSpace[s[i]] != 0
|
||||
if r >= utf8.RuneSelf {
|
||||
r, size = utf8.DecodeRune(s[i:])
|
||||
isSpace = unicode.IsSpace(r)
|
||||
}
|
||||
if isSpace {
|
||||
if start >= 0 {
|
||||
if !yield(s[start:i:i]) {
|
||||
return
|
||||
}
|
||||
start = -1
|
||||
}
|
||||
} else if start < 0 {
|
||||
start = i
|
||||
}
|
||||
i += size
|
||||
}
|
||||
if start >= 0 {
|
||||
yield(s[start:len(s):len(s)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
||||
// Unicode code points satisfying f(c).
|
||||
// The iterator yields the same strings that would be returned by FieldsFunc(s),
|
||||
// but without constructing the slice.
|
||||
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
||||
return func(yield func([]byte) bool) {
|
||||
start := -1
|
||||
for i := 0; i < len(s); {
|
||||
size := 1
|
||||
r := rune(s[i])
|
||||
if r >= utf8.RuneSelf {
|
||||
r, size = utf8.DecodeRune(s[i:])
|
||||
}
|
||||
if f(r) {
|
||||
if start >= 0 {
|
||||
if !yield(s[start:i:i]) {
|
||||
return
|
||||
}
|
||||
start = -1
|
||||
}
|
||||
} else if start < 0 {
|
||||
start = i
|
||||
}
|
||||
i += size
|
||||
}
|
||||
if start >= 0 {
|
||||
yield(s[start:len(s):len(s)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker],
|
||||
// [io.ByteScanner], and [io.RuneScanner] interfaces by reading from
|
||||
// A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,
|
||||
// io.ByteScanner, and io.RuneScanner interfaces by reading from
|
||||
// a byte slice.
|
||||
// Unlike a [Buffer], a Reader is read-only and supports seeking.
|
||||
// The zero value for Reader operates like a Reader of an empty slice.
|
||||
@@ -152,8 +152,8 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Reset resets the [Reader] to be reading from b.
|
||||
// Reset resets the [Reader.Reader] to be reading from b.
|
||||
func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} }
|
||||
|
||||
// NewReader returns a new [Reader] reading from b.
|
||||
// NewReader returns a new [Reader.Reader] reading from b.
|
||||
func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -27,6 +28,26 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// addr2linePath returns the path to the "addr2line" binary to run.
|
||||
func addr2linePath(t testing.TB) string {
|
||||
t.Helper()
|
||||
testenv.MustHaveExec(t)
|
||||
|
||||
addr2linePathOnce.Do(func() {
|
||||
addr2lineExePath, addr2linePathErr = os.Executable()
|
||||
})
|
||||
if addr2linePathErr != nil {
|
||||
t.Fatal(addr2linePathErr)
|
||||
}
|
||||
return addr2lineExePath
|
||||
}
|
||||
|
||||
var (
|
||||
addr2linePathOnce sync.Once
|
||||
addr2lineExePath string
|
||||
addr2linePathErr error
|
||||
)
|
||||
|
||||
func loadSyms(t *testing.T, dbgExePath string) map[string]string {
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", dbgExePath)
|
||||
out, err := cmd.CombinedOutput()
|
||||
@@ -49,7 +70,7 @@ func loadSyms(t *testing.T, dbgExePath string) map[string]string {
|
||||
}
|
||||
|
||||
func runAddr2Line(t *testing.T, dbgExePath, addr string) (funcname, path, lineno string) {
|
||||
cmd := testenv.Command(t, testenv.Executable(t), dbgExePath)
|
||||
cmd := testenv.Command(t, addr2linePath(t), dbgExePath)
|
||||
cmd.Stdin = strings.NewReader(addr)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -87,22 +108,41 @@ func testAddr2Line(t *testing.T, dbgExePath, addr string) {
|
||||
// Debug paths are stored slash-separated, so convert to system-native.
|
||||
srcPath = filepath.FromSlash(srcPath)
|
||||
fi2, err := os.Stat(srcPath)
|
||||
|
||||
// If GOROOT_FINAL is set and srcPath is not the file we expect, perhaps
|
||||
// srcPath has had GOROOT_FINAL substituted for GOROOT and GOROOT hasn't been
|
||||
// moved to its final location yet. If so, try the original location instead.
|
||||
if gorootFinal := os.Getenv("GOROOT_FINAL"); gorootFinal != "" &&
|
||||
(os.IsNotExist(err) || (err == nil && !os.SameFile(fi1, fi2))) {
|
||||
// srcPath is clean, but GOROOT_FINAL itself might not be.
|
||||
// (See https://golang.org/issue/41447.)
|
||||
gorootFinal = filepath.Clean(gorootFinal)
|
||||
|
||||
if strings.HasPrefix(srcPath, gorootFinal) {
|
||||
fi2, err = os.Stat(runtime.GOROOT() + strings.TrimPrefix(srcPath, gorootFinal))
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Stat failed: %v", err)
|
||||
}
|
||||
if !os.SameFile(fi1, fi2) {
|
||||
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
|
||||
}
|
||||
if want := "102"; srcLineNo != want {
|
||||
t.Fatalf("line number = %v; want %s", srcLineNo, want)
|
||||
if srcLineNo != "138" {
|
||||
t.Fatalf("line number = %v; want 138", srcLineNo)
|
||||
}
|
||||
}
|
||||
|
||||
// This is line 101. The test depends on that.
|
||||
// This is line 137. The test depends on that.
|
||||
func TestAddr2Line(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
tmpDir, err := os.MkdirTemp("", "TestAddr2Line")
|
||||
if err != nil {
|
||||
t.Fatal("TempDir failed: ", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// Build copy of test binary with debug symbols,
|
||||
// since the one running now may not have them.
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"cmd/internal/objfile"
|
||||
"cmd/internal/telemetry/counter"
|
||||
)
|
||||
|
||||
func printUsage(w *os.File) {
|
||||
@@ -46,7 +45,6 @@ func usage() {
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("addr2line: ")
|
||||
counter.Open()
|
||||
|
||||
// pprof expects this behavior when checking for addr2line
|
||||
if len(os.Args) > 1 && os.Args[1] == "--help" {
|
||||
@@ -56,8 +54,6 @@ func main() {
|
||||
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
counter.Inc("addr2line/invocations")
|
||||
counter.CountFlags("addr2line/flag:", *flag.CommandLine)
|
||||
if flag.NArg() != 1 {
|
||||
usage()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -77,7 +77,7 @@ func TestGolden(t *testing.T) {
|
||||
t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
|
||||
}
|
||||
wanted := strings.Split(string(bs), "\n")
|
||||
slices.Sort(wanted)
|
||||
sort.Strings(wanted)
|
||||
for _, feature := range wanted {
|
||||
if feature == "" {
|
||||
continue
|
||||
@@ -285,25 +285,6 @@ func TestIssue41358(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue64958(t *testing.T) {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
t.Errorf("expected no panic; recovered %v", x)
|
||||
}
|
||||
}()
|
||||
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
for _, context := range contexts {
|
||||
w := NewWalker(context, "testdata/src/issue64958")
|
||||
pkg, err := w.importFrom("p", "", 0)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error importing; got %T", err)
|
||||
}
|
||||
w.export(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheck(t *testing.T) {
|
||||
if !*flagCheck {
|
||||
t.Skip("-check not specified")
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -232,8 +232,8 @@ func compareAPI(w io.Writer, features, required, exception []string) (ok bool) {
|
||||
featureSet := set(features)
|
||||
exceptionSet := set(exception)
|
||||
|
||||
slices.Sort(features)
|
||||
slices.Sort(required)
|
||||
sort.Strings(features)
|
||||
sort.Strings(required)
|
||||
|
||||
take := func(sl *[]string) string {
|
||||
s := (*sl)[0]
|
||||
@@ -378,7 +378,7 @@ func (w *Walker) Features() (fs []string) {
|
||||
for f := range w.features {
|
||||
fs = append(fs, f)
|
||||
}
|
||||
slices.Sort(fs)
|
||||
sort.Strings(fs)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ func tagKey(dir string, context *build.Context, tags []string) string {
|
||||
// an indirect imported package. See https://github.com/golang/go/issues/21181
|
||||
// for more detail.
|
||||
tags = append(tags, context.GOOS, context.GOARCH)
|
||||
slices.Sort(tags)
|
||||
sort.Strings(tags)
|
||||
|
||||
for _, tag := range tags {
|
||||
if ctags[tag] {
|
||||
@@ -535,7 +535,7 @@ func (w *Walker) loadImports() {
|
||||
}
|
||||
}
|
||||
|
||||
slices.Sort(stdPackages)
|
||||
sort.Strings(stdPackages)
|
||||
imports = listImports{
|
||||
stdPackages: stdPackages,
|
||||
importMap: importMap,
|
||||
@@ -717,7 +717,7 @@ func sortedMethodNames(typ *types.Interface) []string {
|
||||
for i := range list {
|
||||
list[i] = typ.Method(i).Name()
|
||||
}
|
||||
slices.Sort(list)
|
||||
sort.Strings(list)
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -747,7 +747,7 @@ func (w *Walker) sortedEmbeddeds(typ *types.Interface) []string {
|
||||
list = append(list, buf.String())
|
||||
}
|
||||
}
|
||||
slices.Sort(list)
|
||||
sort.Strings(list)
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -843,9 +843,6 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
|
||||
buf.WriteString(s)
|
||||
w.writeType(buf, typ.Elem())
|
||||
|
||||
case *types.Alias:
|
||||
w.writeType(buf, types.Unalias(typ))
|
||||
|
||||
case *types.Named:
|
||||
obj := typ.Obj()
|
||||
pkg := obj.Pkg()
|
||||
@@ -854,16 +851,6 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
|
||||
buf.WriteByte('.')
|
||||
}
|
||||
buf.WriteString(typ.Obj().Name())
|
||||
if targs := typ.TypeArgs(); targs.Len() > 0 {
|
||||
buf.WriteByte('[')
|
||||
for i := 0; i < targs.Len(); i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
w.writeType(buf, targs.At(i))
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
}
|
||||
|
||||
case *types.TypeParam:
|
||||
// Type parameter names may change, so use a placeholder instead.
|
||||
@@ -970,17 +957,17 @@ func (w *Walker) emitType(obj *types.TypeName) {
|
||||
if w.isDeprecated(obj) {
|
||||
w.emitf("type %s //deprecated", name)
|
||||
}
|
||||
typ := obj.Type()
|
||||
if obj.IsAlias() {
|
||||
w.emitf("type %s = %s", name, w.typeString(typ))
|
||||
return
|
||||
}
|
||||
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))
|
||||
return
|
||||
}
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.Struct:
|
||||
w.emitStructType(name, typ)
|
||||
@@ -1019,7 +1006,7 @@ func (w *Walker) emitType(obj *types.TypeName) {
|
||||
|
||||
func (w *Walker) emitStructType(name string, typ *types.Struct) {
|
||||
typeStruct := fmt.Sprintf("type %s struct", name)
|
||||
w.emitf("%s", typeStruct)
|
||||
w.emitf(typeStruct)
|
||||
defer w.pushScope(typeStruct)()
|
||||
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
@@ -1083,7 +1070,7 @@ func (w *Walker) emitIfaceType(name string, typ *types.Interface) {
|
||||
return
|
||||
}
|
||||
|
||||
slices.Sort(methodNames)
|
||||
sort.Strings(methodNames)
|
||||
w.emitf("type %s interface { %s }", name, strings.Join(methodNames, ", "))
|
||||
}
|
||||
|
||||
|
||||
3
src/cmd/api/testdata/src/issue64958/p/p.go
vendored
3
src/cmd/api/testdata/src/issue64958/p/p.go
vendored
@@ -1,3 +0,0 @@
|
||||
package p
|
||||
|
||||
type BasicAlias = uint8
|
||||
2
src/cmd/api/testdata/src/pkg/p4/golden.txt
vendored
2
src/cmd/api/testdata/src/pkg/p4/golden.txt
vendored
@@ -1,4 +1,4 @@
|
||||
pkg p4, func NewPair[$0 interface{ M }, $1 interface{ ~int }]($0, $1) Pair[$0, $1]
|
||||
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
|
||||
|
||||
@@ -520,27 +520,15 @@ func archLoong64(linkArch *obj.LinkArch) *Arch {
|
||||
for i := loong64.REG_R0; i <= loong64.REG_R31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
for i := loong64.REG_F0; i <= loong64.REG_F31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
for i := loong64.REG_FCSR0; i <= loong64.REG_FCSR31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
for i := loong64.REG_FCC0; i <= loong64.REG_FCC31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
for i := loong64.REG_V0; i <= loong64.REG_V31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
for i := loong64.REG_X0; i <= loong64.REG_X31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
@@ -553,8 +541,6 @@ func archLoong64(linkArch *obj.LinkArch) *Arch {
|
||||
"FCSR": true,
|
||||
"FCC": true,
|
||||
"R": true,
|
||||
"V": true,
|
||||
"X": true,
|
||||
}
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
@@ -600,10 +586,6 @@ func archRISCV64(shared bool) *Arch {
|
||||
name := fmt.Sprintf("F%d", i-riscv.REG_F0)
|
||||
register[name] = int16(i)
|
||||
}
|
||||
for i := riscv.REG_V0; i <= riscv.REG_V31; i++ {
|
||||
name := fmt.Sprintf("V%d", i-riscv.REG_V0)
|
||||
register[name] = int16(i)
|
||||
}
|
||||
|
||||
// General registers with ABI names.
|
||||
register["ZERO"] = riscv.REG_ZERO
|
||||
|
||||
@@ -101,7 +101,7 @@ func IsARMCMP(op obj.As) bool {
|
||||
// one of the STREX-like instructions that require special handling.
|
||||
func IsARMSTREX(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.ASTREX, arm.ASTREXD, arm.ASTREXB, arm.ASWPW, arm.ASWPBU:
|
||||
case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -11,8 +11,6 @@ package arch
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/loong64"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func jumpLoong64(word string) bool {
|
||||
@@ -23,6 +21,17 @@ func jumpLoong64(word string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLoong64CMP reports whether the op (as defined by an loong64.A* constant) is
|
||||
// one of the CMP instructions that require special handling.
|
||||
func IsLoong64CMP(op obj.As) bool {
|
||||
switch op {
|
||||
case loong64.ACMPEQF, loong64.ACMPEQD, loong64.ACMPGEF, loong64.ACMPGED,
|
||||
loong64.ACMPGTF, loong64.ACMPGTD:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLoong64MUL reports whether the op (as defined by an loong64.A* constant) is
|
||||
// one of the MUL/DIV/REM instructions that require special handling.
|
||||
func IsLoong64MUL(op obj.As) bool {
|
||||
@@ -46,86 +55,6 @@ func IsLoong64RDTIME(op obj.As) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func IsLoong64AMO(op obj.As) bool {
|
||||
return loong64.IsAtomicInst(op)
|
||||
}
|
||||
|
||||
var loong64ElemExtMap = map[string]int16{
|
||||
"B": loong64.ARNG_B,
|
||||
"H": loong64.ARNG_H,
|
||||
"W": loong64.ARNG_W,
|
||||
"V": loong64.ARNG_V,
|
||||
"BU": loong64.ARNG_BU,
|
||||
"HU": loong64.ARNG_HU,
|
||||
"WU": loong64.ARNG_WU,
|
||||
"VU": loong64.ARNG_VU,
|
||||
}
|
||||
|
||||
var loong64LsxArngExtMap = map[string]int16{
|
||||
"B16": loong64.ARNG_16B,
|
||||
"H8": loong64.ARNG_8H,
|
||||
"W4": loong64.ARNG_4W,
|
||||
"V2": loong64.ARNG_2V,
|
||||
}
|
||||
|
||||
var loong64LasxArngExtMap = map[string]int16{
|
||||
"B32": loong64.ARNG_32B,
|
||||
"H16": loong64.ARNG_16H,
|
||||
"W8": loong64.ARNG_8W,
|
||||
"V4": loong64.ARNG_4V,
|
||||
"Q2": loong64.ARNG_2Q,
|
||||
}
|
||||
|
||||
// Loong64RegisterExtension constructs an Loong64 register with extension or arrangement.
|
||||
func Loong64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
|
||||
var ok bool
|
||||
var arng_type int16
|
||||
var simd_type int16
|
||||
|
||||
switch {
|
||||
case reg >= loong64.REG_V0 && reg <= loong64.REG_V31:
|
||||
simd_type = loong64.LSX
|
||||
case reg >= loong64.REG_X0 && reg <= loong64.REG_X31:
|
||||
simd_type = loong64.LASX
|
||||
default:
|
||||
return errors.New("Loong64 extension: invalid LSX/LASX register: " + fmt.Sprintf("%d", reg))
|
||||
}
|
||||
|
||||
if isIndex {
|
||||
arng_type, ok = loong64ElemExtMap[ext]
|
||||
if !ok {
|
||||
return errors.New("Loong64 extension: invalid LSX/LASX arrangement type: " + ext)
|
||||
}
|
||||
|
||||
a.Reg = loong64.REG_ELEM
|
||||
a.Reg += ((reg & loong64.EXT_REG_MASK) << loong64.EXT_REG_SHIFT)
|
||||
a.Reg += ((arng_type & loong64.EXT_TYPE_MASK) << loong64.EXT_TYPE_SHIFT)
|
||||
a.Reg += ((simd_type & loong64.EXT_SIMDTYPE_MASK) << loong64.EXT_SIMDTYPE_SHIFT)
|
||||
a.Index = num
|
||||
} else {
|
||||
switch simd_type {
|
||||
case loong64.LSX:
|
||||
arng_type, ok = loong64LsxArngExtMap[ext]
|
||||
if !ok {
|
||||
return errors.New("Loong64 extension: invalid LSX arrangement type: " + ext)
|
||||
}
|
||||
|
||||
case loong64.LASX:
|
||||
arng_type, ok = loong64LasxArngExtMap[ext]
|
||||
if !ok {
|
||||
return errors.New("Loong64 extension: invalid LASX arrangement type: " + ext)
|
||||
}
|
||||
}
|
||||
|
||||
a.Reg = loong64.REG_ARNG
|
||||
a.Reg += ((reg & loong64.EXT_REG_MASK) << loong64.EXT_REG_SHIFT)
|
||||
a.Reg += ((arng_type & loong64.EXT_TYPE_MASK) << loong64.EXT_TYPE_SHIFT)
|
||||
a.Reg += ((simd_type & loong64.EXT_SIMDTYPE_MASK) << loong64.EXT_SIMDTYPE_SHIFT)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loong64RegisterNumber(name string, n int16) (int16, bool) {
|
||||
switch name {
|
||||
case "F":
|
||||
@@ -144,14 +73,6 @@ func loong64RegisterNumber(name string, n int16) (int16, bool) {
|
||||
if 0 <= n && n <= 31 {
|
||||
return loong64.REG_R0 + n, true
|
||||
}
|
||||
case "V":
|
||||
if 0 <= n && n <= 31 {
|
||||
return loong64.REG_V0 + n, true
|
||||
}
|
||||
case "X":
|
||||
if 0 <= n && n <= 31 {
|
||||
return loong64.REG_X0 + n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func jumpPPC64(word string) bool {
|
||||
// one of the CMP instructions that require special handling.
|
||||
func IsPPC64CMP(op obj.As) bool {
|
||||
switch op {
|
||||
case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU, ppc64.AFCMPO, ppc64.AFCMPU, ppc64.ADCMPO, ppc64.ADCMPU, ppc64.ADCMPOQ, ppc64.ADCMPUQ:
|
||||
case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU, ppc64.AFCMPU:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"cmd/asm/internal/lex"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/ppc64"
|
||||
"cmd/internal/obj/riscv"
|
||||
"cmd/internal/obj/x86"
|
||||
"cmd/internal/sys"
|
||||
)
|
||||
@@ -47,11 +46,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
|
||||
p.errorf("%v", err)
|
||||
return
|
||||
}
|
||||
case sys.RISCV64:
|
||||
if err := riscv.ParseSuffix(prog, cond); err != nil {
|
||||
p.errorf("unrecognized suffix .%q", cond)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
p.errorf("unrecognized suffix .%q", cond)
|
||||
return
|
||||
@@ -353,7 +348,6 @@ func (p *Parser) asmPCAlign(operands [][]lex.Token) {
|
||||
prog := &obj.Prog{
|
||||
Ctxt: p.ctxt,
|
||||
As: obj.APCALIGN,
|
||||
Pos: p.pos(),
|
||||
From: key,
|
||||
}
|
||||
p.append(prog, "", true)
|
||||
@@ -643,6 +637,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||
break
|
||||
}
|
||||
} else if p.arch.Family == sys.Loong64 {
|
||||
if arch.IsLoong64CMP(op) {
|
||||
prog.From = a[0]
|
||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||
break
|
||||
}
|
||||
|
||||
if arch.IsLoong64RDTIME(op) {
|
||||
// The Loong64 RDTIME family of instructions is a bit special,
|
||||
// in that both its register operands are outputs
|
||||
@@ -664,17 +664,9 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||
prog.To = a[2]
|
||||
case sys.Loong64:
|
||||
switch {
|
||||
// Loong64 atomic instructions with one input and two outputs.
|
||||
case arch.IsLoong64AMO(op):
|
||||
prog.From = a[0]
|
||||
prog.To = a[1]
|
||||
prog.RegTo2 = a[2].Reg
|
||||
default:
|
||||
prog.From = a[0]
|
||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||
prog.To = a[2]
|
||||
}
|
||||
prog.From = a[0]
|
||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||
prog.To = a[2]
|
||||
case sys.ARM:
|
||||
// Special cases.
|
||||
if arch.IsARMSTREX(op) {
|
||||
@@ -823,13 +815,6 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||
prog.To = a[3]
|
||||
break
|
||||
}
|
||||
if p.arch.Family == sys.Loong64 {
|
||||
prog.From = a[0]
|
||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||
prog.AddRestSource(a[2])
|
||||
prog.To = a[3]
|
||||
break
|
||||
}
|
||||
if p.arch.Family == sys.PPC64 {
|
||||
prog.From = a[0]
|
||||
prog.To = a[3]
|
||||
|
||||
@@ -217,8 +217,8 @@ next:
|
||||
for {
|
||||
tok = p.nextToken()
|
||||
if len(operands) == 0 && len(items) == 0 {
|
||||
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386, sys.Loong64, sys.RISCV64) && tok == '.' {
|
||||
// Suffixes: ARM conditionals, Loong64 vector instructions, RISCV rounding mode or x86 modifiers.
|
||||
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
|
||||
// Suffixes: ARM conditionals or x86 modifiers.
|
||||
tok = p.nextToken()
|
||||
str := p.lex.Text()
|
||||
if tok != scanner.Ident {
|
||||
@@ -570,13 +570,12 @@ func (p *Parser) atRegisterShift() bool {
|
||||
// atRegisterExtension reports whether we are at the start of an ARM64 extended register.
|
||||
// We have consumed the register or R prefix.
|
||||
func (p *Parser) atRegisterExtension() bool {
|
||||
switch p.arch.Family {
|
||||
case sys.ARM64, sys.Loong64:
|
||||
// R1.xxx
|
||||
return p.peek() == '.'
|
||||
default:
|
||||
// ARM64 only.
|
||||
if p.arch.Family != sys.ARM64 {
|
||||
return false
|
||||
}
|
||||
// R1.xxx
|
||||
return p.peek() == '.'
|
||||
}
|
||||
|
||||
// registerReference parses a register given either the name, R10, or a parenthesized form, SPR(10).
|
||||
@@ -709,7 +708,7 @@ func (p *Parser) registerShift(name string, prefix rune) int64 {
|
||||
if p.arch.Family == sys.ARM64 {
|
||||
off, err := arch.ARM64RegisterShift(r1, op, count)
|
||||
if err != nil {
|
||||
p.errorf("%v", err)
|
||||
p.errorf(err.Error())
|
||||
}
|
||||
return off
|
||||
} else {
|
||||
@@ -771,12 +770,7 @@ func (p *Parser) registerExtension(a *obj.Addr, name string, prefix rune) {
|
||||
case sys.ARM64:
|
||||
err := arch.ARM64RegisterExtension(a, ext, reg, num, isAmount, isIndex)
|
||||
if err != nil {
|
||||
p.errorf("%v", err)
|
||||
}
|
||||
case sys.Loong64:
|
||||
err := arch.Loong64RegisterExtension(a, ext, reg, num, isAmount, isIndex)
|
||||
if err != nil {
|
||||
p.errorf("%v", err)
|
||||
p.errorf(err.Error())
|
||||
}
|
||||
default:
|
||||
p.errorf("register extension not supported on this architecture")
|
||||
@@ -1123,7 +1117,7 @@ ListLoop:
|
||||
ext := tok.String()
|
||||
curArrangement, err := arch.ARM64RegisterArrangement(reg, name, ext)
|
||||
if err != nil {
|
||||
p.errorf("%v", err)
|
||||
p.errorf(err.Error())
|
||||
}
|
||||
if firstReg == -1 {
|
||||
// only record the first register and arrangement
|
||||
@@ -1170,7 +1164,7 @@ ListLoop:
|
||||
case sys.ARM64:
|
||||
offset, err := arch.ARM64RegisterListOffset(firstReg, regCnt, arrangement)
|
||||
if err != nil {
|
||||
p.errorf("%v", err)
|
||||
p.errorf(err.Error())
|
||||
}
|
||||
a.Offset = offset
|
||||
default:
|
||||
|
||||
7
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
7
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@@ -961,11 +961,7 @@ again:
|
||||
CASPD (R2, R3), (R2), (R8, R9) // 487c2248
|
||||
|
||||
// RET
|
||||
RET // c0035fd6
|
||||
RET R0 // 00005fd6
|
||||
RET R6 // c0005fd6
|
||||
RET R27 // 60035fd6
|
||||
RET R30 // c0035fd6
|
||||
RET
|
||||
RET foo(SB)
|
||||
|
||||
// B/BL/B.cond cases, and canonical names JMP, CALL.
|
||||
@@ -1777,7 +1773,6 @@ next:
|
||||
MSR R17, ZCR_EL1 // 111218d5
|
||||
SYS $32768, R1 // 018008d5
|
||||
SYS $32768 // 1f8008d5
|
||||
MSR $1, DIT // 5f4103d5
|
||||
|
||||
// TLBI instruction
|
||||
TLBI VMALLE1IS // 1f8308d5
|
||||
|
||||
2
src/cmd/asm/internal/asm/testdata/armerror.s
vendored
2
src/cmd/asm/internal/asm/testdata/armerror.s
vendored
@@ -260,7 +260,5 @@ TEXT errors(SB),$0
|
||||
STREXD R0, (R2), R1 // ERROR "cannot use same register as both source and destination"
|
||||
STREXD R0, (R2), R2 // ERROR "cannot use same register as both source and destination"
|
||||
STREXD R1, (R4), R7 // ERROR "must be even"
|
||||
STREXB R0, (R2), R0 // ERROR "cannot use same register as both source and destination"
|
||||
STREXB R0, (R2), R2 // ERROR "cannot use same register as both source and destination"
|
||||
|
||||
END
|
||||
|
||||
2
src/cmd/asm/internal/asm/testdata/armv6.s
vendored
2
src/cmd/asm/internal/asm/testdata/armv6.s
vendored
@@ -52,10 +52,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $0
|
||||
MOVDF F4, F5 // c45bb7ee
|
||||
|
||||
LDREX (R8), R9 // 9f9f98e1
|
||||
LDREXB (R11), R12 // 9fcfdbe1
|
||||
LDREXD (R11), R12 // 9fcfbbe1
|
||||
STREX R3, (R4), R5 // STREX (R4), R3, R5 // 935f84e1
|
||||
STREXB R8, (R9), g // STREXB (R9), R8, g // 98afc9e1
|
||||
STREXD R8, (R9), g // STREXD (R9), R8, g // 98afa9e1
|
||||
|
||||
CMPF F8, F9 // c89ab4ee10faf1ee
|
||||
|
||||
339
src/cmd/asm/internal/asm/testdata/loong64enc1.s
vendored
339
src/cmd/asm/internal/asm/testdata/loong64enc1.s
vendored
@@ -21,11 +21,8 @@ lable2:
|
||||
MOVW $65536, R4 // 04020014
|
||||
MOVW $4096, R4 // 24000014
|
||||
MOVV $65536, R4 // 04020014
|
||||
MOVB R4, R5 // 855c0000
|
||||
MOVH R4, R5 // 85580000
|
||||
MOVV $4096, R4 // 24000014
|
||||
MOVW R4, R5 // 85001700
|
||||
MOVWU R4, R5 // 8500df00
|
||||
MOVV R4, R5 // 85001500
|
||||
MOVBU R4, R5 // 85fc4303
|
||||
SUB R4, R5, R6 // a6101100
|
||||
@@ -52,29 +49,11 @@ lable2:
|
||||
SLLV R4, R5, R6 // a6901800
|
||||
ROTRV R4, R5 // a5901b00
|
||||
ROTRV R4, R5, R6 // a6901b00
|
||||
CLOW R4, R5 // 85100000
|
||||
CLZW R4, R5 // 85140000
|
||||
CTOW R4, R5 // 85180000
|
||||
CTZW R4, R5 // 851c0000
|
||||
CLOV R4, R5 // 85200000
|
||||
CLZV R4, R5 // 85240000
|
||||
CTOV R4, R5 // 85280000
|
||||
CTZV R4, R5 // 852c0000
|
||||
REVB2H R4, R5 // 85300000
|
||||
REVB4H R4, R5 // 85340000
|
||||
REVB2W R4, R5 // 85380000
|
||||
REVBV R4, R5 // 853c0000
|
||||
REVH2W R4, R5 // 85400000
|
||||
REVHV R4, R5 // 85440000
|
||||
BITREV4B R4, R5 // 85480000
|
||||
BITREVW R4, R5 // 85500000
|
||||
BITREV8B R4, R5 // 854c0000
|
||||
BITREVV R4, R5 // 85540000
|
||||
EXTWB R4, R5 // 855c0000
|
||||
EXTWH R4, R5 // 85580000
|
||||
CPUCFG R4, R5 // 856c0000
|
||||
CLO R4, R5 // 85100000
|
||||
CLZ R4, R5 // 85140000
|
||||
ADDF F4, F5 // a5900001
|
||||
ADDF F4, F5, F6 // a6900001
|
||||
ADDF F4, R5, F6 // a6900001
|
||||
CMPEQF F4, R5 // a010120c
|
||||
ABSF F4, F5 // 85041401
|
||||
MOVVF F4, F5 // 85181d01
|
||||
MOVF F4, F5 // 85941401
|
||||
@@ -84,11 +63,15 @@ lable2:
|
||||
MOVV R4, result+16(FP) // 6460c029
|
||||
MOVB R4, result+16(FP) // 64600029
|
||||
MOVBU R4, result+16(FP) // 64600029
|
||||
MOVWL R4, result+16(FP) // 6460002f
|
||||
MOVVL R4, result+16(FP) // 6460802f
|
||||
MOVW R4, 1(R5) // a4048029
|
||||
MOVWU R4, 1(R5) // a4048029
|
||||
MOVV R4, 1(R5) // a404c029
|
||||
MOVB R4, 1(R5) // a4040029
|
||||
MOVBU R4, 1(R5) // a4040029
|
||||
MOVWL R4, 1(R5) // a404002f
|
||||
MOVVL R4, 1(R5) // a404802f
|
||||
SC R4, 1(R5) // a4040021
|
||||
SCV R4, 1(R5) // a4040023
|
||||
MOVW y+8(FP), R4 // 64408028
|
||||
@@ -96,11 +79,15 @@ lable2:
|
||||
MOVV y+8(FP), R4 // 6440c028
|
||||
MOVB y+8(FP), R4 // 64400028
|
||||
MOVBU y+8(FP), R4 // 6440002a
|
||||
MOVWL y+8(FP), R4 // 6440002e
|
||||
MOVVL y+8(FP), R4 // 6440802e
|
||||
MOVW 1(R5), R4 // a4048028
|
||||
MOVWU 1(R5), R4 // a404802a
|
||||
MOVV 1(R5), R4 // a404c028
|
||||
MOVB 1(R5), R4 // a4040028
|
||||
MOVBU 1(R5), R4 // a404002a
|
||||
MOVWL 1(R5), R4 // a404002e
|
||||
MOVVL 1(R5), R4 // a404802e
|
||||
LL 1(R5), R4 // a4040020
|
||||
LLV 1(R5), R4 // a4040022
|
||||
MOVW $4(R4), R5 // 8510c002
|
||||
@@ -137,12 +124,16 @@ lable2:
|
||||
BNE R4, R0, 1(PC) // 80040044
|
||||
BNE R0, R4, 1(PC) // 80040044
|
||||
BLTU R4, 1(PC) // 80040068
|
||||
MOVW y+8(FP), F4 // 6440002b
|
||||
MOVF y+8(FP), F4 // 6440002b
|
||||
MOVD y+8(FP), F4 // 6440802b
|
||||
MOVW 1(F5), F4 // a404002b
|
||||
MOVF 1(F5), F4 // a404002b
|
||||
MOVD 1(F5), F4 // a404802b
|
||||
MOVW F4, result+16(FP) // 6460402b
|
||||
MOVF F4, result+16(FP) // 6460402b
|
||||
MOVD F4, result+16(FP) // 6460c02b
|
||||
MOVW F4, 1(F5) // a404402b
|
||||
MOVF F4, 1(F5) // a404402b
|
||||
MOVD F4, 1(F5) // a404c02b
|
||||
MOVW R4, F5 // 85a41401
|
||||
@@ -150,14 +141,11 @@ lable2:
|
||||
MOVV R4, F5 // 85a81401
|
||||
MOVV F4, R5 // 85b81401
|
||||
WORD $74565 // 45230100
|
||||
BREAK R4, result+16(FP) // 64600006
|
||||
BREAK R4, 1(R5) // a4040006
|
||||
BREAK // 00002a00
|
||||
UNDEF // 00002a00
|
||||
|
||||
ANDN R4, R5, R6 // a6901600
|
||||
ANDN R4, R5 // a5901600
|
||||
ORN R4, R5, R6 // a6101600
|
||||
ORN R4, R5 // a5101600
|
||||
|
||||
// mul
|
||||
MUL R4, R5 // a5101c00
|
||||
MUL R4, R5, R6 // a6101c00
|
||||
@@ -211,16 +199,6 @@ lable2:
|
||||
MASKEQZ R4, R5, R6 // a6101300
|
||||
MASKNEZ R4, R5, R6 // a6901300
|
||||
|
||||
// CRC32
|
||||
CRCWBW R4, R5, R6 // a6102400
|
||||
CRCWHW R4, R5, R6 // a6902400
|
||||
CRCWWW R4, R5, R6 // a6102500
|
||||
CRCWVW R4, R5, R6 // a6902500
|
||||
CRCCWBW R4, R5, R6 // a6102600
|
||||
CRCCWHW R4, R5, R6 // a6902600
|
||||
CRCCWWW R4, R5, R6 // a6102700
|
||||
CRCCWVW R4, R5, R6 // a6902700
|
||||
|
||||
MOVFD F4, F5 // 85241901
|
||||
MOVDF F4, F5 // 85181901
|
||||
MOVWF F4, F5 // 85101d01
|
||||
@@ -238,281 +216,20 @@ lable2:
|
||||
DBAR // 00007238
|
||||
NOOP // 00004003
|
||||
|
||||
CMPEQF F4, F5, FCC0 // a010120c
|
||||
CMPGTF F4, F5, FCC1 // a190110c
|
||||
CMPGTD F4, F5, FCC2 // a290210c
|
||||
CMPGEF F4, F5, FCC3 // a390130c
|
||||
CMPGED F4, F5, FCC4 // a490230c
|
||||
CMPEQD F4, F5, FCC5 // a510220c
|
||||
MOVWR R4, result+16(FP) // 6460402f
|
||||
MOVWR R4, 1(R5) // a404402f
|
||||
MOVWR y+8(FP), R4 // 6440402e
|
||||
MOVWR 1(R5), R4 // a404402e
|
||||
|
||||
CMPGTF F4, R5 // a090110c
|
||||
CMPGTD F4, R5 // a090210c
|
||||
CMPGEF F4, R5 // a090130c
|
||||
CMPGED F4, R5 // a090230c
|
||||
CMPEQD F4, R5 // a010220c
|
||||
|
||||
RDTIMELW R4, R0 // 80600000
|
||||
RDTIMEHW R4, R0 // 80640000
|
||||
RDTIMED R4, R5 // 85680000
|
||||
|
||||
MOVV R4, FCSR3 // 83c01401
|
||||
MOVV FCSR3, R4 // 64c81401
|
||||
MOVV F4, FCC0 // 80d01401
|
||||
MOVV FCC0, F4 // 04d41401
|
||||
MOVV FCC0, R4 // 04dc1401
|
||||
MOVV R4, FCC0 // 80d81401
|
||||
|
||||
// Loong64 atomic memory access instructions
|
||||
AMSWAPB R14, (R13), R12 // ac395c38
|
||||
AMSWAPH R14, (R13), R12 // acb95c38
|
||||
AMSWAPW R14, (R13), R12 // ac396038
|
||||
AMSWAPV R14, (R13), R12 // acb96038
|
||||
AMCASB R14, (R13), R12 // ac395838
|
||||
AMCASH R14, (R13), R12 // acb95838
|
||||
AMCASW R14, (R13), R12 // ac395938
|
||||
AMCASV R14, (R13), R12 // acb95938
|
||||
AMADDW R14, (R13), R12 // ac396138
|
||||
AMADDV R14, (R13), R12 // acb96138
|
||||
AMANDW R14, (R13), R12 // ac396238
|
||||
AMANDV R14, (R13), R12 // acb96238
|
||||
AMORW R14, (R13), R12 // ac396338
|
||||
AMORV R14, (R13), R12 // acb96338
|
||||
AMXORW R14, (R13), R12 // ac396438
|
||||
AMXORV R14, (R13), R12 // acb96438
|
||||
AMMAXW R14, (R13), R12 // ac396538
|
||||
AMMAXV R14, (R13), R12 // acb96538
|
||||
AMMINW R14, (R13), R12 // ac396638
|
||||
AMMINV R14, (R13), R12 // acb96638
|
||||
AMMAXWU R14, (R13), R12 // ac396738
|
||||
AMMAXVU R14, (R13), R12 // acb96738
|
||||
AMMINWU R14, (R13), R12 // ac396838
|
||||
AMMINVU R14, (R13), R12 // acb96838
|
||||
AMSWAPDBB R14, (R13), R12 // ac395e38
|
||||
AMSWAPDBH R14, (R13), R12 // acb95e38
|
||||
AMSWAPDBW R14, (R13), R12 // ac396938
|
||||
AMSWAPDBV R14, (R13), R12 // acb96938
|
||||
AMCASDBB R14, (R13), R12 // ac395a38
|
||||
AMCASDBH R14, (R13), R12 // acb95a38
|
||||
AMCASDBW R14, (R13), R12 // ac395b38
|
||||
AMCASDBV R14, (R13), R12 // acb95b38
|
||||
AMADDDBW R14, (R13), R12 // ac396a38
|
||||
AMADDDBV R14, (R13), R12 // acb96a38
|
||||
AMANDDBW R14, (R13), R12 // ac396b38
|
||||
AMANDDBV R14, (R13), R12 // acb96b38
|
||||
AMORDBW R14, (R13), R12 // ac396c38
|
||||
AMORDBV R14, (R13), R12 // acb96c38
|
||||
AMXORDBW R14, (R13), R12 // ac396d38
|
||||
AMXORDBV R14, (R13), R12 // acb96d38
|
||||
AMMAXDBW R14, (R13), R12 // ac396e38
|
||||
AMMAXDBV R14, (R13), R12 // acb96e38
|
||||
AMMINDBW R14, (R13), R12 // ac396f38
|
||||
AMMINDBV R14, (R13), R12 // acb96f38
|
||||
AMMAXDBWU R14, (R13), R12 // ac397038
|
||||
AMMAXDBVU R14, (R13), R12 // acb97038
|
||||
AMMINDBWU R14, (R13), R12 // ac397138
|
||||
AMMINDBVU R14, (R13), R12 // acb97138
|
||||
|
||||
FMADDF F2, F14, F9, F16 // 30391108
|
||||
FMADDD F11, F20, F23, F12 // ecd22508
|
||||
FMSUBF F3, F11, F31, F22 // f6af5108
|
||||
FMSUBD F13, F30, F9, F15 // 2ff96608
|
||||
FNMADDF F27, F11, F5, F21 // b5ac9d08
|
||||
FNMADDD F29, F14, F27, F6 // 66bbae08
|
||||
FNMSUBF F17, F8, F12, F8 // 88a1d808
|
||||
FNMSUBD F29, F21, F3, F17 // 71d4ee08
|
||||
FMADDF F2, F14, F9 // 29391108
|
||||
FMADDD F11, F20, F23 // f7d22508
|
||||
FMSUBF F3, F11, F31 // ffaf5108
|
||||
FMSUBD F13, F30, F9 // 29f96608
|
||||
FNMADDF F27, F11, F5 // a5ac9d08
|
||||
FNMADDD F29, F14, F27 // 7bbbae08
|
||||
FNMSUBF F17, F8, F12 // 8ca1d808
|
||||
FNMSUBD F29, F21, F3 // 63d4ee08
|
||||
|
||||
FMINF F4, F5, F6 // a6900a01
|
||||
FMINF F4, F5 // a5900a01
|
||||
FMIND F4, F5, F6 // a6100b01
|
||||
FMIND F4, F5 // a5100b01
|
||||
FMAXF F4, F5, F6 // a6900801
|
||||
FMAXF F4, F5 // a5900801
|
||||
FMAXD F4, F5, F6 // a6100901
|
||||
FMAXD F4, F5 // a5100901
|
||||
|
||||
FCOPYSGF F4, F5, F6 // a6901201
|
||||
FCOPYSGD F4, F5, F6 // a6101301
|
||||
FCLASSF F4, F5 // 85341401
|
||||
FCLASSD F4, F5 // 85381401
|
||||
|
||||
FFINTFW F0, F1 // 01101d01
|
||||
FFINTFV F0, F1 // 01181d01
|
||||
FFINTDW F0, F1 // 01201d01
|
||||
FFINTDV F0, F1 // 01281d01
|
||||
FTINTWF F0, F1 // 01041b01
|
||||
FTINTWD F0, F1 // 01081b01
|
||||
FTINTVF F0, F1 // 01241b01
|
||||
FTINTVD F0, F1 // 01281b01
|
||||
|
||||
FTINTRMWF F0, F2 // 02041a01
|
||||
FTINTRMWD F0, F2 // 02081a01
|
||||
FTINTRMVF F0, F2 // 02241a01
|
||||
FTINTRMVD F0, F2 // 02281a01
|
||||
FTINTRPWF F0, F2 // 02441a01
|
||||
FTINTRPWD F0, F2 // 02481a01
|
||||
FTINTRPVF F0, F2 // 02641a01
|
||||
FTINTRPVD F0, F2 // 02681a01
|
||||
FTINTRZWF F0, F2 // 02841a01
|
||||
FTINTRZWD F0, F2 // 02881a01
|
||||
FTINTRZVF F0, F2 // 02a41a01
|
||||
FTINTRZVD F0, F2 // 02a81a01
|
||||
FTINTRNEWF F0, F2 // 02c41a01
|
||||
FTINTRNEWD F0, F2 // 02c81a01
|
||||
FTINTRNEVF F0, F2 // 02e41a01
|
||||
FTINTRNEVD F0, F2 // 02e81a01
|
||||
|
||||
// LDX.{B,BU,H,HU,W,WU,D} instructions
|
||||
MOVB (R14)(R13), R12 // cc350038
|
||||
MOVBU (R14)(R13), R12 // cc352038
|
||||
MOVH (R14)(R13), R12 // cc350438
|
||||
MOVHU (R14)(R13), R12 // cc352438
|
||||
MOVW (R14)(R13), R12 // cc350838
|
||||
MOVWU (R14)(R13), R12 // cc352838
|
||||
MOVV (R14)(R13), R12 // cc350c38
|
||||
|
||||
// STX.{B,H,W,D} instructions
|
||||
MOVB R12, (R14)(R13) // cc351038
|
||||
MOVH R12, (R14)(R13) // cc351438
|
||||
MOVW R12, (R14)(R13) // cc351838
|
||||
MOVV R12, (R14)(R13) // cc351c38
|
||||
|
||||
// FLDX.{S,D} instructions
|
||||
MOVF (R14)(R13), F2 // c2353038
|
||||
MOVD (R14)(R13), F2 // c2353438
|
||||
|
||||
// FSTX.{S,D} instructions
|
||||
MOVF F2, (R14)(R13) // c2353838
|
||||
MOVD F2, (R14)(R13) // c2353c38
|
||||
|
||||
BSTRINSW $0, R4, $0, R5 // 85006000
|
||||
BSTRINSW $31, R4, $0, R5 // 85007f00
|
||||
BSTRINSW $15, R4, $6, R5 // 85186f00
|
||||
BSTRINSV $0, R4, $0, R5 // 85008000
|
||||
BSTRINSV $63, R4, $0, R5 // 8500bf00
|
||||
BSTRINSV $15, R4, $6, R5 // 85188f00
|
||||
|
||||
BSTRPICKW $0, R4, $0, R5 // 85806000
|
||||
BSTRPICKW $31, R4, $0, R5 // 85807f00
|
||||
BSTRPICKW $15, R4, $6, R5 // 85986f00
|
||||
BSTRPICKV $0, R4, $0, R5 // 8500c000
|
||||
BSTRPICKV $63, R4, $0, R5 // 8500ff00
|
||||
BSTRPICKV $15, R4, $6, R5 // 8518cf00
|
||||
|
||||
FSCALEBF F4, F5, F6 // a6901001
|
||||
FSCALEBD F4, F5, F6 // a6101101
|
||||
FLOGBF F4, F5 // 85241401
|
||||
FLOGBD F4, F5 // 85281401
|
||||
|
||||
// VSTX/VLDX/XVSTX/XVLDX instructions
|
||||
VMOVQ V2, (R5)(R5) // a2144438
|
||||
VMOVQ (R4)(R5), V2 // 82144038
|
||||
XVMOVQ X2, (R4)(R5) // 82144c38
|
||||
XVMOVQ (R4)(R5), X2 // 82144838
|
||||
|
||||
// VST/VLD/XVST/XVLD instructions
|
||||
VMOVQ V2, (R4) // 8200402c
|
||||
VMOVQ V2, 3(R4) // 820c402c
|
||||
VMOVQ V2, 2040(R4) // 82e05f2c
|
||||
VMOVQ V2, -2040(R4) // 8220602c
|
||||
VMOVQ V2, y+16(FP) // 0260402c
|
||||
VMOVQ V2, x+2030(FP) // 02d85f2c
|
||||
VMOVQ (R4), V2 // 8200002c
|
||||
VMOVQ 3(R4), V2 // 820c002c
|
||||
VMOVQ 2044(R4), V2 // 82f01f2c
|
||||
VMOVQ -2044(R4), V2 // 8210202c
|
||||
VMOVQ y+16(FP), V2 // 0260002c
|
||||
VMOVQ x+2030(FP), V2 // 02d81f2c
|
||||
XVMOVQ X2, (R4) // 8200c02c
|
||||
XVMOVQ X3, 3(R4) // 830cc02c
|
||||
XVMOVQ X4, 2040(R4) // 84e0df2c
|
||||
XVMOVQ X5, -2040(R4) // 8520e02c
|
||||
XVMOVQ X6, y+16(FP) // 0660c02c
|
||||
XVMOVQ X7, x+2030(FP) // 07d8df2c
|
||||
XVMOVQ (R4), X2 // 8200802c
|
||||
XVMOVQ 3(R4), X3 // 830c802c
|
||||
XVMOVQ 2044(R4), X4 // 84f09f2c
|
||||
XVMOVQ -2044(R4), X5 // 8510a02c
|
||||
XVMOVQ y+16(FP), X6 // 0660802c
|
||||
XVMOVQ x+2030(FP), X7 // 07d89f2c
|
||||
|
||||
// Move vector element to general-purpose register: VMOVQ <Vn>.<T>[index], Rd
|
||||
VMOVQ V0.B[0], R4 // 0480ef72
|
||||
VMOVQ V3.B[3], R5 // 658cef72
|
||||
VMOVQ V4.H[2], R6 // 86c8ef72
|
||||
VMOVQ V5.W[2], R7 // a7e8ef72
|
||||
VMOVQ V6.V[1], R8 // c8f4ef72
|
||||
VMOVQ V7.BU[0], R4 // e480f372
|
||||
VMOVQ V7.BU[1], R4 // e484f372
|
||||
VMOVQ V9.BU[3], R5 // 258df372
|
||||
VMOVQ V10.HU[2], R6 // 46c9f372
|
||||
VMOVQ V11.WU[2], R7 // 67e9f372
|
||||
VMOVQ V31.VU[1], R8 // e8f7f372
|
||||
XVMOVQ X1.W[2], R7 // 27c8ef76
|
||||
XVMOVQ X6.V[2], R8 // c8e8ef76
|
||||
XVMOVQ X8.WU[2], R7 // 07c9f376
|
||||
XVMOVQ X31.VU[2], R8 // e8ebf376
|
||||
|
||||
// Move general-purpose register to a vector element: VMOVQ Rn, <Vd>.<T>[index]
|
||||
VMOVQ R4, V2.B[0] // 8280eb72
|
||||
VMOVQ R4, V3.B[1] // 8384eb72
|
||||
VMOVQ R5, V4.B[3] // a48ceb72
|
||||
VMOVQ R6, V5.H[2] // c5c8eb72
|
||||
VMOVQ R7, V6.W[2] // e6e8eb72
|
||||
VMOVQ R8, V7.V[1] // 07f5eb72
|
||||
XVMOVQ R7, X9.W[2] // e9c8eb76
|
||||
XVMOVQ R8, X10.V[2] // 0ae9eb76
|
||||
|
||||
// Duplicate general-purpose register to vector
|
||||
VMOVQ R4, V2.B16 // 82009f72
|
||||
VMOVQ R5, V3.H8 // a3049f72
|
||||
VMOVQ R6, V4.W4 // c4089f72
|
||||
VMOVQ R7, V5.V2 // e50c9f72
|
||||
XVMOVQ R16, X31.B32 // 1f029f76
|
||||
XVMOVQ R17, X28.H16 // 3c069f76
|
||||
XVMOVQ R18, X10.W8 // 4a0a9f76
|
||||
XVMOVQ R19, X9.V4 // 690e9f76
|
||||
|
||||
// Move vector
|
||||
XVMOVQ X0, X31.B32 // 1f000777
|
||||
XVMOVQ X1, X30.H16 // 3e800777
|
||||
XVMOVQ X2, X29.W8 // 5dc00777
|
||||
XVMOVQ X3, X28.V4 // 7ce00777
|
||||
XVMOVQ X3, X27.Q2 // 7bf00777
|
||||
|
||||
// Move vector element to scalar.
|
||||
XVMOVQ X0, X31.W[7] // 1fdcff76
|
||||
XVMOVQ X1, X29.W[0] // 3dc0ff76
|
||||
XVMOVQ X3, X28.V[3] // 7cecff76
|
||||
XVMOVQ X4, X27.V[0] // 9be0ff76
|
||||
XVMOVQ X31.W[7], X0 // e0df0377
|
||||
XVMOVQ X29.W[0], X1 // a1c30377
|
||||
XVMOVQ X28.V[3], X8 // 88ef0377
|
||||
XVMOVQ X27.V[0], X9 // 69e30377
|
||||
|
||||
//Move vector element to vector.
|
||||
VMOVQ V1.B[3], V9.B16 // 298cf772
|
||||
VMOVQ V2.H[2], V8.H8 // 48c8f772
|
||||
VMOVQ V3.W[1], V7.W4 // 67e4f772
|
||||
VMOVQ V4.V[0], V6.V2 // 86f0f772
|
||||
|
||||
// VSEQ{B,H,W,V}, XVSEQ{B,H,W,V} instruction
|
||||
VSEQB V1, V2, V3 // 43040070
|
||||
VSEQH V1, V2, V3 // 43840070
|
||||
VSEQW V1, V2, V3 // 43040170
|
||||
VSEQV V1, V2, V3 // 43840170
|
||||
XVSEQB X3, X2, X4 // 440c0074
|
||||
XVSEQH X3, X2, X4 // 448c0074
|
||||
XVSEQW X3, X2, X4 // 440c0174
|
||||
XVSEQV X3, X2, X4 // 448c0174
|
||||
|
||||
// VPCNT{B,H,W,V}, XVPCNT{B,H,W,V} instruction
|
||||
VPCNTB V1, V2 // 22209c72
|
||||
VPCNTH V1, V2 // 22249c72
|
||||
VPCNTW V1, V2 // 22289c72
|
||||
VPCNTV V1, V2 // 222c9c72
|
||||
XVPCNTB X3, X2 // 62209c76
|
||||
XVPCNTH X3, X2 // 62249c76
|
||||
XVPCNTW X3, X2 // 62289c76
|
||||
XVPCNTV X3, X2 // 622c9c76
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "../../../../../runtime/textflag.h"
|
||||
|
||||
TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
MOVB R4, R5 // 85e04000a5e04800
|
||||
MOVWU R4, R5 // 85804100a5804500
|
||||
MOVW $74565, R4 // 4402001484148d03
|
||||
MOVW $4097, R4 // 2400001484048003
|
||||
MOVV $74565, R4 // 4402001484148d03
|
||||
@@ -57,6 +59,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
XOR $4096, R4 // 3e00001484f81500
|
||||
XOR $-1, R4, R5 // 1efcbf0285f81500
|
||||
XOR $-1, R4 // 1efcbf0284f81500
|
||||
MOVH R4, R5 // 85c04000a5c04800
|
||||
|
||||
// relocation instructions
|
||||
MOVW R4, name(SB) // 1e00001ac4038029
|
||||
|
||||
@@ -64,20 +64,28 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
MOVV 4096(R5), R4 // 3e000014de971000c403c028
|
||||
MOVB 4096(R5), R4 // 3e000014de971000c4030028
|
||||
MOVBU 4096(R5), R4 // 3e000014de971000c403002a
|
||||
MOVW y+65540(FP), F4 // 1e020014de8f1000c433002b
|
||||
MOVF y+65540(FP), F4 // 1e020014de8f1000c433002b
|
||||
MOVD y+65540(FP), F4 // 1e020014de8f1000c433802b
|
||||
MOVW y+4097(FP), F4 // 3e000014de8f1000c427002b
|
||||
MOVF y+4097(FP), F4 // 3e000014de8f1000c427002b
|
||||
MOVD y+4097(FP), F4 // 3e000014de8f1000c427802b
|
||||
MOVW 65536(R5), F4 // 1e020014de971000c403002b
|
||||
MOVF 65536(R5), F4 // 1e020014de971000c403002b
|
||||
MOVD 65536(R5), F4 // 1e020014de971000c403802b
|
||||
MOVW 4096(R5), F4 // 3e000014de971000c403002b
|
||||
MOVF 4096(R5), F4 // 3e000014de971000c403002b
|
||||
MOVD 4096(R5), F4 // 3e000014de971000c403802b
|
||||
MOVW F4, result+65540(FP) // 1e020014de8f1000c433402b
|
||||
MOVF F4, result+65540(FP) // 1e020014de8f1000c433402b
|
||||
MOVD F4, result+65540(FP) // 1e020014de8f1000c433c02b
|
||||
MOVW F4, result+4097(FP) // 3e000014de8f1000c427402b
|
||||
MOVF F4, result+4097(FP) // 3e000014de8f1000c427402b
|
||||
MOVD F4, result+4097(FP) // 3e000014de8f1000c427c02b
|
||||
MOVW F4, 65536(R5) // 1e020014de971000c403402b
|
||||
MOVF F4, 65536(R5) // 1e020014de971000c403402b
|
||||
MOVD F4, 65536(R5) // 1e020014de971000c403c02b
|
||||
MOVW F4, 4096(R5) // 3e000014de971000c403402b
|
||||
MOVF F4, 4096(R5) // 3e000014de971000c403402b
|
||||
MOVD F4, 4096(R5) // 3e000014de971000c403c02b
|
||||
|
||||
|
||||
88
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
88
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@@ -52,9 +52,6 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
// Hex constant 0xFFFFFFFE00000001
|
||||
MOVD $-8589934591, R5 // 38a0ffff or 0602000038a00001
|
||||
|
||||
// For #66955. Verify this opcode turns into a load and assembles.
|
||||
MOVD $-6795364578871345152, R5 // 3ca00000e8a50000 or 04100000e4a00000
|
||||
|
||||
MOVD 8(R3), R4 // e8830008
|
||||
MOVD (R3)(R4), R5 // 7ca4182a
|
||||
MOVD (R3)(R0), R5 // 7ca0182a
|
||||
@@ -93,7 +90,6 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
MOVHBR (R3)(R4), R5 // 7ca41e2c
|
||||
MOVHBR (R3)(R0), R5 // 7ca01e2c
|
||||
MOVHBR (R3), R5 // 7ca01e2c
|
||||
OR $0, R0, R0
|
||||
MOVD $foo+4009806848(FP), R5 // 3ca1ef0138a5cc40 or 0600ef0038a1cc40
|
||||
MOVD $foo(SB), R5 // 3ca0000038a50000 or 0610000038a00000
|
||||
|
||||
@@ -196,10 +192,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
// this is OK since r0 == $0, but the latter is preferred.
|
||||
ADD $0, R6, R5 // 7ca60214
|
||||
|
||||
//TODO: the assembler rewrites these into ADDIS $19, R5, Rx and ADD $-10617, Rx, Rx, but the test only sees the first ADDIS
|
||||
ADD $1234567, R5 // 3ca50013 or 0600001238a5d687
|
||||
ADD $1234567, R5, R6 // 3cc50013 or 0600001238c5d687
|
||||
|
||||
ADD $1234567, R5 // 641f001263ffd6877cbf2a14 or 0600001238a5d687
|
||||
ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14 or 0600001238c5d687
|
||||
ADDEX R3, R5, $3, R6 // 7cc32f54
|
||||
ADDEX R3, $3, R5, R6 // 7cc32f54
|
||||
ADDIS $8, R3 // 3c630008
|
||||
@@ -236,10 +230,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
OR $-32767, R5, R6 // 3be080017fe62b78
|
||||
OR $-32768, R6 // 3be080007fe63378
|
||||
OR $-32768, R6, R7 // 3be080007fe73378
|
||||
OR $1234567, R5 // 64a5001260a5d687
|
||||
OR $1234567, R5, R3 // 64a300126063d687
|
||||
OR $1234567, R5 // 641f001263ffd6877fe52b78
|
||||
OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
|
||||
OR $2147483648, R5, R3 // 64a38000
|
||||
OR $2147483649, R5, R3 // 64a3800060630001
|
||||
OR $2147483649, R5, R3 // 641f800063ff00017fe32b78
|
||||
ORIS $255, R3, R4 // 646400ff
|
||||
OR $16711680, R3, R4 // 646400ff
|
||||
|
||||
@@ -255,37 +249,18 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
XOR $-32767, R5, R6 // 3be080017fe62a78
|
||||
XOR $-32768, R6 // 3be080007fe63278
|
||||
XOR $-32768, R6, R7 // 3be080007fe73278
|
||||
XOR $1234567, R5 // 6ca5001268a5d687
|
||||
XOR $1234567, R5, R3 // 6ca300126863d687
|
||||
XOR $1234567, R5 // 641f001263ffd6877fe52a78
|
||||
XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
|
||||
XORIS $15, R3, R4 // 6c64000f
|
||||
XOR $983040, R3, R4 // 6c64000f
|
||||
|
||||
// TODO: cleanup inconsistency of printing CMPx opcodes with explicit CR arguments.
|
||||
// TODO: the order of CR operands don't match
|
||||
CMP R3, R4 // 7c232000
|
||||
CMP R3, R0 // 7c230000
|
||||
CMP R3, R0, CR1 // CMP R3,CR1,R0 // 7ca30000
|
||||
CMPU R3, R4 // 7c232040
|
||||
CMPU R3, R0 // 7c230040
|
||||
CMPU R3, R0, CR2 // CMPU R3,CR2,R0 // 7d230040
|
||||
CMPW R3, R4 // 7c032000
|
||||
CMPW R3, R0 // 7c030000
|
||||
CMPW R3, R0, CR3 // CMPW R3,CR3,R0 // 7d830000
|
||||
CMPWU R3, R4 // 7c032040
|
||||
CMPWU R3, R0 // 7c030040
|
||||
CMPWU R3, R0, CR4 // CMPWU R3,CR4,R0 // 7e030040
|
||||
CMP R3, $0 // 2c230000
|
||||
CMPU R3, $0 // 28230000
|
||||
CMPW R3, $0 // 2c030000
|
||||
CMPWU R3, $0 // 28030000
|
||||
CMP R3, $0, CR0 // CMP R3,CR0,$0 // 2c230000
|
||||
CMPU R3, $0, CR1 // CMPU R3,CR1,$0 // 28a30000
|
||||
CMPW R3, $0, CR2 // CMPW R3,CR2,$0 // 2d030000
|
||||
CMPW R3, $-32768, CR2 // CMPW R3,CR2,$-32768 // 2d038000
|
||||
CMPWU R3, $0, CR3 // CMPWU R3,CR3,$0 // 29830000
|
||||
CMPWU R3, $0x8008, CR3 // CMPWU R3,CR3,$32776 // 29838008
|
||||
|
||||
CMPEQB R3,R4,CR6 // 7f0321c0
|
||||
CMPB R3,R4,R4 // 7c6423f8
|
||||
CMPEQB R3,R4,CR6 // 7f0321c0
|
||||
|
||||
ADD R3, R4 // 7c841a14
|
||||
ADD R3, R4, R5 // 7ca41a14
|
||||
@@ -508,26 +483,17 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
|
||||
BEQ 0(PC) // 41820000
|
||||
BEQ CR1,0(PC) // 41860000
|
||||
BEQ CR0, LR // 4d820020
|
||||
BEQ CR7, LR // 4d9e0020
|
||||
BGE 0(PC) // 40800000
|
||||
BGE CR2,0(PC) // 40880000
|
||||
BGE CR6,LR // 4c980020
|
||||
BGT 4(PC) // 41810010
|
||||
BGT CR3,4(PC) // 418d0010
|
||||
BGT CR6, LR // 4d990020
|
||||
BLE 0(PC) // 40810000
|
||||
BLE CR4,0(PC) // 40910000
|
||||
BLE CR6, LR // 4c990020
|
||||
BLT 0(PC) // 41800000
|
||||
BLT CR5,0(PC) // 41940000
|
||||
BNE 0(PC) // 40820000
|
||||
BNE CR6, LR // 4c9a0020
|
||||
BLT CR6,0(PC) // 41980000
|
||||
BLT CR6, LR // 4d980020
|
||||
BVC 0(PC) // 40830000
|
||||
BVC CR6, LR // 4c9b0020
|
||||
BVS CR6, LR // 4d9b0020
|
||||
BVS 0(PC) // 41830000
|
||||
JMP 8(PC) // 48000010
|
||||
|
||||
@@ -690,17 +656,9 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
FMOVDCC F1, F2 // fc400891
|
||||
FADDS F1, F2 // ec42082a
|
||||
FADDS F1, F2, F3 // ec62082a
|
||||
DADD F1, F2 // ec420804
|
||||
DADD F1, F2, F3 // ec620804
|
||||
DADDQ F2, F4 // fc841004
|
||||
DADDQ F2, F4, F6 // fcc41004
|
||||
FADDSCC F1, F2, F3 // ec62082b
|
||||
FSUB F1, F2 // fc420828
|
||||
FSUB F1, F2, F3 // fc620828
|
||||
DSUB F1, F2 // ec420c04
|
||||
DSUB F1, F2, F3 // ec620c04
|
||||
DSUBQ F2, F4 // fc841404
|
||||
DSUBQ F2, F4, F6 // fcc41404
|
||||
FSUBCC F1, F2, F3 // fc620829
|
||||
FSUBS F1, F2 // ec420828
|
||||
FSUBS F1, F2, F3 // ec620828
|
||||
@@ -708,20 +666,12 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
FSUBSCC F1, F2, F3 // ec620829
|
||||
FMUL F1, F2 // fc420072
|
||||
FMUL F1, F2, F3 // fc620072
|
||||
DMUL F1, F2 // ec420044
|
||||
DMUL F1, F2, F3 // ec620044
|
||||
DMULQ F2, F4 // fc8400c4
|
||||
DMULQ F2, F4, F6 // fcc400c4
|
||||
FMULCC F1, F2, F3 // fc620073
|
||||
FMULS F1, F2 // ec420072
|
||||
FMULS F1, F2, F3 // ec620072
|
||||
FMULSCC F1, F2, F3 // ec620073
|
||||
FDIV F1, F2 // fc420824
|
||||
FDIV F1, F2, F3 // fc620824
|
||||
DDIV F1, F2 // ec420c44
|
||||
DDIV F1, F2, F3 // ec620c44
|
||||
DDIVQ F2, F4 // fc841444
|
||||
DDIVQ F2, F4, F6 // fcc41444
|
||||
FDIVCC F1, F2, F3 // fc620825
|
||||
FDIVS F1, F2 // ec420824
|
||||
FDIVS F1, F2, F3 // ec620824
|
||||
@@ -788,17 +738,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
FCPSGN F1, F2 // fc420810
|
||||
FCPSGNCC F1, F2 // fc420811
|
||||
FCMPO F1, F2 // fc011040
|
||||
FCMPO F1, F2, CR0 // FCMPO F1,CR0,F2 // fc011040
|
||||
FCMPU F1, F2 // fc011000
|
||||
FCMPU F1, F2, CR0 // FCMPU F1,CR0,F2 // fc011000
|
||||
DCMPO F1, F2 // ec011104
|
||||
DCMPO F1, F2, CR0 // DCMPO F1,CR0,F2 // ec011104
|
||||
DCMPOQ F2, F4 // fc022104
|
||||
DCMPOQ F2,F4, CR0 // DCMPOQ F2,CR0,F4 // fc022104
|
||||
DCMPU F1, F2 // ec011504
|
||||
DCMPU F1, F2, CR0 // DCMPU F1,CR0,F2 // ec011504
|
||||
DCMPUQ F2, F4 // fc022504
|
||||
DCMPUQ F2,F4, CR0 // DCMPUQ F2,CR0,F4 // fc022504
|
||||
LVX (R3)(R4), V1 // 7c2418ce
|
||||
LVX (R3)(R0), V1 // 7c2018ce
|
||||
LVX (R3), V1 // 7c2018ce
|
||||
@@ -1188,16 +1128,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
MOVD XER, 4(R1) // 7fe102a6fbe10004
|
||||
MOVD 4(R1), SPR(3) // ebe100047fe303a6
|
||||
MOVD 4(R1), XER // ebe100047fe103a6
|
||||
OR $0, R0, R0 // 60000000
|
||||
|
||||
PCALIGN $16
|
||||
PNOP // 0700000000000000
|
||||
|
||||
SETB CR1,R3 // 7c640100
|
||||
VCLZLSBB V1,R2 // 10400e02
|
||||
VCTZLSBB V1,R2 // 10410e02
|
||||
|
||||
XSMAXJDP VS1,VS2,VS3 // f0611480
|
||||
XSMINJDP VS1,VS2,VS3 // f06114c0
|
||||
VCLZLSBB V1, R2 // 10400e02
|
||||
VCTZLSBB V1, R2 // 10410e02
|
||||
|
||||
RET
|
||||
|
||||
171
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
171
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
@@ -6,9 +6,7 @@
|
||||
|
||||
TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
start:
|
||||
//
|
||||
// Unprivileged ISA
|
||||
//
|
||||
|
||||
// 2.4: Integer Computational Instructions
|
||||
|
||||
@@ -141,7 +139,7 @@ start:
|
||||
// 2.7: Memory Ordering Instructions
|
||||
FENCE // 0f00f00f
|
||||
|
||||
// 4.2: Integer Computational Instructions (RV64I)
|
||||
// 5.2: Integer Computational Instructions (RV64I)
|
||||
ADDIW $1, X5, X6 // 1b831200
|
||||
SLLIW $1, X5, X6 // 1b931200
|
||||
SRLIW $1, X5, X6 // 1bd31200
|
||||
@@ -166,25 +164,18 @@ start:
|
||||
SUBW $1, X6 // 1b03f3ff
|
||||
SRAW $1, X6 // 1b531340
|
||||
|
||||
// 4.3: Load and Store Instructions (RV64I)
|
||||
// 5.3: Load and Store Instructions (RV64I)
|
||||
LD (X5), X6 // 03b30200
|
||||
LD 4(X5), X6 // 03b34200
|
||||
SD X5, (X6) // 23305300
|
||||
SD X5, 4(X6) // 23325300
|
||||
|
||||
// 8.1: Base Counters and Timers (Zicntr)
|
||||
RDCYCLE X5 // f32200c0
|
||||
RDTIME X5 // f32210c0
|
||||
RDINSTRET X5 // f32220c0
|
||||
|
||||
// 13.1: Multiplication Operations
|
||||
// 7.1: Multiplication Operations
|
||||
MUL X5, X6, X7 // b3035302
|
||||
MULH X5, X6, X7 // b3135302
|
||||
MULHU X5, X6, X7 // b3335302
|
||||
MULHSU X5, X6, X7 // b3235302
|
||||
MULW X5, X6, X7 // bb035302
|
||||
|
||||
// 13.2: Division Operations
|
||||
DIV X5, X6, X7 // b3435302
|
||||
DIVU X5, X6, X7 // b3535302
|
||||
REM X5, X6, X7 // b3635302
|
||||
@@ -194,13 +185,13 @@ start:
|
||||
REMW X5, X6, X7 // bb635302
|
||||
REMUW X5, X6, X7 // bb735302
|
||||
|
||||
// 14.2: Load-Reserved/Store-Conditional (Zalrsc)
|
||||
// 8.2: Load-Reserved/Store-Conditional
|
||||
LRW (X5), X6 // 2fa30214
|
||||
LRD (X5), X6 // 2fb30214
|
||||
SCW X5, (X6), X7 // af23531a
|
||||
SCD X5, (X6), X7 // af33531a
|
||||
|
||||
// 14.4: Atomic Memory Operations (Zaamo)
|
||||
// 8.3: Atomic Memory Operations
|
||||
AMOSWAPW X5, (X6), X7 // af23530e
|
||||
AMOSWAPD X5, (X6), X7 // af33530e
|
||||
AMOADDW X5, (X6), X7 // af235306
|
||||
@@ -220,13 +211,18 @@ start:
|
||||
AMOMINUW X5, (X6), X7 // af2353c6
|
||||
AMOMINUD X5, (X6), X7 // af3353c6
|
||||
|
||||
// 20.5: Single-Precision Load and Store Instructions
|
||||
// 10.1: Base Counters and Timers
|
||||
RDCYCLE X5 // f32200c0
|
||||
RDTIME X5 // f32210c0
|
||||
RDINSTRET X5 // f32220c0
|
||||
|
||||
// 11.5: Single-Precision Load and Store Instructions
|
||||
FLW (X5), F0 // 07a00200
|
||||
FLW 4(X5), F0 // 07a04200
|
||||
FSW F0, (X5) // 27a00200
|
||||
FSW F0, 4(X5) // 27a20200
|
||||
|
||||
// 20.6: Single-Precision Floating-Point Computational Instructions
|
||||
// 11.6: Single-Precision Floating-Point Computational Instructions
|
||||
FADDS F1, F0, F2 // 53011000
|
||||
FSUBS F1, F0, F2 // 53011008
|
||||
FMULS F1, F0, F2 // 53011010
|
||||
@@ -235,33 +231,13 @@ start:
|
||||
FMAXS F1, F0, F2 // 53111028
|
||||
FSQRTS F0, F1 // d3000058
|
||||
|
||||
// 20.7: Single-Precision Floating-Point Conversion and Move Instructions
|
||||
// 11.7: Single-Precision Floating-Point Conversion and Move Instructions
|
||||
FCVTWS F0, X5 // d31200c0
|
||||
FCVTWS.RNE F0, X5 // d30200c0
|
||||
FCVTWS.RTZ F0, X5 // d31200c0
|
||||
FCVTWS.RDN F0, X5 // d32200c0
|
||||
FCVTWS.RUP F0, X5 // d33200c0
|
||||
FCVTWS.RMM F0, X5 // d34200c0
|
||||
FCVTLS F0, X5 // d31220c0
|
||||
FCVTLS.RNE F0, X5 // d30220c0
|
||||
FCVTLS.RTZ F0, X5 // d31220c0
|
||||
FCVTLS.RDN F0, X5 // d32220c0
|
||||
FCVTLS.RUP F0, X5 // d33220c0
|
||||
FCVTLS.RMM F0, X5 // d34220c0
|
||||
FCVTSW X5, F0 // 538002d0
|
||||
FCVTSL X5, F0 // 538022d0
|
||||
FCVTWUS F0, X5 // d31210c0
|
||||
FCVTWUS.RNE F0, X5 // d30210c0
|
||||
FCVTWUS.RTZ F0, X5 // d31210c0
|
||||
FCVTWUS.RDN F0, X5 // d32210c0
|
||||
FCVTWUS.RUP F0, X5 // d33210c0
|
||||
FCVTWUS.RMM F0, X5 // d34210c0
|
||||
FCVTLUS F0, X5 // d31230c0
|
||||
FCVTLUS.RNE F0, X5 // d30230c0
|
||||
FCVTLUS.RTZ F0, X5 // d31230c0
|
||||
FCVTLUS.RDN F0, X5 // d32230c0
|
||||
FCVTLUS.RUP F0, X5 // d33230c0
|
||||
FCVTLUS.RMM F0, X5 // d34230c0
|
||||
FCVTSWU X5, F0 // 538012d0
|
||||
FCVTSLU X5, F0 // 538032d0
|
||||
FSGNJS F1, F0, F2 // 53011020
|
||||
@@ -276,21 +252,21 @@ start:
|
||||
FNMSUBS F1, F2, F3, F4 // 4b822018
|
||||
FNMADDS F1, F2, F3, F4 // 4f822018
|
||||
|
||||
// 20.8: Single-Precision Floating-Point Compare Instructions
|
||||
// 11.8: Single-Precision Floating-Point Compare Instructions
|
||||
FEQS F0, F1, X7 // d3a300a0
|
||||
FLTS F0, F1, X7 // d39300a0
|
||||
FLES F0, F1, X7 // d38300a0
|
||||
|
||||
// 20.9: Single-Precision Floating-Point Classify Instruction
|
||||
// 11.9: Single-Precision Floating-Point Classify Instruction
|
||||
FCLASSS F0, X5 // d31200e0
|
||||
|
||||
// 21.3: Double-Precision Load and Store Instructions
|
||||
// 12.3: Double-Precision Load and Store Instructions
|
||||
FLD (X5), F0 // 07b00200
|
||||
FLD 4(X5), F0 // 07b04200
|
||||
FSD F0, (X5) // 27b00200
|
||||
FSD F0, 4(X5) // 27b20200
|
||||
|
||||
// 21.4: Double-Precision Floating-Point Computational Instructions
|
||||
// 12.4: Double-Precision Floating-Point Computational Instructions
|
||||
FADDD F1, F0, F2 // 53011002
|
||||
FSUBD F1, F0, F2 // 5301100a
|
||||
FMULD F1, F0, F2 // 53011012
|
||||
@@ -299,33 +275,13 @@ start:
|
||||
FMAXD F1, F0, F2 // 5311102a
|
||||
FSQRTD F0, F1 // d300005a
|
||||
|
||||
// 21.5: Double-Precision Floating-Point Conversion and Move Instructions
|
||||
// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
|
||||
FCVTWD F0, X5 // d31200c2
|
||||
FCVTWD.RNE F0, X5 // d30200c2
|
||||
FCVTWD.RTZ F0, X5 // d31200c2
|
||||
FCVTWD.RDN F0, X5 // d32200c2
|
||||
FCVTWD.RUP F0, X5 // d33200c2
|
||||
FCVTWD.RMM F0, X5 // d34200c2
|
||||
FCVTLD F0, X5 // d31220c2
|
||||
FCVTLD.RNE F0, X5 // d30220c2
|
||||
FCVTLD.RTZ F0, X5 // d31220c2
|
||||
FCVTLD.RDN F0, X5 // d32220c2
|
||||
FCVTLD.RUP F0, X5 // d33220c2
|
||||
FCVTLD.RMM F0, X5 // d34220c2
|
||||
FCVTDW X5, F0 // 538002d2
|
||||
FCVTDL X5, F0 // 538022d2
|
||||
FCVTWUD F0, X5 // d31210c2
|
||||
FCVTWUD.RNE F0, X5 // d30210c2
|
||||
FCVTWUD.RTZ F0, X5 // d31210c2
|
||||
FCVTWUD.RDN F0, X5 // d32210c2
|
||||
FCVTWUD.RUP F0, X5 // d33210c2
|
||||
FCVTWUD.RMM F0, X5 // d34210c2
|
||||
FCVTLUD F0, X5 // d31230c2
|
||||
FCVTLUD.RNE F0, X5 // d30230c2
|
||||
FCVTLUD.RTZ F0, X5 // d31230c2
|
||||
FCVTLUD.RDN F0, X5 // d32230c2
|
||||
FCVTLUD.RUP F0, X5 // d33230c2
|
||||
FCVTLUD.RMM F0, X5 // d34230c2
|
||||
FCVTDWU X5, F0 // 538012d2
|
||||
FCVTDLU X5, F0 // 538032d2
|
||||
FCVTSD F0, F1 // d3001040
|
||||
@@ -340,91 +296,12 @@ start:
|
||||
FNMSUBD F1, F2, F3, F4 // 4b82201a
|
||||
FNMADDD F1, F2, F3, F4 // 4f82201a
|
||||
|
||||
// 21.7: Double-Precision Floating-Point Classify Instruction
|
||||
// 12.6: Double-Precision Floating-Point Classify Instruction
|
||||
FCLASSD F0, X5 // d31200e2
|
||||
|
||||
// 28.4.1: Address Generation Instructions (Zba)
|
||||
ADDUW X10, X11, X12 // 3b86a508
|
||||
ADDUW X10, X11 // bb85a508
|
||||
SH1ADD X11, X12, X13 // b326b620
|
||||
SH1ADD X11, X12 // 3326b620
|
||||
SH1ADDUW X12, X13, X14 // 3ba7c620
|
||||
SH1ADDUW X12, X13 // bba6c620
|
||||
SH2ADD X13, X14, X15 // b347d720
|
||||
SH2ADD X13, X14 // 3347d720
|
||||
SH2ADDUW X14, X15, X16 // 3bc8e720
|
||||
SH2ADDUW X14, X15 // bbc7e720
|
||||
SH3ADD X15, X16, X17 // b368f820
|
||||
SH3ADD X15, X16 // 3368f820
|
||||
SH3ADDUW X16, X17, X18 // 3be90821
|
||||
SH3ADDUW X16, X17 // bbe80821
|
||||
SLLIUW $31, X17, X18 // 1b99f809
|
||||
SLLIUW $63, X17 // 9b98f80b
|
||||
SLLIUW $63, X17, X18 // 1b99f80b
|
||||
SLLIUW $1, X18, X19 // 9b191908
|
||||
|
||||
// 28.4.2: Basic Bit Manipulation (Zbb)
|
||||
ANDN X19, X20, X21 // b37a3a41 or 93caf9ffb37a5a01
|
||||
ANDN X19, X20 // 337a3a41 or 93cff9ff337afa01
|
||||
CLZ X20, X21 // 931a0a60
|
||||
CLZW X21, X22 // 1b9b0a60
|
||||
CPOP X22, X23 // 931b2b60
|
||||
CPOPW X23, X24 // 1b9c2b60
|
||||
CTZ X24, X25 // 931c1c60
|
||||
CTZW X25, X26 // 1b9d1c60
|
||||
MAX X26, X28, X29 // b36eae0b
|
||||
MAX X26, X28 // 336eae0b
|
||||
MAXU X28, X29, X30 // 33ffce0b
|
||||
MAXU X28, X29 // b3fece0b
|
||||
MIN X29, X30, X5 // b342df0b
|
||||
MIN X29, X30 // 334fdf0b
|
||||
MINU X30, X5, X6 // 33d3e20b
|
||||
MINU X30, X5 // b3d2e20b
|
||||
ORN X6, X7, X8 // 33e46340 or 1344f3ff33e48300
|
||||
ORN X6, X7 // b3e36340 or 934ff3ffb3e3f301
|
||||
SEXTB X16, X17 // 93184860
|
||||
SEXTH X17, X18 // 13995860
|
||||
XNOR X18, X19, X20 // 33ca2941 or 33ca2901134afaff
|
||||
XNOR X18, X19 // b3c92941 or b3c9290193c9f9ff
|
||||
ZEXTH X19, X20 // 3bca0908
|
||||
|
||||
// 28.4.2: Bitwise Rotation (Zbb)
|
||||
ROL X8, X9, X10 // 33958460 or b30f8040b3dff4013395840033e5af00
|
||||
ROL X8, X9 // b3948460 or b30f8040b3dff401b3948400b3e49f00
|
||||
ROLW X9, X10, X11 // bb159560 or b30f9040bb5ff501bb159500b3e5bf00
|
||||
ROLW X9, X10 // 3b159560 or b30f9040bb5ff5013b15950033e5af00
|
||||
ROR X10, X11, X12 // 33d6a560 or b30fa040b39ff50133d6a50033e6cf00
|
||||
ROR X10, X11 // b3d5a560 or b30fa040b39ff501b3d5a500b3e5bf00
|
||||
ROR $63, X11 // 93d5f563 or 93dff50393951500b3e5bf00
|
||||
RORI $63, X11, X12 // 13d6f563 or 93dff5031396150033e6cf00
|
||||
RORI $1, X12, X13 // 93561660 or 935f16009316f603b3e6df00
|
||||
RORIW $31, X13, X14 // 1bd7f661 or 9bdff6011b97160033e7ef00
|
||||
RORIW $1, X14, X15 // 9b571760 or 9b5f17009b17f701b3e7ff00
|
||||
RORW X15, X16, X17 // bb58f860 or b30ff040bb1ff801bb58f800b3e81f01
|
||||
RORW X15, X16 // 3b58f860 or b30ff040bb1ff8013b58f80033e80f01
|
||||
RORW $31, X13 // 9bd6f661 or 9bdff6019b961600b3e6df00
|
||||
ORCB X5, X6 // 13d37228
|
||||
REV8 X7, X8 // 13d4836b
|
||||
|
||||
// 28.4.4: Single-bit Instructions (Zbs)
|
||||
BCLR X23, X24, X25 // b31c7c49
|
||||
BCLR $63, X24 // 131cfc4b
|
||||
BCLRI $1, X25, X26 // 139d1c48
|
||||
BEXT X26, X28, X29 // b35eae49
|
||||
BEXT $63, X28 // 135efe4b
|
||||
BEXTI $1, X29, X30 // 13df1e48
|
||||
BINV X30, X5, X6 // 3393e269
|
||||
BINV $63, X6 // 1313f36b
|
||||
BINVI $1, X7, X8 // 13941368
|
||||
BSET X8, X9, X10 // 33958428
|
||||
BSET $63, X9 // 9394f42b
|
||||
BSETI $1, X10, X11 // 93151528
|
||||
|
||||
//
|
||||
// Privileged ISA
|
||||
//
|
||||
|
||||
// 3.3.1: Environment Call and Breakpoint
|
||||
// 3.2.1: Environment Call and Breakpoint
|
||||
ECALL // 73000000
|
||||
SCALL // 73000000
|
||||
EBREAK // 73001000
|
||||
@@ -467,12 +344,12 @@ start:
|
||||
MOVW X5, (X6) // 23205300
|
||||
MOVW X5, 4(X6) // 23225300
|
||||
|
||||
MOVB X5, X6 // 1393820313538343 or 13934260
|
||||
MOVH X5, X6 // 1393020313530343 or 13935260
|
||||
MOVB X5, X6 // 1393820313538343
|
||||
MOVH X5, X6 // 1393020313530343
|
||||
MOVW X5, X6 // 1b830200
|
||||
MOVBU X5, X6 // 13f3f20f
|
||||
MOVHU X5, X6 // 1393020313530303 or 3bc30208
|
||||
MOVWU X5, X6 // 1393020213530302 or 3b830208
|
||||
MOVHU X5, X6 // 1393020313530303
|
||||
MOVWU X5, X6 // 1393020213530302
|
||||
|
||||
MOVF 4(X5), F0 // 07a04200
|
||||
MOVF F0, 4(X5) // 27a20200
|
||||
|
||||
28
src/cmd/asm/internal/asm/testdata/riscv64error.s
vendored
28
src/cmd/asm/internal/asm/testdata/riscv64error.s
vendored
@@ -26,22 +26,18 @@ TEXT errors(SB),$0
|
||||
MOVD F0, F1, F2 // ERROR "illegal MOV instruction"
|
||||
MOV X10, X11, X12 // ERROR "illegal MOV instruction"
|
||||
MOVW X10, X11, X12 // ERROR "illegal MOV instruction"
|
||||
RORI $64, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
SLLI $64, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
SRLI $64, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
SRAI $64, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
RORI $-1, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
SLLI $-1, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
SRLI $-1, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
SRAI $-1, X5, X6 // ERROR "immediate out of range 0 to 63"
|
||||
RORIW $32, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SLLIW $32, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SRLIW $32, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SRAIW $32, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
RORIW $-1, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SLLIW $-1, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SRLIW $-1, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SRAIW $-1, X5, X6 // ERROR "immediate out of range 0 to 31"
|
||||
SLLI $64, X5, X6 // ERROR "shift amount out of range 0 to 63"
|
||||
SRLI $64, X5, X6 // ERROR "shift amount out of range 0 to 63"
|
||||
SRAI $64, X5, X6 // ERROR "shift amount out of range 0 to 63"
|
||||
SLLI $-1, X5, X6 // ERROR "shift amount out of range 0 to 63"
|
||||
SRLI $-1, X5, X6 // ERROR "shift amount out of range 0 to 63"
|
||||
SRAI $-1, X5, X6 // ERROR "shift amount out of range 0 to 63"
|
||||
SLLIW $32, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||
SRLIW $32, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||
SRAIW $32, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||
SLLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||
SRLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||
SRAIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||
SD X5, 4294967296(X6) // ERROR "constant 4294967296 too large"
|
||||
SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1"
|
||||
SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1"
|
||||
|
||||
15
src/cmd/asm/internal/asm/testdata/s390x.s
vendored
15
src/cmd/asm/internal/asm/testdata/s390x.s
vendored
@@ -520,20 +520,7 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
|
||||
VSUMQF V4, V5, V6 // e76450002067
|
||||
VSUMQG V19, V20, V21 // e75340003e67
|
||||
VSUMB V7, V8, V9 // e79780000064
|
||||
VSUMH V22, V23, V24 // e78670001e64
|
||||
VSTRC V18, V20, V22, V24 // e78240006f8a
|
||||
VSTRCB V18, V20, V22, V24 // e78240006f8a
|
||||
VSTRCH V18, V20, V22, V24 // e78241006f8a
|
||||
VSTRCF V18, V20, V22, V24 // e78242006f8a
|
||||
VSTRCBS V18, V20, V22, V24 // e78240106f8a
|
||||
VSTRCHS V18, V20, V22, V24 // e78241106f8a
|
||||
VSTRCFS V18, V20, V22, V24 // e78242106f8a
|
||||
VSTRCZB V18, V20, V22, V24 // e78240206f8a
|
||||
VSTRCZH V18, V20, V22, V24 // e78241206f8a
|
||||
VSTRCZF V18, V20, V22, V24 // e78242206f8a
|
||||
VSTRCZBS V18, V20, V22, V24 // e78240306f8a
|
||||
VSTRCZHS V18, V20, V22, V24 // e78241306f8a
|
||||
VSTRCZFS V18, V20, V22, V24 // e78242306f8a
|
||||
VSUMH V22, V23, V24 // e78670001e64
|
||||
|
||||
RET
|
||||
RET foo(SB)
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
@@ -253,7 +252,7 @@ func (in *Input) macroDefinition(name string) ([]string, []Token) {
|
||||
in.Error("bad syntax in definition for macro:", name)
|
||||
}
|
||||
arg := in.Stack.Text()
|
||||
if slices.Contains(args, arg) {
|
||||
if i := lookup(args, arg); i >= 0 {
|
||||
in.Error("duplicate argument", arg, "in definition for macro:", name)
|
||||
}
|
||||
args = append(args, arg)
|
||||
@@ -281,6 +280,15 @@ func (in *Input) macroDefinition(name string) ([]string, []Token) {
|
||||
return args, tokens
|
||||
}
|
||||
|
||||
func lookup(args []string, arg string) int {
|
||||
for i, a := range args {
|
||||
if a == arg {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// invokeMacro pushes onto the input Stack a Slice that holds the macro definition with the actual
|
||||
// parameters substituted for the formals.
|
||||
// Invoking a macro does not touch the PC/line history.
|
||||
|
||||
@@ -20,20 +20,16 @@ import (
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/telemetry/counter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("asm: ")
|
||||
counter.Open()
|
||||
|
||||
buildcfg.Check()
|
||||
GOARCH := buildcfg.GOARCH
|
||||
|
||||
flags.Parse()
|
||||
counter.Inc("asm/invocations")
|
||||
counter.CountFlags("asm/flag:", *flag.CommandLine)
|
||||
|
||||
architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink)
|
||||
if architecture == nil {
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"cmd/internal/buildid"
|
||||
"cmd/internal/telemetry/counter"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
@@ -26,11 +25,8 @@ var wflag = flag.Bool("w", false, "write build ID")
|
||||
func main() {
|
||||
log.SetPrefix("buildid: ")
|
||||
log.SetFlags(0)
|
||||
counter.Open()
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
counter.Inc("buildid/invocations")
|
||||
counter.CountFlags("buildid/flag:", *flag.CommandLine)
|
||||
if flag.NArg() != 1 {
|
||||
usage()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user