mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
115 Commits
dev.corety
...
go1.22.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7529d09a11 | ||
|
|
d4c53812e6 | ||
|
|
2092294f2b | ||
|
|
b232596139 | ||
|
|
e87be9833e | ||
|
|
676d6100d8 | ||
|
|
0a525a3ed0 | ||
|
|
cb4eee693c | ||
|
|
8c8adffd53 | ||
|
|
70a1aae67f | ||
|
|
2c88c1d599 | ||
|
|
4c50f9162c | ||
|
|
9e148a4150 | ||
|
|
4b27560db9 | ||
|
|
4e548f2c8e | ||
|
|
45f9ded1df | ||
|
|
49906f9575 | ||
|
|
ea96074191 | ||
|
|
8e1fdea831 | ||
|
|
c2d4f852ce | ||
|
|
3222951439 | ||
|
|
ceaf26ecce | ||
|
|
dfe4dbf8c0 | ||
|
|
3560cf0afb | ||
|
|
5159a7193a | ||
|
|
11b861e459 | ||
|
|
81fc616267 | ||
|
|
14f0251867 | ||
|
|
ab60a7bc18 | ||
|
|
4c97e883b5 | ||
|
|
179ccb7042 | ||
|
|
fe9b3c3399 | ||
|
|
b515c5208b | ||
|
|
ace5bb40d0 | ||
|
|
12d5810cdb | ||
|
|
745657509e | ||
|
|
95389d3d9d | ||
|
|
cf501ac0c5 | ||
|
|
cb55d1a0c8 | ||
|
|
3c96ae0870 | ||
|
|
6b89e7dc5a | ||
|
|
185457da9b | ||
|
|
3a84293118 | ||
|
|
362dcedfdb | ||
|
|
d4a81ec7ee | ||
|
|
dc8976dd0b | ||
|
|
00e6815208 | ||
|
|
adbfb672ba | ||
|
|
fa0292d252 | ||
|
|
947e43e371 | ||
|
|
9d2e28501c | ||
|
|
93d8777d24 | ||
|
|
3f4af1ff0e | ||
|
|
a7ff78d585 | ||
|
|
12c1177045 | ||
|
|
d6c972ad41 | ||
|
|
a65a2bbd8e | ||
|
|
dddf0ae40f | ||
|
|
e55d7cf843 | ||
|
|
4edf4bb2c6 | ||
|
|
2c6d106541 | ||
|
|
46587483e3 | ||
|
|
0a5b33a883 | ||
|
|
0c53f93faa | ||
|
|
abfd578156 | ||
|
|
7fb7acb82d | ||
|
|
e23707b59c | ||
|
|
3826650c99 | ||
|
|
e71b0b1fee | ||
|
|
9508eae5d1 | ||
|
|
35b1a146d9 | ||
|
|
db6097f8cb | ||
|
|
041a47712e | ||
|
|
3a855208e3 | ||
|
|
337b8e9cbf | ||
|
|
16830ab48a | ||
|
|
056b0edcb8 | ||
|
|
f73eba76a0 | ||
|
|
5330cd225b | ||
|
|
d8c4239f08 | ||
|
|
c33adf44ff | ||
|
|
3b71998078 | ||
|
|
8fe2ad6494 | ||
|
|
686662f3a4 | ||
|
|
6cbe522fe1 | ||
|
|
fb86598cd3 | ||
|
|
6fbd01a711 | ||
|
|
d6a271939f | ||
|
|
20107e05a6 | ||
|
|
53d1b73dff | ||
|
|
dd31ad7e9f | ||
|
|
a10e42f219 | ||
|
|
b0957cfcf9 | ||
|
|
58a35fe55b | ||
|
|
4c5517913c | ||
|
|
5d647ed9fc | ||
|
|
e34f6a9928 | ||
|
|
7b3786bbb1 | ||
|
|
9289b9c336 | ||
|
|
aa721d1e7d | ||
|
|
117d7b107e | ||
|
|
333ecd4b40 | ||
|
|
1e1da49105 | ||
|
|
817009da40 | ||
|
|
b29ec30780 | ||
|
|
10e9ab55c8 | ||
|
|
ba8e9e14f4 | ||
|
|
77e9c26960 | ||
|
|
fe55bbcfd1 | ||
|
|
9a70e17e0f | ||
|
|
66f8e1e817 | ||
|
|
fa72f3e034 | ||
|
|
fb23428a85 | ||
|
|
f06eaf0c4f | ||
|
|
796f59df92 |
2
.github/ISSUE_TEMPLATE/03-gopls.yml
vendored
2
.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"
|
||||
|
||||
@@ -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
|
||||
|
||||
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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
191
doc/go_spec.html
191
doc/go_spec.html
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Language version go1.24 (Nov 20, 2024)",
|
||||
"Subtitle": "Language version go1.22 (Feb 6, 2024)",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -674,7 +674,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 +861,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 +1086,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 +1127,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>
|
||||
@@ -1682,7 +1682,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 +1926,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>
|
||||
|
||||
@@ -2511,12 +2510,12 @@ 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 +2525,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>
|
||||
|
||||
@@ -3093,7 +3074,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 +3098,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>
|
||||
@@ -5056,7 +5021,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 +5111,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>
|
||||
@@ -5576,7 +5541,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.
|
||||
@@ -6654,8 +6619,7 @@ In that case, the example above prints
|
||||
<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 [<a href="#Go_1.22">Go 1.22</a>].
|
||||
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 +6632,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 +6655,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 value i see below
|
||||
</pre>
|
||||
|
||||
<ol>
|
||||
@@ -6745,34 +6702,10 @@ 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>
|
||||
For an integer value <code>n</code>, 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>.
|
||||
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>
|
||||
@@ -6782,7 +6715,11 @@ The iteration variables may be declared by the "range" clause using a form of
|
||||
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.
|
||||
If the range expression is a (possibly untyped) integer expression <code>n</code>,
|
||||
the variable has the same type as if it was
|
||||
<a href="#Variable_declarations">declared</a> with initialization
|
||||
expression <code>n</code>.
|
||||
Otherwise, the variables have the types of their respective iteration values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -6790,6 +6727,9 @@ 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>.
|
||||
If the range expression is a (possibly untyped) integer expression <code>n</code>,
|
||||
<code>n</code> too must be <a href="#Assignability">assignable</a> to the iteration variable;
|
||||
if there is no iteration variable, <code>n</code> must be assignable to <code>int</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -6837,48 +6777,6 @@ for i := range 10 {
|
||||
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 +7300,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>
|
||||
|
||||
@@ -8715,21 +8613,6 @@ 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>
|
||||
|
||||
162
doc/godebug.md
162
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)
|
||||
@@ -405,7 +259,7 @@ There is no plan to remove this setting.
|
||||
|
||||
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=2023d
|
||||
DATA=2023d
|
||||
|
||||
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,7 @@ 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
|
||||
|
||||
const (
|
||||
// Mode constants from the USTAR spec:
|
||||
@@ -640,10 +639,6 @@ const (
|
||||
// Since fs.FileInfo's Name method only returns the base name of
|
||||
// the file it describes, it may be necessary to modify Header.Name
|
||||
// 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.
|
||||
func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
if fi == nil {
|
||||
return nil, errors.New("archive/tar: FileInfo is nil")
|
||||
@@ -697,45 +692,31 @@ 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)
|
||||
}
|
||||
var doNameLookups = true
|
||||
if iface, ok := fi.(FileInfoNames); ok {
|
||||
doNameLookups = false
|
||||
var err error
|
||||
h.Gname, err = iface.Gname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.Uname, err = iface.Uname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if sys.PAXRecords != nil {
|
||||
h.PAXRecords = make(map[string]string)
|
||||
for k, v := range sys.PAXRecords {
|
||||
h.PAXRecords[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
if sysStat != nil {
|
||||
return h, sysStat(fi, h, doNameLookups)
|
||||
return h, sysStat(fi, h)
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// FileInfoNames extends [fs.FileInfo].
|
||||
// Passing an instance of this to [FileInfoHeader] permits the caller
|
||||
// to avoid a system-dependent name lookup by specifying the Uname and Gname directly.
|
||||
type FileInfoNames interface {
|
||||
fs.FileInfo
|
||||
// Uname should give a user name.
|
||||
Uname() (string, error)
|
||||
// Gname should give a group name.
|
||||
Gname() (string, error)
|
||||
}
|
||||
|
||||
// isHeaderOnlyType checks if the given type flag is of the type that has no
|
||||
// data section even if a size is specified.
|
||||
func isHeaderOnlyType(flag byte) bool {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -23,30 +23,30 @@ func init() {
|
||||
// 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)
|
||||
|
||||
|
||||
@@ -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) {
|
||||
@@ -846,53 +848,3 @@ func Benchmark(b *testing.B) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
var _ fileInfoNames = fileInfoNames{}
|
||||
|
||||
type fileInfoNames struct{}
|
||||
|
||||
func (f *fileInfoNames) Name() string {
|
||||
return "tmp"
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Size() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Mode() fs.FileMode {
|
||||
return 0777
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) ModTime() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Uname() (string, error) {
|
||||
return "Uname", nil
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Gname() (string, error) {
|
||||
return "Gname", nil
|
||||
}
|
||||
|
||||
func TestFileInfoHeaderUseFileInfoNames(t *testing.T) {
|
||||
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")
|
||||
}
|
||||
if header.Gname != "Gname" {
|
||||
t.Fatalf("header.Gname: got %s, want %s", 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"
|
||||
@@ -862,19 +862,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 +897,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 +920,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 +935,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"
|
||||
@@ -912,7 +912,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 +1276,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 +1582,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 +1695,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 +1720,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
|
||||
|
||||
@@ -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' {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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, ", "))
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
84
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
84
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@@ -196,10 +196,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 +234,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 +253,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 +487,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 +660,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 +670,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 +742,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 +1132,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()
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ func (f *File) ParseGo(abspath string, src []byte) {
|
||||
// Like ast.CommentGroup's Text method but preserves
|
||||
// leading blank lines, so that line numbers line up.
|
||||
func commentText(g *ast.CommentGroup) string {
|
||||
pieces := make([]string, 0, len(g.List))
|
||||
var pieces []string
|
||||
for _, com := range g.List {
|
||||
c := com.Text
|
||||
// Remove comment markers.
|
||||
|
||||
@@ -163,14 +163,10 @@ type in Go are instead represented by a uintptr. See the Special
|
||||
cases section below.
|
||||
|
||||
To access a struct, union, or enum type directly, prefix it with
|
||||
struct_, union_, or enum_, as in C.struct_stat. The size of any C type
|
||||
T is available as C.sizeof_T, as in C.sizeof_struct_stat. These
|
||||
special prefixes means that there is no way to directly reference a C
|
||||
identifier that starts with "struct_", "union_", "enum_", or
|
||||
"sizeof_", such as a function named "struct_function".
|
||||
A workaround is to use a "#define" in the preamble, as in
|
||||
"#define c_struct_function struct_function" and then in the
|
||||
Go code refer to "C.c_struct_function".
|
||||
struct_, union_, or enum_, as in C.struct_stat.
|
||||
|
||||
The size of any C type T is available as C.sizeof_T, as in
|
||||
C.sizeof_struct_stat.
|
||||
|
||||
A C function may be declared in the Go file with a parameter type of
|
||||
the special name _GoString_. This function may be called with an
|
||||
@@ -209,17 +205,6 @@ function returns void). For example:
|
||||
_, err := C.voidFunc()
|
||||
var n, err = C.sqrt(1)
|
||||
|
||||
Note that the C errno value may be non-zero, and thus the err result may be
|
||||
non-nil, even if the function call is successful. Unlike normal Go conventions,
|
||||
you should first check whether the call succeeded before checking the error
|
||||
result. For example:
|
||||
|
||||
n, err := C.setenv(key, value, 1)
|
||||
if n != 0 {
|
||||
// we know the call failed, so it is now valid to use err
|
||||
return err
|
||||
}
|
||||
|
||||
Calling C function pointers is currently not supported, however you can
|
||||
declare Go variables which hold C function pointers and pass them
|
||||
back and forth between Go and C. C code may call function pointers
|
||||
@@ -358,12 +343,12 @@ determined by how the memory was allocated; it has nothing to do with
|
||||
the type of the pointer.
|
||||
|
||||
Note that values of some Go types, other than the type's zero value,
|
||||
always include Go pointers. This is true of interface, channel, map,
|
||||
and function types. A pointer type may hold a Go pointer or a C pointer.
|
||||
Array, slice, string, and struct types may or may not include Go pointers,
|
||||
depending on their type and how they are constructed. All the discussion
|
||||
below about Go pointers applies not just to pointer types,
|
||||
but also to other types that include Go pointers.
|
||||
always include Go pointers. This is true of string, slice, interface,
|
||||
channel, map, and function types. A pointer type may hold a Go pointer
|
||||
or a C pointer. Array and struct types may or may not include Go
|
||||
pointers, depending on the element types. All the discussion below
|
||||
about Go pointers applies not just to pointer types, but also to other
|
||||
types that include Go pointers.
|
||||
|
||||
All Go pointers passed to C must point to pinned Go memory. Go pointers
|
||||
passed as function arguments to C functions have the memory they point to
|
||||
@@ -417,8 +402,7 @@ controlled by the cgocheck setting of the GODEBUG environment
|
||||
variable. The default setting is GODEBUG=cgocheck=1, which implements
|
||||
reasonably cheap dynamic checks. These checks may be disabled
|
||||
entirely using GODEBUG=cgocheck=0. Complete checking of pointer
|
||||
handling, at some cost in run time, is available by setting
|
||||
GOEXPERIMENT=cgocheck2 at build time.
|
||||
handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
|
||||
|
||||
It is possible to defeat this enforcement by using the unsafe package,
|
||||
and of course there is nothing stopping the C code from doing anything
|
||||
@@ -436,30 +420,6 @@ passing uninitialized C memory to Go code if the Go code is going to
|
||||
store pointer values in it. Zero out the memory in C before passing it
|
||||
to Go.
|
||||
|
||||
# Optimizing calls of C code
|
||||
|
||||
When passing a Go pointer to a C function the compiler normally ensures
|
||||
that the Go object lives on the heap. If the C function does not keep
|
||||
a copy of the Go pointer, and never passes the Go pointer back to Go code,
|
||||
then this is unnecessary. The #cgo noescape directive may be used to tell
|
||||
the compiler that no Go pointers escape via the named C function.
|
||||
If the noescape directive is used and the C function does not handle the
|
||||
pointer safely, the program may crash or see memory corruption.
|
||||
|
||||
For example:
|
||||
|
||||
// #cgo noescape cFunctionName
|
||||
|
||||
When a Go function calls a C function, it prepares for the C function to
|
||||
call back to a Go function. The #cgo nocallback directive may be used to
|
||||
tell the compiler that these preparations are not necessary.
|
||||
If the nocallback directive is used and the C function does call back into
|
||||
Go code, the program will panic.
|
||||
|
||||
For example:
|
||||
|
||||
// #cgo nocallback cFunctionName
|
||||
|
||||
# Special cases
|
||||
|
||||
A few special C types which would normally be represented by a pointer
|
||||
@@ -545,6 +505,15 @@ The following options are available when running cgo directly:
|
||||
If there are any exported functions, write the
|
||||
generated export declarations to file.
|
||||
C code can #include this to see the declarations.
|
||||
-importpath string
|
||||
The import path for the Go package. Optional; used for
|
||||
nicer comments in the generated files.
|
||||
-import_runtime_cgo
|
||||
If set (which it is by default) import runtime/cgo in
|
||||
generated output.
|
||||
-import_syscall
|
||||
If set (which it is by default) import syscall in
|
||||
generated output.
|
||||
-gccgo
|
||||
Generate output for the gccgo compiler rather than the
|
||||
gc compiler.
|
||||
@@ -559,25 +528,9 @@ The following options are available when running cgo directly:
|
||||
Write out input file in Go syntax replacing C package
|
||||
names with real values. Used to generate files in the
|
||||
syscall package when bootstrapping a new target.
|
||||
-importpath string
|
||||
The import path for the Go package. Optional; used for
|
||||
nicer comments in the generated files.
|
||||
-import_runtime_cgo
|
||||
If set (which it is by default) import runtime/cgo in
|
||||
generated output.
|
||||
-import_syscall
|
||||
If set (which it is by default) import syscall in
|
||||
generated output.
|
||||
-ldflags flags
|
||||
Flags to pass to the C linker. The cmd/go tool uses
|
||||
this to pass in the flags in the CGO_LDFLAGS variable.
|
||||
-objdir directory
|
||||
Put all generated files in directory.
|
||||
-srcdir directory
|
||||
Find the Go input files, listed on the command line,
|
||||
in directory.
|
||||
-trimpath rewrites
|
||||
Apply trims and rewrites to source file paths.
|
||||
*/
|
||||
package main
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
@@ -59,17 +58,17 @@ func cname(s string) string {
|
||||
return t
|
||||
}
|
||||
|
||||
if t, ok := strings.CutPrefix(s, "struct_"); ok {
|
||||
return "struct " + t
|
||||
if strings.HasPrefix(s, "struct_") {
|
||||
return "struct " + s[len("struct_"):]
|
||||
}
|
||||
if t, ok := strings.CutPrefix(s, "union_"); ok {
|
||||
return "union " + t
|
||||
if strings.HasPrefix(s, "union_") {
|
||||
return "union " + s[len("union_"):]
|
||||
}
|
||||
if t, ok := strings.CutPrefix(s, "enum_"); ok {
|
||||
return "enum " + t
|
||||
if strings.HasPrefix(s, "enum_") {
|
||||
return "enum " + s[len("enum_"):]
|
||||
}
|
||||
if t, ok := strings.CutPrefix(s, "sizeof_"); ok {
|
||||
return "sizeof(" + cname(t) + ")"
|
||||
if strings.HasPrefix(s, "sizeof_") {
|
||||
return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -95,8 +94,10 @@ func (f *File) ProcessCgoDirectives() {
|
||||
directive := fields[1]
|
||||
funcName := fields[2]
|
||||
if directive == "nocallback" {
|
||||
fatalf("#cgo nocallback disabled until Go 1.23")
|
||||
f.NoCallbacks[funcName] = true
|
||||
} else if directive == "noescape" {
|
||||
fatalf("#cgo noescape disabled until Go 1.23")
|
||||
f.NoEscapes[funcName] = true
|
||||
}
|
||||
}
|
||||
@@ -194,6 +195,7 @@ func (p *Package) Translate(f *File) {
|
||||
var conv typeConv
|
||||
conv.Init(p.PtrSize, p.IntSize)
|
||||
|
||||
p.loadDefines(f)
|
||||
p.typedefs = map[string]bool{}
|
||||
p.typedefList = nil
|
||||
numTypedefs := -1
|
||||
@@ -233,14 +235,12 @@ func (p *Package) Translate(f *File) {
|
||||
|
||||
// loadDefines coerces gcc into spitting out the #defines in use
|
||||
// in the file f and saves relevant renamings in f.Name[name].Define.
|
||||
// Returns true if env:CC is Clang
|
||||
func (f *File) loadDefines(gccOptions []string) bool {
|
||||
func (p *Package) loadDefines(f *File) {
|
||||
var b bytes.Buffer
|
||||
b.WriteString(builtinProlog)
|
||||
b.WriteString(f.Preamble)
|
||||
stdout := gccDefines(b.Bytes(), gccOptions)
|
||||
stdout := p.gccDefines(b.Bytes())
|
||||
|
||||
var gccIsClang bool
|
||||
for _, line := range strings.Split(stdout, "\n") {
|
||||
if len(line) < 9 || line[0:7] != "#define" {
|
||||
continue
|
||||
@@ -263,7 +263,7 @@ func (f *File) loadDefines(gccOptions []string) bool {
|
||||
}
|
||||
|
||||
if key == "__clang__" {
|
||||
gccIsClang = true
|
||||
p.GccIsClang = true
|
||||
}
|
||||
|
||||
if n := f.Name[key]; n != nil {
|
||||
@@ -273,7 +273,6 @@ func (f *File) loadDefines(gccOptions []string) bool {
|
||||
n.Define = val
|
||||
}
|
||||
}
|
||||
return gccIsClang
|
||||
}
|
||||
|
||||
// guessKinds tricks gcc into revealing the kind of each
|
||||
@@ -490,7 +489,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||
// Don't report an error, and skip adding n to the needType array.
|
||||
continue
|
||||
}
|
||||
error_(f.NamePos[n], "could not determine what C.%s refers to", fixGo(n.Go))
|
||||
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notStrLiteral | notType:
|
||||
n.Kind = "iconst"
|
||||
case notIntConst | notStrLiteral | notType:
|
||||
@@ -782,13 +781,16 @@ func (p *Package) mangleName(n *Name) {
|
||||
}
|
||||
|
||||
func (f *File) isMangledName(s string) bool {
|
||||
t, ok := strings.CutPrefix(s, "_C")
|
||||
if !ok {
|
||||
return false
|
||||
prefix := "_C"
|
||||
if strings.HasPrefix(s, prefix) {
|
||||
t := s[len(prefix):]
|
||||
for _, k := range nameKinds {
|
||||
if strings.HasPrefix(t, k+"_") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return slices.ContainsFunc(nameKinds, func(k string) bool {
|
||||
return strings.HasPrefix(t, k+"_")
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
// rewriteCalls rewrites all calls that pass pointers to check that
|
||||
@@ -922,7 +924,7 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
|
||||
if rtype != name.FuncType.Result.Go {
|
||||
needsUnsafe = true
|
||||
}
|
||||
sb.WriteString(gofmt(rtype))
|
||||
sb.WriteString(gofmtLine(rtype))
|
||||
result = true
|
||||
}
|
||||
|
||||
@@ -958,7 +960,7 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
|
||||
needsUnsafe = true
|
||||
}
|
||||
fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
|
||||
gofmt(ptype), gofmtPos(arg, origArg.Pos()))
|
||||
gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1048,9 +1050,12 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
||||
}
|
||||
return p.hasPointer(f, t.Elt, top)
|
||||
case *ast.StructType:
|
||||
return slices.ContainsFunc(t.Fields.List, func(field *ast.Field) bool {
|
||||
return p.hasPointer(f, field.Type, top)
|
||||
})
|
||||
for _, field := range t.Fields.List {
|
||||
if p.hasPointer(f, field.Type, top) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case *ast.StarExpr: // Pointer type.
|
||||
if !top {
|
||||
return true
|
||||
@@ -1596,8 +1601,8 @@ func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
|
||||
break
|
||||
}
|
||||
if r.Context == ctxCall2 {
|
||||
if builtinDefs[r.Name.Go] != "" {
|
||||
error_(r.Pos(), "no two-result form for C.%s", r.Name.Go)
|
||||
if r.Name.Go == "_CMalloc" {
|
||||
error_(r.Pos(), "no two-result form for C.malloc")
|
||||
break
|
||||
}
|
||||
// Invent new Name for the two-result function.
|
||||
@@ -1677,7 +1682,7 @@ func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
|
||||
// gofmtPos returns the gofmt-formatted string for an AST node,
|
||||
// with a comment setting the position before the node.
|
||||
func gofmtPos(n ast.Expr, pos token.Pos) string {
|
||||
s := gofmt(n)
|
||||
s := gofmtLine(n)
|
||||
p := fset.Position(pos)
|
||||
if p.Column == 0 {
|
||||
return s
|
||||
@@ -1719,7 +1724,7 @@ func checkGCCBaseCmd() ([]string, error) {
|
||||
}
|
||||
|
||||
// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
|
||||
func gccMachine() []string {
|
||||
func (p *Package) gccMachine() []string {
|
||||
switch goarch {
|
||||
case "amd64":
|
||||
if goos == "darwin" {
|
||||
@@ -1792,7 +1797,7 @@ func (p *Package) gccCmd() []string {
|
||||
}
|
||||
|
||||
c = append(c, p.GccOptions...)
|
||||
c = append(c, gccMachine()...)
|
||||
c = append(c, p.gccMachine()...)
|
||||
if goos == "aix" {
|
||||
c = append(c, "-maix64")
|
||||
c = append(c, "-mcmodel=large")
|
||||
@@ -1833,8 +1838,8 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
|
||||
if strings.HasPrefix(s, "___") {
|
||||
s = s[1:]
|
||||
}
|
||||
if t, ok := strings.CutPrefix(s, "__cgodebug_strlen__"); ok {
|
||||
if n, err := strconv.Atoi(t); err == nil {
|
||||
if strings.HasPrefix(s, "__cgodebug_strlen__") {
|
||||
if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil {
|
||||
return n
|
||||
}
|
||||
}
|
||||
@@ -2184,10 +2189,10 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
|
||||
// and returns the corresponding standard output, which is the
|
||||
// #defines that gcc encountered while processing the input
|
||||
// and its included files.
|
||||
func gccDefines(stdin []byte, gccOptions []string) string {
|
||||
func (p *Package) gccDefines(stdin []byte) string {
|
||||
base := append(gccBaseCmd, "-E", "-dM", "-xc")
|
||||
base = append(base, gccMachine()...)
|
||||
stdout, _ := runGcc(stdin, append(append(base, gccOptions...), "-"))
|
||||
base = append(base, p.gccMachine()...)
|
||||
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
|
||||
return stdout
|
||||
}
|
||||
|
||||
@@ -2574,11 +2579,6 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||
if dt.BitSize > 0 {
|
||||
fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
|
||||
}
|
||||
|
||||
if t.Align = t.Size; t.Align >= c.ptrSize {
|
||||
t.Align = c.ptrSize
|
||||
}
|
||||
|
||||
switch t.Size {
|
||||
default:
|
||||
fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
|
||||
@@ -2595,8 +2595,9 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||
Len: c.intExpr(t.Size),
|
||||
Elt: c.uint8,
|
||||
}
|
||||
// t.Align is the alignment of the Go type.
|
||||
t.Align = 1
|
||||
}
|
||||
if t.Align = t.Size; t.Align >= c.ptrSize {
|
||||
t.Align = c.ptrSize
|
||||
}
|
||||
|
||||
case *dwarf.PtrType:
|
||||
@@ -2825,11 +2826,6 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||
if dt.BitSize > 0 {
|
||||
fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
|
||||
}
|
||||
|
||||
if t.Align = t.Size; t.Align >= c.ptrSize {
|
||||
t.Align = c.ptrSize
|
||||
}
|
||||
|
||||
switch t.Size {
|
||||
default:
|
||||
fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
|
||||
@@ -2846,8 +2842,9 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||
Len: c.intExpr(t.Size),
|
||||
Elt: c.uint8,
|
||||
}
|
||||
// t.Align is the alignment of the Go type.
|
||||
t.Align = 1
|
||||
}
|
||||
if t.Align = t.Size; t.Align >= c.ptrSize {
|
||||
t.Align = c.ptrSize
|
||||
}
|
||||
|
||||
case *dwarf.VoidType:
|
||||
@@ -3113,11 +3110,10 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
||||
}
|
||||
|
||||
// Round off up to talign, assumed to be a power of 2.
|
||||
origOff := off
|
||||
off = (off + talign - 1) &^ (talign - 1)
|
||||
|
||||
if f.ByteOffset > off {
|
||||
fld, sizes = c.pad(fld, sizes, f.ByteOffset-origOff)
|
||||
fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
|
||||
off = f.ByteOffset
|
||||
}
|
||||
if f.ByteOffset < off {
|
||||
@@ -3197,9 +3193,12 @@ func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
|
||||
return c.dwarfHasPointer(dt.Type, pos)
|
||||
|
||||
case *dwarf.StructType:
|
||||
return slices.ContainsFunc(dt.Field, func(f *dwarf.StructField) bool {
|
||||
return c.dwarfHasPointer(f.Type, pos)
|
||||
})
|
||||
for _, f := range dt.Field {
|
||||
if c.dwarfHasPointer(f.Type, pos) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
case *dwarf.TypedefType:
|
||||
if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
|
||||
|
||||
@@ -125,3 +125,46 @@ func gofmt(n interface{}) string {
|
||||
}
|
||||
return gofmtBuf.String()
|
||||
}
|
||||
|
||||
// gofmtLineReplacer is used to put a gofmt-formatted string for an
|
||||
// AST expression onto a single line. The lexer normally inserts a
|
||||
// semicolon at each newline, so we can replace newline with semicolon.
|
||||
// However, we can't do that in cases where the lexer would not insert
|
||||
// a semicolon. We only have to worry about cases that can occur in an
|
||||
// expression passed through gofmt, which means composite literals and
|
||||
// (due to the printer possibly inserting newlines because of position
|
||||
// information) operators.
|
||||
var gofmtLineReplacer = strings.NewReplacer(
|
||||
// Want to replace \n without ; after everything from
|
||||
// https://golang.org/ref/spec#Operators_and_punctuation
|
||||
// EXCEPT ++ -- ) ] }
|
||||
"++\n", "++;",
|
||||
"--\n", "--;",
|
||||
|
||||
"+\n", "+ ",
|
||||
"-\n", "- ",
|
||||
"*\n", "* ",
|
||||
"/\n", "/ ",
|
||||
"%\n", "% ",
|
||||
"&\n", "& ",
|
||||
"|\n", "| ",
|
||||
"^\n", "^ ",
|
||||
"<\n", "< ",
|
||||
">\n", "> ",
|
||||
"=\n", "= ",
|
||||
"!\n", "! ", // not possible in gofmt today
|
||||
"(\n", "(",
|
||||
"[\n", "[", // not possible in gofmt today
|
||||
"{\n", "{",
|
||||
",\n", ",",
|
||||
".\n", ". ",
|
||||
":\n", ": ", // not possible in gofmt today
|
||||
|
||||
"\n", ";",
|
||||
)
|
||||
|
||||
// gofmtLine returns the gofmt-formatted string for an AST node,
|
||||
// ensuring that it is on a single line.
|
||||
func gofmtLine(n interface{}) string {
|
||||
return gofmtLineReplacer.Replace(gofmt(n))
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ func testCallbackCallersSEH(t *testing.T) {
|
||||
want := []string{
|
||||
"test._Cfunc_backtrace",
|
||||
"test.testCallbackCallersSEH.func1.1",
|
||||
// "test.testCallbackCallersSEH.func1", // hidden by inlining
|
||||
"test.testCallbackCallersSEH.func1",
|
||||
"test.goCallback",
|
||||
"test._Cfunc_callback",
|
||||
"test.nestedCall.func1",
|
||||
// "test.nestedCall", // hidden by inlining
|
||||
"test.nestedCall",
|
||||
"test.testCallbackCallersSEH",
|
||||
"test.TestCallbackCallersSEH",
|
||||
}
|
||||
@@ -84,7 +84,6 @@ func testCallbackCallersSEH(t *testing.T) {
|
||||
})
|
||||
got := make([]string, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
// This test is brittle in the face of inliner changes
|
||||
f := runtime.FuncForPC(pc[i] - 1)
|
||||
if f == nil {
|
||||
continue
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package cgotest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
@@ -15,6 +16,9 @@ func TestSetgid(t *testing.T) {
|
||||
if runtime.GOOS == "android" {
|
||||
t.Skip("unsupported on Android")
|
||||
}
|
||||
if _, err := os.Stat("/etc/alpine-release"); err == nil {
|
||||
t.Skip("setgid is broken with musl libc - go.dev/issue/39857")
|
||||
}
|
||||
testSetgid(t)
|
||||
}
|
||||
|
||||
@@ -22,11 +26,20 @@ func TestSetgidStress(t *testing.T) {
|
||||
if runtime.GOOS == "android" {
|
||||
t.Skip("unsupported on Android")
|
||||
}
|
||||
if _, err := os.Stat("/etc/alpine-release"); err == nil {
|
||||
t.Skip("setgid is broken with musl libc - go.dev/issue/39857")
|
||||
}
|
||||
testSetgidStress(t)
|
||||
}
|
||||
|
||||
func Test1435(t *testing.T) { test1435(t) }
|
||||
func Test6997(t *testing.T) { test6997(t) }
|
||||
func Test9400(t *testing.T) { test9400(t) }
|
||||
|
||||
func Test9400(t *testing.T) {
|
||||
if _, err := os.Stat("/etc/alpine-release"); err == nil {
|
||||
t.Skip("setgid is broken with musl libc - go.dev/issue/39857")
|
||||
}
|
||||
test9400(t)
|
||||
}
|
||||
|
||||
func TestBuildID(t *testing.T) { testBuildID(t) }
|
||||
|
||||
@@ -1,15 +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 (ppc64 || ppc64le) && internal
|
||||
|
||||
package cgotest
|
||||
|
||||
import "testing"
|
||||
|
||||
// If gcc is used, and linking internally, __mulsc3 and __muldc3
|
||||
// will be linked in from libgcc which make several R_PPC64_TOC16_DS
|
||||
// relocations which may not be resolvable with the internal linker.
|
||||
func test8694(t *testing.T) { t.Skip("not supported on ppc64/ppc64le with internal linking") }
|
||||
func test9510(t *testing.T) { t.Skip("not supported on ppc64/ppc64le with internal linking") }
|
||||
@@ -70,7 +70,6 @@ func Test31891(t *testing.T) { test31891(t) }
|
||||
func Test42018(t *testing.T) { test42018(t) }
|
||||
func Test45451(t *testing.T) { test45451(t) }
|
||||
func Test49633(t *testing.T) { test49633(t) }
|
||||
func Test69086(t *testing.T) { test69086(t) }
|
||||
func TestAlign(t *testing.T) { testAlign(t) }
|
||||
func TestAtol(t *testing.T) { testAtol(t) }
|
||||
func TestBlocking(t *testing.T) { testBlocking(t) }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !android && !((ppc64 || ppc64le) && internal)
|
||||
//go:build !android
|
||||
|
||||
package cgotest
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user