mirror of
https://github.com/golang/go.git
synced 2026-01-30 07:32:05 +03:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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>
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1294,8 +1294,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.Type.IsUnsigned() || 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.
|
||||
@@ -1318,8 +1320,8 @@ func zeroUpper48Bits(x *Value, depth int) bool {
|
||||
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.Type.IsUnsigned() || 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.
|
||||
@@ -1342,8 +1344,8 @@ func zeroUpper56Bits(x *Value, depth int) bool {
|
||||
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.Type.IsUnsigned() || 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 +2133,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"`)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -486,74 +488,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
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
|
||||
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!
|
||||
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.
|
||||
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"'
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
//
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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 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) {
|
||||
|
||||
@@ -556,13 +556,7 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var aead cipher.AEAD
|
||||
if boring.Enabled {
|
||||
aead, err = boring.NewGCMTLS13(aes)
|
||||
} else {
|
||||
boring.Unreachable()
|
||||
aead, err = cipher.NewGCM(aes)
|
||||
}
|
||||
aead, err := cipher.NewGCM(aes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -139,9 +139,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) {
|
||||
if len(hello.supportedVersions) == 1 {
|
||||
hello.cipherSuites = nil
|
||||
}
|
||||
if needFIPS() {
|
||||
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
|
||||
} else if hasAESGCMHardwareSupport {
|
||||
if hasAESGCMHardwareSupport {
|
||||
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
|
||||
} else {
|
||||
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
|
||||
|
||||
@@ -41,6 +41,10 @@ type clientHandshakeStateTLS13 struct {
|
||||
func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
c := hs.c
|
||||
|
||||
if needFIPS() {
|
||||
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
|
||||
}
|
||||
|
||||
// The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
|
||||
// sections 4.1.2 and 4.1.3.
|
||||
if c.handshakes > 0 {
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
)
|
||||
|
||||
func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
|
||||
t.Helper()
|
||||
testClientHelloFailure(t, serverConfig, m, "")
|
||||
}
|
||||
|
||||
@@ -53,32 +52,23 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
|
||||
ctx := context.Background()
|
||||
conn := Server(s, serverConfig)
|
||||
ch, err := conn.readClientHello(ctx)
|
||||
if err == nil && conn.vers == VersionTLS13 {
|
||||
hs := serverHandshakeStateTLS13{
|
||||
c: conn,
|
||||
ctx: ctx,
|
||||
clientHello: ch,
|
||||
}
|
||||
hs := serverHandshakeState{
|
||||
c: conn,
|
||||
ctx: ctx,
|
||||
clientHello: ch,
|
||||
}
|
||||
if err == nil {
|
||||
err = hs.processClientHello()
|
||||
} else if err == nil {
|
||||
hs := serverHandshakeState{
|
||||
c: conn,
|
||||
ctx: ctx,
|
||||
clientHello: ch,
|
||||
}
|
||||
err = hs.processClientHello()
|
||||
if err == nil {
|
||||
err = hs.pickCipherSuite()
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
err = hs.pickCipherSuite()
|
||||
}
|
||||
s.Close()
|
||||
if len(expectedSubStr) == 0 {
|
||||
if err != nil && err != io.EOF {
|
||||
t.Helper()
|
||||
t.Errorf("Got error: %s; expected to succeed", err)
|
||||
}
|
||||
} else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
|
||||
t.Helper()
|
||||
t.Errorf("Got error: %v; expected to match substring '%s'", err, expectedSubStr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ type serverHandshakeStateTLS13 struct {
|
||||
func (hs *serverHandshakeStateTLS13) handshake() error {
|
||||
c := hs.c
|
||||
|
||||
if needFIPS() {
|
||||
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
|
||||
}
|
||||
|
||||
// For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
|
||||
if err := hs.processClientHello(); err != nil {
|
||||
return err
|
||||
@@ -159,9 +163,6 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
|
||||
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
|
||||
preferenceList = defaultCipherSuitesTLS13NoAES
|
||||
}
|
||||
if needFIPS() {
|
||||
preferenceList = defaultCipherSuitesTLS13FIPS
|
||||
}
|
||||
for _, suiteID := range preferenceList {
|
||||
hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
|
||||
if hs.suite != nil {
|
||||
|
||||
@@ -18,5 +18,3 @@ func fipsCurvePreferences(c *Config) []CurveID { panic("fipsCurvePreferences") }
|
||||
func fipsCipherSuites(c *Config) []uint16 { panic("fipsCipherSuites") }
|
||||
|
||||
var fipsSupportedSignatureAlgorithms []SignatureScheme
|
||||
|
||||
var defaultCipherSuitesTLS13FIPS []uint16
|
||||
|
||||
@@ -22,7 +22,7 @@ func boringAllowCert(c *Certificate) bool {
|
||||
}
|
||||
|
||||
// The key must be RSA 2048, RSA 3072, RSA 4096,
|
||||
// or ECDSA P-256 or P-384.
|
||||
// or ECDSA P-256, P-384, P-521.
|
||||
switch k := c.PublicKey.(type) {
|
||||
default:
|
||||
return false
|
||||
@@ -31,7 +31,7 @@ func boringAllowCert(c *Certificate) bool {
|
||||
return false
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
if k.Curve != elliptic.P256() && k.Curve != elliptic.P384() {
|
||||
if k.Curve != elliptic.P256() && k.Curve != elliptic.P384() && k.Curve != elliptic.P521() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +899,7 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
|
||||
)
|
||||
|
||||
considerCandidate := func(certType int, candidate potentialParent) {
|
||||
if alreadyInChain(candidate.cert, currentChain) {
|
||||
if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -2792,3 +2792,22 @@ func TestVerifyEKURootAsLeaf(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestVerifyNilPubKey(t *testing.T) {
|
||||
c := &Certificate{
|
||||
RawIssuer: []byte{1, 2, 3},
|
||||
AuthorityKeyId: []byte{1, 2, 3},
|
||||
}
|
||||
opts := &VerifyOptions{}
|
||||
opts.Roots = NewCertPool()
|
||||
r := &Certificate{
|
||||
RawSubject: []byte{1, 2, 3},
|
||||
SubjectKeyId: []byte{1, 2, 3},
|
||||
}
|
||||
opts.Roots.AddCert(r)
|
||||
|
||||
_, err := c.buildChains([]*Certificate{r}, nil, opts)
|
||||
if _, ok := err.(UnknownAuthorityError); !ok {
|
||||
t.Fatalf("buildChains returned unexpected error, got: %v, want %v", err, UnknownAuthorityError{})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,6 +780,7 @@ type Certificate struct {
|
||||
PolicyIdentifiers []asn1.ObjectIdentifier
|
||||
|
||||
// Policies contains all policy identifiers included in the certificate.
|
||||
// In Go 1.22, encoding/gob cannot handle and ignores this field.
|
||||
Policies []OID
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/gob"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
@@ -3999,3 +4000,13 @@ func TestCertificatePoliciesGODEBUG(t *testing.T) {
|
||||
t.Errorf("cert.Policies = %v, want: %v", cert.Policies, expectPolicies)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGob(t *testing.T) {
|
||||
// Test that gob does not reject Certificate.
|
||||
// See go.dev/issue/65633.
|
||||
cert := new(Certificate)
|
||||
err := gob.NewEncoder(io.Discard).Encode(cert)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +601,7 @@ func compileEnc(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine {
|
||||
if ut.externalEnc == 0 && srt.Kind() == reflect.Struct {
|
||||
for fieldNum, wireFieldNum := 0, 0; fieldNum < srt.NumField(); fieldNum++ {
|
||||
f := srt.Field(fieldNum)
|
||||
if !isSent(&f) {
|
||||
if !isSent(srt, &f) {
|
||||
continue
|
||||
}
|
||||
op, indir := encOpFor(f.Type, seen, building)
|
||||
|
||||
@@ -538,7 +538,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
|
||||
idToTypeSlice[st.id()] = st
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
if !isSent(&f) {
|
||||
if !isSent(t, &f) {
|
||||
continue
|
||||
}
|
||||
typ := userType(f.Type).base
|
||||
@@ -576,7 +576,7 @@ func isExported(name string) bool {
|
||||
// isSent reports whether this struct field is to be transmitted.
|
||||
// It will be transmitted only if it is exported and not a chan or func field
|
||||
// or pointer to chan or func.
|
||||
func isSent(field *reflect.StructField) bool {
|
||||
func isSent(struct_ reflect.Type, field *reflect.StructField) bool {
|
||||
if !isExported(field.Name) {
|
||||
return false
|
||||
}
|
||||
@@ -589,6 +589,17 @@ func isSent(field *reflect.StructField) bool {
|
||||
if typ.Kind() == reflect.Chan || typ.Kind() == reflect.Func {
|
||||
return false
|
||||
}
|
||||
|
||||
// Special case for Go 1.22: the x509.Certificate.Policies
|
||||
// field is unencodable but also unused by default.
|
||||
// Ignore it, so that x509.Certificate continues to be encodeable.
|
||||
// Go 1.23 will add the right methods so that gob can
|
||||
// handle the Policies field, and then we can remove this check.
|
||||
// See go.dev/issue/65633.
|
||||
if field.Name == "Policies" && struct_.PkgPath() == "crypto/x509" && struct_.Name() == "Certificate" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ go 1.22
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.16.1-0.20231129163542-152cdb1503eb
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/net v0.19.1-0.20240412193750-db050b07227e
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
golang.org/x/crypto v0.16.1-0.20231129163542-152cdb1503eb h1:1ceSY7sk6sJuiDREHpfyrqDnDljsLfEP2GuTClhBBfI=
|
||||
golang.org/x/crypto v0.16.1-0.20231129163542-152cdb1503eb/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.19.1-0.20240412193750-db050b07227e h1:oDnvqaqHo3ho8OChMtkQbQAyp9eqnm3J7JRtt0+Cabc=
|
||||
golang.org/x/net v0.19.1-0.20240412193750-db050b07227e/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
|
||||
@@ -23,11 +23,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
|
||||
@@ -38,24 +41,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 {
|
||||
|
||||
@@ -2196,6 +2196,12 @@ func TestIssue61737(t *testing.T) {
|
||||
iface.Complete()
|
||||
}
|
||||
|
||||
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)"
|
||||
fset := token.NewFileSet()
|
||||
|
||||
@@ -97,6 +97,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 {
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package version provides operations on [Go versions].
|
||||
// Package version provides operations on [Go versions]
|
||||
// in [Go toolchain name syntax]: strings like
|
||||
// "go1.20", "go1.21.0", "go1.22rc2", and "go1.23.4-bigcorp".
|
||||
//
|
||||
// [Go versions]: https://go.dev/doc/toolchain#version
|
||||
// [Go toolchain name syntax]: https://go.dev/doc/toolchain#name
|
||||
package version // import "go/version"
|
||||
|
||||
import (
|
||||
@@ -12,9 +15,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// stripGo converts from a "go1.21" version to a "1.21" version.
|
||||
// stripGo converts from a "go1.21-bigcorp" version to a "1.21" version.
|
||||
// If v does not start with "go", stripGo returns the empty string (a known invalid version).
|
||||
func stripGo(v string) string {
|
||||
v, _, _ = strings.Cut(v, "-") // strip -bigcorp suffix.
|
||||
if len(v) < 2 || v[:2] != "go" {
|
||||
return ""
|
||||
}
|
||||
@@ -50,8 +54,6 @@ func Lang(x string) string {
|
||||
// valid versions and equal to each other.
|
||||
// The language version "go1.21" compares less than the
|
||||
// release candidate and eventual releases "go1.21rc1" and "go1.21.0".
|
||||
// Custom toolchain suffixes are ignored during comparison:
|
||||
// "go1.21.0" and "go1.21.0-bigcorp" are equal.
|
||||
func Compare(x, y string) int {
|
||||
return gover.Compare(stripGo(x), stripGo(y))
|
||||
}
|
||||
|
||||
@@ -23,13 +23,16 @@ var compareTests = []testCase2[string, string, int]{
|
||||
{"go1.19", "go1.19.0", 0},
|
||||
{"go1.19rc1", "go1.19", -1},
|
||||
{"go1.20", "go1.20.0", 0},
|
||||
{"go1.20", "go1.20.0-bigcorp", 0},
|
||||
{"go1.20rc1", "go1.20", -1},
|
||||
{"go1.21", "go1.21.0", -1},
|
||||
{"go1.21", "go1.21.0-bigcorp", -1},
|
||||
{"go1.21", "go1.21rc1", -1},
|
||||
{"go1.21rc1", "go1.21.0", -1},
|
||||
{"go1.6", "go1.19", -1},
|
||||
{"go1.19", "go1.19.1", -1},
|
||||
{"go1.19rc1", "go1.19", -1},
|
||||
{"go1.19rc1", "go1.19", -1},
|
||||
{"go1.19rc1", "go1.19.1", -1},
|
||||
{"go1.19rc1", "go1.19rc2", -1},
|
||||
{"go1.19.0", "go1.19.1", -1},
|
||||
|
||||
@@ -171,13 +171,31 @@ func jsValEscaper(args ...any) string {
|
||||
// cyclic data. This may be an unacceptable DoS risk.
|
||||
b, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
// Put a space before comment so that if it is flush against
|
||||
// While the standard JSON marshaller does not include user controlled
|
||||
// information in the error message, if a type has a MarshalJSON method,
|
||||
// the content of the error message is not guaranteed. Since we insert
|
||||
// the error into the template, as part of a comment, we attempt to
|
||||
// prevent the error from either terminating the comment, or the script
|
||||
// block itself.
|
||||
//
|
||||
// In particular we:
|
||||
// * replace "*/" comment end tokens with "* /", which does not
|
||||
// terminate the comment
|
||||
// * replace "</script" with "\x3C/script", and "<!--" with
|
||||
// "\x3C!--", which prevents confusing script block termination
|
||||
// semantics
|
||||
//
|
||||
// We also put a space before the comment so that if it is flush against
|
||||
// a division operator it is not turned into a line comment:
|
||||
// x/{{y}}
|
||||
// turning into
|
||||
// x//* error marshaling y:
|
||||
// second line of error message */null
|
||||
return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /"))
|
||||
errStr := err.Error()
|
||||
errStr = strings.ReplaceAll(errStr, "*/", "* /")
|
||||
errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`)
|
||||
errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`)
|
||||
return fmt.Sprintf(" /* %s */null ", errStr)
|
||||
}
|
||||
|
||||
// TODO: maybe post-process output to prevent it from containing
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -103,61 +104,72 @@ func TestNextJsCtx(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type jsonErrType struct{}
|
||||
|
||||
func (e *jsonErrType) MarshalJSON() ([]byte, error) {
|
||||
return nil, errors.New("beep */ boop </script blip <!--")
|
||||
}
|
||||
|
||||
func TestJSValEscaper(t *testing.T) {
|
||||
tests := []struct {
|
||||
x any
|
||||
js string
|
||||
x any
|
||||
js string
|
||||
skipNest bool
|
||||
}{
|
||||
{int(42), " 42 "},
|
||||
{uint(42), " 42 "},
|
||||
{int16(42), " 42 "},
|
||||
{uint16(42), " 42 "},
|
||||
{int32(-42), " -42 "},
|
||||
{uint32(42), " 42 "},
|
||||
{int16(-42), " -42 "},
|
||||
{uint16(42), " 42 "},
|
||||
{int64(-42), " -42 "},
|
||||
{uint64(42), " 42 "},
|
||||
{uint64(1) << 53, " 9007199254740992 "},
|
||||
{int(42), " 42 ", false},
|
||||
{uint(42), " 42 ", false},
|
||||
{int16(42), " 42 ", false},
|
||||
{uint16(42), " 42 ", false},
|
||||
{int32(-42), " -42 ", false},
|
||||
{uint32(42), " 42 ", false},
|
||||
{int16(-42), " -42 ", false},
|
||||
{uint16(42), " 42 ", false},
|
||||
{int64(-42), " -42 ", false},
|
||||
{uint64(42), " 42 ", false},
|
||||
{uint64(1) << 53, " 9007199254740992 ", false},
|
||||
// ulp(1 << 53) > 1 so this loses precision in JS
|
||||
// but it is still a representable integer literal.
|
||||
{uint64(1)<<53 + 1, " 9007199254740993 "},
|
||||
{float32(1.0), " 1 "},
|
||||
{float32(-1.0), " -1 "},
|
||||
{float32(0.5), " 0.5 "},
|
||||
{float32(-0.5), " -0.5 "},
|
||||
{float32(1.0) / float32(256), " 0.00390625 "},
|
||||
{float32(0), " 0 "},
|
||||
{math.Copysign(0, -1), " -0 "},
|
||||
{float64(1.0), " 1 "},
|
||||
{float64(-1.0), " -1 "},
|
||||
{float64(0.5), " 0.5 "},
|
||||
{float64(-0.5), " -0.5 "},
|
||||
{float64(0), " 0 "},
|
||||
{math.Copysign(0, -1), " -0 "},
|
||||
{"", `""`},
|
||||
{"foo", `"foo"`},
|
||||
{uint64(1)<<53 + 1, " 9007199254740993 ", false},
|
||||
{float32(1.0), " 1 ", false},
|
||||
{float32(-1.0), " -1 ", false},
|
||||
{float32(0.5), " 0.5 ", false},
|
||||
{float32(-0.5), " -0.5 ", false},
|
||||
{float32(1.0) / float32(256), " 0.00390625 ", false},
|
||||
{float32(0), " 0 ", false},
|
||||
{math.Copysign(0, -1), " -0 ", false},
|
||||
{float64(1.0), " 1 ", false},
|
||||
{float64(-1.0), " -1 ", false},
|
||||
{float64(0.5), " 0.5 ", false},
|
||||
{float64(-0.5), " -0.5 ", false},
|
||||
{float64(0), " 0 ", false},
|
||||
{math.Copysign(0, -1), " -0 ", false},
|
||||
{"", `""`, false},
|
||||
{"foo", `"foo"`, false},
|
||||
// Newlines.
|
||||
{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
|
||||
{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false},
|
||||
// "\v" == "v" on IE 6 so use "\u000b" instead.
|
||||
{"\t\x0b", `"\t\u000b"`},
|
||||
{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
|
||||
{[]any{}, "[]"},
|
||||
{[]any{42, "foo", nil}, `[42,"foo",null]`},
|
||||
{[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
|
||||
{"<!--", `"\u003c!--"`},
|
||||
{"-->", `"--\u003e"`},
|
||||
{"<![CDATA[", `"\u003c![CDATA["`},
|
||||
{"]]>", `"]]\u003e"`},
|
||||
{"</script", `"\u003c/script"`},
|
||||
{"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
|
||||
{nil, " null "},
|
||||
{"\t\x0b", `"\t\u000b"`, false},
|
||||
{struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false},
|
||||
{[]any{}, "[]", false},
|
||||
{[]any{42, "foo", nil}, `[42,"foo",null]`, false},
|
||||
{[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false},
|
||||
{"<!--", `"\u003c!--"`, false},
|
||||
{"-->", `"--\u003e"`, false},
|
||||
{"<![CDATA[", `"\u003c![CDATA["`, false},
|
||||
{"]]>", `"]]\u003e"`, false},
|
||||
{"</script", `"\u003c/script"`, false},
|
||||
{"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E"
|
||||
{nil, " null ", false},
|
||||
{&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if js := jsValEscaper(test.x); js != test.js {
|
||||
t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
|
||||
}
|
||||
if test.skipNest {
|
||||
continue
|
||||
}
|
||||
// Make sure that escaping corner cases are not broken
|
||||
// by nesting.
|
||||
a := []any{test.x}
|
||||
|
||||
@@ -78,7 +78,7 @@ func TestHasGoBuild(t *testing.T) {
|
||||
// we will presumably find out about it when those tests fail.)
|
||||
switch runtime.GOOS {
|
||||
case "ios":
|
||||
if strings.HasSuffix(b, "-corellium") {
|
||||
if isCorelliumBuilder(b) {
|
||||
// The corellium environment is self-hosting, so it should be able
|
||||
// to build even though real "ios" devices can't exec.
|
||||
} else {
|
||||
@@ -89,7 +89,7 @@ func TestHasGoBuild(t *testing.T) {
|
||||
return
|
||||
}
|
||||
case "android":
|
||||
if strings.HasSuffix(b, "-emu") && platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, false) {
|
||||
if isEmulatedBuilder(b) && platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, false) {
|
||||
// As of 2023-05-02, the test environment on the emulated builders is
|
||||
// missing a C linker.
|
||||
t.Logf("HasGoBuild is false on %s", b)
|
||||
@@ -97,7 +97,7 @@ func TestHasGoBuild(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(b, "-noopt") {
|
||||
if strings.Contains(b, "-noopt") {
|
||||
// The -noopt builder sets GO_GCFLAGS, which causes tests of 'go build' to
|
||||
// be skipped.
|
||||
t.Logf("HasGoBuild is false on %s", b)
|
||||
@@ -153,7 +153,7 @@ func TestMustHaveExec(t *testing.T) {
|
||||
t.Errorf("expected MustHaveExec to skip on %v", runtime.GOOS)
|
||||
}
|
||||
case "ios":
|
||||
if b := testenv.Builder(); strings.HasSuffix(b, "-corellium") && !hasExec {
|
||||
if b := testenv.Builder(); isCorelliumBuilder(b) && !hasExec {
|
||||
// Most ios environments can't exec, but the corellium builder can.
|
||||
t.Errorf("expected MustHaveExec not to skip on %v", b)
|
||||
}
|
||||
@@ -186,3 +186,23 @@ func TestCleanCmdEnvPWD(t *testing.T) {
|
||||
}
|
||||
t.Error("PWD not set in cmd.Env")
|
||||
}
|
||||
|
||||
func isCorelliumBuilder(builderName string) bool {
|
||||
// Support both the old infra's builder names and the LUCI builder names.
|
||||
// The former's names are ad-hoc so we could maintain this invariant on
|
||||
// the builder side. The latter's names are structured, and "corellium" will
|
||||
// appear as a "host" suffix after the GOOS and GOARCH, which always begin
|
||||
// with an underscore.
|
||||
return strings.HasSuffix(builderName, "-corellium") || strings.Contains(builderName, "_corellium")
|
||||
}
|
||||
|
||||
func isEmulatedBuilder(builderName string) bool {
|
||||
// Support both the old infra's builder names and the LUCI builder names.
|
||||
// The former's names are ad-hoc so we could maintain this invariant on
|
||||
// the builder side. The latter's names are structured, and the signifier
|
||||
// of emulation "emu" will appear as a "host" suffix after the GOOS and
|
||||
// GOARCH because it modifies the run environment in such a way that it
|
||||
// the target GOOS and GOARCH may not match the host. This suffix always
|
||||
// begins with an underscore.
|
||||
return strings.HasSuffix(builderName, "-emu") || strings.Contains(builderName, "_emu")
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type Summary struct {
|
||||
type GoroutineSummary struct {
|
||||
ID tracev2.GoID
|
||||
Name string // A non-unique human-friendly identifier for the goroutine.
|
||||
PC uint64 // The start PC of the goroutine.
|
||||
PC uint64 // The first PC we saw for the entry function of the goroutine
|
||||
CreationTime tracev2.Time // Timestamp of the first appearance in the trace.
|
||||
StartTime tracev2.Time // Timestamp of the first time it started running. 0 if the goroutine never ran.
|
||||
EndTime tracev2.Time // Timestamp of when the goroutine exited. 0 if the goroutine never exited.
|
||||
@@ -385,10 +385,10 @@ func (s *Summarizer) Event(ev *tracev2.Event) {
|
||||
}
|
||||
|
||||
// The goroutine hasn't been identified yet. Take the transition stack
|
||||
// and identify the goroutine by the bottom-most frame of that stack.
|
||||
// This bottom-most frame will be identical for all transitions on this
|
||||
// and identify the goroutine by the root frame of that stack.
|
||||
// This root frame will be identical for all transitions on this
|
||||
// goroutine, because it represents its immutable start point.
|
||||
if g.PC == 0 {
|
||||
if g.Name == "" {
|
||||
stk := st.Stack
|
||||
if stk != tracev2.NoStack {
|
||||
var frame tracev2.StackFrame
|
||||
@@ -396,9 +396,14 @@ func (s *Summarizer) Event(ev *tracev2.Event) {
|
||||
stk.Frames(func(f tracev2.StackFrame) bool {
|
||||
frame = f
|
||||
ok = true
|
||||
return false
|
||||
return true
|
||||
})
|
||||
if ok {
|
||||
// NB: this PC won't actually be consistent for
|
||||
// goroutines which existed at the start of the
|
||||
// trace. The UI doesn't use it directly; this
|
||||
// mainly serves as an indication that we
|
||||
// actually saw a call stack for the goroutine
|
||||
g.PC = frame.PC
|
||||
g.Name = frame.Func
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ func TestSummarizeGoroutinesTrace(t *testing.T) {
|
||||
hasSyncBlockTime bool
|
||||
hasGCMarkAssistTime bool
|
||||
)
|
||||
|
||||
assertContainsGoroutine(t, summaries, "runtime.gcBgMarkWorker")
|
||||
assertContainsGoroutine(t, summaries, "main.main.func1")
|
||||
|
||||
for _, summary := range summaries {
|
||||
basicGoroutineSummaryChecks(t, summary)
|
||||
hasSchedWaitTime = hasSchedWaitTime || summary.SchedWaitTime > 0
|
||||
@@ -232,6 +236,15 @@ func TestSummarizeTasksTrace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func assertContainsGoroutine(t *testing.T, summaries map[tracev2.GoID]*GoroutineSummary, name string) {
|
||||
for _, summary := range summaries {
|
||||
if summary.Name == name {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf("missing goroutine %s", name)
|
||||
}
|
||||
|
||||
func basicGoroutineSummaryChecks(t *testing.T, summary *GoroutineSummary) {
|
||||
if summary.ID == tracev2.NoGoroutine {
|
||||
t.Error("summary found for no goroutine")
|
||||
|
||||
@@ -302,6 +302,13 @@ func (o *ordering) advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64)
|
||||
// Otherwise, we're talking about a G sitting in a syscall on an M.
|
||||
// Validate the named M.
|
||||
if mid == curCtx.M {
|
||||
if gen != o.initialGen && curCtx.G != gid {
|
||||
// If this isn't the first generation, we *must* have seen this
|
||||
// binding occur already. Even if the G was blocked in a syscall
|
||||
// for multiple generations since trace start, we would have seen
|
||||
// a previous GoStatus event that bound the goroutine to an M.
|
||||
return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, curCtx.G)
|
||||
}
|
||||
newCtx.G = gid
|
||||
break
|
||||
}
|
||||
|
||||
66
src/internal/trace/v2/testdata/testprog/wait-on-pipe.go
vendored
Normal file
66
src/internal/trace/v2/testdata/testprog/wait-on-pipe.go
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Tests a goroutine sitting blocked in a syscall for
|
||||
// an entire generation. This is a regression test for
|
||||
// #65196.
|
||||
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"runtime/trace"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a pipe to block on.
|
||||
var p [2]int
|
||||
if err := syscall.Pipe(p[:]); err != nil {
|
||||
log.Fatalf("failed to create pipe: %v", err)
|
||||
}
|
||||
rfd, wfd := p[0], p[1]
|
||||
|
||||
// Create a goroutine that blocks on the pipe.
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
var data [1]byte
|
||||
_, err := syscall.Read(rfd, data[:])
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read from pipe: %v", err)
|
||||
}
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
// Give the goroutine ample chance to block on the pipe.
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
// Start tracing.
|
||||
if err := trace.Start(os.Stdout); err != nil {
|
||||
log.Fatalf("failed to start tracing: %v", err)
|
||||
}
|
||||
|
||||
// This isn't enough to have a full generation pass by default,
|
||||
// but it is generally enough in stress mode.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// Write to the pipe to unblock it.
|
||||
if _, err := syscall.Write(wfd, []byte{10}); err != nil {
|
||||
log.Fatalf("failed to write to pipe: %v", err)
|
||||
}
|
||||
|
||||
// Wait for the goroutine to unblock and start running.
|
||||
// This is helpful to catch incorrect information written
|
||||
// down for the syscall-blocked goroutine, since it'll start
|
||||
// executing, and that execution information will be
|
||||
// inconsistent.
|
||||
<-done
|
||||
|
||||
// Stop tracing.
|
||||
trace.Stop()
|
||||
}
|
||||
@@ -896,7 +896,7 @@ String id=18
|
||||
String id=19
|
||||
data="sleep"
|
||||
String id=20
|
||||
data="runtime.GoSched"
|
||||
data="runtime.Gosched"
|
||||
String id=21
|
||||
data="start trace"
|
||||
String id=22
|
||||
|
||||
@@ -220,7 +220,7 @@ String id=18
|
||||
String id=19
|
||||
data="sleep"
|
||||
String id=20
|
||||
data="runtime.GoSched"
|
||||
data="runtime.Gosched"
|
||||
String id=21
|
||||
data="start trace"
|
||||
String id=22
|
||||
|
||||
@@ -4086,7 +4086,7 @@ String id=18
|
||||
String id=19
|
||||
data="sleep"
|
||||
String id=20
|
||||
data="runtime.GoSched"
|
||||
data="runtime.Gosched"
|
||||
String id=21
|
||||
data="GC mark termination"
|
||||
String id=22
|
||||
|
||||
@@ -213,7 +213,7 @@ func TestTraceFutileWakeup(t *testing.T) {
|
||||
// Check to make sure that no goroutine in the "special" trace region
|
||||
// ends up blocking, unblocking, then immediately blocking again.
|
||||
//
|
||||
// The goroutines are careful to call runtime.GoSched in between blocking,
|
||||
// The goroutines are careful to call runtime.Gosched in between blocking,
|
||||
// so there should never be a clean block/unblock on the goroutine unless
|
||||
// the runtime was generating extraneous events.
|
||||
const (
|
||||
@@ -521,6 +521,15 @@ func TestTraceManyStartStop(t *testing.T) {
|
||||
testTraceProg(t, "many-start-stop.go", nil)
|
||||
}
|
||||
|
||||
func TestTraceWaitOnPipe(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
|
||||
testTraceProg(t, "wait-on-pipe.go", nil)
|
||||
return
|
||||
}
|
||||
t.Skip("no applicable syscall.Pipe on " + runtime.GOOS)
|
||||
}
|
||||
|
||||
func testTraceProg(t *testing.T, progName string, extra func(t *testing.T, trace, stderr []byte, stress bool)) {
|
||||
testenv.MustHaveGoRun(t)
|
||||
|
||||
|
||||
13
src/internal/types/testdata/fixedbugs/issue65854.go
vendored
Normal file
13
src/internal/types/testdata/fixedbugs/issue65854.go
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// -gotypesalias=1
|
||||
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type A = int
|
||||
|
||||
type T[P any] *A
|
||||
|
||||
var _ T[int]
|
||||
@@ -452,6 +452,48 @@ func TestReadFormLimits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadFormEndlessHeaderLine(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
prefix string
|
||||
}{{
|
||||
name: "name",
|
||||
prefix: "X-",
|
||||
}, {
|
||||
name: "value",
|
||||
prefix: "X-Header: ",
|
||||
}, {
|
||||
name: "continuation",
|
||||
prefix: "X-Header: foo\r\n ",
|
||||
}} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
const eol = "\r\n"
|
||||
s := `--boundary` + eol
|
||||
s += `Content-Disposition: form-data; name="a"` + eol
|
||||
s += `Content-Type: text/plain` + eol
|
||||
s += test.prefix
|
||||
fr := io.MultiReader(
|
||||
strings.NewReader(s),
|
||||
neverendingReader('X'),
|
||||
)
|
||||
r := NewReader(fr, "boundary")
|
||||
_, err := r.ReadForm(1 << 20)
|
||||
if err != ErrMessageTooLarge {
|
||||
t.Fatalf("ReadForm(1 << 20): %v, want ErrMessageTooLarge", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type neverendingReader byte
|
||||
|
||||
func (r neverendingReader) Read(p []byte) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = byte(r)
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func BenchmarkReadForm(b *testing.B) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user