mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
99 Commits
dev.corety
...
go1.23.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d375ae5063 | ||
|
|
b897e97c36 | ||
|
|
c2c89d9551 | ||
|
|
8eeb1340b2 | ||
|
|
4ca7c01706 | ||
|
|
f77084d15d | ||
|
|
8ff45d1aa0 | ||
|
|
96537d5044 | ||
|
|
7a2cfb70b0 | ||
|
|
c72a2bad68 | ||
|
|
2c0a0fc6b9 | ||
|
|
c855149768 | ||
|
|
ec6e84df74 | ||
|
|
15e01a2e43 | ||
|
|
45aade7f1e | ||
|
|
c01c4d41d6 | ||
|
|
25177ecde0 | ||
|
|
e4772831d3 | ||
|
|
9facf1f2c2 | ||
|
|
0fa31cb69f | ||
|
|
d89fda21d5 | ||
|
|
acde84cf1b | ||
|
|
c57e2bd22c | ||
|
|
2aaa388971 | ||
|
|
22fdd35c24 | ||
|
|
a991f9c34d | ||
|
|
6644ed63b1 | ||
|
|
ab44565bcd | ||
|
|
9cbbf5e0f4 | ||
|
|
d04e3cbc92 | ||
|
|
bb8230f805 | ||
|
|
fdb8413fe5 | ||
|
|
1dde0b4844 | ||
|
|
3417000c69 | ||
|
|
1576793c51 | ||
|
|
59b7d40774 | ||
|
|
69c8cfe29b | ||
|
|
194de8fbfa | ||
|
|
5164a865e3 | ||
|
|
25f042daec | ||
|
|
be062b7f61 | ||
|
|
d8adc6c4c7 | ||
|
|
847cb6f9ca | ||
|
|
777f43ab27 | ||
|
|
3726f07c46 | ||
|
|
c390a1c22e | ||
|
|
1207de4f6c | ||
|
|
a0d15cb9c8 | ||
|
|
958f3a0309 | ||
|
|
6ba3a8a6ba | ||
|
|
5472853843 | ||
|
|
cfe0ae0b70 | ||
|
|
58babf6e0b | ||
|
|
8d79bf799b | ||
|
|
35c010ad6d | ||
|
|
6495ce0495 | ||
|
|
7fc8312673 | ||
|
|
cc16cdf48f | ||
|
|
9563300f6e | ||
|
|
f8080edefd | ||
|
|
ed07b321ae | ||
|
|
3b2e846e11 | ||
|
|
fbddfae62f | ||
|
|
c8c6f9abfb | ||
|
|
a74951c5af | ||
|
|
e6598e7baa | ||
|
|
82575f76b8 | ||
|
|
a886959aa2 | ||
|
|
80ff7cd35a | ||
|
|
69234ded30 | ||
|
|
032ac075c2 | ||
|
|
fa8ff1a46d | ||
|
|
53487e5477 | ||
|
|
3d1f1f27cf | ||
|
|
6de5a7180c | ||
|
|
9625a7faae | ||
|
|
9c939a1e60 | ||
|
|
7afe17bbdb | ||
|
|
8002845759 | ||
|
|
9166d2feec | ||
|
|
76346b3543 | ||
|
|
3c9340557c | ||
|
|
dbecb416d1 | ||
|
|
6885bad7dd | ||
|
|
ec7d6094e6 | ||
|
|
63b0f805cd | ||
|
|
7adb012205 | ||
|
|
c9940fe2a9 | ||
|
|
3509415eca | ||
|
|
559c77592f | ||
|
|
f5e4e45ef7 | ||
|
|
30b6fd60a6 | ||
|
|
7e4d6c2bcb | ||
|
|
8bd4ed6cbb | ||
|
|
7dff7439dc | ||
|
|
62c3a6350b | ||
|
|
eba9e08766 | ||
|
|
f3bdcda88a | ||
|
|
362f22d2d2 |
@@ -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:
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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.23
|
||||
parent-branch: master
|
||||
|
||||
@@ -70,6 +70,6 @@ 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
|
||||
> 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"
|
||||
}-->
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Language version go1.24 (Nov 20, 2024)",
|
||||
"Subtitle": "Language version go1.23 (June 13, 2024)",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -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>
|
||||
@@ -1927,8 +1927,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 +2511,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 +2526,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 +3075,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 +3099,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>
|
||||
@@ -8721,15 +8687,6 @@ integer values from zero to an upper limit.
|
||||
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>
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -151,68 +150,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
|
||||
@@ -405,7 +342,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,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
|
||||
#
|
||||
@@ -24,8 +24,8 @@
|
||||
# in the CL match the update.bash in the CL.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2024b
|
||||
DATA=2024b
|
||||
CODE=2024a
|
||||
DATA=2024a
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -33,10 +33,6 @@ 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.
|
||||
|
||||
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:
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"fmt"
|
||||
"internal/godebug"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"math"
|
||||
"path"
|
||||
"reflect"
|
||||
@@ -697,14 +696,24 @@ func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
h.Gname = sys.Gname
|
||||
h.AccessTime = sys.AccessTime
|
||||
h.ChangeTime = sys.ChangeTime
|
||||
h.Xattrs = maps.Clone(sys.Xattrs)
|
||||
if sys.Xattrs != nil {
|
||||
h.Xattrs = make(map[string]string)
|
||||
for k, v := range sys.Xattrs {
|
||||
h.Xattrs[k] = v
|
||||
}
|
||||
}
|
||||
if sys.Typeflag == TypeLink {
|
||||
// hard link
|
||||
h.Typeflag = TypeLink
|
||||
h.Size = 0
|
||||
h.Linkname = sys.Linkname
|
||||
}
|
||||
h.PAXRecords = maps.Clone(sys.PAXRecords)
|
||||
if sys.PAXRecords != nil {
|
||||
h.PAXRecords = make(map[string]string)
|
||||
for k, v := range sys.PAXRecords {
|
||||
h.PAXRecords[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
var doNameLookups = true
|
||||
if iface, ok := fi.(FileInfoNames); ok {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -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)
|
||||
}
|
||||
slices.Sort(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,11 +10,10 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"maps"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -902,8 +902,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
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
@@ -1274,7 +1274,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 +1580,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 +1693,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 +1718,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,14 +505,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 +525,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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -247,8 +247,8 @@ 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.
|
||||
|
||||
@@ -213,7 +213,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 +222,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 +274,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 +337,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,7 +8,6 @@ package bytes
|
||||
|
||||
import (
|
||||
"internal/bytealg"
|
||||
"math/bits"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
_ "unsafe" // for linkname
|
||||
@@ -137,7 +136,6 @@ func LastIndexByte(s []byte, c byte) int {
|
||||
// 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 +151,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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +535,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.
|
||||
@@ -651,11 +594,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{}
|
||||
@@ -682,7 +624,10 @@ func Repeat(b []byte, count int) []byte {
|
||||
nb := bytealg.MakeNoZero(n)[:n: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
|
||||
|
||||
@@ -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
|
||||
@@ -935,18 +808,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 +825,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 +866,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 +880,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 +919,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 +939,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 +962,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)
|
||||
}
|
||||
@@ -1438,6 +1286,18 @@ func TestRepeatCatchesOverflow(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
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 {
|
||||
in string
|
||||
out []rune
|
||||
@@ -1458,7 +1318,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 +2044,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)
|
||||
}
|
||||
|
||||
@@ -502,10 +502,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)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,27 @@ 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 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 {
|
||||
if want := "124"; srcLineNo != want {
|
||||
t.Fatalf("line number = %v; want %s", srcLineNo, want)
|
||||
}
|
||||
}
|
||||
|
||||
// This is line 101. The test depends on that.
|
||||
// This is line 123. 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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1019,7 +1019,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 +1083,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, ", "))
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@@ -50,82 +59,6 @@ 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 +77,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.AFCMPO, ppc64.AFCMPU:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -353,7 +353,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 +642,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
|
||||
@@ -823,13 +828,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, sys.RISCV64) && tok == '.' {
|
||||
// Suffixes: ARM conditionals, RISCV rounding mode 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:
|
||||
|
||||
1
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
1
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@@ -1777,7 +1777,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
|
||||
|
||||
287
src/cmd/asm/internal/asm/testdata/loong64enc1.s
vendored
287
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
|
||||
@@ -153,11 +144,6 @@ lable2:
|
||||
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 +197,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,21 +214,21 @@ 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
|
||||
|
||||
@@ -305,214 +281,3 @@ lable2:
|
||||
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
|
||||
|
||||
|
||||
39
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
39
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@@ -508,26 +508,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 +681,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 +691,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 +763,9 @@ 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
|
||||
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
|
||||
FCMPU F1, F2, CR0 // FCMPU F1,CR0,F2 // fc011000
|
||||
LVX (R3)(R4), V1 // 7c2418ce
|
||||
LVX (R3)(R0), V1 // 7c2018ce
|
||||
LVX (R3), V1 // 7c2018ce
|
||||
@@ -1189,8 +1156,6 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
MOVD 4(R1), SPR(3) // ebe100047fe303a6
|
||||
MOVD 4(R1), XER // ebe100047fe103a6
|
||||
OR $0, R0, R0 // 60000000
|
||||
|
||||
PCALIGN $16
|
||||
PNOP // 0700000000000000
|
||||
|
||||
SETB CR1,R3 // 7c640100
|
||||
|
||||
67
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
67
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,7 +231,7 @@ 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
|
||||
@@ -276,21 +272,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,7 +295,7 @@ 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
|
||||
@@ -340,10 +336,11 @@ 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)
|
||||
// RISC-V Bit-Manipulation ISA-extensions (1.0)
|
||||
// 1.1: Address Generation Instructions (Zba)
|
||||
ADDUW X10, X11, X12 // 3b86a508
|
||||
ADDUW X10, X11 // bb85a508
|
||||
SH1ADD X11, X12, X13 // b326b620
|
||||
@@ -363,9 +360,9 @@ start:
|
||||
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
|
||||
// 1.2: Basic Bit Manipulation (Zbb)
|
||||
ANDN X19, X20, X21 // b37a3a41
|
||||
ANDN X19, X20 // 337a3a41
|
||||
CLZ X20, X21 // 931a0a60
|
||||
CLZW X21, X22 // 1b9b0a60
|
||||
CPOP X22, X23 // 931b2b60
|
||||
@@ -380,15 +377,15 @@ start:
|
||||
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
|
||||
ORN X6, X7, X8 // 33e46340
|
||||
ORN X6, X7 // b3e36340
|
||||
SEXTB X16, X17 // 93184860
|
||||
SEXTH X17, X18 // 13995860
|
||||
XNOR X18, X19, X20 // 33ca2941 or 33ca2901134afaff
|
||||
XNOR X18, X19 // b3c92941 or b3c9290193c9f9ff
|
||||
XNOR X18, X19, X20 // 33ca2941
|
||||
XNOR X18, X19 // b3c92941
|
||||
ZEXTH X19, X20 // 3bca0908
|
||||
|
||||
// 28.4.2: Bitwise Rotation (Zbb)
|
||||
// 1.3: Bitwise Rotation (Zbb)
|
||||
ROL X8, X9, X10 // 33958460 or b30f8040b3dff4013395840033e5af00
|
||||
ROL X8, X9 // b3948460 or b30f8040b3dff401b3948400b3e49f00
|
||||
ROLW X9, X10, X11 // bb159560 or b30f9040bb5ff501bb159500b3e5bf00
|
||||
@@ -406,7 +403,7 @@ start:
|
||||
ORCB X5, X6 // 13d37228
|
||||
REV8 X7, X8 // 13d4836b
|
||||
|
||||
// 28.4.4: Single-bit Instructions (Zbs)
|
||||
// 1.5: Single-bit Instructions (Zbs)
|
||||
BCLR X23, X24, X25 // b31c7c49
|
||||
BCLR $63, X24 // 131cfc4b
|
||||
BCLRI $1, X25, X26 // 139d1c48
|
||||
@@ -420,11 +417,9 @@ start:
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
@@ -436,30 +421,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 +506,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 +529,12 @@ 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -3197,9 +3202,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_" {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -117,8 +117,8 @@ int add(int x, int y) {
|
||||
|
||||
// escape vs noescape
|
||||
|
||||
#cgo noescape handleGoStringPointerNoescape
|
||||
#cgo nocallback handleGoStringPointerNoescape
|
||||
// TODO(#56378): enable in Go 1.23:
|
||||
// #cgo noescape handleGoStringPointerNoescape
|
||||
void handleGoStringPointerNoescape(void *s) {}
|
||||
|
||||
void handleGoStringPointerEscape(void *s) {}
|
||||
@@ -959,7 +959,6 @@ import "C"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"internal/asan"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -1774,9 +1773,6 @@ func issue8331a() C.issue8331 {
|
||||
// issue 10303
|
||||
|
||||
func test10303(t *testing.T, n int) {
|
||||
if asan.Enabled {
|
||||
t.Skip("variable z is heap-allocated due to extra allocations with -asan; see #70079")
|
||||
}
|
||||
if runtime.Compiler == "gccgo" {
|
||||
t.Skip("gccgo permits C pointers on the stack")
|
||||
}
|
||||
|
||||
@@ -41,16 +41,16 @@ func (v *Visitor) Visit(node ast.Node) ast.Visitor {
|
||||
var errorMessage strings.Builder
|
||||
for caseIndex, expectedPos := range expectedPositions {
|
||||
actualPosition := v.fset.PositionFor(ident.Pos(), true)
|
||||
errorOccurred := false
|
||||
errorOccured := false
|
||||
if expectedPos.Line != actualPosition.Line {
|
||||
fmt.Fprintf(&errorMessage, "wrong line number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Line, actualPosition.Line)
|
||||
errorOccurred = true
|
||||
errorOccured = true
|
||||
}
|
||||
if expectedPos.Column != actualPosition.Column {
|
||||
fmt.Fprintf(&errorMessage, "wrong column number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Column, actualPosition.Column)
|
||||
errorOccurred = true
|
||||
errorOccured = true
|
||||
}
|
||||
if errorOccurred {
|
||||
if errorOccured {
|
||||
continue
|
||||
}
|
||||
gotMatch = true
|
||||
@@ -58,7 +58,7 @@ func (v *Visitor) Visit(node ast.Node) ast.Visitor {
|
||||
}
|
||||
|
||||
if !gotMatch {
|
||||
v.t.Error(errorMessage.String())
|
||||
v.t.Errorf(errorMessage.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,23 +60,19 @@ func check(t *testing.T, file string) {
|
||||
if len(errors) == 0 {
|
||||
t.Fatalf("cannot find ERROR HERE")
|
||||
}
|
||||
expect(t, errors, file)
|
||||
expect(t, file, errors)
|
||||
})
|
||||
}
|
||||
|
||||
func expect(t *testing.T, errors []*regexp.Regexp, files ...string) {
|
||||
func expect(t *testing.T, file string, errors []*regexp.Regexp) {
|
||||
dir, err := os.MkdirTemp("", filepath.Base(t.Name()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
dst := filepath.Join(dir, strings.TrimSuffix(files[0], ".go"))
|
||||
args := []string{"build", "-gcflags=-L -e", "-o=" + dst} // TODO(gri) no need for -gcflags=-L if go tool is adjusted
|
||||
for _, file := range files {
|
||||
args = append(args, path(file))
|
||||
}
|
||||
cmd := exec.Command("go", args...)
|
||||
dst := filepath.Join(dir, strings.TrimSuffix(file, ".go"))
|
||||
cmd := exec.Command("go", "build", "-gcflags=-L -e", "-o="+dst, path(file)) // TODO(gri) no need for -gcflags=-L if go tool is adjusted
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Errorf("expected cgo to fail but it succeeded")
|
||||
@@ -132,7 +128,6 @@ func TestReportsTypeErrors(t *testing.T) {
|
||||
"issue50710.go",
|
||||
"issue67517.go",
|
||||
"issue67707.go",
|
||||
"issue69176.go",
|
||||
} {
|
||||
check(t, file)
|
||||
}
|
||||
@@ -185,13 +180,3 @@ func TestNotMatchedCFunction(t *testing.T) {
|
||||
file := "notmatchedcfunction.go"
|
||||
check(t, file)
|
||||
}
|
||||
|
||||
func TestIncompatibleDeclarations(t *testing.T) {
|
||||
testenv.MustHaveCGO(t)
|
||||
testenv.MustHaveGoRun(t)
|
||||
t.Parallel()
|
||||
expect(t, []*regexp.Regexp{
|
||||
regexp.MustCompile("inconsistent definitions for C[.]f"),
|
||||
regexp.MustCompile("inconsistent definitions for C[.]g"),
|
||||
}, "issue67699a.go", "issue67699b.go")
|
||||
}
|
||||
|
||||
@@ -472,23 +472,6 @@ var ptrTests = []ptrTest{
|
||||
body: `s := struct { a [4]byte; p *int }{p: new(int)}; C.f43(unsafe.Pointer(unsafe.SliceData(s.a[:])))`,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
// Passing the address of an element of a pointer-to-array.
|
||||
name: "arraypointer",
|
||||
c: `void f44(void* p) {}`,
|
||||
imports: []string{"unsafe"},
|
||||
body: `a := new([10]byte); C.f44(unsafe.Pointer(&a[0]))`,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
// Passing the address of an element of a pointer-to-array
|
||||
// that contains a Go pointer.
|
||||
name: "arraypointer2",
|
||||
c: `void f45(void** p) {}`,
|
||||
imports: []string{"unsafe"},
|
||||
body: `i := 0; a := &[2]unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f45(&a[0])`,
|
||||
fail: true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestPointerChecks(t *testing.T) {
|
||||
@@ -624,7 +607,7 @@ func buildPtrTests(t *testing.T, gopath string, cgocheck2 bool) (exe string) {
|
||||
goexperiment = append(goexperiment, "cgocheck2")
|
||||
changed = true
|
||||
} else if !cgocheck2 && i >= 0 {
|
||||
goexperiment = slices.Delete(goexperiment, i, i+1)
|
||||
goexperiment = append(goexperiment[:i], goexperiment[i+1:]...)
|
||||
changed = true
|
||||
}
|
||||
if changed {
|
||||
|
||||
@@ -1,12 +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 p
|
||||
|
||||
import "C"
|
||||
|
||||
type T = T // ERROR HERE
|
||||
|
||||
//export F
|
||||
func F(p *T) {}
|
||||
@@ -5,7 +5,8 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
// ERROR MESSAGE: #cgo noescape noMatchedCFunction: no matched C function
|
||||
// TODO(#56378): change back to "#cgo noescape noMatchedCFunction: no matched C function" in Go 1.23
|
||||
// ERROR MESSAGE: #cgo noescape disabled until Go 1.23
|
||||
#cgo noescape noMatchedCFunction
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -7,19 +7,42 @@
|
||||
package sanitizers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"internal/platform"
|
||||
"internal/testenv"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestASAN(t *testing.T) {
|
||||
config := mustHaveASAN(t)
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustHaveCGO(t)
|
||||
goos, err := goEnv("GOOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
goarch, err := goEnv("GOARCH")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The asan tests require support for the -asan option.
|
||||
if !platform.ASanSupported(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
|
||||
}
|
||||
// The current implementation is only compatible with the ASan library from version
|
||||
// v7 to v9 (See the description in src/runtime/asan/asan.go). Therefore, using the
|
||||
// -asan option must use a compatible version of ASan library, which requires that
|
||||
// the gcc version is not less than 7 and the clang version is not less than 9,
|
||||
// otherwise a segmentation fault will occur.
|
||||
if !compilerRequiredAsanVersion(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s: too old version of compiler", goos, goarch)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
requireOvercommit(t)
|
||||
config := configure("address")
|
||||
config.skipIfCSanitizerBroken(t)
|
||||
|
||||
mustRun(t, config.goCmd("build", "std"))
|
||||
|
||||
cases := []struct {
|
||||
@@ -83,10 +106,29 @@ func TestASAN(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestASANLinkerX(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustHaveCGO(t)
|
||||
// Test ASAN with linker's -X flag (see issue 56175).
|
||||
config := mustHaveASAN(t)
|
||||
goos, err := goEnv("GOOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
goarch, err := goEnv("GOARCH")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The asan tests require support for the -asan option.
|
||||
if !platform.ASanSupported(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
|
||||
}
|
||||
if !compilerRequiredAsanVersion(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s: too old version of compiler", goos, goarch)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
requireOvercommit(t)
|
||||
config := configure("address")
|
||||
config.skipIfCSanitizerBroken(t)
|
||||
|
||||
dir := newTempDir(t)
|
||||
defer dir.RemoveAll(t)
|
||||
@@ -105,66 +147,3 @@ func TestASANLinkerX(t *testing.T) {
|
||||
// run the binary
|
||||
mustRun(t, hangProneCmd(outPath))
|
||||
}
|
||||
|
||||
// Issue 66966.
|
||||
func TestASANFuzz(t *testing.T) {
|
||||
config := mustHaveASAN(t)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
dir := newTempDir(t)
|
||||
defer dir.RemoveAll(t)
|
||||
|
||||
exe := dir.Join("asan_fuzz_test.exe")
|
||||
cmd := config.goCmd("test", "-c", "-o", exe, srcPath("asan_fuzz_test.go"))
|
||||
t.Logf("%v", cmd)
|
||||
out, err := cmd.CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd = exec.Command(exe, "-test.fuzz=Fuzz", "-test.fuzzcachedir="+dir.Base())
|
||||
cmd.Dir = dir.Base()
|
||||
t.Logf("%v", cmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
t.Logf("%s", out)
|
||||
if err == nil {
|
||||
t.Error("expected fuzzing failure")
|
||||
}
|
||||
if bytes.Contains(out, []byte("AddressSanitizer")) {
|
||||
t.Error(`output contains "AddressSanitizer", but should not`)
|
||||
}
|
||||
}
|
||||
|
||||
func mustHaveASAN(t *testing.T) *config {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustHaveCGO(t)
|
||||
goos, err := goEnv("GOOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
goarch, err := goEnv("GOARCH")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !platform.ASanSupported(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
|
||||
}
|
||||
|
||||
// The current implementation is only compatible with the ASan library from version
|
||||
// v7 to v9 (See the description in src/runtime/asan/asan.go). Therefore, using the
|
||||
// -asan option must use a compatible version of ASan library, which requires that
|
||||
// the gcc version is not less than 7 and the clang version is not less than 9,
|
||||
// otherwise a segmentation fault will occur.
|
||||
if !compilerRequiredAsanVersion(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s: too old version of compiler", goos, goarch)
|
||||
}
|
||||
|
||||
requireOvercommit(t)
|
||||
|
||||
config := configure("address")
|
||||
config.skipIfCSanitizerBroken(t)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -563,7 +563,12 @@ func (d *tempDir) Join(name string) string {
|
||||
}
|
||||
|
||||
func newTempDir(t *testing.T) *tempDir {
|
||||
return &tempDir{base: t.TempDir()}
|
||||
t.Helper()
|
||||
dir, err := os.MkdirTemp("", filepath.Dir(t.Name()))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
return &tempDir{base: dir}
|
||||
}
|
||||
|
||||
// hangProneCmd returns an exec.Cmd for a command that is likely to hang.
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"internal/platform"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -91,23 +90,7 @@ func TestShared(t *testing.T) {
|
||||
cmd.Args = append(cmd.Args, "-o", dstBin, cSrc, lib)
|
||||
mustRun(t, cmd)
|
||||
|
||||
cmdArgs := []string{dstBin}
|
||||
if tc.sanitizer == "thread" && GOOS == "linux" {
|
||||
// Disable ASLR for TSAN. See https://go.dev/issue/59418.
|
||||
out, err := exec.Command("uname", "-m").Output()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to run `uname -m`: %v", err)
|
||||
}
|
||||
arch := strings.TrimSpace(string(out))
|
||||
if _, err := exec.Command("setarch", arch, "-R", "true").Output(); err != nil {
|
||||
// Some systems don't have permission to run `setarch`.
|
||||
// See https://go.dev/issue/70463.
|
||||
t.Logf("failed to run `setarch %s -R true`: %v", arch, err)
|
||||
} else {
|
||||
cmdArgs = []string{"setarch", arch, "-R", dstBin}
|
||||
}
|
||||
}
|
||||
cmd = hangProneCmd(cmdArgs[0], cmdArgs[1:]...)
|
||||
cmd = hangProneCmd(dstBin)
|
||||
replaceEnv(cmd, "LD_LIBRARY_PATH", ".")
|
||||
mustRun(t, cmd)
|
||||
})
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Reverse(s string) string {
|
||||
runes := []rune(s)
|
||||
slices.Reverse(runes)
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// This fuzz test should quickly fail, because Reverse doesn't
|
||||
// work for strings that are not valid UTF-8.
|
||||
// What we are testing for is whether we see a failure from ASAN;
|
||||
// we should see a fuzzing failure, not an ASAN failure.
|
||||
|
||||
func FuzzReverse(f *testing.F) {
|
||||
f.Add("Go")
|
||||
f.Add("Gopher")
|
||||
f.Add("Hello, 世界")
|
||||
f.Fuzz(func(t *testing.T, s string) {
|
||||
r1 := Reverse(s)
|
||||
r2 := Reverse(r1)
|
||||
if s != r2 {
|
||||
t.Errorf("got %q want %q", r2, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -26,22 +26,12 @@ void msanGoTraceback(void* parg) {
|
||||
arg->buf[0] = 0;
|
||||
}
|
||||
|
||||
// Don't warn if the compiler doesn't support the maybe_undef attribute.
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
|
||||
// msanGoWait will be called with all registers undefined as far as
|
||||
// msan is concerned. It just waits for a signal.
|
||||
// Because the registers are msan-undefined, the signal handler will
|
||||
// be invoked with all registers msan-undefined.
|
||||
// The maybe_undef attribute tells clang to not complain about
|
||||
// passing uninitialized values.
|
||||
__attribute__((noinline))
|
||||
void msanGoWait(unsigned long a1 __attribute__((maybe_undef)),
|
||||
unsigned long a2 __attribute__((maybe_undef)),
|
||||
unsigned long a3 __attribute__((maybe_undef)),
|
||||
unsigned long a4 __attribute__((maybe_undef)),
|
||||
unsigned long a5 __attribute__((maybe_undef)),
|
||||
unsigned long a6 __attribute__((maybe_undef))) {
|
||||
void msanGoWait(unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6) {
|
||||
sigset_t mask;
|
||||
|
||||
sigemptyset(&mask);
|
||||
|
||||
@@ -8,7 +8,6 @@ package sanitizers_test
|
||||
|
||||
import (
|
||||
"internal/testenv"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -25,7 +24,7 @@ func TestTSAN(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The tsan tests require support for the -tsan option.
|
||||
// The msan tests require support for the -msan option.
|
||||
if !compilerRequiredTsanVersion(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s; compiler version for -tsan option is too old.", goos, goarch)
|
||||
}
|
||||
@@ -69,23 +68,7 @@ func TestTSAN(t *testing.T) {
|
||||
outPath := dir.Join(name)
|
||||
mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
|
||||
|
||||
cmdArgs := []string{outPath}
|
||||
if goos == "linux" {
|
||||
// Disable ASLR for TSAN. See https://go.dev/issue/59418.
|
||||
out, err := exec.Command("uname", "-m").Output()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to run `uname -m`: %v", err)
|
||||
}
|
||||
arch := strings.TrimSpace(string(out))
|
||||
if _, err := exec.Command("setarch", arch, "-R", "true").Output(); err != nil {
|
||||
// Some systems don't have permission to run `setarch`.
|
||||
// See https://go.dev/issue/70463.
|
||||
t.Logf("failed to run `setarch %s -R true`: %v", arch, err)
|
||||
} else {
|
||||
cmdArgs = []string{"setarch", arch, "-R", outPath}
|
||||
}
|
||||
}
|
||||
cmd := hangProneCmd(cmdArgs[0], cmdArgs[1:]...)
|
||||
cmd := hangProneCmd(outPath)
|
||||
if tc.needsRuntime {
|
||||
config.skipIfRuntimeIncompatible(t)
|
||||
}
|
||||
|
||||
@@ -18,17 +18,15 @@ import (
|
||||
"go/token"
|
||||
"internal/buildcfg"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/internal/edit"
|
||||
"cmd/internal/hash"
|
||||
"cmd/internal/notsha256"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/telemetry/counter"
|
||||
)
|
||||
@@ -83,7 +81,7 @@ func (f *File) offset(p token.Pos) int {
|
||||
}
|
||||
|
||||
func nameKeys(m map[string]*Name) []string {
|
||||
ks := make([]string, 0, len(m))
|
||||
var ks []string
|
||||
for k := range m {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
@@ -161,13 +159,6 @@ type Type struct {
|
||||
BadPointer bool // this pointer type should be represented as a uintptr (deprecated)
|
||||
}
|
||||
|
||||
func (t *Type) fuzzyMatch(t2 *Type) bool {
|
||||
if t == nil || t2 == nil {
|
||||
return false
|
||||
}
|
||||
return t.Size == t2.Size && t.Align == t2.Align
|
||||
}
|
||||
|
||||
// A FuncType collects information about a function type in both the C and Go worlds.
|
||||
type FuncType struct {
|
||||
Params []*Type
|
||||
@@ -175,24 +166,6 @@ type FuncType struct {
|
||||
Go *ast.FuncType
|
||||
}
|
||||
|
||||
func (t *FuncType) fuzzyMatch(t2 *FuncType) bool {
|
||||
if t == nil || t2 == nil {
|
||||
return false
|
||||
}
|
||||
if !t.Result.fuzzyMatch(t2.Result) {
|
||||
return false
|
||||
}
|
||||
if len(t.Params) != len(t2.Params) {
|
||||
return false
|
||||
}
|
||||
for i := range t.Params {
|
||||
if !t.Params[i].fuzzyMatch(t2.Params[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
|
||||
flag.PrintDefaults()
|
||||
@@ -389,11 +362,9 @@ func main() {
|
||||
// we use to coordinate between gcc and ourselves.
|
||||
// We already put _cgo_ at the beginning, so the main
|
||||
// concern is other cgo wrappers for the same functions.
|
||||
// Use the beginning of the 16 bytes hash of the input to disambiguate.
|
||||
h := hash.New16()
|
||||
// Use the beginning of the notsha256 of the input to disambiguate.
|
||||
h := notsha256.New()
|
||||
io.WriteString(h, *importPath)
|
||||
var once sync.Once
|
||||
var wg sync.WaitGroup
|
||||
fs := make([]*File, len(goFiles))
|
||||
for i, input := range goFiles {
|
||||
if *srcDir != "" {
|
||||
@@ -415,34 +386,23 @@ func main() {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// Apply trimpath to the file path. The path won't be read from after this point.
|
||||
input, _ = objabi.ApplyRewrites(input, *trimpath)
|
||||
if strings.ContainsAny(input, "\r\n") {
|
||||
// ParseGo, (*Package).writeOutput, and printer.Fprint in SourcePos mode
|
||||
// all emit line directives, which don't permit newlines in the file path.
|
||||
// Bail early if we see anything newline-like in the trimmed path.
|
||||
fatalf("input path contains newline character: %q", input)
|
||||
}
|
||||
goFiles[i] = input
|
||||
// Apply trimpath to the file path. The path won't be read from after this point.
|
||||
input, _ = objabi.ApplyRewrites(input, *trimpath)
|
||||
if strings.ContainsAny(input, "\r\n") {
|
||||
// ParseGo, (*Package).writeOutput, and printer.Fprint in SourcePos mode
|
||||
// all emit line directives, which don't permit newlines in the file path.
|
||||
// Bail early if we see anything newline-like in the trimmed path.
|
||||
fatalf("input path contains newline character: %q", input)
|
||||
}
|
||||
goFiles[i] = input
|
||||
|
||||
f := new(File)
|
||||
f.Edit = edit.NewBuffer(b)
|
||||
f.ParseGo(input, b)
|
||||
f.ProcessCgoDirectives()
|
||||
gccIsClang := f.loadDefines(p.GccOptions)
|
||||
once.Do(func() {
|
||||
p.GccIsClang = gccIsClang
|
||||
})
|
||||
|
||||
fs[i] = f
|
||||
}()
|
||||
f := new(File)
|
||||
f.Edit = edit.NewBuffer(b)
|
||||
f.ParseGo(input, b)
|
||||
f.ProcessCgoDirectives()
|
||||
fs[i] = f
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
|
||||
|
||||
if *objDir == "" {
|
||||
@@ -555,52 +515,30 @@ func (p *Package) Record(f *File) {
|
||||
if p.Name == nil {
|
||||
p.Name = f.Name
|
||||
} else {
|
||||
// Merge the new file's names in with the existing names.
|
||||
for k, v := range f.Name {
|
||||
if p.Name[k] == nil {
|
||||
// Never seen before, just save it.
|
||||
p.Name[k] = v
|
||||
} else if p.incompleteTypedef(p.Name[k].Type) && p.Name[k].FuncType == nil {
|
||||
// Old one is incomplete, just use new one.
|
||||
} else if p.incompleteTypedef(p.Name[k].Type) {
|
||||
p.Name[k] = v
|
||||
} else if p.incompleteTypedef(v.Type) && v.FuncType == nil {
|
||||
// New one is incomplete, just use old one.
|
||||
} else if p.incompleteTypedef(v.Type) {
|
||||
// Nothing to do.
|
||||
} else if _, ok := nameToC[k]; ok {
|
||||
// Names we predefine may appear inconsistent
|
||||
// if some files typedef them and some don't.
|
||||
// Issue 26743.
|
||||
} else if !reflect.DeepEqual(p.Name[k], v) {
|
||||
// We don't require strict func type equality, because some functions
|
||||
// can have things like typedef'd arguments that are equivalent to
|
||||
// the standard arguments. e.g.
|
||||
// int usleep(unsigned);
|
||||
// int usleep(useconds_t);
|
||||
// So we just check size/alignment of arguments. At least that
|
||||
// avoids problems like those in #67670 and #67699.
|
||||
ok := false
|
||||
ft1 := p.Name[k].FuncType
|
||||
ft2 := v.FuncType
|
||||
if ft1.fuzzyMatch(ft2) {
|
||||
// Retry DeepEqual with the FuncType field cleared.
|
||||
x1 := *p.Name[k]
|
||||
x2 := *v
|
||||
x1.FuncType = nil
|
||||
x2.FuncType = nil
|
||||
if reflect.DeepEqual(&x1, &x2) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
|
||||
}
|
||||
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// merge nocallback & noescape
|
||||
maps.Copy(p.noCallbacks, f.NoCallbacks)
|
||||
maps.Copy(p.noEscapes, f.NoEscapes)
|
||||
for k, v := range f.NoCallbacks {
|
||||
p.noCallbacks[k] = v
|
||||
}
|
||||
for k, v := range f.NoEscapes {
|
||||
p.noEscapes[k] = v
|
||||
}
|
||||
|
||||
if f.ExpFunc != nil {
|
||||
p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
|
||||
|
||||
@@ -104,9 +104,6 @@ func (p *Package) writeDefs() {
|
||||
fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n")
|
||||
fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n")
|
||||
fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n")
|
||||
fmt.Fprintf(fgo2, "//go:linkname _Cgo_keepalive runtime.cgoKeepAlive\n")
|
||||
fmt.Fprintf(fgo2, "//go:noescape\n")
|
||||
fmt.Fprintf(fgo2, "func _Cgo_keepalive(interface{})\n")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "//go:linkname _Cgo_no_callback runtime.cgoNoCallback\n")
|
||||
fmt.Fprintf(fgo2, "func _Cgo_no_callback(bool)\n")
|
||||
@@ -381,7 +378,9 @@ func dynimport(obj string) {
|
||||
defer f.Close()
|
||||
sym, _ := f.ImportedSymbols()
|
||||
for _, s := range sym {
|
||||
s = strings.TrimPrefix(s, "_")
|
||||
if len(s) > 0 && s[0] == '_' {
|
||||
s = s[1:]
|
||||
}
|
||||
checkImportSymName(s)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
|
||||
}
|
||||
@@ -447,7 +446,7 @@ func checkImportSymName(s string) {
|
||||
}
|
||||
}
|
||||
if strings.Contains(s, "//") || strings.Contains(s, "/*") {
|
||||
fatalf("dynamic symbol %q contains Go comment", s)
|
||||
fatalf("dynamic symbol %q contains Go comment")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,20 +641,17 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
|
||||
fmt.Fprintf(fgo2, "\t_Cgo_no_callback(false)\n")
|
||||
}
|
||||
|
||||
// Use _Cgo_keepalive instead of _Cgo_use when noescape & nocallback exist,
|
||||
// skip _Cgo_use when noescape exist,
|
||||
// so that the compiler won't force to escape them to heap.
|
||||
// Instead, make the compiler keep them alive by using _Cgo_keepalive.
|
||||
touchFunc := "_Cgo_use"
|
||||
if p.noEscapes[n.C] && p.noCallbacks[n.C] {
|
||||
touchFunc = "_Cgo_keepalive"
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
|
||||
if d.Type.Params != nil {
|
||||
for _, name := range paramnames {
|
||||
fmt.Fprintf(fgo2, "\t\t%s(%s)\n", touchFunc, name)
|
||||
if !p.noEscapes[n.C] {
|
||||
fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
|
||||
if d.Type.Params != nil {
|
||||
for i := range d.Type.Params.List {
|
||||
fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\t}\n")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\t}\n")
|
||||
fmt.Fprintf(fgo2, "\treturn\n")
|
||||
fmt.Fprintf(fgo2, "}\n")
|
||||
}
|
||||
@@ -1418,18 +1414,9 @@ var goTypes = map[string]*Type{
|
||||
|
||||
// Map an ast type to a Type.
|
||||
func (p *Package) cgoType(e ast.Expr) *Type {
|
||||
return p.doCgoType(e, make(map[ast.Expr]bool))
|
||||
}
|
||||
|
||||
// Map an ast type to a Type, avoiding cycles.
|
||||
func (p *Package) doCgoType(e ast.Expr, m map[ast.Expr]bool) *Type {
|
||||
if m[e] {
|
||||
fatalf("%s: invalid recursive type", fset.Position(e.Pos()))
|
||||
}
|
||||
m[e] = true
|
||||
switch t := e.(type) {
|
||||
case *ast.StarExpr:
|
||||
x := p.doCgoType(t.X, m)
|
||||
x := p.cgoType(t.X)
|
||||
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
|
||||
case *ast.ArrayType:
|
||||
if t.Len == nil {
|
||||
@@ -1474,12 +1461,7 @@ func (p *Package) doCgoType(e ast.Expr, m map[ast.Expr]bool) *Type {
|
||||
continue
|
||||
}
|
||||
if ts.Name.Name == t.Name {
|
||||
// Give a better error than the one
|
||||
// above if we detect a recursive type.
|
||||
if m[ts.Type] {
|
||||
fatalf("%s: invalid recursive type: %s refers to itself", fset.Position(e.Pos()), t.Name)
|
||||
}
|
||||
return p.doCgoType(ts.Type, m)
|
||||
return p.cgoType(ts.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,13 @@ import (
|
||||
"go/token"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// run runs the command argv, feeding in stdin on standard input.
|
||||
// It returns the output to standard output and standard error.
|
||||
// ok indicates whether the command exited successfully.
|
||||
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
if i := slices.Index(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
|
||||
if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
|
||||
// Some compilers have trouble with standard input.
|
||||
// Others have trouble with -xc.
|
||||
// Avoid both problems by writing a file with a .c extension.
|
||||
@@ -70,6 +69,15 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func find(argv []string, target string) int {
|
||||
for i, arg := range argv {
|
||||
if arg == target {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func lineno(pos token.Pos) string {
|
||||
return fset.Position(pos).String()
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -309,33 +309,13 @@ The types of parameters and return values to the Go function are translated to
|
||||
Wasm according to the following table:
|
||||
|
||||
Go types Wasm types
|
||||
bool i32
|
||||
int32, uint32 i32
|
||||
int64, uint64 i64
|
||||
float32 f32
|
||||
float64 f64
|
||||
unsafe.Pointer i32
|
||||
pointer i32 (more restrictions below)
|
||||
string (i32, i32) (only permitted as a parameters, not a result)
|
||||
|
||||
For a pointer type, its element type must be a bool, int8, uint8, int16, uint16,
|
||||
int32, uint32, int64, uint64, float32, float64, an array whose element type is
|
||||
a permitted pointer element type, or a struct, which, if non-empty, embeds
|
||||
structs.HostLayout, and contains only fields whose types are permitted pointer
|
||||
element types.
|
||||
|
||||
Any other parameter types are disallowed by the compiler.
|
||||
|
||||
//go:wasmexport exportname
|
||||
|
||||
The //go:wasmexport directive is wasm-only and must be followed by a
|
||||
function definition.
|
||||
It specifies that the function is exported to the wasm host as ``exportname``.
|
||||
|
||||
//go:wasmexport f
|
||||
func g()
|
||||
|
||||
The types of parameters and return values to the Go function are permitted and
|
||||
translated to Wasm in the same way as //go:wasmimport functions.
|
||||
*/
|
||||
package main
|
||||
|
||||
@@ -819,6 +819,13 @@ func (t *node32) leftToRoot() *node32 {
|
||||
return left
|
||||
}
|
||||
|
||||
func max(a, b int8) int8 {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (t *node32) copy() *node32 {
|
||||
u := *t
|
||||
return &u
|
||||
|
||||
@@ -256,39 +256,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
ssa.OpAMD64POR, ssa.OpAMD64PXOR,
|
||||
ssa.OpAMD64BTSL, ssa.OpAMD64BTSQ,
|
||||
ssa.OpAMD64BTCL, ssa.OpAMD64BTCQ,
|
||||
ssa.OpAMD64BTRL, ssa.OpAMD64BTRQ,
|
||||
ssa.OpAMD64PCMPEQB, ssa.OpAMD64PSIGNB,
|
||||
ssa.OpAMD64PUNPCKLBW:
|
||||
ssa.OpAMD64BTRL, ssa.OpAMD64BTRQ:
|
||||
opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())
|
||||
|
||||
case ssa.OpAMD64PSHUFLW:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
imm := v.AuxInt
|
||||
if imm < 0 || imm > 255 {
|
||||
v.Fatalf("Invalid source selection immediate")
|
||||
}
|
||||
p.From.Offset = imm
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.AddRestSourceReg(v.Args[0].Reg())
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
case ssa.OpAMD64PSHUFBbroadcast:
|
||||
// PSHUFB with a control mask of zero copies byte 0 to all
|
||||
// bytes in the register.
|
||||
//
|
||||
// X15 is always zero with ABIInternal.
|
||||
if s.ABI != obj.ABIInternal {
|
||||
// zero X15 manually
|
||||
opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)
|
||||
}
|
||||
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
p.From.Reg = x86.REG_X15
|
||||
|
||||
case ssa.OpAMD64SHRDQ, ssa.OpAMD64SHLDQ:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
lo, hi, bits := v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg()
|
||||
@@ -945,7 +915,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
ssagen.AddAux2(&p.To, v, sc.Off64())
|
||||
case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
|
||||
ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
|
||||
ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS, ssa.OpAMD64VPBROADCASTB, ssa.OpAMD64PMOVMSKB:
|
||||
ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
|
||||
opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
|
||||
case ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSL2SS:
|
||||
r := v.Reg()
|
||||
@@ -1316,8 +1286,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
p = s.Prog(x86.ASETEQ)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg0()
|
||||
case ssa.OpAMD64ANDBlock, ssa.OpAMD64ANDLlock, ssa.OpAMD64ANDQlock, ssa.OpAMD64ORBlock, ssa.OpAMD64ORLlock, ssa.OpAMD64ORQlock:
|
||||
// Atomic memory operations that don't need to return the old value.
|
||||
case ssa.OpAMD64ANDBlock, ssa.OpAMD64ANDLlock, ssa.OpAMD64ORBlock, ssa.OpAMD64ORLlock:
|
||||
s.Prog(x86.ALOCK)
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
@@ -1325,60 +1294,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Reg = v.Args[0].Reg()
|
||||
ssagen.AddAux(&p.To, v)
|
||||
case ssa.OpAMD64LoweredAtomicAnd64, ssa.OpAMD64LoweredAtomicOr64, ssa.OpAMD64LoweredAtomicAnd32, ssa.OpAMD64LoweredAtomicOr32:
|
||||
// Atomic memory operations that need to return the old value.
|
||||
// We need to do these with compare-and-exchange to get access to the old value.
|
||||
// loop:
|
||||
// MOVQ mask, tmp
|
||||
// MOVQ (addr), AX
|
||||
// ANDQ AX, tmp
|
||||
// LOCK CMPXCHGQ tmp, (addr) : note that AX is implicit old value to compare against
|
||||
// JNE loop
|
||||
// : result in AX
|
||||
mov := x86.AMOVQ
|
||||
op := x86.AANDQ
|
||||
cmpxchg := x86.ACMPXCHGQ
|
||||
switch v.Op {
|
||||
case ssa.OpAMD64LoweredAtomicOr64:
|
||||
op = x86.AORQ
|
||||
case ssa.OpAMD64LoweredAtomicAnd32:
|
||||
mov = x86.AMOVL
|
||||
op = x86.AANDL
|
||||
cmpxchg = x86.ACMPXCHGL
|
||||
case ssa.OpAMD64LoweredAtomicOr32:
|
||||
mov = x86.AMOVL
|
||||
op = x86.AORL
|
||||
cmpxchg = x86.ACMPXCHGL
|
||||
}
|
||||
addr := v.Args[0].Reg()
|
||||
mask := v.Args[1].Reg()
|
||||
tmp := v.RegTmp()
|
||||
p1 := s.Prog(mov)
|
||||
p1.From.Type = obj.TYPE_REG
|
||||
p1.From.Reg = mask
|
||||
p1.To.Type = obj.TYPE_REG
|
||||
p1.To.Reg = tmp
|
||||
p2 := s.Prog(mov)
|
||||
p2.From.Type = obj.TYPE_MEM
|
||||
p2.From.Reg = addr
|
||||
ssagen.AddAux(&p2.From, v)
|
||||
p2.To.Type = obj.TYPE_REG
|
||||
p2.To.Reg = x86.REG_AX
|
||||
p3 := s.Prog(op)
|
||||
p3.From.Type = obj.TYPE_REG
|
||||
p3.From.Reg = x86.REG_AX
|
||||
p3.To.Type = obj.TYPE_REG
|
||||
p3.To.Reg = tmp
|
||||
s.Prog(x86.ALOCK)
|
||||
p5 := s.Prog(cmpxchg)
|
||||
p5.From.Type = obj.TYPE_REG
|
||||
p5.From.Reg = tmp
|
||||
p5.To.Type = obj.TYPE_MEM
|
||||
p5.To.Reg = addr
|
||||
ssagen.AddAux(&p5.To, v)
|
||||
p6 := s.Prog(x86.AJNE)
|
||||
p6.To.Type = obj.TYPE_BRANCH
|
||||
p6.To.SetTarget(p1)
|
||||
case ssa.OpAMD64PrefetchT0, ssa.OpAMD64PrefetchNTA:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
|
||||
@@ -78,7 +78,7 @@ func TestGoAMD64v1(t *testing.T) {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("GODEBUG=%s", strings.Join(features, ",")))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't execute test: %s\n%s", err, out)
|
||||
t.Fatalf("couldn't execute test: %s", err)
|
||||
}
|
||||
// Expect to see output of the form "PASS\n", unless the test binary
|
||||
// was compiled for coverage (in which case there will be an extra line).
|
||||
|
||||
@@ -78,48 +78,6 @@ func storeByType(t *types.Type) obj.As {
|
||||
panic("bad store type")
|
||||
}
|
||||
|
||||
// loadByType2 returns an opcode that can load consecutive memory locations into 2 registers with type t.
|
||||
// returns obj.AXXX if no such opcode exists.
|
||||
func loadByType2(t *types.Type) obj.As {
|
||||
if t.IsFloat() {
|
||||
switch t.Size() {
|
||||
case 4:
|
||||
return arm64.AFLDPS
|
||||
case 8:
|
||||
return arm64.AFLDPD
|
||||
}
|
||||
} else {
|
||||
switch t.Size() {
|
||||
case 4:
|
||||
return arm64.ALDPW
|
||||
case 8:
|
||||
return arm64.ALDP
|
||||
}
|
||||
}
|
||||
return obj.AXXX
|
||||
}
|
||||
|
||||
// storeByType2 returns an opcode that can store registers with type t into 2 consecutive memory locations.
|
||||
// returns obj.AXXX if no such opcode exists.
|
||||
func storeByType2(t *types.Type) obj.As {
|
||||
if t.IsFloat() {
|
||||
switch t.Size() {
|
||||
case 4:
|
||||
return arm64.AFSTPS
|
||||
case 8:
|
||||
return arm64.AFSTPD
|
||||
}
|
||||
} else {
|
||||
switch t.Size() {
|
||||
case 4:
|
||||
return arm64.ASTPW
|
||||
case 8:
|
||||
return arm64.ASTP
|
||||
}
|
||||
}
|
||||
return obj.AXXX
|
||||
}
|
||||
|
||||
// makeshift encodes a register shifted by a constant, used as an Offset in Prog.
|
||||
func makeshift(v *ssa.Value, reg int16, typ int64, s int64) int64 {
|
||||
if s < 0 || s >= 64 {
|
||||
@@ -209,38 +167,17 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
ssagen.AddrAuto(&p.To, v)
|
||||
case ssa.OpArgIntReg, ssa.OpArgFloatReg:
|
||||
ssagen.CheckArgReg(v)
|
||||
// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
|
||||
// The loop only runs once.
|
||||
args := v.Block.Func.RegArgs
|
||||
if len(args) == 0 {
|
||||
break
|
||||
}
|
||||
v.Block.Func.RegArgs = nil // prevent from running again
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
a := args[i]
|
||||
// Offset by size of the saved LR slot.
|
||||
for _, a := range v.Block.Func.RegArgs {
|
||||
// Pass the spill/unspill information along to the assembler, offset by size of
|
||||
// the saved LR slot.
|
||||
addr := ssagen.SpillSlotAddr(a, arm64.REGSP, base.Ctxt.Arch.FixedFrameSize)
|
||||
// Look for double-register operations if we can.
|
||||
if i < len(args)-1 {
|
||||
b := args[i+1]
|
||||
if a.Type.Size() == b.Type.Size() &&
|
||||
a.Type.IsFloat() == b.Type.IsFloat() &&
|
||||
b.Offset == a.Offset+a.Type.Size() {
|
||||
ld := loadByType2(a.Type)
|
||||
st := storeByType2(a.Type)
|
||||
if ld != obj.AXXX && st != obj.AXXX {
|
||||
s.FuncInfo().AddSpill(obj.RegSpill{Reg: a.Reg, Reg2: b.Reg, Addr: addr, Unspill: ld, Spill: st})
|
||||
i++ // b is done also, skip it.
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pass the spill/unspill information along to the assembler.
|
||||
s.FuncInfo().AddSpill(obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
|
||||
s.FuncInfo().AddSpill(
|
||||
obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
|
||||
}
|
||||
|
||||
v.Block.Func.RegArgs = nil
|
||||
ssagen.CheckArgReg(v)
|
||||
case ssa.OpARM64ADD,
|
||||
ssa.OpARM64SUB,
|
||||
ssa.OpARM64AND,
|
||||
@@ -641,22 +578,15 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64LoweredAtomicExchange64,
|
||||
ssa.OpARM64LoweredAtomicExchange32,
|
||||
ssa.OpARM64LoweredAtomicExchange8:
|
||||
ssa.OpARM64LoweredAtomicExchange32:
|
||||
// LDAXR (Rarg0), Rout
|
||||
// STLXR Rarg1, (Rarg0), Rtmp
|
||||
// CBNZ Rtmp, -2(PC)
|
||||
var ld, st obj.As
|
||||
switch v.Op {
|
||||
case ssa.OpARM64LoweredAtomicExchange8:
|
||||
ld = arm64.ALDAXRB
|
||||
st = arm64.ASTLXRB
|
||||
case ssa.OpARM64LoweredAtomicExchange32:
|
||||
ld := arm64.ALDAXR
|
||||
st := arm64.ASTLXR
|
||||
if v.Op == ssa.OpARM64LoweredAtomicExchange32 {
|
||||
ld = arm64.ALDAXRW
|
||||
st = arm64.ASTLXRW
|
||||
case ssa.OpARM64LoweredAtomicExchange64:
|
||||
ld = arm64.ALDAXR
|
||||
st = arm64.ASTLXR
|
||||
}
|
||||
r0 := v.Args[0].Reg()
|
||||
r1 := v.Args[1].Reg()
|
||||
@@ -678,16 +608,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
p2.To.Type = obj.TYPE_BRANCH
|
||||
p2.To.SetTarget(p)
|
||||
case ssa.OpARM64LoweredAtomicExchange64Variant,
|
||||
ssa.OpARM64LoweredAtomicExchange32Variant,
|
||||
ssa.OpARM64LoweredAtomicExchange8Variant:
|
||||
var swap obj.As
|
||||
switch v.Op {
|
||||
case ssa.OpARM64LoweredAtomicExchange8Variant:
|
||||
swap = arm64.ASWPALB
|
||||
case ssa.OpARM64LoweredAtomicExchange32Variant:
|
||||
ssa.OpARM64LoweredAtomicExchange32Variant:
|
||||
swap := arm64.ASWPALD
|
||||
if v.Op == ssa.OpARM64LoweredAtomicExchange32Variant {
|
||||
swap = arm64.ASWPALW
|
||||
case ssa.OpARM64LoweredAtomicExchange64Variant:
|
||||
swap = arm64.ASWPALD
|
||||
}
|
||||
r0 := v.Args[0].Reg()
|
||||
r1 := v.Args[1].Reg()
|
||||
|
||||
@@ -30,7 +30,6 @@ type DebugFlags struct {
|
||||
DwarfInl int `help:"print information about DWARF inlined function creation"`
|
||||
EscapeMutationsCalls int `help:"print extra escape analysis diagnostics about mutations and calls" concurrent:"ok"`
|
||||
Export int `help:"print export data"`
|
||||
FIPSHash string `help:"hash value for FIPS debugging" concurrent:"ok"`
|
||||
Fmahash string `help:"hash value for use in debugging platform-dependent multiply-add use" concurrent:"ok"`
|
||||
GCAdjust int `help:"log adjustments to GOGC" concurrent:"ok"`
|
||||
GCCheck int `help:"check heap/gc use by compiler" concurrent:"ok"`
|
||||
@@ -49,7 +48,6 @@ type DebugFlags struct {
|
||||
MergeLocalsTrace int `help:"trace debug output for locals merging"`
|
||||
MergeLocalsHTrace int `help:"hash-selected trace debug output for locals merging"`
|
||||
Nil int `help:"print information about nil checks"`
|
||||
NoDeadLocals int `help:"disable deadlocals pass" concurrent:"ok"`
|
||||
NoOpenDefer int `help:"disable open-coded defers" concurrent:"ok"`
|
||||
NoRefName int `help:"do not include referenced symbol names in object file" concurrent:"ok"`
|
||||
PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
|
||||
@@ -60,7 +58,6 @@ type DebugFlags struct {
|
||||
SoftFloat int `help:"force compiler to emit soft-float code" concurrent:"ok"`
|
||||
StaticCopy int `help:"print information about missed static copies" concurrent:"ok"`
|
||||
SyncFrames int `help:"how many writer stack frames to include at sync points in unified export data"`
|
||||
TailCall int `help:"print information about tail calls"`
|
||||
TypeAssert int `help:"print information about type assertion inlining"`
|
||||
WB int `help:"print information about write barriers"`
|
||||
ABIWrap int `help:"print information about ABI wrapper generation"`
|
||||
|
||||
@@ -206,7 +206,6 @@ func ParseFlags() {
|
||||
if Debug.Gossahash != "" {
|
||||
hashDebug = NewHashDebug("gossahash", Debug.Gossahash, nil)
|
||||
}
|
||||
obj.SetFIPSDebugHash(Debug.FIPSHash)
|
||||
|
||||
// Compute whether we're compiling the runtime from the package path. Test
|
||||
// code can also use the flag to set this explicitly.
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"math/bits"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,11 +33,11 @@ type Bulk struct {
|
||||
nword int32
|
||||
}
|
||||
|
||||
func NewBulk(nbit int32, count int32, pos src.XPos) Bulk {
|
||||
func NewBulk(nbit int32, count int32) Bulk {
|
||||
nword := (nbit + wordBits - 1) / wordBits
|
||||
size := int64(nword) * int64(count)
|
||||
if int64(int32(size*4)) != size*4 {
|
||||
base.FatalfAt(pos, "NewBulk too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size)
|
||||
base.Fatalf("NewBulk too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size)
|
||||
}
|
||||
return Bulk{
|
||||
words: make([]uint32, size),
|
||||
|
||||
@@ -1,194 +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.
|
||||
|
||||
// The deadlocals pass removes assignments to unused local variables.
|
||||
package deadlocals
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
)
|
||||
|
||||
// Funcs applies the deadlocals pass to fns.
|
||||
func Funcs(fns []*ir.Func) {
|
||||
if base.Flag.N != 0 || base.Debug.NoDeadLocals != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
zero := ir.NewBasicLit(base.AutogeneratedPos, types.Types[types.TINT], constant.MakeInt64(0))
|
||||
|
||||
for _, fn := range fns {
|
||||
if fn.IsClosure() {
|
||||
continue
|
||||
}
|
||||
|
||||
v := newVisitor(fn)
|
||||
v.nodes(fn.Body)
|
||||
|
||||
for _, k := range v.defsKeys {
|
||||
assigns := v.defs[k]
|
||||
for _, as := range assigns {
|
||||
// Kludge for "missing func info" linker panic.
|
||||
// See also closureInitLSym in inline/inl.go.
|
||||
if clo, ok := (*as.rhs).(*ir.ClosureExpr); ok && clo.Op() == ir.OCLOSURE {
|
||||
if clo.Func.IsClosure() {
|
||||
ir.InitLSym(clo.Func, true)
|
||||
}
|
||||
}
|
||||
|
||||
*as.lhs = ir.BlankNode
|
||||
*as.rhs = zero
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type visitor struct {
|
||||
curfn *ir.Func
|
||||
// defs[name] contains assignments that can be discarded if name can be discarded.
|
||||
// if defs[name] is defined nil, then name is actually used.
|
||||
defs map[*ir.Name][]assign
|
||||
defsKeys []*ir.Name // insertion order of keys, for reproducible iteration (and builds)
|
||||
|
||||
doNode func(ir.Node) bool
|
||||
}
|
||||
|
||||
type assign struct {
|
||||
pos src.XPos
|
||||
lhs, rhs *ir.Node
|
||||
}
|
||||
|
||||
func newVisitor(fn *ir.Func) *visitor {
|
||||
v := &visitor{
|
||||
curfn: fn,
|
||||
defs: make(map[*ir.Name][]assign),
|
||||
}
|
||||
v.doNode = func(n ir.Node) bool {
|
||||
v.node(n)
|
||||
return false
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *visitor) node(n ir.Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch n.Op() {
|
||||
default:
|
||||
ir.DoChildrenWithHidden(n, v.doNode)
|
||||
case ir.OCLOSURE:
|
||||
n := n.(*ir.ClosureExpr)
|
||||
v.nodes(n.Init())
|
||||
for _, cv := range n.Func.ClosureVars {
|
||||
v.node(cv)
|
||||
}
|
||||
v.nodes(n.Func.Body)
|
||||
|
||||
case ir.ODCL:
|
||||
// ignore
|
||||
case ir.ONAME:
|
||||
n := n.(*ir.Name)
|
||||
n = n.Canonical()
|
||||
if isLocal(n, false) {
|
||||
// Force any lazy definitions.
|
||||
s, ok := v.defs[n]
|
||||
if !ok {
|
||||
v.defsKeys = append(v.defsKeys, n)
|
||||
}
|
||||
v.defs[n] = nil
|
||||
for _, as := range s {
|
||||
// do the visit that was skipped in v.assign when as was appended to v.defs[n]
|
||||
v.node(*as.rhs)
|
||||
}
|
||||
}
|
||||
|
||||
case ir.OAS:
|
||||
n := n.(*ir.AssignStmt)
|
||||
v.assign(n.Pos(), &n.X, &n.Y, false)
|
||||
case ir.OAS2:
|
||||
n := n.(*ir.AssignListStmt)
|
||||
|
||||
// If all LHS vars are blank, treat them as intentional
|
||||
// uses of corresponding RHS vars. If any are non-blank
|
||||
// then any blanks are discards.
|
||||
hasNonBlank := false
|
||||
for i := range n.Lhs {
|
||||
if !ir.IsBlank(n.Lhs[i]) {
|
||||
hasNonBlank = true
|
||||
break
|
||||
}
|
||||
}
|
||||
for i := range n.Lhs {
|
||||
v.assign(n.Pos(), &n.Lhs[i], &n.Rhs[i], hasNonBlank)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *visitor) nodes(list ir.Nodes) {
|
||||
for _, n := range list {
|
||||
v.node(n)
|
||||
}
|
||||
}
|
||||
|
||||
func hasEffects(n ir.Node) bool {
|
||||
if n == nil {
|
||||
return false
|
||||
}
|
||||
if len(n.Init()) != 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
switch n.Op() {
|
||||
// TODO(mdempsky): More.
|
||||
case ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OCLOSURE:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v *visitor) assign(pos src.XPos, lhs, rhs *ir.Node, blankIsNotUse bool) {
|
||||
name, ok := (*lhs).(*ir.Name)
|
||||
if !ok {
|
||||
v.node(*lhs) // XXX: Interpret as variable, not value.
|
||||
v.node(*rhs)
|
||||
return
|
||||
}
|
||||
name = name.Canonical()
|
||||
|
||||
if isLocal(name, blankIsNotUse) && !hasEffects(*rhs) {
|
||||
if s, ok := v.defs[name]; !ok || s != nil {
|
||||
// !ok || s != nil is FALSE if previously "v.defs[name] = nil" -- that marks a use.
|
||||
if !ok {
|
||||
v.defsKeys = append(v.defsKeys, name)
|
||||
}
|
||||
v.defs[name] = append(s, assign{pos, lhs, rhs})
|
||||
return // don't visit rhs unless that node ends up live, later.
|
||||
}
|
||||
}
|
||||
|
||||
v.node(*rhs)
|
||||
}
|
||||
|
||||
func isLocal(n *ir.Name, blankIsNotUse bool) bool {
|
||||
if ir.IsBlank(n) {
|
||||
// Treat single assignments as intentional use (false), anything else is a discard (true).
|
||||
return blankIsNotUse
|
||||
}
|
||||
|
||||
switch n.Class {
|
||||
case ir.PAUTO, ir.PPARAM:
|
||||
return true
|
||||
case ir.PPARAMOUT:
|
||||
return false
|
||||
case ir.PEXTERN, ir.PFUNC:
|
||||
return false
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected Class: %+v", n))
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func StaticCall(call *ir.CallExpr) {
|
||||
// dictionary parameter. We could devirtualize this call if we
|
||||
// could derive an appropriate dictionary argument.
|
||||
//
|
||||
// TODO(mdempsky): If typ has a promoted non-generic method,
|
||||
// TODO(mdempsky): If typ has has a promoted non-generic method,
|
||||
// then that method won't require a dictionary argument. We could
|
||||
// still devirtualize those calls.
|
||||
//
|
||||
|
||||
@@ -241,9 +241,8 @@ func maybeDevirtualizeFunctionCall(p *pgoir.Profile, fn *ir.Func, call *ir.CallE
|
||||
return nil, nil, 0
|
||||
}
|
||||
// runtime.memhash_varlen does not look like a closure, but it uses
|
||||
// internal/runtime/sys.GetClosurePtr to access data encoded by
|
||||
// callers, which are generated by
|
||||
// cmd/compile/internal/reflectdata.genhash.
|
||||
// runtime.getclosureptr to access data encoded by callers, which are
|
||||
// are generated by cmd/compile/internal/reflectdata.genhash.
|
||||
if callee.Sym().Pkg.Path == "runtime" && callee.Sym().Name == "memhash_varlen" {
|
||||
if base.Debug.PGODebug >= 3 {
|
||||
fmt.Printf("callee %s is a closure (runtime.memhash_varlen), skipping\n", ir.FuncName(callee))
|
||||
|
||||
@@ -9,9 +9,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/buildcfg"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
@@ -26,7 +24,7 @@ import (
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
func Info(ctxt *obj.Link, fnsym *obj.LSym, infosym *obj.LSym, curfn obj.Func) (scopes []dwarf.Scope, inlcalls dwarf.InlCalls) {
|
||||
func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn obj.Func) (scopes []dwarf.Scope, inlcalls dwarf.InlCalls) {
|
||||
fn := curfn.(*ir.Func)
|
||||
|
||||
if fn.Nname != nil {
|
||||
@@ -132,11 +130,11 @@ func Info(ctxt *obj.Link, fnsym *obj.LSym, infosym *obj.LSym, curfn obj.Func) (s
|
||||
for t := range fnsym.Func().Autot {
|
||||
typesyms = append(typesyms, t)
|
||||
}
|
||||
slices.SortFunc(typesyms, func(a, b *obj.LSym) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
})
|
||||
sort.Sort(obj.BySymName(typesyms))
|
||||
for _, sym := range typesyms {
|
||||
infosym.AddRel(ctxt, obj.Reloc{Type: objabi.R_USETYPE, Sym: sym})
|
||||
r := obj.Addrel(infosym)
|
||||
r.Sym = sym
|
||||
r.Type = objabi.R_USETYPE
|
||||
}
|
||||
fnsym.Func().Autot = nil
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package dwarfgen
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"debug/dwarf"
|
||||
"fmt"
|
||||
"internal/platform"
|
||||
@@ -13,7 +12,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -401,8 +400,8 @@ func readScope(ctxt *scopexplainContext, scope *lexblock, entry *dwarf.Entry) {
|
||||
}
|
||||
switch e.Tag {
|
||||
case 0:
|
||||
slices.SortFunc(scope.vars, func(a, b variable) int {
|
||||
return cmp.Compare(a.expr, b.expr)
|
||||
sort.Slice(scope.vars, func(i, j int) bool {
|
||||
return scope.vars[i].expr < scope.vars[j].expr
|
||||
})
|
||||
return
|
||||
case dwarf.TagFormalParameter:
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// call evaluates a call expressions, including builtin calls. ks
|
||||
@@ -83,29 +82,6 @@ func (e *escape) call(ks []hole, call ir.Node) {
|
||||
argument(e.tagHole(ks, fn, param), arg)
|
||||
}
|
||||
|
||||
// hash/maphash.escapeForHash forces its argument to be on
|
||||
// the heap, if it contains a non-string pointer. We cannot
|
||||
// hash pointers to local variables, as the address of the
|
||||
// local variable might change on stack growth.
|
||||
// Strings are okay as the hash depends on only the content,
|
||||
// not the pointer.
|
||||
// The actual call we match is
|
||||
// hash/maphash.escapeForHash[go.shape.T](dict, go.shape.T)
|
||||
if fn != nil && fn.Sym().Pkg.Path == "hash/maphash" && strings.HasPrefix(fn.Sym().Name, "escapeForHash[") {
|
||||
ps := fntype.Params()
|
||||
if len(ps) == 2 && ps[1].Type.IsShape() {
|
||||
if !hasNonStringPointers(ps[1].Type) {
|
||||
argumentParam = func(param *types.Field, arg ir.Node) {
|
||||
argument(e.discardHole(), arg)
|
||||
}
|
||||
} else {
|
||||
argumentParam = func(param *types.Field, arg ir.Node) {
|
||||
argument(e.heapHole(), arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args := call.Args
|
||||
if recvParam := fntype.Recv(); recvParam != nil {
|
||||
if recvArg == nil {
|
||||
@@ -383,23 +359,3 @@ func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole {
|
||||
|
||||
return e.teeHole(tagKs...)
|
||||
}
|
||||
|
||||
func hasNonStringPointers(t *types.Type) bool {
|
||||
if !t.HasPointers() {
|
||||
return false
|
||||
}
|
||||
switch t.Kind() {
|
||||
case types.TSTRING:
|
||||
return false
|
||||
case types.TSTRUCT:
|
||||
for _, f := range t.Fields() {
|
||||
if hasNonStringPointers(f.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case types.TARRAY:
|
||||
return hasNonStringPointers(t.Elem())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -139,13 +139,13 @@ func Batch(fns []*ir.Func, recursive bool) {
|
||||
b.initFunc(fn)
|
||||
}
|
||||
for _, fn := range fns {
|
||||
if !fn.IsClosure() {
|
||||
if !fn.IsHiddenClosure() {
|
||||
b.walkFunc(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// We've walked the function bodies, so we've seen everywhere a
|
||||
// variable might be reassigned or have its address taken. Now we
|
||||
// variable might be reassigned or have it's address taken. Now we
|
||||
// can decide whether closures should capture their free variables
|
||||
// by value or reference.
|
||||
for _, closure := range b.closures {
|
||||
|
||||
@@ -38,7 +38,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
||||
default:
|
||||
base.Fatalf("unexpected expr: %s %v", n.Op().String(), n)
|
||||
|
||||
case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OGETCALLERSP, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET:
|
||||
case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET:
|
||||
// nop
|
||||
|
||||
case ir.ONAME:
|
||||
@@ -230,7 +230,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
||||
k = e.spill(k, n)
|
||||
e.closures = append(e.closures, closure{k, n})
|
||||
|
||||
if fn := n.Func; fn.IsClosure() {
|
||||
if fn := n.Func; fn.IsHiddenClosure() {
|
||||
for _, cv := range fn.ClosureVars {
|
||||
if loc := e.oldLoc(cv); !loc.captured {
|
||||
loc.captured = true
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"internal/race"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
@@ -40,7 +39,12 @@ func enqueueFunc(fn *ir.Func) {
|
||||
return
|
||||
}
|
||||
|
||||
if fn.IsClosure() {
|
||||
// Don't try compiling dead hidden closure.
|
||||
if fn.IsDeadcodeClosure() {
|
||||
return
|
||||
}
|
||||
|
||||
if clo := fn.OClosure; clo != nil && !ir.IsTrivialClosure(clo) {
|
||||
return // we'll get this as part of its enclosing function
|
||||
}
|
||||
|
||||
@@ -106,11 +110,6 @@ func prepareFunc(fn *ir.Func) {
|
||||
// Calculate parameter offsets.
|
||||
types.CalcSize(fn.Type())
|
||||
|
||||
// Generate wrappers between Go ABI and Wasm ABI, for a wasmexport
|
||||
// function.
|
||||
// Must be done after InitLSym and CalcSize.
|
||||
ssagen.GenWasmExportWrapper(fn)
|
||||
|
||||
ir.CurFunc = fn
|
||||
walk.Walk(fn)
|
||||
ir.CurFunc = nil // enforce no further uses of CurFunc
|
||||
@@ -132,8 +131,8 @@ func compileFunctions(profile *pgoir.Profile) {
|
||||
// Compile the longest functions first,
|
||||
// since they're most likely to be the slowest.
|
||||
// This helps avoid stragglers.
|
||||
slices.SortFunc(compilequeue, func(a, b *ir.Func) int {
|
||||
return cmp.Compare(len(b.Body), len(a.Body))
|
||||
sort.Slice(compilequeue, func(i, j int) bool {
|
||||
return len(compilequeue[i].Body) > len(compilequeue[j].Body)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"bytes"
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/coverage"
|
||||
"cmd/compile/internal/deadlocals"
|
||||
"cmd/compile/internal/dwarfgen"
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/inline"
|
||||
@@ -104,13 +103,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||
ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
|
||||
ir.Pkgs.Runtime.Prefix = "runtime"
|
||||
|
||||
if buildcfg.Experiment.SwissMap {
|
||||
// Pseudo-package that contains the compiler's builtin
|
||||
// declarations for maps.
|
||||
ir.Pkgs.InternalMaps = types.NewPkg("go.internal/runtime/maps", "internal/runtime/maps")
|
||||
ir.Pkgs.InternalMaps.Prefix = "internal/runtime/maps"
|
||||
}
|
||||
|
||||
// pseudo-packages used in symbol tables
|
||||
ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
|
||||
ir.Pkgs.Itab.Prefix = "go:itab"
|
||||
@@ -140,7 +132,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||
}
|
||||
|
||||
if base.Flag.SmallFrames {
|
||||
ir.MaxStackVarSize = 64 * 1024
|
||||
ir.MaxStackVarSize = 128 * 1024
|
||||
ir.MaxImplicitStackVarSize = 16 * 1024
|
||||
}
|
||||
|
||||
@@ -255,8 +247,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||
// and doesn't benefit from dead-coding or inlining.
|
||||
symABIs.GenABIWrappers()
|
||||
|
||||
deadlocals.Funcs(typecheck.Target.Funcs)
|
||||
|
||||
// Escape analysis.
|
||||
// Required for moving heap allocations onto stack,
|
||||
// which in turn is required by the closure implementation,
|
||||
|
||||
95
src/cmd/compile/internal/importer/exportdata.go
Normal file
95
src/cmd/compile/internal/importer/exportdata.go
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements FindExportData.
|
||||
|
||||
package importer
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
||||
// See $GOROOT/include/ar.h.
|
||||
hdr := make([]byte, 16+12+6+6+8+10+2)
|
||||
_, err = io.ReadFull(r, hdr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// leave for debugging
|
||||
if false {
|
||||
fmt.Printf("header: %s", hdr)
|
||||
}
|
||||
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
|
||||
size, err = strconv.Atoi(s)
|
||||
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
|
||||
err = fmt.Errorf("invalid archive header")
|
||||
return
|
||||
}
|
||||
name = strings.TrimSpace(string(hdr[:16]))
|
||||
return
|
||||
}
|
||||
|
||||
// FindExportData positions the reader r at the beginning of the
|
||||
// export data section of an underlying GC-created object/archive
|
||||
// file by reading from it. The reader must be positioned at the
|
||||
// start of the file before calling this function. The hdr result
|
||||
// is the string before the export data, either "$$" or "$$B".
|
||||
//
|
||||
// If size is non-negative, it's the number of bytes of export data
|
||||
// still available to read from r.
|
||||
func FindExportData(r *bufio.Reader) (hdr string, size int, err error) {
|
||||
// Read first line to make sure this is an object file.
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
|
||||
if string(line) == "!<arch>\n" {
|
||||
// Archive file. Scan to __.PKGDEF.
|
||||
var name string
|
||||
if name, size, err = readGopackHeader(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// First entry should be __.PKGDEF.
|
||||
if name != "__.PKGDEF" {
|
||||
err = fmt.Errorf("go archive is missing __.PKGDEF")
|
||||
return
|
||||
}
|
||||
|
||||
// Read first line of __.PKGDEF data, so that line
|
||||
// is once again the first line of the input.
|
||||
if line, err = r.ReadSlice('\n'); err != nil {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Now at __.PKGDEF in archive or still at beginning of file.
|
||||
// Either way, line should begin with "go object ".
|
||||
if !strings.HasPrefix(string(line), "go object ") {
|
||||
err = fmt.Errorf("not a Go object file")
|
||||
return
|
||||
}
|
||||
size -= len(line)
|
||||
|
||||
// Skip over object header to export data.
|
||||
// Begins after first line starting with $$.
|
||||
for line[0] != '$' {
|
||||
if line, err = r.ReadSlice('\n'); err != nil {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
size -= len(line)
|
||||
}
|
||||
hdr = string(line)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -2,26 +2,151 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements the Import function for tests to use gc-generated object files.
|
||||
|
||||
// package importer implements Import for gc-generated object files.
|
||||
package importer
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/exportdata"
|
||||
"go/build"
|
||||
"internal/pkgbits"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/compile/internal/types2"
|
||||
)
|
||||
|
||||
var exportMap sync.Map // package dir → func() (string, error)
|
||||
|
||||
// lookupGorootExport returns the location of the export data
|
||||
// (normally found in the build cache, but located in GOROOT/pkg
|
||||
// in prior Go releases) for the package located in pkgDir.
|
||||
//
|
||||
// (We use the package's directory instead of its import path
|
||||
// mainly to simplify handling of the packages in src/vendor
|
||||
// and cmd/vendor.)
|
||||
func lookupGorootExport(pkgDir string) (string, error) {
|
||||
f, ok := exportMap.Load(pkgDir)
|
||||
if !ok {
|
||||
var (
|
||||
listOnce sync.Once
|
||||
exportPath string
|
||||
err error
|
||||
)
|
||||
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, error) {
|
||||
listOnce.Do(func() {
|
||||
cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd.Dir = build.Default.GOROOT
|
||||
cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT)
|
||||
var output []byte
|
||||
output, err = cmd.Output()
|
||||
if err != nil {
|
||||
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
|
||||
err = errors.New(string(ee.Stderr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
exports := strings.Split(string(bytes.TrimSpace(output)), "\n")
|
||||
if len(exports) != 1 {
|
||||
err = fmt.Errorf("go list reported %d exports; expected 1", len(exports))
|
||||
return
|
||||
}
|
||||
|
||||
exportPath = exports[0]
|
||||
})
|
||||
|
||||
return exportPath, err
|
||||
})
|
||||
}
|
||||
|
||||
return f.(func() (string, error))()
|
||||
}
|
||||
|
||||
var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
|
||||
|
||||
// FindPkg returns the filename and unique package id for an import
|
||||
// path based on package information provided by build.Import (using
|
||||
// the build.Default build.Context). A relative srcDir is interpreted
|
||||
// relative to the current working directory.
|
||||
func FindPkg(path, srcDir string) (filename, id string, err error) {
|
||||
if path == "" {
|
||||
return "", "", errors.New("path is empty")
|
||||
}
|
||||
|
||||
var noext string
|
||||
switch {
|
||||
default:
|
||||
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
|
||||
// Don't require the source files to be present.
|
||||
if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
|
||||
srcDir = abs
|
||||
}
|
||||
var bp *build.Package
|
||||
bp, err = build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
|
||||
if bp.PkgObj == "" {
|
||||
if bp.Goroot && bp.Dir != "" {
|
||||
filename, err = lookupGorootExport(bp.Dir)
|
||||
if err == nil {
|
||||
_, err = os.Stat(filename)
|
||||
}
|
||||
if err == nil {
|
||||
return filename, bp.ImportPath, nil
|
||||
}
|
||||
}
|
||||
goto notfound
|
||||
} else {
|
||||
noext = strings.TrimSuffix(bp.PkgObj, ".a")
|
||||
}
|
||||
id = bp.ImportPath
|
||||
|
||||
case build.IsLocalImport(path):
|
||||
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
|
||||
noext = filepath.Join(srcDir, path)
|
||||
id = noext
|
||||
|
||||
case filepath.IsAbs(path):
|
||||
// for completeness only - go/build.Import
|
||||
// does not support absolute imports
|
||||
// "/x" -> "/x.ext", "/x"
|
||||
noext = path
|
||||
id = path
|
||||
}
|
||||
|
||||
if false { // for debugging
|
||||
if path != id {
|
||||
fmt.Printf("%s -> %s\n", path, id)
|
||||
}
|
||||
}
|
||||
|
||||
// try extensions
|
||||
for _, ext := range pkgExts {
|
||||
filename = noext + ext
|
||||
f, statErr := os.Stat(filename)
|
||||
if statErr == nil && !f.IsDir() {
|
||||
return filename, id, nil
|
||||
}
|
||||
if err == nil {
|
||||
err = statErr
|
||||
}
|
||||
}
|
||||
|
||||
notfound:
|
||||
if err == nil {
|
||||
return "", path, fmt.Errorf("can't find import: %q", path)
|
||||
}
|
||||
return "", path, fmt.Errorf("can't find import: %q: %w", path, err)
|
||||
}
|
||||
|
||||
// Import imports a gc-generated package given its import path and srcDir, adds
|
||||
// the corresponding package object to the packages map, and returns the object.
|
||||
// The packages map must contain all packages already imported.
|
||||
//
|
||||
// This function should only be used in tests.
|
||||
func Import(packages map[string]*types2.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types2.Package, err error) {
|
||||
var rc io.ReadCloser
|
||||
var id string
|
||||
@@ -44,7 +169,7 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun
|
||||
rc = f
|
||||
} else {
|
||||
var filename string
|
||||
filename, id, err = exportdata.FindPkg(path, srcDir)
|
||||
filename, id, err = FindPkg(path, srcDir)
|
||||
if filename == "" {
|
||||
if path == "unsafe" {
|
||||
return types2.Unsafe, nil
|
||||
@@ -73,15 +198,56 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun
|
||||
defer rc.Close()
|
||||
|
||||
buf := bufio.NewReader(rc)
|
||||
data, err := exportdata.ReadUnified(buf)
|
||||
hdr, size, err := FindExportData(buf)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("import %q: %v", path, err)
|
||||
return
|
||||
}
|
||||
s := string(data)
|
||||
|
||||
input := pkgbits.NewPkgDecoder(id, s)
|
||||
pkg = ReadPackage(nil, packages, input)
|
||||
switch hdr {
|
||||
case "$$\n":
|
||||
err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path)
|
||||
|
||||
case "$$B\n":
|
||||
var data []byte
|
||||
var r io.Reader = buf
|
||||
if size >= 0 {
|
||||
r = io.LimitReader(r, int64(size))
|
||||
}
|
||||
data, err = io.ReadAll(r)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
err = fmt.Errorf("import %q: missing export data", path)
|
||||
break
|
||||
}
|
||||
exportFormat := data[0]
|
||||
s := string(data[1:])
|
||||
|
||||
// The indexed export format starts with an 'i'; the older
|
||||
// binary export format starts with a 'c', 'd', or 'v'
|
||||
// (from "version"). Select appropriate importer.
|
||||
switch exportFormat {
|
||||
case 'u':
|
||||
s = s[:strings.Index(s, "\n$$\n")]
|
||||
input := pkgbits.NewPkgDecoder(id, s)
|
||||
pkg = ReadPackage(nil, packages, input)
|
||||
case 'i':
|
||||
pkg, err = ImportData(packages, s, id)
|
||||
default:
|
||||
err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
|
||||
}
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("import %q: unknown export data header: %q", path, hdr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type byPath []*types2.Package
|
||||
|
||||
func (a byPath) Len() int { return len(a) }
|
||||
func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
|
||||
|
||||
@@ -6,11 +6,9 @@ package importer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/compile/internal/syntax"
|
||||
"cmd/compile/internal/types2"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/exportdata"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -18,7 +16,6 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -93,16 +90,22 @@ func TestImportTestdata(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
testfiles := map[string][]string{
|
||||
"exports.go": {"go/ast"},
|
||||
"exports.go": {"go/ast", "go/token"},
|
||||
"generics.go": nil,
|
||||
}
|
||||
if true /* was goexperiment.Unified */ {
|
||||
// TODO(mdempsky): Fix test below to flatten the transitive
|
||||
// Package.Imports graph. Unified IR is more precise about
|
||||
// recreating the package import graph.
|
||||
testfiles["exports.go"] = []string{"go/ast"}
|
||||
}
|
||||
|
||||
for testfile, wantImports := range testfiles {
|
||||
tmpdir := mktmpdir(t)
|
||||
|
||||
importMap := map[string]string{}
|
||||
for _, pkg := range wantImports {
|
||||
export, _, err := exportdata.FindPkg(pkg, "testdata")
|
||||
export, _, err := FindPkg(pkg, "testdata")
|
||||
if export == "" {
|
||||
t.Fatalf("no export data found for %s: %v", pkg, err)
|
||||
}
|
||||
@@ -163,29 +166,17 @@ func TestVersionHandling(t *testing.T) {
|
||||
// test that export data can be imported
|
||||
_, err := Import(make(map[string]*types2.Package), pkgpath, dir, nil)
|
||||
if err != nil {
|
||||
// ok to fail if it fails with a 'not the start of an archive file' error for select files
|
||||
// ok to fail if it fails with a no longer supported error for select files
|
||||
if strings.Contains(err.Error(), "no longer supported") {
|
||||
switch name {
|
||||
case "test_go1.8_4.a",
|
||||
"test_go1.8_5.a":
|
||||
case "test_go1.7_0.a", "test_go1.7_1.a",
|
||||
"test_go1.8_4.a", "test_go1.8_5.a",
|
||||
"test_go1.11_6b.a", "test_go1.11_999b.a":
|
||||
continue
|
||||
}
|
||||
// fall through
|
||||
}
|
||||
// ok to fail if it fails with a 'no longer supported' error for select files
|
||||
if strings.Contains(err.Error(), "no longer supported") {
|
||||
switch name {
|
||||
case "test_go1.7_0.a",
|
||||
"test_go1.7_1.a",
|
||||
"test_go1.8_4.a",
|
||||
"test_go1.8_5.a",
|
||||
"test_go1.11_6b.a",
|
||||
"test_go1.11_999b.a":
|
||||
continue
|
||||
}
|
||||
// fall through
|
||||
}
|
||||
// ok to fail if it fails with a 'newer version' error for select files
|
||||
// ok to fail if it fails with a newer version error for select files
|
||||
if strings.Contains(err.Error(), "newer version") {
|
||||
switch name {
|
||||
case "test_go1.11_999i.a":
|
||||
@@ -205,8 +196,6 @@ func TestVersionHandling(t *testing.T) {
|
||||
}
|
||||
// 2) find export data
|
||||
i := bytes.Index(data, []byte("\n$$B\n")) + 5
|
||||
// Export data can contain "\n$$\n" in string constants, however,
|
||||
// searching for the next end of section marker "\n$$\n" is good enough for testzs.
|
||||
j := bytes.Index(data[i:], []byte("\n$$\n")) + i
|
||||
if i < 0 || j < 0 || i > j {
|
||||
t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
|
||||
@@ -279,7 +268,7 @@ var importedObjectTests = []struct {
|
||||
{"math.Pi", "const Pi untyped float"},
|
||||
{"math.Sin", "func Sin(x float64) float64"},
|
||||
{"go/ast.NotNilFilter", "func NotNilFilter(_ string, v reflect.Value) bool"},
|
||||
{"internal/exportdata.FindPkg", "func FindPkg(path string, srcDir string) (filename string, id string, err error)"},
|
||||
{"go/internal/gcimporter.FindPkg", "func FindPkg(path string, srcDir string) (filename string, id string, err error)"},
|
||||
|
||||
// interfaces
|
||||
{"context.Context", "type Context interface{Deadline() (deadline time.Time, ok bool); Done() <-chan struct{}; Err() error; Value(key any) any}"},
|
||||
@@ -347,7 +336,14 @@ func verifyInterfaceMethodRecvs(t *testing.T, named *types2.Named, level int) {
|
||||
// The unified IR importer always sets interface method receiver
|
||||
// parameters to point to the Interface type, rather than the Named.
|
||||
// See #49906.
|
||||
var want types2.Type = iface
|
||||
//
|
||||
// TODO(mdempsky): This is only true for the types2 importer. For
|
||||
// the go/types importer, we duplicate the Interface and rewrite its
|
||||
// receiver methods to match historical behavior.
|
||||
var want types2.Type = named
|
||||
if true /* was goexperiment.Unified */ {
|
||||
want = iface
|
||||
}
|
||||
|
||||
// check explicitly declared methods
|
||||
for i := 0; i < iface.NumExplicitMethods(); i++ {
|
||||
@@ -441,7 +437,7 @@ func TestIssue13566(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
jsonExport, _, err := exportdata.FindPkg("encoding/json", "testdata")
|
||||
jsonExport, _, err := FindPkg("encoding/json", "testdata")
|
||||
if jsonExport == "" {
|
||||
t.Fatalf("no export data found for encoding/json: %v", err)
|
||||
}
|
||||
@@ -586,6 +582,23 @@ func TestIssue25596(t *testing.T) {
|
||||
compileAndImportPkg(t, "issue25596")
|
||||
}
|
||||
|
||||
func TestIssue70394(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
// This package only handles gc export data.
|
||||
if runtime.Compiler != "gc" {
|
||||
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||
}
|
||||
|
||||
pkg := compileAndImportPkg(t, "alias")
|
||||
obj := lookupObj(t, pkg.Scope(), "A")
|
||||
|
||||
typ := obj.Type()
|
||||
if _, ok := typ.(*types2.Alias); !ok {
|
||||
t.Fatalf("type of %s is %s, wanted an alias", obj, typ)
|
||||
}
|
||||
}
|
||||
|
||||
func importPkg(t *testing.T, path, srcDir string) *types2.Package {
|
||||
pkg, err := Import(make(map[string]*types2.Package), path, srcDir, nil)
|
||||
if err != nil {
|
||||
@@ -610,66 +623,3 @@ func lookupObj(t *testing.T, scope *types2.Scope, name string) types2.Object {
|
||||
t.Fatalf("%s not found", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// importMap implements the types2.Importer interface.
|
||||
type importMap map[string]*types2.Package
|
||||
|
||||
func (m importMap) Import(path string) (*types2.Package, error) { return m[path], nil }
|
||||
|
||||
func TestIssue69912(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
// This package only handles gc export data.
|
||||
if runtime.Compiler != "gc" {
|
||||
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||
}
|
||||
|
||||
tmpdir := t.TempDir()
|
||||
testoutdir := filepath.Join(tmpdir, "testdata")
|
||||
if err := os.Mkdir(testoutdir, 0700); err != nil {
|
||||
t.Fatalf("making output dir: %v", err)
|
||||
}
|
||||
|
||||
compile(t, "testdata", "issue69912.go", testoutdir, nil)
|
||||
|
||||
issue69912, err := Import(make(map[string]*types2.Package), "./testdata/issue69912", tmpdir, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := func(pkgname, src string, imports importMap) (*types2.Package, error) {
|
||||
f, err := syntax.Parse(syntax.NewFileBase(pkgname), strings.NewReader(src), nil, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := &types2.Config{
|
||||
Importer: imports,
|
||||
}
|
||||
return config.Check(pkgname, []*syntax.File{f}, nil)
|
||||
}
|
||||
|
||||
// Use the resulting package concurrently, via dot-imports, to exercise the
|
||||
// race of issue #69912.
|
||||
const pSrc = `package p
|
||||
|
||||
import . "issue69912"
|
||||
|
||||
type S struct {
|
||||
f T
|
||||
}
|
||||
`
|
||||
importer := importMap{
|
||||
"issue69912": issue69912,
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for range 10 {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if _, err := check("p", pSrc, importer); err != nil {
|
||||
t.Errorf("Check failed: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user