mirror of
https://github.com/golang/go.git
synced 2026-01-30 07:32:05 +03:00
Compare commits
108 Commits
dev.corety
...
go1.22.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb4eee693c | ||
|
|
8c8adffd53 | ||
|
|
70a1aae67f | ||
|
|
2c88c1d599 | ||
|
|
4c50f9162c | ||
|
|
9e148a4150 | ||
|
|
4b27560db9 | ||
|
|
4e548f2c8e | ||
|
|
45f9ded1df | ||
|
|
49906f9575 | ||
|
|
ea96074191 | ||
|
|
8e1fdea831 | ||
|
|
c2d4f852ce | ||
|
|
3222951439 | ||
|
|
ceaf26ecce | ||
|
|
dfe4dbf8c0 | ||
|
|
3560cf0afb | ||
|
|
5159a7193a | ||
|
|
11b861e459 | ||
|
|
81fc616267 | ||
|
|
14f0251867 | ||
|
|
ab60a7bc18 | ||
|
|
4c97e883b5 | ||
|
|
179ccb7042 | ||
|
|
fe9b3c3399 | ||
|
|
b515c5208b | ||
|
|
ace5bb40d0 | ||
|
|
12d5810cdb | ||
|
|
745657509e | ||
|
|
95389d3d9d | ||
|
|
cf501ac0c5 | ||
|
|
cb55d1a0c8 | ||
|
|
3c96ae0870 | ||
|
|
6b89e7dc5a | ||
|
|
185457da9b | ||
|
|
3a84293118 | ||
|
|
362dcedfdb | ||
|
|
d4a81ec7ee | ||
|
|
dc8976dd0b | ||
|
|
00e6815208 | ||
|
|
adbfb672ba | ||
|
|
fa0292d252 | ||
|
|
947e43e371 | ||
|
|
9d2e28501c | ||
|
|
93d8777d24 | ||
|
|
3f4af1ff0e | ||
|
|
a7ff78d585 | ||
|
|
12c1177045 | ||
|
|
d6c972ad41 | ||
|
|
a65a2bbd8e | ||
|
|
dddf0ae40f | ||
|
|
e55d7cf843 | ||
|
|
4edf4bb2c6 | ||
|
|
2c6d106541 | ||
|
|
46587483e3 | ||
|
|
0a5b33a883 | ||
|
|
0c53f93faa | ||
|
|
abfd578156 | ||
|
|
7fb7acb82d | ||
|
|
e23707b59c | ||
|
|
3826650c99 | ||
|
|
e71b0b1fee | ||
|
|
9508eae5d1 | ||
|
|
35b1a146d9 | ||
|
|
db6097f8cb | ||
|
|
041a47712e | ||
|
|
3a855208e3 | ||
|
|
337b8e9cbf | ||
|
|
16830ab48a | ||
|
|
056b0edcb8 | ||
|
|
f73eba76a0 | ||
|
|
5330cd225b | ||
|
|
d8c4239f08 | ||
|
|
c33adf44ff | ||
|
|
3b71998078 | ||
|
|
8fe2ad6494 | ||
|
|
686662f3a4 | ||
|
|
6cbe522fe1 | ||
|
|
fb86598cd3 | ||
|
|
6fbd01a711 | ||
|
|
d6a271939f | ||
|
|
20107e05a6 | ||
|
|
53d1b73dff | ||
|
|
dd31ad7e9f | ||
|
|
a10e42f219 | ||
|
|
b0957cfcf9 | ||
|
|
58a35fe55b | ||
|
|
4c5517913c | ||
|
|
5d647ed9fc | ||
|
|
e34f6a9928 | ||
|
|
7b3786bbb1 | ||
|
|
9289b9c336 | ||
|
|
aa721d1e7d | ||
|
|
117d7b107e | ||
|
|
333ecd4b40 | ||
|
|
1e1da49105 | ||
|
|
817009da40 | ||
|
|
b29ec30780 | ||
|
|
10e9ab55c8 | ||
|
|
ba8e9e14f4 | ||
|
|
77e9c26960 | ||
|
|
fe55bbcfd1 | ||
|
|
9a70e17e0f | ||
|
|
66f8e1e817 | ||
|
|
fa72f3e034 | ||
|
|
fb23428a85 | ||
|
|
f06eaf0c4f | ||
|
|
796f59df92 |
@@ -1,13 +1,4 @@
|
||||
pkg archive/tar, method (*Writer) AddFS(fs.FS) error #58000
|
||||
pkg archive/tar, type FileInfoNames interface { Gname, IsDir, ModTime, Mode, Name, Size, Sys, Uname } #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Gname(int) (string, error) #50102
|
||||
pkg archive/tar, type FileInfoNames interface, IsDir() bool #50102
|
||||
pkg archive/tar, type FileInfoNames interface, ModTime() time.Time #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Mode() fs.FileMode #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Name() string #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Size() int64 #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Sys() interface{} #50102
|
||||
pkg archive/tar, type FileInfoNames interface, Uname(int) (string, error) #50102
|
||||
pkg archive/zip, method (*Writer) AddFS(fs.FS) error #54898
|
||||
pkg cmp, func Or[$0 comparable](...$0) $0 #60204
|
||||
pkg crypto/x509, func OIDFromInts([]uint64) (OID, error) #60665
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.22
|
||||
parent-branch: master
|
||||
|
||||
1021
doc/go1.22.html
1021
doc/go1.22.html
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of Dec 27, 2023",
|
||||
"Subtitle": "Language version go1.22 (Feb 6, 2024)",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -6661,7 +6661,7 @@ array or slice a [n]E, *[n]E, or []E index i int a[i] E
|
||||
string s string type index i int see below rune
|
||||
map m map[K]V key k K m[k] V
|
||||
channel c chan E, <-chan E element e E
|
||||
integer n integer type I value i I
|
||||
integer n integer type value i see below
|
||||
</pre>
|
||||
|
||||
<ol>
|
||||
@@ -6703,26 +6703,33 @@ is <code>nil</code>, the range expression blocks forever.
|
||||
|
||||
<li>
|
||||
For an integer value <code>n</code>, the iteration values 0 through <code>n-1</code>
|
||||
are produced in increasing order, with the same type as <code>n</code>.
|
||||
are produced in increasing order.
|
||||
If <code>n</code> <= 0, the loop does not run any iterations.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
The iteration values are assigned to the respective
|
||||
iteration variables as in an <a href="#Assignment_statements">assignment statement</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The iteration variables may be declared by the "range" clause using a form of
|
||||
<a href="#Short_variable_declarations">short variable declaration</a>
|
||||
(<code>:=</code>).
|
||||
In this case their types are set to the types of the respective iteration values
|
||||
and their <a href="#Declarations_and_scope">scope</a> is the block of the "for" statement;
|
||||
each iteration has its own separate variables [<a href="#Go_1.22">Go 1.22</a>]
|
||||
In this case their <a href="#Declarations_and_scope">scope</a> is the block of the "for" statement
|
||||
and each iteration has its own new variables [<a href="#Go_1.22">Go 1.22</a>]
|
||||
(see also <a href="#For_clause">"for" statements with a ForClause</a>).
|
||||
If the iteration variables are declared outside the “for” statement,
|
||||
after execution their values will be those of the last iteration.
|
||||
If the range expression is a (possibly untyped) integer expression <code>n</code>,
|
||||
the variable has the same type as if it was
|
||||
<a href="#Variable_declarations">declared</a> with initialization
|
||||
expression <code>n</code>.
|
||||
Otherwise, the variables have the types of their respective iteration values.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If the iteration variables are not explicitly declared by the "range" clause,
|
||||
they must be preexisting.
|
||||
In this case, the iteration values are assigned to the respective variables
|
||||
as in an <a href="#Assignment_statements">assignment statement</a>.
|
||||
If the range expression is a (possibly untyped) integer expression <code>n</code>,
|
||||
<code>n</code> too must be <a href="#Assignability">assignable</a> to the iteration variable;
|
||||
if there is no iteration variable, <code>n</code> must be assignable to <code>int</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -6765,6 +6772,11 @@ for i := range 10 {
|
||||
// type of i is int (default type for untyped constant 10)
|
||||
f(i)
|
||||
}
|
||||
|
||||
// invalid: 256 cannot be assigned to uint8
|
||||
var u uint8
|
||||
for u = range 256 {
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
@@ -248,6 +248,13 @@ Go 1.19 made it an error for path lookups to resolve to binaries in the current
|
||||
controlled by the [`execerrdot` setting](/pkg/os/exec#hdr-Executables_in_the_current_directory).
|
||||
There is no plan to remove this setting.
|
||||
|
||||
Go 1.19 started sending EDNS0 additional headers on DNS requests.
|
||||
This can reportedly break the DNS server provided on some routers,
|
||||
such as CenturyLink Zyxel C3000Z.
|
||||
This can be changed by the [`netedns0` setting](/pkg/net#hdr-Name_Resolution).
|
||||
This setting is available in Go 1.21.12, Go 1.22.5, Go 1.23, and later.
|
||||
There is no plan to remove this setting.
|
||||
|
||||
### Go 1.18
|
||||
|
||||
Go 1.18 removed support for SHA1 in most X.509 certificates,
|
||||
|
||||
@@ -614,8 +614,6 @@ func (fi headerFileInfo) String() string {
|
||||
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
||||
var sysStat func(fi fs.FileInfo, h *Header) error
|
||||
|
||||
var loadUidAndGid func(fi fs.FileInfo, uid, gid *int)
|
||||
|
||||
const (
|
||||
// Mode constants from the USTAR spec:
|
||||
// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
|
||||
@@ -641,10 +639,6 @@ const (
|
||||
// Since fs.FileInfo's Name method only returns the base name of
|
||||
// the file it describes, it may be necessary to modify Header.Name
|
||||
// to provide the full path name of the file.
|
||||
//
|
||||
// If fi implements [FileInfoNames]
|
||||
// the Gname and Uname of the header are
|
||||
// provided by the methods of the interface.
|
||||
func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
if fi == nil {
|
||||
return nil, errors.New("archive/tar: FileInfo is nil")
|
||||
@@ -717,38 +711,12 @@ func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if iface, ok := fi.(FileInfoNames); ok {
|
||||
var err error
|
||||
if loadUidAndGid != nil {
|
||||
loadUidAndGid(fi, &h.Uid, &h.Gid)
|
||||
}
|
||||
h.Gname, err = iface.Gname(h.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.Uname, err = iface.Uname(h.Uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
if sysStat != nil {
|
||||
return h, sysStat(fi, h)
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// FileInfoNames extends [FileInfo] to translate UID/GID to names.
|
||||
// Passing an instance of this to [FileInfoHeader] permits the caller
|
||||
// to control UID/GID resolution.
|
||||
type FileInfoNames interface {
|
||||
fs.FileInfo
|
||||
// Uname should translate a UID into a user name.
|
||||
Uname(uid int) (string, error)
|
||||
// Gname should translate a GID into a group name.
|
||||
Gname(gid int) (string, error)
|
||||
}
|
||||
|
||||
// isHeaderOnlyType checks if the given type flag is of the type that has no
|
||||
// data section even if a size is specified.
|
||||
func isHeaderOnlyType(flag byte) bool {
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
|
||||
func init() {
|
||||
sysStat = statUnix
|
||||
loadUidAndGid = loadUidAndGidFunc
|
||||
}
|
||||
|
||||
// userMap and groupMap caches UID and GID lookups for performance reasons.
|
||||
@@ -100,12 +99,3 @@ func statUnix(fi fs.FileInfo, h *Header) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadUidAndGidFunc(fi fs.FileInfo, uid, gid *int) {
|
||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
*uid = int(sys.Uid)
|
||||
*gid = int(sys.Gid)
|
||||
}
|
||||
|
||||
@@ -848,71 +848,3 @@ func Benchmark(b *testing.B) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const (
|
||||
testUid = 10
|
||||
testGid = 20
|
||||
)
|
||||
|
||||
type fileInfoNames struct{}
|
||||
|
||||
func (f *fileInfoNames) Name() string {
|
||||
return "tmp"
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Size() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Mode() fs.FileMode {
|
||||
return 0777
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) ModTime() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Sys() any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Uname(uid int) (string, error) {
|
||||
if uid == testUid {
|
||||
return "Uname", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (f *fileInfoNames) Gname(gid int) (string, error) {
|
||||
if gid == testGid {
|
||||
return "Gname", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func TestFileInfoHeaderUseFileInfoNames(t *testing.T) {
|
||||
origLoadUidAndGid := loadUidAndGid
|
||||
defer func() {
|
||||
loadUidAndGid = origLoadUidAndGid
|
||||
}()
|
||||
loadUidAndGid = func(fi fs.FileInfo, uid, gid *int) {
|
||||
*uid = testUid
|
||||
*gid = testGid
|
||||
}
|
||||
|
||||
info := &fileInfoNames{}
|
||||
header, err := FileInfoHeader(info, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if header.Uname != "Uname" {
|
||||
t.Fatalf("header.Uname: got %v, want %v", header.Uname, "Uname")
|
||||
}
|
||||
if header.Gname != "Gname" {
|
||||
t.Fatalf("header.Gname: got %v, want %v", header.Gname, "Gname")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,9 +699,13 @@ func findSignatureInBlock(b []byte) int {
|
||||
if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
|
||||
// n is length of comment
|
||||
n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
|
||||
if n+directoryEndLen+i <= len(b) {
|
||||
return i
|
||||
if n+directoryEndLen+i > len(b) {
|
||||
// Truncated comment.
|
||||
// Some parsers (such as Info-ZIP) ignore the truncated comment
|
||||
// rather than treating it as a hard error.
|
||||
return -1
|
||||
}
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
|
||||
@@ -570,6 +570,14 @@ var tests = []ZipTest{
|
||||
},
|
||||
},
|
||||
},
|
||||
// Issue 66869: Don't skip over an EOCDR with a truncated comment.
|
||||
// The test file sneakily hides a second EOCDR before the first one;
|
||||
// previously we would extract one file ("file") from this archive,
|
||||
// while most other tools would reject the file or extract a different one ("FILE").
|
||||
{
|
||||
Name: "comment-truncated.zip",
|
||||
Error: ErrFormat,
|
||||
},
|
||||
}
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
|
||||
BIN
src/archive/zip/testdata/comment-truncated.zip
vendored
Normal file
BIN
src/archive/zip/testdata/comment-truncated.zip
vendored
Normal file
Binary file not shown.
21
src/bytes/bytes_js_wasm_test.go
Normal file
21
src/bytes/bytes_js_wasm_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build js && wasm
|
||||
|
||||
package bytes_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIssue65571(t *testing.T) {
|
||||
b := make([]byte, 1<<31+1)
|
||||
b[1<<31] = 1
|
||||
i := bytes.IndexByte(b, 1)
|
||||
if i != 1<<31 {
|
||||
t.Errorf("IndexByte(b, 1) = %d; want %d", i, 1<<31)
|
||||
}
|
||||
}
|
||||
4
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
4
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@@ -52,6 +52,9 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
// Hex constant 0xFFFFFFFE00000001
|
||||
MOVD $-8589934591, R5 // 38a0ffff or 0602000038a00001
|
||||
|
||||
// For #66955. Verify this opcode turns into a load and assembles.
|
||||
MOVD $-6795364578871345152, R5 // 3ca00000e8a50000 or 04100000e4a00000
|
||||
|
||||
MOVD 8(R3), R4 // e8830008
|
||||
MOVD (R3)(R4), R5 // 7ca4182a
|
||||
MOVD (R3)(R0), R5 // 7ca0182a
|
||||
@@ -90,6 +93,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
MOVHBR (R3)(R4), R5 // 7ca41e2c
|
||||
MOVHBR (R3)(R0), R5 // 7ca01e2c
|
||||
MOVHBR (R3), R5 // 7ca01e2c
|
||||
OR $0, R0, R0
|
||||
MOVD $foo+4009806848(FP), R5 // 3ca1ef0138a5cc40 or 0600ef0038a1cc40
|
||||
MOVD $foo(SB), R5 // 3ca0000038a50000 or 0610000038a00000
|
||||
|
||||
|
||||
@@ -44,11 +44,18 @@ func run(t *testing.T, dir string, lto bool, args ...string) {
|
||||
cmd := exec.Command("go", runArgs...)
|
||||
cmd.Dir = dir
|
||||
if lto {
|
||||
// On the builders we're using the default /usr/bin/ld, but
|
||||
// that has problems when asking for LTO in particular. Force
|
||||
// use of lld, which ships with our clang installation.
|
||||
extraLDFlags := ""
|
||||
if strings.Contains(testenv.Builder(), "clang") {
|
||||
extraLDFlags += " -fuse-ld=lld"
|
||||
}
|
||||
const cflags = "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option"
|
||||
cmd.Env = append(cmd.Environ(),
|
||||
"CGO_CFLAGS="+cflags,
|
||||
"CGO_CXXFLAGS="+cflags,
|
||||
"CGO_LDFLAGS="+cflags)
|
||||
"CGO_LDFLAGS="+cflags+extraLDFlags)
|
||||
}
|
||||
out, err := cmd.CombinedOutput()
|
||||
if string(out) != "OK\n" {
|
||||
|
||||
16
src/cmd/cgo/internal/test/seh_internal_windows_test.go
Normal file
16
src/cmd/cgo/internal/test/seh_internal_windows_test.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build cgo && windows && internal
|
||||
|
||||
package cgotest
|
||||
|
||||
import (
|
||||
"internal/testenv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCallbackCallersSEH(t *testing.T) {
|
||||
testenv.SkipFlaky(t, 65116)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build cgo && windows
|
||||
//go:build cgo && windows && !internal
|
||||
|
||||
package cgotest
|
||||
|
||||
@@ -74,6 +74,7 @@ func testMain(m *testing.M) int {
|
||||
}
|
||||
defer os.RemoveAll(GOPATH)
|
||||
tmpDir = GOPATH
|
||||
fmt.Printf("TMPDIR=%s\n", tmpDir)
|
||||
|
||||
modRoot := filepath.Join(GOPATH, "src", "testplugin")
|
||||
altRoot := filepath.Join(GOPATH, "alt", "src", "testplugin")
|
||||
@@ -395,3 +396,29 @@ func TestIssue62430(t *testing.T) {
|
||||
goCmd(t, "build", "-o", "issue62430.exe", "./issue62430/main.go")
|
||||
run(t, "./issue62430.exe")
|
||||
}
|
||||
|
||||
func TestTextSectionSplit(t *testing.T) {
|
||||
globalSkip(t)
|
||||
if runtime.GOOS != "darwin" || runtime.GOARCH != "arm64" {
|
||||
t.Skipf("text section splitting is not done in %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// Use -ldflags=-debugtextsize=262144 to let the linker split text section
|
||||
// at a smaller size threshold, so it actually splits for the test binary.
|
||||
goCmd(nil, "build", "-ldflags=-debugtextsize=262144", "-o", "host-split.exe", "./host")
|
||||
run(t, "./host-split.exe")
|
||||
|
||||
// Check that we did split text sections.
|
||||
syms := goCmd(nil, "tool", "nm", "host-split.exe")
|
||||
if !strings.Contains(syms, "runtime.text.1") {
|
||||
t.Errorf("runtime.text.1 not found, text section not split?")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue67976(t *testing.T) {
|
||||
// Issue 67976: build failure with loading a dynimport variable (the runtime/pprof
|
||||
// package does this on darwin) in a plugin on darwin/amd64.
|
||||
// The test program uses runtime/pprof in a plugin.
|
||||
globalSkip(t)
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "issue67976.so", "./issue67976/plugin.go")
|
||||
}
|
||||
|
||||
16
src/cmd/cgo/internal/testplugin/testdata/issue67976/plugin.go
vendored
Normal file
16
src/cmd/cgo/internal/testplugin/testdata/issue67976/plugin.go
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime/pprof"
|
||||
)
|
||||
|
||||
func main() {}
|
||||
|
||||
func Start() {
|
||||
pprof.StartCPUProfile(io.Discard)
|
||||
}
|
||||
@@ -16,8 +16,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -266,12 +268,28 @@ func compilerSupportsLocation() bool {
|
||||
case "gcc":
|
||||
return compiler.major >= 10
|
||||
case "clang":
|
||||
// TODO(65606): The clang toolchain on the LUCI builders is not built against
|
||||
// zlib, the ASAN runtime can't actually symbolize its own stack trace. Once
|
||||
// this is resolved, one way or another, switch this back to 'true'. We still
|
||||
// have coverage from the 'gcc' case above.
|
||||
if inLUCIBuild() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// inLUCIBuild returns true if we're currently executing in a LUCI build.
|
||||
func inLUCIBuild() bool {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return testenv.Builder() != "" && u.Username == "swarming"
|
||||
}
|
||||
|
||||
// compilerRequiredTsanVersion reports whether the compiler is the version required by Tsan.
|
||||
// Only restrictions for ppc64le are known; otherwise return true.
|
||||
func compilerRequiredTsanVersion(goos, goarch string) bool {
|
||||
|
||||
@@ -13,8 +13,13 @@ import (
|
||||
)
|
||||
|
||||
func TestLibFuzzer(t *testing.T) {
|
||||
// Skip tests in short mode.
|
||||
if testing.Short() {
|
||||
t.Skip("libfuzzer tests can take upwards of minutes to run; skipping in short mode")
|
||||
}
|
||||
testenv.MustHaveGoBuild(t)
|
||||
testenv.MustHaveCGO(t)
|
||||
|
||||
goos, err := goEnv("GOOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -148,7 +148,7 @@ func calculateCostForType(t *types.Type) int64 {
|
||||
return EqStructCost(t)
|
||||
case types.TSLICE:
|
||||
// Slices are not comparable.
|
||||
base.Fatalf("eqStructFieldCost: unexpected slice type")
|
||||
base.Fatalf("calculateCostForType: unexpected slice type")
|
||||
case types.TARRAY:
|
||||
elemCost := calculateCostForType(t.Elem())
|
||||
cost = t.NumElem() * elemCost
|
||||
@@ -371,6 +371,11 @@ func eqmem(p, q ir.Node, field int, size int64) ir.Node {
|
||||
}
|
||||
|
||||
func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
|
||||
if !base.Ctxt.Arch.CanMergeLoads && t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Size() {
|
||||
// We can't use larger comparisons if the value might not be aligned
|
||||
// enough for the larger comparison. See issues 46283 and 67160.
|
||||
size = 0
|
||||
}
|
||||
switch size {
|
||||
case 1, 2, 4, 8, 16:
|
||||
buf := fmt.Sprintf("memequal%d", int(size)*8)
|
||||
|
||||
@@ -34,7 +34,13 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
|
||||
posBaseMap := make(map[*syntax.PosBase]*syntax.File)
|
||||
for i, p := range noders {
|
||||
files[i] = p.file
|
||||
posBaseMap[p.file.Pos().Base()] = p.file
|
||||
// The file.Pos() is the position of the package clause.
|
||||
// If there's a //line directive before that, file.Pos().Base()
|
||||
// refers to that directive, not the file itself.
|
||||
// Make sure to consistently map back to file base, here and
|
||||
// when we look for a file in the conf.Error handler below,
|
||||
// otherwise the file may not be found (was go.dev/issue/67141).
|
||||
posBaseMap[fileBase(p.file.Pos())] = p.file
|
||||
}
|
||||
|
||||
// typechecking
|
||||
@@ -68,13 +74,12 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
|
||||
terr := err.(types2.Error)
|
||||
msg := terr.Msg
|
||||
if versionErrorRx.MatchString(msg) {
|
||||
posBase := terr.Pos.Base()
|
||||
for !posBase.IsFileBase() { // line directive base
|
||||
posBase = posBase.Pos().Base()
|
||||
}
|
||||
posBase := fileBase(terr.Pos)
|
||||
fileVersion := info.FileVersions[posBase]
|
||||
file := posBaseMap[posBase]
|
||||
if file.GoVersion == fileVersion {
|
||||
if file == nil {
|
||||
// This should never happen, but be careful and don't crash.
|
||||
} else if file.GoVersion == fileVersion {
|
||||
// If we have a version error caused by //go:build, report it.
|
||||
msg = fmt.Sprintf("%s (file declares //go:build %s)", msg, fileVersion)
|
||||
} else {
|
||||
@@ -149,6 +154,15 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
|
||||
return pkg, info
|
||||
}
|
||||
|
||||
// fileBase returns a file's position base given a position in the file.
|
||||
func fileBase(pos syntax.Pos) *syntax.PosBase {
|
||||
base := pos.Base()
|
||||
for !base.IsFileBase() { // line directive base
|
||||
base = base.Pos().Base()
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
// A cycleFinder detects anonymous interface cycles (go.dev/issue/56103).
|
||||
type cycleFinder struct {
|
||||
cyclic map[*types2.Interface]bool
|
||||
|
||||
@@ -663,9 +663,24 @@ func (pr *pkgReader) objInstIdx(info objInfo, dict *readerDict, shaped bool) ir.
|
||||
}
|
||||
|
||||
// objIdx returns the specified object, instantiated with the given
|
||||
// type arguments, if any. If shaped is true, then the shaped variant
|
||||
// of the object is returned instead.
|
||||
// type arguments, if any.
|
||||
// If shaped is true, then the shaped variant of the object is returned
|
||||
// instead.
|
||||
func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Type, shaped bool) ir.Node {
|
||||
n, err := pr.objIdxMayFail(idx, implicits, explicits, shaped)
|
||||
if err != nil {
|
||||
base.Fatalf("%v", err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// objIdxMayFail is equivalent to objIdx, but returns an error rather than
|
||||
// failing the build if this object requires type arguments and the incorrect
|
||||
// number of type arguments were passed.
|
||||
//
|
||||
// Other sources of internal failure (such as duplicate definitions) still fail
|
||||
// the build.
|
||||
func (pr *pkgReader) objIdxMayFail(idx pkgbits.Index, implicits, explicits []*types.Type, shaped bool) (ir.Node, error) {
|
||||
rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
||||
_, sym := rname.qualifiedIdent()
|
||||
tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
||||
@@ -674,22 +689,25 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Typ
|
||||
assert(!sym.IsBlank())
|
||||
switch sym.Pkg {
|
||||
case types.BuiltinPkg, types.UnsafePkg:
|
||||
return sym.Def.(ir.Node)
|
||||
return sym.Def.(ir.Node), nil
|
||||
}
|
||||
if pri, ok := objReader[sym]; ok {
|
||||
return pri.pr.objIdx(pri.idx, nil, explicits, shaped)
|
||||
return pri.pr.objIdxMayFail(pri.idx, nil, explicits, shaped)
|
||||
}
|
||||
if sym.Pkg.Path == "runtime" {
|
||||
return typecheck.LookupRuntime(sym.Name)
|
||||
return typecheck.LookupRuntime(sym.Name), nil
|
||||
}
|
||||
base.Fatalf("unresolved stub: %v", sym)
|
||||
}
|
||||
|
||||
dict := pr.objDictIdx(sym, idx, implicits, explicits, shaped)
|
||||
dict, err := pr.objDictIdx(sym, idx, implicits, explicits, shaped)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sym = dict.baseSym
|
||||
if !sym.IsBlank() && sym.Def != nil {
|
||||
return sym.Def.(*ir.Name)
|
||||
return sym.Def.(*ir.Name), nil
|
||||
}
|
||||
|
||||
r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1)
|
||||
@@ -725,7 +743,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Typ
|
||||
name := do(ir.OTYPE, false)
|
||||
setType(name, r.typ())
|
||||
name.SetAlias(true)
|
||||
return name
|
||||
return name, nil
|
||||
|
||||
case pkgbits.ObjConst:
|
||||
name := do(ir.OLITERAL, false)
|
||||
@@ -733,7 +751,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Typ
|
||||
val := FixValue(typ, r.Value())
|
||||
setType(name, typ)
|
||||
setValue(name, val)
|
||||
return name
|
||||
return name, nil
|
||||
|
||||
case pkgbits.ObjFunc:
|
||||
if sym.Name == "init" {
|
||||
@@ -768,7 +786,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Typ
|
||||
}
|
||||
|
||||
rext.funcExt(name, nil)
|
||||
return name
|
||||
return name, nil
|
||||
|
||||
case pkgbits.ObjType:
|
||||
name := do(ir.OTYPE, true)
|
||||
@@ -805,13 +823,13 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Typ
|
||||
r.needWrapper(typ)
|
||||
}
|
||||
|
||||
return name
|
||||
return name, nil
|
||||
|
||||
case pkgbits.ObjVar:
|
||||
name := do(ir.ONAME, false)
|
||||
setType(name, r.typ())
|
||||
rext.varExt(name)
|
||||
return name
|
||||
return name, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -908,7 +926,7 @@ func shapify(targ *types.Type, basic bool) *types.Type {
|
||||
}
|
||||
|
||||
// objDictIdx reads and returns the specified object dictionary.
|
||||
func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, explicits []*types.Type, shaped bool) *readerDict {
|
||||
func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, explicits []*types.Type, shaped bool) (*readerDict, error) {
|
||||
r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
||||
|
||||
dict := readerDict{
|
||||
@@ -919,7 +937,7 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, ex
|
||||
nexplicits := r.Len()
|
||||
|
||||
if nimplicits > len(implicits) || nexplicits != len(explicits) {
|
||||
base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits))
|
||||
return nil, fmt.Errorf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits))
|
||||
}
|
||||
|
||||
dict.targs = append(implicits[:nimplicits:nimplicits], explicits...)
|
||||
@@ -984,7 +1002,7 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, ex
|
||||
dict.itabs[i] = itabInfo{typ: r.typInfo(), iface: r.typInfo()}
|
||||
}
|
||||
|
||||
return &dict
|
||||
return &dict, nil
|
||||
}
|
||||
|
||||
func (r *reader) typeParamNames() {
|
||||
@@ -2529,7 +2547,10 @@ func (pr *pkgReader) objDictName(idx pkgbits.Index, implicits, explicits []*type
|
||||
base.Fatalf("unresolved stub: %v", sym)
|
||||
}
|
||||
|
||||
dict := pr.objDictIdx(sym, idx, implicits, explicits, false)
|
||||
dict, err := pr.objDictIdx(sym, idx, implicits, explicits, false)
|
||||
if err != nil {
|
||||
base.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
return pr.dictNameOf(dict)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,11 @@ func lookupFunction(pkg *types.Pkg, symName string) (*ir.Func, error) {
|
||||
return nil, fmt.Errorf("func sym %v missing objReader", sym)
|
||||
}
|
||||
|
||||
name := pri.pr.objIdx(pri.idx, nil, nil, false).(*ir.Name)
|
||||
node, err := pri.pr.objIdxMayFail(pri.idx, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("func sym %v lookup error: %w", sym, err)
|
||||
}
|
||||
name := node.(*ir.Name)
|
||||
if name.Op() != ir.ONAME || name.Class != ir.PFUNC {
|
||||
return nil, fmt.Errorf("func sym %v refers to non-function name: %v", sym, name)
|
||||
}
|
||||
@@ -105,13 +109,20 @@ func lookupMethod(pkg *types.Pkg, symName string) (*ir.Func, error) {
|
||||
return nil, fmt.Errorf("type sym %v missing objReader", typ)
|
||||
}
|
||||
|
||||
name := pri.pr.objIdx(pri.idx, nil, nil, false).(*ir.Name)
|
||||
node, err := pri.pr.objIdxMayFail(pri.idx, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("func sym %v lookup error: %w", typ, err)
|
||||
}
|
||||
name := node.(*ir.Name)
|
||||
if name.Op() != ir.OTYPE {
|
||||
return nil, fmt.Errorf("type sym %v refers to non-type name: %v", typ, name)
|
||||
}
|
||||
if name.Alias() {
|
||||
return nil, fmt.Errorf("type sym %v refers to alias", typ)
|
||||
}
|
||||
if name.Type().IsInterface() {
|
||||
return nil, fmt.Errorf("type sym %v refers to interface type", typ)
|
||||
}
|
||||
|
||||
for _, m := range name.Type().Methods() {
|
||||
if m.Sym == meth {
|
||||
|
||||
@@ -1209,10 +1209,17 @@ func (w *writer) stmt(stmt syntax.Stmt) {
|
||||
func (w *writer) stmts(stmts []syntax.Stmt) {
|
||||
dead := false
|
||||
w.Sync(pkgbits.SyncStmts)
|
||||
for _, stmt := range stmts {
|
||||
if dead {
|
||||
// Any statements after a terminating statement are safe to
|
||||
// omit, at least until the next labeled statement.
|
||||
var lastLabel = -1
|
||||
for i, stmt := range stmts {
|
||||
if _, ok := stmt.(*syntax.LabeledStmt); ok {
|
||||
lastLabel = i
|
||||
}
|
||||
}
|
||||
for i, stmt := range stmts {
|
||||
if dead && i > lastLabel {
|
||||
// Any statements after a terminating and last label statement are safe to omit.
|
||||
// Otherwise, code after label statement may refer to dead stmts between terminating
|
||||
// and label statement, see issue #65593.
|
||||
if _, ok := stmt.(*syntax.LabeledStmt); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1020,10 +1020,6 @@
|
||||
(MOVLQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
|
||||
(MOVLQZX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
|
||||
|
||||
(MOVLQZX x) && zeroUpper32Bits(x,3) => x
|
||||
(MOVWQZX x) && zeroUpper48Bits(x,3) => x
|
||||
(MOVBQZX x) && zeroUpper56Bits(x,3) => x
|
||||
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) => (MOVBQZX x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) => (MOVWQZX x)
|
||||
|
||||
@@ -6,3 +6,8 @@
|
||||
(SAR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SARX(Q|L) x y)
|
||||
(SHL(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHLX(Q|L) x y)
|
||||
(SHR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHRX(Q|L) x y)
|
||||
|
||||
// See comments in ARM64latelower.rules for why these are here.
|
||||
(MOVLQZX x) && zeroUpper32Bits(x,3) => x
|
||||
(MOVWQZX x) && zeroUpper48Bits(x,3) => x
|
||||
(MOVBQZX x) && zeroUpper56Bits(x,3) => x
|
||||
|
||||
@@ -1054,61 +1054,6 @@
|
||||
(MOVWUloadidx4 ptr idx (MOVWstorezeroidx4 ptr2 idx2 _)) && isSamePtr(ptr, ptr2) && isSamePtr(idx, idx2) => (MOVDconst [0])
|
||||
(MOVDloadidx8 ptr idx (MOVDstorezeroidx8 ptr2 idx2 _)) && isSamePtr(ptr, ptr2) && isSamePtr(idx, idx2) => (MOVDconst [0])
|
||||
|
||||
// don't extend after proper load
|
||||
(MOVBreg x:(MOVBload _ _)) => (MOVDreg x)
|
||||
(MOVBUreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBload _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHload _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHUload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWload _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUload _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUload _ _)) => (MOVDreg x)
|
||||
(MOVBreg x:(MOVBloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVBUreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHUloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWloadidx4 _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUloadidx4 _ _ _)) => (MOVDreg x)
|
||||
|
||||
// fold double extensions
|
||||
(MOVBreg x:(MOVBreg _)) => (MOVDreg x)
|
||||
(MOVBUreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBreg _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHreg _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWreg _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUreg _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUreg _)) => (MOVDreg x)
|
||||
|
||||
// don't extend before store
|
||||
(MOVBstore [off] {sym} ptr (MOVBreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
|
||||
(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
|
||||
@@ -1572,18 +1517,11 @@
|
||||
(LessThanNoov (InvertFlags x)) => (CSEL0 [OpARM64NotEqual] (GreaterEqualNoov <typ.Bool> x) x)
|
||||
(GreaterEqualNoov (InvertFlags x)) => (CSINC [OpARM64NotEqual] (LessThanNoov <typ.Bool> x) (MOVDconst [0]) x)
|
||||
|
||||
// Boolean-generating instructions (NOTE: NOT all boolean Values) always
|
||||
// zero upper bit of the register; no need to zero-extend
|
||||
(MOVBUreg x:((Equal|NotEqual|LessThan|LessThanU|LessThanF|LessEqual|LessEqualU|LessEqualF|GreaterThan|GreaterThanU|GreaterThanF|GreaterEqual|GreaterEqualU|GreaterEqualF) _)) => (MOVDreg x)
|
||||
|
||||
// Don't bother extending if we're not using the higher bits.
|
||||
(MOV(B|BU)reg x) && v.Type.Size() <= 1 => x
|
||||
(MOV(H|HU)reg x) && v.Type.Size() <= 2 => x
|
||||
(MOV(W|WU)reg x) && v.Type.Size() <= 4 => x
|
||||
|
||||
// omit unsign extension
|
||||
(MOVWUreg x) && zeroUpper32Bits(x, 3) => x
|
||||
|
||||
// omit sign extension
|
||||
(MOVWreg <t> (ANDconst x [c])) && uint64(c) & uint64(0xffffffff80000000) == 0 => (ANDconst <t> x [c])
|
||||
(MOVHreg <t> (ANDconst x [c])) && uint64(c) & uint64(0xffffffffffff8000) == 0 => (ANDconst <t> x [c])
|
||||
|
||||
@@ -19,3 +19,69 @@
|
||||
(CMNWconst [c] x) && !isARM64addcon(int64(c)) => (CMNW x (MOVDconst [int64(c)]))
|
||||
|
||||
(ADDSconstflags [c] x) && !isARM64addcon(c) => (ADDSflags x (MOVDconst [c]))
|
||||
|
||||
// These rules remove unneeded sign/zero extensions.
|
||||
// They occur in late lower because they rely on the fact
|
||||
// that their arguments don't get rewritten to a non-extended opcode instead.
|
||||
|
||||
// Boolean-generating instructions (NOTE: NOT all boolean Values) always
|
||||
// zero upper bit of the register; no need to zero-extend
|
||||
(MOVBUreg x:((Equal|NotEqual|LessThan|LessThanU|LessThanF|LessEqual|LessEqualU|LessEqualF|GreaterThan|GreaterThanU|GreaterThanF|GreaterEqual|GreaterEqualU|GreaterEqualF) _)) => x
|
||||
|
||||
// omit unsigned extension
|
||||
(MOVWUreg x) && zeroUpper32Bits(x, 3) => x
|
||||
|
||||
// don't extend after proper load
|
||||
(MOVBreg x:(MOVBload _ _)) => (MOVDreg x)
|
||||
(MOVBUreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBload _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHload _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHUload _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWload _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVBUload _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUload _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUload _ _)) => (MOVDreg x)
|
||||
(MOVBreg x:(MOVBloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVBUreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVBUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUloadidx _ _ _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHUloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWloadidx4 _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUloadidx2 _ _ _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUloadidx4 _ _ _)) => (MOVDreg x)
|
||||
|
||||
// fold double extensions
|
||||
(MOVBreg x:(MOVBreg _)) => (MOVDreg x)
|
||||
(MOVBUreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBreg _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVHreg x:(MOVHreg _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVHUreg x:(MOVHUreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVHreg _)) => (MOVDreg x)
|
||||
(MOVWreg x:(MOVWreg _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVBUreg _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVHUreg _)) => (MOVDreg x)
|
||||
(MOVWUreg x:(MOVWUreg _)) => (MOVDreg x)
|
||||
|
||||
@@ -11,6 +11,17 @@ func copyelim(f *Func) {
|
||||
// of OpCopy) is a copy.
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
|
||||
// This is an early place in SSA where all values are examined.
|
||||
// Rewrite all 0-sized Go values to remove accessors, dereferences, loads, etc.
|
||||
if t := v.Type; (t.IsStruct() || t.IsArray()) && t.Size() == 0 {
|
||||
if t.IsStruct() {
|
||||
v.reset(OpStructMake0)
|
||||
} else {
|
||||
v.reset(OpArrayMake0)
|
||||
}
|
||||
}
|
||||
|
||||
copyelimValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1279,6 +1279,11 @@ func areAdjacentOffsets(off1, off2, size int64) bool {
|
||||
// depth limits recursion depth. In AMD64.rules 3 is used as limit,
|
||||
// because it catches same amount of cases as 4.
|
||||
func zeroUpper32Bits(x *Value, depth int) bool {
|
||||
if x.Type.IsSigned() && x.Type.Size() < 8 {
|
||||
// If the value is signed, it might get re-sign-extended
|
||||
// during spill and restore. See issue 68227.
|
||||
return false
|
||||
}
|
||||
switch x.Op {
|
||||
case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1,
|
||||
OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1,
|
||||
@@ -1294,8 +1299,10 @@ func zeroUpper32Bits(x *Value, depth int) bool {
|
||||
OpARM64MULW, OpARM64MNEGW, OpARM64UDIVW, OpARM64DIVW, OpARM64UMODW,
|
||||
OpARM64MADDW, OpARM64MSUBW, OpARM64RORW, OpARM64RORWconst:
|
||||
return true
|
||||
case OpArg:
|
||||
return x.Type.Size() == 4
|
||||
case OpArg: // note: but not ArgIntReg
|
||||
// amd64 always loads args from the stack unsigned.
|
||||
// most other architectures load them sign/zero extended based on the type.
|
||||
return x.Type.Size() == 4 && x.Block.Func.Config.arch == "amd64"
|
||||
case OpPhi, OpSelect0, OpSelect1:
|
||||
// Phis can use each-other as an arguments, instead of tracking visited values,
|
||||
// just limit recursion depth.
|
||||
@@ -1315,11 +1322,14 @@ func zeroUpper32Bits(x *Value, depth int) bool {
|
||||
|
||||
// zeroUpper48Bits is similar to zeroUpper32Bits, but for upper 48 bits.
|
||||
func zeroUpper48Bits(x *Value, depth int) bool {
|
||||
if x.Type.IsSigned() && x.Type.Size() < 8 {
|
||||
return false
|
||||
}
|
||||
switch x.Op {
|
||||
case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2:
|
||||
return true
|
||||
case OpArg:
|
||||
return x.Type.Size() == 2
|
||||
case OpArg: // note: but not ArgIntReg
|
||||
return x.Type.Size() == 2 && x.Block.Func.Config.arch == "amd64"
|
||||
case OpPhi, OpSelect0, OpSelect1:
|
||||
// Phis can use each-other as an arguments, instead of tracking visited values,
|
||||
// just limit recursion depth.
|
||||
@@ -1339,11 +1349,14 @@ func zeroUpper48Bits(x *Value, depth int) bool {
|
||||
|
||||
// zeroUpper56Bits is similar to zeroUpper32Bits, but for upper 56 bits.
|
||||
func zeroUpper56Bits(x *Value, depth int) bool {
|
||||
if x.Type.IsSigned() && x.Type.Size() < 8 {
|
||||
return false
|
||||
}
|
||||
switch x.Op {
|
||||
case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1:
|
||||
return true
|
||||
case OpArg:
|
||||
return x.Type.Size() == 1
|
||||
case OpArg: // note: but not ArgIntReg
|
||||
return x.Type.Size() == 1 && x.Block.Func.Config.arch == "amd64"
|
||||
case OpPhi, OpSelect0, OpSelect1:
|
||||
// Phis can use each-other as an arguments, instead of tracking visited values,
|
||||
// just limit recursion depth.
|
||||
@@ -2131,8 +2144,8 @@ func logicFlags32(x int32) flagConstant {
|
||||
|
||||
func makeJumpTableSym(b *Block) *obj.LSym {
|
||||
s := base.Ctxt.Lookup(fmt.Sprintf("%s.jump%d", b.Func.fe.Func().LSym.Name, b.ID))
|
||||
s.Set(obj.AttrDuplicateOK, true)
|
||||
s.Set(obj.AttrLocal, true)
|
||||
// The jump table symbol is accessed only from the function symbol.
|
||||
s.Set(obj.AttrStatic, true)
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
@@ -9640,17 +9640,6 @@ func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value) bool {
|
||||
v0.AddArg2(ptr, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBQZX x)
|
||||
// cond: zeroUpper56Bits(x,3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper56Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBQZX (ANDLconst [c] x))
|
||||
// result: (ANDLconst [c & 0xff] x)
|
||||
for {
|
||||
@@ -10392,17 +10381,6 @@ func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value) bool {
|
||||
v0.AddArg2(ptr, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLQZX x)
|
||||
// cond: zeroUpper32Bits(x,3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper32Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLQZX (ANDLconst [c] x))
|
||||
// result: (ANDLconst [c] x)
|
||||
for {
|
||||
@@ -12756,17 +12734,6 @@ func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value) bool {
|
||||
v0.AddArg2(ptr, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWQZX x)
|
||||
// cond: zeroUpper48Bits(x,3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper48Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWQZX (ANDLconst [c] x))
|
||||
// result: (ANDLconst [c & 0xffff] x)
|
||||
for {
|
||||
|
||||
@@ -6,6 +6,12 @@ import "internal/buildcfg"
|
||||
|
||||
func rewriteValueAMD64latelower(v *Value) bool {
|
||||
switch v.Op {
|
||||
case OpAMD64MOVBQZX:
|
||||
return rewriteValueAMD64latelower_OpAMD64MOVBQZX(v)
|
||||
case OpAMD64MOVLQZX:
|
||||
return rewriteValueAMD64latelower_OpAMD64MOVLQZX(v)
|
||||
case OpAMD64MOVWQZX:
|
||||
return rewriteValueAMD64latelower_OpAMD64MOVWQZX(v)
|
||||
case OpAMD64SARL:
|
||||
return rewriteValueAMD64latelower_OpAMD64SARL(v)
|
||||
case OpAMD64SARQ:
|
||||
@@ -21,6 +27,51 @@ func rewriteValueAMD64latelower(v *Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64MOVBQZX(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBQZX x)
|
||||
// cond: zeroUpper56Bits(x,3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper56Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64MOVLQZX(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVLQZX x)
|
||||
// cond: zeroUpper32Bits(x,3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper32Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64MOVWQZX(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVWQZX x)
|
||||
// cond: zeroUpper48Bits(x,3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper48Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64latelower_OpAMD64SARL(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
|
||||
@@ -8307,39 +8307,6 @@ func rewriteValueARM64_OpARM64MOVBUloadidx(v *Value) bool {
|
||||
}
|
||||
func rewriteValueARM64_OpARM64MOVBUreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBUreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg (ANDconst [c] x))
|
||||
// result: (ANDconst [c&(1<<8-1)] x)
|
||||
for {
|
||||
@@ -8364,160 +8331,6 @@ func rewriteValueARM64_OpARM64MOVBUreg(v *Value) bool {
|
||||
v.AuxInt = int64ToAuxInt(int64(uint8(c)))
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(Equal _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64Equal {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(NotEqual _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64NotEqual {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessThan _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessThan {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessThanU _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessThanU {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessThanF _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessThanF {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessEqual _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessEqual {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessEqualU _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessEqualU {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessEqualF _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessEqualF {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterThan _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterThan {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterThanU _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterThanU {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterThanF _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterThanF {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterEqual _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterEqual {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterEqualU _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterEqualU {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterEqualF _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterEqualF {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x)
|
||||
// cond: v.Type.Size() <= 1
|
||||
// result: x
|
||||
@@ -8748,39 +8561,6 @@ func rewriteValueARM64_OpARM64MOVBloadidx(v *Value) bool {
|
||||
}
|
||||
func rewriteValueARM64_OpARM64MOVBreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBreg x:(MOVBload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg x:(MOVBloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg x:(MOVBreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg (MOVDconst [c]))
|
||||
// result: (MOVDconst [int64(int8(c))])
|
||||
for {
|
||||
@@ -10353,83 +10133,6 @@ func rewriteValueARM64_OpARM64MOVHUloadidx2(v *Value) bool {
|
||||
}
|
||||
func rewriteValueARM64_OpARM64MOVHUreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVHUreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg (ANDconst [c] x))
|
||||
// result: (ANDconst [c&(1<<16-1)] x)
|
||||
for {
|
||||
@@ -10790,116 +10493,6 @@ func rewriteValueARM64_OpARM64MOVHloadidx2(v *Value) bool {
|
||||
}
|
||||
func rewriteValueARM64_OpARM64MOVHreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVHreg x:(MOVBload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg (MOVDconst [c]))
|
||||
// result: (MOVDconst [int64(int16(c))])
|
||||
for {
|
||||
@@ -11955,127 +11548,6 @@ func rewriteValueARM64_OpARM64MOVWUloadidx4(v *Value) bool {
|
||||
}
|
||||
func rewriteValueARM64_OpARM64MOVWUreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVWUreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUloadidx4 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUloadidx4 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg (ANDconst [c] x))
|
||||
// result: (ANDconst [c&(1<<32-1)] x)
|
||||
for {
|
||||
@@ -12111,17 +11583,6 @@ func rewriteValueARM64_OpARM64MOVWUreg(v *Value) bool {
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x)
|
||||
// cond: zeroUpper32Bits(x, 3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper32Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg (SLLconst [lc] x))
|
||||
// cond: lc >= 32
|
||||
// result: (MOVDconst [0])
|
||||
@@ -12428,193 +11889,6 @@ func rewriteValueARM64_OpARM64MOVWloadidx4(v *Value) bool {
|
||||
}
|
||||
func rewriteValueARM64_OpARM64MOVWreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVWreg x:(MOVBload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHUloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWloadidx4 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWloadidx4 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg (MOVDconst [c]))
|
||||
// result: (MOVDconst [int64(int32(c))])
|
||||
for {
|
||||
|
||||
@@ -18,6 +18,18 @@ func rewriteValueARM64latelower(v *Value) bool {
|
||||
return rewriteValueARM64latelower_OpARM64CMPWconst(v)
|
||||
case OpARM64CMPconst:
|
||||
return rewriteValueARM64latelower_OpARM64CMPconst(v)
|
||||
case OpARM64MOVBUreg:
|
||||
return rewriteValueARM64latelower_OpARM64MOVBUreg(v)
|
||||
case OpARM64MOVBreg:
|
||||
return rewriteValueARM64latelower_OpARM64MOVBreg(v)
|
||||
case OpARM64MOVHUreg:
|
||||
return rewriteValueARM64latelower_OpARM64MOVHUreg(v)
|
||||
case OpARM64MOVHreg:
|
||||
return rewriteValueARM64latelower_OpARM64MOVHreg(v)
|
||||
case OpARM64MOVWUreg:
|
||||
return rewriteValueARM64latelower_OpARM64MOVWUreg(v)
|
||||
case OpARM64MOVWreg:
|
||||
return rewriteValueARM64latelower_OpARM64MOVWreg(v)
|
||||
case OpARM64ORconst:
|
||||
return rewriteValueARM64latelower_OpARM64ORconst(v)
|
||||
case OpARM64SUBconst:
|
||||
@@ -178,6 +190,742 @@ func rewriteValueARM64latelower_OpARM64CMPconst(v *Value) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64MOVBUreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBUreg x:(Equal _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64Equal {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(NotEqual _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64NotEqual {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessThan _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessThan {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessThanU _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessThanU {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessThanF _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessThanF {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessEqual _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessEqual {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessEqualU _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessEqualU {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(LessEqualF _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64LessEqualF {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterThan _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterThan {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterThanU _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterThanU {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterThanF _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterThanF {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterEqual _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterEqual {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterEqualU _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterEqualU {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(GreaterEqualF _))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64GreaterEqualF {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64MOVBreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBreg x:(MOVBload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg x:(MOVBloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg x:(MOVBreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64MOVHUreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVHUreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUreg x:(MOVHUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64MOVHreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVHreg x:(MOVBload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64MOVWUreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVWUreg x)
|
||||
// cond: zeroUpper32Bits(x, 3)
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if !(zeroUpper32Bits(x, 3)) {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUloadidx4 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUloadidx4 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVHUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUreg x:(MOVWUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64MOVWreg(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVWreg x:(MOVBload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHUload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWload _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWload {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHUloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWloadidx _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWloadidx {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHUloadidx2 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHUloadidx2 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWloadidx4 _ _ _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWloadidx4 {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBUreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVBUreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWreg _))
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v_0
|
||||
if x.Op != OpARM64MOVWreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM64latelower_OpARM64ORconst(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
|
||||
@@ -14,8 +14,13 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type devirtualization struct {
|
||||
pos string
|
||||
callee string
|
||||
}
|
||||
|
||||
// testPGODevirtualize tests that specific PGO devirtualize rewrites are performed.
|
||||
func testPGODevirtualize(t *testing.T, dir string) {
|
||||
func testPGODevirtualize(t *testing.T, dir string, want []devirtualization) {
|
||||
testenv.MustHaveGoRun(t)
|
||||
t.Parallel()
|
||||
|
||||
@@ -23,7 +28,7 @@ func testPGODevirtualize(t *testing.T, dir string) {
|
||||
|
||||
// Add a go.mod so we have a consistent symbol names in this temp dir.
|
||||
goMod := fmt.Sprintf(`module %s
|
||||
go 1.19
|
||||
go 1.21
|
||||
`, pkg)
|
||||
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte(goMod), 0644); err != nil {
|
||||
t.Fatalf("error writing go.mod: %v", err)
|
||||
@@ -60,51 +65,6 @@ go 1.19
|
||||
t.Fatalf("error starting go test: %v", err)
|
||||
}
|
||||
|
||||
type devirtualization struct {
|
||||
pos string
|
||||
callee string
|
||||
}
|
||||
|
||||
want := []devirtualization{
|
||||
// ExerciseIface
|
||||
{
|
||||
pos: "./devirt.go:101:20",
|
||||
callee: "mult.Mult.Multiply",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:101:39",
|
||||
callee: "Add.Add",
|
||||
},
|
||||
// ExerciseFuncConcrete
|
||||
{
|
||||
pos: "./devirt.go:173:36",
|
||||
callee: "AddFn",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:173:15",
|
||||
callee: "mult.MultFn",
|
||||
},
|
||||
// ExerciseFuncField
|
||||
{
|
||||
pos: "./devirt.go:207:35",
|
||||
callee: "AddFn",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:207:19",
|
||||
callee: "mult.MultFn",
|
||||
},
|
||||
// ExerciseFuncClosure
|
||||
// TODO(prattmic): Closure callees not implemented.
|
||||
//{
|
||||
// pos: "./devirt.go:249:27",
|
||||
// callee: "AddClosure.func1",
|
||||
//},
|
||||
//{
|
||||
// pos: "./devirt.go:249:15",
|
||||
// callee: "mult.MultClosure.func1",
|
||||
//},
|
||||
}
|
||||
|
||||
got := make(map[devirtualization]struct{})
|
||||
|
||||
devirtualizedLine := regexp.MustCompile(`(.*): PGO devirtualizing \w+ call .* to (.*)`)
|
||||
@@ -172,5 +132,130 @@ func TestPGODevirtualize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
testPGODevirtualize(t, dir)
|
||||
want := []devirtualization{
|
||||
// ExerciseIface
|
||||
{
|
||||
pos: "./devirt.go:101:20",
|
||||
callee: "mult.Mult.Multiply",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:101:39",
|
||||
callee: "Add.Add",
|
||||
},
|
||||
// ExerciseFuncConcrete
|
||||
{
|
||||
pos: "./devirt.go:173:36",
|
||||
callee: "AddFn",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:173:15",
|
||||
callee: "mult.MultFn",
|
||||
},
|
||||
// ExerciseFuncField
|
||||
{
|
||||
pos: "./devirt.go:207:35",
|
||||
callee: "AddFn",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:207:19",
|
||||
callee: "mult.MultFn",
|
||||
},
|
||||
// ExerciseFuncClosure
|
||||
// TODO(prattmic): Closure callees not implemented.
|
||||
//{
|
||||
// pos: "./devirt.go:249:27",
|
||||
// callee: "AddClosure.func1",
|
||||
//},
|
||||
//{
|
||||
// pos: "./devirt.go:249:15",
|
||||
// callee: "mult.MultClosure.func1",
|
||||
//},
|
||||
}
|
||||
|
||||
testPGODevirtualize(t, dir, want)
|
||||
}
|
||||
|
||||
// Regression test for https://go.dev/issue/65615. If a target function changes
|
||||
// from non-generic to generic we can't devirtualize it (don't know the type
|
||||
// parameters), but the compiler should not crash.
|
||||
func TestLookupFuncGeneric(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("error getting wd: %v", err)
|
||||
}
|
||||
srcDir := filepath.Join(wd, "testdata", "pgo", "devirtualize")
|
||||
|
||||
// Copy the module to a scratch location so we can add a go.mod.
|
||||
dir := t.TempDir()
|
||||
if err := os.Mkdir(filepath.Join(dir, "mult.pkg"), 0755); err != nil {
|
||||
t.Fatalf("error creating dir: %v", err)
|
||||
}
|
||||
for _, file := range []string{"devirt.go", "devirt_test.go", "devirt.pprof", filepath.Join("mult.pkg", "mult.go")} {
|
||||
if err := copyFile(filepath.Join(dir, file), filepath.Join(srcDir, file)); err != nil {
|
||||
t.Fatalf("error copying %s: %v", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Change MultFn from a concrete function to a parameterized function.
|
||||
if err := convertMultToGeneric(filepath.Join(dir, "mult.pkg", "mult.go")); err != nil {
|
||||
t.Fatalf("error editing mult.go: %v", err)
|
||||
}
|
||||
|
||||
// Same as TestPGODevirtualize except for MultFn, which we cannot
|
||||
// devirtualize to because it has become generic.
|
||||
//
|
||||
// Note that the important part of this test is that the build is
|
||||
// successful, not the specific devirtualizations.
|
||||
want := []devirtualization{
|
||||
// ExerciseIface
|
||||
{
|
||||
pos: "./devirt.go:101:20",
|
||||
callee: "mult.Mult.Multiply",
|
||||
},
|
||||
{
|
||||
pos: "./devirt.go:101:39",
|
||||
callee: "Add.Add",
|
||||
},
|
||||
// ExerciseFuncConcrete
|
||||
{
|
||||
pos: "./devirt.go:173:36",
|
||||
callee: "AddFn",
|
||||
},
|
||||
// ExerciseFuncField
|
||||
{
|
||||
pos: "./devirt.go:207:35",
|
||||
callee: "AddFn",
|
||||
},
|
||||
// ExerciseFuncClosure
|
||||
// TODO(prattmic): Closure callees not implemented.
|
||||
//{
|
||||
// pos: "./devirt.go:249:27",
|
||||
// callee: "AddClosure.func1",
|
||||
//},
|
||||
//{
|
||||
// pos: "./devirt.go:249:15",
|
||||
// callee: "mult.MultClosure.func1",
|
||||
//},
|
||||
}
|
||||
|
||||
testPGODevirtualize(t, dir, want)
|
||||
}
|
||||
|
||||
var multFnRe = regexp.MustCompile(`func MultFn\(a, b int64\) int64`)
|
||||
|
||||
func convertMultToGeneric(path string) error {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening: %w", err)
|
||||
}
|
||||
|
||||
if !multFnRe.Match(content) {
|
||||
return fmt.Errorf("MultFn not found; update regexp?")
|
||||
}
|
||||
|
||||
// Users of MultFn shouldn't need adjustment, type inference should
|
||||
// work OK.
|
||||
content = multFnRe.ReplaceAll(content, []byte(`func MultFn[T int32|int64](a, b T) T`))
|
||||
|
||||
return os.WriteFile(path, content, 0644)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func AllowsGoVersion(major, minor int) bool {
|
||||
}
|
||||
|
||||
// ParseLangFlag verifies that the -lang flag holds a valid value, and
|
||||
// exits if not. It initializes data used by langSupported.
|
||||
// exits if not. It initializes data used by AllowsGoVersion.
|
||||
func ParseLangFlag() {
|
||||
if base.Flag.Lang == "" {
|
||||
return
|
||||
@@ -59,6 +59,10 @@ func ParseLangFlag() {
|
||||
|
||||
// parseLang parses a -lang option into a langVer.
|
||||
func parseLang(s string) (lang, error) {
|
||||
if s == "go1" { // cmd/go's new spelling of "go1.0" (#65528)
|
||||
s = "go1.0"
|
||||
}
|
||||
|
||||
matches := goVersionRE.FindStringSubmatch(s)
|
||||
if matches == nil {
|
||||
return lang{}, fmt.Errorf(`should be something like "go1.12"`)
|
||||
|
||||
@@ -657,6 +657,9 @@ func NewPtr(elem *Type) *Type {
|
||||
if elem.HasShape() {
|
||||
t.SetHasShape(true)
|
||||
}
|
||||
if elem.Noalg() {
|
||||
t.SetNoalg(true)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,14 @@ type Alias struct {
|
||||
// NewAlias creates a new Alias type with the given type name and rhs.
|
||||
// rhs must not be nil.
|
||||
func NewAlias(obj *TypeName, rhs Type) *Alias {
|
||||
return (*Checker)(nil).newAlias(obj, rhs)
|
||||
alias := (*Checker)(nil).newAlias(obj, rhs)
|
||||
// Ensure that alias.actual is set (#65455).
|
||||
unalias(alias)
|
||||
return alias
|
||||
}
|
||||
|
||||
func (a *Alias) Obj() *TypeName { return a.obj }
|
||||
func (a *Alias) Underlying() Type { return a.actual.Underlying() }
|
||||
func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
|
||||
func (a *Alias) String() string { return TypeString(a, nil) }
|
||||
|
||||
// Type accessors
|
||||
@@ -36,24 +39,26 @@ func (a *Alias) String() string { return TypeString(a, nil) }
|
||||
// Consequently, the result is never an alias type.
|
||||
func Unalias(t Type) Type {
|
||||
if a0, _ := t.(*Alias); a0 != nil {
|
||||
if a0.actual != nil {
|
||||
return a0.actual
|
||||
}
|
||||
for a := a0; ; {
|
||||
t = a.fromRHS
|
||||
a, _ = t.(*Alias)
|
||||
if a == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if t == nil {
|
||||
panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
|
||||
}
|
||||
a0.actual = t
|
||||
return unalias(a0)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func unalias(a0 *Alias) Type {
|
||||
if a0.actual != nil {
|
||||
return a0.actual
|
||||
}
|
||||
var t Type
|
||||
for a := a0; a != nil; a, _ = t.(*Alias) {
|
||||
t = a.fromRHS
|
||||
}
|
||||
if t == nil {
|
||||
panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
|
||||
}
|
||||
a0.actual = t
|
||||
return t
|
||||
}
|
||||
|
||||
// asNamed returns t as *Named if that is t's
|
||||
// actual type. It returns nil otherwise.
|
||||
func asNamed(t Type) *Named {
|
||||
|
||||
@@ -2195,6 +2195,12 @@ func TestIssue61737(t *testing.T) {
|
||||
iface.NumMethods() // unlike go/types, there is no Complete() method, so we complete implicitly
|
||||
}
|
||||
|
||||
func TestNewAlias_Issue65455(t *testing.T) {
|
||||
obj := NewTypeName(nopos, nil, "A", nil)
|
||||
alias := NewAlias(obj, Typ[Int])
|
||||
alias.Underlying() // must not panic
|
||||
}
|
||||
|
||||
func TestIssue15305(t *testing.T) {
|
||||
const src = "package p; func f() int16; var _ = f(undef)"
|
||||
f := mustParse(src)
|
||||
|
||||
@@ -310,6 +310,14 @@ func (a nodeQueue) Swap(i, j int) {
|
||||
|
||||
func (a nodeQueue) Less(i, j int) bool {
|
||||
x, y := a[i], a[j]
|
||||
|
||||
// Prioritize all constants before non-constants. See go.dev/issue/66575/.
|
||||
_, xConst := x.obj.(*Const)
|
||||
_, yConst := y.obj.(*Const)
|
||||
if xConst != yConst {
|
||||
return xConst
|
||||
}
|
||||
|
||||
// nodes are prioritized by number of incoming dependencies (1st key)
|
||||
// and source order (2nd key)
|
||||
return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
|
||||
|
||||
@@ -1093,3 +1093,32 @@ func _() {
|
||||
conf := Config{GoVersion: "go1.17"}
|
||||
mustTypecheck(src, &conf, nil)
|
||||
}
|
||||
|
||||
func TestIssue68334(t *testing.T) {
|
||||
const src = `
|
||||
package p
|
||||
|
||||
func f(x int) {
|
||||
for i, j := range x {
|
||||
_, _ = i, j
|
||||
}
|
||||
var a, b int
|
||||
for a, b = range x {
|
||||
_, _ = a, b
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
got := ""
|
||||
conf := Config{
|
||||
GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
|
||||
Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
|
||||
}
|
||||
typecheck(src, &conf, nil) // do not crash
|
||||
|
||||
want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
|
||||
"p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
|
||||
if got != want {
|
||||
t.Errorf("got: %s want: %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,7 +902,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
lhs := [2]Expr{sKey, sValue} // sKey, sValue may be nil
|
||||
rhs := [2]Type{key, val} // key, val may be nil
|
||||
|
||||
constIntRange := x.mode == constant_ && isInteger(x.typ)
|
||||
rangeOverInt := isInteger(x.typ)
|
||||
|
||||
if isDef {
|
||||
// short variable declaration
|
||||
@@ -927,19 +927,28 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs)
|
||||
obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
|
||||
}
|
||||
assert(obj.typ == nil)
|
||||
|
||||
// initialize lhs variable
|
||||
if constIntRange {
|
||||
check.initVar(obj, &x, "range clause")
|
||||
} else if typ := rhs[i]; typ != nil {
|
||||
x.mode = value
|
||||
x.expr = lhs // we don't have a better rhs expression to use here
|
||||
x.typ = typ
|
||||
check.initVar(obj, &x, "assignment") // error is on variable, use "assignment" not "range clause"
|
||||
} else {
|
||||
// initialize lhs iteration variable, if any
|
||||
typ := rhs[i]
|
||||
if typ == nil || typ == Typ[Invalid] {
|
||||
// typ == Typ[Invalid] can happen if allowVersion fails.
|
||||
obj.typ = Typ[Invalid]
|
||||
obj.used = true // don't complain about unused variable
|
||||
continue
|
||||
}
|
||||
|
||||
if rangeOverInt {
|
||||
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
|
||||
check.initVar(obj, &x, "range clause")
|
||||
} else {
|
||||
var y operand
|
||||
y.mode = value
|
||||
y.expr = lhs // we don't have a better rhs expression to use here
|
||||
y.typ = typ
|
||||
check.initVar(obj, &y, "assignment") // error is on variable, use "assignment" not "range clause"
|
||||
}
|
||||
assert(obj.typ != nil)
|
||||
}
|
||||
|
||||
// declare variables
|
||||
@@ -958,21 +967,36 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
continue
|
||||
}
|
||||
|
||||
if constIntRange {
|
||||
// assign to lhs iteration variable, if any
|
||||
typ := rhs[i]
|
||||
if typ == nil || typ == Typ[Invalid] {
|
||||
continue
|
||||
}
|
||||
|
||||
if rangeOverInt {
|
||||
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
|
||||
check.assignVar(lhs, nil, &x, "range clause")
|
||||
} else if typ := rhs[i]; typ != nil {
|
||||
x.mode = value
|
||||
x.expr = lhs // we don't have a better rhs expression to use here
|
||||
x.typ = typ
|
||||
check.assignVar(lhs, nil, &x, "assignment") // error is on variable, use "assignment" not "range clause"
|
||||
// If the assignment succeeded, if x was untyped before, it now
|
||||
// has a type inferred via the assignment. It must be an integer.
|
||||
// (go.dev/issues/67027)
|
||||
if x.mode != invalid && !isInteger(x.typ) {
|
||||
check.softErrorf(lhs, InvalidRangeExpr, "cannot use iteration variable of type %s", x.typ)
|
||||
}
|
||||
} else {
|
||||
var y operand
|
||||
y.mode = value
|
||||
y.expr = lhs // we don't have a better rhs expression to use here
|
||||
y.typ = typ
|
||||
check.assignVar(lhs, nil, &y, "assignment") // error is on variable, use "assignment" not "range clause"
|
||||
}
|
||||
}
|
||||
} else if constIntRange {
|
||||
} else if rangeOverInt {
|
||||
// If we don't have any iteration variables, we still need to
|
||||
// check that a (possibly untyped) integer range expression x
|
||||
// is valid.
|
||||
// We do this by checking the assignment _ = x. This ensures
|
||||
// that an untyped x can be converted to a value of type int.
|
||||
// that an untyped x can be converted to a value of its default
|
||||
// type (rune or int).
|
||||
check.assignment(&x, nil, "range clause")
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,18 @@ func (subst *subster) typ(typ Type) Type {
|
||||
case *Basic:
|
||||
// nothing to do
|
||||
|
||||
case *Alias:
|
||||
rhs := subst.typ(t.fromRHS)
|
||||
if rhs != t.fromRHS {
|
||||
// This branch cannot be reached because the RHS of an alias
|
||||
// may only contain type parameters of an enclosing function.
|
||||
// Such function bodies are never "instantiated" and thus
|
||||
// substitution is not called on locally declared alias types.
|
||||
// TODO(gri) adjust once parameterized aliases are supported
|
||||
panic("unreachable for unparameterized aliases")
|
||||
// return subst.check.newAlias(t.obj, rhs)
|
||||
}
|
||||
|
||||
case *Array:
|
||||
elem := subst.typOrNil(t.elem)
|
||||
if elem != t.elem {
|
||||
|
||||
@@ -623,21 +623,23 @@ func isAppendOfMake(n ir.Node) bool {
|
||||
// panicmakeslicelen()
|
||||
// }
|
||||
// s := l1
|
||||
// n := len(s) + l2
|
||||
// // Compare n and s as uint so growslice can panic on overflow of len(s) + l2.
|
||||
// // cap is a positive int and n can become negative when len(s) + l2
|
||||
// // overflows int. Interpreting n when negative as uint makes it larger
|
||||
// // than cap(s). growslice will check the int n arg and panic if n is
|
||||
// // negative. This prevents the overflow from being undetected.
|
||||
// if uint(n) <= uint(cap(s)) {
|
||||
// s = s[:n]
|
||||
// } else {
|
||||
// s = growslice(T, s.ptr, n, s.cap, l2, T)
|
||||
// if l2 != 0 {
|
||||
// n := len(s) + l2
|
||||
// // Compare n and s as uint so growslice can panic on overflow of len(s) + l2.
|
||||
// // cap is a positive int and n can become negative when len(s) + l2
|
||||
// // overflows int. Interpreting n when negative as uint makes it larger
|
||||
// // than cap(s). growslice will check the int n arg and panic if n is
|
||||
// // negative. This prevents the overflow from being undetected.
|
||||
// if uint(n) <= uint(cap(s)) {
|
||||
// s = s[:n]
|
||||
// } else {
|
||||
// s = growslice(T, s.ptr, n, s.cap, l2, T)
|
||||
// }
|
||||
// // clear the new portion of the underlying array.
|
||||
// hp := &s[len(s)-l2]
|
||||
// hn := l2 * sizeof(T)
|
||||
// memclr(hp, hn)
|
||||
// }
|
||||
// // clear the new portion of the underlying array.
|
||||
// hp := &s[len(s)-l2]
|
||||
// hn := l2 * sizeof(T)
|
||||
// memclr(hp, hn)
|
||||
// }
|
||||
// s
|
||||
//
|
||||
@@ -671,11 +673,18 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
s := typecheck.TempAt(base.Pos, ir.CurFunc, l1.Type())
|
||||
nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, l1))
|
||||
|
||||
// if l2 != 0 {
|
||||
// Avoid work if we're not appending anything. But more importantly,
|
||||
// avoid allowing hp to be a past-the-end pointer when clearing. See issue 67255.
|
||||
nifnz := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.ONE, l2, ir.NewInt(base.Pos, 0)), nil, nil)
|
||||
nifnz.Likely = true
|
||||
nodes = append(nodes, nifnz)
|
||||
|
||||
elemtype := s.Type().Elem()
|
||||
|
||||
// n := s.len + l2
|
||||
nn := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
|
||||
nodes = append(nodes, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
|
||||
nifnz.Body = append(nifnz.Body, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
|
||||
|
||||
// if uint(n) <= uint(s.cap)
|
||||
nuint := typecheck.Conv(nn, types.Types[types.TUINT])
|
||||
@@ -697,7 +706,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
l2)),
|
||||
}
|
||||
|
||||
nodes = append(nodes, nif)
|
||||
nifnz.Body = append(nifnz.Body, nif)
|
||||
|
||||
// hp := &s[s.len - l2]
|
||||
// TODO: &s[s.len] - hn?
|
||||
@@ -723,7 +732,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
// if growslice isn't called do we need to do the zeroing ourselves.
|
||||
nif.Body = append(nif.Body, clr...)
|
||||
} else {
|
||||
nodes = append(nodes, clr...)
|
||||
nifnz.Body = append(nifnz.Body, clr...)
|
||||
}
|
||||
|
||||
typecheck.Stmts(nodes)
|
||||
|
||||
@@ -643,7 +643,12 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
indexLHS.Index = o.cheapExpr(indexLHS.Index)
|
||||
|
||||
call := n.Y.(*ir.CallExpr)
|
||||
indexRHS := call.Args[0].(*ir.IndexExpr)
|
||||
arg0 := call.Args[0]
|
||||
// ir.SameSafeExpr skips OCONVNOPs, so we must do the same here (#66096).
|
||||
for arg0.Op() == ir.OCONVNOP {
|
||||
arg0 = arg0.(*ir.ConvExpr).X
|
||||
}
|
||||
indexRHS := arg0.(*ir.IndexExpr)
|
||||
indexRHS.X = indexLHS.X
|
||||
indexRHS.Index = indexLHS.Index
|
||||
|
||||
|
||||
@@ -181,6 +181,8 @@ func init() {
|
||||
}
|
||||
|
||||
func runGenerate(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
if generateRunFlag != "" {
|
||||
var err error
|
||||
generateRunRE, err = regexp.Compile(generateRunFlag)
|
||||
|
||||
@@ -723,6 +723,9 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
b.IsCmdList = true
|
||||
b.NeedExport = *listExport
|
||||
b.NeedCompiledGoFiles = *listCompiled
|
||||
if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
|
||||
load.PrepareForCoverageBuild(pkgs)
|
||||
}
|
||||
a := &work.Action{}
|
||||
// TODO: Use pkgsFilter?
|
||||
for _, p := range pkgs {
|
||||
@@ -730,9 +733,6 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
||||
}
|
||||
}
|
||||
if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
|
||||
load.PrepareForCoverageBuild(pkgs)
|
||||
}
|
||||
b.Do(ctx, a)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if err != nil {
|
||||
base.Fatal(err)
|
||||
}
|
||||
mods := mg.BuildList()[modload.MainModules.Len():]
|
||||
mods := mg.BuildList()
|
||||
// Use a slice of result channels, so that the output is deterministic.
|
||||
errsChans := make([]<-chan []error, len(mods))
|
||||
|
||||
@@ -94,6 +94,9 @@ func verifyMod(ctx context.Context, mod module.Version) []error {
|
||||
// "go" and "toolchain" have no disk footprint; nothing to verify.
|
||||
return nil
|
||||
}
|
||||
if modload.MainModules.Contains(mod.Path) {
|
||||
return nil
|
||||
}
|
||||
var errs []error
|
||||
zip, zipErr := modfetch.CachePath(ctx, mod, "zip")
|
||||
if zipErr == nil {
|
||||
|
||||
@@ -554,7 +554,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro
|
||||
// an apparent Git bug introduced in Git 2.21 (commit 61c771),
|
||||
// which causes the handler for protocol version 1 to sometimes miss
|
||||
// tags that point to the requested commit (see https://go.dev/issue/56881).
|
||||
_, err = Run(ctx, r.dir, "git", "fetch", "-f", "-c", "protocol.version=2", "--depth=1", r.remote, refspec)
|
||||
_, err = Run(ctx, r.dir, "git", "-c", "protocol.version=2", "fetch", "-f", "--depth=1", r.remote, refspec)
|
||||
release()
|
||||
|
||||
if err == nil {
|
||||
|
||||
@@ -190,7 +190,7 @@ func CheckRetractions(ctx context.Context, m module.Version) (err error) {
|
||||
return err
|
||||
}
|
||||
summary, err := rawGoModSummary(rm)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, gover.ErrTooNew) {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string
|
||||
return "", err
|
||||
}
|
||||
summary, err := rawGoModSummary(latest)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, gover.ErrTooNew) {
|
||||
return "", err
|
||||
}
|
||||
return summary.deprecated, nil
|
||||
@@ -644,6 +644,8 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
// its dependencies.
|
||||
//
|
||||
// rawGoModSummary cannot be used on the main module outside of workspace mode.
|
||||
// The modFileSummary can still be used for retractions and deprecations
|
||||
// even if a TooNewError is returned.
|
||||
func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
||||
if gover.IsToolchain(m.Path) {
|
||||
if m.Path == "go" && gover.Compare(m.Version, gover.GoStrictVersion) >= 0 {
|
||||
@@ -698,12 +700,7 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
||||
summary.require = append(summary.require, req.Mod)
|
||||
}
|
||||
}
|
||||
if summary.goVersion != "" && gover.Compare(summary.goVersion, gover.GoStrictVersion) >= 0 {
|
||||
if gover.Compare(summary.goVersion, gover.Local()) > 0 {
|
||||
return nil, &gover.TooNewError{What: "module " + m.String(), GoVersion: summary.goVersion}
|
||||
}
|
||||
summary.require = append(summary.require, module.Version{Path: "go", Version: summary.goVersion})
|
||||
}
|
||||
|
||||
if len(f.Retract) > 0 {
|
||||
summary.retract = make([]retraction, 0, len(f.Retract))
|
||||
for _, ret := range f.Retract {
|
||||
@@ -714,6 +711,16 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// This block must be kept at the end of the function because the summary may
|
||||
// be used for reading retractions or deprecations even if a TooNewError is
|
||||
// returned.
|
||||
if summary.goVersion != "" && gover.Compare(summary.goVersion, gover.GoStrictVersion) >= 0 {
|
||||
summary.require = append(summary.require, module.Version{Path: "go", Version: summary.goVersion})
|
||||
if gover.Compare(summary.goVersion, gover.Local()) > 0 {
|
||||
return summary, &gover.TooNewError{What: "module " + m.String(), GoVersion: summary.goVersion}
|
||||
}
|
||||
}
|
||||
|
||||
return summary, nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1396,7 +1396,7 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action)
|
||||
|
||||
if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||
reportNoTestFiles := true
|
||||
if cfg.BuildCover && cfg.Experiment.CoverageRedesign {
|
||||
if cfg.BuildCover && cfg.Experiment.CoverageRedesign && p.Internal.Cover.GenMeta {
|
||||
if err := sh.Mkdir(a.Objdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package toolchain
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/fs"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/run"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
@@ -182,6 +184,13 @@ func Select() {
|
||||
}
|
||||
if gover.Compare(goVers, minVers) > 0 {
|
||||
gotoolchain = "go" + goVers
|
||||
// Starting with Go 1.21, the first released version has a .0 patch version suffix.
|
||||
// Don't try to download a language version (sans patch component), such as go1.22.
|
||||
// Instead, use the first toolchain of that language version, such as 1.22.0.
|
||||
// See golang.org/issue/62278.
|
||||
if gover.IsLang(goVers) && gover.Compare(goVers, "1.21") >= 0 {
|
||||
gotoolchain += ".0"
|
||||
}
|
||||
gover.Startup.AutoGoVersion = goVers
|
||||
gover.Startup.AutoToolchain = "" // in case we are overriding it for being too old
|
||||
}
|
||||
@@ -310,6 +319,10 @@ func Exec(gotoolchain string) {
|
||||
dir, err := modfetch.Download(context.Background(), m)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
toolVers := gover.FromToolchain(gotoolchain)
|
||||
if gover.IsLang(toolVers) && gover.Compare(toolVers, "1.21") >= 0 {
|
||||
base.Fatalf("invalid toolchain: %s is a language version but not a toolchain version (%s.x)", gotoolchain, gotoolchain)
|
||||
}
|
||||
base.Fatalf("download %s for %s/%s: toolchain not available", gotoolchain, runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
base.Fatalf("download %s: %v", gotoolchain, err)
|
||||
@@ -486,74 +499,132 @@ func goInstallVersion() bool {
|
||||
// Note: We assume there are no flags between 'go' and 'install' or 'run'.
|
||||
// During testing there are some debugging flags that are accepted
|
||||
// in that position, but in production go binaries there are not.
|
||||
if len(os.Args) < 3 || (os.Args[1] != "install" && os.Args[1] != "run") {
|
||||
if len(os.Args) < 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for pkg@version.
|
||||
var arg string
|
||||
var cmdFlags *flag.FlagSet
|
||||
switch os.Args[1] {
|
||||
default:
|
||||
// Command doesn't support a pkg@version as the main module.
|
||||
return false
|
||||
case "install":
|
||||
// We would like to let 'go install -newflag pkg@version' work even
|
||||
// across a toolchain switch. To make that work, assume the pkg@version
|
||||
// is the last argument and skip the flag parsing.
|
||||
arg = os.Args[len(os.Args)-1]
|
||||
cmdFlags = &work.CmdInstall.Flag
|
||||
case "run":
|
||||
// For run, the pkg@version can be anywhere on the command line,
|
||||
// because it is preceded by run flags and followed by arguments to the
|
||||
// program being run. To handle that precisely, we have to interpret the
|
||||
// flags a little bit, to know whether each flag takes an optional argument.
|
||||
// We can still allow unknown flags as long as they have an explicit =value.
|
||||
args := os.Args[2:]
|
||||
for i := 0; i < len(args); i++ {
|
||||
a := args[i]
|
||||
if !strings.HasPrefix(a, "-") {
|
||||
arg = a
|
||||
break
|
||||
}
|
||||
if a == "-" {
|
||||
// non-flag but also non-pkg@version
|
||||
cmdFlags = &run.CmdRun.Flag
|
||||
}
|
||||
|
||||
// The modcachrw flag is unique, in that it affects how we fetch the
|
||||
// requested module to even figure out what toolchain it needs.
|
||||
// We need to actually set it before we check the toolchain version.
|
||||
// (See https://go.dev/issue/64282.)
|
||||
modcacherwFlag := cmdFlags.Lookup("modcacherw")
|
||||
if modcacherwFlag == nil {
|
||||
base.Fatalf("internal error: modcacherw flag not registered for command")
|
||||
}
|
||||
modcacherwVal, ok := modcacherwFlag.Value.(interface {
|
||||
IsBoolFlag() bool
|
||||
flag.Value
|
||||
})
|
||||
if !ok || !modcacherwVal.IsBoolFlag() {
|
||||
base.Fatalf("internal error: modcacherw is not a boolean flag")
|
||||
}
|
||||
|
||||
// Make a best effort to parse the command's args to find the pkg@version
|
||||
// argument and the -modcacherw flag.
|
||||
var (
|
||||
pkgArg string
|
||||
modcacherwSeen bool
|
||||
)
|
||||
for args := os.Args[2:]; len(args) > 0; {
|
||||
a := args[0]
|
||||
args = args[1:]
|
||||
if a == "--" {
|
||||
if len(args) == 0 {
|
||||
return false
|
||||
}
|
||||
if a == "--" {
|
||||
if i+1 >= len(args) {
|
||||
return false
|
||||
pkgArg = args[0]
|
||||
break
|
||||
}
|
||||
|
||||
a, ok := strings.CutPrefix(a, "-")
|
||||
if !ok {
|
||||
// Not a flag argument. Must be a package.
|
||||
pkgArg = a
|
||||
break
|
||||
}
|
||||
a = strings.TrimPrefix(a, "-") // Treat --flag as -flag.
|
||||
|
||||
name, val, hasEq := strings.Cut(a, "=")
|
||||
|
||||
if name == "modcacherw" {
|
||||
if !hasEq {
|
||||
val = "true"
|
||||
}
|
||||
if err := modcacherwVal.Set(val); err != nil {
|
||||
return false
|
||||
}
|
||||
modcacherwSeen = true
|
||||
continue
|
||||
}
|
||||
|
||||
if hasEq {
|
||||
// Already has a value; don't bother parsing it.
|
||||
continue
|
||||
}
|
||||
|
||||
f := run.CmdRun.Flag.Lookup(a)
|
||||
if f == nil {
|
||||
// We don't know whether this flag is a boolean.
|
||||
if os.Args[1] == "run" {
|
||||
// We don't know where to find the pkg@version argument.
|
||||
// For run, the pkg@version can be anywhere on the command line,
|
||||
// because it is preceded by run flags and followed by arguments to the
|
||||
// program being run. Since we don't know whether this flag takes
|
||||
// an argument, we can't reliably identify the end of the run flags.
|
||||
// Just give up and let the user clarify using the "=" form..
|
||||
return false
|
||||
}
|
||||
|
||||
// We would like to let 'go install -newflag pkg@version' work even
|
||||
// across a toolchain switch. To make that work, assume by default that
|
||||
// the pkg@version is the last argument and skip the remaining args unless
|
||||
// we spot a plausible "-modcacherw" flag.
|
||||
for len(args) > 0 {
|
||||
a := args[0]
|
||||
name, _, _ := strings.Cut(a, "=")
|
||||
if name == "-modcacherw" || name == "--modcacherw" {
|
||||
break
|
||||
}
|
||||
arg = args[i+1]
|
||||
break
|
||||
if len(args) == 1 && !strings.HasPrefix(a, "-") {
|
||||
pkgArg = a
|
||||
}
|
||||
args = args[1:]
|
||||
}
|
||||
a = strings.TrimPrefix(a, "-")
|
||||
a = strings.TrimPrefix(a, "-")
|
||||
if strings.HasPrefix(a, "-") {
|
||||
// non-flag but also non-pkg@version
|
||||
return false
|
||||
}
|
||||
if strings.Contains(a, "=") {
|
||||
// already has value
|
||||
continue
|
||||
}
|
||||
f := run.CmdRun.Flag.Lookup(a)
|
||||
if f == nil {
|
||||
// Unknown flag. Give up. The command is going to fail in flag parsing.
|
||||
return false
|
||||
}
|
||||
if bf, ok := f.Value.(interface{ IsBoolFlag() bool }); ok && bf.IsBoolFlag() {
|
||||
// Does not take value.
|
||||
continue
|
||||
}
|
||||
i++ // Does take a value; skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
if bf, ok := f.Value.(interface{ IsBoolFlag() bool }); !ok || !bf.IsBoolFlag() {
|
||||
// The next arg is the value for this flag. Skip it.
|
||||
args = args[1:]
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !strings.Contains(arg, "@") || build.IsLocalImport(arg) || filepath.IsAbs(arg) {
|
||||
|
||||
if !strings.Contains(pkgArg, "@") || build.IsLocalImport(pkgArg) || filepath.IsAbs(pkgArg) {
|
||||
return false
|
||||
}
|
||||
path, version, _ := strings.Cut(arg, "@")
|
||||
path, version, _ := strings.Cut(pkgArg, "@")
|
||||
if path == "" || version == "" || gover.IsToolchain(path) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !modcacherwSeen && base.InGOFLAGS("-modcacherw") {
|
||||
fs := flag.NewFlagSet("goInstallVersion", flag.ExitOnError)
|
||||
fs.Var(modcacherwVal, "modcacherw", modcacherwFlag.Usage)
|
||||
base.SetFromGOFLAGS(fs)
|
||||
}
|
||||
|
||||
// It would be correct to simply return true here, bypassing use
|
||||
// of the current go.mod or go.work, and let "go run" or "go install"
|
||||
// do the rest, including a toolchain switch.
|
||||
|
||||
@@ -145,6 +145,12 @@ var validCompilerFlagsWithNextArg = []string{
|
||||
"-x",
|
||||
}
|
||||
|
||||
var invalidLinkerFlags = []*lazyregexp.Regexp{
|
||||
// On macOS this means the linker loads and executes the next argument.
|
||||
// Have to exclude separately because -lfoo is allowed in general.
|
||||
re(`-lto_library`),
|
||||
}
|
||||
|
||||
var validLinkerFlags = []*lazyregexp.Regexp{
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-l([^@\-].*)`),
|
||||
@@ -235,12 +241,12 @@ var validLinkerFlagsWithNextArg = []string{
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides)
|
||||
return checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
checkOverrides := true
|
||||
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||
}
|
||||
|
||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||
@@ -249,7 +255,7 @@ func checkLinkerFlags(name, source string, list []string) error {
|
||||
// external linker).
|
||||
func checkCompilerFlagsForInternalLink(name, source string, list []string) error {
|
||||
checkOverrides := false
|
||||
if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
|
||||
if err := checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
|
||||
return err
|
||||
}
|
||||
// Currently the only flag on the allow list that causes problems
|
||||
@@ -262,7 +268,7 @@ func checkCompilerFlagsForInternalLink(name, source string, list []string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error {
|
||||
func checkFlags(name, source string, list []string, invalid, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error {
|
||||
// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
|
||||
var (
|
||||
allow *regexp.Regexp
|
||||
@@ -294,6 +300,11 @@ Args:
|
||||
if allow != nil && allow.FindString(arg) == arg {
|
||||
continue Args
|
||||
}
|
||||
for _, re := range invalid {
|
||||
if re.FindString(arg) == arg { // must be complete match
|
||||
goto Bad
|
||||
}
|
||||
}
|
||||
for _, re := range valid {
|
||||
if re.FindString(arg) == arg { // must be complete match
|
||||
continue Args
|
||||
|
||||
10
src/cmd/go/testdata/mod/example.com_retract_newergoversion_v1.0.0.txt
vendored
Normal file
10
src/cmd/go/testdata/mod/example.com_retract_newergoversion_v1.0.0.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-- .mod --
|
||||
module example.com/retract/newergoversion
|
||||
|
||||
go 1.21
|
||||
|
||||
-- .info --
|
||||
{"Version":"v1.0.0"}
|
||||
|
||||
-- retract.go --
|
||||
package newergoversion
|
||||
12
src/cmd/go/testdata/mod/example.com_retract_newergoversion_v1.2.0.txt
vendored
Normal file
12
src/cmd/go/testdata/mod/example.com_retract_newergoversion_v1.2.0.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
-- .mod --
|
||||
module example.com/retract/newergoversion
|
||||
|
||||
go 1.23
|
||||
|
||||
retract v1.2.0
|
||||
|
||||
-- .info --
|
||||
{"Version":"v1.2.0"}
|
||||
|
||||
-- retract.go --
|
||||
package newergoversion
|
||||
@@ -4,6 +4,13 @@
|
||||
[short] skip
|
||||
[!cgo] skip
|
||||
|
||||
# This test has problems when run on the LUCI darwin longtest builder,
|
||||
# which uses a more contemporary Xcode version that is unfriendly to
|
||||
# reproducible builds (see issue #64947 for the gory details). Note
|
||||
# that individual developers running "go test cmd/go" on Darwin may
|
||||
# still run into failures depending on their Xcode version.
|
||||
[GOOS:darwin] [go-builder] skip
|
||||
|
||||
# This test is sensitive to cache invalidation,
|
||||
# so use a separate build cache that we can control.
|
||||
env GOCACHE=$WORK/gocache
|
||||
|
||||
9
src/cmd/go/testdata/script/build_issue_65528.txt
vendored
Normal file
9
src/cmd/go/testdata/script/build_issue_65528.txt
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
go build
|
||||
|
||||
-- go.mod --
|
||||
module test
|
||||
|
||||
go 1.0
|
||||
|
||||
-- p.go --
|
||||
package p
|
||||
@@ -1,6 +1,13 @@
|
||||
[!buildmode:plugin] skip
|
||||
[short] skip
|
||||
|
||||
# This test has problems when run on the LUCI darwin longtest builder,
|
||||
# which uses a more contemporary Xcode version that is unfriendly to
|
||||
# reproducible builds (see issue #64947 for the gory details). Note
|
||||
# that individual developers running "go test cmd/go" on Darwin may
|
||||
# still run into failures depending on their Xcode version.
|
||||
[GOOS:darwin] [go-builder] skip
|
||||
|
||||
go build -trimpath -buildvcs=false -buildmode=plugin -o a.so main.go
|
||||
go build -trimpath -buildvcs=false -buildmode=plugin -o b.so main.go
|
||||
cmp -q a.so b.so
|
||||
|
||||
@@ -39,6 +39,14 @@ go test -coverprofile=baz.p -coverpkg=./a,./d,./f ./b ./f
|
||||
stdout '^ok\s+M/b\s+\S+\s+coverage: 83.3% of statements in ./a, ./d, ./f'
|
||||
stdout '^\s*M/f\s+coverage: 0.0% of statements'
|
||||
|
||||
# This sub-test inspired by issue 65653: if package P is is matched
|
||||
# via the package pattern supplied as the argument to "go test -cover"
|
||||
# but P is not part of "-coverpkg", then we don't want coverage for P
|
||||
# (including the specific case where P has no test files).
|
||||
go test -coverpkg=./a ./...
|
||||
stdout '^ok\s+M/a\s+\S+\s+coverage: 100.0% of statements in ./a'
|
||||
stdout '^\s*\?\s+M/f\s+\[no test files\]'
|
||||
|
||||
-- a/a.go --
|
||||
package a
|
||||
|
||||
|
||||
4
src/cmd/go/testdata/script/cover_list.txt
vendored
4
src/cmd/go/testdata/script/cover_list.txt
vendored
@@ -38,6 +38,10 @@ cp stdout $WORK/toolbuildid.txt
|
||||
# Build IDs should match here.
|
||||
cmp $WORK/toolbuildid.txt $WORK/listbuildid.txt
|
||||
|
||||
# Make sure that the build succeeds regardless of covermode.
|
||||
go list -export -covermode=atomic m/example
|
||||
go list -export -covermode=count m/example
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
|
||||
17
src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt
vendored
Normal file
17
src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
[!GOOS:darwin] skip
|
||||
[!cgo] skip
|
||||
|
||||
! go build
|
||||
stderr 'invalid flag in #cgo LDFLAGS: -lto_library'
|
||||
|
||||
-- go.mod --
|
||||
module ldflag
|
||||
|
||||
-- main.go --
|
||||
package main
|
||||
|
||||
// #cgo CFLAGS: -flto
|
||||
// #cgo LDFLAGS: -lto_library bad.dylib
|
||||
import "C"
|
||||
|
||||
func main() {}
|
||||
27
src/cmd/go/testdata/script/generate_workspace.txt
vendored
Normal file
27
src/cmd/go/testdata/script/generate_workspace.txt
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# This is a regression test for Issue #56098: Go generate
|
||||
# wasn't initializing workspace mode
|
||||
|
||||
[short] skip
|
||||
|
||||
go generate ./mod
|
||||
cmp ./mod/got.txt want.txt
|
||||
|
||||
-- go.work --
|
||||
go 1.22
|
||||
|
||||
use ./mod
|
||||
-- mod/go.mod --
|
||||
module example.com/mod
|
||||
-- mod/gen.go --
|
||||
//go:generate go run gen.go got.txt
|
||||
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func main() {
|
||||
outfile := os.Args[1]
|
||||
os.WriteFile(outfile, []byte("Hello World!\n"), 0644)
|
||||
}
|
||||
-- want.txt --
|
||||
Hello World!
|
||||
109
src/cmd/go/testdata/script/gotoolchain_issue66175.txt
vendored
Normal file
109
src/cmd/go/testdata/script/gotoolchain_issue66175.txt
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
env TESTGO_VERSION=go1.14
|
||||
|
||||
# Clear the path so this test doesn't fail if the system running it\
|
||||
# has a binary named go1.21 or go1.22 on its path.
|
||||
[GOOS:plan9] env path=
|
||||
[!GOOS:plan9] env PATH=
|
||||
|
||||
# check for invalid toolchain in go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.14 -toolchain=go1.22
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.22 is a language version but not a toolchain version \(go1.22.x\)'
|
||||
|
||||
rm go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.14 -toolchain=go1.21
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.21 is a language version but not a toolchain version \(go1.21.x\)'
|
||||
|
||||
rm go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.14 -toolchain=go1.20
|
||||
! go version
|
||||
stderr 'go: downloading go1.20 '
|
||||
|
||||
|
||||
# check for invalid GOTOOLCHAIN
|
||||
env GOTOOLCHAIN=go1.14
|
||||
go version
|
||||
stdout 'go1.14'
|
||||
|
||||
env GOTOOLCHAIN=go1.20
|
||||
! go version
|
||||
stderr 'go: downloading go1.20 '
|
||||
|
||||
env GOTOOLCHAIN=go1.21
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.21 is a language version but not a toolchain version \(go1.21.x\)'
|
||||
|
||||
env GOTOOLCHAIN=go1.22
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.22 is a language version but not a toolchain version \(go1.22.x\)'
|
||||
|
||||
env GOTOOLCHAIN=go1.20+auto
|
||||
! go version
|
||||
stderr 'go: downloading go1.20 '
|
||||
|
||||
env GOTOOLCHAIN=go1.21+auto
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.21 is a language version but not a toolchain version \(go1.21.x\)'
|
||||
|
||||
env GOTOOLCHAIN=go1.22+auto
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.22 is a language version but not a toolchain version \(go1.22.x\)'
|
||||
|
||||
env GOTOOLCHAIN=go1.21rc3
|
||||
! go version
|
||||
stderr 'go: downloading go1.21rc3 '
|
||||
|
||||
env GOTOOLCHAIN=go1.22rc2
|
||||
! go version
|
||||
stderr 'go: downloading go1.22rc2 '
|
||||
|
||||
env GOTOOLCHAIN=go1.66
|
||||
! go version
|
||||
stderr 'go: invalid toolchain: go1.66 is a language version but not a toolchain version \(go1.66.x\)'
|
||||
|
||||
env GOTOOLCHAIN=go1.18beta2
|
||||
! go version
|
||||
stderr 'go: downloading go1.18beta2 '
|
||||
|
||||
# go1.X is okay for path lookups
|
||||
env GOTOOLCHAIN=go1.20+path
|
||||
! go version
|
||||
stderr 'go: cannot find "go1.20" in PATH'
|
||||
|
||||
env GOTOOLCHAIN=go1.21+path
|
||||
! go version
|
||||
stderr 'go: cannot find "go1.21" in PATH'
|
||||
|
||||
env GOTOOLCHAIN=go1.22+path
|
||||
! go version
|
||||
stderr 'go: cannot find "go1.22" in PATH'
|
||||
|
||||
# When a toolchain download takes place, download 1.X.0
|
||||
env GOTOOLCHAIN=auto
|
||||
rm go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.300 -toolchain=none
|
||||
! go version
|
||||
stderr 'go: downloading go1.300.0 '
|
||||
|
||||
rm go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.21 -toolchain=none
|
||||
! go version
|
||||
stderr 'go: downloading go1.21.0 '
|
||||
|
||||
rm go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.22 -toolchain=none
|
||||
! go version
|
||||
stderr 'go: downloading go1.22.0 '
|
||||
|
||||
rm go.mod
|
||||
go mod init m
|
||||
go mod edit -go=1.15 -toolchain=none
|
||||
! go version
|
||||
stderr 'go: downloading go1.15 '
|
||||
45
src/cmd/go/testdata/script/install_modcacherw_issue64282.txt
vendored
Normal file
45
src/cmd/go/testdata/script/install_modcacherw_issue64282.txt
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Regression test for https://go.dev/issue/64282.
|
||||
#
|
||||
# 'go install' and 'go run' with pkg@version arguments should make
|
||||
# a best effort to parse flags relevant to downloading modules
|
||||
# (currently only -modcacherw) before actually downloading the module
|
||||
# to identify which toolchain version to use.
|
||||
#
|
||||
# However, the best-effort flag parsing should not interfere with
|
||||
# actual flag parsing if we don't switch toolchains. In particular,
|
||||
# unrecognized flags should still be diagnosed after the module for
|
||||
# the requested package has been downloaded and checked for toolchain
|
||||
# upgrades.
|
||||
|
||||
|
||||
! go install -cake=delicious -modcacherw example.com/printversion@v0.1.0
|
||||
stderr '^flag provided but not defined: -cake$'
|
||||
# Because the -modcacherw flag was set, we should be able to modify the contents
|
||||
# of a directory within the module cache.
|
||||
cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go
|
||||
go clean -modcache
|
||||
|
||||
|
||||
! go install -unknownflag -tags -modcacherw example.com/printversion@v0.1.0
|
||||
stderr '^flag provided but not defined: -unknownflag$'
|
||||
cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go
|
||||
go clean -modcache
|
||||
|
||||
|
||||
# Also try it with a 'go install' that succeeds.
|
||||
# (But skip in short mode, because linking a binary is expensive.)
|
||||
[!short] go install -modcacherw example.com/printversion@v0.1.0
|
||||
[!short] cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go
|
||||
[!short] go clean -modcache
|
||||
|
||||
|
||||
# The flag should also be applied if given in GOFLAGS
|
||||
# instead of on the command line.
|
||||
env GOFLAGS=-modcacherw
|
||||
! go install -cake=delicious example.com/printversion@v0.1.0
|
||||
stderr '^flag provided but not defined: -cake$'
|
||||
cp $WORK/extraneous.txt $GOPATH/pkg/mod/example.com/printversion@v0.1.0/extraneous_file.go
|
||||
|
||||
|
||||
-- $WORK/extraneous.txt --
|
||||
This is not a Go source file.
|
||||
20
src/cmd/go/testdata/script/list_retractions_issue66403.txt
vendored
Normal file
20
src/cmd/go/testdata/script/list_retractions_issue66403.txt
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# For issue #66403, go list -u -m all should not fail if a module
|
||||
# with retractions has a newer version.
|
||||
|
||||
env TESTGO_VERSION=go1.21
|
||||
env TESTGO_VERSION_SWITCH=switch
|
||||
go list -u -m example.com/retract/newergoversion
|
||||
stdout 'example.com/retract/newergoversion v1.0.0'
|
||||
! stdout 'v1.2.0'
|
||||
|
||||
-- go.mod --
|
||||
module example.com/m
|
||||
|
||||
go 1.22
|
||||
|
||||
require example.com/retract/newergoversion v1.0.0
|
||||
|
||||
-- main.go --
|
||||
package main
|
||||
|
||||
import _ "example.com/retract/newergoversion"
|
||||
24
src/cmd/go/testdata/script/mod_verify_work.txt
vendored
Normal file
24
src/cmd/go/testdata/script/mod_verify_work.txt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Regression test for Issue #62663: we would filter out the toolchain and
|
||||
# main modules from the build list incorrectly, leading to the workspace
|
||||
# modules being checked for correct sums. Specifically this would happen when
|
||||
# the module name sorted after the virtual 'go' version module name because
|
||||
# it could not get chopped off when we removed the MainModules.Len() modules
|
||||
# at the beginning of the build list and we would remove the go module instead.
|
||||
|
||||
go mod verify
|
||||
|
||||
-- go.work --
|
||||
go 1.21
|
||||
|
||||
use (
|
||||
./a
|
||||
./b
|
||||
)
|
||||
-- a/go.mod --
|
||||
module hexample.com/a // important for test that module name sorts after 'go'
|
||||
|
||||
go 1.21
|
||||
-- b/go.mod --
|
||||
module hexample.com/b // important for test that module name sorts after 'go'
|
||||
|
||||
go 1.21
|
||||
44
src/cmd/go/testdata/script/reuse_git.txt
vendored
44
src/cmd/go/testdata/script/reuse_git.txt
vendored
@@ -7,7 +7,7 @@ env GOSUMDB=off
|
||||
|
||||
# go mod download with the pseudo-version should invoke git but not have a TagSum or Ref.
|
||||
go mod download -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20170922010558-fc3a09f3dc5c
|
||||
stderr 'git fetch'
|
||||
stderr 'git( .*)* fetch'
|
||||
cp stdout hellopseudo.json
|
||||
! stdout '"(Query|TagPrefix|TagSum|Ref)"'
|
||||
stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"'
|
||||
@@ -18,7 +18,7 @@ go clean -modcache
|
||||
|
||||
# go mod download vcstest/hello should invoke git, print origin info
|
||||
go mod download -x -json vcs-test.golang.org/git/hello.git@latest
|
||||
stderr 'git fetch'
|
||||
stderr 'git( .*)* fetch'
|
||||
cp stdout hello.json
|
||||
stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"'
|
||||
stdout '"VCS": "git"'
|
||||
@@ -33,13 +33,13 @@ stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"'
|
||||
# but still be careful not to include a TagSum or a Ref, especially not Ref set to HEAD,
|
||||
# which is easy to do when reusing the cached version from the @latest query.
|
||||
go mod download -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20170922010558-fc3a09f3dc5c
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
cp stdout hellopseudo2.json
|
||||
cmpenv hellopseudo.json hellopseudo2.json
|
||||
|
||||
# go mod download vcstest/hello@hash needs to check TagSum to find pseudoversion base.
|
||||
go mod download -x -json vcs-test.golang.org/git/hello.git@fc3a09f3dc5c
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
cp stdout hellohash.json
|
||||
stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"'
|
||||
stdout '"Query": "fc3a09f3dc5c"'
|
||||
@@ -98,7 +98,7 @@ stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="'
|
||||
|
||||
# go mod download vcstest/tagtests should invoke git, print origin info
|
||||
go mod download -x -json vcs-test.golang.org/git/tagtests.git@latest
|
||||
stderr 'git fetch'
|
||||
stderr 'git( .*)* fetch'
|
||||
cp stdout tagtests.json
|
||||
stdout '"Version": "v0.2.2"'
|
||||
stdout '"Query": "latest"'
|
||||
@@ -135,7 +135,7 @@ stdout '"Hash": "c7818c24fa2f3f714c67d0a6d3e411c85a518d1f"'
|
||||
|
||||
# go mod download vcstest/prefixtagtests should invoke git, print origin info
|
||||
go mod download -x -json vcs-test.golang.org/git/prefixtagtests.git/sub@latest
|
||||
stderr 'git fetch'
|
||||
stderr 'git( .*)* fetch'
|
||||
cp stdout prefixtagtests.json
|
||||
stdout '"Version": "v0.0.10"'
|
||||
stdout '"Query": "latest"'
|
||||
@@ -154,12 +154,12 @@ cp stdout all.json
|
||||
# clean the module cache, make sure that makes go mod download re-run git fetch, clean again
|
||||
go clean -modcache
|
||||
go mod download -x -json vcs-test.golang.org/git/hello.git@latest
|
||||
stderr 'git fetch'
|
||||
stderr 'git( .*)* fetch'
|
||||
go clean -modcache
|
||||
|
||||
# reuse go mod download vcstest/hello result
|
||||
go mod download -reuse=hello.json -x -json vcs-test.golang.org/git/hello.git@latest
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"'
|
||||
stdout '"VCS": "git"'
|
||||
@@ -175,7 +175,7 @@ stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"'
|
||||
|
||||
# reuse go mod download vcstest/hello pseudoversion result
|
||||
go mod download -reuse=hellopseudo.json -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20170922010558-fc3a09f3dc5c
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"'
|
||||
stdout '"VCS": "git"'
|
||||
@@ -186,7 +186,7 @@ stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"'
|
||||
|
||||
# reuse go mod download vcstest/hello@hash
|
||||
go mod download -reuse=hellohash.json -x -json vcs-test.golang.org/git/hello.git@fc3a09f3dc5c
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Query": "fc3a09f3dc5c"'
|
||||
stdout '"Version": "v0.0.0-20170922010558-fc3a09f3dc5c"'
|
||||
@@ -199,7 +199,7 @@ stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"'
|
||||
|
||||
# reuse go mod download vcstest/hello/v9 error result
|
||||
! go mod download -reuse=hellov9.json -x -json vcs-test.golang.org/git/hello.git/v9@latest
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Error":.*no matching versions'
|
||||
! stdout '"TagPrefix"'
|
||||
@@ -210,7 +210,7 @@ stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"'
|
||||
|
||||
# reuse go mod download vcstest/hello/sub/v9 error result
|
||||
! go mod download -reuse=hellosubv9.json -x -json vcs-test.golang.org/git/hello.git/sub/v9@latest
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Error":.*no matching versions'
|
||||
stdout '"TagPrefix": "sub/"'
|
||||
@@ -221,7 +221,7 @@ stdout '"Hash": "fc3a09f3dc5cfe0d7a743ea18f1f5226e68b3777"'
|
||||
|
||||
# reuse go mod download vcstest/hello@nonexist
|
||||
! go mod download -reuse=hellononexist.json -x -json vcs-test.golang.org/git/hello.git@nonexist
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "nonexist"'
|
||||
stdout '"Error":.*unknown revision nonexist'
|
||||
@@ -231,7 +231,7 @@ stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="'
|
||||
|
||||
# reuse go mod download vcstest/hello@1234567890123456789012345678901234567890
|
||||
! go mod download -reuse=hellononhash.json -x -json vcs-test.golang.org/git/hello.git@1234567890123456789012345678901234567890
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "1234567890123456789012345678901234567890"'
|
||||
stdout '"Error":.*unknown revision 1234567890123456789012345678901234567890'
|
||||
@@ -241,7 +241,7 @@ stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="'
|
||||
|
||||
# reuse go mod download vcstest/hello@v0.0.0-20220101120101-123456789abc
|
||||
! go mod download -reuse=hellononpseudo.json -x -json vcs-test.golang.org/git/hello.git@v0.0.0-20220101120101-123456789abc
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.0.0-20220101120101-123456789abc"'
|
||||
stdout '"Error":.*unknown revision 123456789abc'
|
||||
@@ -251,7 +251,7 @@ stdout '"RepoSum": "r1:c0/9JCZ25lxoBiK3[+]3BhACU4giH49flcJmBynJ[+]Jvmc="'
|
||||
|
||||
# reuse go mod download vcstest/tagtests result
|
||||
go mod download -reuse=tagtests.json -x -json vcs-test.golang.org/git/tagtests.git@latest
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.2.2"'
|
||||
stdout '"Query": "latest"'
|
||||
@@ -265,7 +265,7 @@ stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"'
|
||||
|
||||
# reuse go mod download vcstest/tagtests@v0.2.2 result
|
||||
go mod download -reuse=tagtestsv022.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.2.2"'
|
||||
! stdout '"Query":'
|
||||
@@ -279,7 +279,7 @@ stdout '"Hash": "59356c8cd18c5fe9a598167d98a6843e52d57952"'
|
||||
|
||||
# reuse go mod download vcstest/tagtests@master result
|
||||
go mod download -reuse=tagtestsmaster.json -x -json vcs-test.golang.org/git/tagtests.git@master
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.2.3-0.20190509225625-c7818c24fa2f"'
|
||||
stdout '"Query": "master"'
|
||||
@@ -293,7 +293,7 @@ stdout '"Hash": "c7818c24fa2f3f714c67d0a6d3e411c85a518d1f"'
|
||||
|
||||
# reuse go mod download vcstest/tagtests@master result again with all.json
|
||||
go mod download -reuse=all.json -x -json vcs-test.golang.org/git/tagtests.git@master
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.2.3-0.20190509225625-c7818c24fa2f"'
|
||||
stdout '"Query": "master"'
|
||||
@@ -307,7 +307,7 @@ stdout '"Hash": "c7818c24fa2f3f714c67d0a6d3e411c85a518d1f"'
|
||||
|
||||
# go mod download vcstest/prefixtagtests result with json
|
||||
go mod download -reuse=prefixtagtests.json -x -json vcs-test.golang.org/git/prefixtagtests.git/sub@latest
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Version": "v0.0.10"'
|
||||
stdout '"Query": "latest"'
|
||||
stdout '"VCS": "git"'
|
||||
@@ -321,7 +321,7 @@ stdout '"Hash": "2b7c4692e12c109263cab51b416fcc835ddd7eae"'
|
||||
|
||||
# reuse the bulk results with all.json
|
||||
! go mod download -reuse=all.json -json vcs-test.golang.org/git/hello.git@latest vcs-test.golang.org/git/hello.git/v9@latest vcs-test.golang.org/git/hello.git/sub/v9@latest vcs-test.golang.org/git/tagtests.git@latest vcs-test.golang.org/git/tagtests.git@v0.2.2 vcs-test.golang.org/git/tagtests.git@master
|
||||
! stderr 'git fetch'
|
||||
! stderr 'git( .*)* fetch'
|
||||
stdout '"Reuse": true'
|
||||
! stdout '"(Dir|Info|GoMod|Zip)"'
|
||||
|
||||
@@ -329,7 +329,7 @@ stdout '"Reuse": true'
|
||||
cp tagtestsv022.json tagtestsv022badhash.json
|
||||
replace '57952' '56952XXX' tagtestsv022badhash.json
|
||||
go mod download -reuse=tagtestsv022badhash.json -x -json vcs-test.golang.org/git/tagtests.git@v0.2.2
|
||||
stderr 'git fetch'
|
||||
stderr 'git( .*)* fetch'
|
||||
! stdout '"Reuse": true'
|
||||
stdout '"Version": "v0.2.2"'
|
||||
! stdout '"Query"'
|
||||
|
||||
28
src/cmd/go/testdata/script/test_fuzz_cgo.txt
vendored
Normal file
28
src/cmd/go/testdata/script/test_fuzz_cgo.txt
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
[!fuzz] skip
|
||||
[!cgo] skip
|
||||
[short] skip
|
||||
env GOCACHE=$WORK/cache
|
||||
|
||||
# Test that fuzzing works with cgo (issue 65169)
|
||||
|
||||
go test -fuzz=. -fuzztime=1x
|
||||
stdout ok
|
||||
! stdout FAIL
|
||||
|
||||
-- go.mod --
|
||||
module example.com/p
|
||||
|
||||
go 1.20
|
||||
-- c.go --
|
||||
package p
|
||||
|
||||
import "C"
|
||||
-- c_test.go --
|
||||
package p
|
||||
|
||||
import "testing"
|
||||
|
||||
func Fuzz(f *testing.F) {
|
||||
f.Add(0)
|
||||
f.Fuzz(func(t *testing.T, x int) {})
|
||||
}
|
||||
@@ -14,6 +14,10 @@ go build -ldflags='-linkmode=internal'
|
||||
exec ./abitest
|
||||
stdout success
|
||||
|
||||
go build -buildmode=pie -o abitest.pie -ldflags='-linkmode=internal'
|
||||
exec ./abitest.pie
|
||||
stdout success
|
||||
|
||||
-- go.mod --
|
||||
module abitest
|
||||
|
||||
|
||||
@@ -204,15 +204,12 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
}
|
||||
r.vis.VisitMetaDataFile(p.MetaFile, mfr)
|
||||
|
||||
// Read counter data files.
|
||||
for k, cdf := range p.CounterDataFiles {
|
||||
processCounterDataFile := func(cdf string, k int) error {
|
||||
cf, err := os.Open(cdf)
|
||||
if err != nil {
|
||||
return r.fatal("opening counter data file %s: %s", cdf, err)
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
f.Close()
|
||||
}(cf)
|
||||
defer cf.Close()
|
||||
var mr *MReader
|
||||
mr, err = NewMreader(cf)
|
||||
if err != nil {
|
||||
@@ -236,6 +233,14 @@ func (r *CovDataReader) visitPod(p pods.Pod) error {
|
||||
r.vis.VisitFuncCounterData(data)
|
||||
}
|
||||
r.vis.EndCounterDataFile(cdf, cdr, p.Origins[k])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read counter data files.
|
||||
for k, cdf := range p.CounterDataFiles {
|
||||
if err := processCounterDataFile(cdf, k); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
r.vis.EndCounters()
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"internal/abi"
|
||||
"log"
|
||||
"math/bits"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Test if this value can encoded as a mask for
|
||||
@@ -72,6 +73,22 @@ func encodePPC64RLDCMask(mask int64) (mb, me int) {
|
||||
return mb, me - 1
|
||||
}
|
||||
|
||||
// Is this a symbol which should never have a TOC prologue generated?
|
||||
// These are special functions which should not have a TOC regeneration
|
||||
// prologue.
|
||||
func isNOTOCfunc(name string) bool {
|
||||
switch {
|
||||
case name == "runtime.duffzero":
|
||||
return true
|
||||
case name == "runtime.duffcopy":
|
||||
return true
|
||||
case strings.HasPrefix(name, "runtime.elf_"):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
|
||||
p.From.Class = 0
|
||||
p.To.Class = 0
|
||||
@@ -158,8 +175,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
|
||||
// Is this a shifted 16b constant? If so, rewrite it to avoid a creating and loading a constant.
|
||||
val := p.From.Offset
|
||||
shift := bits.TrailingZeros64(uint64(val))
|
||||
mask := 0xFFFF << shift
|
||||
if val&int64(mask) == val || (val>>(shift+16) == -1 && (val>>shift)<<shift == val) {
|
||||
mask := int64(0xFFFF) << shift
|
||||
if val&mask == val || (val>>(shift+16) == -1 && (val>>shift)<<shift == val) {
|
||||
// Rewrite this value into MOVD $const>>shift, Rto; SLD $shift, Rto
|
||||
q := obj.Appendp(p, c.newprog)
|
||||
q.As = ASLD
|
||||
@@ -762,7 +779,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
||||
|
||||
q = p
|
||||
|
||||
if NeedTOCpointer(c.ctxt) && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
|
||||
if NeedTOCpointer(c.ctxt) && !isNOTOCfunc(c.cursym.Name) {
|
||||
// When compiling Go into PIC, without PCrel support, all functions must start
|
||||
// with instructions to load the TOC pointer into r2:
|
||||
//
|
||||
|
||||
@@ -398,6 +398,13 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
|
||||
// (e.g. go version).
|
||||
return true
|
||||
}
|
||||
case objabi.R_GOTPCREL:
|
||||
if target.IsExternal() {
|
||||
// External linker will do this relocation.
|
||||
return true
|
||||
}
|
||||
// We only need to handle external linking mode, as R_GOTPCREL can
|
||||
// only occur in plugin or shared build modes.
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -1915,7 +1915,6 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
|
||||
sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrbss", sym.SNOPTRBSS, sym.Sxxx, 06)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.noptrbss", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.enoptrbss", 0), sect)
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.end", 0), sect)
|
||||
|
||||
// Code coverage counters are assigned to the .noptrbss section.
|
||||
// We assign them in a separate pass so that they stay aggregated
|
||||
@@ -1935,6 +1934,9 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._ecounters", 0), sect)
|
||||
}
|
||||
|
||||
// Assign runtime.end to the last section of data segment.
|
||||
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.end", 0), Segdata.Sections[len(Segdata.Sections)-1])
|
||||
|
||||
if len(state.data[sym.STLSBSS]) > 0 {
|
||||
var sect *sym.Section
|
||||
// FIXME: not clear why it is sometimes necessary to suppress .tbss section creation.
|
||||
|
||||
@@ -1954,7 +1954,15 @@ func (ctxt *Link) hostlink() {
|
||||
cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
|
||||
// dsymutil may not clean up its temp directory at exit.
|
||||
// Set DSYMUTIL_REPRODUCER_PATH to work around. see issue 59026.
|
||||
cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+*flagTmpdir)
|
||||
// dsymutil (Apple LLVM version 16.0.0) deletes the directory
|
||||
// even if it is not empty. We still need our tmpdir, so give a
|
||||
// subdirectory to dsymutil.
|
||||
dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
|
||||
err = os.MkdirAll(dsymDir, 0777)
|
||||
if err != nil {
|
||||
Exitf("fail to create temp dir: %v", err)
|
||||
}
|
||||
cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
|
||||
if ctxt.Debugvlog != 0 {
|
||||
ctxt.Logf("host link dsymutil:")
|
||||
for _, v := range cmd.Args {
|
||||
|
||||
@@ -901,21 +901,25 @@ func collectmachosyms(ctxt *Link) {
|
||||
// Add special runtime.text and runtime.etext symbols (which are local).
|
||||
// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
|
||||
// See data.go:/textaddress
|
||||
// NOTE: runtime.text.N symbols (if we split text sections) are not added, though,
|
||||
// so we handle them here.
|
||||
if !*FlagS {
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s := ldr.Lookup("runtime.text", 0)
|
||||
if ldr.SymType(s) == sym.STEXT {
|
||||
addsym(s)
|
||||
}
|
||||
for n := range Segtext.Sections[1:] {
|
||||
s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
|
||||
if s != 0 {
|
||||
addsym(s)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
for n := range Segtext.Sections[1:] {
|
||||
s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
|
||||
if s != 0 {
|
||||
addsym(s)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
s = ldr.Lookup("runtime.etext", 0)
|
||||
}
|
||||
if !ctxt.DynlinkingGo() {
|
||||
s := ldr.Lookup("runtime.etext", 0)
|
||||
if ldr.SymType(s) == sym.STEXT {
|
||||
addsym(s)
|
||||
}
|
||||
|
||||
@@ -474,24 +474,9 @@ func rewriteABIFuncReloc(ctxt *ld.Link, ldr *loader.Loader, tname string, r load
|
||||
r.SetAdd(int64((n - minReg) * offMul))
|
||||
firstUse = !ldr.AttrReachable(ts)
|
||||
if firstUse {
|
||||
ldr.SetAttrReachable(ts, true)
|
||||
// This function only becomes reachable now. It has been dropped from
|
||||
// the text section (it was unreachable until now), it needs included.
|
||||
//
|
||||
// Similarly, TOC regeneration should not happen for these functions,
|
||||
// remove it from this save/restore function.
|
||||
if ldr.AttrShared(ts) {
|
||||
sb := ldr.MakeSymbolUpdater(ts)
|
||||
sb.SetData(sb.Data()[8:])
|
||||
sb.SetSize(sb.Size() - 8)
|
||||
relocs := sb.Relocs()
|
||||
// Only one PCREL reloc to .TOC. should be present.
|
||||
if relocs.Count() != 1 {
|
||||
log.Fatalf("Unexpected number of relocs in %s\n", ldr.SymName(ts))
|
||||
}
|
||||
sb.ResetRelocs()
|
||||
|
||||
}
|
||||
ldr.SetAttrReachable(ts, true)
|
||||
}
|
||||
return ts, firstUse
|
||||
}
|
||||
|
||||
@@ -170,8 +170,8 @@ func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
|
||||
relocs := ldr.Relocs(s)
|
||||
for ri := 0; ri < relocs.Count(); ri++ {
|
||||
r := relocs.At(ri)
|
||||
if r.Type() != objabi.R_RISCV_PCREL_ITYPE && r.Type() != objabi.R_RISCV_PCREL_STYPE &&
|
||||
r.Type() != objabi.R_RISCV_TLS_IE {
|
||||
if r.Type() != objabi.R_RISCV_CALL && r.Type() != objabi.R_RISCV_PCREL_ITYPE &&
|
||||
r.Type() != objabi.R_RISCV_PCREL_STYPE && r.Type() != objabi.R_RISCV_TLS_IE {
|
||||
continue
|
||||
}
|
||||
if r.Off() == 0 && ldr.SymType(s) == sym.STEXT {
|
||||
|
||||
@@ -31,6 +31,9 @@ type generator interface {
|
||||
ProcRange(ctx *traceContext, ev *tracev2.Event)
|
||||
ProcTransition(ctx *traceContext, ev *tracev2.Event)
|
||||
|
||||
// User annotations.
|
||||
Log(ctx *traceContext, ev *tracev2.Event)
|
||||
|
||||
// Finish indicates the end of the trace and finalizes generation.
|
||||
Finish(ctx *traceContext)
|
||||
}
|
||||
@@ -69,6 +72,8 @@ func runGenerator(ctx *traceContext, g generator, parsed *parsedTrace, opts *gen
|
||||
case tracev2.ResourceGoroutine:
|
||||
g.GoroutineTransition(ctx, ev)
|
||||
}
|
||||
case tracev2.EventLog:
|
||||
g.Log(ctx, ev)
|
||||
}
|
||||
}
|
||||
for i, task := range opts.tasks {
|
||||
@@ -357,3 +362,33 @@ type completedRange struct {
|
||||
endStack tracev2.Stack
|
||||
arg any
|
||||
}
|
||||
|
||||
type logEventGenerator[R resource] struct {
|
||||
// getResource is a function to extract a resource ID from a Log event.
|
||||
getResource func(*tracev2.Event) R
|
||||
}
|
||||
|
||||
// Log implements a log event handler. It expects ev to be one such event.
|
||||
func (g *logEventGenerator[R]) Log(ctx *traceContext, ev *tracev2.Event) {
|
||||
id := g.getResource(ev)
|
||||
if id == R(noResource) {
|
||||
// We have nowhere to put this in the UI.
|
||||
return
|
||||
}
|
||||
|
||||
// Construct the name to present.
|
||||
log := ev.Log()
|
||||
name := log.Message
|
||||
if log.Category != "" {
|
||||
name = "[" + log.Category + "] " + name
|
||||
}
|
||||
|
||||
// Emit an instant event.
|
||||
ctx.Instant(traceviewer.InstantEvent{
|
||||
Name: name,
|
||||
Ts: ctx.elapsed(ev.Time()),
|
||||
Category: "user event",
|
||||
Resource: uint64(id),
|
||||
Stack: ctx.Stack(viewerFrames(ev.Stack())),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ type goroutineGenerator struct {
|
||||
globalRangeGenerator
|
||||
globalMetricGenerator
|
||||
stackSampleGenerator[tracev2.GoID]
|
||||
logEventGenerator[tracev2.GoID]
|
||||
|
||||
gStates map[tracev2.GoID]*gState[tracev2.GoID]
|
||||
focus tracev2.GoID
|
||||
@@ -22,9 +23,11 @@ type goroutineGenerator struct {
|
||||
|
||||
func newGoroutineGenerator(ctx *traceContext, focus tracev2.GoID, filter map[tracev2.GoID]struct{}) *goroutineGenerator {
|
||||
gg := new(goroutineGenerator)
|
||||
gg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.GoID {
|
||||
rg := func(ev *tracev2.Event) tracev2.GoID {
|
||||
return ev.Goroutine()
|
||||
}
|
||||
gg.stackSampleGenerator.getResource = rg
|
||||
gg.logEventGenerator.getResource = rg
|
||||
gg.gStates = make(map[tracev2.GoID]*gState[tracev2.GoID])
|
||||
gg.focus = focus
|
||||
gg.filter = filter
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"net/http"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -25,31 +24,23 @@ import (
|
||||
// GoroutinesHandlerFunc returns a HandlerFunc that serves list of goroutine groups.
|
||||
func GoroutinesHandlerFunc(summaries map[tracev2.GoID]*trace.GoroutineSummary) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// goroutineGroup describes a group of goroutines grouped by start PC.
|
||||
// goroutineGroup describes a group of goroutines grouped by name.
|
||||
type goroutineGroup struct {
|
||||
ID uint64 // Unique identifier (PC).
|
||||
Name string // Start function.
|
||||
N int // Total number of goroutines in this group.
|
||||
ExecTime time.Duration // Total execution time of all goroutines in this group.
|
||||
}
|
||||
// Accumulate groups by PC.
|
||||
groupsByPC := make(map[uint64]goroutineGroup)
|
||||
// Accumulate groups by Name.
|
||||
groupsByName := make(map[string]goroutineGroup)
|
||||
for _, summary := range summaries {
|
||||
group := groupsByPC[summary.PC]
|
||||
group.ID = summary.PC
|
||||
group := groupsByName[summary.Name]
|
||||
group.Name = summary.Name
|
||||
group.N++
|
||||
group.ExecTime += summary.ExecTime
|
||||
groupsByPC[summary.PC] = group
|
||||
groupsByName[summary.Name] = group
|
||||
}
|
||||
var groups []goroutineGroup
|
||||
for pc, group := range groupsByPC {
|
||||
group.ID = pc
|
||||
// If goroutine didn't run during the trace (no sampled PC),
|
||||
// the v.ID and v.Name will be zero value.
|
||||
if group.ID == 0 && group.Name == "" {
|
||||
group.Name = "(Inactive, no stack trace sampled)"
|
||||
}
|
||||
for _, group := range groupsByName {
|
||||
groups = append(groups, group)
|
||||
}
|
||||
slices.SortFunc(groups, func(a, b goroutineGroup) int {
|
||||
@@ -92,7 +83,7 @@ Click a start location to view more details about that group.<br>
|
||||
</tr>
|
||||
{{range $}}
|
||||
<tr>
|
||||
<td><code><a href="/goroutine?id={{.ID}}">{{.Name}}</a></code></td>
|
||||
<td><code><a href="/goroutine?name={{.Name}}">{{or .Name "(Inactive, no stack trace sampled)"}}</a></code></td>
|
||||
<td>{{.N}}</td>
|
||||
<td>{{.ExecTime}}</td>
|
||||
</tr>
|
||||
@@ -106,11 +97,7 @@ Click a start location to view more details about that group.<br>
|
||||
// goroutines in a particular group.
|
||||
func GoroutineHandler(summaries map[tracev2.GoID]*trace.GoroutineSummary) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
pc, err := strconv.ParseUint(r.FormValue("id"), 10, 64)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to parse id parameter '%v': %v", r.FormValue("id"), err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
goroutineName := r.FormValue("name")
|
||||
|
||||
type goroutine struct {
|
||||
*trace.GoroutineSummary
|
||||
@@ -130,7 +117,7 @@ func GoroutineHandler(summaries map[tracev2.GoID]*trace.GoroutineSummary) http.H
|
||||
for _, summary := range summaries {
|
||||
totalExecTime += summary.ExecTime
|
||||
|
||||
if summary.PC != pc {
|
||||
if summary.Name != goroutineName {
|
||||
continue
|
||||
}
|
||||
nonOverlappingStats := summary.NonOverlappingStats()
|
||||
@@ -198,9 +185,8 @@ func GoroutineHandler(summaries map[tracev2.GoID]*trace.GoroutineSummary) http.H
|
||||
}
|
||||
sort.Strings(allRangeStats)
|
||||
|
||||
err = templGoroutine.Execute(w, struct {
|
||||
err := templGoroutine.Execute(w, struct {
|
||||
Name string
|
||||
PC uint64
|
||||
N int
|
||||
ExecTimePercent string
|
||||
MaxTotal time.Duration
|
||||
@@ -209,7 +195,6 @@ func GoroutineHandler(summaries map[tracev2.GoID]*trace.GoroutineSummary) http.H
|
||||
RangeStats []string
|
||||
}{
|
||||
Name: name,
|
||||
PC: pc,
|
||||
N: len(goroutines),
|
||||
ExecTimePercent: execTimePercent,
|
||||
MaxTotal: maxTotalTime,
|
||||
@@ -339,19 +324,19 @@ Table of contents
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Network wait profile:</td>
|
||||
<td> <a href="/io?id={{.PC}}">graph</a> <a href="/io?id={{.PC}}&raw=1" download="io.profile">(download)</a></td>
|
||||
<td> <a href="/io?name={{.Name}}">graph</a> <a href="/io?name={{.Name}}&raw=1" download="io.profile">(download)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sync block profile:</td>
|
||||
<td> <a href="/block?id={{.PC}}">graph</a> <a href="/block?id={{.PC}}&raw=1" download="block.profile">(download)</a></td>
|
||||
<td> <a href="/block?name={{.Name}}">graph</a> <a href="/block?name={{.Name}}&raw=1" download="block.profile">(download)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Syscall profile:</td>
|
||||
<td> <a href="/syscall?id={{.PC}}">graph</a> <a href="/syscall?id={{.PC}}&raw=1" download="syscall.profile">(download)</a></td>
|
||||
<td> <a href="/syscall?name={{.Name}}">graph</a> <a href="/syscall?name={{.Name}}&raw=1" download="syscall.profile">(download)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Scheduler wait profile:</td>
|
||||
<td> <a href="/sched?id={{.PC}}">graph</a> <a href="/sched?id={{.PC}}&raw=1" download="sched.profile">(download)</a></td>
|
||||
<td> <a href="/sched?name={{.Name}}">graph</a> <a href="/sched?name={{.Name}}&raw=1" download="sched.profile">(download)</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -167,8 +167,8 @@ func checkNetworkUnblock(t *testing.T, data format.Data) {
|
||||
if netBlockEv == nil {
|
||||
t.Error("failed to find a network unblock")
|
||||
}
|
||||
if count == 0 || count > 2 {
|
||||
t.Errorf("found too many network block events: want 1 or 2, found %d", count)
|
||||
if count == 0 {
|
||||
t.Errorf("found zero network block events, want at least one")
|
||||
}
|
||||
// TODO(mknyszek): Check for the flow of this event to some slice event of a goroutine running.
|
||||
}
|
||||
|
||||
@@ -28,6 +28,35 @@ func Main(traceFile, httpAddr, pprof string, debug int) error {
|
||||
}
|
||||
defer tracef.Close()
|
||||
|
||||
// Handle requests for profiles.
|
||||
if pprof != "" {
|
||||
parsed, err := parseTrace(tracef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var f traceviewer.ProfileFunc
|
||||
switch pprof {
|
||||
case "net":
|
||||
f = pprofByGoroutine(computePprofIO(), parsed)
|
||||
case "sync":
|
||||
f = pprofByGoroutine(computePprofBlock(), parsed)
|
||||
case "syscall":
|
||||
f = pprofByGoroutine(computePprofSyscall(), parsed)
|
||||
case "sched":
|
||||
f = pprofByGoroutine(computePprofSched(), parsed)
|
||||
default:
|
||||
return fmt.Errorf("unknown pprof type %s\n", pprof)
|
||||
}
|
||||
records, err := f(&http.Request{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate pprof: %v\n", err)
|
||||
}
|
||||
if err := traceviewer.BuildProfile(records).Write(os.Stdout); err != nil {
|
||||
return fmt.Errorf("failed to generate pprof: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debug flags.
|
||||
switch debug {
|
||||
case 1:
|
||||
|
||||
@@ -14,15 +14,14 @@ import (
|
||||
tracev2 "internal/trace/v2"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func pprofByGoroutine(compute computePprofFunc, t *parsedTrace) traceviewer.ProfileFunc {
|
||||
return func(r *http.Request) ([]traceviewer.ProfileRecord, error) {
|
||||
id := r.FormValue("id")
|
||||
gToIntervals, err := pprofMatchingGoroutines(id, t)
|
||||
name := r.FormValue("name")
|
||||
gToIntervals, err := pprofMatchingGoroutines(name, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -44,20 +43,12 @@ func pprofByRegion(compute computePprofFunc, t *parsedTrace) traceviewer.Profile
|
||||
}
|
||||
}
|
||||
|
||||
// pprofMatchingGoroutines parses the goroutine type id string (i.e. pc)
|
||||
// and returns the ids of goroutines of the matching type and its interval.
|
||||
// pprofMatchingGoroutines returns the ids of goroutines of the matching name and its interval.
|
||||
// If the id string is empty, returns nil without an error.
|
||||
func pprofMatchingGoroutines(id string, t *parsedTrace) (map[tracev2.GoID][]interval, error) {
|
||||
if id == "" {
|
||||
return nil, nil
|
||||
}
|
||||
pc, err := strconv.ParseUint(id, 10, 64) // id is string
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid goroutine type: %v", id)
|
||||
}
|
||||
func pprofMatchingGoroutines(name string, t *parsedTrace) (map[tracev2.GoID][]interval, error) {
|
||||
res := make(map[tracev2.GoID][]interval)
|
||||
for _, g := range t.summary.Goroutines {
|
||||
if g.PC != pc {
|
||||
if name != "" && g.Name != name {
|
||||
continue
|
||||
}
|
||||
endTime := g.EndTime
|
||||
@@ -66,8 +57,8 @@ func pprofMatchingGoroutines(id string, t *parsedTrace) (map[tracev2.GoID][]inte
|
||||
}
|
||||
res[g.ID] = []interval{{start: g.StartTime, end: endTime}}
|
||||
}
|
||||
if len(res) == 0 && id != "" {
|
||||
return nil, fmt.Errorf("failed to find matching goroutines for ID: %s", id)
|
||||
if len(res) == 0 {
|
||||
return nil, fmt.Errorf("failed to find matching goroutines for name: %s", name)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ type procGenerator struct {
|
||||
globalMetricGenerator
|
||||
procRangeGenerator
|
||||
stackSampleGenerator[tracev2.ProcID]
|
||||
logEventGenerator[tracev2.ProcID]
|
||||
|
||||
gStates map[tracev2.GoID]*gState[tracev2.ProcID]
|
||||
inSyscall map[tracev2.ProcID]*gState[tracev2.ProcID]
|
||||
@@ -26,9 +27,11 @@ type procGenerator struct {
|
||||
|
||||
func newProcGenerator() *procGenerator {
|
||||
pg := new(procGenerator)
|
||||
pg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.ProcID {
|
||||
rg := func(ev *tracev2.Event) tracev2.ProcID {
|
||||
return ev.Proc()
|
||||
}
|
||||
pg.stackSampleGenerator.getResource = rg
|
||||
pg.logEventGenerator.getResource = rg
|
||||
pg.gStates = make(map[tracev2.GoID]*gState[tracev2.ProcID])
|
||||
pg.inSyscall = make(map[tracev2.ProcID]*gState[tracev2.ProcID])
|
||||
return pg
|
||||
|
||||
8819
src/cmd/trace/v2/testdata/go122.test
vendored
8819
src/cmd/trace/v2/testdata/go122.test
vendored
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@ type threadGenerator struct {
|
||||
globalRangeGenerator
|
||||
globalMetricGenerator
|
||||
stackSampleGenerator[tracev2.ThreadID]
|
||||
logEventGenerator[tracev2.ThreadID]
|
||||
|
||||
gStates map[tracev2.GoID]*gState[tracev2.ThreadID]
|
||||
threads map[tracev2.ThreadID]struct{}
|
||||
@@ -24,9 +25,11 @@ type threadGenerator struct {
|
||||
|
||||
func newThreadGenerator() *threadGenerator {
|
||||
tg := new(threadGenerator)
|
||||
tg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.ThreadID {
|
||||
rg := func(ev *tracev2.Event) tracev2.ThreadID {
|
||||
return ev.Thread()
|
||||
}
|
||||
tg.stackSampleGenerator.getResource = rg
|
||||
tg.logEventGenerator.getResource = rg
|
||||
tg.gStates = make(map[tracev2.GoID]*gState[tracev2.ThreadID])
|
||||
tg.threads = make(map[tracev2.ThreadID]struct{})
|
||||
return tg
|
||||
|
||||
@@ -13,21 +13,15 @@ WORKDIR /boring
|
||||
ENV LANG=C
|
||||
ENV LANGUAGE=
|
||||
|
||||
# Following NIST submission draft for In Progress module validation.
|
||||
# This corresponds to boringssl.googlesource.com/boringssl tag fips-20220613.
|
||||
# Following NIST submission draft dated July 3, 2021.
|
||||
# This corresponds to boringssl.googlesource.com/boringssl tag fips-20210429.
|
||||
ENV ClangV=12
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -y cmake xz-utils wget unzip ca-certificates python lsb-release software-properties-common gnupg
|
||||
|
||||
# Install Clang.
|
||||
ENV ClangV=14
|
||||
RUN \
|
||||
wget https://apt.llvm.org/llvm.sh && \
|
||||
chmod +x llvm.sh && \
|
||||
./llvm.sh $ClangV
|
||||
apt-get install --no-install-recommends -y cmake xz-utils wget unzip ca-certificates clang-$ClangV python
|
||||
|
||||
# Download, validate, unpack, build, and install Ninja.
|
||||
ENV NinjaV=1.10.1
|
||||
ENV NinjaH=a6b6f7ac360d4aabd54e299cc1d8fa7b234cd81b9401693da21221c62569a23e
|
||||
ENV NinjaV=1.10.2
|
||||
ENV NinjaH=ce35865411f0490368a8fc383f29071de6690cbadc27704734978221f25e2bed
|
||||
RUN \
|
||||
wget https://github.com/ninja-build/ninja/archive/refs/tags/v$NinjaV.tar.gz && \
|
||||
echo "$NinjaH v$NinjaV.tar.gz" >sha && sha256sum -c sha && \
|
||||
@@ -39,9 +33,9 @@ RUN \
|
||||
|
||||
# Download, validate, unpack, and install Go.
|
||||
ARG GOARCH
|
||||
ENV GoV=1.18.1
|
||||
ENV GoHamd64=b3b815f47ababac13810fc6021eb73d65478e0b2db4b09d348eefad9581a2334
|
||||
ENV GoHarm64=56a91851c97fb4697077abbca38860f735c32b38993ff79b088dac46e4735633
|
||||
ENV GoV=1.16.5
|
||||
ENV GoHamd64=b12c23023b68de22f74c0524f10b753e7b08b1504cb7e417eccebdd3fae49061
|
||||
ENV GoHarm64=d5446b46ef6f36fdffa852f73dfbbe78c1ddf010b99fa4964944b9ae8b4d6799
|
||||
RUN \
|
||||
eval GoH=\${GoH$GOARCH} && \
|
||||
wget https://golang.org/dl/go$GoV.linux-$GOARCH.tar.gz && \
|
||||
@@ -51,8 +45,8 @@ RUN \
|
||||
ln -s /usr/local/go/bin/go /usr/local/bin/
|
||||
|
||||
# Download, validate, and unpack BoringCrypto.
|
||||
ENV BoringV=0c6f40132b828e92ba365c6b7680e32820c63fa7
|
||||
ENV BoringH=62f733289f2d677c2723f556aa58034c438f3a7bbca6c12b156538a88e38da8a
|
||||
ENV BoringV=853ca1ea1168dff08011e5d42d94609cc0ca2e27
|
||||
ENV BoringH=a4d069ccef6f3c7bc0c68de82b91414f05cb817494cd1ab483dcf3368883c7c2
|
||||
RUN \
|
||||
wget https://commondatastorage.googleapis.com/chromium-boringssl-fips/boringssl-$BoringV.tar.xz && \
|
||||
echo "$BoringH boringssl-$BoringV.tar.xz" >sha && sha256sum -c sha && \
|
||||
|
||||
@@ -6,7 +6,7 @@ When building with GOEXPERIMENT=boringcrypto, the following applies.
|
||||
The goboringcrypto_linux_amd64.syso object file is built
|
||||
from BoringSSL source code by build/build.sh and is covered
|
||||
by the BoringSSL license reproduced below and also at
|
||||
https://boringssl.googlesource.com/boringssl/+/fips-20220613/LICENSE.
|
||||
https://boringssl.googlesource.com/boringssl/+/fips-20190808/LICENSE.
|
||||
|
||||
BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL
|
||||
licensing. Files that are completely new have a Google copyright and an ISC
|
||||
|
||||
@@ -27,14 +27,13 @@ syso/goboringcrypto_linux_arm64.syso is built with:
|
||||
|
||||
GOARCH=arm64 ./build.sh
|
||||
|
||||
Both run using Docker.
|
||||
|
||||
Both run on an x86 Debian Linux system using Docker.
|
||||
For the arm64 build to run on an x86 system, you need
|
||||
|
||||
apt-get install qemu-user-static qemu-binfmt-support
|
||||
|
||||
to allow the x86 kernel to run arm64 binaries via QEMU.
|
||||
|
||||
For the amd64 build to run on an Apple Silicon macOS, you need Rosetta 2.
|
||||
|
||||
See build.sh for more details about the build.
|
||||
|
||||
|
||||
|
||||
@@ -228,41 +228,26 @@ func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
|
||||
if tagSize != gcmTagSize {
|
||||
return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
|
||||
}
|
||||
return c.newGCM(0)
|
||||
return c.newGCM(false)
|
||||
}
|
||||
|
||||
const (
|
||||
VersionTLS12 = 0x0303
|
||||
VersionTLS13 = 0x0304
|
||||
)
|
||||
|
||||
func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
|
||||
return c.(*aesCipher).newGCM(VersionTLS12)
|
||||
return c.(*aesCipher).newGCM(true)
|
||||
}
|
||||
|
||||
func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
|
||||
return c.(*aesCipher).newGCM(VersionTLS13)
|
||||
}
|
||||
|
||||
func (c *aesCipher) newGCM(tlsVersion uint16) (cipher.AEAD, error) {
|
||||
func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
|
||||
var aead *C.GO_EVP_AEAD
|
||||
switch len(c.key) * 8 {
|
||||
case 128:
|
||||
switch tlsVersion {
|
||||
case VersionTLS12:
|
||||
if tls {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
|
||||
case VersionTLS13:
|
||||
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls13()
|
||||
default:
|
||||
} else {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
|
||||
}
|
||||
case 256:
|
||||
switch tlsVersion {
|
||||
case VersionTLS12:
|
||||
if tls {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
|
||||
case VersionTLS13:
|
||||
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls13()
|
||||
default:
|
||||
} else {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -122,7 +122,7 @@ awk -f boringx.awk goboringcrypto.h # writes goboringcrypto.x
|
||||
awk -f boringh.awk goboringcrypto.h # writes goboringcrypto[01].h
|
||||
|
||||
ls -l ../boringssl/include
|
||||
clang++ -fPIC -I../boringssl/include -O2 -o a.out goboringcrypto.cc
|
||||
clang++ -std=c++11 -fPIC -I../boringssl/include -O2 -o a.out goboringcrypto.cc
|
||||
./a.out || exit 2
|
||||
|
||||
# clang implements u128 % u128 -> u128 by calling __umodti3,
|
||||
|
||||
@@ -22,12 +22,6 @@ platform=""
|
||||
buildargs=""
|
||||
case "$GOARCH" in
|
||||
amd64)
|
||||
if ! docker run --rm -t amd64/ubuntu:focal uname -m >/dev/null 2>&1; then
|
||||
echo "# Docker cannot run amd64 binaries."
|
||||
exit 1
|
||||
fi
|
||||
platform="--platform linux/amd64"
|
||||
buildargs="--build-arg ubuntu=amd64/ubuntu"
|
||||
;;
|
||||
arm64)
|
||||
if ! docker run --rm -t arm64v8/ubuntu:focal uname -m >/dev/null 2>&1; then
|
||||
|
||||
@@ -125,9 +125,7 @@ void _goboringcrypto_EVP_AEAD_CTX_cleanup(GO_EVP_AEAD_CTX*);
|
||||
int _goboringcrypto_EVP_AEAD_CTX_seal(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t);
|
||||
int _goboringcrypto_EVP_AEAD_CTX_open(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t);
|
||||
const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm_tls12(void);
|
||||
const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm_tls13(void);
|
||||
const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm_tls12(void);
|
||||
const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm_tls13(void);
|
||||
enum go_evp_aead_direction_t {
|
||||
go_evp_aead_open = 0,
|
||||
go_evp_aead_seal = 1
|
||||
|
||||
@@ -50,7 +50,6 @@ func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: no
|
||||
|
||||
func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") }
|
||||
func NewGCMTLS(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
|
||||
func NewGCMTLS13(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
|
||||
|
||||
type PublicKeyECDSA struct{ _ int }
|
||||
type PrivateKeyECDSA struct{ _ int }
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -6,10 +6,9 @@
|
||||
|
||||
package tls
|
||||
|
||||
import "crypto/internal/boring/fipstls"
|
||||
|
||||
// The FIPS-only policies enforced here currently match BoringSSL's
|
||||
// ssl_policy_fips_202205.
|
||||
import (
|
||||
"crypto/internal/boring/fipstls"
|
||||
)
|
||||
|
||||
// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
|
||||
func needFIPS() bool {
|
||||
@@ -18,19 +17,19 @@ func needFIPS() bool {
|
||||
|
||||
// fipsMinVersion replaces c.minVersion in FIPS-only mode.
|
||||
func fipsMinVersion(c *Config) uint16 {
|
||||
// FIPS requires TLS 1.2 or TLS 1.3.
|
||||
// FIPS requires TLS 1.2.
|
||||
return VersionTLS12
|
||||
}
|
||||
|
||||
// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
|
||||
func fipsMaxVersion(c *Config) uint16 {
|
||||
// FIPS requires TLS 1.2 or TLS 1.3.
|
||||
return VersionTLS13
|
||||
// FIPS requires TLS 1.2.
|
||||
return VersionTLS12
|
||||
}
|
||||
|
||||
// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
|
||||
// in preference order (most preferable first).
|
||||
var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384}
|
||||
var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
|
||||
|
||||
// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
|
||||
func fipsCurvePreferences(c *Config) []CurveID {
|
||||
@@ -55,6 +54,8 @@ var defaultCipherSuitesFIPS = []uint16{
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
}
|
||||
|
||||
// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
|
||||
@@ -74,14 +75,8 @@ func fipsCipherSuites(c *Config) []uint16 {
|
||||
return list
|
||||
}
|
||||
|
||||
// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3.
|
||||
var defaultCipherSuitesTLS13FIPS = []uint16{
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
TLS_AES_256_GCM_SHA384,
|
||||
}
|
||||
|
||||
// fipsSupportedSignatureAlgorithms currently are a subset of
|
||||
// defaultSupportedSignatureAlgorithms without Ed25519, SHA-1, and P-521.
|
||||
// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
|
||||
var fipsSupportedSignatureAlgorithms = []SignatureScheme{
|
||||
PSSWithSHA256,
|
||||
PSSWithSHA384,
|
||||
@@ -91,6 +86,7 @@ var fipsSupportedSignatureAlgorithms = []SignatureScheme{
|
||||
PKCS1WithSHA384,
|
||||
ECDSAWithP384AndSHA384,
|
||||
PKCS1WithSHA512,
|
||||
ECDSAWithP521AndSHA512,
|
||||
}
|
||||
|
||||
// supportedSignatureAlgorithms returns the supported signature algorithms.
|
||||
|
||||
@@ -25,31 +25,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func allCipherSuitesIncludingTLS13() []uint16 {
|
||||
s := allCipherSuites()
|
||||
for _, suite := range cipherSuitesTLS13 {
|
||||
s = append(s, suite.id)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func isTLS13CipherSuite(id uint16) bool {
|
||||
for _, suite := range cipherSuitesTLS13 {
|
||||
if id == suite.id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func generateKeyShare(group CurveID) keyShare {
|
||||
key, err := generateECDHEKey(rand.Reader, group)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return keyShare{group: group, data: key.PublicKey().Bytes()}
|
||||
}
|
||||
|
||||
func TestBoringServerProtocolVersion(t *testing.T) {
|
||||
test := func(name string, v uint16, msg string) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
@@ -58,11 +33,8 @@ func TestBoringServerProtocolVersion(t *testing.T) {
|
||||
clientHello := &clientHelloMsg{
|
||||
vers: v,
|
||||
random: make([]byte, 32),
|
||||
cipherSuites: allCipherSuitesIncludingTLS13(),
|
||||
cipherSuites: allCipherSuites(),
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
supportedCurves: defaultCurvePreferences,
|
||||
keyShares: []keyShare{generateKeyShare(CurveP256)},
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
supportedVersions: []uint16{v},
|
||||
}
|
||||
testClientHelloFailure(t, serverConfig, clientHello, msg)
|
||||
@@ -76,25 +48,25 @@ func TestBoringServerProtocolVersion(t *testing.T) {
|
||||
|
||||
fipstls.Force()
|
||||
defer fipstls.Abandon()
|
||||
test("VersionSSL30/fipstls", VersionSSL30, "client offered only unsupported versions")
|
||||
test("VersionTLS10/fipstls", VersionTLS10, "client offered only unsupported versions")
|
||||
test("VersionTLS11/fipstls", VersionTLS11, "client offered only unsupported versions")
|
||||
test("VersionTLS12/fipstls", VersionTLS12, "")
|
||||
test("VersionTLS13/fipstls", VersionTLS13, "")
|
||||
test("VersionSSL30", VersionSSL30, "client offered only unsupported versions")
|
||||
test("VersionTLS10", VersionTLS10, "client offered only unsupported versions")
|
||||
test("VersionTLS11", VersionTLS11, "client offered only unsupported versions")
|
||||
test("VersionTLS12", VersionTLS12, "")
|
||||
test("VersionTLS13", VersionTLS13, "client offered only unsupported versions")
|
||||
}
|
||||
|
||||
func isBoringVersion(v uint16) bool {
|
||||
return v == VersionTLS12 || v == VersionTLS13
|
||||
return v == VersionTLS12
|
||||
}
|
||||
|
||||
func isBoringCipherSuite(id uint16) bool {
|
||||
switch id {
|
||||
case TLS_AES_128_GCM_SHA256,
|
||||
TLS_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_256_GCM_SHA384:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -102,7 +74,7 @@ func isBoringCipherSuite(id uint16) bool {
|
||||
|
||||
func isBoringCurve(id CurveID) bool {
|
||||
switch id {
|
||||
case CurveP256, CurveP384:
|
||||
case CurveP256, CurveP384, CurveP521:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -114,7 +86,7 @@ func isECDSA(id uint16) bool {
|
||||
return suite.flags&suiteECSign == suiteECSign
|
||||
}
|
||||
}
|
||||
return false // TLS 1.3 cipher suites are not tied to the signature algorithm.
|
||||
panic(fmt.Sprintf("unknown cipher suite %#x", id))
|
||||
}
|
||||
|
||||
func isBoringSignatureScheme(alg SignatureScheme) bool {
|
||||
@@ -126,6 +98,7 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
|
||||
PKCS1WithSHA384,
|
||||
ECDSAWithP384AndSHA384,
|
||||
PKCS1WithSHA512,
|
||||
ECDSAWithP521AndSHA512,
|
||||
PSSWithSHA256,
|
||||
PSSWithSHA384,
|
||||
PSSWithSHA512:
|
||||
@@ -136,9 +109,10 @@ func isBoringSignatureScheme(alg SignatureScheme) bool {
|
||||
|
||||
func TestBoringServerCipherSuites(t *testing.T) {
|
||||
serverConfig := testConfig.Clone()
|
||||
serverConfig.CipherSuites = allCipherSuites()
|
||||
serverConfig.Certificates = make([]Certificate, 1)
|
||||
|
||||
for _, id := range allCipherSuitesIncludingTLS13() {
|
||||
for _, id := range allCipherSuites() {
|
||||
if isECDSA(id) {
|
||||
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
|
||||
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
|
||||
@@ -147,19 +121,14 @@ func TestBoringServerCipherSuites(t *testing.T) {
|
||||
serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
|
||||
}
|
||||
serverConfig.BuildNameToCertificate()
|
||||
t.Run(fmt.Sprintf("suite=%s", CipherSuiteName(id)), func(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
|
||||
clientHello := &clientHelloMsg{
|
||||
vers: VersionTLS12,
|
||||
random: make([]byte, 32),
|
||||
cipherSuites: []uint16{id},
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
supportedCurves: defaultCurvePreferences,
|
||||
keyShares: []keyShare{generateKeyShare(CurveP256)},
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
supportedVersions: []uint16{VersionTLS12},
|
||||
}
|
||||
if isTLS13CipherSuite(id) {
|
||||
clientHello.supportedVersions = []uint16{VersionTLS13}
|
||||
}
|
||||
|
||||
testClientHello(t, serverConfig, clientHello)
|
||||
@@ -191,9 +160,7 @@ func TestBoringServerCurves(t *testing.T) {
|
||||
cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
supportedCurves: []CurveID{curveid},
|
||||
keyShares: []keyShare{generateKeyShare(curveid)},
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
supportedVersions: []uint16{VersionTLS12},
|
||||
}
|
||||
|
||||
testClientHello(t, serverConfig, clientHello)
|
||||
@@ -312,7 +279,7 @@ func TestBoringClientHello(t *testing.T) {
|
||||
}
|
||||
|
||||
if !isBoringVersion(hello.vers) {
|
||||
t.Errorf("client vers=%#x", hello.vers)
|
||||
t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
|
||||
}
|
||||
for _, v := range hello.supportedVersions {
|
||||
if !isBoringVersion(v) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user